Merge branch 'master' into releases 3.0.0
authorHolger Schemel <info@artsoft.org>
Sat, 30 Aug 2014 08:43:05 +0000 (10:43 +0200)
committerHolger Schemel <info@artsoft.org>
Sat, 30 Aug 2014 08:43:05 +0000 (10:43 +0200)
68 files changed:
CHANGES
Makefile
src/Makefile
src/cartoons.c
src/conf_chr.c [new file with mode: 0644]
src/conf_chr.h [new file with mode: 0644]
src/conf_cus.c [new file with mode: 0644]
src/conf_cus.h [new file with mode: 0644]
src/conf_e2g.c [new file with mode: 0644]
src/conf_e2s.c [new file with mode: 0644]
src/conf_esg.c [new file with mode: 0644]
src/conf_fnt.c [new file with mode: 0644]
src/conf_gfx.c [new file with mode: 0644]
src/conf_gfx.h [new file with mode: 0644]
src/conf_snd.c [new file with mode: 0644]
src/conf_snd.h [new file with mode: 0644]
src/conftime.h
src/editor.c
src/editor.h
src/events.c
src/files.c
src/files.h
src/game.c
src/game.h
src/init.c
src/init.h
src/libgame/Makefile
src/libgame/gadgets.c
src/libgame/gadgets.h
src/libgame/hash.c [new file with mode: 0644]
src/libgame/hash.h [new file with mode: 0644]
src/libgame/image.c
src/libgame/image.h
src/libgame/joystick.c
src/libgame/macosx.h [new file with mode: 0644]
src/libgame/misc.c
src/libgame/misc.h
src/libgame/msdos.c
src/libgame/msdos.h
src/libgame/pcx.c
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/toons.c
src/libgame/toons.h
src/libgame/types.h
src/libgame/windows.h [new file with mode: 0644]
src/libgame/x11.c
src/libgame/x11.h
src/main.c
src/main.h
src/netserv.c
src/network.c
src/screens.c
src/screens.h
src/tape.c
src/tape.h
src/tools.c
src/tools.h

diff --git a/CHANGES b/CHANGES
index 3635776709fae4786c845201ec4e5726c37d49f4..10ebc7f0a29e6ba5ef344faba569706f3d456a40 100644 (file)
--- a/CHANGES
+++ b/CHANGES
@@ -1,3 +1,97 @@
+Release Version 3.0.0 [05 AUG 2003]
+------------------------------------------
+       - final version bumped to 3.0.0 due to the massive changes
+       - graphics and sounds now completely and dynamically customizable
+       - custom elements now have lots of configurable properties
+       - advanced custom element settings for powerful, self-created elements
+       - fixed Supaplex gravity tubes
+       - fixed very nasty bug in SDL_image (and X11) PCX loading routine
+       - fixed some very nasty bugs in bitmap zoom routine
+       - fixed very nasty bug in level/artwork loading routine
+       - added new contributed levels and artwork from the following players:
+         * in the section "Contributions - 2002":
+            + Abby King (14 levels)
+           + Alan Bond (30 levels, all solvable, BD style artwork set)
+           + David Hutchinson (25 levels, artwork set)
+           + Equinox Tetrachloride (50 levels + 100 levels, all solvable)
+           + Sylvan Hancock (39 levels)
+         * in the section "Contributions - 2003":
+           + Andreas Buschbeck (85 levels, all solvable, complete artwork set)
+           + Edward Leuf (10 levels, all solvable, artwork set)
+           + Emanuel Schmieg (22 levels, all solvable, complete artwork set)
+           + Gavin Davidson (47 levels)
+           + Jorge Jordan (17 levels)
+           + Rafael Gatti (17 levels)
+           + Randy Johannessen (17 levels)
+           + Richard Valvona (3 levels)
+           + Sam Bateman (35 levels)
+       - great new levels with full artwork are now available from:
+         + Juergen Bonhagen (with complete artwork set)
+           * download these levels from "http://www.jb-line.de/"
+         + Andreas Buschbeck (with complete artwork set)
+           * download these levels from "http://home.vr-web.de/~abuschbeck/"
+
+Pre-Release Version 2.2.0rc7 [17 JUL 2003]
+------------------------------------------
+       - fixed bug when picking element in the editor
+       - added more custom elements properties
+       - fixed bugs when smashing penguin
+
+Pre-Release Version 2.2.0rc6 [22 APR 2003]
+------------------------------------------
+       - fixed small font configuration directive bug
+       - tape recorder font slightly enhanced (now complete character set)
+       - added missing font configuration source file
+       - added updated CHANGES file ;-)
+
+Pre-Release Version 2.2.0rc5 [20 APR 2003]
+------------------------------------------
+       - added generic selectbox gadget
+       - added special mouse cursor for playfield while playing
+       - font handling now more flexible (support for ISO-Latin-1 fonts)
+       - font graphics adjusted accordingly
+
+Pre-Release Version 2.2.0rc4 [30 MAR 2003]
+------------------------------------------
+       - changes for menu configuration
+       - not officially announced pre-release version
+       - Emerald Mine text font now much better quality
+
+Pre-Release Version 2.2.0rc3 [11 FEB 2003]
+------------------------------------------
+       - first custom element properties
+       - animation configuration for dynamically defined element actions
+       - automatically downscaled graphics (small graphics not needed anymore)
+       - ".EDITOR" and ".PREVIEW" suffixes for special editor/preview graphics
+       - toon animations (and number of toons) now fully configurable
+
+Pre-Release Version 2.2.0rc2 [13 JAN 2003]
+------------------------------------------
+       - added support for stereo WAV sound files
+       - moving objects can now have arbitrary animation length
+       - new batch command for dumping level information
+       - added support for background images for all menu screens
+       - added 128 custom elements that can be decorated with own graphics
+       - added some example levels showing how to create custom artwork
+       - added new contributed levels from the following players:
+         + Emanuel Schmieg: "Into The Ice Caves" (22 levels + artwork)
+
+Pre-Release Version 2.2.0rc1 [31 DEC 2002]
+------------------------------------------
+       - level series artwork now configurable via level series config file
+       - single graphics and animations can now be replaced with different
+         ones (independantly from default image files which may be larger)
+         by defining and using additional image files
+       - element animation length, speed and mode now freely configurable
+       - automatic tape playing function for game engine and level testing
+       - missing steel wall graphic added (thanks to Equinox Tetrachloride)
+       - added new contributed levels from the following players:
+         + Abby King (14 levels)
+         + Andreas Buschbeck (80 levels with complete artwork set)
+         + David Hutchinson (25 levels with graphics set)
+         + Equinox Tetrachloride (150 levels guaranteed to be solvable)
+         + Sylvan Hancock (39 levels)
+
 Release Version 2.1.1 [13 AUG 2002]
 -----------------------------------
        - sound bug (causing crashes) fixed (reported by Keith Peterston)
@@ -6,7 +100,7 @@ Release Version 2.1.1 [13 AUG 2002]
        - default keys for "snap field" and "place bomb" fixed for Mac OS X
        - added new contributed levels from the following players:
          + Alan Bond
-         + Gerrit Holl
+         + Gerrit Holl and Timen van den Berg
 
 Release Version 2.1.0 [05 AUG 2002]
 -----------------------------------
@@ -180,8 +274,8 @@ Version 0.9b2 [21 NOV 1995] [NOT RELEASED]
 ------------------------------------------
        - new game elements
 
-Prerelease Version 0.9b [4 NOV 1995]
-------------------------------------
+Pre-Release Version 0.9b [4 NOV 1995]
+-------------------------------------
        - the game is now completely Freeware
        - the game is now better playable by keyboard
          (in the last version, the player was making more than
@@ -196,6 +290,6 @@ Prerelease Version 0.9b [4 NOV 1995]
        - FreeBSD sound and joystick support (thanks to Jean-Marc
          Zucconi)
 
-Prerelease Version 0.9 [23 OCT 1995]
-------------------------------------
+Pre-Release Version 0.9 [23 OCT 1995]
+-------------------------------------
        - first (pre)release version
index 0496dc3c38b4eee1d8f826081b0075f1df459ac0..0c22aefb3fa9bcb1696e9a9c507b3dde989eaf00 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -49,8 +49,11 @@ CROSS_PATH_WIN32=/usr/local/cross-tools/i386-mingw32msvc
 SRC_DIR = src
 MAKE_CMD = $(MAKE) -C $(SRC_DIR)
 
+# DEFAULT_TARGET = x11
+DEFAULT_TARGET = sdl
+
 all:
-       @$(MAKE_CMD) TARGET=x11
+       @$(MAKE_CMD) TARGET=$(DEFAULT_TARGET)
 
 x11:
        @$(MAKE_CMD) TARGET=x11
@@ -84,8 +87,20 @@ clean:
 # development only stuff                                                      #
 #-----------------------------------------------------------------------------#
 
+auto-conf:
+       @$(MAKE_CMD) auto-conf
+
 run:
-       @$(MAKE_CMD) TARGET=x11 && ./rocksndiamonds --verbose
+       @$(MAKE_CMD) TARGET=$(DEFAULT_TARGET) && ./rocksndiamonds --verbose
+
+gdb:
+       @$(MAKE_CMD) TARGET=$(DEFAULT_TARGET) && gdb ./rocksndiamonds
+
+enginetest:
+       ./Scripts/make_enginetest.sh
+
+enginetestfast:
+       ./Scripts/make_enginetest.sh fast
 
 backup:
        ./Scripts/make_backup.sh src
@@ -108,16 +123,39 @@ dist-win32:
 dist-macosx:
        ./Scripts/make_dist.sh mac . $(MAKE)
 
+upload-unix:
+       ./Scripts/make_dist.sh unix . upload
+
+upload-msdos:
+       ./Scripts/make_dist.sh dos . upload
+
+upload-win32:
+       ./Scripts/make_dist.sh win . upload
+
+upload-macosx:
+       ./Scripts/make_dist.sh mac . upload
+
 dist-clean:
        @$(MAKE_CMD) dist-clean
 
+dist-build-unix:
+       @BUILD_DIST=TRUE $(MAKE) x11
+
+dist-build-win32:
+       @BUILD_DIST=TRUE $(MAKE) cross-win32
+
+dist-build-msdos:
+       @BUILD_DIST=TRUE $(MAKE) cross-msdos
+
 dist-build-all:
        $(MAKE) clean
-       @BUILD_DIST=TRUE $(MAKE) x11            ; $(MAKE) dist-clean
-       @BUILD_DIST=TRUE $(MAKE) cross-win32    ; $(MAKE) dist-clean
-       @BUILD_DIST=TRUE $(MAKE) cross-msdos    ; $(MAKE) dist-clean
+       $(MAKE) dist-build-unix         ; $(MAKE) dist-clean
+       $(MAKE) dist-build-win32        ; $(MAKE) dist-clean
+       $(MAKE) dist-build-msdos        ; $(MAKE) dist-clean
 
 dist-all: dist-build-all dist-unix dist-msdos dist-win32 dist-macosx
 
+upload-all: upload-unix upload-msdos upload-win32 upload-macosx
+
 depend dep:
        $(MAKE_CMD) depend
index 609d753f1d7de98efe5d015a2724117790ba0f0b..ff28877633b2b653aa14aa87f2e396da2af41c55 100644 (file)
@@ -64,6 +64,7 @@ TARGET = allegro
 endif
 
 ifeq ($(PLATFORM),cross-win32)
+EXTRA_LDFLAGS = -lshfolder
 PROGNAME = ../$(PROGBASE).exe
 TARGET = sdl
 endif
@@ -106,7 +107,8 @@ CONFIG = $(CONFIG_GAME_DIR) $(CONFIG_SCORE_ENTRIES) $(JOYSTICK)
 # PROFILING = $(PROFILING_FLAGS)
 
 # OPTIONS = $(DEBUG) -Wall                     # only for debugging purposes
-OPTIONS = $(DEBUG) -O3 -Wall                   # only for debugging purposes
+# OPTIONS = $(DEBUG) -O3 -Wall                 # only for debugging purposes
+OPTIONS = $(DEBUG) -Wall                       # only for debugging purposes
 # OPTIONS = $(DEBUG) -Wall -ansi -pedantic     # only for debugging purposes
 # OPTIONS = -O3 -Wall -ansi -pedantic
 # OPTIONS = -O3 -Wall
@@ -122,6 +124,8 @@ LDFLAGS = $(SYS_LDFLAGS) $(EXTRA_LDFLAGS) -lm
 
 
 SRCS = main.c          \
+       conf_gfx.c      \
+       conf_snd.c      \
        init.c          \
        config.c        \
        events.c        \
@@ -136,6 +140,8 @@ SRCS =      main.c          \
        netserv.c
 
 OBJS = main.o          \
+       conf_gfx.o      \
+       conf_snd.o      \
        init.o          \
        config.o        \
        events.o        \
@@ -149,6 +155,19 @@ OBJS =     main.o          \
        network.o       \
        netserv.o
 
+CNFS = conf_gfx.h      \
+       conf_snd.h      \
+       conf_chr.c      \
+       conf_chr.h      \
+       conf_cus.c      \
+       conf_cus.h      \
+       conf_e2g.c      \
+       conf_esg.c      \
+       conf_e2s.c      \
+       conf_fnt.c
+
+CNFS_CMD = ../Scripts/create_element_defs.pl
+
 TIMESTAMP_FILE = conftime.h
 
 LIBDIR = libgame
@@ -171,6 +190,18 @@ libgame_dir:
 $(LIBGAME):
        @$(MAKE) -C $(LIBDIR)
 
+auto-conf:
+       @for i in $(CNFS); do                   \
+               echo "$(CNFS_CMD) $$i > $$i";   \
+               $(CNFS_CMD) $$i > $$i;          \
+       done
+
+conf_gfx.h: conf_gfx.c
+       @$(MAKE) auto-conf
+
+conf_snd.h: conf_snd.c
+       @$(MAKE) auto-conf
+
 $(TIMESTAMP_FILE): $(SRCS) $(LIBGAME)
        @date '+"[%Y-%m-%d %H:%M]"' \
        | sed -e 's/^/#define COMPILE_DATE_STRING /' \
index e97005dd9635a51e17fd5109c2c4ee41d62b474f..5bacdf29c3aad8c6dcd3d1e6c3984617d3a92a87 100644 (file)
 
 
 /* values for toon definition */
-#define NUM_TOONS      18
+#define MAX_NUM_TOONS                  20
 
-#define DWARF_XSIZE    40
-#define DWARF_YSIZE    48
-#define DWARF_X                2
-#define DWARF_Y                72
-#define DWARF2_Y       186
-#define DWARF_FRAMES   8
-#define DWARF_FPS      10
-#define DWARF_STEPSIZE 4
-#define JUMPER_XSIZE   48
-#define JUMPER_YSIZE   56
-#define JUMPER_X       2
-#define JUMPER_Y       125
-#define JUMPER_FRAMES  8
-#define JUMPER_FPS     10
-#define JUMPER_STEPSIZE        4
-#define CLOWN_XSIZE    80
-#define CLOWN_YSIZE    110
-#define CLOWN_X                327
-#define CLOWN_Y                10
-#define CLOWN_FRAMES   1
-#define CLOWN_FPS      10
-#define CLOWN_STEPSIZE 4
-#define BIRD_XSIZE     32
-#define BIRD_YSIZE     30
-#define BIRD1_X                2
-#define BIRD1_Y                2
-#define BIRD2_X                2
-#define BIRD2_Y                37
-#define BIRD_FRAMES    8
-#define BIRD_FPS       20
-#define BIRD_STEPSIZE  4
-
-#define GAMETOON_XSIZE         TILEX
-#define GAMETOON_YSIZE         TILEY
-#define GAMETOON_FRAMES_4      4
-#define GAMETOON_FRAMES_8      8
-#define GAMETOON_FPS           20
-#define GAMETOON_STEPSIZE      4
-
-struct ToonInfo toons[NUM_TOONS] =
-{
-  {
-    PIX_TOONS,
-    DWARF_XSIZE, DWARF_YSIZE,
-    DWARF_X, DWARF_Y,
-    DWARF_FRAMES,
-    DWARF_FPS,
-    DWARF_STEPSIZE,
-    ANIM_NORMAL,
-    ANIMDIR_RIGHT,
-    ANIMPOS_DOWN
-  },
-  {
-    PIX_TOONS,
-    DWARF_XSIZE, DWARF_YSIZE,
-    DWARF_X, DWARF2_Y,
-    DWARF_FRAMES,
-    DWARF_FPS,
-    DWARF_STEPSIZE,
-    ANIM_NORMAL,
-    ANIMDIR_LEFT,
-    ANIMPOS_DOWN
-  },
-  {
-    PIX_TOONS,
-    JUMPER_XSIZE, JUMPER_YSIZE,
-    JUMPER_X, JUMPER_Y,
-    JUMPER_FRAMES,
-    JUMPER_FPS,
-    JUMPER_STEPSIZE,
-    ANIM_NORMAL,
-    ANIMDIR_RIGHT,
-    ANIMPOS_DOWN
-  },
-  {
-    PIX_TOONS,
-    CLOWN_XSIZE, CLOWN_YSIZE,
-    CLOWN_X, CLOWN_Y,
-    CLOWN_FRAMES,
-    CLOWN_FPS,
-    CLOWN_STEPSIZE,
-    ANIM_NORMAL,
-    ANIMDIR_UP,
-    ANIMPOS_ANY
-  },
-  {
-    PIX_TOONS,
-    BIRD_XSIZE, BIRD_YSIZE,
-    BIRD1_X, BIRD1_Y,
-    BIRD_FRAMES,
-    BIRD_FPS,
-    BIRD_STEPSIZE,
-    ANIM_OSCILLATE,
-    ANIMDIR_RIGHT,
-    ANIMPOS_UPPER
-  },
-  {
-    PIX_TOONS,
-    BIRD_XSIZE, BIRD_YSIZE,
-    BIRD2_X, BIRD2_Y,
-    BIRD_FRAMES,
-    BIRD_FPS,
-    BIRD_STEPSIZE,
-    ANIM_OSCILLATE,
-    ANIMDIR_LEFT,
-    ANIMPOS_UPPER
-  },
-  {
-    PIX_HEROES,
-    GAMETOON_XSIZE, GAMETOON_YSIZE,
-    ((GFX_SPIELER1_LEFT - GFX_START_ROCKSHEROES) % HEROES_PER_LINE)*TILEX,
-    ((GFX_SPIELER1_LEFT - GFX_START_ROCKSHEROES) / HEROES_PER_LINE)*TILEY,
-    GAMETOON_FRAMES_4,
-    GAMETOON_FPS,
-    GAMETOON_STEPSIZE,
-    ANIM_NORMAL,
-    ANIMDIR_LEFT,
-    ANIMPOS_DOWN
-  },
-  {
-    PIX_HEROES,
-    GAMETOON_XSIZE, GAMETOON_YSIZE,
-    ((GFX_SPIELER1_RIGHT - GFX_START_ROCKSHEROES) % HEROES_PER_LINE)*TILEX,
-    ((GFX_SPIELER1_RIGHT - GFX_START_ROCKSHEROES) / HEROES_PER_LINE)*TILEY,
-    GAMETOON_FRAMES_4,
-    GAMETOON_FPS,
-    GAMETOON_STEPSIZE,
-    ANIM_NORMAL,
-    ANIMDIR_RIGHT,
-    ANIMPOS_DOWN
-  },
-  {
-    PIX_HEROES,
-    GAMETOON_XSIZE, GAMETOON_YSIZE,
-    ((GFX_PINGUIN_LEFT - GFX_START_ROCKSHEROES) % HEROES_PER_LINE)*TILEX,
-    ((GFX_PINGUIN_LEFT - GFX_START_ROCKSHEROES) / HEROES_PER_LINE)*TILEY,
-    GAMETOON_FRAMES_4,
-    GAMETOON_FPS,
-    GAMETOON_STEPSIZE,
-    ANIM_NORMAL,
-    ANIMDIR_LEFT,
-    ANIMPOS_DOWN
-  },
-  {
-    PIX_HEROES,
-    GAMETOON_XSIZE, GAMETOON_YSIZE,
-    ((GFX_PINGUIN_RIGHT - GFX_START_ROCKSHEROES) % HEROES_PER_LINE)*TILEX,
-    ((GFX_PINGUIN_RIGHT - GFX_START_ROCKSHEROES) / HEROES_PER_LINE)*TILEY,
-    GAMETOON_FRAMES_4,
-    GAMETOON_FPS,
-    GAMETOON_STEPSIZE,
-    ANIM_NORMAL,
-    ANIMDIR_RIGHT,
-    ANIMPOS_DOWN
-  },
-  {
-    PIX_HEROES,
-    GAMETOON_XSIZE, GAMETOON_YSIZE,
-    ((GFX_MOLE_LEFT - GFX_START_ROCKSHEROES) % HEROES_PER_LINE)*TILEX,
-    ((GFX_MOLE_LEFT - GFX_START_ROCKSHEROES) / HEROES_PER_LINE)*TILEY,
-    GAMETOON_FRAMES_4,
-    GAMETOON_FPS,
-    GAMETOON_STEPSIZE,
-    ANIM_NORMAL,
-    ANIMDIR_LEFT,
-    ANIMPOS_DOWN
-  },
-  {
-    PIX_HEROES,
-    GAMETOON_XSIZE, GAMETOON_YSIZE,
-    ((GFX_MOLE_RIGHT - GFX_START_ROCKSHEROES) % HEROES_PER_LINE)*TILEX,
-    ((GFX_MOLE_RIGHT - GFX_START_ROCKSHEROES) / HEROES_PER_LINE)*TILEY,
-    GAMETOON_FRAMES_4,
-    GAMETOON_FPS,
-    GAMETOON_STEPSIZE,
-    ANIM_NORMAL,
-    ANIMDIR_RIGHT,
-    ANIMPOS_DOWN
-  },
-  {
-    PIX_HEROES,
-    GAMETOON_XSIZE, GAMETOON_YSIZE,
-    ((GFX_SCHWEIN_LEFT - GFX_START_ROCKSHEROES) % HEROES_PER_LINE)*TILEX,
-    ((GFX_SCHWEIN_LEFT - GFX_START_ROCKSHEROES) / HEROES_PER_LINE)*TILEY,
-    GAMETOON_FRAMES_4,
-    GAMETOON_FPS,
-    GAMETOON_STEPSIZE,
-    ANIM_NORMAL,
-    ANIMDIR_LEFT,
-    ANIMPOS_DOWN
-  },
-  {
-    PIX_HEROES,
-    GAMETOON_XSIZE, GAMETOON_YSIZE,
-    ((GFX_SCHWEIN_RIGHT - GFX_START_ROCKSHEROES) % HEROES_PER_LINE)*TILEX,
-    ((GFX_SCHWEIN_RIGHT - GFX_START_ROCKSHEROES) / HEROES_PER_LINE)*TILEY,
-    GAMETOON_FRAMES_4,
-    GAMETOON_FPS,
-    GAMETOON_STEPSIZE,
-    ANIM_NORMAL,
-    ANIMDIR_RIGHT,
-    ANIMPOS_DOWN
-  },
-  {
-    PIX_HEROES,
-    GAMETOON_XSIZE, GAMETOON_YSIZE,
-    ((GFX_DRACHE_LEFT - GFX_START_ROCKSHEROES) % HEROES_PER_LINE)*TILEX,
-    ((GFX_DRACHE_LEFT - GFX_START_ROCKSHEROES) / HEROES_PER_LINE)*TILEY,
-    GAMETOON_FRAMES_4,
-    GAMETOON_FPS,
-    GAMETOON_STEPSIZE,
-    ANIM_NORMAL,
-    ANIMDIR_LEFT,
-    ANIMPOS_DOWN
-  },
-  {
-    PIX_HEROES,
-    GAMETOON_XSIZE, GAMETOON_YSIZE,
-    ((GFX_DRACHE_RIGHT - GFX_START_ROCKSHEROES) % HEROES_PER_LINE)*TILEX,
-    ((GFX_DRACHE_RIGHT - GFX_START_ROCKSHEROES) / HEROES_PER_LINE)*TILEY,
-    GAMETOON_FRAMES_4,
-    GAMETOON_FPS,
-    GAMETOON_STEPSIZE,
-    ANIM_NORMAL,
-    ANIMDIR_RIGHT,
-    ANIMPOS_DOWN
-  },
-  {
-    PIX_HEROES,
-    GAMETOON_XSIZE, GAMETOON_YSIZE,
-    ((GFX_SONDE - GFX_START_ROCKSHEROES) % HEROES_PER_LINE)*TILEX,
-    ((GFX_SONDE - GFX_START_ROCKSHEROES) / HEROES_PER_LINE)*TILEY,
-    GAMETOON_FRAMES_8,
-    GAMETOON_FPS,
-    GAMETOON_STEPSIZE,
-    ANIM_NORMAL,
-    ANIMDIR_LEFT,
-    ANIMPOS_ANY
-  },
-  {
-    PIX_HEROES,
-    GAMETOON_XSIZE, GAMETOON_YSIZE,
-    ((GFX_SONDE - GFX_START_ROCKSHEROES) % HEROES_PER_LINE)*TILEX,
-    ((GFX_SONDE - GFX_START_ROCKSHEROES) / HEROES_PER_LINE)*TILEY,
-    GAMETOON_FRAMES_8,
-    GAMETOON_FPS,
-    GAMETOON_STEPSIZE,
-    ANIM_NORMAL,
-    ANIMDIR_RIGHT,
-    ANIMPOS_ANY
-  },
-};
+static struct ToonInfo toons[MAX_NUM_TOONS];
 
 static void PrepareBackbuffer()
 {
   /* Fill empty backbuffer for animation functions */
-  if (setup.direct_draw && game_status == PLAYING)
+  if (setup.direct_draw && game_status == GAME_MODE_PLAYING)
   {
     int xx,yy;
 
@@ -289,7 +38,7 @@ static void PrepareBackbuffer()
     SetDrawtoField(DRAW_DIRECT);
   }
 
-  if (setup.soft_scrolling && game_status == PLAYING)
+  if (setup.soft_scrolling && game_status == GAME_MODE_PLAYING)
   {
     int fx = FX, fy = FY;
 
@@ -302,16 +51,48 @@ static void PrepareBackbuffer()
 
 boolean ToonNeedsRedraw()
 {
-  return (game_status == HELPSCREEN ||
-         (game_status == MAINMENU &&
+  return (game_status == GAME_MODE_INFO ||
+         (game_status == GAME_MODE_MAIN &&
           ((redraw_mask & REDRAW_MICROLEVEL) ||
            (redraw_mask & REDRAW_MICROLABEL))));
 }
 
 void InitToons()
 {
-  InitToonScreen(pix, pix[PIX_DB_DOOR],
+  int num_toons = MAX_NUM_TOONS;
+  int i;
+
+  if (global.num_toons > 0 && global.num_toons < MAX_NUM_TOONS)
+    num_toons = global.num_toons;
+
+  for (i=0; i < num_toons; i++)
+  {
+    int graphic = IMG_TOON_1 + i;
+    struct FileInfo *image = getImageListEntry(graphic);
+
+    toons[i].bitmap = graphic_info[graphic].bitmap;
+
+    toons[i].src_x = graphic_info[graphic].src_x;
+    toons[i].src_y = graphic_info[graphic].src_y;
+
+    toons[i].width  = graphic_info[graphic].width;
+    toons[i].height = graphic_info[graphic].height;
+
+    toons[i].anim_frames      = graphic_info[graphic].anim_frames;
+    toons[i].anim_delay       = graphic_info[graphic].anim_delay;
+    toons[i].anim_mode        = graphic_info[graphic].anim_mode;
+    toons[i].anim_start_frame = graphic_info[graphic].anim_start_frame;
+
+    toons[i].step_offset = graphic_info[graphic].step_offset;
+    toons[i].step_delay  = graphic_info[graphic].step_delay;
+
+    toons[i].direction = image->parameter[GFX_ARG_DIRECTION];
+    toons[i].position = image->parameter[GFX_ARG_POSITION];
+  }
+
+  InitToonScreen(bitmap_db_door,
                 BackToFront, PrepareBackbuffer, ToonNeedsRedraw,
-                toons, NUM_TOONS,
-                REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE);
+                toons, num_toons,
+                REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE,
+                GAME_FRAME_DELAY);
 }
diff --git a/src/conf_chr.c b/src/conf_chr.c
new file mode 100644 (file)
index 0000000..506c8b2
--- /dev/null
@@ -0,0 +1,377 @@
+/***********************************************************
+* Rocks'n'Diamonds -- McDuffin Strikes Back!               *
+*----------------------------------------------------------*
+* (c) 1995-2002 Artsoft Entertainment                      *
+*               Holger Schemel                             *
+*               Detmolder Strasse 189                      *
+*               33604 Bielefeld                            *
+*               Germany                                    *
+*               e-mail: info@artsoft.org                   *
+*----------------------------------------------------------*
+* conf_chr.c                                               *
+***********************************************************/
+
+/* ----- this file was automatically generated -- do not edit by hand ----- */
+
+#ifndef CONF_CHR_C
+#define CONF_CHR_C
+
+/* values for graphics configuration (character elements) */
+
+  { "char_space",                              "RocksFontEM.pcx"       },
+  { "char_space.xpos",                         "0"                     },
+  { "char_space.ypos",                         "0"                     },
+  { "char_space.frames",                       "1"                     },
+
+  { "char_exclam",                             "RocksFontEM.pcx"       },
+  { "char_exclam.xpos",                                "1"                     },
+  { "char_exclam.ypos",                                "0"                     },
+  { "char_exclam.frames",                      "1"                     },
+
+  { "char_quotedbl",                           "RocksFontEM.pcx"       },
+  { "char_quotedbl.xpos",                      "2"                     },
+  { "char_quotedbl.ypos",                      "0"                     },
+  { "char_quotedbl.frames",                    "1"                     },
+
+  { "char_numbersign",                         "RocksFontEM.pcx"       },
+  { "char_numbersign.xpos",                    "3"                     },
+  { "char_numbersign.ypos",                    "0"                     },
+  { "char_numbersign.frames",                  "1"                     },
+
+  { "char_dollar",                             "RocksFontEM.pcx"       },
+  { "char_dollar.xpos",                                "4"                     },
+  { "char_dollar.ypos",                                "0"                     },
+  { "char_dollar.frames",                      "1"                     },
+
+  { "char_procent",                            "RocksFontEM.pcx"       },
+  { "char_procent.xpos",                       "5"                     },
+  { "char_procent.ypos",                       "0"                     },
+  { "char_procent.frames",                     "1"                     },
+
+  { "char_ampersand",                          "RocksFontEM.pcx"       },
+  { "char_ampersand.xpos",                     "6"                     },
+  { "char_ampersand.ypos",                     "0"                     },
+  { "char_ampersand.frames",                   "1"                     },
+
+  { "char_apostrophe",                         "RocksFontEM.pcx"       },
+  { "char_apostrophe.xpos",                    "7"                     },
+  { "char_apostrophe.ypos",                    "0"                     },
+  { "char_apostrophe.frames",                  "1"                     },
+
+  { "char_parenleft",                          "RocksFontEM.pcx"       },
+  { "char_parenleft.xpos",                     "8"                     },
+  { "char_parenleft.ypos",                     "0"                     },
+  { "char_parenleft.frames",                   "1"                     },
+
+  { "char_parenright",                         "RocksFontEM.pcx"       },
+  { "char_parenright.xpos",                    "9"                     },
+  { "char_parenright.ypos",                    "0"                     },
+  { "char_parenright.frames",                  "1"                     },
+
+  { "char_asterisk",                           "RocksFontEM.pcx"       },
+  { "char_asterisk.xpos",                      "10"                    },
+  { "char_asterisk.ypos",                      "0"                     },
+  { "char_asterisk.frames",                    "1"                     },
+
+  { "char_plus",                               "RocksFontEM.pcx"       },
+  { "char_plus.xpos",                          "11"                    },
+  { "char_plus.ypos",                          "0"                     },
+  { "char_plus.frames",                                "1"                     },
+
+  { "char_comma",                              "RocksFontEM.pcx"       },
+  { "char_comma.xpos",                         "12"                    },
+  { "char_comma.ypos",                         "0"                     },
+  { "char_comma.frames",                       "1"                     },
+
+  { "char_minus",                              "RocksFontEM.pcx"       },
+  { "char_minus.xpos",                         "13"                    },
+  { "char_minus.ypos",                         "0"                     },
+  { "char_minus.frames",                       "1"                     },
+
+  { "char_period",                             "RocksFontEM.pcx"       },
+  { "char_period.xpos",                                "14"                    },
+  { "char_period.ypos",                                "0"                     },
+  { "char_period.frames",                      "1"                     },
+
+  { "char_slash",                              "RocksFontEM.pcx"       },
+  { "char_slash.xpos",                         "15"                    },
+  { "char_slash.ypos",                         "0"                     },
+  { "char_slash.frames",                       "1"                     },
+
+  { "char_0",                                  "RocksFontEM.pcx"       },
+  { "char_0.xpos",                             "0"                     },
+  { "char_0.ypos",                             "1"                     },
+  { "char_0.frames",                           "1"                     },
+
+  { "char_1",                                  "RocksFontEM.pcx"       },
+  { "char_1.xpos",                             "1"                     },
+  { "char_1.ypos",                             "1"                     },
+  { "char_1.frames",                           "1"                     },
+
+  { "char_2",                                  "RocksFontEM.pcx"       },
+  { "char_2.xpos",                             "2"                     },
+  { "char_2.ypos",                             "1"                     },
+  { "char_2.frames",                           "1"                     },
+
+  { "char_3",                                  "RocksFontEM.pcx"       },
+  { "char_3.xpos",                             "3"                     },
+  { "char_3.ypos",                             "1"                     },
+  { "char_3.frames",                           "1"                     },
+
+  { "char_4",                                  "RocksFontEM.pcx"       },
+  { "char_4.xpos",                             "4"                     },
+  { "char_4.ypos",                             "1"                     },
+  { "char_4.frames",                           "1"                     },
+
+  { "char_5",                                  "RocksFontEM.pcx"       },
+  { "char_5.xpos",                             "5"                     },
+  { "char_5.ypos",                             "1"                     },
+  { "char_5.frames",                           "1"                     },
+
+  { "char_6",                                  "RocksFontEM.pcx"       },
+  { "char_6.xpos",                             "6"                     },
+  { "char_6.ypos",                             "1"                     },
+  { "char_6.frames",                           "1"                     },
+
+  { "char_7",                                  "RocksFontEM.pcx"       },
+  { "char_7.xpos",                             "7"                     },
+  { "char_7.ypos",                             "1"                     },
+  { "char_7.frames",                           "1"                     },
+
+  { "char_8",                                  "RocksFontEM.pcx"       },
+  { "char_8.xpos",                             "8"                     },
+  { "char_8.ypos",                             "1"                     },
+  { "char_8.frames",                           "1"                     },
+
+  { "char_9",                                  "RocksFontEM.pcx"       },
+  { "char_9.xpos",                             "9"                     },
+  { "char_9.ypos",                             "1"                     },
+  { "char_9.frames",                           "1"                     },
+
+  { "char_colon",                              "RocksFontEM.pcx"       },
+  { "char_colon.xpos",                         "10"                    },
+  { "char_colon.ypos",                         "1"                     },
+  { "char_colon.frames",                       "1"                     },
+
+  { "char_semicolon",                          "RocksFontEM.pcx"       },
+  { "char_semicolon.xpos",                     "11"                    },
+  { "char_semicolon.ypos",                     "1"                     },
+  { "char_semicolon.frames",                   "1"                     },
+
+  { "char_less",                               "RocksFontEM.pcx"       },
+  { "char_less.xpos",                          "12"                    },
+  { "char_less.ypos",                          "1"                     },
+  { "char_less.frames",                                "1"                     },
+
+  { "char_equal",                              "RocksFontEM.pcx"       },
+  { "char_equal.xpos",                         "13"                    },
+  { "char_equal.ypos",                         "1"                     },
+  { "char_equal.frames",                       "1"                     },
+
+  { "char_greater",                            "RocksFontEM.pcx"       },
+  { "char_greater.xpos",                       "14"                    },
+  { "char_greater.ypos",                       "1"                     },
+  { "char_greater.frames",                     "1"                     },
+
+  { "char_question",                           "RocksFontEM.pcx"       },
+  { "char_question.xpos",                      "15"                    },
+  { "char_question.ypos",                      "1"                     },
+  { "char_question.frames",                    "1"                     },
+
+  { "char_at",                                 "RocksFontEM.pcx"       },
+  { "char_at.xpos",                            "0"                     },
+  { "char_at.ypos",                            "2"                     },
+  { "char_at.frames",                          "1"                     },
+
+  { "char_a",                                  "RocksFontEM.pcx"       },
+  { "char_a.xpos",                             "1"                     },
+  { "char_a.ypos",                             "2"                     },
+  { "char_a.frames",                           "1"                     },
+
+  { "char_b",                                  "RocksFontEM.pcx"       },
+  { "char_b.xpos",                             "2"                     },
+  { "char_b.ypos",                             "2"                     },
+  { "char_b.frames",                           "1"                     },
+
+  { "char_c",                                  "RocksFontEM.pcx"       },
+  { "char_c.xpos",                             "3"                     },
+  { "char_c.ypos",                             "2"                     },
+  { "char_c.frames",                           "1"                     },
+
+  { "char_d",                                  "RocksFontEM.pcx"       },
+  { "char_d.xpos",                             "4"                     },
+  { "char_d.ypos",                             "2"                     },
+  { "char_d.frames",                           "1"                     },
+
+  { "char_e",                                  "RocksFontEM.pcx"       },
+  { "char_e.xpos",                             "5"                     },
+  { "char_e.ypos",                             "2"                     },
+  { "char_e.frames",                           "1"                     },
+
+  { "char_f",                                  "RocksFontEM.pcx"       },
+  { "char_f.xpos",                             "6"                     },
+  { "char_f.ypos",                             "2"                     },
+  { "char_f.frames",                           "1"                     },
+
+  { "char_g",                                  "RocksFontEM.pcx"       },
+  { "char_g.xpos",                             "7"                     },
+  { "char_g.ypos",                             "2"                     },
+  { "char_g.frames",                           "1"                     },
+
+  { "char_h",                                  "RocksFontEM.pcx"       },
+  { "char_h.xpos",                             "8"                     },
+  { "char_h.ypos",                             "2"                     },
+  { "char_h.frames",                           "1"                     },
+
+  { "char_i",                                  "RocksFontEM.pcx"       },
+  { "char_i.xpos",                             "9"                     },
+  { "char_i.ypos",                             "2"                     },
+  { "char_i.frames",                           "1"                     },
+
+  { "char_j",                                  "RocksFontEM.pcx"       },
+  { "char_j.xpos",                             "10"                    },
+  { "char_j.ypos",                             "2"                     },
+  { "char_j.frames",                           "1"                     },
+
+  { "char_k",                                  "RocksFontEM.pcx"       },
+  { "char_k.xpos",                             "11"                    },
+  { "char_k.ypos",                             "2"                     },
+  { "char_k.frames",                           "1"                     },
+
+  { "char_l",                                  "RocksFontEM.pcx"       },
+  { "char_l.xpos",                             "12"                    },
+  { "char_l.ypos",                             "2"                     },
+  { "char_l.frames",                           "1"                     },
+
+  { "char_m",                                  "RocksFontEM.pcx"       },
+  { "char_m.xpos",                             "13"                    },
+  { "char_m.ypos",                             "2"                     },
+  { "char_m.frames",                           "1"                     },
+
+  { "char_n",                                  "RocksFontEM.pcx"       },
+  { "char_n.xpos",                             "14"                    },
+  { "char_n.ypos",                             "2"                     },
+  { "char_n.frames",                           "1"                     },
+
+  { "char_o",                                  "RocksFontEM.pcx"       },
+  { "char_o.xpos",                             "15"                    },
+  { "char_o.ypos",                             "2"                     },
+  { "char_o.frames",                           "1"                     },
+
+  { "char_p",                                  "RocksFontEM.pcx"       },
+  { "char_p.xpos",                             "0"                     },
+  { "char_p.ypos",                             "3"                     },
+  { "char_p.frames",                           "1"                     },
+
+  { "char_q",                                  "RocksFontEM.pcx"       },
+  { "char_q.xpos",                             "1"                     },
+  { "char_q.ypos",                             "3"                     },
+  { "char_q.frames",                           "1"                     },
+
+  { "char_r",                                  "RocksFontEM.pcx"       },
+  { "char_r.xpos",                             "2"                     },
+  { "char_r.ypos",                             "3"                     },
+  { "char_r.frames",                           "1"                     },
+
+  { "char_s",                                  "RocksFontEM.pcx"       },
+  { "char_s.xpos",                             "3"                     },
+  { "char_s.ypos",                             "3"                     },
+  { "char_s.frames",                           "1"                     },
+
+  { "char_t",                                  "RocksFontEM.pcx"       },
+  { "char_t.xpos",                             "4"                     },
+  { "char_t.ypos",                             "3"                     },
+  { "char_t.frames",                           "1"                     },
+
+  { "char_u",                                  "RocksFontEM.pcx"       },
+  { "char_u.xpos",                             "5"                     },
+  { "char_u.ypos",                             "3"                     },
+  { "char_u.frames",                           "1"                     },
+
+  { "char_v",                                  "RocksFontEM.pcx"       },
+  { "char_v.xpos",                             "6"                     },
+  { "char_v.ypos",                             "3"                     },
+  { "char_v.frames",                           "1"                     },
+
+  { "char_w",                                  "RocksFontEM.pcx"       },
+  { "char_w.xpos",                             "7"                     },
+  { "char_w.ypos",                             "3"                     },
+  { "char_w.frames",                           "1"                     },
+
+  { "char_x",                                  "RocksFontEM.pcx"       },
+  { "char_x.xpos",                             "8"                     },
+  { "char_x.ypos",                             "3"                     },
+  { "char_x.frames",                           "1"                     },
+
+  { "char_y",                                  "RocksFontEM.pcx"       },
+  { "char_y.xpos",                             "9"                     },
+  { "char_y.ypos",                             "3"                     },
+  { "char_y.frames",                           "1"                     },
+
+  { "char_z",                                  "RocksFontEM.pcx"       },
+  { "char_z.xpos",                             "10"                    },
+  { "char_z.ypos",                             "3"                     },
+  { "char_z.frames",                           "1"                     },
+
+  { "char_bracketleft",                                "RocksFontEM.pcx"       },
+  { "char_bracketleft.xpos",                   "11"                    },
+  { "char_bracketleft.ypos",                   "3"                     },
+  { "char_bracketleft.frames",                 "1"                     },
+
+  { "char_backslash",                          "RocksFontEM.pcx"       },
+  { "char_backslash.xpos",                     "12"                    },
+  { "char_backslash.ypos",                     "3"                     },
+  { "char_backslash.frames",                   "1"                     },
+
+  { "char_bracketright",                       "RocksFontEM.pcx"       },
+  { "char_bracketright.xpos",                  "13"                    },
+  { "char_bracketright.ypos",                  "3"                     },
+  { "char_bracketright.frames",                        "1"                     },
+
+  { "char_asciicircum",                                "RocksFontEM.pcx"       },
+  { "char_asciicircum.xpos",                   "14"                    },
+  { "char_asciicircum.ypos",                   "3"                     },
+  { "char_asciicircum.frames",                 "1"                     },
+
+  { "char_underscore",                         "RocksFontEM.pcx"       },
+  { "char_underscore.xpos",                    "15"                    },
+  { "char_underscore.ypos",                    "3"                     },
+  { "char_underscore.frames",                  "1"                     },
+
+  { "char_copyright",                          "RocksFontEM.pcx"       },
+  { "char_copyright.xpos",                     "0"                     },
+  { "char_copyright.ypos",                     "4"                     },
+  { "char_copyright.frames",                   "1"                     },
+
+  { "char_aumlaut",                            "RocksFontEM.pcx"       },
+  { "char_aumlaut.xpos",                       "1"                     },
+  { "char_aumlaut.ypos",                       "4"                     },
+  { "char_aumlaut.frames",                     "1"                     },
+
+  { "char_oumlaut",                            "RocksFontEM.pcx"       },
+  { "char_oumlaut.xpos",                       "2"                     },
+  { "char_oumlaut.ypos",                       "4"                     },
+  { "char_oumlaut.frames",                     "1"                     },
+
+  { "char_uumlaut",                            "RocksFontEM.pcx"       },
+  { "char_uumlaut.xpos",                       "3"                     },
+  { "char_uumlaut.ypos",                       "4"                     },
+  { "char_uumlaut.frames",                     "1"                     },
+
+  { "char_degree",                             "RocksFontEM.pcx"       },
+  { "char_degree.xpos",                                "4"                     },
+  { "char_degree.ypos",                                "4"                     },
+  { "char_degree.frames",                      "1"                     },
+
+  { "char_trademark",                          "RocksFontEM.pcx"       },
+  { "char_trademark.xpos",                     "5"                     },
+  { "char_trademark.ypos",                     "4"                     },
+  { "char_trademark.frames",                   "1"                     },
+
+  { "char_cursor",                             "RocksFontEM.pcx"       },
+  { "char_cursor.xpos",                                "6"                     },
+  { "char_cursor.ypos",                                "4"                     },
+  { "char_cursor.frames",                      "1"                     },
+
+
+#endif /* CONF_CHR_C */
diff --git a/src/conf_chr.h b/src/conf_chr.h
new file mode 100644 (file)
index 0000000..8cee272
--- /dev/null
@@ -0,0 +1,93 @@
+/***********************************************************
+* Rocks'n'Diamonds -- McDuffin Strikes Back!               *
+*----------------------------------------------------------*
+* (c) 1995-2002 Artsoft Entertainment                      *
+*               Holger Schemel                             *
+*               Detmolder Strasse 189                      *
+*               33604 Bielefeld                            *
+*               Germany                                    *
+*               e-mail: info@artsoft.org                   *
+*----------------------------------------------------------*
+* conf_chr.h                                               *
+***********************************************************/
+
+/* ----- this file was automatically generated -- do not edit by hand ----- */
+
+#ifndef CONF_CHR_H
+#define CONF_CHR_H
+
+/* values for elements configuration (character elements) */
+
+#define EL_CHAR_SPACE                  (EL_CHAR_ASCII0 + 32)
+#define EL_CHAR_EXCLAM                 (EL_CHAR_ASCII0 + 33)
+#define EL_CHAR_QUOTEDBL               (EL_CHAR_ASCII0 + 34)
+#define EL_CHAR_NUMBERSIGN             (EL_CHAR_ASCII0 + 35)
+#define EL_CHAR_DOLLAR                 (EL_CHAR_ASCII0 + 36)
+#define EL_CHAR_PROCENT                        (EL_CHAR_ASCII0 + 37)
+#define EL_CHAR_AMPERSAND              (EL_CHAR_ASCII0 + 38)
+#define EL_CHAR_APOSTROPHE             (EL_CHAR_ASCII0 + 39)
+#define EL_CHAR_PARENLEFT              (EL_CHAR_ASCII0 + 40)
+#define EL_CHAR_PARENRIGHT             (EL_CHAR_ASCII0 + 41)
+#define EL_CHAR_ASTERISK               (EL_CHAR_ASCII0 + 42)
+#define EL_CHAR_PLUS                   (EL_CHAR_ASCII0 + 43)
+#define EL_CHAR_COMMA                  (EL_CHAR_ASCII0 + 44)
+#define EL_CHAR_MINUS                  (EL_CHAR_ASCII0 + 45)
+#define EL_CHAR_PERIOD                 (EL_CHAR_ASCII0 + 46)
+#define EL_CHAR_SLASH                  (EL_CHAR_ASCII0 + 47)
+#define EL_CHAR_0                      (EL_CHAR_ASCII0 + 48)
+#define EL_CHAR_1                      (EL_CHAR_ASCII0 + 49)
+#define EL_CHAR_2                      (EL_CHAR_ASCII0 + 50)
+#define EL_CHAR_3                      (EL_CHAR_ASCII0 + 51)
+#define EL_CHAR_4                      (EL_CHAR_ASCII0 + 52)
+#define EL_CHAR_5                      (EL_CHAR_ASCII0 + 53)
+#define EL_CHAR_6                      (EL_CHAR_ASCII0 + 54)
+#define EL_CHAR_7                      (EL_CHAR_ASCII0 + 55)
+#define EL_CHAR_8                      (EL_CHAR_ASCII0 + 56)
+#define EL_CHAR_9                      (EL_CHAR_ASCII0 + 57)
+#define EL_CHAR_COLON                  (EL_CHAR_ASCII0 + 58)
+#define EL_CHAR_SEMICOLON              (EL_CHAR_ASCII0 + 59)
+#define EL_CHAR_LESS                   (EL_CHAR_ASCII0 + 60)
+#define EL_CHAR_EQUAL                  (EL_CHAR_ASCII0 + 61)
+#define EL_CHAR_GREATER                        (EL_CHAR_ASCII0 + 62)
+#define EL_CHAR_QUESTION               (EL_CHAR_ASCII0 + 63)
+#define EL_CHAR_AT                     (EL_CHAR_ASCII0 + 64)
+#define EL_CHAR_A                      (EL_CHAR_ASCII0 + 65)
+#define EL_CHAR_B                      (EL_CHAR_ASCII0 + 66)
+#define EL_CHAR_C                      (EL_CHAR_ASCII0 + 67)
+#define EL_CHAR_D                      (EL_CHAR_ASCII0 + 68)
+#define EL_CHAR_E                      (EL_CHAR_ASCII0 + 69)
+#define EL_CHAR_F                      (EL_CHAR_ASCII0 + 70)
+#define EL_CHAR_G                      (EL_CHAR_ASCII0 + 71)
+#define EL_CHAR_H                      (EL_CHAR_ASCII0 + 72)
+#define EL_CHAR_I                      (EL_CHAR_ASCII0 + 73)
+#define EL_CHAR_J                      (EL_CHAR_ASCII0 + 74)
+#define EL_CHAR_K                      (EL_CHAR_ASCII0 + 75)
+#define EL_CHAR_L                      (EL_CHAR_ASCII0 + 76)
+#define EL_CHAR_M                      (EL_CHAR_ASCII0 + 77)
+#define EL_CHAR_N                      (EL_CHAR_ASCII0 + 78)
+#define EL_CHAR_O                      (EL_CHAR_ASCII0 + 79)
+#define EL_CHAR_P                      (EL_CHAR_ASCII0 + 80)
+#define EL_CHAR_Q                      (EL_CHAR_ASCII0 + 81)
+#define EL_CHAR_R                      (EL_CHAR_ASCII0 + 82)
+#define EL_CHAR_S                      (EL_CHAR_ASCII0 + 83)
+#define EL_CHAR_T                      (EL_CHAR_ASCII0 + 84)
+#define EL_CHAR_U                      (EL_CHAR_ASCII0 + 85)
+#define EL_CHAR_V                      (EL_CHAR_ASCII0 + 86)
+#define EL_CHAR_W                      (EL_CHAR_ASCII0 + 87)
+#define EL_CHAR_X                      (EL_CHAR_ASCII0 + 88)
+#define EL_CHAR_Y                      (EL_CHAR_ASCII0 + 89)
+#define EL_CHAR_Z                      (EL_CHAR_ASCII0 + 90)
+#define EL_CHAR_BRACKETLEFT            (EL_CHAR_ASCII0 + 91)
+#define EL_CHAR_BACKSLASH              (EL_CHAR_ASCII0 + 92)
+#define EL_CHAR_BRACKETRIGHT           (EL_CHAR_ASCII0 + 93)
+#define EL_CHAR_ASCIICIRCUM            (EL_CHAR_ASCII0 + 94)
+#define EL_CHAR_UNDERSCORE             (EL_CHAR_ASCII0 + 95)
+#define EL_CHAR_COPYRIGHT              (EL_CHAR_ASCII0 + 96)
+#define EL_CHAR_AUMLAUT                        (EL_CHAR_ASCII0 + 97)
+#define EL_CHAR_OUMLAUT                        (EL_CHAR_ASCII0 + 98)
+#define EL_CHAR_UUMLAUT                        (EL_CHAR_ASCII0 + 99)
+#define EL_CHAR_DEGREE                 (EL_CHAR_ASCII0 + 100)
+#define EL_CHAR_TRADEMARK              (EL_CHAR_ASCII0 + 101)
+#define EL_CHAR_CURSOR                 (EL_CHAR_ASCII0 + 102)
+
+#endif /* CONF_CHR_C */
diff --git a/src/conf_cus.c b/src/conf_cus.c
new file mode 100644 (file)
index 0000000..82144cd
--- /dev/null
@@ -0,0 +1,1046 @@
+/***********************************************************
+* Rocks'n'Diamonds -- McDuffin Strikes Back!               *
+*----------------------------------------------------------*
+* (c) 1995-2002 Artsoft Entertainment                      *
+*               Holger Schemel                             *
+*               Detmolder Strasse 189                      *
+*               33604 Bielefeld                            *
+*               Germany                                    *
+*               e-mail: info@artsoft.org                   *
+*----------------------------------------------------------*
+* conf_cus.c                                               *
+***********************************************************/
+
+/* ----- this file was automatically generated -- do not edit by hand ----- */
+
+#ifndef CONF_CUS_C
+#define CONF_CUS_C
+
+/* values for graphics configuration (custom elements) */
+
+  { "custom_1",                                        "RocksElements.pcx"     },
+  { "custom_1.xpos",                           "7"                     },
+  { "custom_1.ypos",                           "9"                     },
+  { "custom_1.frames",                         "1"                     },
+  { "custom_1.EDITOR",                         "RocksElements.pcx"     },
+  { "custom_1.EDITOR.xpos",                    "15"                    },
+  { "custom_1.EDITOR.ypos",                    "13"                    },
+
+  { "custom_2",                                        "RocksElements.pcx"     },
+  { "custom_2.xpos",                           "7"                     },
+  { "custom_2.ypos",                           "9"                     },
+  { "custom_2.frames",                         "1"                     },
+  { "custom_2.EDITOR",                         "RocksElements.pcx"     },
+  { "custom_2.EDITOR.xpos",                    "15"                    },
+  { "custom_2.EDITOR.ypos",                    "13"                    },
+
+  { "custom_3",                                        "RocksElements.pcx"     },
+  { "custom_3.xpos",                           "7"                     },
+  { "custom_3.ypos",                           "9"                     },
+  { "custom_3.frames",                         "1"                     },
+  { "custom_3.EDITOR",                         "RocksElements.pcx"     },
+  { "custom_3.EDITOR.xpos",                    "15"                    },
+  { "custom_3.EDITOR.ypos",                    "13"                    },
+
+  { "custom_4",                                        "RocksElements.pcx"     },
+  { "custom_4.xpos",                           "7"                     },
+  { "custom_4.ypos",                           "9"                     },
+  { "custom_4.frames",                         "1"                     },
+  { "custom_4.EDITOR",                         "RocksElements.pcx"     },
+  { "custom_4.EDITOR.xpos",                    "15"                    },
+  { "custom_4.EDITOR.ypos",                    "13"                    },
+
+  { "custom_5",                                        "RocksElements.pcx"     },
+  { "custom_5.xpos",                           "7"                     },
+  { "custom_5.ypos",                           "9"                     },
+  { "custom_5.frames",                         "1"                     },
+  { "custom_5.EDITOR",                         "RocksElements.pcx"     },
+  { "custom_5.EDITOR.xpos",                    "15"                    },
+  { "custom_5.EDITOR.ypos",                    "13"                    },
+
+  { "custom_6",                                        "RocksElements.pcx"     },
+  { "custom_6.xpos",                           "7"                     },
+  { "custom_6.ypos",                           "9"                     },
+  { "custom_6.frames",                         "1"                     },
+  { "custom_6.EDITOR",                         "RocksElements.pcx"     },
+  { "custom_6.EDITOR.xpos",                    "15"                    },
+  { "custom_6.EDITOR.ypos",                    "13"                    },
+
+  { "custom_7",                                        "RocksElements.pcx"     },
+  { "custom_7.xpos",                           "7"                     },
+  { "custom_7.ypos",                           "9"                     },
+  { "custom_7.frames",                         "1"                     },
+  { "custom_7.EDITOR",                         "RocksElements.pcx"     },
+  { "custom_7.EDITOR.xpos",                    "15"                    },
+  { "custom_7.EDITOR.ypos",                    "13"                    },
+
+  { "custom_8",                                        "RocksElements.pcx"     },
+  { "custom_8.xpos",                           "7"                     },
+  { "custom_8.ypos",                           "9"                     },
+  { "custom_8.frames",                         "1"                     },
+  { "custom_8.EDITOR",                         "RocksElements.pcx"     },
+  { "custom_8.EDITOR.xpos",                    "15"                    },
+  { "custom_8.EDITOR.ypos",                    "13"                    },
+
+  { "custom_9",                                        "RocksElements.pcx"     },
+  { "custom_9.xpos",                           "7"                     },
+  { "custom_9.ypos",                           "9"                     },
+  { "custom_9.frames",                         "1"                     },
+  { "custom_9.EDITOR",                         "RocksElements.pcx"     },
+  { "custom_9.EDITOR.xpos",                    "15"                    },
+  { "custom_9.EDITOR.ypos",                    "13"                    },
+
+  { "custom_10",                               "RocksElements.pcx"     },
+  { "custom_10.xpos",                          "7"                     },
+  { "custom_10.ypos",                          "9"                     },
+  { "custom_10.frames",                                "1"                     },
+  { "custom_10.EDITOR",                                "RocksElements.pcx"     },
+  { "custom_10.EDITOR.xpos",                   "15"                    },
+  { "custom_10.EDITOR.ypos",                   "13"                    },
+
+  { "custom_11",                               "RocksElements.pcx"     },
+  { "custom_11.xpos",                          "7"                     },
+  { "custom_11.ypos",                          "9"                     },
+  { "custom_11.frames",                                "1"                     },
+  { "custom_11.EDITOR",                                "RocksElements.pcx"     },
+  { "custom_11.EDITOR.xpos",                   "15"                    },
+  { "custom_11.EDITOR.ypos",                   "13"                    },
+
+  { "custom_12",                               "RocksElements.pcx"     },
+  { "custom_12.xpos",                          "7"                     },
+  { "custom_12.ypos",                          "9"                     },
+  { "custom_12.frames",                                "1"                     },
+  { "custom_12.EDITOR",                                "RocksElements.pcx"     },
+  { "custom_12.EDITOR.xpos",                   "15"                    },
+  { "custom_12.EDITOR.ypos",                   "13"                    },
+
+  { "custom_13",                               "RocksElements.pcx"     },
+  { "custom_13.xpos",                          "7"                     },
+  { "custom_13.ypos",                          "9"                     },
+  { "custom_13.frames",                                "1"                     },
+  { "custom_13.EDITOR",                                "RocksElements.pcx"     },
+  { "custom_13.EDITOR.xpos",                   "15"                    },
+  { "custom_13.EDITOR.ypos",                   "13"                    },
+
+  { "custom_14",                               "RocksElements.pcx"     },
+  { "custom_14.xpos",                          "7"                     },
+  { "custom_14.ypos",                          "9"                     },
+  { "custom_14.frames",                                "1"                     },
+  { "custom_14.EDITOR",                                "RocksElements.pcx"     },
+  { "custom_14.EDITOR.xpos",                   "15"                    },
+  { "custom_14.EDITOR.ypos",                   "13"                    },
+
+  { "custom_15",                               "RocksElements.pcx"     },
+  { "custom_15.xpos",                          "7"                     },
+  { "custom_15.ypos",                          "9"                     },
+  { "custom_15.frames",                                "1"                     },
+  { "custom_15.EDITOR",                                "RocksElements.pcx"     },
+  { "custom_15.EDITOR.xpos",                   "15"                    },
+  { "custom_15.EDITOR.ypos",                   "13"                    },
+
+  { "custom_16",                               "RocksElements.pcx"     },
+  { "custom_16.xpos",                          "7"                     },
+  { "custom_16.ypos",                          "9"                     },
+  { "custom_16.frames",                                "1"                     },
+  { "custom_16.EDITOR",                                "RocksElements.pcx"     },
+  { "custom_16.EDITOR.xpos",                   "15"                    },
+  { "custom_16.EDITOR.ypos",                   "13"                    },
+
+  { "custom_17",                               "RocksElements.pcx"     },
+  { "custom_17.xpos",                          "7"                     },
+  { "custom_17.ypos",                          "9"                     },
+  { "custom_17.frames",                                "1"                     },
+  { "custom_17.EDITOR",                                "RocksElements.pcx"     },
+  { "custom_17.EDITOR.xpos",                   "15"                    },
+  { "custom_17.EDITOR.ypos",                   "13"                    },
+
+  { "custom_18",                               "RocksElements.pcx"     },
+  { "custom_18.xpos",                          "7"                     },
+  { "custom_18.ypos",                          "9"                     },
+  { "custom_18.frames",                                "1"                     },
+  { "custom_18.EDITOR",                                "RocksElements.pcx"     },
+  { "custom_18.EDITOR.xpos",                   "15"                    },
+  { "custom_18.EDITOR.ypos",                   "13"                    },
+
+  { "custom_19",                               "RocksElements.pcx"     },
+  { "custom_19.xpos",                          "7"                     },
+  { "custom_19.ypos",                          "9"                     },
+  { "custom_19.frames",                                "1"                     },
+  { "custom_19.EDITOR",                                "RocksElements.pcx"     },
+  { "custom_19.EDITOR.xpos",                   "15"                    },
+  { "custom_19.EDITOR.ypos",                   "13"                    },
+
+  { "custom_20",                               "RocksElements.pcx"     },
+  { "custom_20.xpos",                          "7"                     },
+  { "custom_20.ypos",                          "9"                     },
+  { "custom_20.frames",                                "1"                     },
+  { "custom_20.EDITOR",                                "RocksElements.pcx"     },
+  { "custom_20.EDITOR.xpos",                   "15"                    },
+  { "custom_20.EDITOR.ypos",                   "13"                    },
+
+  { "custom_21",                               "RocksElements.pcx"     },
+  { "custom_21.xpos",                          "7"                     },
+  { "custom_21.ypos",                          "9"                     },
+  { "custom_21.frames",                                "1"                     },
+  { "custom_21.EDITOR",                                "RocksElements.pcx"     },
+  { "custom_21.EDITOR.xpos",                   "15"                    },
+  { "custom_21.EDITOR.ypos",                   "13"                    },
+
+  { "custom_22",                               "RocksElements.pcx"     },
+  { "custom_22.xpos",                          "7"                     },
+  { "custom_22.ypos",                          "9"                     },
+  { "custom_22.frames",                                "1"                     },
+  { "custom_22.EDITOR",                                "RocksElements.pcx"     },
+  { "custom_22.EDITOR.xpos",                   "15"                    },
+  { "custom_22.EDITOR.ypos",                   "13"                    },
+
+  { "custom_23",                               "RocksElements.pcx"     },
+  { "custom_23.xpos",                          "7"                     },
+  { "custom_23.ypos",                          "9"                     },
+  { "custom_23.frames",                                "1"                     },
+  { "custom_23.EDITOR",                                "RocksElements.pcx"     },
+  { "custom_23.EDITOR.xpos",                   "15"                    },
+  { "custom_23.EDITOR.ypos",                   "13"                    },
+
+  { "custom_24",                               "RocksElements.pcx"     },
+  { "custom_24.xpos",                          "7"                     },
+  { "custom_24.ypos",                          "9"                     },
+  { "custom_24.frames",                                "1"                     },
+  { "custom_24.EDITOR",                                "RocksElements.pcx"     },
+  { "custom_24.EDITOR.xpos",                   "15"                    },
+  { "custom_24.EDITOR.ypos",                   "13"                    },
+
+  { "custom_25",                               "RocksElements.pcx"     },
+  { "custom_25.xpos",                          "7"                     },
+  { "custom_25.ypos",                          "9"                     },
+  { "custom_25.frames",                                "1"                     },
+  { "custom_25.EDITOR",                                "RocksElements.pcx"     },
+  { "custom_25.EDITOR.xpos",                   "15"                    },
+  { "custom_25.EDITOR.ypos",                   "13"                    },
+
+  { "custom_26",                               "RocksElements.pcx"     },
+  { "custom_26.xpos",                          "7"                     },
+  { "custom_26.ypos",                          "9"                     },
+  { "custom_26.frames",                                "1"                     },
+  { "custom_26.EDITOR",                                "RocksElements.pcx"     },
+  { "custom_26.EDITOR.xpos",                   "15"                    },
+  { "custom_26.EDITOR.ypos",                   "13"                    },
+
+  { "custom_27",                               "RocksElements.pcx"     },
+  { "custom_27.xpos",                          "7"                     },
+  { "custom_27.ypos",                          "9"                     },
+  { "custom_27.frames",                                "1"                     },
+  { "custom_27.EDITOR",                                "RocksElements.pcx"     },
+  { "custom_27.EDITOR.xpos",                   "15"                    },
+  { "custom_27.EDITOR.ypos",                   "13"                    },
+
+  { "custom_28",                               "RocksElements.pcx"     },
+  { "custom_28.xpos",                          "7"                     },
+  { "custom_28.ypos",                          "9"                     },
+  { "custom_28.frames",                                "1"                     },
+  { "custom_28.EDITOR",                                "RocksElements.pcx"     },
+  { "custom_28.EDITOR.xpos",                   "15"                    },
+  { "custom_28.EDITOR.ypos",                   "13"                    },
+
+  { "custom_29",                               "RocksElements.pcx"     },
+  { "custom_29.xpos",                          "7"                     },
+  { "custom_29.ypos",                          "9"                     },
+  { "custom_29.frames",                                "1"                     },
+  { "custom_29.EDITOR",                                "RocksElements.pcx"     },
+  { "custom_29.EDITOR.xpos",                   "15"                    },
+  { "custom_29.EDITOR.ypos",                   "13"                    },
+
+  { "custom_30",                               "RocksElements.pcx"     },
+  { "custom_30.xpos",                          "7"                     },
+  { "custom_30.ypos",                          "9"                     },
+  { "custom_30.frames",                                "1"                     },
+  { "custom_30.EDITOR",                                "RocksElements.pcx"     },
+  { "custom_30.EDITOR.xpos",                   "15"                    },
+  { "custom_30.EDITOR.ypos",                   "13"                    },
+
+  { "custom_31",                               "RocksElements.pcx"     },
+  { "custom_31.xpos",                          "7"                     },
+  { "custom_31.ypos",                          "9"                     },
+  { "custom_31.frames",                                "1"                     },
+  { "custom_31.EDITOR",                                "RocksElements.pcx"     },
+  { "custom_31.EDITOR.xpos",                   "15"                    },
+  { "custom_31.EDITOR.ypos",                   "13"                    },
+
+  { "custom_32",                               "RocksElements.pcx"     },
+  { "custom_32.xpos",                          "7"                     },
+  { "custom_32.ypos",                          "9"                     },
+  { "custom_32.frames",                                "1"                     },
+  { "custom_32.EDITOR",                                "RocksElements.pcx"     },
+  { "custom_32.EDITOR.xpos",                   "15"                    },
+  { "custom_32.EDITOR.ypos",                   "13"                    },
+
+  { "custom_33",                               "RocksElements.pcx"     },
+  { "custom_33.xpos",                          "7"                     },
+  { "custom_33.ypos",                          "9"                     },
+  { "custom_33.frames",                                "1"                     },
+  { "custom_33.EDITOR",                                "RocksElements.pcx"     },
+  { "custom_33.EDITOR.xpos",                   "15"                    },
+  { "custom_33.EDITOR.ypos",                   "13"                    },
+
+  { "custom_34",                               "RocksElements.pcx"     },
+  { "custom_34.xpos",                          "7"                     },
+  { "custom_34.ypos",                          "9"                     },
+  { "custom_34.frames",                                "1"                     },
+  { "custom_34.EDITOR",                                "RocksElements.pcx"     },
+  { "custom_34.EDITOR.xpos",                   "15"                    },
+  { "custom_34.EDITOR.ypos",                   "13"                    },
+
+  { "custom_35",                               "RocksElements.pcx"     },
+  { "custom_35.xpos",                          "7"                     },
+  { "custom_35.ypos",                          "9"                     },
+  { "custom_35.frames",                                "1"                     },
+  { "custom_35.EDITOR",                                "RocksElements.pcx"     },
+  { "custom_35.EDITOR.xpos",                   "15"                    },
+  { "custom_35.EDITOR.ypos",                   "13"                    },
+
+  { "custom_36",                               "RocksElements.pcx"     },
+  { "custom_36.xpos",                          "7"                     },
+  { "custom_36.ypos",                          "9"                     },
+  { "custom_36.frames",                                "1"                     },
+  { "custom_36.EDITOR",                                "RocksElements.pcx"     },
+  { "custom_36.EDITOR.xpos",                   "15"                    },
+  { "custom_36.EDITOR.ypos",                   "13"                    },
+
+  { "custom_37",                               "RocksElements.pcx"     },
+  { "custom_37.xpos",                          "7"                     },
+  { "custom_37.ypos",                          "9"                     },
+  { "custom_37.frames",                                "1"                     },
+  { "custom_37.EDITOR",                                "RocksElements.pcx"     },
+  { "custom_37.EDITOR.xpos",                   "15"                    },
+  { "custom_37.EDITOR.ypos",                   "13"                    },
+
+  { "custom_38",                               "RocksElements.pcx"     },
+  { "custom_38.xpos",                          "7"                     },
+  { "custom_38.ypos",                          "9"                     },
+  { "custom_38.frames",                                "1"                     },
+  { "custom_38.EDITOR",                                "RocksElements.pcx"     },
+  { "custom_38.EDITOR.xpos",                   "15"                    },
+  { "custom_38.EDITOR.ypos",                   "13"                    },
+
+  { "custom_39",                               "RocksElements.pcx"     },
+  { "custom_39.xpos",                          "7"                     },
+  { "custom_39.ypos",                          "9"                     },
+  { "custom_39.frames",                                "1"                     },
+  { "custom_39.EDITOR",                                "RocksElements.pcx"     },
+  { "custom_39.EDITOR.xpos",                   "15"                    },
+  { "custom_39.EDITOR.ypos",                   "13"                    },
+
+  { "custom_40",                               "RocksElements.pcx"     },
+  { "custom_40.xpos",                          "7"                     },
+  { "custom_40.ypos",                          "9"                     },
+  { "custom_40.frames",                                "1"                     },
+  { "custom_40.EDITOR",                                "RocksElements.pcx"     },
+  { "custom_40.EDITOR.xpos",                   "15"                    },
+  { "custom_40.EDITOR.ypos",                   "13"                    },
+
+  { "custom_41",                               "RocksElements.pcx"     },
+  { "custom_41.xpos",                          "7"                     },
+  { "custom_41.ypos",                          "9"                     },
+  { "custom_41.frames",                                "1"                     },
+  { "custom_41.EDITOR",                                "RocksElements.pcx"     },
+  { "custom_41.EDITOR.xpos",                   "15"                    },
+  { "custom_41.EDITOR.ypos",                   "13"                    },
+
+  { "custom_42",                               "RocksElements.pcx"     },
+  { "custom_42.xpos",                          "7"                     },
+  { "custom_42.ypos",                          "9"                     },
+  { "custom_42.frames",                                "1"                     },
+  { "custom_42.EDITOR",                                "RocksElements.pcx"     },
+  { "custom_42.EDITOR.xpos",                   "15"                    },
+  { "custom_42.EDITOR.ypos",                   "13"                    },
+
+  { "custom_43",                               "RocksElements.pcx"     },
+  { "custom_43.xpos",                          "7"                     },
+  { "custom_43.ypos",                          "9"                     },
+  { "custom_43.frames",                                "1"                     },
+  { "custom_43.EDITOR",                                "RocksElements.pcx"     },
+  { "custom_43.EDITOR.xpos",                   "15"                    },
+  { "custom_43.EDITOR.ypos",                   "13"                    },
+
+  { "custom_44",                               "RocksElements.pcx"     },
+  { "custom_44.xpos",                          "7"                     },
+  { "custom_44.ypos",                          "9"                     },
+  { "custom_44.frames",                                "1"                     },
+  { "custom_44.EDITOR",                                "RocksElements.pcx"     },
+  { "custom_44.EDITOR.xpos",                   "15"                    },
+  { "custom_44.EDITOR.ypos",                   "13"                    },
+
+  { "custom_45",                               "RocksElements.pcx"     },
+  { "custom_45.xpos",                          "7"                     },
+  { "custom_45.ypos",                          "9"                     },
+  { "custom_45.frames",                                "1"                     },
+  { "custom_45.EDITOR",                                "RocksElements.pcx"     },
+  { "custom_45.EDITOR.xpos",                   "15"                    },
+  { "custom_45.EDITOR.ypos",                   "13"                    },
+
+  { "custom_46",                               "RocksElements.pcx"     },
+  { "custom_46.xpos",                          "7"                     },
+  { "custom_46.ypos",                          "9"                     },
+  { "custom_46.frames",                                "1"                     },
+  { "custom_46.EDITOR",                                "RocksElements.pcx"     },
+  { "custom_46.EDITOR.xpos",                   "15"                    },
+  { "custom_46.EDITOR.ypos",                   "13"                    },
+
+  { "custom_47",                               "RocksElements.pcx"     },
+  { "custom_47.xpos",                          "7"                     },
+  { "custom_47.ypos",                          "9"                     },
+  { "custom_47.frames",                                "1"                     },
+  { "custom_47.EDITOR",                                "RocksElements.pcx"     },
+  { "custom_47.EDITOR.xpos",                   "15"                    },
+  { "custom_47.EDITOR.ypos",                   "13"                    },
+
+  { "custom_48",                               "RocksElements.pcx"     },
+  { "custom_48.xpos",                          "7"                     },
+  { "custom_48.ypos",                          "9"                     },
+  { "custom_48.frames",                                "1"                     },
+  { "custom_48.EDITOR",                                "RocksElements.pcx"     },
+  { "custom_48.EDITOR.xpos",                   "15"                    },
+  { "custom_48.EDITOR.ypos",                   "13"                    },
+
+  { "custom_49",                               "RocksElements.pcx"     },
+  { "custom_49.xpos",                          "7"                     },
+  { "custom_49.ypos",                          "9"                     },
+  { "custom_49.frames",                                "1"                     },
+  { "custom_49.EDITOR",                                "RocksElements.pcx"     },
+  { "custom_49.EDITOR.xpos",                   "15"                    },
+  { "custom_49.EDITOR.ypos",                   "13"                    },
+
+  { "custom_50",                               "RocksElements.pcx"     },
+  { "custom_50.xpos",                          "7"                     },
+  { "custom_50.ypos",                          "9"                     },
+  { "custom_50.frames",                                "1"                     },
+  { "custom_50.EDITOR",                                "RocksElements.pcx"     },
+  { "custom_50.EDITOR.xpos",                   "15"                    },
+  { "custom_50.EDITOR.ypos",                   "13"                    },
+
+  { "custom_51",                               "RocksElements.pcx"     },
+  { "custom_51.xpos",                          "7"                     },
+  { "custom_51.ypos",                          "9"                     },
+  { "custom_51.frames",                                "1"                     },
+  { "custom_51.EDITOR",                                "RocksElements.pcx"     },
+  { "custom_51.EDITOR.xpos",                   "15"                    },
+  { "custom_51.EDITOR.ypos",                   "13"                    },
+
+  { "custom_52",                               "RocksElements.pcx"     },
+  { "custom_52.xpos",                          "7"                     },
+  { "custom_52.ypos",                          "9"                     },
+  { "custom_52.frames",                                "1"                     },
+  { "custom_52.EDITOR",                                "RocksElements.pcx"     },
+  { "custom_52.EDITOR.xpos",                   "15"                    },
+  { "custom_52.EDITOR.ypos",                   "13"                    },
+
+  { "custom_53",                               "RocksElements.pcx"     },
+  { "custom_53.xpos",                          "7"                     },
+  { "custom_53.ypos",                          "9"                     },
+  { "custom_53.frames",                                "1"                     },
+  { "custom_53.EDITOR",                                "RocksElements.pcx"     },
+  { "custom_53.EDITOR.xpos",                   "15"                    },
+  { "custom_53.EDITOR.ypos",                   "13"                    },
+
+  { "custom_54",                               "RocksElements.pcx"     },
+  { "custom_54.xpos",                          "7"                     },
+  { "custom_54.ypos",                          "9"                     },
+  { "custom_54.frames",                                "1"                     },
+  { "custom_54.EDITOR",                                "RocksElements.pcx"     },
+  { "custom_54.EDITOR.xpos",                   "15"                    },
+  { "custom_54.EDITOR.ypos",                   "13"                    },
+
+  { "custom_55",                               "RocksElements.pcx"     },
+  { "custom_55.xpos",                          "7"                     },
+  { "custom_55.ypos",                          "9"                     },
+  { "custom_55.frames",                                "1"                     },
+  { "custom_55.EDITOR",                                "RocksElements.pcx"     },
+  { "custom_55.EDITOR.xpos",                   "15"                    },
+  { "custom_55.EDITOR.ypos",                   "13"                    },
+
+  { "custom_56",                               "RocksElements.pcx"     },
+  { "custom_56.xpos",                          "7"                     },
+  { "custom_56.ypos",                          "9"                     },
+  { "custom_56.frames",                                "1"                     },
+  { "custom_56.EDITOR",                                "RocksElements.pcx"     },
+  { "custom_56.EDITOR.xpos",                   "15"                    },
+  { "custom_56.EDITOR.ypos",                   "13"                    },
+
+  { "custom_57",                               "RocksElements.pcx"     },
+  { "custom_57.xpos",                          "7"                     },
+  { "custom_57.ypos",                          "9"                     },
+  { "custom_57.frames",                                "1"                     },
+  { "custom_57.EDITOR",                                "RocksElements.pcx"     },
+  { "custom_57.EDITOR.xpos",                   "15"                    },
+  { "custom_57.EDITOR.ypos",                   "13"                    },
+
+  { "custom_58",                               "RocksElements.pcx"     },
+  { "custom_58.xpos",                          "7"                     },
+  { "custom_58.ypos",                          "9"                     },
+  { "custom_58.frames",                                "1"                     },
+  { "custom_58.EDITOR",                                "RocksElements.pcx"     },
+  { "custom_58.EDITOR.xpos",                   "15"                    },
+  { "custom_58.EDITOR.ypos",                   "13"                    },
+
+  { "custom_59",                               "RocksElements.pcx"     },
+  { "custom_59.xpos",                          "7"                     },
+  { "custom_59.ypos",                          "9"                     },
+  { "custom_59.frames",                                "1"                     },
+  { "custom_59.EDITOR",                                "RocksElements.pcx"     },
+  { "custom_59.EDITOR.xpos",                   "15"                    },
+  { "custom_59.EDITOR.ypos",                   "13"                    },
+
+  { "custom_60",                               "RocksElements.pcx"     },
+  { "custom_60.xpos",                          "7"                     },
+  { "custom_60.ypos",                          "9"                     },
+  { "custom_60.frames",                                "1"                     },
+  { "custom_60.EDITOR",                                "RocksElements.pcx"     },
+  { "custom_60.EDITOR.xpos",                   "15"                    },
+  { "custom_60.EDITOR.ypos",                   "13"                    },
+
+  { "custom_61",                               "RocksElements.pcx"     },
+  { "custom_61.xpos",                          "7"                     },
+  { "custom_61.ypos",                          "9"                     },
+  { "custom_61.frames",                                "1"                     },
+  { "custom_61.EDITOR",                                "RocksElements.pcx"     },
+  { "custom_61.EDITOR.xpos",                   "15"                    },
+  { "custom_61.EDITOR.ypos",                   "13"                    },
+
+  { "custom_62",                               "RocksElements.pcx"     },
+  { "custom_62.xpos",                          "7"                     },
+  { "custom_62.ypos",                          "9"                     },
+  { "custom_62.frames",                                "1"                     },
+  { "custom_62.EDITOR",                                "RocksElements.pcx"     },
+  { "custom_62.EDITOR.xpos",                   "15"                    },
+  { "custom_62.EDITOR.ypos",                   "13"                    },
+
+  { "custom_63",                               "RocksElements.pcx"     },
+  { "custom_63.xpos",                          "7"                     },
+  { "custom_63.ypos",                          "9"                     },
+  { "custom_63.frames",                                "1"                     },
+  { "custom_63.EDITOR",                                "RocksElements.pcx"     },
+  { "custom_63.EDITOR.xpos",                   "15"                    },
+  { "custom_63.EDITOR.ypos",                   "13"                    },
+
+  { "custom_64",                               "RocksElements.pcx"     },
+  { "custom_64.xpos",                          "7"                     },
+  { "custom_64.ypos",                          "9"                     },
+  { "custom_64.frames",                                "1"                     },
+  { "custom_64.EDITOR",                                "RocksElements.pcx"     },
+  { "custom_64.EDITOR.xpos",                   "15"                    },
+  { "custom_64.EDITOR.ypos",                   "13"                    },
+
+  { "custom_65",                               "RocksElements.pcx"     },
+  { "custom_65.xpos",                          "7"                     },
+  { "custom_65.ypos",                          "9"                     },
+  { "custom_65.frames",                                "1"                     },
+  { "custom_65.EDITOR",                                "RocksElements.pcx"     },
+  { "custom_65.EDITOR.xpos",                   "15"                    },
+  { "custom_65.EDITOR.ypos",                   "13"                    },
+
+  { "custom_66",                               "RocksElements.pcx"     },
+  { "custom_66.xpos",                          "7"                     },
+  { "custom_66.ypos",                          "9"                     },
+  { "custom_66.frames",                                "1"                     },
+  { "custom_66.EDITOR",                                "RocksElements.pcx"     },
+  { "custom_66.EDITOR.xpos",                   "15"                    },
+  { "custom_66.EDITOR.ypos",                   "13"                    },
+
+  { "custom_67",                               "RocksElements.pcx"     },
+  { "custom_67.xpos",                          "7"                     },
+  { "custom_67.ypos",                          "9"                     },
+  { "custom_67.frames",                                "1"                     },
+  { "custom_67.EDITOR",                                "RocksElements.pcx"     },
+  { "custom_67.EDITOR.xpos",                   "15"                    },
+  { "custom_67.EDITOR.ypos",                   "13"                    },
+
+  { "custom_68",                               "RocksElements.pcx"     },
+  { "custom_68.xpos",                          "7"                     },
+  { "custom_68.ypos",                          "9"                     },
+  { "custom_68.frames",                                "1"                     },
+  { "custom_68.EDITOR",                                "RocksElements.pcx"     },
+  { "custom_68.EDITOR.xpos",                   "15"                    },
+  { "custom_68.EDITOR.ypos",                   "13"                    },
+
+  { "custom_69",                               "RocksElements.pcx"     },
+  { "custom_69.xpos",                          "7"                     },
+  { "custom_69.ypos",                          "9"                     },
+  { "custom_69.frames",                                "1"                     },
+  { "custom_69.EDITOR",                                "RocksElements.pcx"     },
+  { "custom_69.EDITOR.xpos",                   "15"                    },
+  { "custom_69.EDITOR.ypos",                   "13"                    },
+
+  { "custom_70",                               "RocksElements.pcx"     },
+  { "custom_70.xpos",                          "7"                     },
+  { "custom_70.ypos",                          "9"                     },
+  { "custom_70.frames",                                "1"                     },
+  { "custom_70.EDITOR",                                "RocksElements.pcx"     },
+  { "custom_70.EDITOR.xpos",                   "15"                    },
+  { "custom_70.EDITOR.ypos",                   "13"                    },
+
+  { "custom_71",                               "RocksElements.pcx"     },
+  { "custom_71.xpos",                          "7"                     },
+  { "custom_71.ypos",                          "9"                     },
+  { "custom_71.frames",                                "1"                     },
+  { "custom_71.EDITOR",                                "RocksElements.pcx"     },
+  { "custom_71.EDITOR.xpos",                   "15"                    },
+  { "custom_71.EDITOR.ypos",                   "13"                    },
+
+  { "custom_72",                               "RocksElements.pcx"     },
+  { "custom_72.xpos",                          "7"                     },
+  { "custom_72.ypos",                          "9"                     },
+  { "custom_72.frames",                                "1"                     },
+  { "custom_72.EDITOR",                                "RocksElements.pcx"     },
+  { "custom_72.EDITOR.xpos",                   "15"                    },
+  { "custom_72.EDITOR.ypos",                   "13"                    },
+
+  { "custom_73",                               "RocksElements.pcx"     },
+  { "custom_73.xpos",                          "7"                     },
+  { "custom_73.ypos",                          "9"                     },
+  { "custom_73.frames",                                "1"                     },
+  { "custom_73.EDITOR",                                "RocksElements.pcx"     },
+  { "custom_73.EDITOR.xpos",                   "15"                    },
+  { "custom_73.EDITOR.ypos",                   "13"                    },
+
+  { "custom_74",                               "RocksElements.pcx"     },
+  { "custom_74.xpos",                          "7"                     },
+  { "custom_74.ypos",                          "9"                     },
+  { "custom_74.frames",                                "1"                     },
+  { "custom_74.EDITOR",                                "RocksElements.pcx"     },
+  { "custom_74.EDITOR.xpos",                   "15"                    },
+  { "custom_74.EDITOR.ypos",                   "13"                    },
+
+  { "custom_75",                               "RocksElements.pcx"     },
+  { "custom_75.xpos",                          "7"                     },
+  { "custom_75.ypos",                          "9"                     },
+  { "custom_75.frames",                                "1"                     },
+  { "custom_75.EDITOR",                                "RocksElements.pcx"     },
+  { "custom_75.EDITOR.xpos",                   "15"                    },
+  { "custom_75.EDITOR.ypos",                   "13"                    },
+
+  { "custom_76",                               "RocksElements.pcx"     },
+  { "custom_76.xpos",                          "7"                     },
+  { "custom_76.ypos",                          "9"                     },
+  { "custom_76.frames",                                "1"                     },
+  { "custom_76.EDITOR",                                "RocksElements.pcx"     },
+  { "custom_76.EDITOR.xpos",                   "15"                    },
+  { "custom_76.EDITOR.ypos",                   "13"                    },
+
+  { "custom_77",                               "RocksElements.pcx"     },
+  { "custom_77.xpos",                          "7"                     },
+  { "custom_77.ypos",                          "9"                     },
+  { "custom_77.frames",                                "1"                     },
+  { "custom_77.EDITOR",                                "RocksElements.pcx"     },
+  { "custom_77.EDITOR.xpos",                   "15"                    },
+  { "custom_77.EDITOR.ypos",                   "13"                    },
+
+  { "custom_78",                               "RocksElements.pcx"     },
+  { "custom_78.xpos",                          "7"                     },
+  { "custom_78.ypos",                          "9"                     },
+  { "custom_78.frames",                                "1"                     },
+  { "custom_78.EDITOR",                                "RocksElements.pcx"     },
+  { "custom_78.EDITOR.xpos",                   "15"                    },
+  { "custom_78.EDITOR.ypos",                   "13"                    },
+
+  { "custom_79",                               "RocksElements.pcx"     },
+  { "custom_79.xpos",                          "7"                     },
+  { "custom_79.ypos",                          "9"                     },
+  { "custom_79.frames",                                "1"                     },
+  { "custom_79.EDITOR",                                "RocksElements.pcx"     },
+  { "custom_79.EDITOR.xpos",                   "15"                    },
+  { "custom_79.EDITOR.ypos",                   "13"                    },
+
+  { "custom_80",                               "RocksElements.pcx"     },
+  { "custom_80.xpos",                          "7"                     },
+  { "custom_80.ypos",                          "9"                     },
+  { "custom_80.frames",                                "1"                     },
+  { "custom_80.EDITOR",                                "RocksElements.pcx"     },
+  { "custom_80.EDITOR.xpos",                   "15"                    },
+  { "custom_80.EDITOR.ypos",                   "13"                    },
+
+  { "custom_81",                               "RocksElements.pcx"     },
+  { "custom_81.xpos",                          "7"                     },
+  { "custom_81.ypos",                          "9"                     },
+  { "custom_81.frames",                                "1"                     },
+  { "custom_81.EDITOR",                                "RocksElements.pcx"     },
+  { "custom_81.EDITOR.xpos",                   "15"                    },
+  { "custom_81.EDITOR.ypos",                   "13"                    },
+
+  { "custom_82",                               "RocksElements.pcx"     },
+  { "custom_82.xpos",                          "7"                     },
+  { "custom_82.ypos",                          "9"                     },
+  { "custom_82.frames",                                "1"                     },
+  { "custom_82.EDITOR",                                "RocksElements.pcx"     },
+  { "custom_82.EDITOR.xpos",                   "15"                    },
+  { "custom_82.EDITOR.ypos",                   "13"                    },
+
+  { "custom_83",                               "RocksElements.pcx"     },
+  { "custom_83.xpos",                          "7"                     },
+  { "custom_83.ypos",                          "9"                     },
+  { "custom_83.frames",                                "1"                     },
+  { "custom_83.EDITOR",                                "RocksElements.pcx"     },
+  { "custom_83.EDITOR.xpos",                   "15"                    },
+  { "custom_83.EDITOR.ypos",                   "13"                    },
+
+  { "custom_84",                               "RocksElements.pcx"     },
+  { "custom_84.xpos",                          "7"                     },
+  { "custom_84.ypos",                          "9"                     },
+  { "custom_84.frames",                                "1"                     },
+  { "custom_84.EDITOR",                                "RocksElements.pcx"     },
+  { "custom_84.EDITOR.xpos",                   "15"                    },
+  { "custom_84.EDITOR.ypos",                   "13"                    },
+
+  { "custom_85",                               "RocksElements.pcx"     },
+  { "custom_85.xpos",                          "7"                     },
+  { "custom_85.ypos",                          "9"                     },
+  { "custom_85.frames",                                "1"                     },
+  { "custom_85.EDITOR",                                "RocksElements.pcx"     },
+  { "custom_85.EDITOR.xpos",                   "15"                    },
+  { "custom_85.EDITOR.ypos",                   "13"                    },
+
+  { "custom_86",                               "RocksElements.pcx"     },
+  { "custom_86.xpos",                          "7"                     },
+  { "custom_86.ypos",                          "9"                     },
+  { "custom_86.frames",                                "1"                     },
+  { "custom_86.EDITOR",                                "RocksElements.pcx"     },
+  { "custom_86.EDITOR.xpos",                   "15"                    },
+  { "custom_86.EDITOR.ypos",                   "13"                    },
+
+  { "custom_87",                               "RocksElements.pcx"     },
+  { "custom_87.xpos",                          "7"                     },
+  { "custom_87.ypos",                          "9"                     },
+  { "custom_87.frames",                                "1"                     },
+  { "custom_87.EDITOR",                                "RocksElements.pcx"     },
+  { "custom_87.EDITOR.xpos",                   "15"                    },
+  { "custom_87.EDITOR.ypos",                   "13"                    },
+
+  { "custom_88",                               "RocksElements.pcx"     },
+  { "custom_88.xpos",                          "7"                     },
+  { "custom_88.ypos",                          "9"                     },
+  { "custom_88.frames",                                "1"                     },
+  { "custom_88.EDITOR",                                "RocksElements.pcx"     },
+  { "custom_88.EDITOR.xpos",                   "15"                    },
+  { "custom_88.EDITOR.ypos",                   "13"                    },
+
+  { "custom_89",                               "RocksElements.pcx"     },
+  { "custom_89.xpos",                          "7"                     },
+  { "custom_89.ypos",                          "9"                     },
+  { "custom_89.frames",                                "1"                     },
+  { "custom_89.EDITOR",                                "RocksElements.pcx"     },
+  { "custom_89.EDITOR.xpos",                   "15"                    },
+  { "custom_89.EDITOR.ypos",                   "13"                    },
+
+  { "custom_90",                               "RocksElements.pcx"     },
+  { "custom_90.xpos",                          "7"                     },
+  { "custom_90.ypos",                          "9"                     },
+  { "custom_90.frames",                                "1"                     },
+  { "custom_90.EDITOR",                                "RocksElements.pcx"     },
+  { "custom_90.EDITOR.xpos",                   "15"                    },
+  { "custom_90.EDITOR.ypos",                   "13"                    },
+
+  { "custom_91",                               "RocksElements.pcx"     },
+  { "custom_91.xpos",                          "7"                     },
+  { "custom_91.ypos",                          "9"                     },
+  { "custom_91.frames",                                "1"                     },
+  { "custom_91.EDITOR",                                "RocksElements.pcx"     },
+  { "custom_91.EDITOR.xpos",                   "15"                    },
+  { "custom_91.EDITOR.ypos",                   "13"                    },
+
+  { "custom_92",                               "RocksElements.pcx"     },
+  { "custom_92.xpos",                          "7"                     },
+  { "custom_92.ypos",                          "9"                     },
+  { "custom_92.frames",                                "1"                     },
+  { "custom_92.EDITOR",                                "RocksElements.pcx"     },
+  { "custom_92.EDITOR.xpos",                   "15"                    },
+  { "custom_92.EDITOR.ypos",                   "13"                    },
+
+  { "custom_93",                               "RocksElements.pcx"     },
+  { "custom_93.xpos",                          "7"                     },
+  { "custom_93.ypos",                          "9"                     },
+  { "custom_93.frames",                                "1"                     },
+  { "custom_93.EDITOR",                                "RocksElements.pcx"     },
+  { "custom_93.EDITOR.xpos",                   "15"                    },
+  { "custom_93.EDITOR.ypos",                   "13"                    },
+
+  { "custom_94",                               "RocksElements.pcx"     },
+  { "custom_94.xpos",                          "7"                     },
+  { "custom_94.ypos",                          "9"                     },
+  { "custom_94.frames",                                "1"                     },
+  { "custom_94.EDITOR",                                "RocksElements.pcx"     },
+  { "custom_94.EDITOR.xpos",                   "15"                    },
+  { "custom_94.EDITOR.ypos",                   "13"                    },
+
+  { "custom_95",                               "RocksElements.pcx"     },
+  { "custom_95.xpos",                          "7"                     },
+  { "custom_95.ypos",                          "9"                     },
+  { "custom_95.frames",                                "1"                     },
+  { "custom_95.EDITOR",                                "RocksElements.pcx"     },
+  { "custom_95.EDITOR.xpos",                   "15"                    },
+  { "custom_95.EDITOR.ypos",                   "13"                    },
+
+  { "custom_96",                               "RocksElements.pcx"     },
+  { "custom_96.xpos",                          "7"                     },
+  { "custom_96.ypos",                          "9"                     },
+  { "custom_96.frames",                                "1"                     },
+  { "custom_96.EDITOR",                                "RocksElements.pcx"     },
+  { "custom_96.EDITOR.xpos",                   "15"                    },
+  { "custom_96.EDITOR.ypos",                   "13"                    },
+
+  { "custom_97",                               "RocksElements.pcx"     },
+  { "custom_97.xpos",                          "7"                     },
+  { "custom_97.ypos",                          "9"                     },
+  { "custom_97.frames",                                "1"                     },
+  { "custom_97.EDITOR",                                "RocksElements.pcx"     },
+  { "custom_97.EDITOR.xpos",                   "15"                    },
+  { "custom_97.EDITOR.ypos",                   "13"                    },
+
+  { "custom_98",                               "RocksElements.pcx"     },
+  { "custom_98.xpos",                          "7"                     },
+  { "custom_98.ypos",                          "9"                     },
+  { "custom_98.frames",                                "1"                     },
+  { "custom_98.EDITOR",                                "RocksElements.pcx"     },
+  { "custom_98.EDITOR.xpos",                   "15"                    },
+  { "custom_98.EDITOR.ypos",                   "13"                    },
+
+  { "custom_99",                               "RocksElements.pcx"     },
+  { "custom_99.xpos",                          "7"                     },
+  { "custom_99.ypos",                          "9"                     },
+  { "custom_99.frames",                                "1"                     },
+  { "custom_99.EDITOR",                                "RocksElements.pcx"     },
+  { "custom_99.EDITOR.xpos",                   "15"                    },
+  { "custom_99.EDITOR.ypos",                   "13"                    },
+
+  { "custom_100",                              "RocksElements.pcx"     },
+  { "custom_100.xpos",                         "7"                     },
+  { "custom_100.ypos",                         "9"                     },
+  { "custom_100.frames",                       "1"                     },
+  { "custom_100.EDITOR",                       "RocksElements.pcx"     },
+  { "custom_100.EDITOR.xpos",                  "15"                    },
+  { "custom_100.EDITOR.ypos",                  "13"                    },
+
+  { "custom_101",                              "RocksElements.pcx"     },
+  { "custom_101.xpos",                         "7"                     },
+  { "custom_101.ypos",                         "9"                     },
+  { "custom_101.frames",                       "1"                     },
+  { "custom_101.EDITOR",                       "RocksElements.pcx"     },
+  { "custom_101.EDITOR.xpos",                  "15"                    },
+  { "custom_101.EDITOR.ypos",                  "13"                    },
+
+  { "custom_102",                              "RocksElements.pcx"     },
+  { "custom_102.xpos",                         "7"                     },
+  { "custom_102.ypos",                         "9"                     },
+  { "custom_102.frames",                       "1"                     },
+  { "custom_102.EDITOR",                       "RocksElements.pcx"     },
+  { "custom_102.EDITOR.xpos",                  "15"                    },
+  { "custom_102.EDITOR.ypos",                  "13"                    },
+
+  { "custom_103",                              "RocksElements.pcx"     },
+  { "custom_103.xpos",                         "7"                     },
+  { "custom_103.ypos",                         "9"                     },
+  { "custom_103.frames",                       "1"                     },
+  { "custom_103.EDITOR",                       "RocksElements.pcx"     },
+  { "custom_103.EDITOR.xpos",                  "15"                    },
+  { "custom_103.EDITOR.ypos",                  "13"                    },
+
+  { "custom_104",                              "RocksElements.pcx"     },
+  { "custom_104.xpos",                         "7"                     },
+  { "custom_104.ypos",                         "9"                     },
+  { "custom_104.frames",                       "1"                     },
+  { "custom_104.EDITOR",                       "RocksElements.pcx"     },
+  { "custom_104.EDITOR.xpos",                  "15"                    },
+  { "custom_104.EDITOR.ypos",                  "13"                    },
+
+  { "custom_105",                              "RocksElements.pcx"     },
+  { "custom_105.xpos",                         "7"                     },
+  { "custom_105.ypos",                         "9"                     },
+  { "custom_105.frames",                       "1"                     },
+  { "custom_105.EDITOR",                       "RocksElements.pcx"     },
+  { "custom_105.EDITOR.xpos",                  "15"                    },
+  { "custom_105.EDITOR.ypos",                  "13"                    },
+
+  { "custom_106",                              "RocksElements.pcx"     },
+  { "custom_106.xpos",                         "7"                     },
+  { "custom_106.ypos",                         "9"                     },
+  { "custom_106.frames",                       "1"                     },
+  { "custom_106.EDITOR",                       "RocksElements.pcx"     },
+  { "custom_106.EDITOR.xpos",                  "15"                    },
+  { "custom_106.EDITOR.ypos",                  "13"                    },
+
+  { "custom_107",                              "RocksElements.pcx"     },
+  { "custom_107.xpos",                         "7"                     },
+  { "custom_107.ypos",                         "9"                     },
+  { "custom_107.frames",                       "1"                     },
+  { "custom_107.EDITOR",                       "RocksElements.pcx"     },
+  { "custom_107.EDITOR.xpos",                  "15"                    },
+  { "custom_107.EDITOR.ypos",                  "13"                    },
+
+  { "custom_108",                              "RocksElements.pcx"     },
+  { "custom_108.xpos",                         "7"                     },
+  { "custom_108.ypos",                         "9"                     },
+  { "custom_108.frames",                       "1"                     },
+  { "custom_108.EDITOR",                       "RocksElements.pcx"     },
+  { "custom_108.EDITOR.xpos",                  "15"                    },
+  { "custom_108.EDITOR.ypos",                  "13"                    },
+
+  { "custom_109",                              "RocksElements.pcx"     },
+  { "custom_109.xpos",                         "7"                     },
+  { "custom_109.ypos",                         "9"                     },
+  { "custom_109.frames",                       "1"                     },
+  { "custom_109.EDITOR",                       "RocksElements.pcx"     },
+  { "custom_109.EDITOR.xpos",                  "15"                    },
+  { "custom_109.EDITOR.ypos",                  "13"                    },
+
+  { "custom_110",                              "RocksElements.pcx"     },
+  { "custom_110.xpos",                         "7"                     },
+  { "custom_110.ypos",                         "9"                     },
+  { "custom_110.frames",                       "1"                     },
+  { "custom_110.EDITOR",                       "RocksElements.pcx"     },
+  { "custom_110.EDITOR.xpos",                  "15"                    },
+  { "custom_110.EDITOR.ypos",                  "13"                    },
+
+  { "custom_111",                              "RocksElements.pcx"     },
+  { "custom_111.xpos",                         "7"                     },
+  { "custom_111.ypos",                         "9"                     },
+  { "custom_111.frames",                       "1"                     },
+  { "custom_111.EDITOR",                       "RocksElements.pcx"     },
+  { "custom_111.EDITOR.xpos",                  "15"                    },
+  { "custom_111.EDITOR.ypos",                  "13"                    },
+
+  { "custom_112",                              "RocksElements.pcx"     },
+  { "custom_112.xpos",                         "7"                     },
+  { "custom_112.ypos",                         "9"                     },
+  { "custom_112.frames",                       "1"                     },
+  { "custom_112.EDITOR",                       "RocksElements.pcx"     },
+  { "custom_112.EDITOR.xpos",                  "15"                    },
+  { "custom_112.EDITOR.ypos",                  "13"                    },
+
+  { "custom_113",                              "RocksElements.pcx"     },
+  { "custom_113.xpos",                         "7"                     },
+  { "custom_113.ypos",                         "9"                     },
+  { "custom_113.frames",                       "1"                     },
+  { "custom_113.EDITOR",                       "RocksElements.pcx"     },
+  { "custom_113.EDITOR.xpos",                  "15"                    },
+  { "custom_113.EDITOR.ypos",                  "13"                    },
+
+  { "custom_114",                              "RocksElements.pcx"     },
+  { "custom_114.xpos",                         "7"                     },
+  { "custom_114.ypos",                         "9"                     },
+  { "custom_114.frames",                       "1"                     },
+  { "custom_114.EDITOR",                       "RocksElements.pcx"     },
+  { "custom_114.EDITOR.xpos",                  "15"                    },
+  { "custom_114.EDITOR.ypos",                  "13"                    },
+
+  { "custom_115",                              "RocksElements.pcx"     },
+  { "custom_115.xpos",                         "7"                     },
+  { "custom_115.ypos",                         "9"                     },
+  { "custom_115.frames",                       "1"                     },
+  { "custom_115.EDITOR",                       "RocksElements.pcx"     },
+  { "custom_115.EDITOR.xpos",                  "15"                    },
+  { "custom_115.EDITOR.ypos",                  "13"                    },
+
+  { "custom_116",                              "RocksElements.pcx"     },
+  { "custom_116.xpos",                         "7"                     },
+  { "custom_116.ypos",                         "9"                     },
+  { "custom_116.frames",                       "1"                     },
+  { "custom_116.EDITOR",                       "RocksElements.pcx"     },
+  { "custom_116.EDITOR.xpos",                  "15"                    },
+  { "custom_116.EDITOR.ypos",                  "13"                    },
+
+  { "custom_117",                              "RocksElements.pcx"     },
+  { "custom_117.xpos",                         "7"                     },
+  { "custom_117.ypos",                         "9"                     },
+  { "custom_117.frames",                       "1"                     },
+  { "custom_117.EDITOR",                       "RocksElements.pcx"     },
+  { "custom_117.EDITOR.xpos",                  "15"                    },
+  { "custom_117.EDITOR.ypos",                  "13"                    },
+
+  { "custom_118",                              "RocksElements.pcx"     },
+  { "custom_118.xpos",                         "7"                     },
+  { "custom_118.ypos",                         "9"                     },
+  { "custom_118.frames",                       "1"                     },
+  { "custom_118.EDITOR",                       "RocksElements.pcx"     },
+  { "custom_118.EDITOR.xpos",                  "15"                    },
+  { "custom_118.EDITOR.ypos",                  "13"                    },
+
+  { "custom_119",                              "RocksElements.pcx"     },
+  { "custom_119.xpos",                         "7"                     },
+  { "custom_119.ypos",                         "9"                     },
+  { "custom_119.frames",                       "1"                     },
+  { "custom_119.EDITOR",                       "RocksElements.pcx"     },
+  { "custom_119.EDITOR.xpos",                  "15"                    },
+  { "custom_119.EDITOR.ypos",                  "13"                    },
+
+  { "custom_120",                              "RocksElements.pcx"     },
+  { "custom_120.xpos",                         "7"                     },
+  { "custom_120.ypos",                         "9"                     },
+  { "custom_120.frames",                       "1"                     },
+  { "custom_120.EDITOR",                       "RocksElements.pcx"     },
+  { "custom_120.EDITOR.xpos",                  "15"                    },
+  { "custom_120.EDITOR.ypos",                  "13"                    },
+
+  { "custom_121",                              "RocksElements.pcx"     },
+  { "custom_121.xpos",                         "7"                     },
+  { "custom_121.ypos",                         "9"                     },
+  { "custom_121.frames",                       "1"                     },
+  { "custom_121.EDITOR",                       "RocksElements.pcx"     },
+  { "custom_121.EDITOR.xpos",                  "15"                    },
+  { "custom_121.EDITOR.ypos",                  "13"                    },
+
+  { "custom_122",                              "RocksElements.pcx"     },
+  { "custom_122.xpos",                         "7"                     },
+  { "custom_122.ypos",                         "9"                     },
+  { "custom_122.frames",                       "1"                     },
+  { "custom_122.EDITOR",                       "RocksElements.pcx"     },
+  { "custom_122.EDITOR.xpos",                  "15"                    },
+  { "custom_122.EDITOR.ypos",                  "13"                    },
+
+  { "custom_123",                              "RocksElements.pcx"     },
+  { "custom_123.xpos",                         "7"                     },
+  { "custom_123.ypos",                         "9"                     },
+  { "custom_123.frames",                       "1"                     },
+  { "custom_123.EDITOR",                       "RocksElements.pcx"     },
+  { "custom_123.EDITOR.xpos",                  "15"                    },
+  { "custom_123.EDITOR.ypos",                  "13"                    },
+
+  { "custom_124",                              "RocksElements.pcx"     },
+  { "custom_124.xpos",                         "7"                     },
+  { "custom_124.ypos",                         "9"                     },
+  { "custom_124.frames",                       "1"                     },
+  { "custom_124.EDITOR",                       "RocksElements.pcx"     },
+  { "custom_124.EDITOR.xpos",                  "15"                    },
+  { "custom_124.EDITOR.ypos",                  "13"                    },
+
+  { "custom_125",                              "RocksElements.pcx"     },
+  { "custom_125.xpos",                         "7"                     },
+  { "custom_125.ypos",                         "9"                     },
+  { "custom_125.frames",                       "1"                     },
+  { "custom_125.EDITOR",                       "RocksElements.pcx"     },
+  { "custom_125.EDITOR.xpos",                  "15"                    },
+  { "custom_125.EDITOR.ypos",                  "13"                    },
+
+  { "custom_126",                              "RocksElements.pcx"     },
+  { "custom_126.xpos",                         "7"                     },
+  { "custom_126.ypos",                         "9"                     },
+  { "custom_126.frames",                       "1"                     },
+  { "custom_126.EDITOR",                       "RocksElements.pcx"     },
+  { "custom_126.EDITOR.xpos",                  "15"                    },
+  { "custom_126.EDITOR.ypos",                  "13"                    },
+
+  { "custom_127",                              "RocksElements.pcx"     },
+  { "custom_127.xpos",                         "7"                     },
+  { "custom_127.ypos",                         "9"                     },
+  { "custom_127.frames",                       "1"                     },
+  { "custom_127.EDITOR",                       "RocksElements.pcx"     },
+  { "custom_127.EDITOR.xpos",                  "15"                    },
+  { "custom_127.EDITOR.ypos",                  "13"                    },
+
+  { "custom_128",                              "RocksElements.pcx"     },
+  { "custom_128.xpos",                         "7"                     },
+  { "custom_128.ypos",                         "9"                     },
+  { "custom_128.frames",                       "1"                     },
+  { "custom_128.EDITOR",                       "RocksElements.pcx"     },
+  { "custom_128.EDITOR.xpos",                  "15"                    },
+  { "custom_128.EDITOR.ypos",                  "13"                    },
+
+
+#endif /* CONF_CUS_C */
diff --git a/src/conf_cus.h b/src/conf_cus.h
new file mode 100644 (file)
index 0000000..425334b
--- /dev/null
@@ -0,0 +1,150 @@
+/***********************************************************
+* Rocks'n'Diamonds -- McDuffin Strikes Back!               *
+*----------------------------------------------------------*
+* (c) 1995-2002 Artsoft Entertainment                      *
+*               Holger Schemel                             *
+*               Detmolder Strasse 189                      *
+*               33604 Bielefeld                            *
+*               Germany                                    *
+*               e-mail: info@artsoft.org                   *
+*----------------------------------------------------------*
+* conf_cus.h                                               *
+***********************************************************/
+
+/* ----- this file was automatically generated -- do not edit by hand ----- */
+
+#ifndef CONF_CUS_H
+#define CONF_CUS_H
+
+/* values for elements configuration (custom elements) */
+
+#define EL_CUSTOM_1                    (EL_CUSTOM_START + 0)
+#define EL_CUSTOM_2                    (EL_CUSTOM_START + 1)
+#define EL_CUSTOM_3                    (EL_CUSTOM_START + 2)
+#define EL_CUSTOM_4                    (EL_CUSTOM_START + 3)
+#define EL_CUSTOM_5                    (EL_CUSTOM_START + 4)
+#define EL_CUSTOM_6                    (EL_CUSTOM_START + 5)
+#define EL_CUSTOM_7                    (EL_CUSTOM_START + 6)
+#define EL_CUSTOM_8                    (EL_CUSTOM_START + 7)
+#define EL_CUSTOM_9                    (EL_CUSTOM_START + 8)
+#define EL_CUSTOM_10                   (EL_CUSTOM_START + 9)
+#define EL_CUSTOM_11                   (EL_CUSTOM_START + 10)
+#define EL_CUSTOM_12                   (EL_CUSTOM_START + 11)
+#define EL_CUSTOM_13                   (EL_CUSTOM_START + 12)
+#define EL_CUSTOM_14                   (EL_CUSTOM_START + 13)
+#define EL_CUSTOM_15                   (EL_CUSTOM_START + 14)
+#define EL_CUSTOM_16                   (EL_CUSTOM_START + 15)
+#define EL_CUSTOM_17                   (EL_CUSTOM_START + 16)
+#define EL_CUSTOM_18                   (EL_CUSTOM_START + 17)
+#define EL_CUSTOM_19                   (EL_CUSTOM_START + 18)
+#define EL_CUSTOM_20                   (EL_CUSTOM_START + 19)
+#define EL_CUSTOM_21                   (EL_CUSTOM_START + 20)
+#define EL_CUSTOM_22                   (EL_CUSTOM_START + 21)
+#define EL_CUSTOM_23                   (EL_CUSTOM_START + 22)
+#define EL_CUSTOM_24                   (EL_CUSTOM_START + 23)
+#define EL_CUSTOM_25                   (EL_CUSTOM_START + 24)
+#define EL_CUSTOM_26                   (EL_CUSTOM_START + 25)
+#define EL_CUSTOM_27                   (EL_CUSTOM_START + 26)
+#define EL_CUSTOM_28                   (EL_CUSTOM_START + 27)
+#define EL_CUSTOM_29                   (EL_CUSTOM_START + 28)
+#define EL_CUSTOM_30                   (EL_CUSTOM_START + 29)
+#define EL_CUSTOM_31                   (EL_CUSTOM_START + 30)
+#define EL_CUSTOM_32                   (EL_CUSTOM_START + 31)
+#define EL_CUSTOM_33                   (EL_CUSTOM_START + 32)
+#define EL_CUSTOM_34                   (EL_CUSTOM_START + 33)
+#define EL_CUSTOM_35                   (EL_CUSTOM_START + 34)
+#define EL_CUSTOM_36                   (EL_CUSTOM_START + 35)
+#define EL_CUSTOM_37                   (EL_CUSTOM_START + 36)
+#define EL_CUSTOM_38                   (EL_CUSTOM_START + 37)
+#define EL_CUSTOM_39                   (EL_CUSTOM_START + 38)
+#define EL_CUSTOM_40                   (EL_CUSTOM_START + 39)
+#define EL_CUSTOM_41                   (EL_CUSTOM_START + 40)
+#define EL_CUSTOM_42                   (EL_CUSTOM_START + 41)
+#define EL_CUSTOM_43                   (EL_CUSTOM_START + 42)
+#define EL_CUSTOM_44                   (EL_CUSTOM_START + 43)
+#define EL_CUSTOM_45                   (EL_CUSTOM_START + 44)
+#define EL_CUSTOM_46                   (EL_CUSTOM_START + 45)
+#define EL_CUSTOM_47                   (EL_CUSTOM_START + 46)
+#define EL_CUSTOM_48                   (EL_CUSTOM_START + 47)
+#define EL_CUSTOM_49                   (EL_CUSTOM_START + 48)
+#define EL_CUSTOM_50                   (EL_CUSTOM_START + 49)
+#define EL_CUSTOM_51                   (EL_CUSTOM_START + 50)
+#define EL_CUSTOM_52                   (EL_CUSTOM_START + 51)
+#define EL_CUSTOM_53                   (EL_CUSTOM_START + 52)
+#define EL_CUSTOM_54                   (EL_CUSTOM_START + 53)
+#define EL_CUSTOM_55                   (EL_CUSTOM_START + 54)
+#define EL_CUSTOM_56                   (EL_CUSTOM_START + 55)
+#define EL_CUSTOM_57                   (EL_CUSTOM_START + 56)
+#define EL_CUSTOM_58                   (EL_CUSTOM_START + 57)
+#define EL_CUSTOM_59                   (EL_CUSTOM_START + 58)
+#define EL_CUSTOM_60                   (EL_CUSTOM_START + 59)
+#define EL_CUSTOM_61                   (EL_CUSTOM_START + 60)
+#define EL_CUSTOM_62                   (EL_CUSTOM_START + 61)
+#define EL_CUSTOM_63                   (EL_CUSTOM_START + 62)
+#define EL_CUSTOM_64                   (EL_CUSTOM_START + 63)
+#define EL_CUSTOM_65                   (EL_CUSTOM_START + 64)
+#define EL_CUSTOM_66                   (EL_CUSTOM_START + 65)
+#define EL_CUSTOM_67                   (EL_CUSTOM_START + 66)
+#define EL_CUSTOM_68                   (EL_CUSTOM_START + 67)
+#define EL_CUSTOM_69                   (EL_CUSTOM_START + 68)
+#define EL_CUSTOM_70                   (EL_CUSTOM_START + 69)
+#define EL_CUSTOM_71                   (EL_CUSTOM_START + 70)
+#define EL_CUSTOM_72                   (EL_CUSTOM_START + 71)
+#define EL_CUSTOM_73                   (EL_CUSTOM_START + 72)
+#define EL_CUSTOM_74                   (EL_CUSTOM_START + 73)
+#define EL_CUSTOM_75                   (EL_CUSTOM_START + 74)
+#define EL_CUSTOM_76                   (EL_CUSTOM_START + 75)
+#define EL_CUSTOM_77                   (EL_CUSTOM_START + 76)
+#define EL_CUSTOM_78                   (EL_CUSTOM_START + 77)
+#define EL_CUSTOM_79                   (EL_CUSTOM_START + 78)
+#define EL_CUSTOM_80                   (EL_CUSTOM_START + 79)
+#define EL_CUSTOM_81                   (EL_CUSTOM_START + 80)
+#define EL_CUSTOM_82                   (EL_CUSTOM_START + 81)
+#define EL_CUSTOM_83                   (EL_CUSTOM_START + 82)
+#define EL_CUSTOM_84                   (EL_CUSTOM_START + 83)
+#define EL_CUSTOM_85                   (EL_CUSTOM_START + 84)
+#define EL_CUSTOM_86                   (EL_CUSTOM_START + 85)
+#define EL_CUSTOM_87                   (EL_CUSTOM_START + 86)
+#define EL_CUSTOM_88                   (EL_CUSTOM_START + 87)
+#define EL_CUSTOM_89                   (EL_CUSTOM_START + 88)
+#define EL_CUSTOM_90                   (EL_CUSTOM_START + 89)
+#define EL_CUSTOM_91                   (EL_CUSTOM_START + 90)
+#define EL_CUSTOM_92                   (EL_CUSTOM_START + 91)
+#define EL_CUSTOM_93                   (EL_CUSTOM_START + 92)
+#define EL_CUSTOM_94                   (EL_CUSTOM_START + 93)
+#define EL_CUSTOM_95                   (EL_CUSTOM_START + 94)
+#define EL_CUSTOM_96                   (EL_CUSTOM_START + 95)
+#define EL_CUSTOM_97                   (EL_CUSTOM_START + 96)
+#define EL_CUSTOM_98                   (EL_CUSTOM_START + 97)
+#define EL_CUSTOM_99                   (EL_CUSTOM_START + 98)
+#define EL_CUSTOM_100                  (EL_CUSTOM_START + 99)
+#define EL_CUSTOM_101                  (EL_CUSTOM_START + 100)
+#define EL_CUSTOM_102                  (EL_CUSTOM_START + 101)
+#define EL_CUSTOM_103                  (EL_CUSTOM_START + 102)
+#define EL_CUSTOM_104                  (EL_CUSTOM_START + 103)
+#define EL_CUSTOM_105                  (EL_CUSTOM_START + 104)
+#define EL_CUSTOM_106                  (EL_CUSTOM_START + 105)
+#define EL_CUSTOM_107                  (EL_CUSTOM_START + 106)
+#define EL_CUSTOM_108                  (EL_CUSTOM_START + 107)
+#define EL_CUSTOM_109                  (EL_CUSTOM_START + 108)
+#define EL_CUSTOM_110                  (EL_CUSTOM_START + 109)
+#define EL_CUSTOM_111                  (EL_CUSTOM_START + 110)
+#define EL_CUSTOM_112                  (EL_CUSTOM_START + 111)
+#define EL_CUSTOM_113                  (EL_CUSTOM_START + 112)
+#define EL_CUSTOM_114                  (EL_CUSTOM_START + 113)
+#define EL_CUSTOM_115                  (EL_CUSTOM_START + 114)
+#define EL_CUSTOM_116                  (EL_CUSTOM_START + 115)
+#define EL_CUSTOM_117                  (EL_CUSTOM_START + 116)
+#define EL_CUSTOM_118                  (EL_CUSTOM_START + 117)
+#define EL_CUSTOM_119                  (EL_CUSTOM_START + 118)
+#define EL_CUSTOM_120                  (EL_CUSTOM_START + 119)
+#define EL_CUSTOM_121                  (EL_CUSTOM_START + 120)
+#define EL_CUSTOM_122                  (EL_CUSTOM_START + 121)
+#define EL_CUSTOM_123                  (EL_CUSTOM_START + 122)
+#define EL_CUSTOM_124                  (EL_CUSTOM_START + 123)
+#define EL_CUSTOM_125                  (EL_CUSTOM_START + 124)
+#define EL_CUSTOM_126                  (EL_CUSTOM_START + 125)
+#define EL_CUSTOM_127                  (EL_CUSTOM_START + 126)
+#define EL_CUSTOM_128                  (EL_CUSTOM_START + 127)
+
+#endif /* CONF_CUS_C */
diff --git a/src/conf_e2g.c b/src/conf_e2g.c
new file mode 100644 (file)
index 0000000..2b9b2e0
--- /dev/null
@@ -0,0 +1,3318 @@
+/***********************************************************
+* Rocks'n'Diamonds -- McDuffin Strikes Back!               *
+*----------------------------------------------------------*
+* (c) 1995-2002 Artsoft Entertainment                      *
+*               Holger Schemel                             *
+*               Detmolder Strasse 189                      *
+*               33604 Bielefeld                            *
+*               Germany                                    *
+*               e-mail: info@artsoft.org                   *
+*----------------------------------------------------------*
+* conf_e2g.c                                               *
+***********************************************************/
+
+/* ----- this file was automatically generated -- do not edit by hand ----- */
+
+#ifndef CONF_E2G_C
+#define CONF_E2G_C
+
+/* values for element/graphics mapping configuration (normal) */
+
+static struct
+{
+  int element;
+  int action;
+  int direction;
+  boolean crumbled;
+
+  int graphic;
+}
+element_to_graphic[] =
+{
+  {
+    EL_BD_WALL,                                -1, -1, FALSE,
+    IMG_BD_WALL
+  },
+  {
+    EL_BD_ROCK,                                -1, -1, FALSE,
+    IMG_BD_ROCK
+  },
+  {
+    EL_BD_ROCK,                                ACTION_MOVING, MV_BIT_LEFT, FALSE,
+    IMG_BD_ROCK_MOVING_LEFT
+  },
+  {
+    EL_BD_ROCK,                                ACTION_MOVING, MV_BIT_RIGHT, FALSE,
+    IMG_BD_ROCK_MOVING_RIGHT
+  },
+  {
+    EL_BD_ROCK,                                ACTION_PUSHING, MV_BIT_LEFT, FALSE,
+    IMG_BD_ROCK_PUSHING_LEFT
+  },
+  {
+    EL_BD_ROCK,                                ACTION_PUSHING, MV_BIT_RIGHT, FALSE,
+    IMG_BD_ROCK_PUSHING_RIGHT
+  },
+  {
+    EL_BD_DIAMOND,                     -1, -1, FALSE,
+    IMG_BD_DIAMOND
+  },
+  {
+    EL_BD_DIAMOND,                     ACTION_MOVING, -1, FALSE,
+    IMG_BD_DIAMOND_MOVING
+  },
+  {
+    EL_BD_DIAMOND,                     ACTION_FALLING, -1, FALSE,
+    IMG_BD_DIAMOND_FALLING
+  },
+  {
+    EL_BD_MAGIC_WALL,                  -1, -1, FALSE,
+    IMG_BD_MAGIC_WALL
+  },
+  {
+    EL_BD_MAGIC_WALL_ACTIVE,           -1, -1, FALSE,
+    IMG_BD_MAGIC_WALL_ACTIVE
+  },
+  {
+    EL_BD_MAGIC_WALL,                  ACTION_ACTIVE, -1, FALSE,
+    IMG_BD_MAGIC_WALL_ACTIVE
+  },
+  {
+    EL_BD_MAGIC_WALL_FILLING,          -1, -1, FALSE,
+    IMG_BD_MAGIC_WALL_FILLING
+  },
+  {
+    EL_BD_MAGIC_WALL,                  ACTION_FILLING, -1, FALSE,
+    IMG_BD_MAGIC_WALL_FILLING
+  },
+  {
+    EL_BD_MAGIC_WALL_FULL,             -1, -1, FALSE,
+    IMG_BD_MAGIC_WALL_FULL
+  },
+  {
+    EL_BD_MAGIC_WALL_EMPTYING,         -1, -1, FALSE,
+    IMG_BD_MAGIC_WALL_EMPTYING
+  },
+  {
+    EL_BD_MAGIC_WALL,                  ACTION_EMPTYING, -1, FALSE,
+    IMG_BD_MAGIC_WALL_EMPTYING
+  },
+  {
+    EL_BD_MAGIC_WALL_DEAD,             -1, -1, FALSE,
+    IMG_BD_MAGIC_WALL_DEAD
+  },
+  {
+    EL_BD_AMOEBA,                      -1, -1, FALSE,
+    IMG_BD_AMOEBA
+  },
+  {
+    EL_BD_BUTTERFLY,                   -1, -1, FALSE,
+    IMG_BD_BUTTERFLY
+  },
+  {
+    EL_BD_BUTTERFLY_RIGHT,             -1, -1, FALSE,
+    IMG_BD_BUTTERFLY_RIGHT
+  },
+  {
+    EL_BD_BUTTERFLY,                   -1, MV_BIT_RIGHT, FALSE,
+    IMG_BD_BUTTERFLY_RIGHT
+  },
+  {
+    EL_BD_BUTTERFLY_UP,                        -1, -1, FALSE,
+    IMG_BD_BUTTERFLY_UP
+  },
+  {
+    EL_BD_BUTTERFLY,                   -1, MV_BIT_UP, FALSE,
+    IMG_BD_BUTTERFLY_UP
+  },
+  {
+    EL_BD_BUTTERFLY_LEFT,              -1, -1, FALSE,
+    IMG_BD_BUTTERFLY_LEFT
+  },
+  {
+    EL_BD_BUTTERFLY,                   -1, MV_BIT_LEFT, FALSE,
+    IMG_BD_BUTTERFLY_LEFT
+  },
+  {
+    EL_BD_BUTTERFLY_DOWN,              -1, -1, FALSE,
+    IMG_BD_BUTTERFLY_DOWN
+  },
+  {
+    EL_BD_BUTTERFLY,                   -1, MV_BIT_DOWN, FALSE,
+    IMG_BD_BUTTERFLY_DOWN
+  },
+  {
+    EL_BD_BUTTERFLY,                   ACTION_MOVING, -1, FALSE,
+    IMG_BD_BUTTERFLY_MOVING
+  },
+  {
+    EL_BD_FIREFLY,                     -1, -1, FALSE,
+    IMG_BD_FIREFLY
+  },
+  {
+    EL_BD_FIREFLY_RIGHT,               -1, -1, FALSE,
+    IMG_BD_FIREFLY_RIGHT
+  },
+  {
+    EL_BD_FIREFLY,                     -1, MV_BIT_RIGHT, FALSE,
+    IMG_BD_FIREFLY_RIGHT
+  },
+  {
+    EL_BD_FIREFLY_UP,                  -1, -1, FALSE,
+    IMG_BD_FIREFLY_UP
+  },
+  {
+    EL_BD_FIREFLY,                     -1, MV_BIT_UP, FALSE,
+    IMG_BD_FIREFLY_UP
+  },
+  {
+    EL_BD_FIREFLY_LEFT,                        -1, -1, FALSE,
+    IMG_BD_FIREFLY_LEFT
+  },
+  {
+    EL_BD_FIREFLY,                     -1, MV_BIT_LEFT, FALSE,
+    IMG_BD_FIREFLY_LEFT
+  },
+  {
+    EL_BD_FIREFLY_DOWN,                        -1, -1, FALSE,
+    IMG_BD_FIREFLY_DOWN
+  },
+  {
+    EL_BD_FIREFLY,                     -1, MV_BIT_DOWN, FALSE,
+    IMG_BD_FIREFLY_DOWN
+  },
+  {
+    EL_BD_FIREFLY,                     ACTION_MOVING, -1, FALSE,
+    IMG_BD_FIREFLY_MOVING
+  },
+  {
+    EL_SP_DEFAULT,                     ACTION_EXPLODING, -1, FALSE,
+    IMG_SP_DEFAULT_EXPLODING
+  },
+  {
+    EL_SP_EMPTY_SPACE,                 -1, -1, FALSE,
+    IMG_SP_EMPTY_SPACE
+  },
+  {
+    EL_SP_ZONK,                                -1, -1, FALSE,
+    IMG_SP_ZONK
+  },
+  {
+    EL_SP_ZONK,                                ACTION_MOVING, MV_BIT_LEFT, FALSE,
+    IMG_SP_ZONK_MOVING_LEFT
+  },
+  {
+    EL_SP_ZONK,                                ACTION_MOVING, MV_BIT_RIGHT, FALSE,
+    IMG_SP_ZONK_MOVING_RIGHT
+  },
+  {
+    EL_SP_ZONK,                                ACTION_PUSHING, MV_BIT_LEFT, FALSE,
+    IMG_SP_ZONK_PUSHING_LEFT
+  },
+  {
+    EL_SP_ZONK,                                ACTION_PUSHING, MV_BIT_RIGHT, FALSE,
+    IMG_SP_ZONK_PUSHING_RIGHT
+  },
+  {
+    EL_SP_BASE,                                -1, -1, FALSE,
+    IMG_SP_BASE
+  },
+  {
+    EL_SP_MURPHY,                      -1, -1, FALSE,
+    IMG_SP_MURPHY
+  },
+  {
+    EL_SP_MURPHY,                      ACTION_MOVING, MV_BIT_LEFT, FALSE,
+    IMG_SP_MURPHY_MOVING_LEFT
+  },
+  {
+    EL_SP_MURPHY,                      ACTION_MOVING, MV_BIT_RIGHT, FALSE,
+    IMG_SP_MURPHY_MOVING_RIGHT
+  },
+  {
+    EL_SP_MURPHY,                      ACTION_DIGGING, MV_BIT_LEFT, FALSE,
+    IMG_SP_MURPHY_DIGGING_LEFT
+  },
+  {
+    EL_SP_MURPHY,                      ACTION_DIGGING, MV_BIT_RIGHT, FALSE,
+    IMG_SP_MURPHY_DIGGING_RIGHT
+  },
+  {
+    EL_SP_MURPHY,                      ACTION_COLLECTING, MV_BIT_LEFT, FALSE,
+    IMG_SP_MURPHY_COLLECTING_LEFT
+  },
+  {
+    EL_SP_MURPHY,                      ACTION_COLLECTING, MV_BIT_RIGHT, FALSE,
+    IMG_SP_MURPHY_COLLECTING_RIGHT
+  },
+  {
+    EL_SP_MURPHY,                      ACTION_PUSHING, MV_BIT_LEFT, FALSE,
+    IMG_SP_MURPHY_PUSHING_LEFT
+  },
+  {
+    EL_SP_MURPHY,                      ACTION_PUSHING, MV_BIT_RIGHT, FALSE,
+    IMG_SP_MURPHY_PUSHING_RIGHT
+  },
+  {
+    EL_SP_MURPHY,                      ACTION_SNAPPING, MV_BIT_LEFT, FALSE,
+    IMG_SP_MURPHY_SNAPPING_LEFT
+  },
+  {
+    EL_SP_MURPHY,                      ACTION_SNAPPING, MV_BIT_RIGHT, FALSE,
+    IMG_SP_MURPHY_SNAPPING_RIGHT
+  },
+  {
+    EL_SP_MURPHY,                      ACTION_SNAPPING, MV_BIT_UP, FALSE,
+    IMG_SP_MURPHY_SNAPPING_UP
+  },
+  {
+    EL_SP_MURPHY,                      ACTION_SNAPPING, MV_BIT_DOWN, FALSE,
+    IMG_SP_MURPHY_SNAPPING_DOWN
+  },
+  {
+    EL_SP_MURPHY_CLONE,                        -1, -1, FALSE,
+    IMG_SP_MURPHY_CLONE
+  },
+  {
+    EL_SP_INFOTRON,                    -1, -1, FALSE,
+    IMG_SP_INFOTRON
+  },
+  {
+    EL_SP_CHIP_SINGLE,                 -1, -1, FALSE,
+    IMG_SP_CHIP_SINGLE
+  },
+  {
+    EL_SP_CHIP_LEFT,                   -1, -1, FALSE,
+    IMG_SP_CHIP_LEFT
+  },
+  {
+    EL_SP_CHIP_RIGHT,                  -1, -1, FALSE,
+    IMG_SP_CHIP_RIGHT
+  },
+  {
+    EL_SP_CHIP_TOP,                    -1, -1, FALSE,
+    IMG_SP_CHIP_TOP
+  },
+  {
+    EL_SP_CHIP_BOTTOM,                 -1, -1, FALSE,
+    IMG_SP_CHIP_BOTTOM
+  },
+  {
+    EL_SP_HARDWARE_GRAY,               -1, -1, FALSE,
+    IMG_SP_HARDWARE_GRAY
+  },
+  {
+    EL_SP_HARDWARE_GREEN,              -1, -1, FALSE,
+    IMG_SP_HARDWARE_GREEN
+  },
+  {
+    EL_SP_HARDWARE_BLUE,               -1, -1, FALSE,
+    IMG_SP_HARDWARE_BLUE
+  },
+  {
+    EL_SP_HARDWARE_RED,                        -1, -1, FALSE,
+    IMG_SP_HARDWARE_RED
+  },
+  {
+    EL_SP_HARDWARE_YELLOW,             -1, -1, FALSE,
+    IMG_SP_HARDWARE_YELLOW
+  },
+  {
+    EL_SP_EXIT_CLOSED,                 -1, -1, FALSE,
+    IMG_SP_EXIT_CLOSED
+  },
+  {
+    EL_SP_EXIT_OPEN,                   -1, -1, FALSE,
+    IMG_SP_EXIT_OPEN
+  },
+  {
+    EL_SP_DISK_ORANGE,                 -1, -1, FALSE,
+    IMG_SP_DISK_ORANGE
+  },
+  {
+    EL_SP_DISK_YELLOW,                 -1, -1, FALSE,
+    IMG_SP_DISK_YELLOW
+  },
+  {
+    EL_SP_DISK_RED,                    -1, -1, FALSE,
+    IMG_SP_DISK_RED
+  },
+  {
+    EL_SP_DISK_RED,                    ACTION_COLLECTING, -1, FALSE,
+    IMG_SP_DISK_RED_COLLECTING
+  },
+  {
+    EL_SP_PORT_RIGHT,                  -1, -1, FALSE,
+    IMG_SP_PORT_RIGHT
+  },
+  {
+    EL_SP_PORT_DOWN,                   -1, -1, FALSE,
+    IMG_SP_PORT_DOWN
+  },
+  {
+    EL_SP_PORT_LEFT,                   -1, -1, FALSE,
+    IMG_SP_PORT_LEFT
+  },
+  {
+    EL_SP_PORT_UP,                     -1, -1, FALSE,
+    IMG_SP_PORT_UP
+  },
+  {
+    EL_SP_PORT_HORIZONTAL,             -1, -1, FALSE,
+    IMG_SP_PORT_HORIZONTAL
+  },
+  {
+    EL_SP_PORT_VERTICAL,               -1, -1, FALSE,
+    IMG_SP_PORT_VERTICAL
+  },
+  {
+    EL_SP_PORT_ANY,                    -1, -1, FALSE,
+    IMG_SP_PORT_ANY
+  },
+  {
+    EL_SP_GRAVITY_PORT_RIGHT,          -1, -1, FALSE,
+    IMG_SP_GRAVITY_PORT_RIGHT
+  },
+  {
+    EL_SP_GRAVITY_PORT_DOWN,           -1, -1, FALSE,
+    IMG_SP_GRAVITY_PORT_DOWN
+  },
+  {
+    EL_SP_GRAVITY_PORT_LEFT,           -1, -1, FALSE,
+    IMG_SP_GRAVITY_PORT_LEFT
+  },
+  {
+    EL_SP_GRAVITY_PORT_UP,             -1, -1, FALSE,
+    IMG_SP_GRAVITY_PORT_UP
+  },
+  {
+    EL_SP_SNIKSNAK,                    -1, -1, FALSE,
+    IMG_SP_SNIKSNAK
+  },
+  {
+    EL_SP_SNIKSNAK,                    -1, MV_BIT_LEFT, FALSE,
+    IMG_SP_SNIKSNAK_LEFT
+  },
+  {
+    EL_SP_SNIKSNAK,                    -1, MV_BIT_RIGHT, FALSE,
+    IMG_SP_SNIKSNAK_RIGHT
+  },
+  {
+    EL_SP_SNIKSNAK,                    -1, MV_BIT_UP, FALSE,
+    IMG_SP_SNIKSNAK_UP
+  },
+  {
+    EL_SP_SNIKSNAK,                    -1, MV_BIT_DOWN, FALSE,
+    IMG_SP_SNIKSNAK_DOWN
+  },
+  {
+    EL_SP_ELECTRON,                    -1, -1, FALSE,
+    IMG_SP_ELECTRON
+  },
+  {
+    EL_SP_ELECTRON,                    ACTION_EXPLODING, -1, FALSE,
+    IMG_SP_ELECTRON_EXPLODING
+  },
+  {
+    EL_SP_TERMINAL,                    -1, -1, FALSE,
+    IMG_SP_TERMINAL
+  },
+  {
+    EL_SP_TERMINAL_ACTIVE,             -1, -1, FALSE,
+    IMG_SP_TERMINAL_ACTIVE
+  },
+  {
+    EL_SP_TERMINAL,                    ACTION_ACTIVE, -1, FALSE,
+    IMG_SP_TERMINAL_ACTIVE
+  },
+  {
+    EL_SP_BUGGY_BASE,                  -1, -1, FALSE,
+    IMG_SP_BUGGY_BASE
+  },
+  {
+    EL_SP_BUGGY_BASE_ACTIVATING,       -1, -1, FALSE,
+    IMG_SP_BUGGY_BASE_ACTIVATING
+  },
+  {
+    EL_SP_BUGGY_BASE,                  ACTION_ACTIVATING, -1, FALSE,
+    IMG_SP_BUGGY_BASE_ACTIVATING
+  },
+  {
+    EL_SP_BUGGY_BASE_ACTIVE,           -1, -1, FALSE,
+    IMG_SP_BUGGY_BASE_ACTIVE
+  },
+  {
+    EL_SP_BUGGY_BASE,                  ACTION_ACTIVE, -1, FALSE,
+    IMG_SP_BUGGY_BASE_ACTIVE
+  },
+  {
+    EL_SP_HARDWARE_BASE_1,             -1, -1, FALSE,
+    IMG_SP_HARDWARE_BASE_1
+  },
+  {
+    EL_SP_HARDWARE_BASE_2,             -1, -1, FALSE,
+    IMG_SP_HARDWARE_BASE_2
+  },
+  {
+    EL_SP_HARDWARE_BASE_3,             -1, -1, FALSE,
+    IMG_SP_HARDWARE_BASE_3
+  },
+  {
+    EL_SP_HARDWARE_BASE_4,             -1, -1, FALSE,
+    IMG_SP_HARDWARE_BASE_4
+  },
+  {
+    EL_SP_HARDWARE_BASE_5,             -1, -1, FALSE,
+    IMG_SP_HARDWARE_BASE_5
+  },
+  {
+    EL_SP_HARDWARE_BASE_6,             -1, -1, FALSE,
+    IMG_SP_HARDWARE_BASE_6
+  },
+  {
+    EL_SOKOBAN_OBJECT,                 -1, -1, FALSE,
+    IMG_SOKOBAN_OBJECT
+  },
+  {
+    EL_SOKOBAN_FIELD_EMPTY,            -1, -1, FALSE,
+    IMG_SOKOBAN_FIELD_EMPTY
+  },
+  {
+    EL_SOKOBAN_FIELD_FULL,             -1, -1, FALSE,
+    IMG_SOKOBAN_FIELD_FULL
+  },
+  {
+    EL_EMPTY_SPACE,                    -1, -1, FALSE,
+    IMG_EMPTY_SPACE
+  },
+  {
+    EL_SAND,                           -1, -1, FALSE,
+    IMG_SAND
+  },
+  {
+    EL_SAND,                           -1, -1, TRUE,
+    IMG_SAND_CRUMBLED
+  },
+  {
+    EL_SAND,                           ACTION_DIGGING, MV_BIT_LEFT, FALSE,
+    IMG_SAND_DIGGING_LEFT
+  },
+  {
+    EL_SAND,                           ACTION_DIGGING, MV_BIT_RIGHT, FALSE,
+    IMG_SAND_DIGGING_RIGHT
+  },
+  {
+    EL_SAND,                           ACTION_DIGGING, MV_BIT_UP, FALSE,
+    IMG_SAND_DIGGING_UP
+  },
+  {
+    EL_SAND,                           ACTION_DIGGING, MV_BIT_DOWN, FALSE,
+    IMG_SAND_DIGGING_DOWN
+  },
+  {
+    EL_SAND,                           ACTION_DIGGING, MV_BIT_LEFT, TRUE,
+    IMG_SAND_DIGGING_LEFT_CRUMBLED
+  },
+  {
+    EL_SAND,                           ACTION_DIGGING, MV_BIT_RIGHT, TRUE,
+    IMG_SAND_DIGGING_RIGHT_CRUMBLED
+  },
+  {
+    EL_SAND,                           ACTION_DIGGING, MV_BIT_UP, TRUE,
+    IMG_SAND_DIGGING_UP_CRUMBLED
+  },
+  {
+    EL_SAND,                           ACTION_DIGGING, MV_BIT_DOWN, TRUE,
+    IMG_SAND_DIGGING_DOWN_CRUMBLED
+  },
+  {
+    EL_WALL,                           -1, -1, FALSE,
+    IMG_WALL
+  },
+  {
+    EL_WALL_SLIPPERY,                  -1, -1, FALSE,
+    IMG_WALL_SLIPPERY
+  },
+  {
+    EL_STEELWALL,                      -1, -1, FALSE,
+    IMG_STEELWALL
+  },
+  {
+    EL_ROCK,                           -1, -1, FALSE,
+    IMG_ROCK
+  },
+  {
+    EL_ROCK,                           ACTION_MOVING, MV_BIT_LEFT, FALSE,
+    IMG_ROCK_MOVING_LEFT
+  },
+  {
+    EL_ROCK,                           ACTION_MOVING, MV_BIT_RIGHT, FALSE,
+    IMG_ROCK_MOVING_RIGHT
+  },
+  {
+    EL_ROCK,                           ACTION_PUSHING, MV_BIT_LEFT, FALSE,
+    IMG_ROCK_PUSHING_LEFT
+  },
+  {
+    EL_ROCK,                           ACTION_PUSHING, MV_BIT_RIGHT, FALSE,
+    IMG_ROCK_PUSHING_RIGHT
+  },
+  {
+    EL_EMERALD,                                -1, -1, FALSE,
+    IMG_EMERALD
+  },
+  {
+    EL_EMERALD,                                ACTION_MOVING, -1, FALSE,
+    IMG_EMERALD_MOVING
+  },
+  {
+    EL_EMERALD,                                ACTION_FALLING, -1, FALSE,
+    IMG_EMERALD_FALLING
+  },
+  {
+    EL_EMERALD,                                ACTION_COLLECTING, -1, FALSE,
+    IMG_EMERALD_COLLECTING
+  },
+  {
+    EL_DIAMOND,                                -1, -1, FALSE,
+    IMG_DIAMOND
+  },
+  {
+    EL_DIAMOND,                                ACTION_MOVING, -1, FALSE,
+    IMG_DIAMOND_MOVING
+  },
+  {
+    EL_DIAMOND,                                ACTION_FALLING, -1, FALSE,
+    IMG_DIAMOND_FALLING
+  },
+  {
+    EL_DIAMOND,                                ACTION_COLLECTING, -1, FALSE,
+    IMG_DIAMOND_COLLECTING
+  },
+  {
+    EL_BOMB,                           -1, -1, FALSE,
+    IMG_BOMB
+  },
+  {
+    EL_NUT,                            -1, -1, FALSE,
+    IMG_NUT
+  },
+  {
+    EL_NUT_BREAKING,                   -1, -1, FALSE,
+    IMG_NUT_BREAKING
+  },
+  {
+    EL_NUT,                            ACTION_BREAKING, -1, FALSE,
+    IMG_NUT_BREAKING
+  },
+  {
+    EL_DYNAMITE,                       -1, -1, FALSE,
+    IMG_DYNAMITE
+  },
+  {
+    EL_DYNAMITE_ACTIVE,                        -1, -1, FALSE,
+    IMG_DYNAMITE_ACTIVE
+  },
+  {
+    EL_DYNAMITE,                       ACTION_ACTIVE, -1, FALSE,
+    IMG_DYNAMITE_ACTIVE
+  },
+  {
+    EL_WALL_EMERALD,                   -1, -1, FALSE,
+    IMG_WALL_EMERALD
+  },
+  {
+    EL_WALL_DIAMOND,                   -1, -1, FALSE,
+    IMG_WALL_DIAMOND
+  },
+  {
+    EL_BUG,                            -1, -1, FALSE,
+    IMG_BUG
+  },
+  {
+    EL_BUG_RIGHT,                      -1, -1, FALSE,
+    IMG_BUG_RIGHT
+  },
+  {
+    EL_BUG,                            -1, MV_BIT_RIGHT, FALSE,
+    IMG_BUG_RIGHT
+  },
+  {
+    EL_BUG_UP,                         -1, -1, FALSE,
+    IMG_BUG_UP
+  },
+  {
+    EL_BUG,                            -1, MV_BIT_UP, FALSE,
+    IMG_BUG_UP
+  },
+  {
+    EL_BUG_LEFT,                       -1, -1, FALSE,
+    IMG_BUG_LEFT
+  },
+  {
+    EL_BUG,                            -1, MV_BIT_LEFT, FALSE,
+    IMG_BUG_LEFT
+  },
+  {
+    EL_BUG_DOWN,                       -1, -1, FALSE,
+    IMG_BUG_DOWN
+  },
+  {
+    EL_BUG,                            -1, MV_BIT_DOWN, FALSE,
+    IMG_BUG_DOWN
+  },
+  {
+    EL_BUG,                            ACTION_MOVING, MV_BIT_RIGHT, FALSE,
+    IMG_BUG_MOVING_RIGHT
+  },
+  {
+    EL_BUG,                            ACTION_MOVING, MV_BIT_UP, FALSE,
+    IMG_BUG_MOVING_UP
+  },
+  {
+    EL_BUG,                            ACTION_MOVING, MV_BIT_LEFT, FALSE,
+    IMG_BUG_MOVING_LEFT
+  },
+  {
+    EL_BUG,                            ACTION_MOVING, MV_BIT_DOWN, FALSE,
+    IMG_BUG_MOVING_DOWN
+  },
+  {
+    EL_SPACESHIP,                      -1, -1, FALSE,
+    IMG_SPACESHIP
+  },
+  {
+    EL_SPACESHIP_RIGHT,                        -1, -1, FALSE,
+    IMG_SPACESHIP_RIGHT
+  },
+  {
+    EL_SPACESHIP,                      -1, MV_BIT_RIGHT, FALSE,
+    IMG_SPACESHIP_RIGHT
+  },
+  {
+    EL_SPACESHIP_UP,                   -1, -1, FALSE,
+    IMG_SPACESHIP_UP
+  },
+  {
+    EL_SPACESHIP,                      -1, MV_BIT_UP, FALSE,
+    IMG_SPACESHIP_UP
+  },
+  {
+    EL_SPACESHIP_LEFT,                 -1, -1, FALSE,
+    IMG_SPACESHIP_LEFT
+  },
+  {
+    EL_SPACESHIP,                      -1, MV_BIT_LEFT, FALSE,
+    IMG_SPACESHIP_LEFT
+  },
+  {
+    EL_SPACESHIP_DOWN,                 -1, -1, FALSE,
+    IMG_SPACESHIP_DOWN
+  },
+  {
+    EL_SPACESHIP,                      -1, MV_BIT_DOWN, FALSE,
+    IMG_SPACESHIP_DOWN
+  },
+  {
+    EL_SPACESHIP,                      ACTION_MOVING, MV_BIT_RIGHT, FALSE,
+    IMG_SPACESHIP_MOVING_RIGHT
+  },
+  {
+    EL_SPACESHIP,                      ACTION_MOVING, MV_BIT_UP, FALSE,
+    IMG_SPACESHIP_MOVING_UP
+  },
+  {
+    EL_SPACESHIP,                      ACTION_MOVING, MV_BIT_LEFT, FALSE,
+    IMG_SPACESHIP_MOVING_LEFT
+  },
+  {
+    EL_SPACESHIP,                      ACTION_MOVING, MV_BIT_DOWN, FALSE,
+    IMG_SPACESHIP_MOVING_DOWN
+  },
+  {
+    EL_YAMYAM,                         -1, -1, FALSE,
+    IMG_YAMYAM
+  },
+  {
+    EL_YAMYAM,                         ACTION_MOVING, -1, FALSE,
+    IMG_YAMYAM_MOVING
+  },
+  {
+    EL_ROBOT,                          -1, -1, FALSE,
+    IMG_ROBOT
+  },
+  {
+    EL_ROBOT,                          ACTION_MOVING, -1, FALSE,
+    IMG_ROBOT_MOVING
+  },
+  {
+    EL_ROBOT_WHEEL,                    -1, -1, FALSE,
+    IMG_ROBOT_WHEEL
+  },
+  {
+    EL_ROBOT_WHEEL_ACTIVE,             -1, -1, FALSE,
+    IMG_ROBOT_WHEEL_ACTIVE
+  },
+  {
+    EL_ROBOT_WHEEL,                    ACTION_ACTIVE, -1, FALSE,
+    IMG_ROBOT_WHEEL_ACTIVE
+  },
+  {
+    EL_MAGIC_WALL,                     -1, -1, FALSE,
+    IMG_MAGIC_WALL
+  },
+  {
+    EL_MAGIC_WALL_ACTIVE,              -1, -1, FALSE,
+    IMG_MAGIC_WALL_ACTIVE
+  },
+  {
+    EL_MAGIC_WALL,                     ACTION_ACTIVE, -1, FALSE,
+    IMG_MAGIC_WALL_ACTIVE
+  },
+  {
+    EL_MAGIC_WALL_FILLING,             -1, -1, FALSE,
+    IMG_MAGIC_WALL_FILLING
+  },
+  {
+    EL_MAGIC_WALL,                     ACTION_FILLING, -1, FALSE,
+    IMG_MAGIC_WALL_FILLING
+  },
+  {
+    EL_MAGIC_WALL_FULL,                        -1, -1, FALSE,
+    IMG_MAGIC_WALL_FULL
+  },
+  {
+    EL_MAGIC_WALL_EMPTYING,            -1, -1, FALSE,
+    IMG_MAGIC_WALL_EMPTYING
+  },
+  {
+    EL_MAGIC_WALL,                     ACTION_EMPTYING, -1, FALSE,
+    IMG_MAGIC_WALL_EMPTYING
+  },
+  {
+    EL_MAGIC_WALL_DEAD,                        -1, -1, FALSE,
+    IMG_MAGIC_WALL_DEAD
+  },
+  {
+    EL_QUICKSAND_EMPTY,                        -1, -1, FALSE,
+    IMG_QUICKSAND_EMPTY
+  },
+  {
+    EL_QUICKSAND_FILLING,              -1, -1, FALSE,
+    IMG_QUICKSAND_FILLING
+  },
+  {
+    EL_QUICKSAND_FULL,                 -1, -1, FALSE,
+    IMG_QUICKSAND_FULL
+  },
+  {
+    EL_QUICKSAND_EMPTYING,             -1, -1, FALSE,
+    IMG_QUICKSAND_EMPTYING
+  },
+  {
+    EL_ACID_POOL_TOPLEFT,              -1, -1, FALSE,
+    IMG_ACID_POOL_TOPLEFT
+  },
+  {
+    EL_ACID_POOL_TOPRIGHT,             -1, -1, FALSE,
+    IMG_ACID_POOL_TOPRIGHT
+  },
+  {
+    EL_ACID_POOL_BOTTOMLEFT,           -1, -1, FALSE,
+    IMG_ACID_POOL_BOTTOMLEFT
+  },
+  {
+    EL_ACID_POOL_BOTTOM,               -1, -1, FALSE,
+    IMG_ACID_POOL_BOTTOM
+  },
+  {
+    EL_ACID_POOL_BOTTOMRIGHT,          -1, -1, FALSE,
+    IMG_ACID_POOL_BOTTOMRIGHT
+  },
+  {
+    EL_ACID,                           -1, -1, FALSE,
+    IMG_ACID
+  },
+  {
+    EL_ACID_SPLASH_LEFT,               -1, -1, FALSE,
+    IMG_ACID_SPLASH_LEFT
+  },
+  {
+    EL_ACID_SPLASH_RIGHT,              -1, -1, FALSE,
+    IMG_ACID_SPLASH_RIGHT
+  },
+  {
+    EL_AMOEBA_DROP,                    -1, -1, FALSE,
+    IMG_AMOEBA_DROP
+  },
+  {
+    EL_AMOEBA_GROWING,                 -1, -1, FALSE,
+    IMG_AMOEBA_GROWING
+  },
+  {
+    EL_AMOEBA_SHRINKING,               -1, -1, FALSE,
+    IMG_AMOEBA_SHRINKING
+  },
+  {
+    EL_AMOEBA_WET,                     -1, -1, FALSE,
+    IMG_AMOEBA_WET
+  },
+  {
+    EL_AMOEBA_DROPPING,                        -1, -1, FALSE,
+    IMG_AMOEBA_DROPPING
+  },
+  {
+    EL_AMOEBA_DRY,                     -1, -1, FALSE,
+    IMG_AMOEBA_DRY
+  },
+  {
+    EL_AMOEBA_FULL,                    -1, -1, FALSE,
+    IMG_AMOEBA_FULL
+  },
+  {
+    EL_AMOEBA_DEAD,                    -1, -1, FALSE,
+    IMG_AMOEBA_DEAD
+  },
+  {
+    EL_EM_KEY_1,                       -1, -1, FALSE,
+    IMG_EM_KEY_1
+  },
+  {
+    EL_EM_KEY_2,                       -1, -1, FALSE,
+    IMG_EM_KEY_2
+  },
+  {
+    EL_EM_KEY_3,                       -1, -1, FALSE,
+    IMG_EM_KEY_3
+  },
+  {
+    EL_EM_KEY_4,                       -1, -1, FALSE,
+    IMG_EM_KEY_4
+  },
+  {
+    EL_EM_GATE_1,                      -1, -1, FALSE,
+    IMG_EM_GATE_1
+  },
+  {
+    EL_EM_GATE_2,                      -1, -1, FALSE,
+    IMG_EM_GATE_2
+  },
+  {
+    EL_EM_GATE_3,                      -1, -1, FALSE,
+    IMG_EM_GATE_3
+  },
+  {
+    EL_EM_GATE_4,                      -1, -1, FALSE,
+    IMG_EM_GATE_4
+  },
+  {
+    EL_EM_GATE_1_GRAY,                 -1, -1, FALSE,
+    IMG_EM_GATE_1_GRAY
+  },
+  {
+    EL_EM_GATE_2_GRAY,                 -1, -1, FALSE,
+    IMG_EM_GATE_2_GRAY
+  },
+  {
+    EL_EM_GATE_3_GRAY,                 -1, -1, FALSE,
+    IMG_EM_GATE_3_GRAY
+  },
+  {
+    EL_EM_GATE_4_GRAY,                 -1, -1, FALSE,
+    IMG_EM_GATE_4_GRAY
+  },
+  {
+    EL_EXIT_CLOSED,                    -1, -1, FALSE,
+    IMG_EXIT_CLOSED
+  },
+  {
+    EL_EXIT_OPENING,                   -1, -1, FALSE,
+    IMG_EXIT_OPENING
+  },
+  {
+    EL_EXIT_OPEN,                      -1, -1, FALSE,
+    IMG_EXIT_OPEN
+  },
+  {
+    EL_BALLOON,                                -1, -1, FALSE,
+    IMG_BALLOON
+  },
+  {
+    EL_BALLOON,                                ACTION_MOVING, -1, FALSE,
+    IMG_BALLOON_MOVING
+  },
+  {
+    EL_BALLOON,                                ACTION_PUSHING, -1, FALSE,
+    IMG_BALLOON_PUSHING
+  },
+  {
+    EL_BALLOON_SWITCH_LEFT,            -1, -1, FALSE,
+    IMG_BALLOON_SWITCH_LEFT
+  },
+  {
+    EL_BALLOON_SWITCH_RIGHT,           -1, -1, FALSE,
+    IMG_BALLOON_SWITCH_RIGHT
+  },
+  {
+    EL_BALLOON_SWITCH_UP,              -1, -1, FALSE,
+    IMG_BALLOON_SWITCH_UP
+  },
+  {
+    EL_BALLOON_SWITCH_DOWN,            -1, -1, FALSE,
+    IMG_BALLOON_SWITCH_DOWN
+  },
+  {
+    EL_BALLOON_SWITCH_ANY,             -1, -1, FALSE,
+    IMG_BALLOON_SWITCH_ANY
+  },
+  {
+    EL_SPRING,                         -1, -1, FALSE,
+    IMG_SPRING
+  },
+  {
+    EL_EMC_STEELWALL_1,                        -1, -1, FALSE,
+    IMG_EMC_STEELWALL_1
+  },
+  {
+    EL_EMC_STEELWALL_2,                        -1, -1, FALSE,
+    IMG_EMC_STEELWALL_2
+  },
+  {
+    EL_EMC_STEELWALL_3,                        -1, -1, FALSE,
+    IMG_EMC_STEELWALL_3
+  },
+  {
+    EL_EMC_STEELWALL_4,                        -1, -1, FALSE,
+    IMG_EMC_STEELWALL_4
+  },
+  {
+    EL_EMC_WALL_1,                     -1, -1, FALSE,
+    IMG_EMC_WALL_1
+  },
+  {
+    EL_EMC_WALL_2,                     -1, -1, FALSE,
+    IMG_EMC_WALL_2
+  },
+  {
+    EL_EMC_WALL_3,                     -1, -1, FALSE,
+    IMG_EMC_WALL_3
+  },
+  {
+    EL_EMC_WALL_4,                     -1, -1, FALSE,
+    IMG_EMC_WALL_4
+  },
+  {
+    EL_EMC_WALL_5,                     -1, -1, FALSE,
+    IMG_EMC_WALL_5
+  },
+  {
+    EL_EMC_WALL_6,                     -1, -1, FALSE,
+    IMG_EMC_WALL_6
+  },
+  {
+    EL_EMC_WALL_7,                     -1, -1, FALSE,
+    IMG_EMC_WALL_7
+  },
+  {
+    EL_EMC_WALL_8,                     -1, -1, FALSE,
+    IMG_EMC_WALL_8
+  },
+  {
+    EL_INVISIBLE_STEELWALL,            -1, -1, FALSE,
+    IMG_INVISIBLE_STEELWALL
+  },
+  {
+    EL_INVISIBLE_STEELWALL_ACTIVE,     -1, -1, FALSE,
+    IMG_INVISIBLE_STEELWALL_ACTIVE
+  },
+  {
+    EL_INVISIBLE_STEELWALL,            ACTION_ACTIVE, -1, FALSE,
+    IMG_INVISIBLE_STEELWALL_ACTIVE
+  },
+  {
+    EL_INVISIBLE_WALL,                 -1, -1, FALSE,
+    IMG_INVISIBLE_WALL
+  },
+  {
+    EL_INVISIBLE_WALL_ACTIVE,          -1, -1, FALSE,
+    IMG_INVISIBLE_WALL_ACTIVE
+  },
+  {
+    EL_INVISIBLE_WALL,                 ACTION_ACTIVE, -1, FALSE,
+    IMG_INVISIBLE_WALL_ACTIVE
+  },
+  {
+    EL_INVISIBLE_SAND,                 -1, -1, FALSE,
+    IMG_INVISIBLE_SAND
+  },
+  {
+    EL_INVISIBLE_SAND_ACTIVE,          -1, -1, FALSE,
+    IMG_INVISIBLE_SAND_ACTIVE
+  },
+  {
+    EL_INVISIBLE_SAND,                 ACTION_ACTIVE, -1, FALSE,
+    IMG_INVISIBLE_SAND_ACTIVE
+  },
+  {
+    EL_CONVEYOR_BELT_1_MIDDLE,         -1, -1, FALSE,
+    IMG_CONVEYOR_BELT_1_MIDDLE
+  },
+  {
+    EL_CONVEYOR_BELT_1_MIDDLE_ACTIVE,  -1, -1, FALSE,
+    IMG_CONVEYOR_BELT_1_MIDDLE_ACTIVE
+  },
+  {
+    EL_CONVEYOR_BELT_1_MIDDLE,         ACTION_ACTIVE, -1, FALSE,
+    IMG_CONVEYOR_BELT_1_MIDDLE_ACTIVE
+  },
+  {
+    EL_CONVEYOR_BELT_1_LEFT,           -1, -1, FALSE,
+    IMG_CONVEYOR_BELT_1_LEFT
+  },
+  {
+    EL_CONVEYOR_BELT_1_LEFT_ACTIVE,    -1, -1, FALSE,
+    IMG_CONVEYOR_BELT_1_LEFT_ACTIVE
+  },
+  {
+    EL_CONVEYOR_BELT_1_LEFT,           ACTION_ACTIVE, -1, FALSE,
+    IMG_CONVEYOR_BELT_1_LEFT_ACTIVE
+  },
+  {
+    EL_CONVEYOR_BELT_1_RIGHT,          -1, -1, FALSE,
+    IMG_CONVEYOR_BELT_1_RIGHT
+  },
+  {
+    EL_CONVEYOR_BELT_1_RIGHT_ACTIVE,   -1, -1, FALSE,
+    IMG_CONVEYOR_BELT_1_RIGHT_ACTIVE
+  },
+  {
+    EL_CONVEYOR_BELT_1_RIGHT,          ACTION_ACTIVE, -1, FALSE,
+    IMG_CONVEYOR_BELT_1_RIGHT_ACTIVE
+  },
+  {
+    EL_CONVEYOR_BELT_1_SWITCH_LEFT,    -1, -1, FALSE,
+    IMG_CONVEYOR_BELT_1_SWITCH_LEFT
+  },
+  {
+    EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,  -1, -1, FALSE,
+    IMG_CONVEYOR_BELT_1_SWITCH_MIDDLE
+  },
+  {
+    EL_CONVEYOR_BELT_1_SWITCH_RIGHT,   -1, -1, FALSE,
+    IMG_CONVEYOR_BELT_1_SWITCH_RIGHT
+  },
+  {
+    EL_CONVEYOR_BELT_2_MIDDLE,         -1, -1, FALSE,
+    IMG_CONVEYOR_BELT_2_MIDDLE
+  },
+  {
+    EL_CONVEYOR_BELT_2_MIDDLE_ACTIVE,  -1, -1, FALSE,
+    IMG_CONVEYOR_BELT_2_MIDDLE_ACTIVE
+  },
+  {
+    EL_CONVEYOR_BELT_2_MIDDLE,         ACTION_ACTIVE, -1, FALSE,
+    IMG_CONVEYOR_BELT_2_MIDDLE_ACTIVE
+  },
+  {
+    EL_CONVEYOR_BELT_2_LEFT,           -1, -1, FALSE,
+    IMG_CONVEYOR_BELT_2_LEFT
+  },
+  {
+    EL_CONVEYOR_BELT_2_LEFT_ACTIVE,    -1, -1, FALSE,
+    IMG_CONVEYOR_BELT_2_LEFT_ACTIVE
+  },
+  {
+    EL_CONVEYOR_BELT_2_LEFT,           ACTION_ACTIVE, -1, FALSE,
+    IMG_CONVEYOR_BELT_2_LEFT_ACTIVE
+  },
+  {
+    EL_CONVEYOR_BELT_2_RIGHT,          -1, -1, FALSE,
+    IMG_CONVEYOR_BELT_2_RIGHT
+  },
+  {
+    EL_CONVEYOR_BELT_2_RIGHT_ACTIVE,   -1, -1, FALSE,
+    IMG_CONVEYOR_BELT_2_RIGHT_ACTIVE
+  },
+  {
+    EL_CONVEYOR_BELT_2_RIGHT,          ACTION_ACTIVE, -1, FALSE,
+    IMG_CONVEYOR_BELT_2_RIGHT_ACTIVE
+  },
+  {
+    EL_CONVEYOR_BELT_2_SWITCH_LEFT,    -1, -1, FALSE,
+    IMG_CONVEYOR_BELT_2_SWITCH_LEFT
+  },
+  {
+    EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,  -1, -1, FALSE,
+    IMG_CONVEYOR_BELT_2_SWITCH_MIDDLE
+  },
+  {
+    EL_CONVEYOR_BELT_2_SWITCH_RIGHT,   -1, -1, FALSE,
+    IMG_CONVEYOR_BELT_2_SWITCH_RIGHT
+  },
+  {
+    EL_CONVEYOR_BELT_3_MIDDLE,         -1, -1, FALSE,
+    IMG_CONVEYOR_BELT_3_MIDDLE
+  },
+  {
+    EL_CONVEYOR_BELT_3_MIDDLE_ACTIVE,  -1, -1, FALSE,
+    IMG_CONVEYOR_BELT_3_MIDDLE_ACTIVE
+  },
+  {
+    EL_CONVEYOR_BELT_3_MIDDLE,         ACTION_ACTIVE, -1, FALSE,
+    IMG_CONVEYOR_BELT_3_MIDDLE_ACTIVE
+  },
+  {
+    EL_CONVEYOR_BELT_3_LEFT,           -1, -1, FALSE,
+    IMG_CONVEYOR_BELT_3_LEFT
+  },
+  {
+    EL_CONVEYOR_BELT_3_LEFT_ACTIVE,    -1, -1, FALSE,
+    IMG_CONVEYOR_BELT_3_LEFT_ACTIVE
+  },
+  {
+    EL_CONVEYOR_BELT_3_LEFT,           ACTION_ACTIVE, -1, FALSE,
+    IMG_CONVEYOR_BELT_3_LEFT_ACTIVE
+  },
+  {
+    EL_CONVEYOR_BELT_3_RIGHT,          -1, -1, FALSE,
+    IMG_CONVEYOR_BELT_3_RIGHT
+  },
+  {
+    EL_CONVEYOR_BELT_3_RIGHT_ACTIVE,   -1, -1, FALSE,
+    IMG_CONVEYOR_BELT_3_RIGHT_ACTIVE
+  },
+  {
+    EL_CONVEYOR_BELT_3_RIGHT,          ACTION_ACTIVE, -1, FALSE,
+    IMG_CONVEYOR_BELT_3_RIGHT_ACTIVE
+  },
+  {
+    EL_CONVEYOR_BELT_3_SWITCH_LEFT,    -1, -1, FALSE,
+    IMG_CONVEYOR_BELT_3_SWITCH_LEFT
+  },
+  {
+    EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,  -1, -1, FALSE,
+    IMG_CONVEYOR_BELT_3_SWITCH_MIDDLE
+  },
+  {
+    EL_CONVEYOR_BELT_3_SWITCH_RIGHT,   -1, -1, FALSE,
+    IMG_CONVEYOR_BELT_3_SWITCH_RIGHT
+  },
+  {
+    EL_CONVEYOR_BELT_4_MIDDLE,         -1, -1, FALSE,
+    IMG_CONVEYOR_BELT_4_MIDDLE
+  },
+  {
+    EL_CONVEYOR_BELT_4_MIDDLE_ACTIVE,  -1, -1, FALSE,
+    IMG_CONVEYOR_BELT_4_MIDDLE_ACTIVE
+  },
+  {
+    EL_CONVEYOR_BELT_4_MIDDLE,         ACTION_ACTIVE, -1, FALSE,
+    IMG_CONVEYOR_BELT_4_MIDDLE_ACTIVE
+  },
+  {
+    EL_CONVEYOR_BELT_4_LEFT,           -1, -1, FALSE,
+    IMG_CONVEYOR_BELT_4_LEFT
+  },
+  {
+    EL_CONVEYOR_BELT_4_LEFT_ACTIVE,    -1, -1, FALSE,
+    IMG_CONVEYOR_BELT_4_LEFT_ACTIVE
+  },
+  {
+    EL_CONVEYOR_BELT_4_LEFT,           ACTION_ACTIVE, -1, FALSE,
+    IMG_CONVEYOR_BELT_4_LEFT_ACTIVE
+  },
+  {
+    EL_CONVEYOR_BELT_4_RIGHT,          -1, -1, FALSE,
+    IMG_CONVEYOR_BELT_4_RIGHT
+  },
+  {
+    EL_CONVEYOR_BELT_4_RIGHT_ACTIVE,   -1, -1, FALSE,
+    IMG_CONVEYOR_BELT_4_RIGHT_ACTIVE
+  },
+  {
+    EL_CONVEYOR_BELT_4_RIGHT,          ACTION_ACTIVE, -1, FALSE,
+    IMG_CONVEYOR_BELT_4_RIGHT_ACTIVE
+  },
+  {
+    EL_CONVEYOR_BELT_4_SWITCH_LEFT,    -1, -1, FALSE,
+    IMG_CONVEYOR_BELT_4_SWITCH_LEFT
+  },
+  {
+    EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,  -1, -1, FALSE,
+    IMG_CONVEYOR_BELT_4_SWITCH_MIDDLE
+  },
+  {
+    EL_CONVEYOR_BELT_4_SWITCH_RIGHT,   -1, -1, FALSE,
+    IMG_CONVEYOR_BELT_4_SWITCH_RIGHT
+  },
+  {
+    EL_SWITCHGATE_SWITCH_UP,           -1, -1, FALSE,
+    IMG_SWITCHGATE_SWITCH_UP
+  },
+  {
+    EL_SWITCHGATE_SWITCH_DOWN,         -1, -1, FALSE,
+    IMG_SWITCHGATE_SWITCH_DOWN
+  },
+  {
+    EL_LIGHT_SWITCH,                   -1, -1, FALSE,
+    IMG_LIGHT_SWITCH
+  },
+  {
+    EL_LIGHT_SWITCH_ACTIVE,            -1, -1, FALSE,
+    IMG_LIGHT_SWITCH_ACTIVE
+  },
+  {
+    EL_LIGHT_SWITCH,                   ACTION_ACTIVE, -1, FALSE,
+    IMG_LIGHT_SWITCH_ACTIVE
+  },
+  {
+    EL_TIMEGATE_SWITCH,                        -1, -1, FALSE,
+    IMG_TIMEGATE_SWITCH
+  },
+  {
+    EL_TIMEGATE_SWITCH_ACTIVE,         -1, -1, FALSE,
+    IMG_TIMEGATE_SWITCH_ACTIVE
+  },
+  {
+    EL_TIMEGATE_SWITCH,                        ACTION_ACTIVE, -1, FALSE,
+    IMG_TIMEGATE_SWITCH_ACTIVE
+  },
+  {
+    EL_ENVELOPE,                       -1, -1, FALSE,
+    IMG_ENVELOPE
+  },
+  {
+    EL_SIGN_EXCLAMATION,               -1, -1, FALSE,
+    IMG_SIGN_EXCLAMATION
+  },
+  {
+    EL_SIGN_STOP,                      -1, -1, FALSE,
+    IMG_SIGN_STOP
+  },
+  {
+    EL_LANDMINE,                       -1, -1, FALSE,
+    IMG_LANDMINE
+  },
+  {
+    EL_STEELWALL_SLIPPERY,             -1, -1, FALSE,
+    IMG_STEELWALL_SLIPPERY
+  },
+  {
+    EL_EXTRA_TIME,                     -1, -1, FALSE,
+    IMG_EXTRA_TIME
+  },
+  {
+    EL_SHIELD_NORMAL,                  -1, -1, FALSE,
+    IMG_SHIELD_NORMAL
+  },
+  {
+    EL_SHIELD_NORMAL_ACTIVE,           -1, -1, FALSE,
+    IMG_SHIELD_NORMAL_ACTIVE
+  },
+  {
+    EL_SHIELD_NORMAL,                  ACTION_ACTIVE, -1, FALSE,
+    IMG_SHIELD_NORMAL_ACTIVE
+  },
+  {
+    EL_SHIELD_DEADLY,                  -1, -1, FALSE,
+    IMG_SHIELD_DEADLY
+  },
+  {
+    EL_SHIELD_DEADLY_ACTIVE,           -1, -1, FALSE,
+    IMG_SHIELD_DEADLY_ACTIVE
+  },
+  {
+    EL_SHIELD_DEADLY,                  ACTION_ACTIVE, -1, FALSE,
+    IMG_SHIELD_DEADLY_ACTIVE
+  },
+  {
+    EL_SWITCHGATE_CLOSED,              -1, -1, FALSE,
+    IMG_SWITCHGATE_CLOSED
+  },
+  {
+    EL_SWITCHGATE_OPENING,             -1, -1, FALSE,
+    IMG_SWITCHGATE_OPENING
+  },
+  {
+    EL_SWITCHGATE_OPEN,                        -1, -1, FALSE,
+    IMG_SWITCHGATE_OPEN
+  },
+  {
+    EL_SWITCHGATE_CLOSING,             -1, -1, FALSE,
+    IMG_SWITCHGATE_CLOSING
+  },
+  {
+    EL_TIMEGATE_CLOSED,                        -1, -1, FALSE,
+    IMG_TIMEGATE_CLOSED
+  },
+  {
+    EL_TIMEGATE_OPENING,               -1, -1, FALSE,
+    IMG_TIMEGATE_OPENING
+  },
+  {
+    EL_TIMEGATE_OPEN,                  -1, -1, FALSE,
+    IMG_TIMEGATE_OPEN
+  },
+  {
+    EL_TIMEGATE_CLOSING,               -1, -1, FALSE,
+    IMG_TIMEGATE_CLOSING
+  },
+  {
+    EL_PEARL,                          -1, -1, FALSE,
+    IMG_PEARL
+  },
+  {
+    EL_PEARL_BREAKING,                 -1, -1, FALSE,
+    IMG_PEARL_BREAKING
+  },
+  {
+    EL_PEARL,                          ACTION_BREAKING, -1, FALSE,
+    IMG_PEARL_BREAKING
+  },
+  {
+    EL_CRYSTAL,                                -1, -1, FALSE,
+    IMG_CRYSTAL
+  },
+  {
+    EL_WALL_PEARL,                     -1, -1, FALSE,
+    IMG_WALL_PEARL
+  },
+  {
+    EL_WALL_CRYSTAL,                   -1, -1, FALSE,
+    IMG_WALL_CRYSTAL
+  },
+  {
+    EL_TUBE_RIGHT_DOWN,                        -1, -1, FALSE,
+    IMG_TUBE_RIGHT_DOWN
+  },
+  {
+    EL_TUBE_HORIZONTAL_DOWN,           -1, -1, FALSE,
+    IMG_TUBE_HORIZONTAL_DOWN
+  },
+  {
+    EL_TUBE_LEFT_DOWN,                 -1, -1, FALSE,
+    IMG_TUBE_LEFT_DOWN
+  },
+  {
+    EL_TUBE_HORIZONTAL,                        -1, -1, FALSE,
+    IMG_TUBE_HORIZONTAL
+  },
+  {
+    EL_TUBE_VERTICAL_RIGHT,            -1, -1, FALSE,
+    IMG_TUBE_VERTICAL_RIGHT
+  },
+  {
+    EL_TUBE_ANY,                       -1, -1, FALSE,
+    IMG_TUBE_ANY
+  },
+  {
+    EL_TUBE_VERTICAL_LEFT,             -1, -1, FALSE,
+    IMG_TUBE_VERTICAL_LEFT
+  },
+  {
+    EL_TUBE_VERTICAL,                  -1, -1, FALSE,
+    IMG_TUBE_VERTICAL
+  },
+  {
+    EL_TUBE_RIGHT_UP,                  -1, -1, FALSE,
+    IMG_TUBE_RIGHT_UP
+  },
+  {
+    EL_TUBE_HORIZONTAL_UP,             -1, -1, FALSE,
+    IMG_TUBE_HORIZONTAL_UP
+  },
+  {
+    EL_TUBE_LEFT_UP,                   -1, -1, FALSE,
+    IMG_TUBE_LEFT_UP
+  },
+  {
+    EL_TRAP,                           -1, -1, FALSE,
+    IMG_TRAP
+  },
+  {
+    EL_TRAP_ACTIVE,                    -1, -1, FALSE,
+    IMG_TRAP_ACTIVE
+  },
+  {
+    EL_TRAP,                           ACTION_ACTIVE, -1, FALSE,
+    IMG_TRAP_ACTIVE
+  },
+  {
+    EL_DX_SUPABOMB,                    -1, -1, FALSE,
+    IMG_DX_SUPABOMB
+  },
+  {
+    EL_KEY_1,                          -1, -1, FALSE,
+    IMG_KEY_1
+  },
+  {
+    EL_KEY_2,                          -1, -1, FALSE,
+    IMG_KEY_2
+  },
+  {
+    EL_KEY_3,                          -1, -1, FALSE,
+    IMG_KEY_3
+  },
+  {
+    EL_KEY_4,                          -1, -1, FALSE,
+    IMG_KEY_4
+  },
+  {
+    EL_GATE_1,                         -1, -1, FALSE,
+    IMG_GATE_1
+  },
+  {
+    EL_GATE_2,                         -1, -1, FALSE,
+    IMG_GATE_2
+  },
+  {
+    EL_GATE_3,                         -1, -1, FALSE,
+    IMG_GATE_3
+  },
+  {
+    EL_GATE_4,                         -1, -1, FALSE,
+    IMG_GATE_4
+  },
+  {
+    EL_GATE_1_GRAY,                    -1, -1, FALSE,
+    IMG_GATE_1_GRAY
+  },
+  {
+    EL_GATE_2_GRAY,                    -1, -1, FALSE,
+    IMG_GATE_2_GRAY
+  },
+  {
+    EL_GATE_3_GRAY,                    -1, -1, FALSE,
+    IMG_GATE_3_GRAY
+  },
+  {
+    EL_GATE_4_GRAY,                    -1, -1, FALSE,
+    IMG_GATE_4_GRAY
+  },
+  {
+    EL_GAME_OF_LIFE,                   -1, -1, FALSE,
+    IMG_GAME_OF_LIFE
+  },
+  {
+    EL_BIOMAZE,                                -1, -1, FALSE,
+    IMG_BIOMAZE
+  },
+  {
+    EL_PACMAN,                         -1, -1, FALSE,
+    IMG_PACMAN
+  },
+  {
+    EL_PACMAN_RIGHT,                   -1, -1, FALSE,
+    IMG_PACMAN_RIGHT
+  },
+  {
+    EL_PACMAN,                         -1, MV_BIT_RIGHT, FALSE,
+    IMG_PACMAN_RIGHT
+  },
+  {
+    EL_PACMAN_UP,                      -1, -1, FALSE,
+    IMG_PACMAN_UP
+  },
+  {
+    EL_PACMAN,                         -1, MV_BIT_UP, FALSE,
+    IMG_PACMAN_UP
+  },
+  {
+    EL_PACMAN_LEFT,                    -1, -1, FALSE,
+    IMG_PACMAN_LEFT
+  },
+  {
+    EL_PACMAN,                         -1, MV_BIT_LEFT, FALSE,
+    IMG_PACMAN_LEFT
+  },
+  {
+    EL_PACMAN_DOWN,                    -1, -1, FALSE,
+    IMG_PACMAN_DOWN
+  },
+  {
+    EL_PACMAN,                         -1, MV_BIT_DOWN, FALSE,
+    IMG_PACMAN_DOWN
+  },
+  {
+    EL_PACMAN,                         ACTION_MOVING, MV_BIT_RIGHT, FALSE,
+    IMG_PACMAN_MOVING_RIGHT
+  },
+  {
+    EL_PACMAN,                         ACTION_MOVING, MV_BIT_UP, FALSE,
+    IMG_PACMAN_MOVING_UP
+  },
+  {
+    EL_PACMAN,                         ACTION_MOVING, MV_BIT_LEFT, FALSE,
+    IMG_PACMAN_MOVING_LEFT
+  },
+  {
+    EL_PACMAN,                         ACTION_MOVING, MV_BIT_DOWN, FALSE,
+    IMG_PACMAN_MOVING_DOWN
+  },
+  {
+    EL_LAMP,                           -1, -1, FALSE,
+    IMG_LAMP
+  },
+  {
+    EL_LAMP_ACTIVE,                    -1, -1, FALSE,
+    IMG_LAMP_ACTIVE
+  },
+  {
+    EL_LAMP,                           ACTION_ACTIVE, -1, FALSE,
+    IMG_LAMP_ACTIVE
+  },
+  {
+    EL_TIME_ORB_FULL,                  -1, -1, FALSE,
+    IMG_TIME_ORB_FULL
+  },
+  {
+    EL_TIME_ORB_EMPTY,                 -1, -1, FALSE,
+    IMG_TIME_ORB_EMPTY
+  },
+  {
+    EL_EMERALD_YELLOW,                 -1, -1, FALSE,
+    IMG_EMERALD_YELLOW
+  },
+  {
+    EL_EMERALD_YELLOW,                 ACTION_MOVING, -1, FALSE,
+    IMG_EMERALD_YELLOW_MOVING
+  },
+  {
+    EL_EMERALD_YELLOW,                 ACTION_FALLING, -1, FALSE,
+    IMG_EMERALD_YELLOW_FALLING
+  },
+  {
+    EL_EMERALD_RED,                    -1, -1, FALSE,
+    IMG_EMERALD_RED
+  },
+  {
+    EL_EMERALD_RED,                    ACTION_MOVING, -1, FALSE,
+    IMG_EMERALD_RED_MOVING
+  },
+  {
+    EL_EMERALD_RED,                    ACTION_FALLING, -1, FALSE,
+    IMG_EMERALD_RED_FALLING
+  },
+  {
+    EL_EMERALD_PURPLE,                 -1, -1, FALSE,
+    IMG_EMERALD_PURPLE
+  },
+  {
+    EL_EMERALD_PURPLE,                 ACTION_MOVING, -1, FALSE,
+    IMG_EMERALD_PURPLE_MOVING
+  },
+  {
+    EL_EMERALD_PURPLE,                 ACTION_FALLING, -1, FALSE,
+    IMG_EMERALD_PURPLE_FALLING
+  },
+  {
+    EL_WALL_EMERALD_YELLOW,            -1, -1, FALSE,
+    IMG_WALL_EMERALD_YELLOW
+  },
+  {
+    EL_WALL_EMERALD_RED,               -1, -1, FALSE,
+    IMG_WALL_EMERALD_RED
+  },
+  {
+    EL_WALL_EMERALD_PURPLE,            -1, -1, FALSE,
+    IMG_WALL_EMERALD_PURPLE
+  },
+  {
+    EL_WALL_BD_DIAMOND,                        -1, -1, FALSE,
+    IMG_WALL_BD_DIAMOND
+  },
+  {
+    EL_EXPANDABLE_WALL,                        -1, -1, FALSE,
+    IMG_EXPANDABLE_WALL
+  },
+  {
+    EL_EXPANDABLE_WALL_HORIZONTAL,     -1, -1, FALSE,
+    IMG_EXPANDABLE_WALL_HORIZONTAL
+  },
+  {
+    EL_EXPANDABLE_WALL_VERTICAL,       -1, -1, FALSE,
+    IMG_EXPANDABLE_WALL_VERTICAL
+  },
+  {
+    EL_EXPANDABLE_WALL_ANY,            -1, -1, FALSE,
+    IMG_EXPANDABLE_WALL_ANY
+  },
+  {
+    EL_EXPANDABLE_WALL,                        ACTION_GROWING, MV_BIT_LEFT, FALSE,
+    IMG_EXPANDABLE_WALL_GROWING_LEFT
+  },
+  {
+    EL_EXPANDABLE_WALL_GROWING,                -1, MV_BIT_LEFT, FALSE,
+    IMG_EXPANDABLE_WALL_GROWING_LEFT
+  },
+  {
+    EL_EXPANDABLE_WALL,                        ACTION_GROWING, MV_BIT_RIGHT, FALSE,
+    IMG_EXPANDABLE_WALL_GROWING_RIGHT
+  },
+  {
+    EL_EXPANDABLE_WALL_GROWING,                -1, MV_BIT_RIGHT, FALSE,
+    IMG_EXPANDABLE_WALL_GROWING_RIGHT
+  },
+  {
+    EL_EXPANDABLE_WALL,                        ACTION_GROWING, MV_BIT_UP, FALSE,
+    IMG_EXPANDABLE_WALL_GROWING_UP
+  },
+  {
+    EL_EXPANDABLE_WALL_GROWING,                -1, MV_BIT_UP, FALSE,
+    IMG_EXPANDABLE_WALL_GROWING_UP
+  },
+  {
+    EL_EXPANDABLE_WALL,                        ACTION_GROWING, MV_BIT_DOWN, FALSE,
+    IMG_EXPANDABLE_WALL_GROWING_DOWN
+  },
+  {
+    EL_EXPANDABLE_WALL_GROWING,                -1, MV_BIT_DOWN, FALSE,
+    IMG_EXPANDABLE_WALL_GROWING_DOWN
+  },
+  {
+    EL_BLACK_ORB,                      -1, -1, FALSE,
+    IMG_BLACK_ORB
+  },
+  {
+    EL_SPEED_PILL,                     -1, -1, FALSE,
+    IMG_SPEED_PILL
+  },
+  {
+    EL_DARK_YAMYAM,                    -1, -1, FALSE,
+    IMG_DARK_YAMYAM
+  },
+  {
+    EL_DYNABOMB,                       -1, -1, FALSE,
+    IMG_DYNABOMB
+  },
+  {
+    EL_DYNABOMB_ACTIVE,                        -1, -1, FALSE,
+    IMG_DYNABOMB_ACTIVE
+  },
+  {
+    EL_DYNABOMB,                       ACTION_ACTIVE, -1, FALSE,
+    IMG_DYNABOMB_ACTIVE
+  },
+  {
+    EL_DYNABOMB_PLAYER_1,              -1, -1, FALSE,
+    IMG_DYNABOMB_PLAYER_1
+  },
+  {
+    EL_DYNABOMB_PLAYER_1_ACTIVE,       -1, -1, FALSE,
+    IMG_DYNABOMB_PLAYER_1_ACTIVE
+  },
+  {
+    EL_DYNABOMB_PLAYER_1,              ACTION_ACTIVE, -1, FALSE,
+    IMG_DYNABOMB_PLAYER_1_ACTIVE
+  },
+  {
+    EL_DYNABOMB_PLAYER_2,              -1, -1, FALSE,
+    IMG_DYNABOMB_PLAYER_2
+  },
+  {
+    EL_DYNABOMB_PLAYER_2_ACTIVE,       -1, -1, FALSE,
+    IMG_DYNABOMB_PLAYER_2_ACTIVE
+  },
+  {
+    EL_DYNABOMB_PLAYER_2,              ACTION_ACTIVE, -1, FALSE,
+    IMG_DYNABOMB_PLAYER_2_ACTIVE
+  },
+  {
+    EL_DYNABOMB_PLAYER_3,              -1, -1, FALSE,
+    IMG_DYNABOMB_PLAYER_3
+  },
+  {
+    EL_DYNABOMB_PLAYER_3_ACTIVE,       -1, -1, FALSE,
+    IMG_DYNABOMB_PLAYER_3_ACTIVE
+  },
+  {
+    EL_DYNABOMB_PLAYER_3,              ACTION_ACTIVE, -1, FALSE,
+    IMG_DYNABOMB_PLAYER_3_ACTIVE
+  },
+  {
+    EL_DYNABOMB_PLAYER_4,              -1, -1, FALSE,
+    IMG_DYNABOMB_PLAYER_4
+  },
+  {
+    EL_DYNABOMB_PLAYER_4_ACTIVE,       -1, -1, FALSE,
+    IMG_DYNABOMB_PLAYER_4_ACTIVE
+  },
+  {
+    EL_DYNABOMB_PLAYER_4,              ACTION_ACTIVE, -1, FALSE,
+    IMG_DYNABOMB_PLAYER_4_ACTIVE
+  },
+  {
+    EL_DYNABOMB_INCREASE_NUMBER,       -1, -1, FALSE,
+    IMG_DYNABOMB_INCREASE_NUMBER
+  },
+  {
+    EL_DYNABOMB_INCREASE_SIZE,         -1, -1, FALSE,
+    IMG_DYNABOMB_INCREASE_SIZE
+  },
+  {
+    EL_DYNABOMB_INCREASE_POWER,                -1, -1, FALSE,
+    IMG_DYNABOMB_INCREASE_POWER
+  },
+  {
+    EL_PIG,                            -1, -1, FALSE,
+    IMG_PIG
+  },
+  {
+    EL_PIG,                            -1, MV_BIT_DOWN, FALSE,
+    IMG_PIG_DOWN
+  },
+  {
+    EL_PIG,                            -1, MV_BIT_UP, FALSE,
+    IMG_PIG_UP
+  },
+  {
+    EL_PIG,                            -1, MV_BIT_LEFT, FALSE,
+    IMG_PIG_LEFT
+  },
+  {
+    EL_PIG,                            -1, MV_BIT_RIGHT, FALSE,
+    IMG_PIG_RIGHT
+  },
+  {
+    EL_PIG,                            ACTION_MOVING, MV_BIT_DOWN, FALSE,
+    IMG_PIG_MOVING_DOWN
+  },
+  {
+    EL_PIG,                            ACTION_MOVING, MV_BIT_UP, FALSE,
+    IMG_PIG_MOVING_UP
+  },
+  {
+    EL_PIG,                            ACTION_MOVING, MV_BIT_LEFT, FALSE,
+    IMG_PIG_MOVING_LEFT
+  },
+  {
+    EL_PIG,                            ACTION_MOVING, MV_BIT_RIGHT, FALSE,
+    IMG_PIG_MOVING_RIGHT
+  },
+  {
+    EL_PIG,                            ACTION_DIGGING, MV_BIT_DOWN, FALSE,
+    IMG_PIG_DIGGING_DOWN
+  },
+  {
+    EL_PIG,                            ACTION_DIGGING, MV_BIT_UP, FALSE,
+    IMG_PIG_DIGGING_UP
+  },
+  {
+    EL_PIG,                            ACTION_DIGGING, MV_BIT_LEFT, FALSE,
+    IMG_PIG_DIGGING_LEFT
+  },
+  {
+    EL_PIG,                            ACTION_DIGGING, MV_BIT_RIGHT, FALSE,
+    IMG_PIG_DIGGING_RIGHT
+  },
+  {
+    EL_DRAGON,                         -1, -1, FALSE,
+    IMG_DRAGON
+  },
+  {
+    EL_DRAGON,                         -1, MV_BIT_DOWN, FALSE,
+    IMG_DRAGON_DOWN
+  },
+  {
+    EL_DRAGON,                         -1, MV_BIT_UP, FALSE,
+    IMG_DRAGON_UP
+  },
+  {
+    EL_DRAGON,                         -1, MV_BIT_LEFT, FALSE,
+    IMG_DRAGON_LEFT
+  },
+  {
+    EL_DRAGON,                         -1, MV_BIT_RIGHT, FALSE,
+    IMG_DRAGON_RIGHT
+  },
+  {
+    EL_DRAGON,                         ACTION_MOVING, MV_BIT_DOWN, FALSE,
+    IMG_DRAGON_MOVING_DOWN
+  },
+  {
+    EL_DRAGON,                         ACTION_MOVING, MV_BIT_UP, FALSE,
+    IMG_DRAGON_MOVING_UP
+  },
+  {
+    EL_DRAGON,                         ACTION_MOVING, MV_BIT_LEFT, FALSE,
+    IMG_DRAGON_MOVING_LEFT
+  },
+  {
+    EL_DRAGON,                         ACTION_MOVING, MV_BIT_RIGHT, FALSE,
+    IMG_DRAGON_MOVING_RIGHT
+  },
+  {
+    EL_DRAGON,                         ACTION_ATTACKING, MV_BIT_DOWN, FALSE,
+    IMG_DRAGON_ATTACKING_DOWN
+  },
+  {
+    EL_DRAGON,                         ACTION_ATTACKING, MV_BIT_UP, FALSE,
+    IMG_DRAGON_ATTACKING_UP
+  },
+  {
+    EL_DRAGON,                         ACTION_ATTACKING, MV_BIT_LEFT, FALSE,
+    IMG_DRAGON_ATTACKING_LEFT
+  },
+  {
+    EL_DRAGON,                         ACTION_ATTACKING, MV_BIT_RIGHT, FALSE,
+    IMG_DRAGON_ATTACKING_RIGHT
+  },
+  {
+    EL_MOLE,                           -1, -1, FALSE,
+    IMG_MOLE
+  },
+  {
+    EL_MOLE_DOWN,                      -1, -1, FALSE,
+    IMG_MOLE_DOWN
+  },
+  {
+    EL_MOLE,                           -1, MV_BIT_DOWN, FALSE,
+    IMG_MOLE_DOWN
+  },
+  {
+    EL_MOLE_UP,                                -1, -1, FALSE,
+    IMG_MOLE_UP
+  },
+  {
+    EL_MOLE,                           -1, MV_BIT_UP, FALSE,
+    IMG_MOLE_UP
+  },
+  {
+    EL_MOLE_LEFT,                      -1, -1, FALSE,
+    IMG_MOLE_LEFT
+  },
+  {
+    EL_MOLE,                           -1, MV_BIT_LEFT, FALSE,
+    IMG_MOLE_LEFT
+  },
+  {
+    EL_MOLE_RIGHT,                     -1, -1, FALSE,
+    IMG_MOLE_RIGHT
+  },
+  {
+    EL_MOLE,                           -1, MV_BIT_RIGHT, FALSE,
+    IMG_MOLE_RIGHT
+  },
+  {
+    EL_MOLE,                           ACTION_MOVING, MV_BIT_DOWN, FALSE,
+    IMG_MOLE_MOVING_DOWN
+  },
+  {
+    EL_MOLE,                           ACTION_MOVING, MV_BIT_UP, FALSE,
+    IMG_MOLE_MOVING_UP
+  },
+  {
+    EL_MOLE,                           ACTION_MOVING, MV_BIT_LEFT, FALSE,
+    IMG_MOLE_MOVING_LEFT
+  },
+  {
+    EL_MOLE,                           ACTION_MOVING, MV_BIT_RIGHT, FALSE,
+    IMG_MOLE_MOVING_RIGHT
+  },
+  {
+    EL_MOLE,                           ACTION_DIGGING, MV_BIT_DOWN, FALSE,
+    IMG_MOLE_DIGGING_DOWN
+  },
+  {
+    EL_MOLE,                           ACTION_DIGGING, MV_BIT_UP, FALSE,
+    IMG_MOLE_DIGGING_UP
+  },
+  {
+    EL_MOLE,                           ACTION_DIGGING, MV_BIT_LEFT, FALSE,
+    IMG_MOLE_DIGGING_LEFT
+  },
+  {
+    EL_MOLE,                           ACTION_DIGGING, MV_BIT_RIGHT, FALSE,
+    IMG_MOLE_DIGGING_RIGHT
+  },
+  {
+    EL_PENGUIN,                                -1, -1, FALSE,
+    IMG_PENGUIN
+  },
+  {
+    EL_PENGUIN,                                -1, MV_BIT_DOWN, FALSE,
+    IMG_PENGUIN_DOWN
+  },
+  {
+    EL_PENGUIN,                                -1, MV_BIT_UP, FALSE,
+    IMG_PENGUIN_UP
+  },
+  {
+    EL_PENGUIN,                                -1, MV_BIT_LEFT, FALSE,
+    IMG_PENGUIN_LEFT
+  },
+  {
+    EL_PENGUIN,                                -1, MV_BIT_RIGHT, FALSE,
+    IMG_PENGUIN_RIGHT
+  },
+  {
+    EL_PENGUIN,                                ACTION_MOVING, MV_BIT_DOWN, FALSE,
+    IMG_PENGUIN_MOVING_DOWN
+  },
+  {
+    EL_PENGUIN,                                ACTION_MOVING, MV_BIT_UP, FALSE,
+    IMG_PENGUIN_MOVING_UP
+  },
+  {
+    EL_PENGUIN,                                ACTION_MOVING, MV_BIT_LEFT, FALSE,
+    IMG_PENGUIN_MOVING_LEFT
+  },
+  {
+    EL_PENGUIN,                                ACTION_MOVING, MV_BIT_RIGHT, FALSE,
+    IMG_PENGUIN_MOVING_RIGHT
+  },
+  {
+    EL_SATELLITE,                      -1, -1, FALSE,
+    IMG_SATELLITE
+  },
+  {
+    EL_STONEBLOCK,                     -1, -1, FALSE,
+    IMG_STONEBLOCK
+  },
+  {
+    EL_PLAYER_1,                       -1, -1, FALSE,
+    IMG_PLAYER_1
+  },
+  {
+    EL_PLAYER_1,                       -1, MV_BIT_DOWN, FALSE,
+    IMG_PLAYER_1_DOWN
+  },
+  {
+    EL_PLAYER_1,                       -1, MV_BIT_UP, FALSE,
+    IMG_PLAYER_1_UP
+  },
+  {
+    EL_PLAYER_1,                       -1, MV_BIT_LEFT, FALSE,
+    IMG_PLAYER_1_LEFT
+  },
+  {
+    EL_PLAYER_1,                       -1, MV_BIT_RIGHT, FALSE,
+    IMG_PLAYER_1_RIGHT
+  },
+  {
+    EL_PLAYER_1,                       ACTION_MOVING, MV_BIT_DOWN, FALSE,
+    IMG_PLAYER_1_MOVING_DOWN
+  },
+  {
+    EL_PLAYER_1,                       ACTION_MOVING, MV_BIT_UP, FALSE,
+    IMG_PLAYER_1_MOVING_UP
+  },
+  {
+    EL_PLAYER_1,                       ACTION_MOVING, MV_BIT_LEFT, FALSE,
+    IMG_PLAYER_1_MOVING_LEFT
+  },
+  {
+    EL_PLAYER_1,                       ACTION_MOVING, MV_BIT_RIGHT, FALSE,
+    IMG_PLAYER_1_MOVING_RIGHT
+  },
+  {
+    EL_PLAYER_1,                       ACTION_DIGGING, MV_BIT_DOWN, FALSE,
+    IMG_PLAYER_1_DIGGING_DOWN
+  },
+  {
+    EL_PLAYER_1,                       ACTION_DIGGING, MV_BIT_UP, FALSE,
+    IMG_PLAYER_1_DIGGING_UP
+  },
+  {
+    EL_PLAYER_1,                       ACTION_DIGGING, MV_BIT_LEFT, FALSE,
+    IMG_PLAYER_1_DIGGING_LEFT
+  },
+  {
+    EL_PLAYER_1,                       ACTION_DIGGING, MV_BIT_RIGHT, FALSE,
+    IMG_PLAYER_1_DIGGING_RIGHT
+  },
+  {
+    EL_PLAYER_1,                       ACTION_COLLECTING, MV_BIT_DOWN, FALSE,
+    IMG_PLAYER_1_COLLECTING_DOWN
+  },
+  {
+    EL_PLAYER_1,                       ACTION_COLLECTING, MV_BIT_UP, FALSE,
+    IMG_PLAYER_1_COLLECTING_UP
+  },
+  {
+    EL_PLAYER_1,                       ACTION_COLLECTING, MV_BIT_LEFT, FALSE,
+    IMG_PLAYER_1_COLLECTING_LEFT
+  },
+  {
+    EL_PLAYER_1,                       ACTION_COLLECTING, MV_BIT_RIGHT, FALSE,
+    IMG_PLAYER_1_COLLECTING_RIGHT
+  },
+  {
+    EL_PLAYER_1,                       ACTION_PUSHING, MV_BIT_DOWN, FALSE,
+    IMG_PLAYER_1_PUSHING_DOWN
+  },
+  {
+    EL_PLAYER_1,                       ACTION_PUSHING, MV_BIT_UP, FALSE,
+    IMG_PLAYER_1_PUSHING_UP
+  },
+  {
+    EL_PLAYER_1,                       ACTION_PUSHING, MV_BIT_LEFT, FALSE,
+    IMG_PLAYER_1_PUSHING_LEFT
+  },
+  {
+    EL_PLAYER_1,                       ACTION_PUSHING, MV_BIT_RIGHT, FALSE,
+    IMG_PLAYER_1_PUSHING_RIGHT
+  },
+  {
+    EL_PLAYER_1,                       ACTION_SNAPPING, MV_BIT_DOWN, FALSE,
+    IMG_PLAYER_1_SNAPPING_DOWN
+  },
+  {
+    EL_PLAYER_1,                       ACTION_SNAPPING, MV_BIT_UP, FALSE,
+    IMG_PLAYER_1_SNAPPING_UP
+  },
+  {
+    EL_PLAYER_1,                       ACTION_SNAPPING, MV_BIT_LEFT, FALSE,
+    IMG_PLAYER_1_SNAPPING_LEFT
+  },
+  {
+    EL_PLAYER_1,                       ACTION_SNAPPING, MV_BIT_RIGHT, FALSE,
+    IMG_PLAYER_1_SNAPPING_RIGHT
+  },
+  {
+    EL_PLAYER_2,                       -1, -1, FALSE,
+    IMG_PLAYER_2
+  },
+  {
+    EL_PLAYER_2,                       -1, MV_BIT_DOWN, FALSE,
+    IMG_PLAYER_2_DOWN
+  },
+  {
+    EL_PLAYER_2,                       -1, MV_BIT_UP, FALSE,
+    IMG_PLAYER_2_UP
+  },
+  {
+    EL_PLAYER_2,                       -1, MV_BIT_LEFT, FALSE,
+    IMG_PLAYER_2_LEFT
+  },
+  {
+    EL_PLAYER_2,                       -1, MV_BIT_RIGHT, FALSE,
+    IMG_PLAYER_2_RIGHT
+  },
+  {
+    EL_PLAYER_2,                       ACTION_MOVING, MV_BIT_DOWN, FALSE,
+    IMG_PLAYER_2_MOVING_DOWN
+  },
+  {
+    EL_PLAYER_2,                       ACTION_MOVING, MV_BIT_UP, FALSE,
+    IMG_PLAYER_2_MOVING_UP
+  },
+  {
+    EL_PLAYER_2,                       ACTION_MOVING, MV_BIT_LEFT, FALSE,
+    IMG_PLAYER_2_MOVING_LEFT
+  },
+  {
+    EL_PLAYER_2,                       ACTION_MOVING, MV_BIT_RIGHT, FALSE,
+    IMG_PLAYER_2_MOVING_RIGHT
+  },
+  {
+    EL_PLAYER_2,                       ACTION_DIGGING, MV_BIT_DOWN, FALSE,
+    IMG_PLAYER_2_DIGGING_DOWN
+  },
+  {
+    EL_PLAYER_2,                       ACTION_DIGGING, MV_BIT_UP, FALSE,
+    IMG_PLAYER_2_DIGGING_UP
+  },
+  {
+    EL_PLAYER_2,                       ACTION_DIGGING, MV_BIT_LEFT, FALSE,
+    IMG_PLAYER_2_DIGGING_LEFT
+  },
+  {
+    EL_PLAYER_2,                       ACTION_DIGGING, MV_BIT_RIGHT, FALSE,
+    IMG_PLAYER_2_DIGGING_RIGHT
+  },
+  {
+    EL_PLAYER_2,                       ACTION_COLLECTING, MV_BIT_DOWN, FALSE,
+    IMG_PLAYER_2_COLLECTING_DOWN
+  },
+  {
+    EL_PLAYER_2,                       ACTION_COLLECTING, MV_BIT_UP, FALSE,
+    IMG_PLAYER_2_COLLECTING_UP
+  },
+  {
+    EL_PLAYER_2,                       ACTION_COLLECTING, MV_BIT_LEFT, FALSE,
+    IMG_PLAYER_2_COLLECTING_LEFT
+  },
+  {
+    EL_PLAYER_2,                       ACTION_COLLECTING, MV_BIT_RIGHT, FALSE,
+    IMG_PLAYER_2_COLLECTING_RIGHT
+  },
+  {
+    EL_PLAYER_2,                       ACTION_PUSHING, MV_BIT_DOWN, FALSE,
+    IMG_PLAYER_2_PUSHING_DOWN
+  },
+  {
+    EL_PLAYER_2,                       ACTION_PUSHING, MV_BIT_UP, FALSE,
+    IMG_PLAYER_2_PUSHING_UP
+  },
+  {
+    EL_PLAYER_2,                       ACTION_PUSHING, MV_BIT_LEFT, FALSE,
+    IMG_PLAYER_2_PUSHING_LEFT
+  },
+  {
+    EL_PLAYER_2,                       ACTION_PUSHING, MV_BIT_RIGHT, FALSE,
+    IMG_PLAYER_2_PUSHING_RIGHT
+  },
+  {
+    EL_PLAYER_2,                       ACTION_SNAPPING, MV_BIT_DOWN, FALSE,
+    IMG_PLAYER_2_SNAPPING_DOWN
+  },
+  {
+    EL_PLAYER_2,                       ACTION_SNAPPING, MV_BIT_UP, FALSE,
+    IMG_PLAYER_2_SNAPPING_UP
+  },
+  {
+    EL_PLAYER_2,                       ACTION_SNAPPING, MV_BIT_LEFT, FALSE,
+    IMG_PLAYER_2_SNAPPING_LEFT
+  },
+  {
+    EL_PLAYER_2,                       ACTION_SNAPPING, MV_BIT_RIGHT, FALSE,
+    IMG_PLAYER_2_SNAPPING_RIGHT
+  },
+  {
+    EL_PLAYER_3,                       -1, -1, FALSE,
+    IMG_PLAYER_3
+  },
+  {
+    EL_PLAYER_3,                       -1, MV_BIT_DOWN, FALSE,
+    IMG_PLAYER_3_DOWN
+  },
+  {
+    EL_PLAYER_3,                       -1, MV_BIT_UP, FALSE,
+    IMG_PLAYER_3_UP
+  },
+  {
+    EL_PLAYER_3,                       -1, MV_BIT_LEFT, FALSE,
+    IMG_PLAYER_3_LEFT
+  },
+  {
+    EL_PLAYER_3,                       -1, MV_BIT_RIGHT, FALSE,
+    IMG_PLAYER_3_RIGHT
+  },
+  {
+    EL_PLAYER_3,                       ACTION_MOVING, MV_BIT_DOWN, FALSE,
+    IMG_PLAYER_3_MOVING_DOWN
+  },
+  {
+    EL_PLAYER_3,                       ACTION_MOVING, MV_BIT_UP, FALSE,
+    IMG_PLAYER_3_MOVING_UP
+  },
+  {
+    EL_PLAYER_3,                       ACTION_MOVING, MV_BIT_LEFT, FALSE,
+    IMG_PLAYER_3_MOVING_LEFT
+  },
+  {
+    EL_PLAYER_3,                       ACTION_MOVING, MV_BIT_RIGHT, FALSE,
+    IMG_PLAYER_3_MOVING_RIGHT
+  },
+  {
+    EL_PLAYER_3,                       ACTION_DIGGING, MV_BIT_DOWN, FALSE,
+    IMG_PLAYER_3_DIGGING_DOWN
+  },
+  {
+    EL_PLAYER_3,                       ACTION_DIGGING, MV_BIT_UP, FALSE,
+    IMG_PLAYER_3_DIGGING_UP
+  },
+  {
+    EL_PLAYER_3,                       ACTION_DIGGING, MV_BIT_LEFT, FALSE,
+    IMG_PLAYER_3_DIGGING_LEFT
+  },
+  {
+    EL_PLAYER_3,                       ACTION_DIGGING, MV_BIT_RIGHT, FALSE,
+    IMG_PLAYER_3_DIGGING_RIGHT
+  },
+  {
+    EL_PLAYER_3,                       ACTION_COLLECTING, MV_BIT_DOWN, FALSE,
+    IMG_PLAYER_3_COLLECTING_DOWN
+  },
+  {
+    EL_PLAYER_3,                       ACTION_COLLECTING, MV_BIT_UP, FALSE,
+    IMG_PLAYER_3_COLLECTING_UP
+  },
+  {
+    EL_PLAYER_3,                       ACTION_COLLECTING, MV_BIT_LEFT, FALSE,
+    IMG_PLAYER_3_COLLECTING_LEFT
+  },
+  {
+    EL_PLAYER_3,                       ACTION_COLLECTING, MV_BIT_RIGHT, FALSE,
+    IMG_PLAYER_3_COLLECTING_RIGHT
+  },
+  {
+    EL_PLAYER_3,                       ACTION_PUSHING, MV_BIT_DOWN, FALSE,
+    IMG_PLAYER_3_PUSHING_DOWN
+  },
+  {
+    EL_PLAYER_3,                       ACTION_PUSHING, MV_BIT_UP, FALSE,
+    IMG_PLAYER_3_PUSHING_UP
+  },
+  {
+    EL_PLAYER_3,                       ACTION_PUSHING, MV_BIT_LEFT, FALSE,
+    IMG_PLAYER_3_PUSHING_LEFT
+  },
+  {
+    EL_PLAYER_3,                       ACTION_PUSHING, MV_BIT_RIGHT, FALSE,
+    IMG_PLAYER_3_PUSHING_RIGHT
+  },
+  {
+    EL_PLAYER_3,                       ACTION_SNAPPING, MV_BIT_DOWN, FALSE,
+    IMG_PLAYER_3_SNAPPING_DOWN
+  },
+  {
+    EL_PLAYER_3,                       ACTION_SNAPPING, MV_BIT_UP, FALSE,
+    IMG_PLAYER_3_SNAPPING_UP
+  },
+  {
+    EL_PLAYER_3,                       ACTION_SNAPPING, MV_BIT_LEFT, FALSE,
+    IMG_PLAYER_3_SNAPPING_LEFT
+  },
+  {
+    EL_PLAYER_3,                       ACTION_SNAPPING, MV_BIT_RIGHT, FALSE,
+    IMG_PLAYER_3_SNAPPING_RIGHT
+  },
+  {
+    EL_PLAYER_4,                       -1, -1, FALSE,
+    IMG_PLAYER_4
+  },
+  {
+    EL_PLAYER_4,                       -1, MV_BIT_DOWN, FALSE,
+    IMG_PLAYER_4_DOWN
+  },
+  {
+    EL_PLAYER_4,                       -1, MV_BIT_UP, FALSE,
+    IMG_PLAYER_4_UP
+  },
+  {
+    EL_PLAYER_4,                       -1, MV_BIT_LEFT, FALSE,
+    IMG_PLAYER_4_LEFT
+  },
+  {
+    EL_PLAYER_4,                       -1, MV_BIT_RIGHT, FALSE,
+    IMG_PLAYER_4_RIGHT
+  },
+  {
+    EL_PLAYER_4,                       ACTION_MOVING, MV_BIT_DOWN, FALSE,
+    IMG_PLAYER_4_MOVING_DOWN
+  },
+  {
+    EL_PLAYER_4,                       ACTION_MOVING, MV_BIT_UP, FALSE,
+    IMG_PLAYER_4_MOVING_UP
+  },
+  {
+    EL_PLAYER_4,                       ACTION_MOVING, MV_BIT_LEFT, FALSE,
+    IMG_PLAYER_4_MOVING_LEFT
+  },
+  {
+    EL_PLAYER_4,                       ACTION_MOVING, MV_BIT_RIGHT, FALSE,
+    IMG_PLAYER_4_MOVING_RIGHT
+  },
+  {
+    EL_PLAYER_4,                       ACTION_DIGGING, MV_BIT_DOWN, FALSE,
+    IMG_PLAYER_4_DIGGING_DOWN
+  },
+  {
+    EL_PLAYER_4,                       ACTION_DIGGING, MV_BIT_UP, FALSE,
+    IMG_PLAYER_4_DIGGING_UP
+  },
+  {
+    EL_PLAYER_4,                       ACTION_DIGGING, MV_BIT_LEFT, FALSE,
+    IMG_PLAYER_4_DIGGING_LEFT
+  },
+  {
+    EL_PLAYER_4,                       ACTION_DIGGING, MV_BIT_RIGHT, FALSE,
+    IMG_PLAYER_4_DIGGING_RIGHT
+  },
+  {
+    EL_PLAYER_4,                       ACTION_COLLECTING, MV_BIT_DOWN, FALSE,
+    IMG_PLAYER_4_COLLECTING_DOWN
+  },
+  {
+    EL_PLAYER_4,                       ACTION_COLLECTING, MV_BIT_UP, FALSE,
+    IMG_PLAYER_4_COLLECTING_UP
+  },
+  {
+    EL_PLAYER_4,                       ACTION_COLLECTING, MV_BIT_LEFT, FALSE,
+    IMG_PLAYER_4_COLLECTING_LEFT
+  },
+  {
+    EL_PLAYER_4,                       ACTION_COLLECTING, MV_BIT_RIGHT, FALSE,
+    IMG_PLAYER_4_COLLECTING_RIGHT
+  },
+  {
+    EL_PLAYER_4,                       ACTION_PUSHING, MV_BIT_DOWN, FALSE,
+    IMG_PLAYER_4_PUSHING_DOWN
+  },
+  {
+    EL_PLAYER_4,                       ACTION_PUSHING, MV_BIT_UP, FALSE,
+    IMG_PLAYER_4_PUSHING_UP
+  },
+  {
+    EL_PLAYER_4,                       ACTION_PUSHING, MV_BIT_LEFT, FALSE,
+    IMG_PLAYER_4_PUSHING_LEFT
+  },
+  {
+    EL_PLAYER_4,                       ACTION_PUSHING, MV_BIT_RIGHT, FALSE,
+    IMG_PLAYER_4_PUSHING_RIGHT
+  },
+  {
+    EL_PLAYER_4,                       ACTION_SNAPPING, MV_BIT_DOWN, FALSE,
+    IMG_PLAYER_4_SNAPPING_DOWN
+  },
+  {
+    EL_PLAYER_4,                       ACTION_SNAPPING, MV_BIT_UP, FALSE,
+    IMG_PLAYER_4_SNAPPING_UP
+  },
+  {
+    EL_PLAYER_4,                       ACTION_SNAPPING, MV_BIT_LEFT, FALSE,
+    IMG_PLAYER_4_SNAPPING_LEFT
+  },
+  {
+    EL_PLAYER_4,                       ACTION_SNAPPING, MV_BIT_RIGHT, FALSE,
+    IMG_PLAYER_4_SNAPPING_RIGHT
+  },
+  {
+    EL_DEFAULT,                                ACTION_EXPLODING, -1, FALSE,
+    IMG_DEFAULT_EXPLODING
+  },
+  {
+    EL_STEELWALL_TOPLEFT,              -1, -1, FALSE,
+    IMG_STEELWALL_TOPLEFT
+  },
+  {
+    EL_STEELWALL_TOPRIGHT,             -1, -1, FALSE,
+    IMG_STEELWALL_TOPRIGHT
+  },
+  {
+    EL_STEELWALL_BOTTOMLEFT,           -1, -1, FALSE,
+    IMG_STEELWALL_BOTTOMLEFT
+  },
+  {
+    EL_STEELWALL_BOTTOMRIGHT,          -1, -1, FALSE,
+    IMG_STEELWALL_BOTTOMRIGHT
+  },
+  {
+    EL_STEELWALL_HORIZONTAL,           -1, -1, FALSE,
+    IMG_STEELWALL_HORIZONTAL
+  },
+  {
+    EL_STEELWALL_VERTICAL,             -1, -1, FALSE,
+    IMG_STEELWALL_VERTICAL
+  },
+  {
+    EL_INVISIBLE_STEELWALL_TOPLEFT,    -1, -1, FALSE,
+    IMG_INVISIBLE_STEELWALL_TOPLEFT
+  },
+  {
+    EL_INVISIBLE_STEELWALL_TOPRIGHT,   -1, -1, FALSE,
+    IMG_INVISIBLE_STEELWALL_TOPRIGHT
+  },
+  {
+    EL_INVISIBLE_STEELWALL_BOTTOMLEFT, -1, -1, FALSE,
+    IMG_INVISIBLE_STEELWALL_BOTTOMLEFT
+  },
+  {
+    EL_INVISIBLE_STEELWALL_BOTTOMRIGHT,        -1, -1, FALSE,
+    IMG_INVISIBLE_STEELWALL_BOTTOMRIGHT
+  },
+  {
+    EL_INVISIBLE_STEELWALL_HORIZONTAL, -1, -1, FALSE,
+    IMG_INVISIBLE_STEELWALL_HORIZONTAL
+  },
+  {
+    EL_INVISIBLE_STEELWALL_VERTICAL,   -1, -1, FALSE,
+    IMG_INVISIBLE_STEELWALL_VERTICAL
+  },
+  {
+    EL_ARROW_LEFT,                     -1, -1, FALSE,
+    IMG_ARROW_LEFT
+  },
+  {
+    EL_ARROW_RIGHT,                    -1, -1, FALSE,
+    IMG_ARROW_RIGHT
+  },
+  {
+    EL_ARROW_UP,                       -1, -1, FALSE,
+    IMG_ARROW_UP
+  },
+  {
+    EL_ARROW_DOWN,                     -1, -1, FALSE,
+    IMG_ARROW_DOWN
+  },
+  {
+    EL_DOOR_WHITE,                     -1, -1, FALSE,
+    IMG_CHAR_QUESTION
+  },
+  {
+    EL_DOOR_WHITE_GRAY,                        -1, -1, FALSE,
+    IMG_CHAR_QUESTION
+  },
+  {
+    EL_DX_UNKNOWN_15,                  -1, -1, FALSE,
+    IMG_CHAR_QUESTION
+  },
+  {
+    EL_DX_UNKNOWN_42,                  -1, -1, FALSE,
+    IMG_CHAR_QUESTION
+  },
+  {
+    EL_EM_KEY_1_FILE,                  -1, -1, FALSE,
+    IMG_EM_KEY_1
+  },
+  {
+    EL_EM_KEY_2_FILE,                  -1, -1, FALSE,
+    IMG_EM_KEY_2
+  },
+  {
+    EL_EM_KEY_3_FILE,                  -1, -1, FALSE,
+    IMG_EM_KEY_3
+  },
+  {
+    EL_EM_KEY_4_FILE,                  -1, -1, FALSE,
+    IMG_EM_KEY_4
+  },
+  {
+    EL_KEY_WHITE,                      -1, -1, FALSE,
+    IMG_CHAR_QUESTION
+  },
+  {
+    EL_SIGN_EXIT,                      -1, -1, FALSE,
+    IMG_CHAR_QUESTION
+  },
+  {
+    EL_SIGN_HEART,                     -1, -1, FALSE,
+    IMG_CHAR_QUESTION
+  },
+  {
+    EL_SIGN_ONEWAY,                    -1, -1, FALSE,
+    IMG_CHAR_QUESTION
+  },
+  {
+    EL_SIGN_OTHER,                     -1, -1, FALSE,
+    IMG_CHAR_QUESTION
+  },
+  {
+    EL_SIGN_PARKING,                   -1, -1, FALSE,
+    IMG_CHAR_QUESTION
+  },
+  {
+    EL_SIGN_RADIOACTIVITY,             -1, -1, FALSE,
+    IMG_CHAR_QUESTION
+  },
+  {
+    EL_SIGN_ROUND,                     -1, -1, FALSE,
+    IMG_CHAR_QUESTION
+  },
+  {
+    EL_SIGN_TRIANGLE,                  -1, -1, FALSE,
+    IMG_CHAR_QUESTION
+  },
+  {
+    EL_SIGN_WHEELCHAIR,                        -1, -1, FALSE,
+    IMG_CHAR_QUESTION
+  },
+  {
+    EL_SIGN_YINYANG,                   -1, -1, FALSE,
+    IMG_CHAR_QUESTION
+  },
+  {
+    EL_CHAR_SPACE,                     -1, -1, FALSE,
+    IMG_CHAR_SPACE
+  },
+  {
+    EL_CHAR_EXCLAM,                    -1, -1, FALSE,
+    IMG_CHAR_EXCLAM
+  },
+  {
+    EL_CHAR_QUOTEDBL,                  -1, -1, FALSE,
+    IMG_CHAR_QUOTEDBL
+  },
+  {
+    EL_CHAR_NUMBERSIGN,                        -1, -1, FALSE,
+    IMG_CHAR_NUMBERSIGN
+  },
+  {
+    EL_CHAR_DOLLAR,                    -1, -1, FALSE,
+    IMG_CHAR_DOLLAR
+  },
+  {
+    EL_CHAR_PROCENT,                   -1, -1, FALSE,
+    IMG_CHAR_PROCENT
+  },
+  {
+    EL_CHAR_AMPERSAND,                 -1, -1, FALSE,
+    IMG_CHAR_AMPERSAND
+  },
+  {
+    EL_CHAR_APOSTROPHE,                        -1, -1, FALSE,
+    IMG_CHAR_APOSTROPHE
+  },
+  {
+    EL_CHAR_PARENLEFT,                 -1, -1, FALSE,
+    IMG_CHAR_PARENLEFT
+  },
+  {
+    EL_CHAR_PARENRIGHT,                        -1, -1, FALSE,
+    IMG_CHAR_PARENRIGHT
+  },
+  {
+    EL_CHAR_ASTERISK,                  -1, -1, FALSE,
+    IMG_CHAR_ASTERISK
+  },
+  {
+    EL_CHAR_PLUS,                      -1, -1, FALSE,
+    IMG_CHAR_PLUS
+  },
+  {
+    EL_CHAR_COMMA,                     -1, -1, FALSE,
+    IMG_CHAR_COMMA
+  },
+  {
+    EL_CHAR_MINUS,                     -1, -1, FALSE,
+    IMG_CHAR_MINUS
+  },
+  {
+    EL_CHAR_PERIOD,                    -1, -1, FALSE,
+    IMG_CHAR_PERIOD
+  },
+  {
+    EL_CHAR_SLASH,                     -1, -1, FALSE,
+    IMG_CHAR_SLASH
+  },
+  {
+    EL_CHAR_0,                         -1, -1, FALSE,
+    IMG_CHAR_0
+  },
+  {
+    EL_CHAR_1,                         -1, -1, FALSE,
+    IMG_CHAR_1
+  },
+  {
+    EL_CHAR_2,                         -1, -1, FALSE,
+    IMG_CHAR_2
+  },
+  {
+    EL_CHAR_3,                         -1, -1, FALSE,
+    IMG_CHAR_3
+  },
+  {
+    EL_CHAR_4,                         -1, -1, FALSE,
+    IMG_CHAR_4
+  },
+  {
+    EL_CHAR_5,                         -1, -1, FALSE,
+    IMG_CHAR_5
+  },
+  {
+    EL_CHAR_6,                         -1, -1, FALSE,
+    IMG_CHAR_6
+  },
+  {
+    EL_CHAR_7,                         -1, -1, FALSE,
+    IMG_CHAR_7
+  },
+  {
+    EL_CHAR_8,                         -1, -1, FALSE,
+    IMG_CHAR_8
+  },
+  {
+    EL_CHAR_9,                         -1, -1, FALSE,
+    IMG_CHAR_9
+  },
+  {
+    EL_CHAR_COLON,                     -1, -1, FALSE,
+    IMG_CHAR_COLON
+  },
+  {
+    EL_CHAR_SEMICOLON,                 -1, -1, FALSE,
+    IMG_CHAR_SEMICOLON
+  },
+  {
+    EL_CHAR_LESS,                      -1, -1, FALSE,
+    IMG_CHAR_LESS
+  },
+  {
+    EL_CHAR_EQUAL,                     -1, -1, FALSE,
+    IMG_CHAR_EQUAL
+  },
+  {
+    EL_CHAR_GREATER,                   -1, -1, FALSE,
+    IMG_CHAR_GREATER
+  },
+  {
+    EL_CHAR_QUESTION,                  -1, -1, FALSE,
+    IMG_CHAR_QUESTION
+  },
+  {
+    EL_CHAR_AT,                                -1, -1, FALSE,
+    IMG_CHAR_AT
+  },
+  {
+    EL_CHAR_A,                         -1, -1, FALSE,
+    IMG_CHAR_A
+  },
+  {
+    EL_CHAR_B,                         -1, -1, FALSE,
+    IMG_CHAR_B
+  },
+  {
+    EL_CHAR_C,                         -1, -1, FALSE,
+    IMG_CHAR_C
+  },
+  {
+    EL_CHAR_D,                         -1, -1, FALSE,
+    IMG_CHAR_D
+  },
+  {
+    EL_CHAR_E,                         -1, -1, FALSE,
+    IMG_CHAR_E
+  },
+  {
+    EL_CHAR_F,                         -1, -1, FALSE,
+    IMG_CHAR_F
+  },
+  {
+    EL_CHAR_G,                         -1, -1, FALSE,
+    IMG_CHAR_G
+  },
+  {
+    EL_CHAR_H,                         -1, -1, FALSE,
+    IMG_CHAR_H
+  },
+  {
+    EL_CHAR_I,                         -1, -1, FALSE,
+    IMG_CHAR_I
+  },
+  {
+    EL_CHAR_J,                         -1, -1, FALSE,
+    IMG_CHAR_J
+  },
+  {
+    EL_CHAR_K,                         -1, -1, FALSE,
+    IMG_CHAR_K
+  },
+  {
+    EL_CHAR_L,                         -1, -1, FALSE,
+    IMG_CHAR_L
+  },
+  {
+    EL_CHAR_M,                         -1, -1, FALSE,
+    IMG_CHAR_M
+  },
+  {
+    EL_CHAR_N,                         -1, -1, FALSE,
+    IMG_CHAR_N
+  },
+  {
+    EL_CHAR_O,                         -1, -1, FALSE,
+    IMG_CHAR_O
+  },
+  {
+    EL_CHAR_P,                         -1, -1, FALSE,
+    IMG_CHAR_P
+  },
+  {
+    EL_CHAR_Q,                         -1, -1, FALSE,
+    IMG_CHAR_Q
+  },
+  {
+    EL_CHAR_R,                         -1, -1, FALSE,
+    IMG_CHAR_R
+  },
+  {
+    EL_CHAR_S,                         -1, -1, FALSE,
+    IMG_CHAR_S
+  },
+  {
+    EL_CHAR_T,                         -1, -1, FALSE,
+    IMG_CHAR_T
+  },
+  {
+    EL_CHAR_U,                         -1, -1, FALSE,
+    IMG_CHAR_U
+  },
+  {
+    EL_CHAR_V,                         -1, -1, FALSE,
+    IMG_CHAR_V
+  },
+  {
+    EL_CHAR_W,                         -1, -1, FALSE,
+    IMG_CHAR_W
+  },
+  {
+    EL_CHAR_X,                         -1, -1, FALSE,
+    IMG_CHAR_X
+  },
+  {
+    EL_CHAR_Y,                         -1, -1, FALSE,
+    IMG_CHAR_Y
+  },
+  {
+    EL_CHAR_Z,                         -1, -1, FALSE,
+    IMG_CHAR_Z
+  },
+  {
+    EL_CHAR_BRACKETLEFT,               -1, -1, FALSE,
+    IMG_CHAR_BRACKETLEFT
+  },
+  {
+    EL_CHAR_BACKSLASH,                 -1, -1, FALSE,
+    IMG_CHAR_BACKSLASH
+  },
+  {
+    EL_CHAR_BRACKETRIGHT,              -1, -1, FALSE,
+    IMG_CHAR_BRACKETRIGHT
+  },
+  {
+    EL_CHAR_ASCIICIRCUM,               -1, -1, FALSE,
+    IMG_CHAR_ASCIICIRCUM
+  },
+  {
+    EL_CHAR_UNDERSCORE,                        -1, -1, FALSE,
+    IMG_CHAR_UNDERSCORE
+  },
+  {
+    EL_CHAR_COPYRIGHT,                 -1, -1, FALSE,
+    IMG_CHAR_COPYRIGHT
+  },
+  {
+    EL_CHAR_AUMLAUT,                   -1, -1, FALSE,
+    IMG_CHAR_AUMLAUT
+  },
+  {
+    EL_CHAR_OUMLAUT,                   -1, -1, FALSE,
+    IMG_CHAR_OUMLAUT
+  },
+  {
+    EL_CHAR_UUMLAUT,                   -1, -1, FALSE,
+    IMG_CHAR_UUMLAUT
+  },
+  {
+    EL_CHAR_DEGREE,                    -1, -1, FALSE,
+    IMG_CHAR_DEGREE
+  },
+  {
+    EL_CHAR_TRADEMARK,                 -1, -1, FALSE,
+    IMG_CHAR_TRADEMARK
+  },
+  {
+    EL_CHAR_CURSOR,                    -1, -1, FALSE,
+    IMG_CHAR_CURSOR
+  },
+  {
+    EL_CUSTOM_1,                       -1, -1, FALSE,
+    IMG_CUSTOM_1
+  },
+  {
+    EL_CUSTOM_2,                       -1, -1, FALSE,
+    IMG_CUSTOM_2
+  },
+  {
+    EL_CUSTOM_3,                       -1, -1, FALSE,
+    IMG_CUSTOM_3
+  },
+  {
+    EL_CUSTOM_4,                       -1, -1, FALSE,
+    IMG_CUSTOM_4
+  },
+  {
+    EL_CUSTOM_5,                       -1, -1, FALSE,
+    IMG_CUSTOM_5
+  },
+  {
+    EL_CUSTOM_6,                       -1, -1, FALSE,
+    IMG_CUSTOM_6
+  },
+  {
+    EL_CUSTOM_7,                       -1, -1, FALSE,
+    IMG_CUSTOM_7
+  },
+  {
+    EL_CUSTOM_8,                       -1, -1, FALSE,
+    IMG_CUSTOM_8
+  },
+  {
+    EL_CUSTOM_9,                       -1, -1, FALSE,
+    IMG_CUSTOM_9
+  },
+  {
+    EL_CUSTOM_10,                      -1, -1, FALSE,
+    IMG_CUSTOM_10
+  },
+  {
+    EL_CUSTOM_11,                      -1, -1, FALSE,
+    IMG_CUSTOM_11
+  },
+  {
+    EL_CUSTOM_12,                      -1, -1, FALSE,
+    IMG_CUSTOM_12
+  },
+  {
+    EL_CUSTOM_13,                      -1, -1, FALSE,
+    IMG_CUSTOM_13
+  },
+  {
+    EL_CUSTOM_14,                      -1, -1, FALSE,
+    IMG_CUSTOM_14
+  },
+  {
+    EL_CUSTOM_15,                      -1, -1, FALSE,
+    IMG_CUSTOM_15
+  },
+  {
+    EL_CUSTOM_16,                      -1, -1, FALSE,
+    IMG_CUSTOM_16
+  },
+  {
+    EL_CUSTOM_17,                      -1, -1, FALSE,
+    IMG_CUSTOM_17
+  },
+  {
+    EL_CUSTOM_18,                      -1, -1, FALSE,
+    IMG_CUSTOM_18
+  },
+  {
+    EL_CUSTOM_19,                      -1, -1, FALSE,
+    IMG_CUSTOM_19
+  },
+  {
+    EL_CUSTOM_20,                      -1, -1, FALSE,
+    IMG_CUSTOM_20
+  },
+  {
+    EL_CUSTOM_21,                      -1, -1, FALSE,
+    IMG_CUSTOM_21
+  },
+  {
+    EL_CUSTOM_22,                      -1, -1, FALSE,
+    IMG_CUSTOM_22
+  },
+  {
+    EL_CUSTOM_23,                      -1, -1, FALSE,
+    IMG_CUSTOM_23
+  },
+  {
+    EL_CUSTOM_24,                      -1, -1, FALSE,
+    IMG_CUSTOM_24
+  },
+  {
+    EL_CUSTOM_25,                      -1, -1, FALSE,
+    IMG_CUSTOM_25
+  },
+  {
+    EL_CUSTOM_26,                      -1, -1, FALSE,
+    IMG_CUSTOM_26
+  },
+  {
+    EL_CUSTOM_27,                      -1, -1, FALSE,
+    IMG_CUSTOM_27
+  },
+  {
+    EL_CUSTOM_28,                      -1, -1, FALSE,
+    IMG_CUSTOM_28
+  },
+  {
+    EL_CUSTOM_29,                      -1, -1, FALSE,
+    IMG_CUSTOM_29
+  },
+  {
+    EL_CUSTOM_30,                      -1, -1, FALSE,
+    IMG_CUSTOM_30
+  },
+  {
+    EL_CUSTOM_31,                      -1, -1, FALSE,
+    IMG_CUSTOM_31
+  },
+  {
+    EL_CUSTOM_32,                      -1, -1, FALSE,
+    IMG_CUSTOM_32
+  },
+  {
+    EL_CUSTOM_33,                      -1, -1, FALSE,
+    IMG_CUSTOM_33
+  },
+  {
+    EL_CUSTOM_34,                      -1, -1, FALSE,
+    IMG_CUSTOM_34
+  },
+  {
+    EL_CUSTOM_35,                      -1, -1, FALSE,
+    IMG_CUSTOM_35
+  },
+  {
+    EL_CUSTOM_36,                      -1, -1, FALSE,
+    IMG_CUSTOM_36
+  },
+  {
+    EL_CUSTOM_37,                      -1, -1, FALSE,
+    IMG_CUSTOM_37
+  },
+  {
+    EL_CUSTOM_38,                      -1, -1, FALSE,
+    IMG_CUSTOM_38
+  },
+  {
+    EL_CUSTOM_39,                      -1, -1, FALSE,
+    IMG_CUSTOM_39
+  },
+  {
+    EL_CUSTOM_40,                      -1, -1, FALSE,
+    IMG_CUSTOM_40
+  },
+  {
+    EL_CUSTOM_41,                      -1, -1, FALSE,
+    IMG_CUSTOM_41
+  },
+  {
+    EL_CUSTOM_42,                      -1, -1, FALSE,
+    IMG_CUSTOM_42
+  },
+  {
+    EL_CUSTOM_43,                      -1, -1, FALSE,
+    IMG_CUSTOM_43
+  },
+  {
+    EL_CUSTOM_44,                      -1, -1, FALSE,
+    IMG_CUSTOM_44
+  },
+  {
+    EL_CUSTOM_45,                      -1, -1, FALSE,
+    IMG_CUSTOM_45
+  },
+  {
+    EL_CUSTOM_46,                      -1, -1, FALSE,
+    IMG_CUSTOM_46
+  },
+  {
+    EL_CUSTOM_47,                      -1, -1, FALSE,
+    IMG_CUSTOM_47
+  },
+  {
+    EL_CUSTOM_48,                      -1, -1, FALSE,
+    IMG_CUSTOM_48
+  },
+  {
+    EL_CUSTOM_49,                      -1, -1, FALSE,
+    IMG_CUSTOM_49
+  },
+  {
+    EL_CUSTOM_50,                      -1, -1, FALSE,
+    IMG_CUSTOM_50
+  },
+  {
+    EL_CUSTOM_51,                      -1, -1, FALSE,
+    IMG_CUSTOM_51
+  },
+  {
+    EL_CUSTOM_52,                      -1, -1, FALSE,
+    IMG_CUSTOM_52
+  },
+  {
+    EL_CUSTOM_53,                      -1, -1, FALSE,
+    IMG_CUSTOM_53
+  },
+  {
+    EL_CUSTOM_54,                      -1, -1, FALSE,
+    IMG_CUSTOM_54
+  },
+  {
+    EL_CUSTOM_55,                      -1, -1, FALSE,
+    IMG_CUSTOM_55
+  },
+  {
+    EL_CUSTOM_56,                      -1, -1, FALSE,
+    IMG_CUSTOM_56
+  },
+  {
+    EL_CUSTOM_57,                      -1, -1, FALSE,
+    IMG_CUSTOM_57
+  },
+  {
+    EL_CUSTOM_58,                      -1, -1, FALSE,
+    IMG_CUSTOM_58
+  },
+  {
+    EL_CUSTOM_59,                      -1, -1, FALSE,
+    IMG_CUSTOM_59
+  },
+  {
+    EL_CUSTOM_60,                      -1, -1, FALSE,
+    IMG_CUSTOM_60
+  },
+  {
+    EL_CUSTOM_61,                      -1, -1, FALSE,
+    IMG_CUSTOM_61
+  },
+  {
+    EL_CUSTOM_62,                      -1, -1, FALSE,
+    IMG_CUSTOM_62
+  },
+  {
+    EL_CUSTOM_63,                      -1, -1, FALSE,
+    IMG_CUSTOM_63
+  },
+  {
+    EL_CUSTOM_64,                      -1, -1, FALSE,
+    IMG_CUSTOM_64
+  },
+  {
+    EL_CUSTOM_65,                      -1, -1, FALSE,
+    IMG_CUSTOM_65
+  },
+  {
+    EL_CUSTOM_66,                      -1, -1, FALSE,
+    IMG_CUSTOM_66
+  },
+  {
+    EL_CUSTOM_67,                      -1, -1, FALSE,
+    IMG_CUSTOM_67
+  },
+  {
+    EL_CUSTOM_68,                      -1, -1, FALSE,
+    IMG_CUSTOM_68
+  },
+  {
+    EL_CUSTOM_69,                      -1, -1, FALSE,
+    IMG_CUSTOM_69
+  },
+  {
+    EL_CUSTOM_70,                      -1, -1, FALSE,
+    IMG_CUSTOM_70
+  },
+  {
+    EL_CUSTOM_71,                      -1, -1, FALSE,
+    IMG_CUSTOM_71
+  },
+  {
+    EL_CUSTOM_72,                      -1, -1, FALSE,
+    IMG_CUSTOM_72
+  },
+  {
+    EL_CUSTOM_73,                      -1, -1, FALSE,
+    IMG_CUSTOM_73
+  },
+  {
+    EL_CUSTOM_74,                      -1, -1, FALSE,
+    IMG_CUSTOM_74
+  },
+  {
+    EL_CUSTOM_75,                      -1, -1, FALSE,
+    IMG_CUSTOM_75
+  },
+  {
+    EL_CUSTOM_76,                      -1, -1, FALSE,
+    IMG_CUSTOM_76
+  },
+  {
+    EL_CUSTOM_77,                      -1, -1, FALSE,
+    IMG_CUSTOM_77
+  },
+  {
+    EL_CUSTOM_78,                      -1, -1, FALSE,
+    IMG_CUSTOM_78
+  },
+  {
+    EL_CUSTOM_79,                      -1, -1, FALSE,
+    IMG_CUSTOM_79
+  },
+  {
+    EL_CUSTOM_80,                      -1, -1, FALSE,
+    IMG_CUSTOM_80
+  },
+  {
+    EL_CUSTOM_81,                      -1, -1, FALSE,
+    IMG_CUSTOM_81
+  },
+  {
+    EL_CUSTOM_82,                      -1, -1, FALSE,
+    IMG_CUSTOM_82
+  },
+  {
+    EL_CUSTOM_83,                      -1, -1, FALSE,
+    IMG_CUSTOM_83
+  },
+  {
+    EL_CUSTOM_84,                      -1, -1, FALSE,
+    IMG_CUSTOM_84
+  },
+  {
+    EL_CUSTOM_85,                      -1, -1, FALSE,
+    IMG_CUSTOM_85
+  },
+  {
+    EL_CUSTOM_86,                      -1, -1, FALSE,
+    IMG_CUSTOM_86
+  },
+  {
+    EL_CUSTOM_87,                      -1, -1, FALSE,
+    IMG_CUSTOM_87
+  },
+  {
+    EL_CUSTOM_88,                      -1, -1, FALSE,
+    IMG_CUSTOM_88
+  },
+  {
+    EL_CUSTOM_89,                      -1, -1, FALSE,
+    IMG_CUSTOM_89
+  },
+  {
+    EL_CUSTOM_90,                      -1, -1, FALSE,
+    IMG_CUSTOM_90
+  },
+  {
+    EL_CUSTOM_91,                      -1, -1, FALSE,
+    IMG_CUSTOM_91
+  },
+  {
+    EL_CUSTOM_92,                      -1, -1, FALSE,
+    IMG_CUSTOM_92
+  },
+  {
+    EL_CUSTOM_93,                      -1, -1, FALSE,
+    IMG_CUSTOM_93
+  },
+  {
+    EL_CUSTOM_94,                      -1, -1, FALSE,
+    IMG_CUSTOM_94
+  },
+  {
+    EL_CUSTOM_95,                      -1, -1, FALSE,
+    IMG_CUSTOM_95
+  },
+  {
+    EL_CUSTOM_96,                      -1, -1, FALSE,
+    IMG_CUSTOM_96
+  },
+  {
+    EL_CUSTOM_97,                      -1, -1, FALSE,
+    IMG_CUSTOM_97
+  },
+  {
+    EL_CUSTOM_98,                      -1, -1, FALSE,
+    IMG_CUSTOM_98
+  },
+  {
+    EL_CUSTOM_99,                      -1, -1, FALSE,
+    IMG_CUSTOM_99
+  },
+  {
+    EL_CUSTOM_100,                     -1, -1, FALSE,
+    IMG_CUSTOM_100
+  },
+  {
+    EL_CUSTOM_101,                     -1, -1, FALSE,
+    IMG_CUSTOM_101
+  },
+  {
+    EL_CUSTOM_102,                     -1, -1, FALSE,
+    IMG_CUSTOM_102
+  },
+  {
+    EL_CUSTOM_103,                     -1, -1, FALSE,
+    IMG_CUSTOM_103
+  },
+  {
+    EL_CUSTOM_104,                     -1, -1, FALSE,
+    IMG_CUSTOM_104
+  },
+  {
+    EL_CUSTOM_105,                     -1, -1, FALSE,
+    IMG_CUSTOM_105
+  },
+  {
+    EL_CUSTOM_106,                     -1, -1, FALSE,
+    IMG_CUSTOM_106
+  },
+  {
+    EL_CUSTOM_107,                     -1, -1, FALSE,
+    IMG_CUSTOM_107
+  },
+  {
+    EL_CUSTOM_108,                     -1, -1, FALSE,
+    IMG_CUSTOM_108
+  },
+  {
+    EL_CUSTOM_109,                     -1, -1, FALSE,
+    IMG_CUSTOM_109
+  },
+  {
+    EL_CUSTOM_110,                     -1, -1, FALSE,
+    IMG_CUSTOM_110
+  },
+  {
+    EL_CUSTOM_111,                     -1, -1, FALSE,
+    IMG_CUSTOM_111
+  },
+  {
+    EL_CUSTOM_112,                     -1, -1, FALSE,
+    IMG_CUSTOM_112
+  },
+  {
+    EL_CUSTOM_113,                     -1, -1, FALSE,
+    IMG_CUSTOM_113
+  },
+  {
+    EL_CUSTOM_114,                     -1, -1, FALSE,
+    IMG_CUSTOM_114
+  },
+  {
+    EL_CUSTOM_115,                     -1, -1, FALSE,
+    IMG_CUSTOM_115
+  },
+  {
+    EL_CUSTOM_116,                     -1, -1, FALSE,
+    IMG_CUSTOM_116
+  },
+  {
+    EL_CUSTOM_117,                     -1, -1, FALSE,
+    IMG_CUSTOM_117
+  },
+  {
+    EL_CUSTOM_118,                     -1, -1, FALSE,
+    IMG_CUSTOM_118
+  },
+  {
+    EL_CUSTOM_119,                     -1, -1, FALSE,
+    IMG_CUSTOM_119
+  },
+  {
+    EL_CUSTOM_120,                     -1, -1, FALSE,
+    IMG_CUSTOM_120
+  },
+  {
+    EL_CUSTOM_121,                     -1, -1, FALSE,
+    IMG_CUSTOM_121
+  },
+  {
+    EL_CUSTOM_122,                     -1, -1, FALSE,
+    IMG_CUSTOM_122
+  },
+  {
+    EL_CUSTOM_123,                     -1, -1, FALSE,
+    IMG_CUSTOM_123
+  },
+  {
+    EL_CUSTOM_124,                     -1, -1, FALSE,
+    IMG_CUSTOM_124
+  },
+  {
+    EL_CUSTOM_125,                     -1, -1, FALSE,
+    IMG_CUSTOM_125
+  },
+  {
+    EL_CUSTOM_126,                     -1, -1, FALSE,
+    IMG_CUSTOM_126
+  },
+  {
+    EL_CUSTOM_127,                     -1, -1, FALSE,
+    IMG_CUSTOM_127
+  },
+  {
+    EL_CUSTOM_128,                     -1, -1, FALSE,
+    IMG_CUSTOM_128
+  },
+  {
+    -1,                                        -1, -1, FALSE,
+    -1
+  },
+};
+
+#endif /* CONF_E2G_C */
diff --git a/src/conf_e2s.c b/src/conf_e2s.c
new file mode 100644 (file)
index 0000000..6e229df
--- /dev/null
@@ -0,0 +1,729 @@
+/***********************************************************
+* Rocks'n'Diamonds -- McDuffin Strikes Back!               *
+*----------------------------------------------------------*
+* (c) 1995-2002 Artsoft Entertainment                      *
+*               Holger Schemel                             *
+*               Detmolder Strasse 189                      *
+*               33604 Bielefeld                            *
+*               Germany                                    *
+*               e-mail: info@artsoft.org                   *
+*----------------------------------------------------------*
+* conf_e2s.c                                               *
+***********************************************************/
+
+/* ----- this file was automatically generated -- do not edit by hand ----- */
+
+#ifndef CONF_E2S_C
+#define CONF_E2S_C
+
+/* values for element/sounds mapping configuration */
+
+static struct
+{
+  int element;
+  boolean is_class;
+  int action;
+
+  int sound;
+}
+element_to_sound[] =
+{
+  {
+    EL_DEFAULT, TRUE,                          ACTION_DIGGING,
+    SND_CLASS_DEFAULT_DIGGING
+  },
+  {
+    EL_DEFAULT, TRUE,                          ACTION_COLLECTING,
+    SND_CLASS_DEFAULT_COLLECTING
+  },
+  {
+    EL_DEFAULT, TRUE,                          ACTION_SNAPPING,
+    SND_CLASS_DEFAULT_SNAPPING
+  },
+  {
+    EL_DEFAULT, TRUE,                          ACTION_PUSHING,
+    SND_CLASS_DEFAULT_PUSHING
+  },
+  {
+    EL_DEFAULT, TRUE,                          ACTION_IMPACT,
+    SND_CLASS_DEFAULT_IMPACT
+  },
+  {
+    EL_DEFAULT, TRUE,                          ACTION_WALKING,
+    SND_CLASS_DEFAULT_WALKING
+  },
+  {
+    EL_DEFAULT, TRUE,                          ACTION_PASSING,
+    SND_CLASS_DEFAULT_PASSING
+  },
+  {
+    EL_DEFAULT, TRUE,                          ACTION_DYING,
+    SND_CLASS_DEFAULT_DYING
+  },
+  {
+    EL_DEFAULT, TRUE,                          ACTION_EXPLODING,
+    SND_CLASS_DEFAULT_EXPLODING
+  },
+  {
+    EL_SP_DEFAULT, TRUE,                       ACTION_EXPLODING,
+    SND_CLASS_SP_DEFAULT_EXPLODING
+  },
+  {
+    EL_BD_DIAMOND, FALSE,                      ACTION_COLLECTING,
+    SND_BD_DIAMOND_COLLECTING
+  },
+  {
+    EL_BD_DIAMOND, FALSE,                      ACTION_IMPACT,
+    SND_BD_DIAMOND_IMPACT
+  },
+  {
+    EL_BD_ROCK, FALSE,                         ACTION_PUSHING,
+    SND_BD_ROCK_PUSHING
+  },
+  {
+    EL_BD_ROCK, FALSE,                         ACTION_IMPACT,
+    SND_BD_ROCK_IMPACT
+  },
+  {
+    EL_BD_MAGIC_WALL, FALSE,                   ACTION_ACTIVATING,
+    SND_BD_MAGIC_WALL_ACTIVATING
+  },
+  {
+    EL_BD_MAGIC_WALL_ACTIVE, FALSE,            -1,
+    SND_BD_MAGIC_WALL_ACTIVE
+  },
+  {
+    EL_BD_MAGIC_WALL, FALSE,                   ACTION_ACTIVE,
+    SND_BD_MAGIC_WALL_ACTIVE
+  },
+  {
+    EL_BD_MAGIC_WALL_FILLING, FALSE,           -1,
+    SND_BD_MAGIC_WALL_FILLING
+  },
+  {
+    EL_BD_MAGIC_WALL, FALSE,                   ACTION_FILLING,
+    SND_BD_MAGIC_WALL_FILLING
+  },
+  {
+    EL_BD_AMOEBA, FALSE,                       ACTION_WAITING,
+    SND_BD_AMOEBA_WAITING
+  },
+  {
+    EL_BD_AMOEBA, FALSE,                       ACTION_GROWING,
+    SND_BD_AMOEBA_GROWING
+  },
+  {
+    EL_BD_BUTTERFLY, FALSE,                    ACTION_MOVING,
+    SND_BD_BUTTERFLY_MOVING
+  },
+  {
+    EL_BD_BUTTERFLY, FALSE,                    ACTION_WAITING,
+    SND_BD_BUTTERFLY_WAITING
+  },
+  {
+    EL_BD_FIREFLY, FALSE,                      ACTION_MOVING,
+    SND_BD_FIREFLY_MOVING
+  },
+  {
+    EL_BD_FIREFLY, FALSE,                      ACTION_WAITING,
+    SND_BD_FIREFLY_WAITING
+  },
+  {
+    EL_SP_BASE, FALSE,                         ACTION_DIGGING,
+    SND_SP_BASE_DIGGING
+  },
+  {
+    EL_SP_BUGGY_BASE, FALSE,                   ACTION_DIGGING,
+    SND_SP_BUGGY_BASE_DIGGING
+  },
+  {
+    EL_SP_BUGGY_BASE_ACTIVE, FALSE,            -1,
+    SND_SP_BUGGY_BASE_ACTIVE
+  },
+  {
+    EL_SP_BUGGY_BASE, FALSE,                   ACTION_ACTIVE,
+    SND_SP_BUGGY_BASE_ACTIVE
+  },
+  {
+    EL_SP_INFOTRON, FALSE,                     ACTION_COLLECTING,
+    SND_SP_INFOTRON_COLLECTING
+  },
+  {
+    EL_SP_INFOTRON, FALSE,                     ACTION_IMPACT,
+    SND_SP_INFOTRON_IMPACT
+  },
+  {
+    EL_SP_ZONK, FALSE,                         ACTION_PUSHING,
+    SND_SP_ZONK_PUSHING
+  },
+  {
+    EL_SP_ZONK, FALSE,                         ACTION_IMPACT,
+    SND_SP_ZONK_IMPACT
+  },
+  {
+    EL_SP_DISK_RED, FALSE,                     ACTION_COLLECTING,
+    SND_SP_DISK_RED_COLLECTING
+  },
+  {
+    EL_SP_DISK_ORANGE, FALSE,                  ACTION_PUSHING,
+    SND_SP_DISK_ORANGE_PUSHING
+  },
+  {
+    EL_SP_DISK_YELLOW, FALSE,                  ACTION_PUSHING,
+    SND_SP_DISK_YELLOW_PUSHING
+  },
+  {
+    EL_SP_PORT_RIGHT, TRUE,                    ACTION_PASSING,
+    SND_CLASS_SP_PORT_PASSING
+  },
+  {
+    EL_SP_EXIT_CLOSED, TRUE,                   ACTION_PASSING,
+    SND_CLASS_SP_EXIT_PASSING
+  },
+  {
+    EL_SP_EXIT_CLOSED, TRUE,                   ACTION_OPENING,
+    SND_CLASS_SP_EXIT_OPENING
+  },
+  {
+    EL_SP_SNIKSNAK, FALSE,                     ACTION_MOVING,
+    SND_SP_SNIKSNAK_MOVING
+  },
+  {
+    EL_SP_SNIKSNAK, FALSE,                     ACTION_WAITING,
+    SND_SP_SNIKSNAK_WAITING
+  },
+  {
+    EL_SP_ELECTRON, FALSE,                     ACTION_MOVING,
+    SND_SP_ELECTRON_MOVING
+  },
+  {
+    EL_SP_ELECTRON, FALSE,                     ACTION_WAITING,
+    SND_SP_ELECTRON_WAITING
+  },
+  {
+    EL_SP_TERMINAL, FALSE,                     ACTION_ACTIVATING,
+    SND_SP_TERMINAL_ACTIVATING
+  },
+  {
+    EL_SP_TERMINAL_ACTIVE, FALSE,              -1,
+    SND_SP_TERMINAL_ACTIVE
+  },
+  {
+    EL_SP_TERMINAL, FALSE,                     ACTION_ACTIVE,
+    SND_SP_TERMINAL_ACTIVE
+  },
+  {
+    EL_SOKOBAN_OBJECT, TRUE,                   ACTION_PUSHING,
+    SND_CLASS_SOKOBAN_PUSHING
+  },
+  {
+    EL_SOKOBAN_OBJECT, TRUE,                   ACTION_FILLING,
+    SND_CLASS_SOKOBAN_FILLING
+  },
+  {
+    EL_SOKOBAN_OBJECT, TRUE,                   ACTION_EMPTYING,
+    SND_CLASS_SOKOBAN_EMPTYING
+  },
+  {
+    EL_PLAYER_OBSOLETE, TRUE,                  ACTION_MOVING,
+    SND_CLASS_PLAYER_MOVING
+  },
+  {
+    EL_SAND, FALSE,                            ACTION_DIGGING,
+    SND_SAND_DIGGING
+  },
+  {
+    EL_EMERALD, FALSE,                         ACTION_COLLECTING,
+    SND_EMERALD_COLLECTING
+  },
+  {
+    EL_EMERALD, FALSE,                         ACTION_IMPACT,
+    SND_EMERALD_IMPACT
+  },
+  {
+    EL_DIAMOND, FALSE,                         ACTION_COLLECTING,
+    SND_DIAMOND_COLLECTING
+  },
+  {
+    EL_DIAMOND, FALSE,                         ACTION_IMPACT,
+    SND_DIAMOND_IMPACT
+  },
+  {
+    EL_DIAMOND_BREAKING, FALSE,                        -1,
+    SND_DIAMOND_BREAKING
+  },
+  {
+    EL_DIAMOND, FALSE,                         ACTION_BREAKING,
+    SND_DIAMOND_BREAKING
+  },
+  {
+    EL_ROCK, FALSE,                            ACTION_PUSHING,
+    SND_ROCK_PUSHING
+  },
+  {
+    EL_ROCK, FALSE,                            ACTION_IMPACT,
+    SND_ROCK_IMPACT
+  },
+  {
+    EL_BOMB, FALSE,                            ACTION_PUSHING,
+    SND_BOMB_PUSHING
+  },
+  {
+    EL_NUT, FALSE,                             ACTION_PUSHING,
+    SND_NUT_PUSHING
+  },
+  {
+    EL_NUT_BREAKING, FALSE,                    -1,
+    SND_NUT_BREAKING
+  },
+  {
+    EL_NUT, FALSE,                             ACTION_BREAKING,
+    SND_NUT_BREAKING
+  },
+  {
+    EL_NUT, FALSE,                             ACTION_IMPACT,
+    SND_NUT_IMPACT
+  },
+  {
+    EL_DYNAMITE_ACTIVE, TRUE,                  ACTION_COLLECTING,
+    SND_CLASS_DYNAMITE_COLLECTING
+  },
+  {
+    EL_DYNAMITE_ACTIVE, TRUE,                  ACTION_DROPPING,
+    SND_CLASS_DYNAMITE_DROPPING
+  },
+  {
+    EL_DYNAMITE_ACTIVE, TRUE,                  ACTION_ACTIVE,
+    SND_CLASS_DYNAMITE_ACTIVE
+  },
+  {
+    EL_KEY_OBSOLETE, TRUE,                     ACTION_COLLECTING,
+    SND_CLASS_KEY_COLLECTING
+  },
+  {
+    EL_GATE_1, TRUE,                           ACTION_PASSING,
+    SND_CLASS_GATE_PASSING
+  },
+  {
+    EL_BUG, FALSE,                             ACTION_MOVING,
+    SND_BUG_MOVING
+  },
+  {
+    EL_BUG, FALSE,                             ACTION_WAITING,
+    SND_BUG_WAITING
+  },
+  {
+    EL_SPACESHIP, FALSE,                       ACTION_MOVING,
+    SND_SPACESHIP_MOVING
+  },
+  {
+    EL_SPACESHIP, FALSE,                       ACTION_WAITING,
+    SND_SPACESHIP_WAITING
+  },
+  {
+    EL_YAMYAM, FALSE,                          ACTION_MOVING,
+    SND_YAMYAM_MOVING
+  },
+  {
+    EL_YAMYAM, FALSE,                          ACTION_WAITING,
+    SND_YAMYAM_WAITING
+  },
+  {
+    EL_YAMYAM, FALSE,                          ACTION_DIGGING,
+    SND_YAMYAM_DIGGING
+  },
+  {
+    EL_ROBOT, FALSE,                           ACTION_MOVING,
+    SND_ROBOT_MOVING
+  },
+  {
+    EL_ROBOT, FALSE,                           ACTION_WAITING,
+    SND_ROBOT_WAITING
+  },
+  {
+    EL_ROBOT_WHEEL, FALSE,                     ACTION_ACTIVATING,
+    SND_ROBOT_WHEEL_ACTIVATING
+  },
+  {
+    EL_ROBOT_WHEEL_ACTIVE, FALSE,              -1,
+    SND_ROBOT_WHEEL_ACTIVE
+  },
+  {
+    EL_ROBOT_WHEEL, FALSE,                     ACTION_ACTIVE,
+    SND_ROBOT_WHEEL_ACTIVE
+  },
+  {
+    EL_MAGIC_WALL, FALSE,                      ACTION_ACTIVATING,
+    SND_MAGIC_WALL_ACTIVATING
+  },
+  {
+    EL_MAGIC_WALL_ACTIVE, FALSE,               -1,
+    SND_MAGIC_WALL_ACTIVE
+  },
+  {
+    EL_MAGIC_WALL, FALSE,                      ACTION_ACTIVE,
+    SND_MAGIC_WALL_ACTIVE
+  },
+  {
+    EL_MAGIC_WALL_FILLING, FALSE,              -1,
+    SND_MAGIC_WALL_FILLING
+  },
+  {
+    EL_MAGIC_WALL, FALSE,                      ACTION_FILLING,
+    SND_MAGIC_WALL_FILLING
+  },
+  {
+    EL_AMOEBA_DEAD, TRUE,                      ACTION_WAITING,
+    SND_CLASS_AMOEBA_WAITING
+  },
+  {
+    EL_AMOEBA_DEAD, TRUE,                      ACTION_GROWING,
+    SND_CLASS_AMOEBA_GROWING
+  },
+  {
+    EL_AMOEBA_DEAD, TRUE,                      ACTION_DROPPING,
+    SND_CLASS_AMOEBA_DROPPING
+  },
+  {
+    EL_QUICKSAND_EMPTY, TRUE,                  ACTION_FILLING,
+    SND_CLASS_QUICKSAND_FILLING
+  },
+  {
+    EL_QUICKSAND_EMPTY, TRUE,                  ACTION_EMPTYING,
+    SND_CLASS_QUICKSAND_EMPTYING
+  },
+  {
+    EL_EXIT_CLOSED, TRUE,                      ACTION_OPENING,
+    SND_CLASS_EXIT_OPENING
+  },
+  {
+    EL_EXIT_CLOSED, TRUE,                      ACTION_PASSING,
+    SND_CLASS_EXIT_PASSING
+  },
+  {
+    EL_PENGUIN, FALSE,                         ACTION_PASSING,
+    SND_PENGUIN_PASSING
+  },
+  {
+    EL_BALLOON, FALSE,                         ACTION_MOVING,
+    SND_BALLOON_MOVING
+  },
+  {
+    EL_BALLOON, FALSE,                         ACTION_WAITING,
+    SND_BALLOON_WAITING
+  },
+  {
+    EL_BALLOON, FALSE,                         ACTION_PUSHING,
+    SND_BALLOON_PUSHING
+  },
+  {
+    EL_BALLOON_SWITCH_LEFT, TRUE,              ACTION_ACTIVATING,
+    SND_CLASS_BALLOON_SWITCH_ACTIVATING
+  },
+  {
+    EL_SPRING, FALSE,                          ACTION_MOVING,
+    SND_SPRING_MOVING
+  },
+  {
+    EL_SPRING, FALSE,                          ACTION_PUSHING,
+    SND_SPRING_PUSHING
+  },
+  {
+    EL_SPRING, FALSE,                          ACTION_IMPACT,
+    SND_SPRING_IMPACT
+  },
+  {
+    EL_WALL, TRUE,                             ACTION_GROWING,
+    SND_CLASS_WALL_GROWING
+  },
+  {
+    EL_PEARL, FALSE,                           ACTION_COLLECTING,
+    SND_PEARL_COLLECTING
+  },
+  {
+    EL_PEARL_BREAKING, FALSE,                  -1,
+    SND_PEARL_BREAKING
+  },
+  {
+    EL_PEARL, FALSE,                           ACTION_BREAKING,
+    SND_PEARL_BREAKING
+  },
+  {
+    EL_PEARL, FALSE,                           ACTION_IMPACT,
+    SND_PEARL_IMPACT
+  },
+  {
+    EL_CRYSTAL, FALSE,                         ACTION_COLLECTING,
+    SND_CRYSTAL_COLLECTING
+  },
+  {
+    EL_CRYSTAL, FALSE,                         ACTION_IMPACT,
+    SND_CRYSTAL_IMPACT
+  },
+  {
+    EL_ENVELOPE, FALSE,                                ACTION_COLLECTING,
+    SND_ENVELOPE_COLLECTING
+  },
+  {
+    EL_INVISIBLE_SAND, FALSE,                  ACTION_DIGGING,
+    SND_INVISIBLE_SAND_DIGGING
+  },
+  {
+    EL_SHIELD_NORMAL, FALSE,                   ACTION_COLLECTING,
+    SND_SHIELD_NORMAL_COLLECTING
+  },
+  {
+    EL_SHIELD_NORMAL_ACTIVE, FALSE,            -1,
+    SND_SHIELD_NORMAL_ACTIVE
+  },
+  {
+    EL_SHIELD_NORMAL, FALSE,                   ACTION_ACTIVE,
+    SND_SHIELD_NORMAL_ACTIVE
+  },
+  {
+    EL_SHIELD_DEADLY, FALSE,                   ACTION_COLLECTING,
+    SND_SHIELD_DEADLY_COLLECTING
+  },
+  {
+    EL_SHIELD_DEADLY_ACTIVE, FALSE,            -1,
+    SND_SHIELD_DEADLY_ACTIVE
+  },
+  {
+    EL_SHIELD_DEADLY, FALSE,                   ACTION_ACTIVE,
+    SND_SHIELD_DEADLY_ACTIVE
+  },
+  {
+    EL_EXTRA_TIME, FALSE,                      ACTION_COLLECTING,
+    SND_EXTRA_TIME_COLLECTING
+  },
+  {
+    EL_MOLE, FALSE,                            ACTION_MOVING,
+    SND_MOLE_MOVING
+  },
+  {
+    EL_MOLE, FALSE,                            ACTION_WAITING,
+    SND_MOLE_WAITING
+  },
+  {
+    EL_MOLE, FALSE,                            ACTION_DIGGING,
+    SND_MOLE_DIGGING
+  },
+  {
+    EL_SWITCHGATE_SWITCH_UP, TRUE,             ACTION_ACTIVATING,
+    SND_CLASS_SWITCHGATE_SWITCH_ACTIVATING
+  },
+  {
+    EL_SWITCHGATE_OPEN, TRUE,                  ACTION_OPENING,
+    SND_CLASS_SWITCHGATE_OPENING
+  },
+  {
+    EL_SWITCHGATE_OPEN, TRUE,                  ACTION_CLOSING,
+    SND_CLASS_SWITCHGATE_CLOSING
+  },
+  {
+    EL_SWITCHGATE_OPEN, TRUE,                  ACTION_PASSING,
+    SND_CLASS_SWITCHGATE_PASSING
+  },
+  {
+    EL_TIMEGATE_SWITCH, FALSE,                 ACTION_ACTIVATING,
+    SND_TIMEGATE_SWITCH_ACTIVATING
+  },
+  {
+    EL_TIMEGATE_SWITCH_ACTIVE, FALSE,          -1,
+    SND_TIMEGATE_SWITCH_ACTIVE
+  },
+  {
+    EL_TIMEGATE_SWITCH, FALSE,                 ACTION_ACTIVE,
+    SND_TIMEGATE_SWITCH_ACTIVE
+  },
+  {
+    EL_TIMEGATE_SWITCH, FALSE,                 ACTION_DEACTIVATING,
+    SND_TIMEGATE_SWITCH_DEACTIVATING
+  },
+  {
+    EL_TIMEGATE_OPENING, FALSE,                        -1,
+    SND_TIMEGATE_OPENING
+  },
+  {
+    EL_TIMEGATE_OPEN, TRUE,                    ACTION_CLOSING,
+    SND_CLASS_TIMEGATE_CLOSING
+  },
+  {
+    EL_TIMEGATE_OPEN, TRUE,                    ACTION_PASSING,
+    SND_CLASS_TIMEGATE_PASSING
+  },
+  {
+    EL_CONVEYOR_BELT_1_SWITCH_LEFT, TRUE,      ACTION_ACTIVATING,
+    SND_CLASS_CONVEYOR_BELT_SWITCH_ACTIVATING
+  },
+  {
+    EL_CONVEYOR_BELT_1_LEFT, TRUE,             ACTION_ACTIVE,
+    SND_CLASS_CONVEYOR_BELT_ACTIVE
+  },
+  {
+    EL_CONVEYOR_BELT_1_SWITCH_LEFT, TRUE,      ACTION_DEACTIVATING,
+    SND_CLASS_CONVEYOR_BELT_SWITCH_DEACTIVATING
+  },
+  {
+    EL_LIGHT_SWITCH, FALSE,                    ACTION_ACTIVATING,
+    SND_LIGHT_SWITCH_ACTIVATING
+  },
+  {
+    EL_LIGHT_SWITCH, FALSE,                    ACTION_DEACTIVATING,
+    SND_LIGHT_SWITCH_DEACTIVATING
+  },
+  {
+    EL_DX_SUPABOMB, FALSE,                     ACTION_PUSHING,
+    SND_DX_SUPABOMB_PUSHING
+  },
+  {
+    EL_TRAP, FALSE,                            ACTION_DIGGING,
+    SND_TRAP_DIGGING
+  },
+  {
+    EL_TRAP, FALSE,                            ACTION_ACTIVATING,
+    SND_TRAP_ACTIVATING
+  },
+  {
+    EL_TUBE_ANY, TRUE,                         ACTION_WALKING,
+    SND_CLASS_TUBE_WALKING
+  },
+  {
+    EL_SPEED_PILL, FALSE,                      ACTION_COLLECTING,
+    SND_SPEED_PILL_COLLECTING
+  },
+  {
+    EL_DYNABOMB_INCREASE_NUMBER, FALSE,                ACTION_COLLECTING,
+    SND_DYNABOMB_INCREASE_NUMBER_COLLECTING
+  },
+  {
+    EL_DYNABOMB_INCREASE_SIZE, FALSE,          ACTION_COLLECTING,
+    SND_DYNABOMB_INCREASE_SIZE_COLLECTING
+  },
+  {
+    EL_DYNABOMB_INCREASE_POWER, FALSE,         ACTION_COLLECTING,
+    SND_DYNABOMB_INCREASE_POWER_COLLECTING
+  },
+  {
+    EL_DYNABOMB_INCREASE_NUMBER, TRUE,         ACTION_DROPPING,
+    SND_CLASS_DYNABOMB_DROPPING
+  },
+  {
+    EL_DYNABOMB_INCREASE_NUMBER, TRUE,         ACTION_ACTIVE,
+    SND_CLASS_DYNABOMB_ACTIVE
+  },
+  {
+    EL_SATELLITE, FALSE,                       ACTION_MOVING,
+    SND_SATELLITE_MOVING
+  },
+  {
+    EL_SATELLITE, FALSE,                       ACTION_WAITING,
+    SND_SATELLITE_WAITING
+  },
+  {
+    EL_SATELLITE, FALSE,                       ACTION_PUSHING,
+    SND_SATELLITE_PUSHING
+  },
+  {
+    EL_LAMP, FALSE,                            ACTION_ACTIVATING,
+    SND_LAMP_ACTIVATING
+  },
+  {
+    EL_LAMP, FALSE,                            ACTION_DEACTIVATING,
+    SND_LAMP_DEACTIVATING
+  },
+  {
+    EL_TIME_ORB_FULL, FALSE,                   ACTION_COLLECTING,
+    SND_TIME_ORB_FULL_COLLECTING
+  },
+  {
+    EL_TIME_ORB_FULL, FALSE,                   ACTION_IMPACT,
+    SND_TIME_ORB_FULL_IMPACT
+  },
+  {
+    EL_TIME_ORB_EMPTY, FALSE,                  ACTION_PUSHING,
+    SND_TIME_ORB_EMPTY_PUSHING
+  },
+  {
+    EL_TIME_ORB_EMPTY, FALSE,                  ACTION_IMPACT,
+    SND_TIME_ORB_EMPTY_IMPACT
+  },
+  {
+    EL_GAME_OF_LIFE, FALSE,                    ACTION_WAITING,
+    SND_GAME_OF_LIFE_WAITING
+  },
+  {
+    EL_GAME_OF_LIFE, FALSE,                    ACTION_GROWING,
+    SND_GAME_OF_LIFE_GROWING
+  },
+  {
+    EL_BIOMAZE, FALSE,                         ACTION_WAITING,
+    SND_BIOMAZE_WAITING
+  },
+  {
+    EL_BIOMAZE, FALSE,                         ACTION_GROWING,
+    SND_BIOMAZE_GROWING
+  },
+  {
+    EL_PACMAN, FALSE,                          ACTION_MOVING,
+    SND_PACMAN_MOVING
+  },
+  {
+    EL_PACMAN, FALSE,                          ACTION_WAITING,
+    SND_PACMAN_WAITING
+  },
+  {
+    EL_PACMAN, FALSE,                          ACTION_DIGGING,
+    SND_PACMAN_DIGGING
+  },
+  {
+    EL_DARK_YAMYAM, FALSE,                     ACTION_MOVING,
+    SND_DARK_YAMYAM_MOVING
+  },
+  {
+    EL_DARK_YAMYAM, FALSE,                     ACTION_WAITING,
+    SND_DARK_YAMYAM_WAITING
+  },
+  {
+    EL_DARK_YAMYAM, FALSE,                     ACTION_DIGGING,
+    SND_DARK_YAMYAM_DIGGING
+  },
+  {
+    EL_PENGUIN, FALSE,                         ACTION_MOVING,
+    SND_PENGUIN_MOVING
+  },
+  {
+    EL_PENGUIN, FALSE,                         ACTION_WAITING,
+    SND_PENGUIN_WAITING
+  },
+  {
+    EL_PIG, FALSE,                             ACTION_MOVING,
+    SND_PIG_MOVING
+  },
+  {
+    EL_PIG, FALSE,                             ACTION_WAITING,
+    SND_PIG_WAITING
+  },
+  {
+    EL_PIG, FALSE,                             ACTION_DIGGING,
+    SND_PIG_DIGGING
+  },
+  {
+    EL_DRAGON, FALSE,                          ACTION_MOVING,
+    SND_DRAGON_MOVING
+  },
+  {
+    EL_DRAGON, FALSE,                          ACTION_WAITING,
+    SND_DRAGON_WAITING
+  },
+  {
+    EL_DRAGON, FALSE,                          ACTION_ATTACKING,
+    SND_DRAGON_ATTACKING
+  },
+  {
+    -1, -1,                                    -1,
+    -1
+  },
+};
+
+#endif /* CONF_E2S_C */
diff --git a/src/conf_esg.c b/src/conf_esg.c
new file mode 100644 (file)
index 0000000..b2180fb
--- /dev/null
@@ -0,0 +1,748 @@
+/***********************************************************
+* Rocks'n'Diamonds -- McDuffin Strikes Back!               *
+*----------------------------------------------------------*
+* (c) 1995-2002 Artsoft Entertainment                      *
+*               Holger Schemel                             *
+*               Detmolder Strasse 189                      *
+*               33604 Bielefeld                            *
+*               Germany                                    *
+*               e-mail: info@artsoft.org                   *
+*----------------------------------------------------------*
+* conf_esg.c                                               *
+***********************************************************/
+
+/* ----- this file was automatically generated -- do not edit by hand ----- */
+
+#ifndef CONF_ESG_C
+#define CONF_ESG_C
+
+/* values for element/graphics mapping configuration (special) */
+
+static struct
+{
+  int element;
+  int special;
+
+  int graphic;
+}
+element_to_special_graphic[] =
+{
+  {
+    EL_BD_WALL,                                        GFX_SPECIAL_ARG_EDITOR,
+    IMG_BD_WALL_EDITOR
+  },
+  {
+    EL_BD_ROCK,                                        GFX_SPECIAL_ARG_EDITOR,
+    IMG_BD_ROCK_EDITOR
+  },
+  {
+    EL_BD_AMOEBA,                              GFX_SPECIAL_ARG_EDITOR,
+    IMG_BD_AMOEBA_EDITOR
+  },
+  {
+    EL_SP_INFOTRON,                            GFX_SPECIAL_ARG_EDITOR,
+    IMG_SP_INFOTRON_EDITOR
+  },
+  {
+    EL_SP_ELECTRON,                            GFX_SPECIAL_ARG_EDITOR,
+    IMG_SP_ELECTRON_EDITOR
+  },
+  {
+    EL_SP_TERMINAL,                            GFX_SPECIAL_ARG_EDITOR,
+    IMG_SP_TERMINAL_EDITOR
+  },
+  {
+    EL_SP_BUGGY_BASE,                          GFX_SPECIAL_ARG_EDITOR,
+    IMG_SP_BUGGY_BASE_EDITOR
+  },
+  {
+    EL_SOKOBAN_OBJECT,                         GFX_SPECIAL_ARG_EDITOR,
+    IMG_SOKOBAN_OBJECT_EDITOR
+  },
+  {
+    EL_DYNAMITE,                               GFX_SPECIAL_ARG_EDITOR,
+    IMG_DYNAMITE_EDITOR
+  },
+  {
+    EL_DYNAMITE_ACTIVE,                                GFX_SPECIAL_ARG_EDITOR,
+    IMG_DYNAMITE_ACTIVE_EDITOR
+  },
+  {
+    EL_QUICKSAND_FULL,                         GFX_SPECIAL_ARG_EDITOR,
+    IMG_QUICKSAND_FULL_EDITOR
+  },
+  {
+    EL_AMOEBA_WET,                             GFX_SPECIAL_ARG_EDITOR,
+    IMG_AMOEBA_WET_EDITOR
+  },
+  {
+    EL_AMOEBA_FULL,                            GFX_SPECIAL_ARG_EDITOR,
+    IMG_AMOEBA_FULL_EDITOR
+  },
+  {
+    EL_AMOEBA_DEAD,                            GFX_SPECIAL_ARG_EDITOR,
+    IMG_AMOEBA_DEAD_EDITOR
+  },
+  {
+    EL_EM_GATE_1_GRAY,                         GFX_SPECIAL_ARG_EDITOR,
+    IMG_EM_GATE_1_GRAY_EDITOR
+  },
+  {
+    EL_EM_GATE_2_GRAY,                         GFX_SPECIAL_ARG_EDITOR,
+    IMG_EM_GATE_2_GRAY_EDITOR
+  },
+  {
+    EL_EM_GATE_3_GRAY,                         GFX_SPECIAL_ARG_EDITOR,
+    IMG_EM_GATE_3_GRAY_EDITOR
+  },
+  {
+    EL_EM_GATE_4_GRAY,                         GFX_SPECIAL_ARG_EDITOR,
+    IMG_EM_GATE_4_GRAY_EDITOR
+  },
+  {
+    EL_INVISIBLE_STEELWALL,                    GFX_SPECIAL_ARG_EDITOR,
+    IMG_INVISIBLE_STEELWALL_EDITOR
+  },
+  {
+    EL_INVISIBLE_WALL,                         GFX_SPECIAL_ARG_EDITOR,
+    IMG_INVISIBLE_WALL_EDITOR
+  },
+  {
+    EL_INVISIBLE_SAND,                         GFX_SPECIAL_ARG_EDITOR,
+    IMG_INVISIBLE_SAND_EDITOR
+  },
+  {
+    EL_KEY_1,                                  GFX_SPECIAL_ARG_EDITOR,
+    IMG_KEY_1_EDITOR
+  },
+  {
+    EL_KEY_2,                                  GFX_SPECIAL_ARG_EDITOR,
+    IMG_KEY_2_EDITOR
+  },
+  {
+    EL_KEY_3,                                  GFX_SPECIAL_ARG_EDITOR,
+    IMG_KEY_3_EDITOR
+  },
+  {
+    EL_KEY_4,                                  GFX_SPECIAL_ARG_EDITOR,
+    IMG_KEY_4_EDITOR
+  },
+  {
+    EL_GATE_1_GRAY,                            GFX_SPECIAL_ARG_EDITOR,
+    IMG_GATE_1_GRAY_EDITOR
+  },
+  {
+    EL_GATE_2_GRAY,                            GFX_SPECIAL_ARG_EDITOR,
+    IMG_GATE_2_GRAY_EDITOR
+  },
+  {
+    EL_GATE_3_GRAY,                            GFX_SPECIAL_ARG_EDITOR,
+    IMG_GATE_3_GRAY_EDITOR
+  },
+  {
+    EL_GATE_4_GRAY,                            GFX_SPECIAL_ARG_EDITOR,
+    IMG_GATE_4_GRAY_EDITOR
+  },
+  {
+    EL_LAMP,                                   GFX_SPECIAL_ARG_EDITOR,
+    IMG_LAMP_EDITOR
+  },
+  {
+    EL_EXPANDABLE_WALL_HORIZONTAL,             GFX_SPECIAL_ARG_EDITOR,
+    IMG_EXPANDABLE_WALL_HORIZONTAL_EDITOR
+  },
+  {
+    EL_EXPANDABLE_WALL_VERTICAL,               GFX_SPECIAL_ARG_EDITOR,
+    IMG_EXPANDABLE_WALL_VERTICAL_EDITOR
+  },
+  {
+    EL_EXPANDABLE_WALL_ANY,                    GFX_SPECIAL_ARG_EDITOR,
+    IMG_EXPANDABLE_WALL_ANY_EDITOR
+  },
+  {
+    EL_PENGUIN,                                        GFX_SPECIAL_ARG_EDITOR,
+    IMG_PENGUIN_EDITOR
+  },
+  {
+    EL_PLAYER_1,                               GFX_SPECIAL_ARG_EDITOR,
+    IMG_PLAYER_1_EDITOR
+  },
+  {
+    EL_PLAYER_2,                               GFX_SPECIAL_ARG_EDITOR,
+    IMG_PLAYER_2_EDITOR
+  },
+  {
+    EL_PLAYER_3,                               GFX_SPECIAL_ARG_EDITOR,
+    IMG_PLAYER_3_EDITOR
+  },
+  {
+    EL_PLAYER_4,                               GFX_SPECIAL_ARG_EDITOR,
+    IMG_PLAYER_4_EDITOR
+  },
+  {
+    EL_STEELWALL_TOPLEFT,                      GFX_SPECIAL_ARG_EDITOR,
+    IMG_STEELWALL_TOPLEFT_EDITOR
+  },
+  {
+    EL_STEELWALL_TOPRIGHT,                     GFX_SPECIAL_ARG_EDITOR,
+    IMG_STEELWALL_TOPRIGHT_EDITOR
+  },
+  {
+    EL_STEELWALL_BOTTOMLEFT,                   GFX_SPECIAL_ARG_EDITOR,
+    IMG_STEELWALL_BOTTOMLEFT_EDITOR
+  },
+  {
+    EL_STEELWALL_BOTTOMRIGHT,                  GFX_SPECIAL_ARG_EDITOR,
+    IMG_STEELWALL_BOTTOMRIGHT_EDITOR
+  },
+  {
+    EL_STEELWALL_HORIZONTAL,                   GFX_SPECIAL_ARG_EDITOR,
+    IMG_STEELWALL_HORIZONTAL_EDITOR
+  },
+  {
+    EL_STEELWALL_VERTICAL,                     GFX_SPECIAL_ARG_EDITOR,
+    IMG_STEELWALL_VERTICAL_EDITOR
+  },
+  {
+    EL_INVISIBLE_STEELWALL_TOPLEFT,            GFX_SPECIAL_ARG_EDITOR,
+    IMG_INVISIBLE_STEELWALL_TOPLEFT_EDITOR
+  },
+  {
+    EL_INVISIBLE_STEELWALL_TOPRIGHT,           GFX_SPECIAL_ARG_EDITOR,
+    IMG_INVISIBLE_STEELWALL_TOPRIGHT_EDITOR
+  },
+  {
+    EL_INVISIBLE_STEELWALL_BOTTOMLEFT,         GFX_SPECIAL_ARG_EDITOR,
+    IMG_INVISIBLE_STEELWALL_BOTTOMLEFT_EDITOR
+  },
+  {
+    EL_INVISIBLE_STEELWALL_BOTTOMRIGHT,                GFX_SPECIAL_ARG_EDITOR,
+    IMG_INVISIBLE_STEELWALL_BOTTOMRIGHT_EDITOR
+  },
+  {
+    EL_INVISIBLE_STEELWALL_HORIZONTAL,         GFX_SPECIAL_ARG_EDITOR,
+    IMG_INVISIBLE_STEELWALL_HORIZONTAL_EDITOR
+  },
+  {
+    EL_INVISIBLE_STEELWALL_VERTICAL,           GFX_SPECIAL_ARG_EDITOR,
+    IMG_INVISIBLE_STEELWALL_VERTICAL_EDITOR
+  },
+  {
+    EL_CUSTOM_1,                               GFX_SPECIAL_ARG_EDITOR,
+    IMG_CUSTOM_1_EDITOR
+  },
+  {
+    EL_CUSTOM_2,                               GFX_SPECIAL_ARG_EDITOR,
+    IMG_CUSTOM_2_EDITOR
+  },
+  {
+    EL_CUSTOM_3,                               GFX_SPECIAL_ARG_EDITOR,
+    IMG_CUSTOM_3_EDITOR
+  },
+  {
+    EL_CUSTOM_4,                               GFX_SPECIAL_ARG_EDITOR,
+    IMG_CUSTOM_4_EDITOR
+  },
+  {
+    EL_CUSTOM_5,                               GFX_SPECIAL_ARG_EDITOR,
+    IMG_CUSTOM_5_EDITOR
+  },
+  {
+    EL_CUSTOM_6,                               GFX_SPECIAL_ARG_EDITOR,
+    IMG_CUSTOM_6_EDITOR
+  },
+  {
+    EL_CUSTOM_7,                               GFX_SPECIAL_ARG_EDITOR,
+    IMG_CUSTOM_7_EDITOR
+  },
+  {
+    EL_CUSTOM_8,                               GFX_SPECIAL_ARG_EDITOR,
+    IMG_CUSTOM_8_EDITOR
+  },
+  {
+    EL_CUSTOM_9,                               GFX_SPECIAL_ARG_EDITOR,
+    IMG_CUSTOM_9_EDITOR
+  },
+  {
+    EL_CUSTOM_10,                              GFX_SPECIAL_ARG_EDITOR,
+    IMG_CUSTOM_10_EDITOR
+  },
+  {
+    EL_CUSTOM_11,                              GFX_SPECIAL_ARG_EDITOR,
+    IMG_CUSTOM_11_EDITOR
+  },
+  {
+    EL_CUSTOM_12,                              GFX_SPECIAL_ARG_EDITOR,
+    IMG_CUSTOM_12_EDITOR
+  },
+  {
+    EL_CUSTOM_13,                              GFX_SPECIAL_ARG_EDITOR,
+    IMG_CUSTOM_13_EDITOR
+  },
+  {
+    EL_CUSTOM_14,                              GFX_SPECIAL_ARG_EDITOR,
+    IMG_CUSTOM_14_EDITOR
+  },
+  {
+    EL_CUSTOM_15,                              GFX_SPECIAL_ARG_EDITOR,
+    IMG_CUSTOM_15_EDITOR
+  },
+  {
+    EL_CUSTOM_16,                              GFX_SPECIAL_ARG_EDITOR,
+    IMG_CUSTOM_16_EDITOR
+  },
+  {
+    EL_CUSTOM_17,                              GFX_SPECIAL_ARG_EDITOR,
+    IMG_CUSTOM_17_EDITOR
+  },
+  {
+    EL_CUSTOM_18,                              GFX_SPECIAL_ARG_EDITOR,
+    IMG_CUSTOM_18_EDITOR
+  },
+  {
+    EL_CUSTOM_19,                              GFX_SPECIAL_ARG_EDITOR,
+    IMG_CUSTOM_19_EDITOR
+  },
+  {
+    EL_CUSTOM_20,                              GFX_SPECIAL_ARG_EDITOR,
+    IMG_CUSTOM_20_EDITOR
+  },
+  {
+    EL_CUSTOM_21,                              GFX_SPECIAL_ARG_EDITOR,
+    IMG_CUSTOM_21_EDITOR
+  },
+  {
+    EL_CUSTOM_22,                              GFX_SPECIAL_ARG_EDITOR,
+    IMG_CUSTOM_22_EDITOR
+  },
+  {
+    EL_CUSTOM_23,                              GFX_SPECIAL_ARG_EDITOR,
+    IMG_CUSTOM_23_EDITOR
+  },
+  {
+    EL_CUSTOM_24,                              GFX_SPECIAL_ARG_EDITOR,
+    IMG_CUSTOM_24_EDITOR
+  },
+  {
+    EL_CUSTOM_25,                              GFX_SPECIAL_ARG_EDITOR,
+    IMG_CUSTOM_25_EDITOR
+  },
+  {
+    EL_CUSTOM_26,                              GFX_SPECIAL_ARG_EDITOR,
+    IMG_CUSTOM_26_EDITOR
+  },
+  {
+    EL_CUSTOM_27,                              GFX_SPECIAL_ARG_EDITOR,
+    IMG_CUSTOM_27_EDITOR
+  },
+  {
+    EL_CUSTOM_28,                              GFX_SPECIAL_ARG_EDITOR,
+    IMG_CUSTOM_28_EDITOR
+  },
+  {
+    EL_CUSTOM_29,                              GFX_SPECIAL_ARG_EDITOR,
+    IMG_CUSTOM_29_EDITOR
+  },
+  {
+    EL_CUSTOM_30,                              GFX_SPECIAL_ARG_EDITOR,
+    IMG_CUSTOM_30_EDITOR
+  },
+  {
+    EL_CUSTOM_31,                              GFX_SPECIAL_ARG_EDITOR,
+    IMG_CUSTOM_31_EDITOR
+  },
+  {
+    EL_CUSTOM_32,                              GFX_SPECIAL_ARG_EDITOR,
+    IMG_CUSTOM_32_EDITOR
+  },
+  {
+    EL_CUSTOM_33,                              GFX_SPECIAL_ARG_EDITOR,
+    IMG_CUSTOM_33_EDITOR
+  },
+  {
+    EL_CUSTOM_34,                              GFX_SPECIAL_ARG_EDITOR,
+    IMG_CUSTOM_34_EDITOR
+  },
+  {
+    EL_CUSTOM_35,                              GFX_SPECIAL_ARG_EDITOR,
+    IMG_CUSTOM_35_EDITOR
+  },
+  {
+    EL_CUSTOM_36,                              GFX_SPECIAL_ARG_EDITOR,
+    IMG_CUSTOM_36_EDITOR
+  },
+  {
+    EL_CUSTOM_37,                              GFX_SPECIAL_ARG_EDITOR,
+    IMG_CUSTOM_37_EDITOR
+  },
+  {
+    EL_CUSTOM_38,                              GFX_SPECIAL_ARG_EDITOR,
+    IMG_CUSTOM_38_EDITOR
+  },
+  {
+    EL_CUSTOM_39,                              GFX_SPECIAL_ARG_EDITOR,
+    IMG_CUSTOM_39_EDITOR
+  },
+  {
+    EL_CUSTOM_40,                              GFX_SPECIAL_ARG_EDITOR,
+    IMG_CUSTOM_40_EDITOR
+  },
+  {
+    EL_CUSTOM_41,                              GFX_SPECIAL_ARG_EDITOR,
+    IMG_CUSTOM_41_EDITOR
+  },
+  {
+    EL_CUSTOM_42,                              GFX_SPECIAL_ARG_EDITOR,
+    IMG_CUSTOM_42_EDITOR
+  },
+  {
+    EL_CUSTOM_43,                              GFX_SPECIAL_ARG_EDITOR,
+    IMG_CUSTOM_43_EDITOR
+  },
+  {
+    EL_CUSTOM_44,                              GFX_SPECIAL_ARG_EDITOR,
+    IMG_CUSTOM_44_EDITOR
+  },
+  {
+    EL_CUSTOM_45,                              GFX_SPECIAL_ARG_EDITOR,
+    IMG_CUSTOM_45_EDITOR
+  },
+  {
+    EL_CUSTOM_46,                              GFX_SPECIAL_ARG_EDITOR,
+    IMG_CUSTOM_46_EDITOR
+  },
+  {
+    EL_CUSTOM_47,                              GFX_SPECIAL_ARG_EDITOR,
+    IMG_CUSTOM_47_EDITOR
+  },
+  {
+    EL_CUSTOM_48,                              GFX_SPECIAL_ARG_EDITOR,
+    IMG_CUSTOM_48_EDITOR
+  },
+  {
+    EL_CUSTOM_49,                              GFX_SPECIAL_ARG_EDITOR,
+    IMG_CUSTOM_49_EDITOR
+  },
+  {
+    EL_CUSTOM_50,                              GFX_SPECIAL_ARG_EDITOR,
+    IMG_CUSTOM_50_EDITOR
+  },
+  {
+    EL_CUSTOM_51,                              GFX_SPECIAL_ARG_EDITOR,
+    IMG_CUSTOM_51_EDITOR
+  },
+  {
+    EL_CUSTOM_52,                              GFX_SPECIAL_ARG_EDITOR,
+    IMG_CUSTOM_52_EDITOR
+  },
+  {
+    EL_CUSTOM_53,                              GFX_SPECIAL_ARG_EDITOR,
+    IMG_CUSTOM_53_EDITOR
+  },
+  {
+    EL_CUSTOM_54,                              GFX_SPECIAL_ARG_EDITOR,
+    IMG_CUSTOM_54_EDITOR
+  },
+  {
+    EL_CUSTOM_55,                              GFX_SPECIAL_ARG_EDITOR,
+    IMG_CUSTOM_55_EDITOR
+  },
+  {
+    EL_CUSTOM_56,                              GFX_SPECIAL_ARG_EDITOR,
+    IMG_CUSTOM_56_EDITOR
+  },
+  {
+    EL_CUSTOM_57,                              GFX_SPECIAL_ARG_EDITOR,
+    IMG_CUSTOM_57_EDITOR
+  },
+  {
+    EL_CUSTOM_58,                              GFX_SPECIAL_ARG_EDITOR,
+    IMG_CUSTOM_58_EDITOR
+  },
+  {
+    EL_CUSTOM_59,                              GFX_SPECIAL_ARG_EDITOR,
+    IMG_CUSTOM_59_EDITOR
+  },
+  {
+    EL_CUSTOM_60,                              GFX_SPECIAL_ARG_EDITOR,
+    IMG_CUSTOM_60_EDITOR
+  },
+  {
+    EL_CUSTOM_61,                              GFX_SPECIAL_ARG_EDITOR,
+    IMG_CUSTOM_61_EDITOR
+  },
+  {
+    EL_CUSTOM_62,                              GFX_SPECIAL_ARG_EDITOR,
+    IMG_CUSTOM_62_EDITOR
+  },
+  {
+    EL_CUSTOM_63,                              GFX_SPECIAL_ARG_EDITOR,
+    IMG_CUSTOM_63_EDITOR
+  },
+  {
+    EL_CUSTOM_64,                              GFX_SPECIAL_ARG_EDITOR,
+    IMG_CUSTOM_64_EDITOR
+  },
+  {
+    EL_CUSTOM_65,                              GFX_SPECIAL_ARG_EDITOR,
+    IMG_CUSTOM_65_EDITOR
+  },
+  {
+    EL_CUSTOM_66,                              GFX_SPECIAL_ARG_EDITOR,
+    IMG_CUSTOM_66_EDITOR
+  },
+  {
+    EL_CUSTOM_67,                              GFX_SPECIAL_ARG_EDITOR,
+    IMG_CUSTOM_67_EDITOR
+  },
+  {
+    EL_CUSTOM_68,                              GFX_SPECIAL_ARG_EDITOR,
+    IMG_CUSTOM_68_EDITOR
+  },
+  {
+    EL_CUSTOM_69,                              GFX_SPECIAL_ARG_EDITOR,
+    IMG_CUSTOM_69_EDITOR
+  },
+  {
+    EL_CUSTOM_70,                              GFX_SPECIAL_ARG_EDITOR,
+    IMG_CUSTOM_70_EDITOR
+  },
+  {
+    EL_CUSTOM_71,                              GFX_SPECIAL_ARG_EDITOR,
+    IMG_CUSTOM_71_EDITOR
+  },
+  {
+    EL_CUSTOM_72,                              GFX_SPECIAL_ARG_EDITOR,
+    IMG_CUSTOM_72_EDITOR
+  },
+  {
+    EL_CUSTOM_73,                              GFX_SPECIAL_ARG_EDITOR,
+    IMG_CUSTOM_73_EDITOR
+  },
+  {
+    EL_CUSTOM_74,                              GFX_SPECIAL_ARG_EDITOR,
+    IMG_CUSTOM_74_EDITOR
+  },
+  {
+    EL_CUSTOM_75,                              GFX_SPECIAL_ARG_EDITOR,
+    IMG_CUSTOM_75_EDITOR
+  },
+  {
+    EL_CUSTOM_76,                              GFX_SPECIAL_ARG_EDITOR,
+    IMG_CUSTOM_76_EDITOR
+  },
+  {
+    EL_CUSTOM_77,                              GFX_SPECIAL_ARG_EDITOR,
+    IMG_CUSTOM_77_EDITOR
+  },
+  {
+    EL_CUSTOM_78,                              GFX_SPECIAL_ARG_EDITOR,
+    IMG_CUSTOM_78_EDITOR
+  },
+  {
+    EL_CUSTOM_79,                              GFX_SPECIAL_ARG_EDITOR,
+    IMG_CUSTOM_79_EDITOR
+  },
+  {
+    EL_CUSTOM_80,                              GFX_SPECIAL_ARG_EDITOR,
+    IMG_CUSTOM_80_EDITOR
+  },
+  {
+    EL_CUSTOM_81,                              GFX_SPECIAL_ARG_EDITOR,
+    IMG_CUSTOM_81_EDITOR
+  },
+  {
+    EL_CUSTOM_82,                              GFX_SPECIAL_ARG_EDITOR,
+    IMG_CUSTOM_82_EDITOR
+  },
+  {
+    EL_CUSTOM_83,                              GFX_SPECIAL_ARG_EDITOR,
+    IMG_CUSTOM_83_EDITOR
+  },
+  {
+    EL_CUSTOM_84,                              GFX_SPECIAL_ARG_EDITOR,
+    IMG_CUSTOM_84_EDITOR
+  },
+  {
+    EL_CUSTOM_85,                              GFX_SPECIAL_ARG_EDITOR,
+    IMG_CUSTOM_85_EDITOR
+  },
+  {
+    EL_CUSTOM_86,                              GFX_SPECIAL_ARG_EDITOR,
+    IMG_CUSTOM_86_EDITOR
+  },
+  {
+    EL_CUSTOM_87,                              GFX_SPECIAL_ARG_EDITOR,
+    IMG_CUSTOM_87_EDITOR
+  },
+  {
+    EL_CUSTOM_88,                              GFX_SPECIAL_ARG_EDITOR,
+    IMG_CUSTOM_88_EDITOR
+  },
+  {
+    EL_CUSTOM_89,                              GFX_SPECIAL_ARG_EDITOR,
+    IMG_CUSTOM_89_EDITOR
+  },
+  {
+    EL_CUSTOM_90,                              GFX_SPECIAL_ARG_EDITOR,
+    IMG_CUSTOM_90_EDITOR
+  },
+  {
+    EL_CUSTOM_91,                              GFX_SPECIAL_ARG_EDITOR,
+    IMG_CUSTOM_91_EDITOR
+  },
+  {
+    EL_CUSTOM_92,                              GFX_SPECIAL_ARG_EDITOR,
+    IMG_CUSTOM_92_EDITOR
+  },
+  {
+    EL_CUSTOM_93,                              GFX_SPECIAL_ARG_EDITOR,
+    IMG_CUSTOM_93_EDITOR
+  },
+  {
+    EL_CUSTOM_94,                              GFX_SPECIAL_ARG_EDITOR,
+    IMG_CUSTOM_94_EDITOR
+  },
+  {
+    EL_CUSTOM_95,                              GFX_SPECIAL_ARG_EDITOR,
+    IMG_CUSTOM_95_EDITOR
+  },
+  {
+    EL_CUSTOM_96,                              GFX_SPECIAL_ARG_EDITOR,
+    IMG_CUSTOM_96_EDITOR
+  },
+  {
+    EL_CUSTOM_97,                              GFX_SPECIAL_ARG_EDITOR,
+    IMG_CUSTOM_97_EDITOR
+  },
+  {
+    EL_CUSTOM_98,                              GFX_SPECIAL_ARG_EDITOR,
+    IMG_CUSTOM_98_EDITOR
+  },
+  {
+    EL_CUSTOM_99,                              GFX_SPECIAL_ARG_EDITOR,
+    IMG_CUSTOM_99_EDITOR
+  },
+  {
+    EL_CUSTOM_100,                             GFX_SPECIAL_ARG_EDITOR,
+    IMG_CUSTOM_100_EDITOR
+  },
+  {
+    EL_CUSTOM_101,                             GFX_SPECIAL_ARG_EDITOR,
+    IMG_CUSTOM_101_EDITOR
+  },
+  {
+    EL_CUSTOM_102,                             GFX_SPECIAL_ARG_EDITOR,
+    IMG_CUSTOM_102_EDITOR
+  },
+  {
+    EL_CUSTOM_103,                             GFX_SPECIAL_ARG_EDITOR,
+    IMG_CUSTOM_103_EDITOR
+  },
+  {
+    EL_CUSTOM_104,                             GFX_SPECIAL_ARG_EDITOR,
+    IMG_CUSTOM_104_EDITOR
+  },
+  {
+    EL_CUSTOM_105,                             GFX_SPECIAL_ARG_EDITOR,
+    IMG_CUSTOM_105_EDITOR
+  },
+  {
+    EL_CUSTOM_106,                             GFX_SPECIAL_ARG_EDITOR,
+    IMG_CUSTOM_106_EDITOR
+  },
+  {
+    EL_CUSTOM_107,                             GFX_SPECIAL_ARG_EDITOR,
+    IMG_CUSTOM_107_EDITOR
+  },
+  {
+    EL_CUSTOM_108,                             GFX_SPECIAL_ARG_EDITOR,
+    IMG_CUSTOM_108_EDITOR
+  },
+  {
+    EL_CUSTOM_109,                             GFX_SPECIAL_ARG_EDITOR,
+    IMG_CUSTOM_109_EDITOR
+  },
+  {
+    EL_CUSTOM_110,                             GFX_SPECIAL_ARG_EDITOR,
+    IMG_CUSTOM_110_EDITOR
+  },
+  {
+    EL_CUSTOM_111,                             GFX_SPECIAL_ARG_EDITOR,
+    IMG_CUSTOM_111_EDITOR
+  },
+  {
+    EL_CUSTOM_112,                             GFX_SPECIAL_ARG_EDITOR,
+    IMG_CUSTOM_112_EDITOR
+  },
+  {
+    EL_CUSTOM_113,                             GFX_SPECIAL_ARG_EDITOR,
+    IMG_CUSTOM_113_EDITOR
+  },
+  {
+    EL_CUSTOM_114,                             GFX_SPECIAL_ARG_EDITOR,
+    IMG_CUSTOM_114_EDITOR
+  },
+  {
+    EL_CUSTOM_115,                             GFX_SPECIAL_ARG_EDITOR,
+    IMG_CUSTOM_115_EDITOR
+  },
+  {
+    EL_CUSTOM_116,                             GFX_SPECIAL_ARG_EDITOR,
+    IMG_CUSTOM_116_EDITOR
+  },
+  {
+    EL_CUSTOM_117,                             GFX_SPECIAL_ARG_EDITOR,
+    IMG_CUSTOM_117_EDITOR
+  },
+  {
+    EL_CUSTOM_118,                             GFX_SPECIAL_ARG_EDITOR,
+    IMG_CUSTOM_118_EDITOR
+  },
+  {
+    EL_CUSTOM_119,                             GFX_SPECIAL_ARG_EDITOR,
+    IMG_CUSTOM_119_EDITOR
+  },
+  {
+    EL_CUSTOM_120,                             GFX_SPECIAL_ARG_EDITOR,
+    IMG_CUSTOM_120_EDITOR
+  },
+  {
+    EL_CUSTOM_121,                             GFX_SPECIAL_ARG_EDITOR,
+    IMG_CUSTOM_121_EDITOR
+  },
+  {
+    EL_CUSTOM_122,                             GFX_SPECIAL_ARG_EDITOR,
+    IMG_CUSTOM_122_EDITOR
+  },
+  {
+    EL_CUSTOM_123,                             GFX_SPECIAL_ARG_EDITOR,
+    IMG_CUSTOM_123_EDITOR
+  },
+  {
+    EL_CUSTOM_124,                             GFX_SPECIAL_ARG_EDITOR,
+    IMG_CUSTOM_124_EDITOR
+  },
+  {
+    EL_CUSTOM_125,                             GFX_SPECIAL_ARG_EDITOR,
+    IMG_CUSTOM_125_EDITOR
+  },
+  {
+    EL_CUSTOM_126,                             GFX_SPECIAL_ARG_EDITOR,
+    IMG_CUSTOM_126_EDITOR
+  },
+  {
+    EL_CUSTOM_127,                             GFX_SPECIAL_ARG_EDITOR,
+    IMG_CUSTOM_127_EDITOR
+  },
+  {
+    EL_CUSTOM_128,                             GFX_SPECIAL_ARG_EDITOR,
+    IMG_CUSTOM_128_EDITOR
+  },
+  {
+    -1,                                                -1,
+    -1
+  },
+};
+
+#endif /* CONF_ESG_C */
diff --git a/src/conf_fnt.c b/src/conf_fnt.c
new file mode 100644 (file)
index 0000000..0a191dd
--- /dev/null
@@ -0,0 +1,208 @@
+/***********************************************************
+* Rocks'n'Diamonds -- McDuffin Strikes Back!               *
+*----------------------------------------------------------*
+* (c) 1995-2002 Artsoft Entertainment                      *
+*               Holger Schemel                             *
+*               Detmolder Strasse 189                      *
+*               33604 Bielefeld                            *
+*               Germany                                    *
+*               e-mail: info@artsoft.org                   *
+*----------------------------------------------------------*
+* conf_fnt.c                                               *
+***********************************************************/
+
+/* ----- this file was automatically generated -- do not edit by hand ----- */
+
+#ifndef CONF_FNT_C
+#define CONF_FNT_C
+
+/* values for font/graphics mapping configuration */
+
+static struct
+{
+  int font_nr;
+  int special;
+
+  int graphic;
+}
+font_to_graphic[] =
+{
+  {
+    FONT_INITIAL_1,                            -1,
+    IMG_FONT_INITIAL_1
+  },
+  {
+    FONT_INITIAL_2,                            -1,
+    IMG_FONT_INITIAL_2
+  },
+  {
+    FONT_INITIAL_3,                            -1,
+    IMG_FONT_INITIAL_3
+  },
+  {
+    FONT_INITIAL_4,                            -1,
+    IMG_FONT_INITIAL_4
+  },
+  {
+    FONT_TITLE_1,                              -1,
+    IMG_FONT_TITLE_1
+  },
+  {
+    FONT_TITLE_1,                              GFX_SPECIAL_ARG_LEVELS,
+    IMG_FONT_TITLE_1_LEVELS
+  },
+  {
+    FONT_TITLE_2,                              -1,
+    IMG_FONT_TITLE_2
+  },
+  {
+    FONT_MENU_1,                               -1,
+    IMG_FONT_MENU_1
+  },
+  {
+    FONT_MENU_2,                               -1,
+    IMG_FONT_MENU_2
+  },
+  {
+    FONT_TEXT_1,                               -1,
+    IMG_FONT_TEXT_1
+  },
+  {
+    FONT_TEXT_1,                               GFX_SPECIAL_ARG_LEVELS,
+    IMG_FONT_TEXT_1_LEVELS
+  },
+  {
+    FONT_TEXT_1,                               GFX_SPECIAL_ARG_PREVIEW,
+    IMG_FONT_TEXT_1_PREVIEW
+  },
+  {
+    FONT_TEXT_1,                               GFX_SPECIAL_ARG_SCORES,
+    IMG_FONT_TEXT_1_SCORES
+  },
+  {
+    FONT_TEXT_1_ACTIVE,                                GFX_SPECIAL_ARG_SCORES,
+    IMG_FONT_TEXT_1_ACTIVE_SCORES
+  },
+  {
+    FONT_TEXT_2,                               -1,
+    IMG_FONT_TEXT_2
+  },
+  {
+    FONT_TEXT_2,                               GFX_SPECIAL_ARG_LEVELS,
+    IMG_FONT_TEXT_2_LEVELS
+  },
+  {
+    FONT_TEXT_2,                               GFX_SPECIAL_ARG_PREVIEW,
+    IMG_FONT_TEXT_2_PREVIEW
+  },
+  {
+    FONT_TEXT_2,                               GFX_SPECIAL_ARG_SCORES,
+    IMG_FONT_TEXT_2_SCORES
+  },
+  {
+    FONT_TEXT_2_ACTIVE,                                GFX_SPECIAL_ARG_SCORES,
+    IMG_FONT_TEXT_2_ACTIVE_SCORES
+  },
+  {
+    FONT_TEXT_3,                               -1,
+    IMG_FONT_TEXT_3
+  },
+  {
+    FONT_TEXT_3,                               GFX_SPECIAL_ARG_LEVELS,
+    IMG_FONT_TEXT_3_LEVELS
+  },
+  {
+    FONT_TEXT_3,                               GFX_SPECIAL_ARG_PREVIEW,
+    IMG_FONT_TEXT_3_PREVIEW
+  },
+  {
+    FONT_TEXT_3,                               GFX_SPECIAL_ARG_SCORES,
+    IMG_FONT_TEXT_3_SCORES
+  },
+  {
+    FONT_TEXT_3_ACTIVE,                                GFX_SPECIAL_ARG_SCORES,
+    IMG_FONT_TEXT_3_ACTIVE_SCORES
+  },
+  {
+    FONT_TEXT_4,                               -1,
+    IMG_FONT_TEXT_4
+  },
+  {
+    FONT_TEXT_4,                               GFX_SPECIAL_ARG_LEVELS,
+    IMG_FONT_TEXT_4_LEVELS
+  },
+  {
+    FONT_TEXT_4,                               GFX_SPECIAL_ARG_SCORES,
+    IMG_FONT_TEXT_4_SCORES
+  },
+  {
+    FONT_TEXT_4_ACTIVE,                                GFX_SPECIAL_ARG_SCORES,
+    IMG_FONT_TEXT_4_ACTIVE_SCORES
+  },
+  {
+    FONT_INPUT_1,                              -1,
+    IMG_FONT_INPUT_1
+  },
+  {
+    FONT_INPUT_1,                              GFX_SPECIAL_ARG_MAIN,
+    IMG_FONT_INPUT_1_MAIN
+  },
+  {
+    FONT_INPUT_1_ACTIVE,                       -1,
+    IMG_FONT_INPUT_1_ACTIVE
+  },
+  {
+    FONT_INPUT_1_ACTIVE,                       GFX_SPECIAL_ARG_MAIN,
+    IMG_FONT_INPUT_1_ACTIVE_MAIN
+  },
+  {
+    FONT_INPUT_1_ACTIVE,                       GFX_SPECIAL_ARG_SETUP,
+    IMG_FONT_INPUT_1_ACTIVE_SETUP
+  },
+  {
+    FONT_INPUT_2,                              -1,
+    IMG_FONT_INPUT_2
+  },
+  {
+    FONT_INPUT_2_ACTIVE,                       -1,
+    IMG_FONT_INPUT_2_ACTIVE
+  },
+  {
+    FONT_OPTION_OFF,                           -1,
+    IMG_FONT_OPTION_OFF
+  },
+  {
+    FONT_OPTION_ON,                            -1,
+    IMG_FONT_OPTION_ON
+  },
+  {
+    FONT_VALUE_1,                              -1,
+    IMG_FONT_VALUE_1
+  },
+  {
+    FONT_VALUE_2,                              -1,
+    IMG_FONT_VALUE_2
+  },
+  {
+    FONT_VALUE_OLD,                            -1,
+    IMG_FONT_VALUE_OLD
+  },
+  {
+    FONT_LEVEL_NUMBER,                         -1,
+    IMG_FONT_LEVEL_NUMBER
+  },
+  {
+    FONT_TAPE_RECORDER,                                -1,
+    IMG_FONT_TAPE_RECORDER
+  },
+  {
+    FONT_GAME_INFO,                            -1,
+    IMG_FONT_GAME_INFO
+  },
+  {
+    -1,                                                -1,
+    -1
+  },
+};
+
+#endif /* CONF_FNT_C */
diff --git a/src/conf_gfx.c b/src/conf_gfx.c
new file mode 100644 (file)
index 0000000..7b692bf
--- /dev/null
@@ -0,0 +1,3474 @@
+/***********************************************************
+* Rocks'n'Diamonds -- McDuffin Strikes Back!               *
+*----------------------------------------------------------*
+* (c) 1995-2002 Artsoft Entertainment                      *
+*               Holger Schemel                             *
+*               Detmolder Strasse 189                      *
+*               33604 Bielefeld                            *
+*               Germany                                    *
+*               e-mail: info@artsoft.org                   *
+*----------------------------------------------------------*
+* conf_gfx.c                                               *
+***********************************************************/
+
+#include "libgame/libgame.h"
+#include "main.h"
+
+
+/* List values that are not defined in the configuration file are set to
+   reliable default values. If that value is GFX_ARG_UNDEFINED, it will
+   be dynamically determined, using some of the other list values. */
+
+struct ConfigInfo 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 },
+  { ".offset",                         ARG_UNDEFINED,  TYPE_INTEGER },
+  { ".vertical",                       "false",        TYPE_BOOLEAN },
+  { ".xoffset",                                ARG_UNDEFINED,  TYPE_INTEGER },
+  { ".yoffset",                                ARG_UNDEFINED,  TYPE_INTEGER },
+  { ".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_TOKEN   },
+  { ".diggable_like",                  ARG_UNDEFINED,  TYPE_TOKEN   },
+  { ".step_offset",                    "4",            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 },
+  { ".name",                           ARG_UNDEFINED,  TYPE_STRING  },
+
+  { NULL,                              NULL,           0            }
+};
+
+struct ConfigInfo image_config[] =
+{
+  /* images for Boulder Dash style elements and actions */
+
+  { "bd_wall",                                 "RocksDC.pcx"           },
+  { "bd_wall.xpos",                            "12"                    },
+  { "bd_wall.ypos",                            "9"                     },
+  { "bd_wall.frames",                          "1"                     },
+  { "bd_wall.EDITOR",                          "RocksDC.pcx"           },
+  { "bd_wall.EDITOR.xpos",                     "14"                    },
+  { "bd_wall.EDITOR.ypos",                     "13"                    },
+
+  { "bd_rock",                                 "RocksDC.pcx"           },
+  { "bd_rock.xpos",                            "12"                    },
+  { "bd_rock.ypos",                            "10"                    },
+  { "bd_rock.frames",                          "1"                     },
+  { "bd_rock.EDITOR",                          "RocksDC.pcx"           },
+  { "bd_rock.EDITOR.xpos",                     "14"                    },
+  { "bd_rock.EDITOR.ypos",                     "14"                    },
+  { "bd_rock.moving.left",                     "RocksDC.pcx"           },
+  { "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.pcx"           },
+  { "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.pcx"           },
+  { "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.pcx"           },
+  { "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.pcx"     },
+  { "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.pcx"     },
+  { "bd_diamond.moving.xpos",                  "3"                     },
+  { "bd_diamond.moving.ypos",                  "10"                    },
+  { "bd_diamond.moving.frames",                        "2"                     },
+  { "bd_diamond.moving.delay",                 "4"                     },
+  { "bd_diamond.falling",                      "RocksElements.pcx"     },
+  { "bd_diamond.falling.xpos",                 "3"                     },
+  { "bd_diamond.falling.ypos",                 "10"                    },
+  { "bd_diamond.falling.frames",               "2"                     },
+  { "bd_diamond.falling.delay",                        "4"                     },
+
+  { "bd_magic_wall",                           "RocksElements.pcx"     },
+  { "bd_magic_wall.xpos",                      "12"                    },
+  { "bd_magic_wall.ypos",                      "10"                    },
+  { "bd_magic_wall.frames",                    "1"                     },
+  { "bd_magic_wall.active",                    "RocksElements.pcx"     },
+  { "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.pcx"     },
+  { "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.pcx"     },
+  { "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.pcx"     },
+  { "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.pcx"     },
+  { "bd_magic_wall_dead.xpos",                 "12"                    },
+  { "bd_magic_wall_dead.ypos",                 "10"                    },
+  { "bd_magic_wall_dead.frames",               "1"                     },
+
+  { "bd_amoeba",                               "RocksElements.pcx"     },
+  { "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.pcx"     },
+  { "bd_amoeba.EDITOR.xpos",                   "8"                     },
+  { "bd_amoeba.EDITOR.ypos",                   "7"                     },
+
+  { "bd_butterfly",                            "RocksElements.pcx"     },
+  { "bd_butterfly.xpos",                       "4"                     },
+  { "bd_butterfly.ypos",                       "12"                    },
+  { "bd_butterfly.frames",                     "2"                     },
+  { "bd_butterfly.anim_mode",                  "pingpong"              },
+  { "bd_butterfly.delay",                      "4"                     },
+  { "bd_butterfly.right",                      "RocksElements.pcx"     },
+  { "bd_butterfly.right.xpos",                 "8"                     },
+  { "bd_butterfly.right.ypos",                 "12"                    },
+  { "bd_butterfly.right.frames",               "1"                     },
+  { "bd_butterfly.up",                         "RocksElements.pcx"     },
+  { "bd_butterfly.up.xpos",                    "9"                     },
+  { "bd_butterfly.up.ypos",                    "12"                    },
+  { "bd_butterfly.up.frames",                  "1"                     },
+  { "bd_butterfly.left",                       "RocksElements.pcx"     },
+  { "bd_butterfly.left.xpos",                  "10"                    },
+  { "bd_butterfly.left.ypos",                  "12"                    },
+  { "bd_butterfly.left.frames",                        "1"                     },
+  { "bd_butterfly.down",                       "RocksElements.pcx"     },
+  { "bd_butterfly.down.xpos",                  "11"                    },
+  { "bd_butterfly.down.ypos",                  "12"                    },
+  { "bd_butterfly.down.frames",                        "1"                     },
+  { "bd_butterfly.moving",                     "RocksElements.pcx"     },
+  { "bd_butterfly.moving.xpos",                        "4"                     },
+  { "bd_butterfly.moving.ypos",                        "12"                    },
+  { "bd_butterfly.moving.frames",              "2"                     },
+  { "bd_butterfly.moving.anim_mode",           "pingpong"              },
+  { "bd_butterfly.moving.delay",               "4"                     },
+
+  { "bd_firefly",                              "RocksElements.pcx"     },
+  { "bd_firefly.xpos",                         "6"                     },
+  { "bd_firefly.ypos",                         "12"                    },
+  { "bd_firefly.frames",                       "2"                     },
+  { "bd_firefly.anim_mode",                    "pingpong"              },
+  { "bd_firefly.delay",                                "4"                     },
+  { "bd_firefly.right",                                "RocksElements.pcx"     },
+  { "bd_firefly.right.xpos",                   "12"                    },
+  { "bd_firefly.right.ypos",                   "12"                    },
+  { "bd_firefly.right.frames",                 "1"                     },
+  { "bd_firefly.up",                           "RocksElements.pcx"     },
+  { "bd_firefly.up.xpos",                      "13"                    },
+  { "bd_firefly.up.ypos",                      "12"                    },
+  { "bd_firefly.up.frames",                    "1"                     },
+  { "bd_firefly.left",                         "RocksElements.pcx"     },
+  { "bd_firefly.left.xpos",                    "14"                    },
+  { "bd_firefly.left.ypos",                    "12"                    },
+  { "bd_firefly.left.frames",                  "1"                     },
+  { "bd_firefly.down",                         "RocksElements.pcx"     },
+  { "bd_firefly.down.xpos",                    "15"                    },
+  { "bd_firefly.down.ypos",                    "12"                    },
+  { "bd_firefly.down.frames",                  "1"                     },
+  { "bd_firefly.moving",                       "RocksElements.pcx"     },
+  { "bd_firefly.moving.xpos",                  "6"                     },
+  { "bd_firefly.moving.ypos",                  "12"                    },
+  { "bd_firefly.moving.frames",                        "2"                     },
+  { "bd_firefly.moving.anim_mode",             "pingpong"              },
+  { "bd_firefly.moving.delay",                 "4"                     },
+
+  /* images for Supaplex style elements and actions */
+
+  { "[sp_default].exploding",                  "RocksSP.pcx"           },
+  { "[sp_default].exploding.xpos",             "8"                     },
+  { "[sp_default].exploding.ypos",             "3"                     },
+  { "[sp_default].exploding.frames",           "8"                     },
+  { "[sp_default].exploding.delay",            "3"                     },
+  { "[sp_default].exploding.anim_mode",                "linear"                },
+
+  { "sp_empty_space",                          "RocksSP.pcx"           },
+  { "sp_empty_space.xpos",                     "0"                     },
+  { "sp_empty_space.ypos",                     "0"                     },
+  { "sp_empty_space.frames",                   "1"                     },
+
+  { "sp_zonk",                                 "RocksSP.pcx"           },
+  { "sp_zonk.xpos",                            "1"                     },
+  { "sp_zonk.ypos",                            "0"                     },
+  { "sp_zonk.frames",                          "1"                     },
+  { "sp_zonk.moving.left",                     "RocksSP.pcx"           },
+  { "sp_zonk.moving.left.xpos",                        "0"                     },
+  { "sp_zonk.moving.left.ypos",                        "6"                     },
+  { "sp_zonk.moving.left.frames",              "4"                     },
+  { "sp_zonk.moving.left.delay",               "2"                     },
+  { "sp_zonk.moving.left.anim_mode",           "reverse"               },
+  { "sp_zonk.moving.right",                    "RocksSP.pcx"           },
+  { "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",              "2"                     },
+  { "sp_zonk.pushing.left",                    "RocksSP.pcx"           },
+  { "sp_zonk.pushing.left.xpos",               "0"                     },
+  { "sp_zonk.pushing.left.ypos",               "6"                     },
+  { "sp_zonk.pushing.left.frames",             "4"                     },
+  { "sp_zonk.pushing.left.delay",              "2"                     },
+  { "sp_zonk.pushing.left.anim_mode",          "reverse"               },
+  { "sp_zonk.pushing.right",                   "RocksSP.pcx"           },
+  { "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",             "2"                     },
+
+  { "sp_base",                                 "RocksSP.pcx"           },
+  { "sp_base.xpos",                            "2"                     },
+  { "sp_base.ypos",                            "0"                     },
+  { "sp_base.frames",                          "1"                     },
+
+  { "sp_murphy",                               "RocksSP.pcx"           },
+  { "sp_murphy.xpos",                          "3"                     },
+  { "sp_murphy.ypos",                          "0"                     },
+  { "sp_murphy.frames",                                "1"                     },
+  { "sp_murphy.moving.left",                   "RocksSP.pcx"           },
+  { "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.right",                  "RocksSP.pcx"           },
+  { "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.digging.left",                  "RocksSP.pcx"           },
+  { "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.right",                 "RocksSP.pcx"           },
+  { "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.collecting.left",               "RocksSP.pcx"           },
+  { "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.right",              "RocksSP.pcx"           },
+  { "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.pushing.left",                  "RocksSP.pcx"           },
+  { "sp_murphy.pushing.left.xpos",             "11"                    },
+  { "sp_murphy.pushing.left.ypos",             "1"                     },
+  { "sp_murphy.pushing.left.frames",           "1"                     },
+  { "sp_murphy.pushing.right",                 "RocksSP.pcx"           },
+  { "sp_murphy.pushing.right.xpos",            "10"                    },
+  { "sp_murphy.pushing.right.ypos",            "1"                     },
+  { "sp_murphy.pushing.right.frames",          "1"                     },
+  { "sp_murphy.snapping.left",                 "RocksSP.pcx"           },
+  { "sp_murphy.snapping.left.xpos",            "9"                     },
+  { "sp_murphy.snapping.left.ypos",            "1"                     },
+  { "sp_murphy.snapping.left.frames",          "1"                     },
+  { "sp_murphy.snapping.right",                        "RocksSP.pcx"           },
+  { "sp_murphy.snapping.right.xpos",           "8"                     },
+  { "sp_murphy.snapping.right.ypos",           "1"                     },
+  { "sp_murphy.snapping.right.frames",         "1"                     },
+  { "sp_murphy.snapping.up",                   "RocksSP.pcx"           },
+  { "sp_murphy.snapping.up.xpos",              "14"                    },
+  { "sp_murphy.snapping.up.ypos",              "0"                     },
+  { "sp_murphy.snapping.up.frames",            "1"                     },
+  { "sp_murphy.snapping.down",                 "RocksSP.pcx"           },
+  { "sp_murphy.snapping.down.xpos",            "15"                    },
+  { "sp_murphy.snapping.down.ypos",            "0"                     },
+  { "sp_murphy.snapping.down.frames",          "1"                     },
+
+  { "sp_murphy_clone",                         "RocksSP.pcx"           },
+  { "sp_murphy_clone.xpos",                    "3"                     },
+  { "sp_murphy_clone.ypos",                    "0"                     },
+  { "sp_murphy_clone.frames",                  "1"                     },
+
+  { "sp_infotron",                             "RocksSP.pcx"           },
+  { "sp_infotron.xpos",                                "4"                     },
+  { "sp_infotron.ypos",                                "0"                     },
+  { "sp_infotron.frames",                      "1"                     },
+  { "sp_infotron.EDITOR",                      "RocksSP.pcx"           },
+  { "sp_infotron.EDITOR.xpos",                 "8"                     },
+  { "sp_infotron.EDITOR.ypos",                 "11"                    },
+
+  { "sp_chip_single",                          "RocksSP.pcx"           },
+  { "sp_chip_single.xpos",                     "5"                     },
+  { "sp_chip_single.ypos",                     "0"                     },
+  { "sp_chip_single.frames",                   "1"                     },
+  { "sp_chip_left",                            "RocksSP.pcx"           },
+  { "sp_chip_left.xpos",                       "2"                     },
+  { "sp_chip_left.ypos",                       "3"                     },
+  { "sp_chip_left.frames",                     "1"                     },
+  { "sp_chip_right",                           "RocksSP.pcx"           },
+  { "sp_chip_right.xpos",                      "3"                     },
+  { "sp_chip_right.ypos",                      "3"                     },
+  { "sp_chip_right.frames",                    "1"                     },
+  { "sp_chip_top",                             "RocksSP.pcx"           },
+  { "sp_chip_top.xpos",                                "6"                     },
+  { "sp_chip_top.ypos",                                "4"                     },
+  { "sp_chip_top.frames",                      "1"                     },
+  { "sp_chip_bottom",                          "RocksSP.pcx"           },
+  { "sp_chip_bottom.xpos",                     "7"                     },
+  { "sp_chip_bottom.ypos",                     "4"                     },
+  { "sp_chip_bottom.frames",                   "1"                     },
+
+  { "sp_hardware_gray",                                "RocksSP.pcx"           },
+  { "sp_hardware_gray.xpos",                   "6"                     },
+  { "sp_hardware_gray.ypos",                   "0"                     },
+  { "sp_hardware_gray.frames",                 "1"                     },
+  { "sp_hardware_green",                       "RocksSP.pcx"           },
+  { "sp_hardware_green.xpos",                  "5"                     },
+  { "sp_hardware_green.ypos",                  "3"                     },
+  { "sp_hardware_green.frames",                        "1"                     },
+  { "sp_hardware_blue",                                "RocksSP.pcx"           },
+  { "sp_hardware_blue.xpos",                   "6"                     },
+  { "sp_hardware_blue.ypos",                   "3"                     },
+  { "sp_hardware_blue.frames",                 "1"                     },
+  { "sp_hardware_red",                         "RocksSP.pcx"           },
+  { "sp_hardware_red.xpos",                    "7"                     },
+  { "sp_hardware_red.ypos",                    "3"                     },
+  { "sp_hardware_red.frames",                  "1"                     },
+  { "sp_hardware_yellow",                      "RocksSP.pcx"           },
+  { "sp_hardware_yellow.xpos",                 "0"                     },
+  { "sp_hardware_yellow.ypos",                 "4"                     },
+  { "sp_hardware_yellow.frames",               "1"                     },
+
+  { "sp_exit_closed",                          "RocksSP.pcx"           },
+  { "sp_exit_closed.xpos",                     "7"                     },
+  { "sp_exit_closed.ypos",                     "0"                     },
+  { "sp_exit_closed.frames",                   "1"                     },
+  { "sp_exit_open",                            "RocksSP.pcx"           },
+  { "sp_exit_open.xpos",                       "7"                     },
+  { "sp_exit_open.ypos",                       "0"                     },
+  { "sp_exit_open.frames",                     "1"                     },
+
+  { "sp_disk_orange",                          "RocksSP.pcx"           },
+  { "sp_disk_orange.xpos",                     "0"                     },
+  { "sp_disk_orange.ypos",                     "1"                     },
+  { "sp_disk_orange.frames",                   "1"                     },
+
+  { "sp_disk_yellow",                          "RocksSP.pcx"           },
+  { "sp_disk_yellow.xpos",                     "2"                     },
+  { "sp_disk_yellow.ypos",                     "2"                     },
+  { "sp_disk_yellow.frames",                   "1"                     },
+
+  { "sp_disk_red",                             "RocksSP.pcx"           },
+  { "sp_disk_red.xpos",                                "4"                     },
+  { "sp_disk_red.ypos",                                "2"                     },
+  { "sp_disk_red.frames",                      "1"                     },
+  { "sp_disk_red.collecting",                  "RocksSP.pcx"           },
+  { "sp_disk_red.collecting.xpos",             "8"                     },
+  { "sp_disk_red.collecting.ypos",             "5"                     },
+  { "sp_disk_red.collecting.frames",           "8"                     },
+
+  { "sp_port_right",                           "RocksSP.pcx"           },
+  { "sp_port_right.xpos",                      "1"                     },
+  { "sp_port_right.ypos",                      "1"                     },
+  { "sp_port_right.frames",                    "1"                     },
+  { "sp_port_down",                            "RocksSP.pcx"           },
+  { "sp_port_down.xpos",                       "2"                     },
+  { "sp_port_down.ypos",                       "1"                     },
+  { "sp_port_down.frames",                     "1"                     },
+  { "sp_port_left",                            "RocksSP.pcx"           },
+  { "sp_port_left.xpos",                       "3"                     },
+  { "sp_port_left.ypos",                       "1"                     },
+  { "sp_port_left.frames",                     "1"                     },
+  { "sp_port_up",                              "RocksSP.pcx"           },
+  { "sp_port_up.xpos",                         "4"                     },
+  { "sp_port_up.ypos",                         "1"                     },
+  { "sp_port_up.frames",                       "1"                     },
+  { "sp_port_horizontal",                      "RocksSP.pcx"           },
+  { "sp_port_horizontal.xpos",                 "6"                     },
+  { "sp_port_horizontal.ypos",                 "2"                     },
+  { "sp_port_horizontal.frames",               "1"                     },
+  { "sp_port_vertical",                                "RocksSP.pcx"           },
+  { "sp_port_vertical.xpos",                   "5"                     },
+  { "sp_port_vertical.ypos",                   "2"                     },
+  { "sp_port_vertical.frames",                 "1"                     },
+  { "sp_port_any",                             "RocksSP.pcx"           },
+  { "sp_port_any.xpos",                                "7"                     },
+  { "sp_port_any.ypos",                                "2"                     },
+  { "sp_port_any.frames",                      "1"                     },
+  { "sp_gravity_port_right",                   "RocksSP.pcx"           },
+  { "sp_gravity_port_right.xpos",              "5"                     },
+  { "sp_gravity_port_right.ypos",              "1"                     },
+  { "sp_gravity_port_right.frames",            "1"                     },
+  { "sp_gravity_port_down",                    "RocksSP.pcx"           },
+  { "sp_gravity_port_down.xpos",               "6"                     },
+  { "sp_gravity_port_down.ypos",               "1"                     },
+  { "sp_gravity_port_down.frames",             "1"                     },
+  { "sp_gravity_port_left",                    "RocksSP.pcx"           },
+  { "sp_gravity_port_left.xpos",               "7"                     },
+  { "sp_gravity_port_left.ypos",               "1"                     },
+  { "sp_gravity_port_left.frames",             "1"                     },
+  { "sp_gravity_port_up",                      "RocksSP.pcx"           },
+  { "sp_gravity_port_up.xpos",                 "0"                     },
+  { "sp_gravity_port_up.ypos",                 "2"                     },
+  { "sp_gravity_port_up.frames",               "1"                     },
+
+  { "sp_sniksnak",                             "RocksSP.pcx"           },
+  { "sp_sniksnak.xpos",                                "1"                     },
+  { "sp_sniksnak.ypos",                                "2"                     },
+  { "sp_sniksnak.frames",                      "1"                     },
+  { "sp_sniksnak.left",                                "RocksSP.pcx"           },
+  { "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.pcx"           },
+  { "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.pcx"           },
+  { "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.pcx"           },
+  { "sp_sniksnak.down.xpos",                   "12"                    },
+  { "sp_sniksnak.down.ypos",                   "9"                     },
+  { "sp_sniksnak.down.frames",                 "4"                     },
+  { "sp_sniksnak.down.anim_mode",              "pingpong2"             },
+
+  { "sp_electron",                             "RocksSP.pcx"           },
+  { "sp_electron.xpos",                                "8"                     },
+  { "sp_electron.ypos",                                "10"                    },
+  { "sp_electron.frames",                      "8"                     },
+  { "sp_electron.delay",                       "2"                     },
+  { "sp_electron.EDITOR",                      "RocksSP.pcx"           },
+  { "sp_electron.EDITOR.xpos",                 "10"                    },
+  { "sp_electron.EDITOR.ypos",                 "11"                    },
+  { "sp_electron.exploding",                   "RocksSP.pcx"           },
+  { "sp_electron.exploding.xpos",              "8"                     },
+  { "sp_electron.exploding.ypos",              "4"                     },
+  { "sp_electron.exploding.frames",            "8"                     },
+  { "sp_electron.exploding.delay",             "3"                     },
+  { "sp_electron.exploding.anim_mode",         "linear"                },
+
+  { "sp_terminal",                             "RocksSP.pcx"           },
+  { "sp_terminal.xpos",                                "0"                     },
+  { "sp_terminal.ypos",                                "10"                    },
+  { "sp_terminal.frames",                      "7"                     },
+  { "sp_terminal.delay",                       "12"                    },
+  { "sp_terminal.EDITOR",                      "RocksSP.pcx"           },
+  { "sp_terminal.EDITOR.xpos",                 "9"                     },
+  { "sp_terminal.EDITOR.ypos",                 "11"                    },
+  { "sp_terminal.active",                      "RocksSP.pcx"           },
+  { "sp_terminal.active.xpos",                 "0"                     },
+  { "sp_terminal.active.ypos",                 "11"                    },
+  { "sp_terminal.active.frames",               "7"                     },
+  { "sp_terminal.active.delay",                        "4"                     },
+
+  { "sp_buggy_base",                           "RocksSP.pcx"           },
+  { "sp_buggy_base.xpos",                      "1"                     },
+  { "sp_buggy_base.ypos",                      "3"                     },
+  { "sp_buggy_base.frames",                    "1"                     },
+  { "sp_buggy_base.EDITOR",                    "RocksSP.pcx"           },
+  { "sp_buggy_base.EDITOR.xpos",               "9"                     },
+  { "sp_buggy_base.EDITOR.ypos",               "6"                     },
+  { "sp_buggy_base.activating",                        "RocksSP.pcx"           },
+  { "sp_buggy_base.activating.xpos",           "15"                    },
+  { "sp_buggy_base.activating.ypos",           "2"                     },
+  { "sp_buggy_base.activating.frames",         "1"                     },
+  { "sp_buggy_base.active",                    "RocksSP.pcx"           },
+  { "sp_buggy_base.active.xpos",               "8"                     },
+  { "sp_buggy_base.active.ypos",               "6"                     },
+  { "sp_buggy_base.active.frames",             "4"                     },
+  { "sp_buggy_base.active.anim_mode",          "random"                },
+
+  { "sp_hardware_base_1",                      "RocksSP.pcx"           },
+  { "sp_hardware_base_1.xpos",                 "4"                     },
+  { "sp_hardware_base_1.ypos",                 "3"                     },
+  { "sp_hardware_base_1.frames",               "1"                     },
+  { "sp_hardware_base_2",                      "RocksSP.pcx"           },
+  { "sp_hardware_base_2.xpos",                 "1"                     },
+  { "sp_hardware_base_2.ypos",                 "4"                     },
+  { "sp_hardware_base_2.frames",               "1"                     },
+  { "sp_hardware_base_3",                      "RocksSP.pcx"           },
+  { "sp_hardware_base_3.xpos",                 "2"                     },
+  { "sp_hardware_base_3.ypos",                 "4"                     },
+  { "sp_hardware_base_3.frames",               "1"                     },
+  { "sp_hardware_base_4",                      "RocksSP.pcx"           },
+  { "sp_hardware_base_4.xpos",                 "3"                     },
+  { "sp_hardware_base_4.ypos",                 "4"                     },
+  { "sp_hardware_base_4.frames",               "1"                     },
+  { "sp_hardware_base_5",                      "RocksSP.pcx"           },
+  { "sp_hardware_base_5.xpos",                 "4"                     },
+  { "sp_hardware_base_5.ypos",                 "4"                     },
+  { "sp_hardware_base_5.frames",               "1"                     },
+  { "sp_hardware_base_6",                      "RocksSP.pcx"           },
+  { "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.pcx"     },
+  { "sokoban_object.xpos",                     "9"                     },
+  { "sokoban_object.ypos",                     "7"                     },
+  { "sokoban_object.frames",                   "1"                     },
+  { "sokoban_object.EDITOR",                   "RocksElements.pcx"     },
+  { "sokoban_object.EDITOR.xpos",              "2"                     },
+  { "sokoban_object.EDITOR.ypos",              "14"                    },
+
+  { "sokoban_field_empty",                     "RocksElements.pcx"     },
+  { "sokoban_field_empty.xpos",                        "10"                    },
+  { "sokoban_field_empty.ypos",                        "7"                     },
+  { "sokoban_field_empty.frames",              "1"                     },
+
+  { "sokoban_field_full",                      "RocksElements.pcx"     },
+  { "sokoban_field_full.xpos",                 "11"                    },
+  { "sokoban_field_full.ypos",                 "7"                     },
+  { "sokoban_field_full.frames",               "1"                     },
+
+  /* images for Emerald Mine style elements and actions */
+
+  { "empty_space",                             "RocksSP.pcx"           },
+  { "empty_space.xpos",                                "0"                     },
+  { "empty_space.ypos",                                "0"                     },
+  { "empty_space.frames",                      "1"                     },
+
+  { "sand",                                    "RocksElements.pcx"     },
+  { "sand.xpos",                               "0"                     },
+  { "sand.ypos",                               "0"                     },
+  { "sand.frames",                             "1"                     },
+  { "sand.CRUMBLED",                           "RocksElements.pcx"     },
+  { "sand.CRUMBLED.xpos",                      "1"                     },
+  { "sand.CRUMBLED.ypos",                      "0"                     },
+  { "sand.CRUMBLED.frames",                    "1"                     },
+  { "sand.digging.left",                       "RocksMore.pcx"         },
+  { "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.pcx"         },
+  { "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.pcx"         },
+  { "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.pcx"         },
+  { "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.pcx"         },
+  { "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.pcx"         },
+  { "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.pcx"         },
+  { "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.pcx"         },
+  { "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.pcx"     },
+  { "wall.xpos",                               "5"                     },
+  { "wall.ypos",                               "0"                     },
+  { "wall.frames",                             "1"                     },
+
+  { "wall_slippery",                           "RocksElements.pcx"     },
+  { "wall_slippery.xpos",                      "6"                     },
+  { "wall_slippery.ypos",                      "0"                     },
+  { "wall_slippery.frames",                    "1"                     },
+
+  { "steelwall",                               "RocksElements.pcx"     },
+  { "steelwall.xpos",                          "4"                     },
+  { "steelwall.ypos",                          "0"                     },
+  { "steelwall.frames",                                "1"                     },
+
+  { "rock",                                    "RocksElements.pcx"     },
+  { "rock.xpos",                               "12"                    },
+  { "rock.ypos",                               "0"                     },
+  { "rock.frames",                             "1"                     },
+  { "rock.moving.left",                                "RocksElements.pcx"     },
+  { "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.pcx"     },
+  { "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.pcx"     },
+  { "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.pcx"     },
+  { "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.pcx"     },
+  { "emerald.xpos",                            "8"                     },
+  { "emerald.ypos",                            "0"                     },
+  { "emerald.frames",                          "1"                     },
+  { "emerald.moving",                          "RocksElements.pcx"     },
+  { "emerald.moving.xpos",                     "8"                     },
+  { "emerald.moving.ypos",                     "0"                     },
+  { "emerald.moving.frames",                   "2"                     },
+  { "emerald.moving.delay",                    "4"                     },
+  { "emerald.falling",                         "RocksElements.pcx"     },
+  { "emerald.falling.xpos",                    "8"                     },
+  { "emerald.falling.ypos",                    "0"                     },
+  { "emerald.falling.frames",                  "2"                     },
+  { "emerald.falling.delay",                   "4"                     },
+  { "emerald.collecting",                      "RocksMore.pcx"         },
+  { "emerald.collecting.xpos",                 "3"                     },
+  { "emerald.collecting.ypos",                 "2"                     },
+  { "emerald.collecting.frames",               "3"                     },
+  { "emerald.collecting.delay",                        "2"                     },
+  { "emerald.collecting.anim_mode",            "linear"                },
+
+  { "diamond",                                 "RocksElements.pcx"     },
+  { "diamond.xpos",                            "10"                    },
+  { "diamond.ypos",                            "0"                     },
+  { "diamond.frames",                          "1"                     },
+  { "diamond.moving",                          "RocksElements.pcx"     },
+  { "diamond.moving.xpos",                     "10"                    },
+  { "diamond.moving.ypos",                     "0"                     },
+  { "diamond.moving.frames",                   "2"                     },
+  { "diamond.moving.delay",                    "4"                     },
+  { "diamond.falling",                         "RocksElements.pcx"     },
+  { "diamond.falling.xpos",                    "10"                    },
+  { "diamond.falling.ypos",                    "0"                     },
+  { "diamond.falling.frames",                  "2"                     },
+  { "diamond.falling.delay",                   "4"                     },
+  { "diamond.collecting",                      "RocksMore.pcx"         },
+  { "diamond.collecting.xpos",                 "7"                     },
+  { "diamond.collecting.ypos",                 "2"                     },
+  { "diamond.collecting.frames",               "3"                     },
+  { "diamond.collecting.delay",                        "2"                     },
+  { "diamond.collecting.anim_mode",            "linear"                },
+
+  { "bomb",                                    "RocksElements.pcx"     },
+  { "bomb.xpos",                               "11"                    },
+  { "bomb.ypos",                               "1"                     },
+  { "bomb.frames",                             "1"                     },
+
+  { "nut",                                     "RocksElements.pcx"     },
+  { "nut.xpos",                                        "12"                    },
+  { "nut.ypos",                                        "1"                     },
+  { "nut.frames",                              "1"                     },
+  { "nut.breaking",                            "RocksElements.pcx"     },
+  { "nut.breaking.xpos",                       "13"                    },
+  { "nut.breaking.ypos",                       "1"                     },
+  { "nut.breaking.frames",                     "3"                     },
+  { "nut.breaking.delay",                      "2"                     },
+  { "nut.breaking.anim_mode",                  "linear"                },
+
+  { "dynamite",                                        "RocksElements.pcx"     },
+  { "dynamite.xpos",                           "0"                     },
+  { "dynamite.ypos",                           "3"                     },
+  { "dynamite.frames",                         "1"                     },
+  { "dynamite.EDITOR",                         "RocksElements.pcx"     },
+  { "dynamite.EDITOR.xpos",                    "0"                     },
+  { "dynamite.EDITOR.ypos",                    "14"                    },
+  { "dynamite.active",                         "RocksElements.pcx"     },
+  { "dynamite.active.xpos",                    "1"                     },
+  { "dynamite.active.ypos",                    "3"                     },
+  { "dynamite.active.frames",                  "7"                     },
+  { "dynamite.active.delay",                   "12"                    },
+  { "dynamite.active.anim_mode",               "linear"                },
+  { "dynamite.active.EDITOR",                  "RocksElements.pcx"     },
+  { "dynamite.active.EDITOR.xpos",             "1"                     },
+  { "dynamite.active.EDITOR.ypos",             "14"                    },
+
+  { "wall_emerald",                            "RocksElements.pcx"     },
+  { "wall_emerald.xpos",                       "4"                     },
+  { "wall_emerald.ypos",                       "8"                     },
+  { "wall_emerald.frames",                     "1"                     },
+
+  { "wall_diamond",                            "RocksElements.pcx"     },
+  { "wall_diamond.xpos",                       "5"                     },
+  { "wall_diamond.ypos",                       "8"                     },
+  { "wall_diamond.frames",                     "1"                     },
+
+  { "bug",                                     "RocksElements.pcx"     },
+  { "bug.xpos",                                        "8"                     },
+  { "bug.ypos",                                        "4"                     },
+  { "bug.frames",                              "4"                     },
+  { "bug.delay",                               "8"                     },
+  { "bug.right",                               "RocksElements.pcx"     },
+  { "bug.right.xpos",                          "8"                     },
+  { "bug.right.ypos",                          "4"                     },
+  { "bug.right.frames",                                "1"                     },
+  { "bug.up",                                  "RocksElements.pcx"     },
+  { "bug.up.xpos",                             "9"                     },
+  { "bug.up.ypos",                             "4"                     },
+  { "bug.up.frames",                           "1"                     },
+  { "bug.left",                                        "RocksElements.pcx"     },
+  { "bug.left.xpos",                           "10"                    },
+  { "bug.left.ypos",                           "4"                     },
+  { "bug.left.frames",                         "1"                     },
+  { "bug.down",                                        "RocksElements.pcx"     },
+  { "bug.down.xpos",                           "11"                    },
+  { "bug.down.ypos",                           "4"                     },
+  { "bug.down.frames",                         "1"                     },
+  { "bug.moving.right",                                "RocksElements.pcx"     },
+  { "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.pcx"     },
+  { "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.pcx"     },
+  { "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.pcx"     },
+  { "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"                   },
+
+  { "spaceship",                               "RocksElements.pcx"     },
+  { "spaceship.xpos",                          "8"                     },
+  { "spaceship.ypos",                          "3"                     },
+  { "spaceship.frames",                                "4"                     },
+  { "spaceship.delay",                         "8"                     },
+  { "spaceship.right",                         "RocksElements.pcx"     },
+  { "spaceship.right.xpos",                    "8"                     },
+  { "spaceship.right.ypos",                    "3"                     },
+  { "spaceship.right.frames",                  "1"                     },
+  { "spaceship.up",                            "RocksElements.pcx"     },
+  { "spaceship.up.xpos",                       "9"                     },
+  { "spaceship.up.ypos",                       "3"                     },
+  { "spaceship.up.frames",                     "1"                     },
+  { "spaceship.left",                          "RocksElements.pcx"     },
+  { "spaceship.left.xpos",                     "10"                    },
+  { "spaceship.left.ypos",                     "3"                     },
+  { "spaceship.left.frames",                   "1"                     },
+  { "spaceship.down",                          "RocksElements.pcx"     },
+  { "spaceship.down.xpos",                     "11"                    },
+  { "spaceship.down.ypos",                     "3"                     },
+  { "spaceship.down.frames",                   "1"                     },
+  { "spaceship.moving.right",                  "RocksElements.pcx"     },
+  { "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.pcx"     },
+  { "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.pcx"     },
+  { "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.pcx"     },
+  { "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"                   },
+
+  { "yamyam",                                  "RocksElements.pcx"     },
+  { "yamyam.xpos",                             "0"                     },
+  { "yamyam.ypos",                             "5"                     },
+  { "yamyam.frames",                           "4"                     },
+  { "yamyam.anim_mode",                                "pingpong2"             },
+  { "yamyam.moving",                           "RocksElements.pcx"     },
+  { "yamyam.moving.xpos",                      "0"                     },
+  { "yamyam.moving.ypos",                      "5"                     },
+  { "yamyam.moving.frames",                    "1"                     },
+
+  { "robot",                                   "RocksElements.pcx"     },
+  { "robot.xpos",                              "4"                     },
+  { "robot.ypos",                              "5"                     },
+  { "robot.frames",                            "4"                     },
+  { "robot.anim_mode",                         "pingpong2"             },
+  { "robot.moving",                            "RocksElements.pcx"     },
+  { "robot.moving.xpos",                       "4"                     },
+  { "robot.moving.ypos",                       "5"                     },
+  { "robot.moving.frames",                     "1"                     },
+
+  { "robot_wheel",                             "RocksElements.pcx"     },
+  { "robot_wheel.xpos",                                "0"                     },
+  { "robot_wheel.ypos",                                "6"                     },
+  { "robot_wheel.frames",                      "1"                     },
+  { "robot_wheel.active",                      "RocksElements.pcx"     },
+  { "robot_wheel.active.xpos",                 "0"                     },
+  { "robot_wheel.active.ypos",                 "6"                     },
+  { "robot_wheel.active.frames",               "4"                     },
+
+  { "magic_wall",                              "RocksElements.pcx"     },
+  { "magic_wall.xpos",                         "0"                     },
+  { "magic_wall.ypos",                         "8"                     },
+  { "magic_wall.frames",                       "1"                     },
+  { "magic_wall.active",                       "RocksElements.pcx"     },
+  { "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.pcx"     },
+  { "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.pcx"     },
+  { "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.pcx"     },
+  { "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.pcx"     },
+  { "magic_wall_dead.xpos",                    "0"                     },
+  { "magic_wall_dead.ypos",                    "8"                     },
+  { "magic_wall_dead.frames",                  "1"                     },
+
+  { "quicksand_empty",                         "RocksElements.pcx"     },
+  { "quicksand_empty.xpos",                    "2"                     },
+  { "quicksand_empty.ypos",                    "0"                     },
+  { "quicksand_empty.frames",                  "1"                     },
+  { "quicksand.filling",                       "RocksElements.pcx"     },
+  { "quicksand.filling.xpos",                  "3"                     },
+  { "quicksand.filling.ypos",                  "0"                     },
+  { "quicksand.filling.frames",                        "1"                     },
+  { "quicksand_full",                          "RocksElements.pcx"     },
+  { "quicksand_full.xpos",                     "3"                     },
+  { "quicksand_full.ypos",                     "0"                     },
+  { "quicksand_full.frames",                   "1"                     },
+  { "quicksand_full.EDITOR",                   "RocksElements.pcx"     },
+  { "quicksand_full.EDITOR.xpos",              "3"                     },
+  { "quicksand_full.EDITOR.ypos",              "14"                    },
+  { "quicksand.emptying",                      "RocksElements.pcx"     },
+  { "quicksand.emptying.xpos",                 "3"                     },
+  { "quicksand.emptying.ypos",                 "0"                     },
+  { "quicksand.emptying.frames",               "1"                     },
+
+  { "acid_pool_topleft",                       "RocksElements.pcx"     },
+  { "acid_pool_topleft.xpos",                  "0"                     },
+  { "acid_pool_topleft.ypos",                  "1"                     },
+  { "acid_pool_topleft.frames",                        "1"                     },
+  { "acid_pool_topright",                      "RocksElements.pcx"     },
+  { "acid_pool_topright.xpos",                 "2"                     },
+  { "acid_pool_topright.ypos",                 "1"                     },
+  { "acid_pool_topright.frames",               "1"                     },
+  { "acid_pool_bottomleft",                    "RocksElements.pcx"     },
+  { "acid_pool_bottomleft.xpos",               "0"                     },
+  { "acid_pool_bottomleft.ypos",               "2"                     },
+  { "acid_pool_bottomleft.frames",             "1"                     },
+  { "acid_pool_bottom",                                "RocksElements.pcx"     },
+  { "acid_pool_bottom.xpos",                   "1"                     },
+  { "acid_pool_bottom.ypos",                   "2"                     },
+  { "acid_pool_bottom.frames",                 "1"                     },
+  { "acid_pool_bottomright",                   "RocksElements.pcx"     },
+  { "acid_pool_bottomright.xpos",              "2"                     },
+  { "acid_pool_bottomright.ypos",              "2"                     },
+  { "acid_pool_bottomright.frames",            "1"                     },
+
+  { "acid",                                    "RocksElements.pcx"     },
+  { "acid.xpos",                               "12"                    },
+  { "acid.ypos",                               "7"                     },
+  { "acid.frames",                             "4"                     },
+  { "acid.delay",                              "10"                    },
+  { "acid.global_sync",                                "true"                  },
+
+  { "acid_splash_left",                                "RocksHeroes.pcx"       },
+  { "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.pcx"       },
+  { "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.pcx"     },
+  { "amoeba_drop.xpos",                                "5"                     },
+  { "amoeba_drop.ypos",                                "6"                     },
+  { "amoeba_drop.frames",                      "1"                     },
+  { "amoeba.growing",                          "RocksElements.pcx"     },
+  { "amoeba.growing.xpos",                     "5"                     },
+  { "amoeba.growing.ypos",                     "6"                     },
+  { "amoeba.growing.frames",                   "3"                     },
+  { "amoeba.growing.delay",                    "2"                     },
+  { "amoeba.growing.anim_mode",                        "linear"                },
+  { "amoeba.shrinking",                                "RocksElements.pcx"     },
+  { "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.pcx"     },
+  { "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.pcx"     },
+  { "amoeba_wet.EDITOR.xpos",                  "4"                     },
+  { "amoeba_wet.EDITOR.ypos",                  "6"                     },
+  { "amoeba.dropping",                         "RocksElements.pcx"     },
+  { "amoeba.dropping.xpos",                    "8"                     },
+  { "amoeba.dropping.ypos",                    "6"                     },
+  { "amoeba.dropping.frames",                  "4"                     },
+  { "amoeba.dropping.delay",                   "1000000"               },
+  { "amoeba.dropping.anim_mode",               "random"                },
+  { "amoeba_dry",                              "RocksElements.pcx"     },
+  { "amoeba_dry.xpos",                         "8"                     },
+  { "amoeba_dry.ypos",                         "6"                     },
+  { "amoeba_dry.frames",                       "4"                     },
+  { "amoeba_dry.delay",                                "1000000"               },
+  { "amoeba_dry.anim_mode",                    "random"                },
+  { "amoeba_full",                             "RocksElements.pcx"     },
+  { "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.pcx"     },
+  { "amoeba_full.EDITOR.xpos",                 "8"                     },
+  { "amoeba_full.EDITOR.ypos",                 "7"                     },
+  { "amoeba_dead",                             "RocksElements.pcx"     },
+  { "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.pcx"     },
+  { "amoeba_dead.EDITOR.xpos",                 "12"                    },
+  { "amoeba_dead.EDITOR.ypos",                 "6"                     },
+
+  { "em_key_1",                                        "RocksSP.pcx"           },
+  { "em_key_1.xpos",                           "4"                     },
+  { "em_key_1.ypos",                           "6"                     },
+  { "em_key_1.frames",                         "1"                     },
+  { "em_key_2",                                        "RocksSP.pcx"           },
+  { "em_key_2.xpos",                           "5"                     },
+  { "em_key_2.ypos",                           "6"                     },
+  { "em_key_2.frames",                         "1"                     },
+  { "em_key_3",                                        "RocksSP.pcx"           },
+  { "em_key_3.xpos",                           "6"                     },
+  { "em_key_3.ypos",                           "6"                     },
+  { "em_key_3.frames",                         "1"                     },
+  { "em_key_4",                                        "RocksSP.pcx"           },
+  { "em_key_4.xpos",                           "7"                     },
+  { "em_key_4.ypos",                           "6"                     },
+  { "em_key_4.frames",                         "1"                     },
+
+  { "em_gate_1",                               "RocksSP.pcx"           },
+  { "em_gate_1.xpos",                          "0"                     },
+  { "em_gate_1.ypos",                          "7"                     },
+  { "em_gate_1.frames",                                "1"                     },
+  { "em_gate_2",                               "RocksSP.pcx"           },
+  { "em_gate_2.xpos",                          "1"                     },
+  { "em_gate_2.ypos",                          "7"                     },
+  { "em_gate_2.frames",                                "1"                     },
+  { "em_gate_3",                               "RocksSP.pcx"           },
+  { "em_gate_3.xpos",                          "2"                     },
+  { "em_gate_3.ypos",                          "7"                     },
+  { "em_gate_3.frames",                                "1"                     },
+  { "em_gate_4",                               "RocksSP.pcx"           },
+  { "em_gate_4.xpos",                          "3"                     },
+  { "em_gate_4.ypos",                          "7"                     },
+  { "em_gate_4.frames",                                "1"                     },
+  { "em_gate_1_gray",                          "RocksSP.pcx"           },
+  { "em_gate_1_gray.xpos",                     "4"                     },
+  { "em_gate_1_gray.ypos",                     "7"                     },
+  { "em_gate_1_gray.frames",                   "1"                     },
+  { "em_gate_1_gray.EDITOR",                   "RocksSP.pcx"           },
+  { "em_gate_1_gray.EDITOR.xpos",              "12"                    },
+  { "em_gate_1_gray.EDITOR.ypos",              "11"                    },
+  { "em_gate_2_gray",                          "RocksSP.pcx"           },
+  { "em_gate_2_gray.xpos",                     "5"                     },
+  { "em_gate_2_gray.ypos",                     "7"                     },
+  { "em_gate_2_gray.frames",                   "1"                     },
+  { "em_gate_2_gray.EDITOR",                   "RocksSP.pcx"           },
+  { "em_gate_2_gray.EDITOR.xpos",              "13"                    },
+  { "em_gate_2_gray.EDITOR.ypos",              "11"                    },
+  { "em_gate_3_gray",                          "RocksSP.pcx"           },
+  { "em_gate_3_gray.xpos",                     "6"                     },
+  { "em_gate_3_gray.ypos",                     "7"                     },
+  { "em_gate_3_gray.frames",                   "1"                     },
+  { "em_gate_3_gray.EDITOR",                   "RocksSP.pcx"           },
+  { "em_gate_3_gray.EDITOR.xpos",              "14"                    },
+  { "em_gate_3_gray.EDITOR.ypos",              "11"                    },
+  { "em_gate_4_gray",                          "RocksSP.pcx"           },
+  { "em_gate_4_gray.xpos",                     "7"                     },
+  { "em_gate_4_gray.ypos",                     "7"                     },
+  { "em_gate_4_gray.frames",                   "1"                     },
+  { "em_gate_4_gray.EDITOR",                   "RocksSP.pcx"           },
+  { "em_gate_4_gray.EDITOR.xpos",              "15"                    },
+  { "em_gate_4_gray.EDITOR.ypos",              "11"                    },
+
+  { "exit_closed",                             "RocksElements.pcx"     },
+  { "exit_closed.xpos",                                "0"                     },
+  { "exit_closed.ypos",                                "11"                    },
+  { "exit_closed.frames",                      "1"                     },
+  { "exit.opening",                            "RocksElements.pcx"     },
+  { "exit.opening.xpos",                       "0"                     },
+  { "exit.opening.ypos",                       "11"                    },
+  { "exit.opening.frames",                     "5"                     },
+  { "exit.opening.delay",                      "6"                     },
+  { "exit.opening.anim_mode",                  "linear"                },
+  { "exit_open",                               "RocksElements.pcx"     },
+  { "exit_open.xpos",                          "4"                     },
+  { "exit_open.ypos",                          "11"                    },
+  { "exit_open.frames",                                "4"                     },
+  { "exit_open.delay",                         "4"                     },
+  { "exit_open.anim_mode",                     "pingpong"              },
+
+  /* images for Emerald Mine Club style elements and actions */
+
+  { "balloon",                                 "RocksDC.pcx"           },
+  { "balloon.xpos",                            "12"                    },
+  { "balloon.ypos",                            "7"                     },
+  { "balloon.frames",                          "1"                     },
+  { "balloon.moving",                          "RocksDC.pcx"           },
+  { "balloon.moving.xpos",                     "12"                    },
+  { "balloon.moving.ypos",                     "7"                     },
+  { "balloon.moving.frames",                   "4"                     },
+  { "balloon.moving.anim_mode",                        "pingpong"              },
+  { "balloon.moving.delay",                    "2"                     },
+  { "balloon.pushing",                         "RocksDC.pcx"           },
+  { "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.pcx"           },
+  { "balloon_switch_left.xpos",                        "8"                     },
+  { "balloon_switch_left.ypos",                        "7"                     },
+  { "balloon_switch_left.frames",              "1"                     },
+  { "balloon_switch_right",                    "RocksDC.pcx"           },
+  { "balloon_switch_right.xpos",               "9"                     },
+  { "balloon_switch_right.ypos",               "7"                     },
+  { "balloon_switch_right.frames",             "1"                     },
+  { "balloon_switch_up",                       "RocksDC.pcx"           },
+  { "balloon_switch_up.xpos",                  "10"                    },
+  { "balloon_switch_up.ypos",                  "7"                     },
+  { "balloon_switch_up.frames",                        "1"                     },
+  { "balloon_switch_down",                     "RocksDC.pcx"           },
+  { "balloon_switch_down.xpos",                        "11"                    },
+  { "balloon_switch_down.ypos",                        "7"                     },
+  { "balloon_switch_down.frames",              "1"                     },
+  { "balloon_switch_any",                      "RocksDC.pcx"           },
+  { "balloon_switch_any.xpos",                 "15"                    },
+  { "balloon_switch_any.ypos",                 "0"                     },
+  { "balloon_switch_any.frames",               "1"                     },
+
+  { "spring",                                  "RocksDC.pcx"           },
+  { "spring.xpos",                             "8"                     },
+  { "spring.ypos",                             "13"                    },
+  { "spring.frames",                           "1"                     },
+
+  { "emc_steelwall_1",                         "RocksDC.pcx"           },
+  { "emc_steelwall_1.xpos",                    "14"                    },
+  { "emc_steelwall_1.ypos",                    "0"                     },
+  { "emc_steelwall_1.frames",                  "1"                     },
+  { "emc_steelwall_2",                         "RocksDC.pcx"           },
+  { "emc_steelwall_2.xpos",                    "14"                    },
+  { "emc_steelwall_2.ypos",                    "0"                     },
+  { "emc_steelwall_2.frames",                  "1"                     },
+  { "emc_steelwall_3",                         "RocksDC.pcx"           },
+  { "emc_steelwall_3.xpos",                    "14"                    },
+  { "emc_steelwall_3.ypos",                    "0"                     },
+  { "emc_steelwall_3.frames",                  "1"                     },
+  { "emc_steelwall_4",                         "RocksDC.pcx"           },
+  { "emc_steelwall_4.xpos",                    "14"                    },
+  { "emc_steelwall_4.ypos",                    "0"                     },
+  { "emc_steelwall_4.frames",                  "1"                     },
+
+  { "emc_wall_1",                              "RocksDC.pcx"           },
+  { "emc_wall_1.xpos",                         "13"                    },
+  { "emc_wall_1.ypos",                         "6"                     },
+  { "emc_wall_1.frames",                       "1"                     },
+  { "emc_wall_2",                              "RocksDC.pcx"           },
+  { "emc_wall_2.xpos",                         "14"                    },
+  { "emc_wall_2.ypos",                         "6"                     },
+  { "emc_wall_2.frames",                       "1"                     },
+  { "emc_wall_3",                              "RocksDC.pcx"           },
+  { "emc_wall_3.xpos",                         "15"                    },
+  { "emc_wall_3.ypos",                         "6"                     },
+  { "emc_wall_3.frames",                       "1"                     },
+  { "emc_wall_4",                              "RocksDC.pcx"           },
+  { "emc_wall_4.xpos",                         "14"                    },
+  { "emc_wall_4.ypos",                         "1"                     },
+  { "emc_wall_4.frames",                       "1"                     },
+  { "emc_wall_5",                              "RocksDC.pcx"           },
+  { "emc_wall_5.xpos",                         "15"                    },
+  { "emc_wall_5.ypos",                         "1"                     },
+  { "emc_wall_5.frames",                       "1"                     },
+  { "emc_wall_6",                              "RocksDC.pcx"           },
+  { "emc_wall_6.xpos",                         "14"                    },
+  { "emc_wall_6.ypos",                         "2"                     },
+  { "emc_wall_6.frames",                       "1"                     },
+  { "emc_wall_7",                              "RocksDC.pcx"           },
+  { "emc_wall_7.xpos",                         "15"                    },
+  { "emc_wall_7.ypos",                         "2"                     },
+  { "emc_wall_7.frames",                       "1"                     },
+  { "emc_wall_8",                              "RocksDC.pcx"           },
+  { "emc_wall_8.xpos",                         "14"                    },
+  { "emc_wall_8.ypos",                         "1"                     },
+  { "emc_wall_8.frames",                       "1"                     },
+
+  /* images for Diamond Caves style elements and actions */
+
+  { "invisible_steelwall",                     "RocksSP.pcx"           },
+  { "invisible_steelwall.xpos",                        "3"                     },
+  { "invisible_steelwall.ypos",                        "5"                     },
+  { "invisible_steelwall.frames",              "1"                     },
+  { "invisible_steelwall.EDITOR",              "RocksSP.pcx"           },
+  { "invisible_steelwall.EDITOR.xpos",         "1"                     },
+  { "invisible_steelwall.EDITOR.ypos",         "5"                     },
+  { "invisible_steelwall.active",              "RocksSP.pcx"           },
+  { "invisible_steelwall.active.xpos",         "1"                     },
+  { "invisible_steelwall.active.ypos",         "5"                     },
+  { "invisible_steelwall.active.frames",       "1"                     },
+
+  { "invisible_wall",                          "RocksSP.pcx"           },
+  { "invisible_wall.xpos",                     "7"                     },
+  { "invisible_wall.ypos",                     "5"                     },
+  { "invisible_wall.frames",                   "1"                     },
+  { "invisible_wall.EDITOR",                   "RocksSP.pcx"           },
+  { "invisible_wall.EDITOR.xpos",              "5"                     },
+  { "invisible_wall.EDITOR.ypos",              "5"                     },
+  { "invisible_wall.active",                   "RocksSP.pcx"           },
+  { "invisible_wall.active.xpos",              "5"                     },
+  { "invisible_wall.active.ypos",              "5"                     },
+  { "invisible_wall.active.frames",            "1"                     },
+
+  { "invisible_sand",                          "RocksSP.pcx"           },
+  { "invisible_sand.xpos",                     "6"                     },
+  { "invisible_sand.ypos",                     "5"                     },
+  { "invisible_sand.frames",                   "1"                     },
+  { "invisible_sand.EDITOR",                   "RocksSP.pcx"           },
+  { "invisible_sand.EDITOR.xpos",              "2"                     },
+  { "invisible_sand.EDITOR.ypos",              "5"                     },
+  { "invisible_sand.active",                   "RocksSP.pcx"           },
+  { "invisible_sand.active.xpos",              "2"                     },
+  { "invisible_sand.active.ypos",              "5"                     },
+  { "invisible_sand.active.frames",            "1"                     },
+
+  { "conveyor_belt_1_middle",                  "RocksDC.pcx"           },
+  { "conveyor_belt_1_middle.xpos",             "0"                     },
+  { "conveyor_belt_1_middle.ypos",             "0"                     },
+  { "conveyor_belt_1_middle.frames",           "1"                     },
+  { "conveyor_belt_1_middle.active",           "RocksDC.pcx"           },
+  { "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.pcx"           },
+  { "conveyor_belt_1_left.xpos",               "0"                     },
+  { "conveyor_belt_1_left.ypos",               "1"                     },
+  { "conveyor_belt_1_left.frames",             "1"                     },
+  { "conveyor_belt_1_left.active",             "RocksDC.pcx"           },
+  { "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.pcx"           },
+  { "conveyor_belt_1_right.xpos",              "0"                     },
+  { "conveyor_belt_1_right.ypos",              "2"                     },
+  { "conveyor_belt_1_right.frames",            "1"                     },
+  { "conveyor_belt_1_right.active",            "RocksDC.pcx"           },
+  { "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.pcx"           },
+  { "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.pcx"           },
+  { "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.pcx"           },
+  { "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.pcx"           },
+  { "conveyor_belt_2_middle.xpos",             "0"                     },
+  { "conveyor_belt_2_middle.ypos",             "3"                     },
+  { "conveyor_belt_2_middle.frames",           "1"                     },
+  { "conveyor_belt_2_middle.active",           "RocksDC.pcx"           },
+  { "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.pcx"           },
+  { "conveyor_belt_2_left.xpos",               "0"                     },
+  { "conveyor_belt_2_left.ypos",               "4"                     },
+  { "conveyor_belt_2_left.frames",             "1"                     },
+  { "conveyor_belt_2_left.active",             "RocksDC.pcx"           },
+  { "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.pcx"           },
+  { "conveyor_belt_2_right.xpos",              "0"                     },
+  { "conveyor_belt_2_right.ypos",              "5"                     },
+  { "conveyor_belt_2_right.frames",            "1"                     },
+  { "conveyor_belt_2_right.active",            "RocksDC.pcx"           },
+  { "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.pcx"           },
+  { "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.pcx"           },
+  { "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.pcx"           },
+  { "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.pcx"           },
+  { "conveyor_belt_3_middle.xpos",             "0"                     },
+  { "conveyor_belt_3_middle.ypos",             "6"                     },
+  { "conveyor_belt_3_middle.frames",           "1"                     },
+  { "conveyor_belt_3_middle.active",           "RocksDC.pcx"           },
+  { "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.pcx"           },
+  { "conveyor_belt_3_left.xpos",               "0"                     },
+  { "conveyor_belt_3_left.ypos",               "7"                     },
+  { "conveyor_belt_3_left.frames",             "1"                     },
+  { "conveyor_belt_3_left.active",             "RocksDC.pcx"           },
+  { "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.pcx"           },
+  { "conveyor_belt_3_right.xpos",              "0"                     },
+  { "conveyor_belt_3_right.ypos",              "8"                     },
+  { "conveyor_belt_3_right.frames",            "1"                     },
+  { "conveyor_belt_3_right.active",            "RocksDC.pcx"           },
+  { "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.pcx"           },
+  { "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.pcx"           },
+  { "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.pcx"           },
+  { "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.pcx"           },
+  { "conveyor_belt_4_middle.xpos",             "0"                     },
+  { "conveyor_belt_4_middle.ypos",             "9"                     },
+  { "conveyor_belt_4_middle.frames",           "1"                     },
+  { "conveyor_belt_4_middle.active",           "RocksDC.pcx"           },
+  { "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.pcx"           },
+  { "conveyor_belt_4_left.xpos",               "0"                     },
+  { "conveyor_belt_4_left.ypos",               "10"                    },
+  { "conveyor_belt_4_left.frames",             "1"                     },
+  { "conveyor_belt_4_left.active",             "RocksDC.pcx"           },
+  { "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.pcx"           },
+  { "conveyor_belt_4_right.xpos",              "0"                     },
+  { "conveyor_belt_4_right.ypos",              "11"                    },
+  { "conveyor_belt_4_right.frames",            "1"                     },
+  { "conveyor_belt_4_right.active",            "RocksDC.pcx"           },
+  { "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.pcx"           },
+  { "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.pcx"           },
+  { "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.pcx"           },
+  { "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.pcx"           },
+  { "switchgate_switch_up.xpos",               "4"                     },
+  { "switchgate_switch_up.ypos",               "12"                    },
+  { "switchgate_switch_up.frames",             "1"                     },
+  { "switchgate_switch_down",                  "RocksDC.pcx"           },
+  { "switchgate_switch_down.xpos",             "5"                     },
+  { "switchgate_switch_down.ypos",             "12"                    },
+  { "switchgate_switch_down.frames",           "1"                     },
+
+  { "light_switch",                            "RocksDC.pcx"           },
+  { "light_switch.xpos",                       "6"                     },
+  { "light_switch.ypos",                       "12"                    },
+  { "light_switch.frames",                     "1"                     },
+  { "light_switch.active",                     "RocksDC.pcx"           },
+  { "light_switch.active.xpos",                        "7"                     },
+  { "light_switch.active.ypos",                        "12"                    },
+  { "light_switch.active.frames",              "1"                     },
+
+  { "timegate_switch",                         "RocksDC.pcx"           },
+  { "timegate_switch.xpos",                    "0"                     },
+  { "timegate_switch.ypos",                    "15"                    },
+  { "timegate_switch.frames",                  "1"                     },
+  { "timegate_switch.active",                  "RocksDC.pcx"           },
+  { "timegate_switch.active.xpos",             "0"                     },
+  { "timegate_switch.active.ypos",             "15"                    },
+  { "timegate_switch.active.frames",           "4"                     },
+
+  { "envelope",                                        "RocksDC.pcx"           },
+  { "envelope.xpos",                           "4"                     },
+  { "envelope.ypos",                           "14"                    },
+  { "envelope.frames",                         "1"                     },
+
+  { "sign_exclamation",                                "RocksDC.pcx"           },
+  { "sign_exclamation.xpos",                   "5"                     },
+  { "sign_exclamation.ypos",                   "14"                    },
+  { "sign_exclamation.frames",                 "1"                     },
+
+  { "sign_stop",                               "RocksDC.pcx"           },
+  { "sign_stop.xpos",                          "6"                     },
+  { "sign_stop.ypos",                          "14"                    },
+  { "sign_stop.frames",                                "1"                     },
+
+  { "landmine",                                        "RocksDC.pcx"           },
+  { "landmine.xpos",                           "7"                     },
+  { "landmine.ypos",                           "14"                    },
+  { "landmine.frames",                         "1"                     },
+  { "landmine.crumbled_like",                  "sand"                  },
+
+  { "steelwall_slippery",                      "RocksDC.pcx"           },
+  { "steelwall_slippery.xpos",                 "5"                     },
+  { "steelwall_slippery.ypos",                 "15"                    },
+  { "steelwall_slippery.frames",               "1"                     },
+
+  { "extra_time",                              "RocksDC.pcx"           },
+  { "extra_time.xpos",                         "8"                     },
+  { "extra_time.ypos",                         "0"                     },
+  { "extra_time.frames",                       "6"                     },
+  { "extra_time.delay",                                "4"                     },
+
+  { "shield_normal",                           "RocksDC.pcx"           },
+  { "shield_normal.xpos",                      "8"                     },
+  { "shield_normal.ypos",                      "2"                     },
+  { "shield_normal.frames",                    "6"                     },
+  { "shield_normal.delay",                     "4"                     },
+  { "shield_normal.active",                    "RocksHeroes.pcx"       },
+  { "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_deadly",                           "RocksDC.pcx"           },
+  { "shield_deadly.xpos",                      "8"                     },
+  { "shield_deadly.ypos",                      "1"                     },
+  { "shield_deadly.frames",                    "6"                     },
+  { "shield_deadly.delay",                     "4"                     },
+  { "shield_deadly.active",                    "RocksHeroes.pcx"       },
+  { "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"              },
+
+  { "switchgate_closed",                       "RocksDC.pcx"           },
+  { "switchgate_closed.xpos",                  "8"                     },
+  { "switchgate_closed.ypos",                  "5"                     },
+  { "switchgate_closed.frames",                        "1"                     },
+  { "switchgate.opening",                      "RocksDC.pcx"           },
+  { "switchgate.opening.xpos",                 "8"                     },
+  { "switchgate.opening.ypos",                 "5"                     },
+  { "switchgate.opening.frames",               "5"                     },
+  { "switchgate.opening.delay",                        "6"                     },
+  { "switchgate_open",                         "RocksDC.pcx"           },
+  { "switchgate_open.xpos",                    "12"                    },
+  { "switchgate_open.ypos",                    "5"                     },
+  { "switchgate_open.frames",                  "1"                     },
+  { "switchgate.closing",                      "RocksDC.pcx"           },
+  { "switchgate.closing.xpos",                 "8"                     },
+  { "switchgate.closing.ypos",                 "5"                     },
+  { "switchgate.closing.frames",               "5"                     },
+  { "switchgate.closing.delay",                        "6"                     },
+  { "switchgate.closing.anim_mode",            "reverse"               },
+
+  { "timegate_closed",                         "RocksDC.pcx"           },
+  { "timegate_closed.xpos",                    "8"                     },
+  { "timegate_closed.ypos",                    "6"                     },
+  { "timegate_closed.frames",                  "1"                     },
+  { "timegate.opening",                                "RocksDC.pcx"           },
+  { "timegate.opening.xpos",                   "8"                     },
+  { "timegate.opening.ypos",                   "6"                     },
+  { "timegate.opening.frames",                 "5"                     },
+  { "timegate.opening.delay",                  "6"                     },
+  { "timegate_open",                           "RocksDC.pcx"           },
+  { "timegate_open.xpos",                      "12"                    },
+  { "timegate_open.ypos",                      "6"                     },
+  { "timegate_open.frames",                    "1"                     },
+  { "timegate.closing",                                "RocksDC.pcx"           },
+  { "timegate.closing.xpos",                   "8"                     },
+  { "timegate.closing.ypos",                   "6"                     },
+  { "timegate.closing.frames",                 "5"                     },
+  { "timegate.closing.delay",                  "6"                     },
+  { "timegate.closing.anim_mode",              "reverse"               },
+
+  { "pearl",                                   "RocksDC.pcx"           },
+  { "pearl.xpos",                              "8"                     },
+  { "pearl.ypos",                              "11"                    },
+  { "pearl.frames",                            "1"                     },
+  { "pearl.breaking",                          "RocksDC.pcx"           },
+  { "pearl.breaking.xpos",                     "8"                     },
+  { "pearl.breaking.ypos",                     "12"                    },
+  { "pearl.breaking.frames",                   "4"                     },
+  { "pearl.breaking.delay",                    "2"                     },
+  { "pearl.breaking.anim_mode",                        "linear"                },
+
+  { "crystal",                                 "RocksDC.pcx"           },
+  { "crystal.xpos",                            "9"                     },
+  { "crystal.ypos",                            "11"                    },
+  { "crystal.frames",                          "1"                     },
+
+  { "wall_pearl",                              "RocksDC.pcx"           },
+  { "wall_pearl.xpos",                         "10"                    },
+  { "wall_pearl.ypos",                         "11"                    },
+  { "wall_pearl.frames",                       "1"                     },
+
+  { "wall_crystal",                            "RocksDC.pcx"           },
+  { "wall_crystal.xpos",                       "11"                    },
+  { "wall_crystal.ypos",                       "11"                    },
+  { "wall_crystal.frames",                     "1"                     },
+
+  /* images for DX Boulderdash style elements and actions */
+
+  { "tube_right_down",                         "RocksDC.pcx"           },
+  { "tube_right_down.xpos",                    "9"                     },
+  { "tube_right_down.ypos",                    "13"                    },
+  { "tube_right_down.frames",                  "1"                     },
+
+  { "tube_horizontal_down",                    "RocksDC.pcx"           },
+  { "tube_horizontal_down.xpos",               "10"                    },
+  { "tube_horizontal_down.ypos",               "13"                    },
+  { "tube_horizontal_down.frames",             "1"                     },
+
+  { "tube_left_down",                          "RocksDC.pcx"           },
+  { "tube_left_down.xpos",                     "11"                    },
+  { "tube_left_down.ypos",                     "13"                    },
+  { "tube_left_down.frames",                   "1"                     },
+
+  { "tube_horizontal",                         "RocksDC.pcx"           },
+  { "tube_horizontal.xpos",                    "8"                     },
+  { "tube_horizontal.ypos",                    "14"                    },
+  { "tube_horizontal.frames",                  "1"                     },
+
+  { "tube_vertical_right",                     "RocksDC.pcx"           },
+  { "tube_vertical_right.xpos",                        "9"                     },
+  { "tube_vertical_right.ypos",                        "14"                    },
+  { "tube_vertical_right.frames",              "1"                     },
+
+  { "tube_any",                                        "RocksDC.pcx"           },
+  { "tube_any.xpos",                           "10"                    },
+  { "tube_any.ypos",                           "14"                    },
+  { "tube_any.frames",                         "1"                     },
+
+  { "tube_vertical_left",                      "RocksDC.pcx"           },
+  { "tube_vertical_left.xpos",                 "11"                    },
+  { "tube_vertical_left.ypos",                 "14"                    },
+  { "tube_vertical_left.frames",               "1"                     },
+
+  { "tube_vertical",                           "RocksDC.pcx"           },
+  { "tube_vertical.xpos",                      "8"                     },
+  { "tube_vertical.ypos",                      "15"                    },
+  { "tube_vertical.frames",                    "1"                     },
+
+  { "tube_right_up",                           "RocksDC.pcx"           },
+  { "tube_right_up.xpos",                      "9"                     },
+  { "tube_right_up.ypos",                      "15"                    },
+  { "tube_right_up.frames",                    "1"                     },
+
+  { "tube_horizontal_up",                      "RocksDC.pcx"           },
+  { "tube_horizontal_up.xpos",                 "10"                    },
+  { "tube_horizontal_up.ypos",                 "15"                    },
+  { "tube_horizontal_up.frames",               "1"                     },
+
+  { "tube_left_up",                            "RocksDC.pcx"           },
+  { "tube_left_up.xpos",                       "11"                    },
+  { "tube_left_up.ypos",                       "15"                    },
+  { "tube_left_up.frames",                     "1"                     },
+
+  { "trap",                                    "RocksDC.pcx"           },
+  { "trap.xpos",                               "12"                    },
+  { "trap.ypos",                               "8"                     },
+  { "trap.frames",                             "1"                     },
+  { "trap.crumbled_like",                      "sand"                  },
+  { "trap.diggable_like",                      "sand"                  },
+  { "trap.active",                             "RocksDC.pcx"           },
+  { "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.pcx"           },
+  { "dx_supabomb.xpos",                                "15"                    },
+  { "dx_supabomb.ypos",                                "9"                     },
+  { "dx_supabomb.frames",                      "1"                     },
+
+  /* images for Rocks'n'Diamonds style elements and actions */
+
+  { "key_1",                                   "RocksElements.pcx"     },
+  { "key_1.xpos",                              "4"                     },
+  { "key_1.ypos",                              "1"                     },
+  { "key_1.frames",                            "1"                     },
+  { "key_1.EDITOR",                            "RocksElements.pcx"     },
+  { "key_1.EDITOR.xpos",                       "4"                     },
+  { "key_1.EDITOR.ypos",                       "14"                    },
+  { "key_2",                                   "RocksElements.pcx"     },
+  { "key_2.xpos",                              "5"                     },
+  { "key_2.ypos",                              "1"                     },
+  { "key_2.frames",                            "1"                     },
+  { "key_2.EDITOR",                            "RocksElements.pcx"     },
+  { "key_2.EDITOR.xpos",                       "5"                     },
+  { "key_2.EDITOR.ypos",                       "14"                    },
+  { "key_3",                                   "RocksElements.pcx"     },
+  { "key_3.xpos",                              "6"                     },
+  { "key_3.ypos",                              "1"                     },
+  { "key_3.frames",                            "1"                     },
+  { "key_3.EDITOR",                            "RocksElements.pcx"     },
+  { "key_3.EDITOR.xpos",                       "6"                     },
+  { "key_3.EDITOR.ypos",                       "14"                    },
+  { "key_4",                                   "RocksElements.pcx"     },
+  { "key_4.xpos",                              "7"                     },
+  { "key_4.ypos",                              "1"                     },
+  { "key_4.frames",                            "1"                     },
+  { "key_4.EDITOR",                            "RocksElements.pcx"     },
+  { "key_4.EDITOR.xpos",                       "7"                     },
+  { "key_4.EDITOR.ypos",                       "14"                    },
+
+  { "gate_1",                                  "RocksElements.pcx"     },
+  { "gate_1.xpos",                             "4"                     },
+  { "gate_1.ypos",                             "2"                     },
+  { "gate_1.frames",                           "1"                     },
+  { "gate_2",                                  "RocksElements.pcx"     },
+  { "gate_2.xpos",                             "5"                     },
+  { "gate_2.ypos",                             "2"                     },
+  { "gate_2.frames",                           "1"                     },
+  { "gate_3",                                  "RocksElements.pcx"     },
+  { "gate_3.xpos",                             "6"                     },
+  { "gate_3.ypos",                             "2"                     },
+  { "gate_3.frames",                           "1"                     },
+  { "gate_4",                                  "RocksElements.pcx"     },
+  { "gate_4.xpos",                             "7"                     },
+  { "gate_4.ypos",                             "2"                     },
+  { "gate_4.frames",                           "1"                     },
+  { "gate_1_gray",                             "RocksElements.pcx"     },
+  { "gate_1_gray.xpos",                                "8"                     },
+  { "gate_1_gray.ypos",                                "2"                     },
+  { "gate_1_gray.frames",                      "1"                     },
+  { "gate_1_gray.EDITOR",                      "RocksElements.pcx"     },
+  { "gate_1_gray.EDITOR.xpos",                 "8"                     },
+  { "gate_1_gray.EDITOR.ypos",                 "14"                    },
+  { "gate_2_gray",                             "RocksElements.pcx"     },
+  { "gate_2_gray.xpos",                                "9"                     },
+  { "gate_2_gray.ypos",                                "2"                     },
+  { "gate_2_gray.frames",                      "1"                     },
+  { "gate_2_gray.EDITOR",                      "RocksElements.pcx"     },
+  { "gate_2_gray.EDITOR.xpos",                 "9"                     },
+  { "gate_2_gray.EDITOR.ypos",                 "14"                    },
+  { "gate_3_gray",                             "RocksElements.pcx"     },
+  { "gate_3_gray.xpos",                                "10"                    },
+  { "gate_3_gray.ypos",                                "2"                     },
+  { "gate_3_gray.frames",                      "1"                     },
+  { "gate_3_gray.EDITOR",                      "RocksElements.pcx"     },
+  { "gate_3_gray.EDITOR.xpos",                 "10"                    },
+  { "gate_3_gray.EDITOR.ypos",                 "14"                    },
+  { "gate_4_gray",                             "RocksElements.pcx"     },
+  { "gate_4_gray.xpos",                                "11"                    },
+  { "gate_4_gray.ypos",                                "2"                     },
+  { "gate_4_gray.frames",                      "1"                     },
+  { "gate_4_gray.EDITOR",                      "RocksElements.pcx"     },
+  { "gate_4_gray.EDITOR.xpos",                 "11"                    },
+  { "gate_4_gray.EDITOR.ypos",                 "14"                    },
+
+  { "game_of_life",                            "RocksElements.pcx"     },
+  { "game_of_life.xpos",                       "8"                     },
+  { "game_of_life.ypos",                       "1"                     },
+  { "game_of_life.frames",                     "1"                     },
+
+  { "biomaze",                                 "RocksElements.pcx"     },
+  { "biomaze.xpos",                            "9"                     },
+  { "biomaze.ypos",                            "1"                     },
+  { "biomaze.frames",                          "1"                     },
+
+  { "pacman",                                  "RocksElements.pcx"     },
+  { "pacman.xpos",                             "8"                     },
+  { "pacman.ypos",                             "5"                     },
+  { "pacman.frames",                           "4"                     },
+  { "pacman.delay",                            "8"                     },
+  { "pacman.right",                            "RocksElements.pcx"     },
+  { "pacman.right.xpos",                       "8"                     },
+  { "pacman.right.ypos",                       "5"                     },
+  { "pacman.right.frames",                     "1"                     },
+  { "pacman.up",                               "RocksElements.pcx"     },
+  { "pacman.up.xpos",                          "9"                     },
+  { "pacman.up.ypos",                          "5"                     },
+  { "pacman.up.frames",                                "1"                     },
+  { "pacman.left",                             "RocksElements.pcx"     },
+  { "pacman.left.xpos",                                "10"                    },
+  { "pacman.left.ypos",                                "5"                     },
+  { "pacman.left.frames",                      "1"                     },
+  { "pacman.down",                             "RocksElements.pcx"     },
+  { "pacman.down.xpos",                                "11"                    },
+  { "pacman.down.ypos",                                "5"                     },
+  { "pacman.down.frames",                      "1"                     },
+  { "pacman.moving.right",                     "RocksElements.pcx"     },
+  { "pacman.moving.right.xpos",                        "8"                     },
+  { "pacman.moving.right.ypos",                        "5"                     },
+  { "pacman.moving.right.frames",              "2"                     },
+  { "pacman.moving.right.anim_mode",           "reverse"               },
+  { "pacman.moving.right.delay",               "4"                     },
+  { "pacman.moving.right.offset",              "128"                   },
+  { "pacman.moving.up",                                "RocksElements.pcx"     },
+  { "pacman.moving.up.xpos",                   "9"                     },
+  { "pacman.moving.up.ypos",                   "5"                     },
+  { "pacman.moving.up.frames",                 "2"                     },
+  { "pacman.moving.up.anim_mode",              "reverse"               },
+  { "pacman.moving.up.delay",                  "4"                     },
+  { "pacman.moving.up.offset",                 "128"                   },
+  { "pacman.moving.left",                      "RocksElements.pcx"     },
+  { "pacman.moving.left.xpos",                 "10"                    },
+  { "pacman.moving.left.ypos",                 "5"                     },
+  { "pacman.moving.left.frames",               "2"                     },
+  { "pacman.moving.left.anim_mode",            "reverse"               },
+  { "pacman.moving.left.delay",                        "4"                     },
+  { "pacman.moving.left.offset",               "128"                   },
+  { "pacman.moving.down",                      "RocksElements.pcx"     },
+  { "pacman.moving.down.xpos",                 "11"                    },
+  { "pacman.moving.down.ypos",                 "5"                     },
+  { "pacman.moving.down.frames",               "2"                     },
+  { "pacman.moving.down.anim_mode",            "reverse"               },
+  { "pacman.moving.down.delay",                        "4"                     },
+  { "pacman.moving.down.offset",               "128"                   },
+
+  { "lamp",                                    "RocksElements.pcx"     },
+  { "lamp.xpos",                               "0"                     },
+  { "lamp.ypos",                               "7"                     },
+  { "lamp.frames",                             "1"                     },
+  { "lamp.EDITOR",                             "RocksElements.pcx"     },
+  { "lamp.EDITOR.xpos",                                "2"                     },
+  { "lamp.EDITOR.ypos",                                "14"                    },
+  { "lamp.active",                             "RocksElements.pcx"     },
+  { "lamp.active.xpos",                                "1"                     },
+  { "lamp.active.ypos",                                "7"                     },
+  { "lamp.active.frames",                      "1"                     },
+
+  { "time_orb_full",                           "RocksElements.pcx"     },
+  { "time_orb_full.xpos",                      "2"                     },
+  { "time_orb_full.ypos",                      "7"                     },
+  { "time_orb_full.frames",                    "1"                     },
+  { "time_orb_empty",                          "RocksElements.pcx"     },
+  { "time_orb_empty.xpos",                     "3"                     },
+  { "time_orb_empty.ypos",                     "7"                     },
+  { "time_orb_empty.frames",                   "1"                     },
+
+  { "emerald_yellow",                          "RocksElements.pcx"     },
+  { "emerald_yellow.xpos",                     "10"                    },
+  { "emerald_yellow.ypos",                     "8"                     },
+  { "emerald_yellow.frames",                   "1"                     },
+  { "emerald_yellow.moving",                   "RocksElements.pcx"     },
+  { "emerald_yellow.moving.xpos",              "10"                    },
+  { "emerald_yellow.moving.ypos",              "8"                     },
+  { "emerald_yellow.moving.frames",            "2"                     },
+  { "emerald_yellow.moving.delay",             "4"                     },
+  { "emerald_yellow.falling",                  "RocksElements.pcx"     },
+  { "emerald_yellow.falling.xpos",             "10"                    },
+  { "emerald_yellow.falling.ypos",             "8"                     },
+  { "emerald_yellow.falling.frames",           "2"                     },
+  { "emerald_yellow.falling.delay",            "4"                     },
+  { "emerald_red",                             "RocksElements.pcx"     },
+  { "emerald_red.xpos",                                "8"                     },
+  { "emerald_red.ypos",                                "9"                     },
+  { "emerald_red.frames",                      "1"                     },
+  { "emerald_red.moving",                      "RocksElements.pcx"     },
+  { "emerald_red.moving.xpos",                 "8"                     },
+  { "emerald_red.moving.ypos",                 "9"                     },
+  { "emerald_red.moving.frames",               "2"                     },
+  { "emerald_red.moving.delay",                        "4"                     },
+  { "emerald_red.falling",                     "RocksElements.pcx"     },
+  { "emerald_red.falling.xpos",                        "8"                     },
+  { "emerald_red.falling.ypos",                        "9"                     },
+  { "emerald_red.falling.frames",              "2"                     },
+  { "emerald_red.falling.delay",               "4"                     },
+  { "emerald_purple",                          "RocksElements.pcx"     },
+  { "emerald_purple.xpos",                     "10"                    },
+  { "emerald_purple.ypos",                     "9"                     },
+  { "emerald_purple.frames",                   "1"                     },
+  { "emerald_purple.moving",                   "RocksElements.pcx"     },
+  { "emerald_purple.moving.xpos",              "10"                    },
+  { "emerald_purple.moving.ypos",              "9"                     },
+  { "emerald_purple.moving.frames",            "2"                     },
+  { "emerald_purple.moving.delay",             "4"                     },
+  { "emerald_purple.falling",                  "RocksElements.pcx"     },
+  { "emerald_purple.falling.xpos",             "10"                    },
+  { "emerald_purple.falling.ypos",             "9"                     },
+  { "emerald_purple.falling.frames",           "2"                     },
+  { "emerald_purple.falling.delay",            "4"                     },
+
+  { "wall_emerald_yellow",                     "RocksElements.pcx"     },
+  { "wall_emerald_yellow.xpos",                        "8"                     },
+  { "wall_emerald_yellow.ypos",                        "8"                     },
+  { "wall_emerald_yellow.frames",              "1"                     },
+  { "wall_emerald_red",                                "RocksElements.pcx"     },
+  { "wall_emerald_red.xpos",                   "6"                     },
+  { "wall_emerald_red.ypos",                   "8"                     },
+  { "wall_emerald_red.frames",                 "1"                     },
+  { "wall_emerald_purple",                     "RocksElements.pcx"     },
+  { "wall_emerald_purple.xpos",                        "7"                     },
+  { "wall_emerald_purple.ypos",                        "8"                     },
+  { "wall_emerald_purple.frames",              "1"                     },
+  { "wall_bd_diamond",                         "RocksElements.pcx"     },
+  { "wall_bd_diamond.xpos",                    "9"                     },
+  { "wall_bd_diamond.ypos",                    "8"                     },
+  { "wall_bd_diamond.frames",                  "1"                     },
+
+  { "expandable_wall",                         "RocksElements.pcx"     },
+  { "expandable_wall.xpos",                    "11"                    },
+  { "expandable_wall.ypos",                    "10"                    },
+  { "expandable_wall.frames",                  "1"                     },
+  { "expandable_wall_horizontal",              "RocksElements.pcx"     },
+  { "expandable_wall_horizontal.xpos",         "5"                     },
+  { "expandable_wall_horizontal.ypos",         "9"                     },
+  { "expandable_wall_horizontal.frames",       "1"                     },
+  { "expandable_wall_horizontal.EDITOR",       "RocksElements.pcx"     },
+  { "expandable_wall_horizontal.EDITOR.xpos",  "13"                    },
+  { "expandable_wall_horizontal.EDITOR.ypos",  "13"                    },
+  { "expandable_wall_vertical",                        "RocksElements.pcx"     },
+  { "expandable_wall_vertical.xpos",           "6"                     },
+  { "expandable_wall_vertical.ypos",           "9"                     },
+  { "expandable_wall_vertical.frames",         "1"                     },
+  { "expandable_wall_vertical.EDITOR",         "RocksElements.pcx"     },
+  { "expandable_wall_vertical.EDITOR.xpos",    "14"                    },
+  { "expandable_wall_vertical.EDITOR.ypos",    "13"                    },
+  { "expandable_wall_any",                     "RocksElements.pcx"     },
+  { "expandable_wall_any.xpos",                        "4"                     },
+  { "expandable_wall_any.ypos",                        "9"                     },
+  { "expandable_wall_any.frames",              "1"                     },
+  { "expandable_wall_any.EDITOR",              "RocksElements.pcx"     },
+  { "expandable_wall_any.EDITOR.xpos",         "12"                    },
+  { "expandable_wall_any.EDITOR.ypos",         "13"                    },
+
+  { "expandable_wall.growing.left",            "RocksElements.pcx"     },
+  { "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.pcx"     },
+  { "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.pcx"       },
+  { "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.pcx"       },
+  { "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"                },
+
+  { "black_orb",                               "RocksElements.pcx"     },
+  { "black_orb.xpos",                          "13"                    },
+  { "black_orb.ypos",                          "9"                     },
+  { "black_orb.frames",                                "1"                     },
+
+  { "speed_pill",                              "RocksElements.pcx"     },
+  { "speed_pill.xpos",                         "14"                    },
+  { "speed_pill.ypos",                         "9"                     },
+  { "speed_pill.frames",                       "1"                     },
+
+  { "dark_yamyam",                             "RocksElements.pcx"     },
+  { "dark_yamyam.xpos",                                "8"                     },
+  { "dark_yamyam.ypos",                                "11"                    },
+  { "dark_yamyam.frames",                      "4"                     },
+  { "dark_yamyam.anim_mode",                   "pingpong2"             },
+
+  { "dynabomb",                                        "RocksElements.pcx"     },
+  { "dynabomb.xpos",                           "12"                    },
+  { "dynabomb.ypos",                           "11"                    },
+  { "dynabomb.frames",                         "1"                     },
+  { "dynabomb.active",                         "RocksElements.pcx"     },
+  { "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.pcx"     },
+  { "dynabomb_player_1.xpos",                  "12"                    },
+  { "dynabomb_player_1.ypos",                  "11"                    },
+  { "dynabomb_player_1.frames",                        "1"                     },
+  { "dynabomb_player_1.active",                        "RocksElements.pcx"     },
+  { "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.pcx"     },
+  { "dynabomb_player_2.xpos",                  "12"                    },
+  { "dynabomb_player_2.ypos",                  "11"                    },
+  { "dynabomb_player_2.frames",                        "1"                     },
+  { "dynabomb_player_2.active",                        "RocksElements.pcx"     },
+  { "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.pcx"     },
+  { "dynabomb_player_3.xpos",                  "12"                    },
+  { "dynabomb_player_3.ypos",                  "11"                    },
+  { "dynabomb_player_3.frames",                        "1"                     },
+  { "dynabomb_player_3.active",                        "RocksElements.pcx"     },
+  { "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.pcx"     },
+  { "dynabomb_player_4.xpos",                  "12"                    },
+  { "dynabomb_player_4.ypos",                  "11"                    },
+  { "dynabomb_player_4.frames",                        "1"                     },
+  { "dynabomb_player_4.active",                        "RocksElements.pcx"     },
+  { "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.pcx"     },
+  { "dynabomb_increase_number.xpos",           "12"                    },
+  { "dynabomb_increase_number.ypos",           "11"                    },
+  { "dynabomb_increase_number.frames",         "1"                     },
+  { "dynabomb_increase_size",                  "RocksElements.pcx"     },
+  { "dynabomb_increase_size.xpos",             "15"                    },
+  { "dynabomb_increase_size.ypos",             "11"                    },
+  { "dynabomb_increase_size.frames",           "1"                     },
+  { "dynabomb_increase_power",                 "RocksElements.pcx"     },
+  { "dynabomb_increase_power.xpos",            "12"                    },
+  { "dynabomb_increase_power.ypos",            "9"                     },
+  { "dynabomb_increase_power.frames",          "1"                     },
+
+  { "pig",                                     "RocksHeroes.pcx"       },
+  { "pig.xpos",                                        "8"                     },
+  { "pig.ypos",                                        "0"                     },
+  { "pig.frames",                              "1"                     },
+  { "pig.down",                                        "RocksHeroes.pcx"       },
+  { "pig.down.xpos",                           "8"                     },
+  { "pig.down.ypos",                           "0"                     },
+  { "pig.down.frames",                         "1"                     },
+  { "pig.up",                                  "RocksHeroes.pcx"       },
+  { "pig.up.xpos",                             "12"                    },
+  { "pig.up.ypos",                             "0"                     },
+  { "pig.up.frames",                           "1"                     },
+  { "pig.left",                                        "RocksHeroes.pcx"       },
+  { "pig.left.xpos",                           "8"                     },
+  { "pig.left.ypos",                           "1"                     },
+  { "pig.left.frames",                         "1"                     },
+  { "pig.right",                               "RocksHeroes.pcx"       },
+  { "pig.right.xpos",                          "12"                    },
+  { "pig.right.ypos",                          "1"                     },
+  { "pig.right.frames",                                "1"                     },
+  { "pig.moving.down",                         "RocksHeroes.pcx"       },
+  { "pig.moving.down.xpos",                    "8"                     },
+  { "pig.moving.down.ypos",                    "0"                     },
+  { "pig.moving.down.frames",                  "4"                     },
+  { "pig.moving.down.delay",                   "2"                     },
+  { "pig.moving.up",                           "RocksHeroes.pcx"       },
+  { "pig.moving.up.xpos",                      "12"                    },
+  { "pig.moving.up.ypos",                      "0"                     },
+  { "pig.moving.up.frames",                    "4"                     },
+  { "pig.moving.up.delay",                     "2"                     },
+  { "pig.moving.left",                         "RocksHeroes.pcx"       },
+  { "pig.moving.left.xpos",                    "8"                     },
+  { "pig.moving.left.ypos",                    "1"                     },
+  { "pig.moving.left.frames",                  "4"                     },
+  { "pig.moving.left.delay",                   "2"                     },
+  { "pig.moving.right",                                "RocksHeroes.pcx"       },
+  { "pig.moving.right.xpos",                   "12"                    },
+  { "pig.moving.right.ypos",                   "1"                     },
+  { "pig.moving.right.frames",                 "4"                     },
+  { "pig.moving.right.delay",                  "2"                     },
+  { "pig.digging.down",                                "RocksHeroes.pcx"       },
+  { "pig.digging.down.xpos",                   "8"                     },
+  { "pig.digging.down.ypos",                   "0"                     },
+  { "pig.digging.down.frames",                 "4"                     },
+  { "pig.digging.down.delay",                  "2"                     },
+  { "pig.digging.up",                          "RocksHeroes.pcx"       },
+  { "pig.digging.up.xpos",                     "12"                    },
+  { "pig.digging.up.ypos",                     "0"                     },
+  { "pig.digging.up.frames",                   "4"                     },
+  { "pig.digging.up.delay",                    "2"                     },
+  { "pig.digging.left",                                "RocksHeroes.pcx"       },
+  { "pig.digging.left.xpos",                   "8"                     },
+  { "pig.digging.left.ypos",                   "1"                     },
+  { "pig.digging.left.frames",                 "4"                     },
+  { "pig.digging.left.delay",                  "2"                     },
+  { "pig.digging.right",                       "RocksHeroes.pcx"       },
+  { "pig.digging.right.xpos",                  "12"                    },
+  { "pig.digging.right.ypos",                  "1"                     },
+  { "pig.digging.right.frames",                        "4"                     },
+  { "pig.digging.right.delay",                 "2"                     },
+
+  { "dragon",                                  "RocksHeroes.pcx"       },
+  { "dragon.xpos",                             "8"                     },
+  { "dragon.ypos",                             "2"                     },
+  { "dragon.frames",                           "1"                     },
+  { "dragon.down",                             "RocksHeroes.pcx"       },
+  { "dragon.down.xpos",                                "8"                     },
+  { "dragon.down.ypos",                                "2"                     },
+  { "dragon.down.frames",                      "1"                     },
+  { "dragon.up",                               "RocksHeroes.pcx"       },
+  { "dragon.up.xpos",                          "12"                    },
+  { "dragon.up.ypos",                          "2"                     },
+  { "dragon.up.frames",                                "1"                     },
+  { "dragon.left",                             "RocksHeroes.pcx"       },
+  { "dragon.left.xpos",                                "8"                     },
+  { "dragon.left.ypos",                                "3"                     },
+  { "dragon.left.frames",                      "1"                     },
+  { "dragon.right",                            "RocksHeroes.pcx"       },
+  { "dragon.right.xpos",                       "12"                    },
+  { "dragon.right.ypos",                       "3"                     },
+  { "dragon.right.frames",                     "1"                     },
+  { "dragon.moving.down",                      "RocksHeroes.pcx"       },
+  { "dragon.moving.down.xpos",                 "8"                     },
+  { "dragon.moving.down.ypos",                 "2"                     },
+  { "dragon.moving.down.frames",               "4"                     },
+  { "dragon.moving.down.delay",                        "2"                     },
+  { "dragon.moving.up",                                "RocksHeroes.pcx"       },
+  { "dragon.moving.up.xpos",                   "12"                    },
+  { "dragon.moving.up.ypos",                   "2"                     },
+  { "dragon.moving.up.frames",                 "4"                     },
+  { "dragon.moving.up.delay",                  "2"                     },
+  { "dragon.moving.left",                      "RocksHeroes.pcx"       },
+  { "dragon.moving.left.xpos",                 "8"                     },
+  { "dragon.moving.left.ypos",                 "3"                     },
+  { "dragon.moving.left.frames",               "4"                     },
+  { "dragon.moving.left.delay",                        "2"                     },
+  { "dragon.moving.right",                     "RocksHeroes.pcx"       },
+  { "dragon.moving.right.xpos",                        "12"                    },
+  { "dragon.moving.right.ypos",                        "3"                     },
+  { "dragon.moving.right.frames",              "4"                     },
+  { "dragon.moving.right.delay",               "2"                     },
+  { "dragon.attacking.down",                   "RocksHeroes.pcx"       },
+  { "dragon.attacking.down.xpos",              "8"                     },
+  { "dragon.attacking.down.ypos",              "2"                     },
+  { "dragon.attacking.down.frames",            "1"                     },
+  { "dragon.attacking.up",                     "RocksHeroes.pcx"       },
+  { "dragon.attacking.up.xpos",                        "12"                    },
+  { "dragon.attacking.up.ypos",                        "2"                     },
+  { "dragon.attacking.up.frames",              "1"                     },
+  { "dragon.attacking.left",                   "RocksHeroes.pcx"       },
+  { "dragon.attacking.left.xpos",              "8"                     },
+  { "dragon.attacking.left.ypos",              "3"                     },
+  { "dragon.attacking.left.frames",            "1"                     },
+  { "dragon.attacking.right",                  "RocksHeroes.pcx"       },
+  { "dragon.attacking.right.xpos",             "12"                    },
+  { "dragon.attacking.right.ypos",             "3"                     },
+  { "dragon.attacking.right.frames",           "1"                     },
+
+  { "mole",                                    "RocksHeroes.pcx"       },
+  { "mole.xpos",                               "8"                     },
+  { "mole.ypos",                               "4"                     },
+  { "mole.frames",                             "1"                     },
+  { "mole.down",                               "RocksHeroes.pcx"       },
+  { "mole.down.xpos",                          "8"                     },
+  { "mole.down.ypos",                          "4"                     },
+  { "mole.down.frames",                                "1"                     },
+  { "mole.up",                                 "RocksHeroes.pcx"       },
+  { "mole.up.xpos",                            "12"                    },
+  { "mole.up.ypos",                            "4"                     },
+  { "mole.up.frames",                          "1"                     },
+  { "mole.left",                               "RocksHeroes.pcx"       },
+  { "mole.left.xpos",                          "8"                     },
+  { "mole.left.ypos",                          "5"                     },
+  { "mole.left.frames",                                "1"                     },
+  { "mole.right",                              "RocksHeroes.pcx"       },
+  { "mole.right.xpos",                         "12"                    },
+  { "mole.right.ypos",                         "5"                     },
+  { "mole.right.frames",                       "1"                     },
+  { "mole.moving.down",                                "RocksHeroes.pcx"       },
+  { "mole.moving.down.xpos",                   "8"                     },
+  { "mole.moving.down.ypos",                   "4"                     },
+  { "mole.moving.down.frames",                 "4"                     },
+  { "mole.moving.down.delay",                  "2"                     },
+  { "mole.moving.up",                          "RocksHeroes.pcx"       },
+  { "mole.moving.up.xpos",                     "12"                    },
+  { "mole.moving.up.ypos",                     "4"                     },
+  { "mole.moving.up.frames",                   "4"                     },
+  { "mole.moving.up.delay",                    "2"                     },
+  { "mole.moving.left",                                "RocksHeroes.pcx"       },
+  { "mole.moving.left.xpos",                   "8"                     },
+  { "mole.moving.left.ypos",                   "5"                     },
+  { "mole.moving.left.frames",                 "4"                     },
+  { "mole.moving.left.delay",                  "2"                     },
+  { "mole.moving.right",                       "RocksHeroes.pcx"       },
+  { "mole.moving.right.xpos",                  "12"                    },
+  { "mole.moving.right.ypos",                  "5"                     },
+  { "mole.moving.right.frames",                        "4"                     },
+  { "mole.moving.right.delay",                 "2"                     },
+  { "mole.digging.down",                       "RocksHeroes.pcx"       },
+  { "mole.digging.down.xpos",                  "8"                     },
+  { "mole.digging.down.ypos",                  "4"                     },
+  { "mole.digging.down.frames",                        "4"                     },
+  { "mole.digging.down.delay",                 "2"                     },
+  { "mole.digging.up",                         "RocksHeroes.pcx"       },
+  { "mole.digging.up.xpos",                    "12"                    },
+  { "mole.digging.up.ypos",                    "4"                     },
+  { "mole.digging.up.frames",                  "4"                     },
+  { "mole.digging.up.delay",                   "2"                     },
+  { "mole.digging.left",                       "RocksHeroes.pcx"       },
+  { "mole.digging.left.xpos",                  "8"                     },
+  { "mole.digging.left.ypos",                  "5"                     },
+  { "mole.digging.left.frames",                        "4"                     },
+  { "mole.digging.left.delay",                 "2"                     },
+  { "mole.digging.right",                      "RocksHeroes.pcx"       },
+  { "mole.digging.right.xpos",                 "12"                    },
+  { "mole.digging.right.ypos",                 "5"                     },
+  { "mole.digging.right.frames",               "4"                     },
+  { "mole.digging.right.delay",                        "2"                     },
+
+  { "penguin",                                 "RocksHeroes.pcx"       },
+  { "penguin.xpos",                            "8"                     },
+  { "penguin.ypos",                            "6"                     },
+  { "penguin.frames",                          "1"                     },
+  { "penguin.EDITOR",                          "RocksElements.pcx"     },
+  { "penguin.EDITOR.xpos",                     "12"                    },
+  { "penguin.EDITOR.ypos",                     "14"                    },
+  { "penguin.down",                            "RocksHeroes.pcx"       },
+  { "penguin.down.xpos",                       "8"                     },
+  { "penguin.down.ypos",                       "6"                     },
+  { "penguin.down.frames",                     "1"                     },
+  { "penguin.up",                              "RocksHeroes.pcx"       },
+  { "penguin.up.xpos",                         "12"                    },
+  { "penguin.up.ypos",                         "6"                     },
+  { "penguin.up.frames",                       "1"                     },
+  { "penguin.left",                            "RocksHeroes.pcx"       },
+  { "penguin.left.xpos",                       "8"                     },
+  { "penguin.left.ypos",                       "7"                     },
+  { "penguin.left.frames",                     "1"                     },
+  { "penguin.right",                           "RocksHeroes.pcx"       },
+  { "penguin.right.xpos",                      "12"                    },
+  { "penguin.right.ypos",                      "7"                     },
+  { "penguin.right.frames",                    "1"                     },
+  { "penguin.moving.down",                     "RocksHeroes.pcx"       },
+  { "penguin.moving.down.xpos",                        "8"                     },
+  { "penguin.moving.down.ypos",                        "6"                     },
+  { "penguin.moving.down.frames",              "4"                     },
+  { "penguin.moving.down.delay",               "2"                     },
+  { "penguin.moving.up",                       "RocksHeroes.pcx"       },
+  { "penguin.moving.up.xpos",                  "12"                    },
+  { "penguin.moving.up.ypos",                  "6"                     },
+  { "penguin.moving.up.frames",                        "4"                     },
+  { "penguin.moving.up.delay",                 "2"                     },
+  { "penguin.moving.left",                     "RocksHeroes.pcx"       },
+  { "penguin.moving.left.xpos",                        "8"                     },
+  { "penguin.moving.left.ypos",                        "7"                     },
+  { "penguin.moving.left.frames",              "4"                     },
+  { "penguin.moving.left.delay",               "2"                     },
+  { "penguin.moving.right",                    "RocksHeroes.pcx"       },
+  { "penguin.moving.right.xpos",               "12"                    },
+  { "penguin.moving.right.ypos",               "7"                     },
+  { "penguin.moving.right.frames",             "4"                     },
+  { "penguin.moving.right.delay",              "2"                     },
+
+  { "satellite",                               "RocksHeroes.pcx"       },
+  { "satellite.xpos",                          "8"                     },
+  { "satellite.ypos",                          "9"                     },
+  { "satellite.frames",                                "8"                     },
+  { "satellite.delay",                         "2"                     },
+  { "satellite.global_sync",                   "true"                  },
+
+  { "flames_1_left",                           "RocksHeroes.pcx"       },
+  { "flames_1_left.xpos",                      "8"                     },
+  { "flames_1_left.ypos",                      "12"                    },
+  { "flames_1_left.frames",                    "2"                     },
+  { "flames_1_left.offset",                    "96"                    },
+  { "flames_2_left",                           "RocksHeroes.pcx"       },
+  { "flames_2_left.xpos",                      "9"                     },
+  { "flames_2_left.ypos",                      "12"                    },
+  { "flames_2_left.frames",                    "2"                     },
+  { "flames_2_left.offset",                    "96"                    },
+  { "flames_3_left",                           "RocksHeroes.pcx"       },
+  { "flames_3_left.xpos",                      "10"                    },
+  { "flames_3_left.ypos",                      "12"                    },
+  { "flames_3_left.frames",                    "2"                     },
+  { "flames_3_left.offset",                    "96"                    },
+
+  { "flames_1_right",                          "RocksHeroes.pcx"       },
+  { "flames_1_right.xpos",                     "8"                     },
+  { "flames_1_right.ypos",                     "13"                    },
+  { "flames_1_right.frames",                   "2"                     },
+  { "flames_1_right.offset",                   "96"                    },
+  { "flames_2_right",                          "RocksHeroes.pcx"       },
+  { "flames_2_right.xpos",                     "9"                     },
+  { "flames_2_right.ypos",                     "13"                    },
+  { "flames_2_right.frames",                   "2"                     },
+  { "flames_2_right.offset",                   "96"                    },
+  { "flames_3_right",                          "RocksHeroes.pcx"       },
+  { "flames_3_right.xpos",                     "10"                    },
+  { "flames_3_right.ypos",                     "13"                    },
+  { "flames_3_right.frames",                   "2"                     },
+  { "flames_3_right.offset",                   "96"                    },
+
+  { "flames_1_up",                             "RocksHeroes.pcx"       },
+  { "flames_1_up.xpos",                                "8"                     },
+  { "flames_1_up.ypos",                                "14"                    },
+  { "flames_1_up.frames",                      "2"                     },
+  { "flames_1_up.offset",                      "96"                    },
+  { "flames_2_up",                             "RocksHeroes.pcx"       },
+  { "flames_2_up.xpos",                                "9"                     },
+  { "flames_2_up.ypos",                                "14"                    },
+  { "flames_2_up.frames",                      "2"                     },
+  { "flames_2_up.offset",                      "96"                    },
+  { "flames_3_up",                             "RocksHeroes.pcx"       },
+  { "flames_3_up.xpos",                                "10"                    },
+  { "flames_3_up.ypos",                                "14"                    },
+  { "flames_3_up.frames",                      "2"                     },
+  { "flames_3_up.offset",                      "96"                    },
+
+  { "flames_1_down",                           "RocksHeroes.pcx"       },
+  { "flames_1_down.xpos",                      "8"                     },
+  { "flames_1_down.ypos",                      "15"                    },
+  { "flames_1_down.frames",                    "2"                     },
+  { "flames_1_down.offset",                    "96"                    },
+  { "flames_2_down",                           "RocksHeroes.pcx"       },
+  { "flames_2_down.xpos",                      "9"                     },
+  { "flames_2_down.ypos",                      "15"                    },
+  { "flames_2_down.frames",                    "2"                     },
+  { "flames_2_down.offset",                    "96"                    },
+  { "flames_3_down",                           "RocksHeroes.pcx"       },
+  { "flames_3_down.xpos",                      "10"                    },
+  { "flames_3_down.ypos",                      "15"                    },
+  { "flames_3_down.frames",                    "2"                     },
+  { "flames_3_down.offset",                    "96"                    },
+
+  { "stoneblock",                              "RocksElements.pcx"     },
+  { "stoneblock.xpos",                         "10"                    },
+  { "stoneblock.ypos",                         "1"                     },
+  { "stoneblock.frames",                       "1"                     },
+
+  /* images for other elements and actions */
+
+  { "player_1",                                        "RocksHeroes.pcx"       },
+  { "player_1.xpos",                           "0"                     },
+  { "player_1.ypos",                           "0"                     },
+  { "player_1.frames",                         "1"                     },
+  { "player_1.EDITOR",                         "RocksElements.pcx"     },
+  { "player_1.EDITOR.xpos",                    "4"                     },
+  { "player_1.EDITOR.ypos",                    "7"                     },
+  { "player_1.down",                           "RocksHeroes.pcx"       },
+  { "player_1.down.xpos",                      "0"                     },
+  { "player_1.down.ypos",                      "0"                     },
+  { "player_1.down.frames",                    "1"                     },
+  { "player_1.up",                             "RocksHeroes.pcx"       },
+  { "player_1.up.xpos",                                "4"                     },
+  { "player_1.up.ypos",                                "0"                     },
+  { "player_1.up.frames",                      "1"                     },
+  { "player_1.left",                           "RocksHeroes.pcx"       },
+  { "player_1.left.xpos",                      "0"                     },
+  { "player_1.left.ypos",                      "1"                     },
+  { "player_1.left.frames",                    "1"                     },
+  { "player_1.right",                          "RocksHeroes.pcx"       },
+  { "player_1.right.xpos",                     "4"                     },
+  { "player_1.right.ypos",                     "1"                     },
+  { "player_1.right.frames",                   "1"                     },
+  { "player_1.moving.down",                    "RocksHeroes.pcx"       },
+  { "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.pcx"       },
+  { "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.pcx"       },
+  { "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.pcx"       },
+  { "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.pcx"       },
+  { "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.pcx"       },
+  { "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.pcx"       },
+  { "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.pcx"       },
+  { "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.pcx"       },
+  { "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.pcx"       },
+  { "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.pcx"       },
+  { "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.pcx"       },
+  { "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.pcx"       },
+  { "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.pcx"       },
+  { "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.pcx"       },
+  { "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.pcx"       },
+  { "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.pcx"       },
+  { "player_1.snapping.down.xpos",             "0"                     },
+  { "player_1.snapping.down.ypos",             "0"                     },
+  { "player_1.snapping.down.frames",           "1"                     },
+  { "player_1.snapping.up",                    "RocksHeroes.pcx"       },
+  { "player_1.snapping.up.xpos",               "4"                     },
+  { "player_1.snapping.up.ypos",               "0"                     },
+  { "player_1.snapping.up.frames",             "1"                     },
+  { "player_1.snapping.left",                  "RocksHeroes.pcx"       },
+  { "player_1.snapping.left.xpos",             "0"                     },
+  { "player_1.snapping.left.ypos",             "1"                     },
+  { "player_1.snapping.left.frames",           "1"                     },
+  { "player_1.snapping.right",                 "RocksHeroes.pcx"       },
+  { "player_1.snapping.right.xpos",            "4"                     },
+  { "player_1.snapping.right.ypos",            "1"                     },
+  { "player_1.snapping.right.frames",          "1"                     },
+
+  { "player_2",                                        "RocksHeroes.pcx"       },
+  { "player_2.xpos",                           "0"                     },
+  { "player_2.ypos",                           "3"                     },
+  { "player_2.frames",                         "1"                     },
+  { "player_2.EDITOR",                         "RocksElements.pcx"     },
+  { "player_2.EDITOR.xpos",                    "5"                     },
+  { "player_2.EDITOR.ypos",                    "7"                     },
+  { "player_2.down",                           "RocksHeroes.pcx"       },
+  { "player_2.down.xpos",                      "0"                     },
+  { "player_2.down.ypos",                      "3"                     },
+  { "player_2.down.frames",                    "1"                     },
+  { "player_2.up",                             "RocksHeroes.pcx"       },
+  { "player_2.up.xpos",                                "4"                     },
+  { "player_2.up.ypos",                                "3"                     },
+  { "player_2.up.frames",                      "1"                     },
+  { "player_2.left",                           "RocksHeroes.pcx"       },
+  { "player_2.left.xpos",                      "0"                     },
+  { "player_2.left.ypos",                      "4"                     },
+  { "player_2.left.frames",                    "1"                     },
+  { "player_2.right",                          "RocksHeroes.pcx"       },
+  { "player_2.right.xpos",                     "4"                     },
+  { "player_2.right.ypos",                     "4"                     },
+  { "player_2.right.frames",                   "1"                     },
+  { "player_2.moving.down",                    "RocksHeroes.pcx"       },
+  { "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.pcx"       },
+  { "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.pcx"       },
+  { "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.pcx"       },
+  { "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.pcx"       },
+  { "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.pcx"       },
+  { "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.pcx"       },
+  { "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.pcx"       },
+  { "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.pcx"       },
+  { "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.pcx"       },
+  { "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.pcx"       },
+  { "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.pcx"       },
+  { "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.pcx"       },
+  { "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.pcx"       },
+  { "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.pcx"       },
+  { "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.pcx"       },
+  { "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.pcx"       },
+  { "player_2.snapping.down.xpos",             "0"                     },
+  { "player_2.snapping.down.ypos",             "3"                     },
+  { "player_2.snapping.down.frames",           "1"                     },
+  { "player_2.snapping.up",                    "RocksHeroes.pcx"       },
+  { "player_2.snapping.up.xpos",               "4"                     },
+  { "player_2.snapping.up.ypos",               "3"                     },
+  { "player_2.snapping.up.frames",             "1"                     },
+  { "player_2.snapping.left",                  "RocksHeroes.pcx"       },
+  { "player_2.snapping.left.xpos",             "0"                     },
+  { "player_2.snapping.left.ypos",             "4"                     },
+  { "player_2.snapping.left.frames",           "1"                     },
+  { "player_2.snapping.right",                 "RocksHeroes.pcx"       },
+  { "player_2.snapping.right.xpos",            "4"                     },
+  { "player_2.snapping.right.ypos",            "4"                     },
+  { "player_2.snapping.right.frames",          "1"                     },
+
+  { "player_3",                                        "RocksHeroes.pcx"       },
+  { "player_3.xpos",                           "0"                     },
+  { "player_3.ypos",                           "6"                     },
+  { "player_3.frames",                         "1"                     },
+  { "player_3.EDITOR",                         "RocksElements.pcx"     },
+  { "player_3.EDITOR.xpos",                    "6"                     },
+  { "player_3.EDITOR.ypos",                    "7"                     },
+  { "player_3.down",                           "RocksHeroes.pcx"       },
+  { "player_3.down.xpos",                      "0"                     },
+  { "player_3.down.ypos",                      "6"                     },
+  { "player_3.down.frames",                    "1"                     },
+  { "player_3.up",                             "RocksHeroes.pcx"       },
+  { "player_3.up.xpos",                                "4"                     },
+  { "player_3.up.ypos",                                "6"                     },
+  { "player_3.up.frames",                      "1"                     },
+  { "player_3.left",                           "RocksHeroes.pcx"       },
+  { "player_3.left.xpos",                      "0"                     },
+  { "player_3.left.ypos",                      "7"                     },
+  { "player_3.left.frames",                    "1"                     },
+  { "player_3.right",                          "RocksHeroes.pcx"       },
+  { "player_3.right.xpos",                     "4"                     },
+  { "player_3.right.ypos",                     "7"                     },
+  { "player_3.right.frames",                   "1"                     },
+  { "player_3.moving.down",                    "RocksHeroes.pcx"       },
+  { "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.pcx"       },
+  { "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.pcx"       },
+  { "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.pcx"       },
+  { "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.pcx"       },
+  { "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.pcx"       },
+  { "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.pcx"       },
+  { "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.pcx"       },
+  { "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.pcx"       },
+  { "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.pcx"       },
+  { "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.pcx"       },
+  { "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.pcx"       },
+  { "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.pcx"       },
+  { "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.pcx"       },
+  { "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.pcx"       },
+  { "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.pcx"       },
+  { "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.pcx"       },
+  { "player_3.snapping.down.xpos",             "0"                     },
+  { "player_3.snapping.down.ypos",             "6"                     },
+  { "player_3.snapping.down.frames",           "1"                     },
+  { "player_3.snapping.up",                    "RocksHeroes.pcx"       },
+  { "player_3.snapping.up.xpos",               "4"                     },
+  { "player_3.snapping.up.ypos",               "6"                     },
+  { "player_3.snapping.up.frames",             "1"                     },
+  { "player_3.snapping.left",                  "RocksHeroes.pcx"       },
+  { "player_3.snapping.left.xpos",             "0"                     },
+  { "player_3.snapping.left.ypos",             "7"                     },
+  { "player_3.snapping.left.frames",           "1"                     },
+  { "player_3.snapping.right",                 "RocksHeroes.pcx"       },
+  { "player_3.snapping.right.xpos",            "4"                     },
+  { "player_3.snapping.right.ypos",            "7"                     },
+  { "player_3.snapping.right.frames",          "1"                     },
+
+  { "player_4",                                        "RocksHeroes.pcx"       },
+  { "player_4.xpos",                           "0"                     },
+  { "player_4.ypos",                           "9"                     },
+  { "player_4.frames",                         "1"                     },
+  { "player_4.EDITOR",                         "RocksElements.pcx"     },
+  { "player_4.EDITOR.xpos",                    "7"                     },
+  { "player_4.EDITOR.ypos",                    "7"                     },
+  { "player_4.down",                           "RocksHeroes.pcx"       },
+  { "player_4.down.xpos",                      "0"                     },
+  { "player_4.down.ypos",                      "9"                     },
+  { "player_4.down.frames",                    "1"                     },
+  { "player_4.up",                             "RocksHeroes.pcx"       },
+  { "player_4.up.xpos",                                "4"                     },
+  { "player_4.up.ypos",                                "9"                     },
+  { "player_4.up.frames",                      "1"                     },
+  { "player_4.left",                           "RocksHeroes.pcx"       },
+  { "player_4.left.xpos",                      "0"                     },
+  { "player_4.left.ypos",                      "10"                    },
+  { "player_4.left.frames",                    "1"                     },
+  { "player_4.right",                          "RocksHeroes.pcx"       },
+  { "player_4.right.xpos",                     "4"                     },
+  { "player_4.right.ypos",                     "10"                    },
+  { "player_4.right.frames",                   "1"                     },
+  { "player_4.moving.down",                    "RocksHeroes.pcx"       },
+  { "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.pcx"       },
+  { "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.pcx"       },
+  { "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.pcx"       },
+  { "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.pcx"       },
+  { "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.pcx"       },
+  { "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.pcx"       },
+  { "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.pcx"       },
+  { "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.pcx"       },
+  { "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.pcx"       },
+  { "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.pcx"       },
+  { "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.pcx"       },
+  { "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.pcx"       },
+  { "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.pcx"       },
+  { "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.pcx"       },
+  { "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.pcx"       },
+  { "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.pcx"       },
+  { "player_4.snapping.down.xpos",             "0"                     },
+  { "player_4.snapping.down.ypos",             "9"                     },
+  { "player_4.snapping.down.frames",           "1"                     },
+  { "player_4.snapping.up",                    "RocksHeroes.pcx"       },
+  { "player_4.snapping.up.xpos",               "4"                     },
+  { "player_4.snapping.up.ypos",               "9"                     },
+  { "player_4.snapping.up.frames",             "1"                     },
+  { "player_4.snapping.left",                  "RocksHeroes.pcx"       },
+  { "player_4.snapping.left.xpos",             "0"                     },
+  { "player_4.snapping.left.ypos",             "10"                    },
+  { "player_4.snapping.left.frames",           "1"                     },
+  { "player_4.snapping.right",                 "RocksHeroes.pcx"       },
+  { "player_4.snapping.right.xpos",            "4"                     },
+  { "player_4.snapping.right.ypos",            "10"                    },
+  { "player_4.snapping.right.frames",          "1"                     },
+
+  { "[default].exploding",                     "RocksElements.pcx"     },
+  { "[default].exploding.xpos",                        "0"                     },
+  { "[default].exploding.ypos",                        "4"                     },
+  { "[default].exploding.frames",              "8"                     },
+  { "[default].exploding.delay",               "2"                     },
+  { "[default].exploding.anim_mode",           "linear"                },
+
+  { "twinkle_blue",                            "RocksHeroes.pcx"       },
+  { "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.pcx"       },
+  { "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.pcx"     },
+  { "steelwall_topleft.xpos",                  "4"                     },
+  { "steelwall_topleft.ypos",                  "0"                     },
+  { "steelwall_topleft.frames",                        "1"                     },
+  { "steelwall_topright",                      "RocksElements.pcx"     },
+  { "steelwall_topright.xpos",                 "4"                     },
+  { "steelwall_topright.ypos",                 "0"                     },
+  { "steelwall_topright.frames",               "1"                     },
+  { "steelwall_bottomleft",                    "RocksElements.pcx"     },
+  { "steelwall_bottomleft.xpos",               "4"                     },
+  { "steelwall_bottomleft.ypos",               "0"                     },
+  { "steelwall_bottomleft.frames",             "1"                     },
+  { "steelwall_bottomright",                   "RocksElements.pcx"     },
+  { "steelwall_bottomright.xpos",              "4"                     },
+  { "steelwall_bottomright.ypos",              "0"                     },
+  { "steelwall_bottomright.frames",            "1"                     },
+  { "steelwall_horizontal",                    "RocksElements.pcx"     },
+  { "steelwall_horizontal.xpos",               "4"                     },
+  { "steelwall_horizontal.ypos",               "0"                     },
+  { "steelwall_horizontal.frames",             "1"                     },
+  { "steelwall_vertical",                      "RocksElements.pcx"     },
+  { "steelwall_vertical.xpos",                 "4"                     },
+  { "steelwall_vertical.ypos",                 "0"                     },
+  { "steelwall_vertical.frames",               "1"                     },
+
+  { "steelwall_topleft.EDITOR",                        "RocksElements.pcx"     },
+  { "steelwall_topleft.EDITOR.xpos",           "0"                     },
+  { "steelwall_topleft.EDITOR.ypos",           "13"                    },
+  { "steelwall_topright.EDITOR",               "RocksElements.pcx"     },
+  { "steelwall_topright.EDITOR.xpos",          "1"                     },
+  { "steelwall_topright.EDITOR.ypos",          "13"                    },
+  { "steelwall_bottomleft.EDITOR",             "RocksElements.pcx"     },
+  { "steelwall_bottomleft.EDITOR.xpos",                "2"                     },
+  { "steelwall_bottomleft.EDITOR.ypos",                "13"                    },
+  { "steelwall_bottomright.EDITOR",            "RocksElements.pcx"     },
+  { "steelwall_bottomright.EDITOR.xpos",       "3"                     },
+  { "steelwall_bottomright.EDITOR.ypos",       "13"                    },
+  { "steelwall_horizontal.EDITOR",             "RocksElements.pcx"     },
+  { "steelwall_horizontal.EDITOR.xpos",                "4"                     },
+  { "steelwall_horizontal.EDITOR.ypos",                "13"                    },
+  { "steelwall_vertical.EDITOR",               "RocksElements.pcx"     },
+  { "steelwall_vertical.EDITOR.xpos",          "5"                     },
+  { "steelwall_vertical.EDITOR.ypos",          "13"                    },
+
+  { "invisible_steelwall_topleft",             "RocksSP.pcx"           },
+  { "invisible_steelwall_topleft.xpos",                "0"                     },
+  { "invisible_steelwall_topleft.ypos",                "0"                     },
+  { "invisible_steelwall_topleft.frames",      "1"                     },
+  { "invisible_steelwall_topright",            "RocksSP.pcx"           },
+  { "invisible_steelwall_topright.xpos",       "0"                     },
+  { "invisible_steelwall_topright.ypos",       "0"                     },
+  { "invisible_steelwall_topright.frames",     "1"                     },
+  { "invisible_steelwall_bottomleft",          "RocksSP.pcx"           },
+  { "invisible_steelwall_bottomleft.xpos",     "0"                     },
+  { "invisible_steelwall_bottomleft.ypos",     "0"                     },
+  { "invisible_steelwall_bottomleft.frames",   "1"                     },
+  { "invisible_steelwall_bottomright",         "RocksSP.pcx"           },
+  { "invisible_steelwall_bottomright.xpos",    "0"                     },
+  { "invisible_steelwall_bottomright.ypos",    "0"                     },
+  { "invisible_steelwall_bottomright.frames",  "1"                     },
+  { "invisible_steelwall_horizontal",          "RocksSP.pcx"           },
+  { "invisible_steelwall_horizontal.xpos",     "0"                     },
+  { "invisible_steelwall_horizontal.ypos",     "0"                     },
+  { "invisible_steelwall_horizontal.frames",   "1"                     },
+  { "invisible_steelwall_vertical",            "RocksSP.pcx"           },
+  { "invisible_steelwall_vertical.xpos",       "0"                     },
+  { "invisible_steelwall_vertical.ypos",       "0"                     },
+  { "invisible_steelwall_vertical.frames",     "1"                     },
+
+  { "invisible_steelwall_topleft.EDITOR",      "RocksElements.pcx"     },
+  { "invisible_steelwall_topleft.EDITOR.xpos", "6"                     },
+  { "invisible_steelwall_topleft.EDITOR.ypos", "13"                    },
+  { "invisible_steelwall_topright.EDITOR",     "RocksElements.pcx"     },
+  { "invisible_steelwall_topright.EDITOR.xpos",        "7"                     },
+  { "invisible_steelwall_topright.EDITOR.ypos",        "13"                    },
+  { "invisible_steelwall_bottomleft.EDITOR",   "RocksElements.pcx"     },
+  { "invisible_steelwall_bottomleft.EDITOR.xpos","8"                   },
+  { "invisible_steelwall_bottomleft.EDITOR.ypos","13"                  },
+  { "invisible_steelwall_bottomright.EDITOR",  "RocksElements.pcx"     },
+  { "invisible_steelwall_bottomright.EDITOR.xpos","9"                  },
+  { "invisible_steelwall_bottomright.EDITOR.ypos","13"                 },
+  { "invisible_steelwall_horizontal.EDITOR",   "RocksElements.pcx"     },
+  { "invisible_steelwall_horizontal.EDITOR.xpos","10"                  },
+  { "invisible_steelwall_horizontal.EDITOR.ypos","13"                  },
+  { "invisible_steelwall_vertical.EDITOR",     "RocksElements.pcx"     },
+  { "invisible_steelwall_vertical.EDITOR.xpos",        "11"                    },
+  { "invisible_steelwall_vertical.EDITOR.ypos",        "13"                    },
+
+  { "arrow_left",                              "RocksDC.pcx"           },
+  { "arrow_left.xpos",                         "8"                     },
+  { "arrow_left.ypos",                         "8"                     },
+  { "arrow_left.frames",                       "1"                     },
+  { "arrow_right",                             "RocksDC.pcx"           },
+  { "arrow_right.xpos",                                "9"                     },
+  { "arrow_right.ypos",                                "8"                     },
+  { "arrow_right.frames",                      "1"                     },
+  { "arrow_up",                                        "RocksDC.pcx"           },
+  { "arrow_up.xpos",                           "10"                    },
+  { "arrow_up.ypos",                           "8"                     },
+  { "arrow_up.frames",                         "1"                     },
+  { "arrow_down",                              "RocksDC.pcx"           },
+  { "arrow_down.xpos",                         "11"                    },
+  { "arrow_down.ypos",                         "8"                     },
+  { "arrow_down.frames",                       "1"                     },
+
+#include "conf_chr.c"  /* include auto-generated data structure definitions */
+#include "conf_cus.c"  /* include auto-generated data structure definitions */
+
+  /* images not associated to game elements (used for menu screens etc.) */
+  /* keyword to stop parser: "NO_MORE_ELEMENT_IMAGES" <-- do not change! */
+
+  { "toon_1",                                  "RocksToons.pcx"        },
+  { "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.pcx"        },
+  { "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.pcx"        },
+  { "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.pcx"        },
+  { "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.pcx"        },
+  { "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.pcx"        },
+  { "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",                                  "RocksHeroes.pcx"       },
+  { "toon_7.xpos",                             "0"                     },
+  { "toon_7.ypos",                             "1"                     },
+  { "toon_7.frames",                           "4"                     },
+  { "toon_7.delay",                            "4"                     },
+  { "toon_7.direction",                                "left"                  },
+  { "toon_7.position",                         "bottom"                },
+
+  { "toon_8",                                  "RocksHeroes.pcx"       },
+  { "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.pcx"       },
+  { "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.pcx"       },
+  { "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.pcx"       },
+  { "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.pcx"       },
+  { "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.pcx"       },
+  { "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.pcx"       },
+  { "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.pcx"       },
+  { "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.pcx"       },
+  { "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.pcx"       },
+  { "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.pcx"       },
+  { "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.pcx"     },
+  { "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.pcx"     },
+  { "toon_20.xpos",                            "10"                    },
+  { "toon_20.ypos",                            "0"                     },
+  { "toon_20.frames",                          "2"                     },
+  { "toon_20.delay",                           "4"                     },
+  { "toon_20.direction",                       "down"                  },
+  { "toon_20.position",                                "any"                   },
+
+  { "menu.calibrate_red",                      "RocksElements.pcx"     },
+  { "menu.calibrate_red.xpos",                 "12"                    },
+  { "menu.calibrate_red.ypos",                 "8"                     },
+  { "menu.calibrate_red.frames",               "1"                     },
+  { "menu.calibrate_blue",                     "RocksElements.pcx"     },
+  { "menu.calibrate_blue.xpos",                        "13"                    },
+  { "menu.calibrate_blue.ypos",                        "8"                     },
+  { "menu.calibrate_blue.frames",              "1"                     },
+  { "menu.calibrate_yellow",                   "RocksElements.pcx"     },
+  { "menu.calibrate_yellow.xpos",              "14"                    },
+  { "menu.calibrate_yellow.ypos",              "8"                     },
+  { "menu.calibrate_yellow.frames",            "1"                     },
+
+  { "menu.button",                             "RocksElements.pcx"     },
+  { "menu.button.xpos",                                "13"                    },
+  { "menu.button.ypos",                                "8"                     },
+  { "menu.button.frames",                      "1"                     },
+  { "menu.button.active",                      "RocksElements.pcx"     },
+  { "menu.button.active.xpos",                 "12"                    },
+  { "menu.button.active.ypos",                 "8"                     },
+  { "menu.button.active.frames",               "1"                     },
+
+  { "menu.button_left",                                "RocksDC.pcx"           },
+  { "menu.button_left.xpos",                   "8"                     },
+  { "menu.button_left.ypos",                   "8"                     },
+  { "menu.button_left.frames",                 "1"                     },
+  { "menu.button_right",                       "RocksDC.pcx"           },
+  { "menu.button_right.xpos",                  "9"                     },
+  { "menu.button_right.ypos",                  "8"                     },
+  { "menu.button_right.frames",                        "1"                     },
+  { "menu.button_up",                          "RocksDC.pcx"           },
+  { "menu.button_up.xpos",                     "10"                    },
+  { "menu.button_up.ypos",                     "8"                     },
+  { "menu.button_up.frames",                   "1"                     },
+  { "menu.button_down",                                "RocksDC.pcx"           },
+  { "menu.button_down.xpos",                   "11"                    },
+  { "menu.button_down.ypos",                   "8"                     },
+  { "menu.button_down.frames",                 "1"                     },
+  { "menu.button_left.active",                 "RocksDC.pcx"           },
+  { "menu.button_left.active.xpos",            "8"                     },
+  { "menu.button_left.active.ypos",            "9"                     },
+  { "menu.button_left.active.frames",          "1"                     },
+  { "menu.button_right.active",                        "RocksDC.pcx"           },
+  { "menu.button_right.active.xpos",           "9"                     },
+  { "menu.button_right.active.ypos",           "9"                     },
+  { "menu.button_right.active.frames",         "1"                     },
+  { "menu.button_up.active",                   "RocksDC.pcx"           },
+  { "menu.button_up.active.xpos",              "10"                    },
+  { "menu.button_up.active.ypos",              "9"                     },
+  { "menu.button_up.active.frames",            "1"                     },
+  { "menu.button_down.active",                 "RocksDC.pcx"           },
+  { "menu.button_down.active.xpos",            "11"                    },
+  { "menu.button_down.active.ypos",            "9"                     },
+  { "menu.button_down.active.frames",          "1"                     },
+
+  { "menu.scrollbar",                          "RocksDC.pcx"           },
+  { "menu.scrollbar.xpos",                     "8"                     },
+  { "menu.scrollbar.ypos",                     "10"                    },
+  { "menu.scrollbar.frames",                   "1"                     },
+  { "menu.scrollbar.active",                   "RocksDC.pcx"           },
+  { "menu.scrollbar.active.xpos",              "9"                     },
+  { "menu.scrollbar.active.ypos",              "10"                    },
+  { "menu.scrollbar.active.frames",            "1"                     },
+
+  { "font.initial_1",                          "RocksFontSmall.pcx"    },
+  { "font.initial_1.x",                                "0"                     },
+  { "font.initial_1.y",                                "0"                     },
+  { "font.initial_1.width",                    "14"                    },
+  { "font.initial_1.height",                   "14"                    },
+  { "font.initial_2",                          "RocksFontSmall.pcx"    },
+  { "font.initial_2.x",                                "0"                     },
+  { "font.initial_2.y",                                "70"                    },
+  { "font.initial_2.width",                    "14"                    },
+  { "font.initial_2.height",                   "14"                    },
+  { "font.initial_3",                          "RocksFontSmall.pcx"    },
+  { "font.initial_3.x",                                "0"                     },
+  { "font.initial_3.y",                                "140"                   },
+  { "font.initial_3.width",                    "14"                    },
+  { "font.initial_3.height",                   "14"                    },
+  { "font.initial_4",                          "RocksFontSmall.pcx"    },
+  { "font.initial_4.x",                                "0"                     },
+  { "font.initial_4.y",                                "210"                   },
+  { "font.initial_4.width",                    "14"                    },
+  { "font.initial_4.height",                   "14"                    },
+
+  { "font.title_1",                            "RocksFontBig.pcx"      },
+  { "font.title_1.x",                          "0"                     },
+  { "font.title_1.y",                          "480"                   },
+  { "font.title_1.width",                      "32"                    },
+  { "font.title_1.height",                     "32"                    },
+  { "font.title_1.LEVELS",                     "RocksFontBig.pcx"      },
+  { "font.title_1.LEVELS.x",                   "0"                     },
+  { "font.title_1.LEVELS.y",                   "320"                   },
+  { "font.title_1.LEVELS.width",               "32"                    },
+  { "font.title_1.LEVELS.height",              "32"                    },
+  { "font.title_2",                            "RocksFontSmall.pcx"    },
+  { "font.title_2.x",                          "0"                     },
+  { "font.title_2.y",                          "0"                     },
+  { "font.title_2.width",                      "14"                    },
+  { "font.title_2.height",                     "14"                    },
+
+  { "font.menu_1",                             "RocksFontBig.pcx"      },
+  { "font.menu_1.x",                           "0"                     },
+  { "font.menu_1.y",                           "320"                   },
+  { "font.menu_1.width",                       "32"                    },
+  { "font.menu_1.height",                      "32"                    },
+  { "font.menu_2",                             "RocksFontMedium.pcx"   },
+  { "font.menu_2.x",                           "0"                     },
+  { "font.menu_2.y",                           "320"                   },
+  { "font.menu_2.width",                       "16"                    },
+  { "font.menu_2.height",                      "32"                    },
+
+  { "font.text_1",                             "RocksFontSmall.pcx"    },
+  { "font.text_1.x",                           "0"                     },
+  { "font.text_1.y",                           "140"                   },
+  { "font.text_1.width",                       "14"                    },
+  { "font.text_1.height",                      "14"                    },
+  { "font.text_1.LEVELS",                      "RocksFontMedium.pcx"   },
+  { "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.PREVIEW",                     "RocksFontEM.pcx"       },
+  { "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.pcx"   },
+  { "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.pcx"   },
+  { "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_2",                             "RocksFontSmall.pcx"    },
+  { "font.text_2.x",                           "0"                     },
+  { "font.text_2.y",                           "210"                   },
+  { "font.text_2.width",                       "14"                    },
+  { "font.text_2.height",                      "14"                    },
+  { "font.text_2.LEVELS",                      "RocksFontMedium.pcx"   },
+  { "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.PREVIEW",                     "RocksFontEM.pcx"       },
+  { "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.pcx"      },
+  { "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.pcx"      },
+  { "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.pcx"    },
+  { "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.pcx"   },
+  { "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.PREVIEW",                     "RocksFontEM.pcx"       },
+  { "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.pcx"   },
+  { "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.pcx"   },
+  { "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.pcx"    },
+  { "font.text_4.x",                           "0"                     },
+  { "font.text_4.y",                           "70"                    },
+  { "font.text_4.width",                       "14"                    },
+  { "font.text_4.height",                      "14"                    },
+  { "font.text_4.LEVELS",                      "RocksFontMedium.pcx"   },
+  { "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.SCORES",                      "RocksFontMedium.pcx"   },
+  { "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.pcx"   },
+  { "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.input_1",                            "RocksFontSmall.pcx"    },
+  { "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.pcx"      },
+  { "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.active",                     "RocksFontSmall.pcx"    },
+  { "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.pcx"      },
+  { "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.SETUP",               "RocksFontBig.pcx"      },
+  { "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.pcx"    },
+  { "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.pcx"    },
+  { "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.pcx"      },
+  { "font.option_off.x",                       "0"                     },
+  { "font.option_off.y",                       "160"                   },
+  { "font.option_off.width",                   "32"                    },
+  { "font.option_off.height",                  "32"                    },
+  { "font.option_on",                          "RocksFontBig.pcx"      },
+  { "font.option_on.x",                                "0"                     },
+  { "font.option_on.y",                                "480"                   },
+  { "font.option_on.width",                    "32"                    },
+  { "font.option_on.height",                   "32"                    },
+
+  { "font.value_1",                            "RocksFontBig.pcx"      },
+  { "font.value_1.x",                          "0"                     },
+  { "font.value_1.y",                          "480"                   },
+  { "font.value_1.width",                      "32"                    },
+  { "font.value_1.height",                     "32"                    },
+  { "font.value_2",                            "RocksFontMedium.pcx"   },
+  { "font.value_2.x",                          "0"                     },
+  { "font.value_2.y",                          "480"                   },
+  { "font.value_2.width",                      "16"                    },
+  { "font.value_2.height",                     "32"                    },
+  { "font.value_old",                          "RocksFontBig.pcx"      },
+  { "font.value_old.x",                                "0"                     },
+  { "font.value_old.y",                                "160"                   },
+  { "font.value_old.width",                    "32"                    },
+  { "font.value_old.height",                   "32"                    },
+
+  { "font.level_number",                       "RocksFontSmall.pcx"    },
+  { "font.level_number.x",                     "0"                     },
+  { "font.level_number.y",                     "350"                   },
+  { "font.level_number.width",                 "10"                    },
+  { "font.level_number.height",                        "14"                    },
+
+  { "font.tape_recorder",                      "RocksFontSmall.pcx"    },
+  { "font.tape_recorder.x",                    "0"                     },
+  { "font.tape_recorder.y",                    "280"                   },
+  { "font.tape_recorder.width",                        "11"                    },
+  { "font.tape_recorder.height",               "14"                    },
+
+  { "font.game_info",                          "RocksFontEM.pcx"       },
+  { "font.game_info.xpos",                     "0"                     },
+  { "font.game_info.ypos",                     "0"                     },
+  { "font.game_info.delay",                    "10"                    },
+
+  { "global.border",                           "RocksScreen.pcx"       },
+  { "global.door",                             "RocksDoor.pcx"         },
+
+  { "editor.element_border",                   "RocksElements.pcx"     },
+  { "editor.element_border.xpos",              "0"                     },
+  { "editor.element_border.ypos",              "0"                     },
+
+  { "editor.element_border_input",             "RocksElements.pcx"     },
+  { "editor.element_border_input.xpos",                "0"                     },
+  { "editor.element_border_input.ypos",                "0"                     },
+
+  { "background",                              UNDEFINED_FILENAME      },
+  { "background.MAIN",                         UNDEFINED_FILENAME      },
+  { "background.LEVELS",                       UNDEFINED_FILENAME      },
+  { "background.SCORES",                       UNDEFINED_FILENAME      },
+  { "background.EDITOR",                       UNDEFINED_FILENAME      },
+  { "background.INFO",                         UNDEFINED_FILENAME      },
+  { "background.SETUP",                                UNDEFINED_FILENAME      },
+  { "background.DOOR",                         UNDEFINED_FILENAME      },
+
+  /* the following directives are not associated with an image, but
+     probably make sense to be defined in "graphicsinfo.conf", too */
+
+  { "global.num_toons",                                "20"                    },
+
+  { "menu.draw_xoffset",                       "0"                     },
+  { "menu.draw_yoffset",                       "0"                     },
+  { "menu.draw_xoffset.MAIN",                  "0"                     },
+  { "menu.draw_yoffset.MAIN",                  "0"                     },
+  { "menu.draw_xoffset.LEVELS",                        "0"                     },
+  { "menu.draw_yoffset.LEVELS",                        "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.SETUP",                 "0"                     },
+  { "menu.draw_yoffset.SETUP",                 "0"                     },
+
+  { "menu.scrollbar_xoffset",                  "0"                     },
+
+  { "menu.list_size",                          "-1"                    },
+  { "menu.list_size.LEVELS",                   "-1"                    },
+  { "menu.list_size.SCORES",                   "-1"                    },
+  { "menu.list_size.INFO",                     "-1"                    },
+
+  { "door.step_offset",                                "2"                     },
+  { "door.step_delay",                         "10"                    },
+
+  { NULL,                                      NULL                    }
+};
diff --git a/src/conf_gfx.h b/src/conf_gfx.h
new file mode 100644 (file)
index 0000000..8b3f18c
--- /dev/null
@@ -0,0 +1,1040 @@
+/***********************************************************
+* Rocks'n'Diamonds -- McDuffin Strikes Back!               *
+*----------------------------------------------------------*
+* (c) 1995-2002 Artsoft Entertainment                      *
+*               Holger Schemel                             *
+*               Detmolder Strasse 189                      *
+*               33604 Bielefeld                            *
+*               Germany                                    *
+*               e-mail: info@artsoft.org                   *
+*----------------------------------------------------------*
+* conf_gfx.h                                               *
+***********************************************************/
+
+/* ----- this file was automatically generated -- do not edit by hand ----- */
+
+#ifndef CONF_GFX_H
+#define CONF_GFX_H
+
+/* values for graphics configuration (normal elements) */
+
+#define IMG_BD_WALL                                    0
+#define IMG_BD_WALL_EDITOR                             1
+#define IMG_BD_ROCK                                    2
+#define IMG_BD_ROCK_EDITOR                             3
+#define IMG_BD_ROCK_MOVING_LEFT                                4
+#define IMG_BD_ROCK_MOVING_RIGHT                       5
+#define IMG_BD_ROCK_PUSHING_LEFT                       6
+#define IMG_BD_ROCK_PUSHING_RIGHT                      7
+#define IMG_BD_DIAMOND                                 8
+#define IMG_BD_DIAMOND_MOVING                          9
+#define IMG_BD_DIAMOND_FALLING                         10
+#define IMG_BD_MAGIC_WALL                              11
+#define IMG_BD_MAGIC_WALL_ACTIVE                       12
+#define IMG_BD_MAGIC_WALL_FILLING                      13
+#define IMG_BD_MAGIC_WALL_FULL                         14
+#define IMG_BD_MAGIC_WALL_EMPTYING                     15
+#define IMG_BD_MAGIC_WALL_DEAD                         16
+#define IMG_BD_AMOEBA                                  17
+#define IMG_BD_AMOEBA_EDITOR                           18
+#define IMG_BD_BUTTERFLY                               19
+#define IMG_BD_BUTTERFLY_RIGHT                         20
+#define IMG_BD_BUTTERFLY_UP                            21
+#define IMG_BD_BUTTERFLY_LEFT                          22
+#define IMG_BD_BUTTERFLY_DOWN                          23
+#define IMG_BD_BUTTERFLY_MOVING                                24
+#define IMG_BD_FIREFLY                                 25
+#define IMG_BD_FIREFLY_RIGHT                           26
+#define IMG_BD_FIREFLY_UP                              27
+#define IMG_BD_FIREFLY_LEFT                            28
+#define IMG_BD_FIREFLY_DOWN                            29
+#define IMG_BD_FIREFLY_MOVING                          30
+#define IMG_SP_DEFAULT_EXPLODING                       31
+#define IMG_SP_EMPTY_SPACE                             32
+#define IMG_SP_ZONK                                    33
+#define IMG_SP_ZONK_MOVING_LEFT                                34
+#define IMG_SP_ZONK_MOVING_RIGHT                       35
+#define IMG_SP_ZONK_PUSHING_LEFT                       36
+#define IMG_SP_ZONK_PUSHING_RIGHT                      37
+#define IMG_SP_BASE                                    38
+#define IMG_SP_MURPHY                                  39
+#define IMG_SP_MURPHY_MOVING_LEFT                      40
+#define IMG_SP_MURPHY_MOVING_RIGHT                     41
+#define IMG_SP_MURPHY_DIGGING_LEFT                     42
+#define IMG_SP_MURPHY_DIGGING_RIGHT                    43
+#define IMG_SP_MURPHY_COLLECTING_LEFT                  44
+#define IMG_SP_MURPHY_COLLECTING_RIGHT                 45
+#define IMG_SP_MURPHY_PUSHING_LEFT                     46
+#define IMG_SP_MURPHY_PUSHING_RIGHT                    47
+#define IMG_SP_MURPHY_SNAPPING_LEFT                    48
+#define IMG_SP_MURPHY_SNAPPING_RIGHT                   49
+#define IMG_SP_MURPHY_SNAPPING_UP                      50
+#define IMG_SP_MURPHY_SNAPPING_DOWN                    51
+#define IMG_SP_MURPHY_CLONE                            52
+#define IMG_SP_INFOTRON                                        53
+#define IMG_SP_INFOTRON_EDITOR                         54
+#define IMG_SP_CHIP_SINGLE                             55
+#define IMG_SP_CHIP_LEFT                               56
+#define IMG_SP_CHIP_RIGHT                              57
+#define IMG_SP_CHIP_TOP                                        58
+#define IMG_SP_CHIP_BOTTOM                             59
+#define IMG_SP_HARDWARE_GRAY                           60
+#define IMG_SP_HARDWARE_GREEN                          61
+#define IMG_SP_HARDWARE_BLUE                           62
+#define IMG_SP_HARDWARE_RED                            63
+#define IMG_SP_HARDWARE_YELLOW                         64
+#define IMG_SP_EXIT_CLOSED                             65
+#define IMG_SP_EXIT_OPEN                               66
+#define IMG_SP_DISK_ORANGE                             67
+#define IMG_SP_DISK_YELLOW                             68
+#define IMG_SP_DISK_RED                                        69
+#define IMG_SP_DISK_RED_COLLECTING                     70
+#define IMG_SP_PORT_RIGHT                              71
+#define IMG_SP_PORT_DOWN                               72
+#define IMG_SP_PORT_LEFT                               73
+#define IMG_SP_PORT_UP                                 74
+#define IMG_SP_PORT_HORIZONTAL                         75
+#define IMG_SP_PORT_VERTICAL                           76
+#define IMG_SP_PORT_ANY                                        77
+#define IMG_SP_GRAVITY_PORT_RIGHT                      78
+#define IMG_SP_GRAVITY_PORT_DOWN                       79
+#define IMG_SP_GRAVITY_PORT_LEFT                       80
+#define IMG_SP_GRAVITY_PORT_UP                         81
+#define IMG_SP_SNIKSNAK                                        82
+#define IMG_SP_SNIKSNAK_LEFT                           83
+#define IMG_SP_SNIKSNAK_RIGHT                          84
+#define IMG_SP_SNIKSNAK_UP                             85
+#define IMG_SP_SNIKSNAK_DOWN                           86
+#define IMG_SP_ELECTRON                                        87
+#define IMG_SP_ELECTRON_EDITOR                         88
+#define IMG_SP_ELECTRON_EXPLODING                      89
+#define IMG_SP_TERMINAL                                        90
+#define IMG_SP_TERMINAL_EDITOR                         91
+#define IMG_SP_TERMINAL_ACTIVE                         92
+#define IMG_SP_BUGGY_BASE                              93
+#define IMG_SP_BUGGY_BASE_EDITOR                       94
+#define IMG_SP_BUGGY_BASE_ACTIVATING                   95
+#define IMG_SP_BUGGY_BASE_ACTIVE                       96
+#define IMG_SP_HARDWARE_BASE_1                         97
+#define IMG_SP_HARDWARE_BASE_2                         98
+#define IMG_SP_HARDWARE_BASE_3                         99
+#define IMG_SP_HARDWARE_BASE_4                         100
+#define IMG_SP_HARDWARE_BASE_5                         101
+#define IMG_SP_HARDWARE_BASE_6                         102
+#define IMG_SOKOBAN_OBJECT                             103
+#define IMG_SOKOBAN_OBJECT_EDITOR                      104
+#define IMG_SOKOBAN_FIELD_EMPTY                                105
+#define IMG_SOKOBAN_FIELD_FULL                         106
+#define IMG_EMPTY_SPACE                                        107
+#define IMG_SAND                                       108
+#define IMG_SAND_CRUMBLED                              109
+#define IMG_SAND_DIGGING_LEFT                          110
+#define IMG_SAND_DIGGING_RIGHT                         111
+#define IMG_SAND_DIGGING_UP                            112
+#define IMG_SAND_DIGGING_DOWN                          113
+#define IMG_SAND_DIGGING_LEFT_CRUMBLED                 114
+#define IMG_SAND_DIGGING_RIGHT_CRUMBLED                        115
+#define IMG_SAND_DIGGING_UP_CRUMBLED                   116
+#define IMG_SAND_DIGGING_DOWN_CRUMBLED                 117
+#define IMG_WALL                                       118
+#define IMG_WALL_SLIPPERY                              119
+#define IMG_STEELWALL                                  120
+#define IMG_ROCK                                       121
+#define IMG_ROCK_MOVING_LEFT                           122
+#define IMG_ROCK_MOVING_RIGHT                          123
+#define IMG_ROCK_PUSHING_LEFT                          124
+#define IMG_ROCK_PUSHING_RIGHT                         125
+#define IMG_EMERALD                                    126
+#define IMG_EMERALD_MOVING                             127
+#define IMG_EMERALD_FALLING                            128
+#define IMG_EMERALD_COLLECTING                         129
+#define IMG_DIAMOND                                    130
+#define IMG_DIAMOND_MOVING                             131
+#define IMG_DIAMOND_FALLING                            132
+#define IMG_DIAMOND_COLLECTING                         133
+#define IMG_BOMB                                       134
+#define IMG_NUT                                                135
+#define IMG_NUT_BREAKING                               136
+#define IMG_DYNAMITE                                   137
+#define IMG_DYNAMITE_EDITOR                            138
+#define IMG_DYNAMITE_ACTIVE                            139
+#define IMG_DYNAMITE_ACTIVE_EDITOR                     140
+#define IMG_WALL_EMERALD                               141
+#define IMG_WALL_DIAMOND                               142
+#define IMG_BUG                                                143
+#define IMG_BUG_RIGHT                                  144
+#define IMG_BUG_UP                                     145
+#define IMG_BUG_LEFT                                   146
+#define IMG_BUG_DOWN                                   147
+#define IMG_BUG_MOVING_RIGHT                           148
+#define IMG_BUG_MOVING_UP                              149
+#define IMG_BUG_MOVING_LEFT                            150
+#define IMG_BUG_MOVING_DOWN                            151
+#define IMG_SPACESHIP                                  152
+#define IMG_SPACESHIP_RIGHT                            153
+#define IMG_SPACESHIP_UP                               154
+#define IMG_SPACESHIP_LEFT                             155
+#define IMG_SPACESHIP_DOWN                             156
+#define IMG_SPACESHIP_MOVING_RIGHT                     157
+#define IMG_SPACESHIP_MOVING_UP                                158
+#define IMG_SPACESHIP_MOVING_LEFT                      159
+#define IMG_SPACESHIP_MOVING_DOWN                      160
+#define IMG_YAMYAM                                     161
+#define IMG_YAMYAM_MOVING                              162
+#define IMG_ROBOT                                      163
+#define IMG_ROBOT_MOVING                               164
+#define IMG_ROBOT_WHEEL                                        165
+#define IMG_ROBOT_WHEEL_ACTIVE                         166
+#define IMG_MAGIC_WALL                                 167
+#define IMG_MAGIC_WALL_ACTIVE                          168
+#define IMG_MAGIC_WALL_FILLING                         169
+#define IMG_MAGIC_WALL_FULL                            170
+#define IMG_MAGIC_WALL_EMPTYING                                171
+#define IMG_MAGIC_WALL_DEAD                            172
+#define IMG_QUICKSAND_EMPTY                            173
+#define IMG_QUICKSAND_FILLING                          174
+#define IMG_QUICKSAND_FULL                             175
+#define IMG_QUICKSAND_FULL_EDITOR                      176
+#define IMG_QUICKSAND_EMPTYING                         177
+#define IMG_ACID_POOL_TOPLEFT                          178
+#define IMG_ACID_POOL_TOPRIGHT                         179
+#define IMG_ACID_POOL_BOTTOMLEFT                       180
+#define IMG_ACID_POOL_BOTTOM                           181
+#define IMG_ACID_POOL_BOTTOMRIGHT                      182
+#define IMG_ACID                                       183
+#define IMG_ACID_SPLASH_LEFT                           184
+#define IMG_ACID_SPLASH_RIGHT                          185
+#define IMG_AMOEBA_DROP                                        186
+#define IMG_AMOEBA_GROWING                             187
+#define IMG_AMOEBA_SHRINKING                           188
+#define IMG_AMOEBA_WET                                 189
+#define IMG_AMOEBA_WET_EDITOR                          190
+#define IMG_AMOEBA_DROPPING                            191
+#define IMG_AMOEBA_DRY                                 192
+#define IMG_AMOEBA_FULL                                        193
+#define IMG_AMOEBA_FULL_EDITOR                         194
+#define IMG_AMOEBA_DEAD                                        195
+#define IMG_AMOEBA_DEAD_EDITOR                         196
+#define IMG_EM_KEY_1                                   197
+#define IMG_EM_KEY_2                                   198
+#define IMG_EM_KEY_3                                   199
+#define IMG_EM_KEY_4                                   200
+#define IMG_EM_GATE_1                                  201
+#define IMG_EM_GATE_2                                  202
+#define IMG_EM_GATE_3                                  203
+#define IMG_EM_GATE_4                                  204
+#define IMG_EM_GATE_1_GRAY                             205
+#define IMG_EM_GATE_1_GRAY_EDITOR                      206
+#define IMG_EM_GATE_2_GRAY                             207
+#define IMG_EM_GATE_2_GRAY_EDITOR                      208
+#define IMG_EM_GATE_3_GRAY                             209
+#define IMG_EM_GATE_3_GRAY_EDITOR                      210
+#define IMG_EM_GATE_4_GRAY                             211
+#define IMG_EM_GATE_4_GRAY_EDITOR                      212
+#define IMG_EXIT_CLOSED                                        213
+#define IMG_EXIT_OPENING                               214
+#define IMG_EXIT_OPEN                                  215
+#define IMG_BALLOON                                    216
+#define IMG_BALLOON_MOVING                             217
+#define IMG_BALLOON_PUSHING                            218
+#define IMG_BALLOON_SWITCH_LEFT                                219
+#define IMG_BALLOON_SWITCH_RIGHT                       220
+#define IMG_BALLOON_SWITCH_UP                          221
+#define IMG_BALLOON_SWITCH_DOWN                                222
+#define IMG_BALLOON_SWITCH_ANY                         223
+#define IMG_SPRING                                     224
+#define IMG_EMC_STEELWALL_1                            225
+#define IMG_EMC_STEELWALL_2                            226
+#define IMG_EMC_STEELWALL_3                            227
+#define IMG_EMC_STEELWALL_4                            228
+#define IMG_EMC_WALL_1                                 229
+#define IMG_EMC_WALL_2                                 230
+#define IMG_EMC_WALL_3                                 231
+#define IMG_EMC_WALL_4                                 232
+#define IMG_EMC_WALL_5                                 233
+#define IMG_EMC_WALL_6                                 234
+#define IMG_EMC_WALL_7                                 235
+#define IMG_EMC_WALL_8                                 236
+#define IMG_INVISIBLE_STEELWALL                                237
+#define IMG_INVISIBLE_STEELWALL_EDITOR                 238
+#define IMG_INVISIBLE_STEELWALL_ACTIVE                 239
+#define IMG_INVISIBLE_WALL                             240
+#define IMG_INVISIBLE_WALL_EDITOR                      241
+#define IMG_INVISIBLE_WALL_ACTIVE                      242
+#define IMG_INVISIBLE_SAND                             243
+#define IMG_INVISIBLE_SAND_EDITOR                      244
+#define IMG_INVISIBLE_SAND_ACTIVE                      245
+#define IMG_CONVEYOR_BELT_1_MIDDLE                     246
+#define IMG_CONVEYOR_BELT_1_MIDDLE_ACTIVE              247
+#define IMG_CONVEYOR_BELT_1_LEFT                       248
+#define IMG_CONVEYOR_BELT_1_LEFT_ACTIVE                        249
+#define IMG_CONVEYOR_BELT_1_RIGHT                      250
+#define IMG_CONVEYOR_BELT_1_RIGHT_ACTIVE               251
+#define IMG_CONVEYOR_BELT_1_SWITCH_LEFT                        252
+#define IMG_CONVEYOR_BELT_1_SWITCH_MIDDLE              253
+#define IMG_CONVEYOR_BELT_1_SWITCH_RIGHT               254
+#define IMG_CONVEYOR_BELT_2_MIDDLE                     255
+#define IMG_CONVEYOR_BELT_2_MIDDLE_ACTIVE              256
+#define IMG_CONVEYOR_BELT_2_LEFT                       257
+#define IMG_CONVEYOR_BELT_2_LEFT_ACTIVE                        258
+#define IMG_CONVEYOR_BELT_2_RIGHT                      259
+#define IMG_CONVEYOR_BELT_2_RIGHT_ACTIVE               260
+#define IMG_CONVEYOR_BELT_2_SWITCH_LEFT                        261
+#define IMG_CONVEYOR_BELT_2_SWITCH_MIDDLE              262
+#define IMG_CONVEYOR_BELT_2_SWITCH_RIGHT               263
+#define IMG_CONVEYOR_BELT_3_MIDDLE                     264
+#define IMG_CONVEYOR_BELT_3_MIDDLE_ACTIVE              265
+#define IMG_CONVEYOR_BELT_3_LEFT                       266
+#define IMG_CONVEYOR_BELT_3_LEFT_ACTIVE                        267
+#define IMG_CONVEYOR_BELT_3_RIGHT                      268
+#define IMG_CONVEYOR_BELT_3_RIGHT_ACTIVE               269
+#define IMG_CONVEYOR_BELT_3_SWITCH_LEFT                        270
+#define IMG_CONVEYOR_BELT_3_SWITCH_MIDDLE              271
+#define IMG_CONVEYOR_BELT_3_SWITCH_RIGHT               272
+#define IMG_CONVEYOR_BELT_4_MIDDLE                     273
+#define IMG_CONVEYOR_BELT_4_MIDDLE_ACTIVE              274
+#define IMG_CONVEYOR_BELT_4_LEFT                       275
+#define IMG_CONVEYOR_BELT_4_LEFT_ACTIVE                        276
+#define IMG_CONVEYOR_BELT_4_RIGHT                      277
+#define IMG_CONVEYOR_BELT_4_RIGHT_ACTIVE               278
+#define IMG_CONVEYOR_BELT_4_SWITCH_LEFT                        279
+#define IMG_CONVEYOR_BELT_4_SWITCH_MIDDLE              280
+#define IMG_CONVEYOR_BELT_4_SWITCH_RIGHT               281
+#define IMG_SWITCHGATE_SWITCH_UP                       282
+#define IMG_SWITCHGATE_SWITCH_DOWN                     283
+#define IMG_LIGHT_SWITCH                               284
+#define IMG_LIGHT_SWITCH_ACTIVE                                285
+#define IMG_TIMEGATE_SWITCH                            286
+#define IMG_TIMEGATE_SWITCH_ACTIVE                     287
+#define IMG_ENVELOPE                                   288
+#define IMG_SIGN_EXCLAMATION                           289
+#define IMG_SIGN_STOP                                  290
+#define IMG_LANDMINE                                   291
+#define IMG_STEELWALL_SLIPPERY                         292
+#define IMG_EXTRA_TIME                                 293
+#define IMG_SHIELD_NORMAL                              294
+#define IMG_SHIELD_NORMAL_ACTIVE                       295
+#define IMG_SHIELD_DEADLY                              296
+#define IMG_SHIELD_DEADLY_ACTIVE                       297
+#define IMG_SWITCHGATE_CLOSED                          298
+#define IMG_SWITCHGATE_OPENING                         299
+#define IMG_SWITCHGATE_OPEN                            300
+#define IMG_SWITCHGATE_CLOSING                         301
+#define IMG_TIMEGATE_CLOSED                            302
+#define IMG_TIMEGATE_OPENING                           303
+#define IMG_TIMEGATE_OPEN                              304
+#define IMG_TIMEGATE_CLOSING                           305
+#define IMG_PEARL                                      306
+#define IMG_PEARL_BREAKING                             307
+#define IMG_CRYSTAL                                    308
+#define IMG_WALL_PEARL                                 309
+#define IMG_WALL_CRYSTAL                               310
+#define IMG_TUBE_RIGHT_DOWN                            311
+#define IMG_TUBE_HORIZONTAL_DOWN                       312
+#define IMG_TUBE_LEFT_DOWN                             313
+#define IMG_TUBE_HORIZONTAL                            314
+#define IMG_TUBE_VERTICAL_RIGHT                                315
+#define IMG_TUBE_ANY                                   316
+#define IMG_TUBE_VERTICAL_LEFT                         317
+#define IMG_TUBE_VERTICAL                              318
+#define IMG_TUBE_RIGHT_UP                              319
+#define IMG_TUBE_HORIZONTAL_UP                         320
+#define IMG_TUBE_LEFT_UP                               321
+#define IMG_TRAP                                       322
+#define IMG_TRAP_ACTIVE                                        323
+#define IMG_DX_SUPABOMB                                        324
+#define IMG_KEY_1                                      325
+#define IMG_KEY_1_EDITOR                               326
+#define IMG_KEY_2                                      327
+#define IMG_KEY_2_EDITOR                               328
+#define IMG_KEY_3                                      329
+#define IMG_KEY_3_EDITOR                               330
+#define IMG_KEY_4                                      331
+#define IMG_KEY_4_EDITOR                               332
+#define IMG_GATE_1                                     333
+#define IMG_GATE_2                                     334
+#define IMG_GATE_3                                     335
+#define IMG_GATE_4                                     336
+#define IMG_GATE_1_GRAY                                        337
+#define IMG_GATE_1_GRAY_EDITOR                         338
+#define IMG_GATE_2_GRAY                                        339
+#define IMG_GATE_2_GRAY_EDITOR                         340
+#define IMG_GATE_3_GRAY                                        341
+#define IMG_GATE_3_GRAY_EDITOR                         342
+#define IMG_GATE_4_GRAY                                        343
+#define IMG_GATE_4_GRAY_EDITOR                         344
+#define IMG_GAME_OF_LIFE                               345
+#define IMG_BIOMAZE                                    346
+#define IMG_PACMAN                                     347
+#define IMG_PACMAN_RIGHT                               348
+#define IMG_PACMAN_UP                                  349
+#define IMG_PACMAN_LEFT                                        350
+#define IMG_PACMAN_DOWN                                        351
+#define IMG_PACMAN_MOVING_RIGHT                                352
+#define IMG_PACMAN_MOVING_UP                           353
+#define IMG_PACMAN_MOVING_LEFT                         354
+#define IMG_PACMAN_MOVING_DOWN                         355
+#define IMG_LAMP                                       356
+#define IMG_LAMP_EDITOR                                        357
+#define IMG_LAMP_ACTIVE                                        358
+#define IMG_TIME_ORB_FULL                              359
+#define IMG_TIME_ORB_EMPTY                             360
+#define IMG_EMERALD_YELLOW                             361
+#define IMG_EMERALD_YELLOW_MOVING                      362
+#define IMG_EMERALD_YELLOW_FALLING                     363
+#define IMG_EMERALD_RED                                        364
+#define IMG_EMERALD_RED_MOVING                         365
+#define IMG_EMERALD_RED_FALLING                                366
+#define IMG_EMERALD_PURPLE                             367
+#define IMG_EMERALD_PURPLE_MOVING                      368
+#define IMG_EMERALD_PURPLE_FALLING                     369
+#define IMG_WALL_EMERALD_YELLOW                                370
+#define IMG_WALL_EMERALD_RED                           371
+#define IMG_WALL_EMERALD_PURPLE                                372
+#define IMG_WALL_BD_DIAMOND                            373
+#define IMG_EXPANDABLE_WALL                            374
+#define IMG_EXPANDABLE_WALL_HORIZONTAL                 375
+#define IMG_EXPANDABLE_WALL_HORIZONTAL_EDITOR          376
+#define IMG_EXPANDABLE_WALL_VERTICAL                   377
+#define IMG_EXPANDABLE_WALL_VERTICAL_EDITOR            378
+#define IMG_EXPANDABLE_WALL_ANY                                379
+#define IMG_EXPANDABLE_WALL_ANY_EDITOR                 380
+#define IMG_EXPANDABLE_WALL_GROWING_LEFT               381
+#define IMG_EXPANDABLE_WALL_GROWING_RIGHT              382
+#define IMG_EXPANDABLE_WALL_GROWING_UP                 383
+#define IMG_EXPANDABLE_WALL_GROWING_DOWN               384
+#define IMG_BLACK_ORB                                  385
+#define IMG_SPEED_PILL                                 386
+#define IMG_DARK_YAMYAM                                        387
+#define IMG_DYNABOMB                                   388
+#define IMG_DYNABOMB_ACTIVE                            389
+#define IMG_DYNABOMB_PLAYER_1                          390
+#define IMG_DYNABOMB_PLAYER_1_ACTIVE                   391
+#define IMG_DYNABOMB_PLAYER_2                          392
+#define IMG_DYNABOMB_PLAYER_2_ACTIVE                   393
+#define IMG_DYNABOMB_PLAYER_3                          394
+#define IMG_DYNABOMB_PLAYER_3_ACTIVE                   395
+#define IMG_DYNABOMB_PLAYER_4                          396
+#define IMG_DYNABOMB_PLAYER_4_ACTIVE                   397
+#define IMG_DYNABOMB_INCREASE_NUMBER                   398
+#define IMG_DYNABOMB_INCREASE_SIZE                     399
+#define IMG_DYNABOMB_INCREASE_POWER                    400
+#define IMG_PIG                                                401
+#define IMG_PIG_DOWN                                   402
+#define IMG_PIG_UP                                     403
+#define IMG_PIG_LEFT                                   404
+#define IMG_PIG_RIGHT                                  405
+#define IMG_PIG_MOVING_DOWN                            406
+#define IMG_PIG_MOVING_UP                              407
+#define IMG_PIG_MOVING_LEFT                            408
+#define IMG_PIG_MOVING_RIGHT                           409
+#define IMG_PIG_DIGGING_DOWN                           410
+#define IMG_PIG_DIGGING_UP                             411
+#define IMG_PIG_DIGGING_LEFT                           412
+#define IMG_PIG_DIGGING_RIGHT                          413
+#define IMG_DRAGON                                     414
+#define IMG_DRAGON_DOWN                                        415
+#define IMG_DRAGON_UP                                  416
+#define IMG_DRAGON_LEFT                                        417
+#define IMG_DRAGON_RIGHT                               418
+#define IMG_DRAGON_MOVING_DOWN                         419
+#define IMG_DRAGON_MOVING_UP                           420
+#define IMG_DRAGON_MOVING_LEFT                         421
+#define IMG_DRAGON_MOVING_RIGHT                                422
+#define IMG_DRAGON_ATTACKING_DOWN                      423
+#define IMG_DRAGON_ATTACKING_UP                                424
+#define IMG_DRAGON_ATTACKING_LEFT                      425
+#define IMG_DRAGON_ATTACKING_RIGHT                     426
+#define IMG_MOLE                                       427
+#define IMG_MOLE_DOWN                                  428
+#define IMG_MOLE_UP                                    429
+#define IMG_MOLE_LEFT                                  430
+#define IMG_MOLE_RIGHT                                 431
+#define IMG_MOLE_MOVING_DOWN                           432
+#define IMG_MOLE_MOVING_UP                             433
+#define IMG_MOLE_MOVING_LEFT                           434
+#define IMG_MOLE_MOVING_RIGHT                          435
+#define IMG_MOLE_DIGGING_DOWN                          436
+#define IMG_MOLE_DIGGING_UP                            437
+#define IMG_MOLE_DIGGING_LEFT                          438
+#define IMG_MOLE_DIGGING_RIGHT                         439
+#define IMG_PENGUIN                                    440
+#define IMG_PENGUIN_EDITOR                             441
+#define IMG_PENGUIN_DOWN                               442
+#define IMG_PENGUIN_UP                                 443
+#define IMG_PENGUIN_LEFT                               444
+#define IMG_PENGUIN_RIGHT                              445
+#define IMG_PENGUIN_MOVING_DOWN                                446
+#define IMG_PENGUIN_MOVING_UP                          447
+#define IMG_PENGUIN_MOVING_LEFT                                448
+#define IMG_PENGUIN_MOVING_RIGHT                       449
+#define IMG_SATELLITE                                  450
+#define IMG_FLAMES_1_LEFT                              451
+#define IMG_FLAMES_2_LEFT                              452
+#define IMG_FLAMES_3_LEFT                              453
+#define IMG_FLAMES_1_RIGHT                             454
+#define IMG_FLAMES_2_RIGHT                             455
+#define IMG_FLAMES_3_RIGHT                             456
+#define IMG_FLAMES_1_UP                                        457
+#define IMG_FLAMES_2_UP                                        458
+#define IMG_FLAMES_3_UP                                        459
+#define IMG_FLAMES_1_DOWN                              460
+#define IMG_FLAMES_2_DOWN                              461
+#define IMG_FLAMES_3_DOWN                              462
+#define IMG_STONEBLOCK                                 463
+#define IMG_PLAYER_1                                   464
+#define IMG_PLAYER_1_EDITOR                            465
+#define IMG_PLAYER_1_DOWN                              466
+#define IMG_PLAYER_1_UP                                        467
+#define IMG_PLAYER_1_LEFT                              468
+#define IMG_PLAYER_1_RIGHT                             469
+#define IMG_PLAYER_1_MOVING_DOWN                       470
+#define IMG_PLAYER_1_MOVING_UP                         471
+#define IMG_PLAYER_1_MOVING_LEFT                       472
+#define IMG_PLAYER_1_MOVING_RIGHT                      473
+#define IMG_PLAYER_1_DIGGING_DOWN                      474
+#define IMG_PLAYER_1_DIGGING_UP                                475
+#define IMG_PLAYER_1_DIGGING_LEFT                      476
+#define IMG_PLAYER_1_DIGGING_RIGHT                     477
+#define IMG_PLAYER_1_COLLECTING_DOWN                   478
+#define IMG_PLAYER_1_COLLECTING_UP                     479
+#define IMG_PLAYER_1_COLLECTING_LEFT                   480
+#define IMG_PLAYER_1_COLLECTING_RIGHT                  481
+#define IMG_PLAYER_1_PUSHING_DOWN                      482
+#define IMG_PLAYER_1_PUSHING_UP                                483
+#define IMG_PLAYER_1_PUSHING_LEFT                      484
+#define IMG_PLAYER_1_PUSHING_RIGHT                     485
+#define IMG_PLAYER_1_SNAPPING_DOWN                     486
+#define IMG_PLAYER_1_SNAPPING_UP                       487
+#define IMG_PLAYER_1_SNAPPING_LEFT                     488
+#define IMG_PLAYER_1_SNAPPING_RIGHT                    489
+#define IMG_PLAYER_2                                   490
+#define IMG_PLAYER_2_EDITOR                            491
+#define IMG_PLAYER_2_DOWN                              492
+#define IMG_PLAYER_2_UP                                        493
+#define IMG_PLAYER_2_LEFT                              494
+#define IMG_PLAYER_2_RIGHT                             495
+#define IMG_PLAYER_2_MOVING_DOWN                       496
+#define IMG_PLAYER_2_MOVING_UP                         497
+#define IMG_PLAYER_2_MOVING_LEFT                       498
+#define IMG_PLAYER_2_MOVING_RIGHT                      499
+#define IMG_PLAYER_2_DIGGING_DOWN                      500
+#define IMG_PLAYER_2_DIGGING_UP                                501
+#define IMG_PLAYER_2_DIGGING_LEFT                      502
+#define IMG_PLAYER_2_DIGGING_RIGHT                     503
+#define IMG_PLAYER_2_COLLECTING_DOWN                   504
+#define IMG_PLAYER_2_COLLECTING_UP                     505
+#define IMG_PLAYER_2_COLLECTING_LEFT                   506
+#define IMG_PLAYER_2_COLLECTING_RIGHT                  507
+#define IMG_PLAYER_2_PUSHING_DOWN                      508
+#define IMG_PLAYER_2_PUSHING_UP                                509
+#define IMG_PLAYER_2_PUSHING_LEFT                      510
+#define IMG_PLAYER_2_PUSHING_RIGHT                     511
+#define IMG_PLAYER_2_SNAPPING_DOWN                     512
+#define IMG_PLAYER_2_SNAPPING_UP                       513
+#define IMG_PLAYER_2_SNAPPING_LEFT                     514
+#define IMG_PLAYER_2_SNAPPING_RIGHT                    515
+#define IMG_PLAYER_3                                   516
+#define IMG_PLAYER_3_EDITOR                            517
+#define IMG_PLAYER_3_DOWN                              518
+#define IMG_PLAYER_3_UP                                        519
+#define IMG_PLAYER_3_LEFT                              520
+#define IMG_PLAYER_3_RIGHT                             521
+#define IMG_PLAYER_3_MOVING_DOWN                       522
+#define IMG_PLAYER_3_MOVING_UP                         523
+#define IMG_PLAYER_3_MOVING_LEFT                       524
+#define IMG_PLAYER_3_MOVING_RIGHT                      525
+#define IMG_PLAYER_3_DIGGING_DOWN                      526
+#define IMG_PLAYER_3_DIGGING_UP                                527
+#define IMG_PLAYER_3_DIGGING_LEFT                      528
+#define IMG_PLAYER_3_DIGGING_RIGHT                     529
+#define IMG_PLAYER_3_COLLECTING_DOWN                   530
+#define IMG_PLAYER_3_COLLECTING_UP                     531
+#define IMG_PLAYER_3_COLLECTING_LEFT                   532
+#define IMG_PLAYER_3_COLLECTING_RIGHT                  533
+#define IMG_PLAYER_3_PUSHING_DOWN                      534
+#define IMG_PLAYER_3_PUSHING_UP                                535
+#define IMG_PLAYER_3_PUSHING_LEFT                      536
+#define IMG_PLAYER_3_PUSHING_RIGHT                     537
+#define IMG_PLAYER_3_SNAPPING_DOWN                     538
+#define IMG_PLAYER_3_SNAPPING_UP                       539
+#define IMG_PLAYER_3_SNAPPING_LEFT                     540
+#define IMG_PLAYER_3_SNAPPING_RIGHT                    541
+#define IMG_PLAYER_4                                   542
+#define IMG_PLAYER_4_EDITOR                            543
+#define IMG_PLAYER_4_DOWN                              544
+#define IMG_PLAYER_4_UP                                        545
+#define IMG_PLAYER_4_LEFT                              546
+#define IMG_PLAYER_4_RIGHT                             547
+#define IMG_PLAYER_4_MOVING_DOWN                       548
+#define IMG_PLAYER_4_MOVING_UP                         549
+#define IMG_PLAYER_4_MOVING_LEFT                       550
+#define IMG_PLAYER_4_MOVING_RIGHT                      551
+#define IMG_PLAYER_4_DIGGING_DOWN                      552
+#define IMG_PLAYER_4_DIGGING_UP                                553
+#define IMG_PLAYER_4_DIGGING_LEFT                      554
+#define IMG_PLAYER_4_DIGGING_RIGHT                     555
+#define IMG_PLAYER_4_COLLECTING_DOWN                   556
+#define IMG_PLAYER_4_COLLECTING_UP                     557
+#define IMG_PLAYER_4_COLLECTING_LEFT                   558
+#define IMG_PLAYER_4_COLLECTING_RIGHT                  559
+#define IMG_PLAYER_4_PUSHING_DOWN                      560
+#define IMG_PLAYER_4_PUSHING_UP                                561
+#define IMG_PLAYER_4_PUSHING_LEFT                      562
+#define IMG_PLAYER_4_PUSHING_RIGHT                     563
+#define IMG_PLAYER_4_SNAPPING_DOWN                     564
+#define IMG_PLAYER_4_SNAPPING_UP                       565
+#define IMG_PLAYER_4_SNAPPING_LEFT                     566
+#define IMG_PLAYER_4_SNAPPING_RIGHT                    567
+#define IMG_DEFAULT_EXPLODING                          568
+#define IMG_TWINKLE_BLUE                               569
+#define IMG_TWINKLE_WHITE                              570
+#define IMG_STEELWALL_TOPLEFT                          571
+#define IMG_STEELWALL_TOPRIGHT                         572
+#define IMG_STEELWALL_BOTTOMLEFT                       573
+#define IMG_STEELWALL_BOTTOMRIGHT                      574
+#define IMG_STEELWALL_HORIZONTAL                       575
+#define IMG_STEELWALL_VERTICAL                         576
+#define IMG_STEELWALL_TOPLEFT_EDITOR                   577
+#define IMG_STEELWALL_TOPRIGHT_EDITOR                  578
+#define IMG_STEELWALL_BOTTOMLEFT_EDITOR                        579
+#define IMG_STEELWALL_BOTTOMRIGHT_EDITOR               580
+#define IMG_STEELWALL_HORIZONTAL_EDITOR                        581
+#define IMG_STEELWALL_VERTICAL_EDITOR                  582
+#define IMG_INVISIBLE_STEELWALL_TOPLEFT                        583
+#define IMG_INVISIBLE_STEELWALL_TOPRIGHT               584
+#define IMG_INVISIBLE_STEELWALL_BOTTOMLEFT             585
+#define IMG_INVISIBLE_STEELWALL_BOTTOMRIGHT            586
+#define IMG_INVISIBLE_STEELWALL_HORIZONTAL             587
+#define IMG_INVISIBLE_STEELWALL_VERTICAL               588
+#define IMG_INVISIBLE_STEELWALL_TOPLEFT_EDITOR         589
+#define IMG_INVISIBLE_STEELWALL_TOPRIGHT_EDITOR                590
+#define IMG_INVISIBLE_STEELWALL_BOTTOMLEFT_EDITOR      591
+#define IMG_INVISIBLE_STEELWALL_BOTTOMRIGHT_EDITOR     592
+#define IMG_INVISIBLE_STEELWALL_HORIZONTAL_EDITOR      593
+#define IMG_INVISIBLE_STEELWALL_VERTICAL_EDITOR                594
+#define IMG_ARROW_LEFT                                 595
+#define IMG_ARROW_RIGHT                                        596
+#define IMG_ARROW_UP                                   597
+#define IMG_ARROW_DOWN                                 598
+#define IMG_CHAR_SPACE                                 599
+#define IMG_CHAR_EXCLAM                                        600
+#define IMG_CHAR_QUOTEDBL                              601
+#define IMG_CHAR_NUMBERSIGN                            602
+#define IMG_CHAR_DOLLAR                                        603
+#define IMG_CHAR_PROCENT                               604
+#define IMG_CHAR_AMPERSAND                             605
+#define IMG_CHAR_APOSTROPHE                            606
+#define IMG_CHAR_PARENLEFT                             607
+#define IMG_CHAR_PARENRIGHT                            608
+#define IMG_CHAR_ASTERISK                              609
+#define IMG_CHAR_PLUS                                  610
+#define IMG_CHAR_COMMA                                 611
+#define IMG_CHAR_MINUS                                 612
+#define IMG_CHAR_PERIOD                                        613
+#define IMG_CHAR_SLASH                                 614
+#define IMG_CHAR_0                                     615
+#define IMG_CHAR_1                                     616
+#define IMG_CHAR_2                                     617
+#define IMG_CHAR_3                                     618
+#define IMG_CHAR_4                                     619
+#define IMG_CHAR_5                                     620
+#define IMG_CHAR_6                                     621
+#define IMG_CHAR_7                                     622
+#define IMG_CHAR_8                                     623
+#define IMG_CHAR_9                                     624
+#define IMG_CHAR_COLON                                 625
+#define IMG_CHAR_SEMICOLON                             626
+#define IMG_CHAR_LESS                                  627
+#define IMG_CHAR_EQUAL                                 628
+#define IMG_CHAR_GREATER                               629
+#define IMG_CHAR_QUESTION                              630
+#define IMG_CHAR_AT                                    631
+#define IMG_CHAR_A                                     632
+#define IMG_CHAR_B                                     633
+#define IMG_CHAR_C                                     634
+#define IMG_CHAR_D                                     635
+#define IMG_CHAR_E                                     636
+#define IMG_CHAR_F                                     637
+#define IMG_CHAR_G                                     638
+#define IMG_CHAR_H                                     639
+#define IMG_CHAR_I                                     640
+#define IMG_CHAR_J                                     641
+#define IMG_CHAR_K                                     642
+#define IMG_CHAR_L                                     643
+#define IMG_CHAR_M                                     644
+#define IMG_CHAR_N                                     645
+#define IMG_CHAR_O                                     646
+#define IMG_CHAR_P                                     647
+#define IMG_CHAR_Q                                     648
+#define IMG_CHAR_R                                     649
+#define IMG_CHAR_S                                     650
+#define IMG_CHAR_T                                     651
+#define IMG_CHAR_U                                     652
+#define IMG_CHAR_V                                     653
+#define IMG_CHAR_W                                     654
+#define IMG_CHAR_X                                     655
+#define IMG_CHAR_Y                                     656
+#define IMG_CHAR_Z                                     657
+#define IMG_CHAR_BRACKETLEFT                           658
+#define IMG_CHAR_BACKSLASH                             659
+#define IMG_CHAR_BRACKETRIGHT                          660
+#define IMG_CHAR_ASCIICIRCUM                           661
+#define IMG_CHAR_UNDERSCORE                            662
+#define IMG_CHAR_COPYRIGHT                             663
+#define IMG_CHAR_AUMLAUT                               664
+#define IMG_CHAR_OUMLAUT                               665
+#define IMG_CHAR_UUMLAUT                               666
+#define IMG_CHAR_DEGREE                                        667
+#define IMG_CHAR_TRADEMARK                             668
+#define IMG_CHAR_CURSOR                                        669
+#define IMG_CUSTOM_1                                   670
+#define IMG_CUSTOM_1_EDITOR                            671
+#define IMG_CUSTOM_2                                   672
+#define IMG_CUSTOM_2_EDITOR                            673
+#define IMG_CUSTOM_3                                   674
+#define IMG_CUSTOM_3_EDITOR                            675
+#define IMG_CUSTOM_4                                   676
+#define IMG_CUSTOM_4_EDITOR                            677
+#define IMG_CUSTOM_5                                   678
+#define IMG_CUSTOM_5_EDITOR                            679
+#define IMG_CUSTOM_6                                   680
+#define IMG_CUSTOM_6_EDITOR                            681
+#define IMG_CUSTOM_7                                   682
+#define IMG_CUSTOM_7_EDITOR                            683
+#define IMG_CUSTOM_8                                   684
+#define IMG_CUSTOM_8_EDITOR                            685
+#define IMG_CUSTOM_9                                   686
+#define IMG_CUSTOM_9_EDITOR                            687
+#define IMG_CUSTOM_10                                  688
+#define IMG_CUSTOM_10_EDITOR                           689
+#define IMG_CUSTOM_11                                  690
+#define IMG_CUSTOM_11_EDITOR                           691
+#define IMG_CUSTOM_12                                  692
+#define IMG_CUSTOM_12_EDITOR                           693
+#define IMG_CUSTOM_13                                  694
+#define IMG_CUSTOM_13_EDITOR                           695
+#define IMG_CUSTOM_14                                  696
+#define IMG_CUSTOM_14_EDITOR                           697
+#define IMG_CUSTOM_15                                  698
+#define IMG_CUSTOM_15_EDITOR                           699
+#define IMG_CUSTOM_16                                  700
+#define IMG_CUSTOM_16_EDITOR                           701
+#define IMG_CUSTOM_17                                  702
+#define IMG_CUSTOM_17_EDITOR                           703
+#define IMG_CUSTOM_18                                  704
+#define IMG_CUSTOM_18_EDITOR                           705
+#define IMG_CUSTOM_19                                  706
+#define IMG_CUSTOM_19_EDITOR                           707
+#define IMG_CUSTOM_20                                  708
+#define IMG_CUSTOM_20_EDITOR                           709
+#define IMG_CUSTOM_21                                  710
+#define IMG_CUSTOM_21_EDITOR                           711
+#define IMG_CUSTOM_22                                  712
+#define IMG_CUSTOM_22_EDITOR                           713
+#define IMG_CUSTOM_23                                  714
+#define IMG_CUSTOM_23_EDITOR                           715
+#define IMG_CUSTOM_24                                  716
+#define IMG_CUSTOM_24_EDITOR                           717
+#define IMG_CUSTOM_25                                  718
+#define IMG_CUSTOM_25_EDITOR                           719
+#define IMG_CUSTOM_26                                  720
+#define IMG_CUSTOM_26_EDITOR                           721
+#define IMG_CUSTOM_27                                  722
+#define IMG_CUSTOM_27_EDITOR                           723
+#define IMG_CUSTOM_28                                  724
+#define IMG_CUSTOM_28_EDITOR                           725
+#define IMG_CUSTOM_29                                  726
+#define IMG_CUSTOM_29_EDITOR                           727
+#define IMG_CUSTOM_30                                  728
+#define IMG_CUSTOM_30_EDITOR                           729
+#define IMG_CUSTOM_31                                  730
+#define IMG_CUSTOM_31_EDITOR                           731
+#define IMG_CUSTOM_32                                  732
+#define IMG_CUSTOM_32_EDITOR                           733
+#define IMG_CUSTOM_33                                  734
+#define IMG_CUSTOM_33_EDITOR                           735
+#define IMG_CUSTOM_34                                  736
+#define IMG_CUSTOM_34_EDITOR                           737
+#define IMG_CUSTOM_35                                  738
+#define IMG_CUSTOM_35_EDITOR                           739
+#define IMG_CUSTOM_36                                  740
+#define IMG_CUSTOM_36_EDITOR                           741
+#define IMG_CUSTOM_37                                  742
+#define IMG_CUSTOM_37_EDITOR                           743
+#define IMG_CUSTOM_38                                  744
+#define IMG_CUSTOM_38_EDITOR                           745
+#define IMG_CUSTOM_39                                  746
+#define IMG_CUSTOM_39_EDITOR                           747
+#define IMG_CUSTOM_40                                  748
+#define IMG_CUSTOM_40_EDITOR                           749
+#define IMG_CUSTOM_41                                  750
+#define IMG_CUSTOM_41_EDITOR                           751
+#define IMG_CUSTOM_42                                  752
+#define IMG_CUSTOM_42_EDITOR                           753
+#define IMG_CUSTOM_43                                  754
+#define IMG_CUSTOM_43_EDITOR                           755
+#define IMG_CUSTOM_44                                  756
+#define IMG_CUSTOM_44_EDITOR                           757
+#define IMG_CUSTOM_45                                  758
+#define IMG_CUSTOM_45_EDITOR                           759
+#define IMG_CUSTOM_46                                  760
+#define IMG_CUSTOM_46_EDITOR                           761
+#define IMG_CUSTOM_47                                  762
+#define IMG_CUSTOM_47_EDITOR                           763
+#define IMG_CUSTOM_48                                  764
+#define IMG_CUSTOM_48_EDITOR                           765
+#define IMG_CUSTOM_49                                  766
+#define IMG_CUSTOM_49_EDITOR                           767
+#define IMG_CUSTOM_50                                  768
+#define IMG_CUSTOM_50_EDITOR                           769
+#define IMG_CUSTOM_51                                  770
+#define IMG_CUSTOM_51_EDITOR                           771
+#define IMG_CUSTOM_52                                  772
+#define IMG_CUSTOM_52_EDITOR                           773
+#define IMG_CUSTOM_53                                  774
+#define IMG_CUSTOM_53_EDITOR                           775
+#define IMG_CUSTOM_54                                  776
+#define IMG_CUSTOM_54_EDITOR                           777
+#define IMG_CUSTOM_55                                  778
+#define IMG_CUSTOM_55_EDITOR                           779
+#define IMG_CUSTOM_56                                  780
+#define IMG_CUSTOM_56_EDITOR                           781
+#define IMG_CUSTOM_57                                  782
+#define IMG_CUSTOM_57_EDITOR                           783
+#define IMG_CUSTOM_58                                  784
+#define IMG_CUSTOM_58_EDITOR                           785
+#define IMG_CUSTOM_59                                  786
+#define IMG_CUSTOM_59_EDITOR                           787
+#define IMG_CUSTOM_60                                  788
+#define IMG_CUSTOM_60_EDITOR                           789
+#define IMG_CUSTOM_61                                  790
+#define IMG_CUSTOM_61_EDITOR                           791
+#define IMG_CUSTOM_62                                  792
+#define IMG_CUSTOM_62_EDITOR                           793
+#define IMG_CUSTOM_63                                  794
+#define IMG_CUSTOM_63_EDITOR                           795
+#define IMG_CUSTOM_64                                  796
+#define IMG_CUSTOM_64_EDITOR                           797
+#define IMG_CUSTOM_65                                  798
+#define IMG_CUSTOM_65_EDITOR                           799
+#define IMG_CUSTOM_66                                  800
+#define IMG_CUSTOM_66_EDITOR                           801
+#define IMG_CUSTOM_67                                  802
+#define IMG_CUSTOM_67_EDITOR                           803
+#define IMG_CUSTOM_68                                  804
+#define IMG_CUSTOM_68_EDITOR                           805
+#define IMG_CUSTOM_69                                  806
+#define IMG_CUSTOM_69_EDITOR                           807
+#define IMG_CUSTOM_70                                  808
+#define IMG_CUSTOM_70_EDITOR                           809
+#define IMG_CUSTOM_71                                  810
+#define IMG_CUSTOM_71_EDITOR                           811
+#define IMG_CUSTOM_72                                  812
+#define IMG_CUSTOM_72_EDITOR                           813
+#define IMG_CUSTOM_73                                  814
+#define IMG_CUSTOM_73_EDITOR                           815
+#define IMG_CUSTOM_74                                  816
+#define IMG_CUSTOM_74_EDITOR                           817
+#define IMG_CUSTOM_75                                  818
+#define IMG_CUSTOM_75_EDITOR                           819
+#define IMG_CUSTOM_76                                  820
+#define IMG_CUSTOM_76_EDITOR                           821
+#define IMG_CUSTOM_77                                  822
+#define IMG_CUSTOM_77_EDITOR                           823
+#define IMG_CUSTOM_78                                  824
+#define IMG_CUSTOM_78_EDITOR                           825
+#define IMG_CUSTOM_79                                  826
+#define IMG_CUSTOM_79_EDITOR                           827
+#define IMG_CUSTOM_80                                  828
+#define IMG_CUSTOM_80_EDITOR                           829
+#define IMG_CUSTOM_81                                  830
+#define IMG_CUSTOM_81_EDITOR                           831
+#define IMG_CUSTOM_82                                  832
+#define IMG_CUSTOM_82_EDITOR                           833
+#define IMG_CUSTOM_83                                  834
+#define IMG_CUSTOM_83_EDITOR                           835
+#define IMG_CUSTOM_84                                  836
+#define IMG_CUSTOM_84_EDITOR                           837
+#define IMG_CUSTOM_85                                  838
+#define IMG_CUSTOM_85_EDITOR                           839
+#define IMG_CUSTOM_86                                  840
+#define IMG_CUSTOM_86_EDITOR                           841
+#define IMG_CUSTOM_87                                  842
+#define IMG_CUSTOM_87_EDITOR                           843
+#define IMG_CUSTOM_88                                  844
+#define IMG_CUSTOM_88_EDITOR                           845
+#define IMG_CUSTOM_89                                  846
+#define IMG_CUSTOM_89_EDITOR                           847
+#define IMG_CUSTOM_90                                  848
+#define IMG_CUSTOM_90_EDITOR                           849
+#define IMG_CUSTOM_91                                  850
+#define IMG_CUSTOM_91_EDITOR                           851
+#define IMG_CUSTOM_92                                  852
+#define IMG_CUSTOM_92_EDITOR                           853
+#define IMG_CUSTOM_93                                  854
+#define IMG_CUSTOM_93_EDITOR                           855
+#define IMG_CUSTOM_94                                  856
+#define IMG_CUSTOM_94_EDITOR                           857
+#define IMG_CUSTOM_95                                  858
+#define IMG_CUSTOM_95_EDITOR                           859
+#define IMG_CUSTOM_96                                  860
+#define IMG_CUSTOM_96_EDITOR                           861
+#define IMG_CUSTOM_97                                  862
+#define IMG_CUSTOM_97_EDITOR                           863
+#define IMG_CUSTOM_98                                  864
+#define IMG_CUSTOM_98_EDITOR                           865
+#define IMG_CUSTOM_99                                  866
+#define IMG_CUSTOM_99_EDITOR                           867
+#define IMG_CUSTOM_100                                 868
+#define IMG_CUSTOM_100_EDITOR                          869
+#define IMG_CUSTOM_101                                 870
+#define IMG_CUSTOM_101_EDITOR                          871
+#define IMG_CUSTOM_102                                 872
+#define IMG_CUSTOM_102_EDITOR                          873
+#define IMG_CUSTOM_103                                 874
+#define IMG_CUSTOM_103_EDITOR                          875
+#define IMG_CUSTOM_104                                 876
+#define IMG_CUSTOM_104_EDITOR                          877
+#define IMG_CUSTOM_105                                 878
+#define IMG_CUSTOM_105_EDITOR                          879
+#define IMG_CUSTOM_106                                 880
+#define IMG_CUSTOM_106_EDITOR                          881
+#define IMG_CUSTOM_107                                 882
+#define IMG_CUSTOM_107_EDITOR                          883
+#define IMG_CUSTOM_108                                 884
+#define IMG_CUSTOM_108_EDITOR                          885
+#define IMG_CUSTOM_109                                 886
+#define IMG_CUSTOM_109_EDITOR                          887
+#define IMG_CUSTOM_110                                 888
+#define IMG_CUSTOM_110_EDITOR                          889
+#define IMG_CUSTOM_111                                 890
+#define IMG_CUSTOM_111_EDITOR                          891
+#define IMG_CUSTOM_112                                 892
+#define IMG_CUSTOM_112_EDITOR                          893
+#define IMG_CUSTOM_113                                 894
+#define IMG_CUSTOM_113_EDITOR                          895
+#define IMG_CUSTOM_114                                 896
+#define IMG_CUSTOM_114_EDITOR                          897
+#define IMG_CUSTOM_115                                 898
+#define IMG_CUSTOM_115_EDITOR                          899
+#define IMG_CUSTOM_116                                 900
+#define IMG_CUSTOM_116_EDITOR                          901
+#define IMG_CUSTOM_117                                 902
+#define IMG_CUSTOM_117_EDITOR                          903
+#define IMG_CUSTOM_118                                 904
+#define IMG_CUSTOM_118_EDITOR                          905
+#define IMG_CUSTOM_119                                 906
+#define IMG_CUSTOM_119_EDITOR                          907
+#define IMG_CUSTOM_120                                 908
+#define IMG_CUSTOM_120_EDITOR                          909
+#define IMG_CUSTOM_121                                 910
+#define IMG_CUSTOM_121_EDITOR                          911
+#define IMG_CUSTOM_122                                 912
+#define IMG_CUSTOM_122_EDITOR                          913
+#define IMG_CUSTOM_123                                 914
+#define IMG_CUSTOM_123_EDITOR                          915
+#define IMG_CUSTOM_124                                 916
+#define IMG_CUSTOM_124_EDITOR                          917
+#define IMG_CUSTOM_125                                 918
+#define IMG_CUSTOM_125_EDITOR                          919
+#define IMG_CUSTOM_126                                 920
+#define IMG_CUSTOM_126_EDITOR                          921
+#define IMG_CUSTOM_127                                 922
+#define IMG_CUSTOM_127_EDITOR                          923
+#define IMG_CUSTOM_128                                 924
+#define IMG_CUSTOM_128_EDITOR                          925
+#define IMG_TOON_1                                     926
+#define IMG_TOON_2                                     927
+#define IMG_TOON_3                                     928
+#define IMG_TOON_4                                     929
+#define IMG_TOON_5                                     930
+#define IMG_TOON_6                                     931
+#define IMG_TOON_7                                     932
+#define IMG_TOON_8                                     933
+#define IMG_TOON_9                                     934
+#define IMG_TOON_10                                    935
+#define IMG_TOON_11                                    936
+#define IMG_TOON_12                                    937
+#define IMG_TOON_13                                    938
+#define IMG_TOON_14                                    939
+#define IMG_TOON_15                                    940
+#define IMG_TOON_16                                    941
+#define IMG_TOON_17                                    942
+#define IMG_TOON_18                                    943
+#define IMG_TOON_19                                    944
+#define IMG_TOON_20                                    945
+#define IMG_MENU_CALIBRATE_RED                         946
+#define IMG_MENU_CALIBRATE_BLUE                                947
+#define IMG_MENU_CALIBRATE_YELLOW                      948
+#define IMG_MENU_BUTTON                                        949
+#define IMG_MENU_BUTTON_ACTIVE                         950
+#define IMG_MENU_BUTTON_LEFT                           951
+#define IMG_MENU_BUTTON_RIGHT                          952
+#define IMG_MENU_BUTTON_UP                             953
+#define IMG_MENU_BUTTON_DOWN                           954
+#define IMG_MENU_BUTTON_LEFT_ACTIVE                    955
+#define IMG_MENU_BUTTON_RIGHT_ACTIVE                   956
+#define IMG_MENU_BUTTON_UP_ACTIVE                      957
+#define IMG_MENU_BUTTON_DOWN_ACTIVE                    958
+#define IMG_MENU_SCROLLBAR                             959
+#define IMG_MENU_SCROLLBAR_ACTIVE                      960
+#define IMG_FONT_INITIAL_1                             961
+#define IMG_FONT_INITIAL_2                             962
+#define IMG_FONT_INITIAL_3                             963
+#define IMG_FONT_INITIAL_4                             964
+#define IMG_FONT_TITLE_1                               965
+#define IMG_FONT_TITLE_1_LEVELS                                966
+#define IMG_FONT_TITLE_2                               967
+#define IMG_FONT_MENU_1                                        968
+#define IMG_FONT_MENU_2                                        969
+#define IMG_FONT_TEXT_1                                        970
+#define IMG_FONT_TEXT_1_LEVELS                         971
+#define IMG_FONT_TEXT_1_PREVIEW                                972
+#define IMG_FONT_TEXT_1_SCORES                         973
+#define IMG_FONT_TEXT_1_ACTIVE_SCORES                  974
+#define IMG_FONT_TEXT_2                                        975
+#define IMG_FONT_TEXT_2_LEVELS                         976
+#define IMG_FONT_TEXT_2_PREVIEW                                977
+#define IMG_FONT_TEXT_2_SCORES                         978
+#define IMG_FONT_TEXT_2_ACTIVE_SCORES                  979
+#define IMG_FONT_TEXT_3                                        980
+#define IMG_FONT_TEXT_3_LEVELS                         981
+#define IMG_FONT_TEXT_3_PREVIEW                                982
+#define IMG_FONT_TEXT_3_SCORES                         983
+#define IMG_FONT_TEXT_3_ACTIVE_SCORES                  984
+#define IMG_FONT_TEXT_4                                        985
+#define IMG_FONT_TEXT_4_LEVELS                         986
+#define IMG_FONT_TEXT_4_SCORES                         987
+#define IMG_FONT_TEXT_4_ACTIVE_SCORES                  988
+#define IMG_FONT_INPUT_1                               989
+#define IMG_FONT_INPUT_1_MAIN                          990
+#define IMG_FONT_INPUT_1_ACTIVE                                991
+#define IMG_FONT_INPUT_1_ACTIVE_MAIN                   992
+#define IMG_FONT_INPUT_1_ACTIVE_SETUP                  993
+#define IMG_FONT_INPUT_2                               994
+#define IMG_FONT_INPUT_2_ACTIVE                                995
+#define IMG_FONT_OPTION_OFF                            996
+#define IMG_FONT_OPTION_ON                             997
+#define IMG_FONT_VALUE_1                               998
+#define IMG_FONT_VALUE_2                               999
+#define IMG_FONT_VALUE_OLD                             1000
+#define IMG_FONT_LEVEL_NUMBER                          1001
+#define IMG_FONT_TAPE_RECORDER                         1002
+#define IMG_FONT_GAME_INFO                             1003
+#define IMG_GLOBAL_BORDER                              1004
+#define IMG_GLOBAL_DOOR                                        1005
+#define IMG_EDITOR_ELEMENT_BORDER                      1006
+#define IMG_EDITOR_ELEMENT_BORDER_INPUT                        1007
+#define IMG_BACKGROUND                                 1008
+#define IMG_BACKGROUND_MAIN                            1009
+#define IMG_BACKGROUND_LEVELS                          1010
+#define IMG_BACKGROUND_SCORES                          1011
+#define IMG_BACKGROUND_EDITOR                          1012
+#define IMG_BACKGROUND_INFO                            1013
+#define IMG_BACKGROUND_SETUP                           1014
+#define IMG_BACKGROUND_DOOR                            1015
+
+#define NUM_IMAGE_FILES                                        1016
+
+#endif /* CONF_GFX_H */
diff --git a/src/conf_snd.c b/src/conf_snd.c
new file mode 100644 (file)
index 0000000..8a90bea
--- /dev/null
@@ -0,0 +1,261 @@
+/***********************************************************
+* Rocks'n'Diamonds -- McDuffin Strikes Back!               *
+*----------------------------------------------------------*
+* (c) 1995-2002 Artsoft Entertainment                      *
+*               Holger Schemel                             *
+*               Detmolder Strasse 189                      *
+*               33604 Bielefeld                            *
+*               Germany                                    *
+*               e-mail: info@artsoft.org                   *
+*----------------------------------------------------------*
+* conf_snd.c                                               *
+***********************************************************/
+
+#include "libgame/libgame.h"
+#include "main.h"
+
+
+/* List values that are not defined in the configuration file are set to
+   reliable default values. If that value is GFX_ARG_UNDEFINED, it will
+   be dynamically determined, using some of the other list values. */
+
+struct ConfigInfo sound_config_suffix[] =
+{
+  { ".mode_loop",                      ARG_UNDEFINED,  TYPE_BOOLEAN },
+
+  { 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"            },
+  { "[sp_default].exploding",          "booom.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"             },
+
+  /* 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_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      },
+
+  /* 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",                  UNDEFINED_FILENAME      },
+  { "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"             },
+  { "[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].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      },
+
+  /* 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"              },
+  { "invisible_sand.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      },
+
+  /* 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      },
+
+  /* sounds not associated to game elements (used for menu screens etc.) */
+  /* keyword to stop parser: "NO_MORE_ELEMENT_SOUNDS" <-- do not change! */
+
+  /* sounds for other game actions */
+  { "game.starting",                   UNDEFINED_FILENAME      },
+  { "game.running_out_of_time",                "gong.wav"              },
+  { "game.leveltime_bonus",            "sirr.wav"              },
+  { "game.losing",                     "lachen.wav"            },
+  { "game.winning",                    UNDEFINED_FILENAME      },
+  { "game.sokoban_solving",            "buing.wav"             },
+
+  /* sounds for other non-game actions */
+  { "door.opening",                    "oeffnen.wav"           },
+  { "door.closing",                    "oeffnen.wav"           },
+
+  { "background.SCORES",               "halloffame.wav"        },
+  { "background.SCORES.mode_loop",     "false"                 },
+
+  { "background.INFO",                 "rhythmloop.wav"        },
+  { "background.INFO.mode_loop",       "true"                  },
+
+#if 0
+  { "[not used]",                      "antigrav.wav"          },
+  { "[not used]",                      "bong.wav"              },
+  { "[not used]",                      "fuel.wav"              },
+  { "[not used]",                      "holz.wav"              },
+  { "[not used]",                      "hui.wav"               },
+  { "[not used]",                      "kabumm.wav"            },
+  { "[not used]",                      "kink.wav"              },
+  { "[not used]",                      "kling.wav"             },
+  { "[not used]",                      "krach.wav"             },
+  { "[not used]",                      "laser.wav"             },
+  { "[not used]",                      "quiek.wav"             },
+  { "[not used]",                      "rumms.wav"             },
+  { "[not used]",                      "schlopp.wav"           },
+  { "[not used]",                      "schrff.wav"            },
+  { "[not used]",                      "schwirr.wav"           },
+  { "[not used]",                      "slurp.wav"             },
+  { "[not used]",                      "sproing.wav"           },
+  { "[not used]",                      "warnton.wav"           },
+  { "[not used]",                      "whoosh.wav"            },
+  { "[not used]",                      "boom.wav"              },
+#endif
+
+  { NULL,                              NULL                    }
+};
diff --git a/src/conf_snd.h b/src/conf_snd.h
new file mode 100644 (file)
index 0000000..9436602
--- /dev/null
@@ -0,0 +1,199 @@
+/***********************************************************
+* Rocks'n'Diamonds -- McDuffin Strikes Back!               *
+*----------------------------------------------------------*
+* (c) 1995-2002 Artsoft Entertainment                      *
+*               Holger Schemel                             *
+*               Detmolder Strasse 189                      *
+*               33604 Bielefeld                            *
+*               Germany                                    *
+*               e-mail: info@artsoft.org                   *
+*----------------------------------------------------------*
+* conf_snd.h                                               *
+***********************************************************/
+
+/* ----- this file was automatically generated -- do not edit by hand ----- */
+
+#ifndef CONF_SND_H
+#define CONF_SND_H
+
+/* values for sounds configuration */
+
+#define SND_CLASS_DEFAULT_DIGGING                              0
+#define SND_CLASS_DEFAULT_COLLECTING                           1
+#define SND_CLASS_DEFAULT_SNAPPING                             2
+#define SND_CLASS_DEFAULT_PUSHING                              3
+#define SND_CLASS_DEFAULT_IMPACT                               4
+#define SND_CLASS_DEFAULT_WALKING                              5
+#define SND_CLASS_DEFAULT_PASSING                              6
+#define SND_CLASS_DEFAULT_DYING                                        7
+#define SND_CLASS_DEFAULT_EXPLODING                            8
+#define SND_CLASS_SP_DEFAULT_EXPLODING                         9
+#define SND_BD_DIAMOND_COLLECTING                              10
+#define SND_BD_DIAMOND_IMPACT                          11
+#define SND_BD_ROCK_PUSHING                                    12
+#define SND_BD_ROCK_IMPACT                                     13
+#define SND_BD_MAGIC_WALL_ACTIVATING                   14
+#define SND_BD_MAGIC_WALL_ACTIVE                               15
+#define SND_BD_MAGIC_WALL_FILLING                              16
+#define SND_BD_AMOEBA_WAITING                          17
+#define SND_BD_AMOEBA_GROWING                          18
+#define SND_BD_AMOEBA_TURNING_TO_GEM                   19
+#define SND_BD_AMOEBA_TURNING_TO_ROCK                  20
+#define SND_BD_BUTTERFLY_MOVING                                21
+#define SND_BD_BUTTERFLY_WAITING                               22
+#define SND_BD_FIREFLY_MOVING                          23
+#define SND_BD_FIREFLY_WAITING                         24
+#define SND_SP_BASE_DIGGING                                    25
+#define SND_SP_BUGGY_BASE_DIGGING                              26
+#define SND_SP_BUGGY_BASE_ACTIVE                               27
+#define SND_SP_INFOTRON_COLLECTING                             28
+#define SND_SP_INFOTRON_IMPACT                         29
+#define SND_SP_ZONK_PUSHING                                    30
+#define SND_SP_ZONK_IMPACT                                     31
+#define SND_SP_DISK_RED_COLLECTING                             32
+#define SND_SP_DISK_ORANGE_PUSHING                             33
+#define SND_SP_DISK_YELLOW_PUSHING                             34
+#define SND_CLASS_SP_PORT_PASSING                              35
+#define SND_CLASS_SP_EXIT_PASSING                              36
+#define SND_CLASS_SP_EXIT_OPENING                              37
+#define SND_SP_SNIKSNAK_MOVING                         38
+#define SND_SP_SNIKSNAK_WAITING                                39
+#define SND_SP_ELECTRON_MOVING                         40
+#define SND_SP_ELECTRON_WAITING                                41
+#define SND_SP_TERMINAL_ACTIVATING                             42
+#define SND_SP_TERMINAL_ACTIVE                         43
+#define SND_CLASS_SOKOBAN_PUSHING                              44
+#define SND_CLASS_SOKOBAN_FILLING                              45
+#define SND_CLASS_SOKOBAN_EMPTYING                             46
+#define SND_CLASS_PLAYER_MOVING                                        47
+#define SND_SAND_DIGGING                                       48
+#define SND_EMERALD_COLLECTING                         49
+#define SND_EMERALD_IMPACT                                     50
+#define SND_DIAMOND_COLLECTING                         51
+#define SND_DIAMOND_IMPACT                                     52
+#define SND_DIAMOND_BREAKING                           53
+#define SND_ROCK_PUSHING                                       54
+#define SND_ROCK_IMPACT                                        55
+#define SND_BOMB_PUSHING                                       56
+#define SND_NUT_PUSHING                                        57
+#define SND_NUT_BREAKING                                       58
+#define SND_NUT_IMPACT                                 59
+#define SND_CLASS_DYNAMITE_COLLECTING                          60
+#define SND_CLASS_DYNAMITE_DROPPING                            61
+#define SND_CLASS_DYNAMITE_ACTIVE                              62
+#define SND_CLASS_KEY_COLLECTING                               63
+#define SND_CLASS_GATE_PASSING                                 64
+#define SND_BUG_MOVING                                 65
+#define SND_BUG_WAITING                                        66
+#define SND_SPACESHIP_MOVING                           67
+#define SND_SPACESHIP_WAITING                          68
+#define SND_YAMYAM_MOVING                                      69
+#define SND_YAMYAM_WAITING                                     70
+#define SND_YAMYAM_DIGGING                                     71
+#define SND_ROBOT_MOVING                                       72
+#define SND_ROBOT_WAITING                                      73
+#define SND_ROBOT_WHEEL_ACTIVATING                             74
+#define SND_ROBOT_WHEEL_ACTIVE                         75
+#define SND_MAGIC_WALL_ACTIVATING                              76
+#define SND_MAGIC_WALL_ACTIVE                          77
+#define SND_MAGIC_WALL_FILLING                         78
+#define SND_CLASS_AMOEBA_WAITING                               79
+#define SND_CLASS_AMOEBA_GROWING                               80
+#define SND_CLASS_AMOEBA_DROPPING                              81
+#define SND_ACID_SPLASHING                                     82
+#define SND_CLASS_QUICKSAND_FILLING                            83
+#define SND_CLASS_QUICKSAND_EMPTYING                           84
+#define SND_CLASS_EXIT_OPENING                                 85
+#define SND_CLASS_EXIT_PASSING                                 86
+#define SND_PENGUIN_PASSING                                    87
+#define SND_BALLOON_MOVING                                     88
+#define SND_BALLOON_WAITING                                    89
+#define SND_BALLOON_PUSHING                                    90
+#define SND_CLASS_BALLOON_SWITCH_ACTIVATING                    91
+#define SND_SPRING_MOVING                                      92
+#define SND_SPRING_PUSHING                                     93
+#define SND_SPRING_IMPACT                                      94
+#define SND_CLASS_WALL_GROWING                                 95
+#define SND_PEARL_COLLECTING                           96
+#define SND_PEARL_BREAKING                                     97
+#define SND_PEARL_IMPACT                                       98
+#define SND_CRYSTAL_COLLECTING                         99
+#define SND_CRYSTAL_IMPACT                                     100
+#define SND_ENVELOPE_COLLECTING                                101
+#define SND_INVISIBLE_SAND_DIGGING                             102
+#define SND_SHIELD_NORMAL_COLLECTING                   103
+#define SND_SHIELD_NORMAL_ACTIVE                               104
+#define SND_SHIELD_DEADLY_COLLECTING                   105
+#define SND_SHIELD_DEADLY_ACTIVE                               106
+#define SND_EXTRA_TIME_COLLECTING                              107
+#define SND_MOLE_MOVING                                        108
+#define SND_MOLE_WAITING                                       109
+#define SND_MOLE_DIGGING                                       110
+#define SND_CLASS_SWITCHGATE_SWITCH_ACTIVATING                 111
+#define SND_CLASS_SWITCHGATE_OPENING                           112
+#define SND_CLASS_SWITCHGATE_CLOSING                           113
+#define SND_CLASS_SWITCHGATE_PASSING                           114
+#define SND_TIMEGATE_SWITCH_ACTIVATING                 115
+#define SND_TIMEGATE_SWITCH_ACTIVE                             116
+#define SND_TIMEGATE_SWITCH_DEACTIVATING                       117
+#define SND_TIMEGATE_OPENING                           118
+#define SND_CLASS_TIMEGATE_CLOSING                             119
+#define SND_CLASS_TIMEGATE_PASSING                             120
+#define SND_CLASS_CONVEYOR_BELT_SWITCH_ACTIVATING              121
+#define SND_CLASS_CONVEYOR_BELT_ACTIVE                         122
+#define SND_CLASS_CONVEYOR_BELT_SWITCH_DEACTIVATING            123
+#define SND_LIGHT_SWITCH_ACTIVATING                            124
+#define SND_LIGHT_SWITCH_DEACTIVATING                  125
+#define SND_DX_SUPABOMB_PUSHING                                126
+#define SND_TRAP_DIGGING                                       127
+#define SND_TRAP_ACTIVATING                                    128
+#define SND_CLASS_TUBE_WALKING                                 129
+#define SND_AMOEBA_TURNING_TO_GEM                              130
+#define SND_AMOEBA_TURNING_TO_ROCK                             131
+#define SND_SPEED_PILL_COLLECTING                              132
+#define SND_DYNABOMB_INCREASE_NUMBER_COLLECTING                133
+#define SND_DYNABOMB_INCREASE_SIZE_COLLECTING          134
+#define SND_DYNABOMB_INCREASE_POWER_COLLECTING         135
+#define SND_CLASS_DYNABOMB_DROPPING                            136
+#define SND_CLASS_DYNABOMB_ACTIVE                              137
+#define SND_SATELLITE_MOVING                           138
+#define SND_SATELLITE_WAITING                          139
+#define SND_SATELLITE_PUSHING                          140
+#define SND_LAMP_ACTIVATING                                    141
+#define SND_LAMP_DEACTIVATING                          142
+#define SND_TIME_ORB_FULL_COLLECTING                   143
+#define SND_TIME_ORB_FULL_IMPACT                               144
+#define SND_TIME_ORB_EMPTY_PUSHING                             145
+#define SND_TIME_ORB_EMPTY_IMPACT                              146
+#define SND_GAME_OF_LIFE_WAITING                               147
+#define SND_GAME_OF_LIFE_GROWING                               148
+#define SND_BIOMAZE_WAITING                                    149
+#define SND_BIOMAZE_GROWING                                    150
+#define SND_PACMAN_MOVING                                      151
+#define SND_PACMAN_WAITING                                     152
+#define SND_PACMAN_DIGGING                                     153
+#define SND_DARK_YAMYAM_MOVING                         154
+#define SND_DARK_YAMYAM_WAITING                                155
+#define SND_DARK_YAMYAM_DIGGING                                156
+#define SND_PENGUIN_MOVING                                     157
+#define SND_PENGUIN_WAITING                                    158
+#define SND_PIG_MOVING                                 159
+#define SND_PIG_WAITING                                        160
+#define SND_PIG_DIGGING                                        161
+#define SND_DRAGON_MOVING                                      162
+#define SND_DRAGON_WAITING                                     163
+#define SND_DRAGON_ATTACKING                           164
+#define SND_GAME_STARTING                                      165
+#define SND_GAME_RUNNING_OUT_OF_TIME                   166
+#define SND_GAME_LEVELTIME_BONUS                               167
+#define SND_GAME_LOSING                                        168
+#define SND_GAME_WINNING                                       169
+#define SND_GAME_SOKOBAN_SOLVING                               170
+#define SND_DOOR_OPENING                                       171
+#define SND_DOOR_CLOSING                                       172
+#define SND_BACKGROUND_SCORES                          173
+#define SND_BACKGROUND_INFO                                    174
+
+#define NUM_SOUND_FILES                                175
+
+#endif /* CONF_SND_H */
index 5cfe6cf0b524a83f139ac455acac71dac979744c..e2c1ccdd7231482331565162a4dda86016edcba3 100644 (file)
@@ -1 +1 @@
-#define COMPILE_DATE_STRING "[2002-08-13 01:52]"
+#define COMPILE_DATE_STRING "[2003-08-05 01:57]"
index eaf1aa29c1102780beb2acd3cfcab5e75b5a3dfc..1749fe25f9c78a59565665ae9999c934c6fdd1b1 100644 (file)
 #include "tools.h"
 #include "files.h"
 #include "game.h"
+#include "init.h"
 #include "tape.h"
 
+
+/*
+  -----------------------------------------------------------------------------
+  screen and artwork graphic pixel position definitions
+  -----------------------------------------------------------------------------
+*/
+
 /* positions in the level editor */
 #define ED_WIN_MB_LEFT_XPOS            6
 #define ED_WIN_MB_LEFT_YPOS            258
 #define ED_WIN_MB_RIGHT_XPOS           78
 #define ED_WIN_MB_RIGHT_YPOS           ED_WIN_MB_LEFT_YPOS
 
-/* other constants for the editor */
-#define ED_SCROLL_NO                   0
-#define ED_SCROLL_LEFT                 1
-#define ED_SCROLL_RIGHT                        2
-#define ED_SCROLL_UP                   4
-#define ED_SCROLL_DOWN                 8
-
-/* screens in the level editor */
-#define ED_MODE_DRAWING                        0
-#define ED_MODE_INFO                   1
-#define ED_MODE_PROPERTIES             2
-
-/* how many steps can be cancelled */
-#define NUM_UNDO_STEPS                 (10 + 1)
-
-/* values for elements with score */
-#define MIN_SCORE                      0
-#define MAX_SCORE                      255
-
 /* values for the control window */
 #define ED_CTRL_BUTTONS_GFX_YPOS       236
 #define ED_CTRL_BUTTONS_ALT_GFX_YPOS   142
 #define ED_NUM_ELEMENTLIST_BUTTONS     (ED_ELEMENTLIST_BUTTONS_HORIZ * \
                                         ED_ELEMENTLIST_BUTTONS_VERT)
 
+/* standard distances */
+#define ED_BORDER_SIZE                 3
+#define ED_BORDER_TEXT_XSIZE           5
+#define ED_BORDER_AREA_YSIZE           1
+
+#define ED_GADGET_DISTANCE             2
+#define ED_GADGET_TEXT_DISTANCE                (2 * ED_GADGET_DISTANCE)
+
 /* values for the setting windows */
-#define ED_SETTINGS_XPOS               (MINI_TILEX + 8)
+#define ED_SETTINGS_XSTART             (3 * MINI_TILEX / 2)
+#define ED_SETTINGS_YSTART             (MINI_TILEY * 10)
+
+#define ED_XOFFSET_CHECKBOX            (ED_CHECKBUTTON_XSIZE + \
+                                        2 * ED_GADGET_DISTANCE)
+
+#define ED_SETTINGS_XOFFSET            ED_XOFFSET_CHECKBOX
+#define ED_SETTINGS_YOFFSET            (3 * MINI_TILEY / 2)
+
+#define ED_SETTINGS_XPOS(n)            (ED_SETTINGS_XSTART + \
+                                        n * ED_SETTINGS_XOFFSET)
+#define ED_SETTINGS_YPOS(n)            (ED_SETTINGS_YSTART + \
+                                        n * ED_SETTINGS_YOFFSET)
+
+#define ED_SETTINGS1_YPOS              MINI_TILEY
 #define ED_SETTINGS2_XPOS              MINI_TILEX
-#define ED_SETTINGS_YPOS               MINI_TILEY
-#define ED_SETTINGS2_YPOS              (ED_SETTINGS_YPOS + 12 * TILEY - 2)
+#define ED_SETTINGS2_YPOS              (ED_SETTINGS1_YPOS + 12 * TILEY - 2)
 
 /* values for counter gadgets */
-#define ED_COUNT_ELEM_SCORE_XPOS       ED_SETTINGS_XPOS
-#define ED_COUNT_ELEM_SCORE_YPOS       (14 * MINI_TILEY)
-#define ED_COUNT_ELEM_CONTENT_XPOS     ED_SETTINGS_XPOS
-#define ED_COUNT_ELEM_CONTENT_YPOS     (19 * MINI_TILEY)
+#define ED_COUNT_PUSH_DELAY_RND_XPOS   (ED_SETTINGS_XPOS(1) + 16 * MINI_TILEX)
+#define ED_COUNT_MOVE_DELAY_RND_XPOS   ED_COUNT_PUSH_DELAY_RND_XPOS
+#define ED_COUNT_CHANGE_DELAY_RND_XPOS (ED_SETTINGS_XPOS(1) + 13 * MINI_TILEX)
 
-#define ED_COUNTER_YSTART              (ED_SETTINGS_YPOS + 2 * TILEY)
+#define ED_COUNTER_YSTART              (ED_SETTINGS1_YPOS + 2 * TILEY)
 #define ED_COUNTER_YDISTANCE           (3 * MINI_TILEY)
 #define ED_COUNTER_YPOS(n)             (ED_COUNTER_YSTART + \
                                         n * ED_COUNTER_YDISTANCE)
 #define ED_COUNTER2_YPOS(n)            (ED_COUNTER_YSTART + \
                                         n * ED_COUNTER_YDISTANCE - 2)
-/* standard distances */
-#define ED_BORDER_SIZE                 3
-#define ED_GADGET_DISTANCE             2
 
 /* values for element content drawing areas */
+/* amoeba content */
 #define ED_AREA_ELEM_CONTENT_XPOS      ( 2 * MINI_TILEX)
 #define ED_AREA_ELEM_CONTENT_YPOS      (22 * MINI_TILEY)
 
+/* yamyam content */
+#define ED_AREA_YAMYAM_CONTENT_XPOS(n) (ED_AREA_ELEM_CONTENT_XPOS + \
+                                        5 * (n % 4) * MINI_TILEX)
+#define ED_AREA_YAMYAM_CONTENT_YPOS(n) (ED_AREA_ELEM_CONTENT_YPOS + \
+                                        6 * (n / 4) * MINI_TILEY)
+
+/* custom change target */
+#define ED_AREA_ELEM_CONTENT2_XPOS     (20 * MINI_TILEX)
+#define ED_AREA_ELEM_CONTENT2_YPOS     (ED_SETTINGS_YPOS(2) + \
+                                        ED_GADGET_DISTANCE)
+/* optional custom graphic */
+#define ED_AREA_ELEM_CONTENT3_XPOS     (24 * MINI_TILEX)
+#define ED_AREA_ELEM_CONTENT3_YPOS     (ED_SETTINGS_YPOS(1) + \
+                                        ED_GADGET_DISTANCE)
+/* custom element content */
+#define ED_AREA_ELEM_CONTENT4_XPOS     (29 * MINI_TILEX)
+#define ED_AREA_ELEM_CONTENT4_YPOS     (ED_SETTINGS_YPOS(12) + \
+                                        ED_GADGET_DISTANCE - MINI_TILEY)
+/* custom change trigger element */
+#define ED_AREA_ELEM_CONTENT5_XPOS     (28 * MINI_TILEX)
+#define ED_AREA_ELEM_CONTENT5_YPOS     (ED_SETTINGS_YPOS(7) + \
+                                        ED_GADGET_DISTANCE)
+/* extended custom change target */
+#define ED_AREA_ELEM_CONTENT6_XPOS     (29 * MINI_TILEX)
+#define ED_AREA_ELEM_CONTENT6_YPOS     (ED_SETTINGS_YPOS(10) + \
+                                        ED_GADGET_DISTANCE - MINI_TILEY)
+
 /* values for random placement background drawing area */
 #define ED_AREA_RANDOM_BACKGROUND_XPOS (29 * MINI_TILEX)
 #define ED_AREA_RANDOM_BACKGROUND_YPOS (31 * MINI_TILEY)
 #define ED_STICKYBUTTON_YPOS           (ED_BUTTON_MINUS_YPOS + 66)
 
 /* some positions in the editor control window */
-#define ED_BUTTON_ELEM_XPOS    6
-#define ED_BUTTON_ELEM_YPOS    30
-#define ED_BUTTON_ELEM_XSIZE   22
-#define ED_BUTTON_ELEM_YSIZE   22
-
-/* some values for text input and counter gadgets */
-#define ED_BUTTON_COUNT_YPOS   60
-#define ED_BUTTON_COUNT_XSIZE  20
-#define ED_BUTTON_COUNT_YSIZE  20
-#define ED_WIN_COUNT_XPOS      (2 + ED_BUTTON_COUNT_XSIZE + 2)
-#define ED_WIN_COUNT_YPOS      ED_BUTTON_COUNT_YPOS
-#define ED_WIN_COUNT_XSIZE     52
-#define ED_WIN_COUNT_YSIZE     ED_BUTTON_COUNT_YSIZE
-#define ED_WIN_COUNT2_XPOS     27
-#define ED_WIN_COUNT2_YPOS     3
-#define ED_WIN_COUNT2_XSIZE    46
-#define ED_WIN_COUNT2_YSIZE    ED_BUTTON_COUNT_YSIZE
-
-#define ED_BUTTON_MINUS_XPOS   2
-#define ED_BUTTON_MINUS_YPOS   ED_BUTTON_COUNT_YPOS
-#define ED_BUTTON_MINUS_XSIZE  ED_BUTTON_COUNT_XSIZE
-#define ED_BUTTON_MINUS_YSIZE  ED_BUTTON_COUNT_YSIZE
-#define ED_BUTTON_PLUS_XPOS    (ED_WIN_COUNT_XPOS + ED_WIN_COUNT_XSIZE + 2)
-#define ED_BUTTON_PLUS_YPOS    ED_BUTTON_COUNT_YPOS
-#define ED_BUTTON_PLUS_XSIZE   ED_BUTTON_COUNT_XSIZE
-#define ED_BUTTON_PLUS_YSIZE   ED_BUTTON_COUNT_YSIZE
-
-/* editor gadget identifiers */
+#define ED_BUTTON_ELEM_XPOS            6
+#define ED_BUTTON_ELEM_YPOS            30
+#define ED_BUTTON_ELEM_XSIZE           22
+#define ED_BUTTON_ELEM_YSIZE           22
+
+/* some values for text input, selectbox and counter gadgets */
+#define ED_BUTTON_COUNT_YPOS           60
+#define ED_BUTTON_COUNT_XSIZE          20
+#define ED_BUTTON_COUNT_YSIZE          20
+#define ED_WIN_COUNT_XPOS              (2 + ED_BUTTON_COUNT_XSIZE + 2)
+#define ED_WIN_COUNT_YPOS              ED_BUTTON_COUNT_YPOS
+#define ED_WIN_COUNT_XSIZE             52
+#define ED_WIN_COUNT_YSIZE             ED_BUTTON_COUNT_YSIZE
+#define ED_WIN_COUNT2_XPOS             27
+#define ED_WIN_COUNT2_YPOS             3
+#define ED_WIN_COUNT2_XSIZE            46
+#define ED_WIN_COUNT2_YSIZE            ED_BUTTON_COUNT_YSIZE
+
+#define ED_BUTTON_MINUS_XPOS           2
+#define ED_BUTTON_MINUS_YPOS           ED_BUTTON_COUNT_YPOS
+#define ED_BUTTON_MINUS_XSIZE          ED_BUTTON_COUNT_XSIZE
+#define ED_BUTTON_MINUS_YSIZE          ED_BUTTON_COUNT_YSIZE
+#define ED_BUTTON_PLUS_XPOS            (ED_WIN_COUNT_XPOS + \
+                                        ED_WIN_COUNT_XSIZE + 2)
+#define ED_BUTTON_PLUS_YPOS            ED_BUTTON_COUNT_YPOS
+#define ED_BUTTON_PLUS_XSIZE           ED_BUTTON_COUNT_XSIZE
+#define ED_BUTTON_PLUS_YSIZE           ED_BUTTON_COUNT_YSIZE
+
+#define ED_SELECTBOX_XPOS              ED_WIN_COUNT_XPOS
+#define ED_SELECTBOX_YPOS              (ED_WIN_COUNT_YPOS + \
+                                        2 + ED_WIN_COUNT_YSIZE)
+#define ED_SELECTBOX_XSIZE             ED_WIN_COUNT_XSIZE
+#define ED_SELECTBOX_YSIZE             ED_WIN_COUNT_YSIZE
+
+#define ED_SELECTBOX_BUTTON_XSIZE      14
+
+#define ED_TEXTBUTTON_XPOS             ED_WIN_COUNT_XPOS
+#define ED_TEXTBUTTON_YPOS             (ED_WIN_COUNT_YPOS + \
+                                        4 * (2 + ED_WIN_COUNT_YSIZE))
+#define ED_TEXTBUTTON_INACTIVE_YPOS    ED_TEXTBUTTON_YPOS
+
+#define ED_TEXTBUTTON_TAB_XPOS         ED_WIN_COUNT_XPOS
+#define ED_TEXTBUTTON_TAB_YPOS         (ED_WIN_COUNT_YPOS + \
+                                        2 * (2 + ED_WIN_COUNT_YSIZE))
+#define ED_TEXTBUTTON_TAB_INACTIVE_YPOS        (ED_WIN_COUNT_YPOS + \
+                                        3 * (2 + ED_WIN_COUNT_YSIZE))
+
+#define ED_TEXTBUTTON_XSIZE            ED_WIN_COUNT_XSIZE
+#define ED_TEXTBUTTON_YSIZE            ED_WIN_COUNT_YSIZE
+
+/* values for ClearEditorGadgetInfoText() and HandleGadgetInfoText() */
+#define INFOTEXT_XPOS                  SX
+#define INFOTEXT_YPOS                  (SY + SYSIZE - MINI_TILEX + 2)
+#define INFOTEXT_XSIZE                 SXSIZE
+#define INFOTEXT_YSIZE                 MINI_TILEX
+
+
+/*
+  -----------------------------------------------------------------------------
+  editor gadget definitions
+  -----------------------------------------------------------------------------
+*/
 
 /* drawing toolbox buttons */
 #define GADGET_ID_NONE                 -1
-#define GADGET_ID_SINGLE_ITEMS         0
-#define GADGET_ID_CONNECTED_ITEMS      1
-#define GADGET_ID_LINE                 2
-#define GADGET_ID_ARC                  3
-#define GADGET_ID_RECTANGLE            4
-#define GADGET_ID_FILLED_BOX           5
-#define GADGET_ID_WRAP_UP              6
-#define GADGET_ID_TEXT                 7
-#define GADGET_ID_FLOOD_FILL           8
-#define GADGET_ID_WRAP_LEFT            9
-#define GADGET_ID_PROPERTIES           10
-#define GADGET_ID_WRAP_RIGHT           11
-#define GADGET_ID_RANDOM_PLACEMENT     12
-#define GADGET_ID_GRAB_BRUSH           13
-#define GADGET_ID_WRAP_DOWN            14
-#define GADGET_ID_PICK_ELEMENT         15
-#define GADGET_ID_UNDO                 16
-#define GADGET_ID_INFO                 17
-#define GADGET_ID_SAVE                 18
-#define GADGET_ID_CLEAR                        19
-#define GADGET_ID_TEST                 20
-#define GADGET_ID_EXIT                 21
+#define GADGET_ID_TOOLBOX_FIRST                0
+
+#define GADGET_ID_SINGLE_ITEMS         (GADGET_ID_TOOLBOX_FIRST + 0)
+#define GADGET_ID_CONNECTED_ITEMS      (GADGET_ID_TOOLBOX_FIRST + 1)
+#define GADGET_ID_LINE                 (GADGET_ID_TOOLBOX_FIRST + 2)
+#define GADGET_ID_ARC                  (GADGET_ID_TOOLBOX_FIRST + 3)
+#define GADGET_ID_RECTANGLE            (GADGET_ID_TOOLBOX_FIRST + 4)
+#define GADGET_ID_FILLED_BOX           (GADGET_ID_TOOLBOX_FIRST + 5)
+#define GADGET_ID_WRAP_UP              (GADGET_ID_TOOLBOX_FIRST + 6)
+#define GADGET_ID_TEXT                 (GADGET_ID_TOOLBOX_FIRST + 7)
+#define GADGET_ID_FLOOD_FILL           (GADGET_ID_TOOLBOX_FIRST + 8)
+#define GADGET_ID_WRAP_LEFT            (GADGET_ID_TOOLBOX_FIRST + 9)
+#define GADGET_ID_PROPERTIES           (GADGET_ID_TOOLBOX_FIRST + 10)
+#define GADGET_ID_WRAP_RIGHT           (GADGET_ID_TOOLBOX_FIRST + 11)
+#define GADGET_ID_RANDOM_PLACEMENT     (GADGET_ID_TOOLBOX_FIRST + 12)
+#define GADGET_ID_GRAB_BRUSH           (GADGET_ID_TOOLBOX_FIRST + 13)
+#define GADGET_ID_WRAP_DOWN            (GADGET_ID_TOOLBOX_FIRST + 14)
+#define GADGET_ID_PICK_ELEMENT         (GADGET_ID_TOOLBOX_FIRST + 15)
+#define GADGET_ID_UNDO                 (GADGET_ID_TOOLBOX_FIRST + 16)
+#define GADGET_ID_INFO                 (GADGET_ID_TOOLBOX_FIRST + 17)
+#define GADGET_ID_SAVE                 (GADGET_ID_TOOLBOX_FIRST + 18)
+#define GADGET_ID_CLEAR                        (GADGET_ID_TOOLBOX_FIRST + 19)
+#define GADGET_ID_TEST                 (GADGET_ID_TOOLBOX_FIRST + 20)
+#define GADGET_ID_EXIT                 (GADGET_ID_TOOLBOX_FIRST + 21)
 
 /* counter button identifiers */
-#define GADGET_ID_ELEM_SCORE_DOWN      22
-#define GADGET_ID_ELEM_SCORE_TEXT      23
-#define GADGET_ID_ELEM_SCORE_UP                24
-#define GADGET_ID_ELEM_CONTENT_DOWN    25
-#define GADGET_ID_ELEM_CONTENT_TEXT    26
-#define GADGET_ID_ELEM_CONTENT_UP      27
-#define GADGET_ID_LEVEL_XSIZE_DOWN     28
-#define GADGET_ID_LEVEL_XSIZE_TEXT     29
-#define GADGET_ID_LEVEL_XSIZE_UP       30
-#define GADGET_ID_LEVEL_YSIZE_DOWN     31
-#define GADGET_ID_LEVEL_YSIZE_TEXT     32
-#define GADGET_ID_LEVEL_YSIZE_UP       33
-#define GADGET_ID_LEVEL_RANDOM_DOWN    34
-#define GADGET_ID_LEVEL_RANDOM_TEXT    35
-#define GADGET_ID_LEVEL_RANDOM_UP      36
-#define GADGET_ID_LEVEL_COLLECT_DOWN   37
-#define GADGET_ID_LEVEL_COLLECT_TEXT   38
-#define GADGET_ID_LEVEL_COLLECT_UP     39
-#define GADGET_ID_LEVEL_TIMELIMIT_DOWN 40
-#define GADGET_ID_LEVEL_TIMELIMIT_TEXT 41
-#define GADGET_ID_LEVEL_TIMELIMIT_UP   42
-#define GADGET_ID_LEVEL_TIMESCORE_DOWN 43
-#define GADGET_ID_LEVEL_TIMESCORE_TEXT 44
-#define GADGET_ID_LEVEL_TIMESCORE_UP   45
-#define GADGET_ID_SELECT_LEVEL_DOWN    46
-#define GADGET_ID_SELECT_LEVEL_TEXT    47
-#define GADGET_ID_SELECT_LEVEL_UP      48
+#define GADGET_ID_COUNTER_FIRST                (GADGET_ID_TOOLBOX_FIRST + 22)
+
+#define GADGET_ID_SELECT_LEVEL_DOWN    (GADGET_ID_COUNTER_FIRST + 0)
+#define GADGET_ID_SELECT_LEVEL_TEXT    (GADGET_ID_COUNTER_FIRST + 1)
+#define GADGET_ID_SELECT_LEVEL_UP      (GADGET_ID_COUNTER_FIRST + 2)
+#define GADGET_ID_LEVEL_XSIZE_DOWN     (GADGET_ID_COUNTER_FIRST + 3)
+#define GADGET_ID_LEVEL_XSIZE_TEXT     (GADGET_ID_COUNTER_FIRST + 4)
+#define GADGET_ID_LEVEL_XSIZE_UP       (GADGET_ID_COUNTER_FIRST + 5)
+#define GADGET_ID_LEVEL_YSIZE_DOWN     (GADGET_ID_COUNTER_FIRST + 6)
+#define GADGET_ID_LEVEL_YSIZE_TEXT     (GADGET_ID_COUNTER_FIRST + 7)
+#define GADGET_ID_LEVEL_YSIZE_UP       (GADGET_ID_COUNTER_FIRST + 8)
+#define GADGET_ID_LEVEL_RANDOM_DOWN    (GADGET_ID_COUNTER_FIRST + 9)
+#define GADGET_ID_LEVEL_RANDOM_TEXT    (GADGET_ID_COUNTER_FIRST + 10)
+#define GADGET_ID_LEVEL_RANDOM_UP      (GADGET_ID_COUNTER_FIRST + 11)
+#define GADGET_ID_LEVEL_GEMSLIMIT_DOWN (GADGET_ID_COUNTER_FIRST + 12)
+#define GADGET_ID_LEVEL_GEMSLIMIT_TEXT (GADGET_ID_COUNTER_FIRST + 13)
+#define GADGET_ID_LEVEL_GEMSLIMIT_UP   (GADGET_ID_COUNTER_FIRST + 14)
+#define GADGET_ID_LEVEL_TIMELIMIT_DOWN (GADGET_ID_COUNTER_FIRST + 15)
+#define GADGET_ID_LEVEL_TIMELIMIT_TEXT (GADGET_ID_COUNTER_FIRST + 16)
+#define GADGET_ID_LEVEL_TIMELIMIT_UP   (GADGET_ID_COUNTER_FIRST + 17)
+#define GADGET_ID_LEVEL_TIMESCORE_DOWN (GADGET_ID_COUNTER_FIRST + 18)
+#define GADGET_ID_LEVEL_TIMESCORE_TEXT (GADGET_ID_COUNTER_FIRST + 19)
+#define GADGET_ID_LEVEL_TIMESCORE_UP   (GADGET_ID_COUNTER_FIRST + 20)
+#define GADGET_ID_ELEMENT_SCORE_DOWN   (GADGET_ID_COUNTER_FIRST + 21)
+#define GADGET_ID_ELEMENT_SCORE_TEXT   (GADGET_ID_COUNTER_FIRST + 22)
+#define GADGET_ID_ELEMENT_SCORE_UP     (GADGET_ID_COUNTER_FIRST + 23)
+#define GADGET_ID_ELEMENT_CONTENT_DOWN (GADGET_ID_COUNTER_FIRST + 24)
+#define GADGET_ID_ELEMENT_CONTENT_TEXT (GADGET_ID_COUNTER_FIRST + 25)
+#define GADGET_ID_ELEMENT_CONTENT_UP   (GADGET_ID_COUNTER_FIRST + 26)
+#define GADGET_ID_CUSTOM_SCORE_DOWN    (GADGET_ID_COUNTER_FIRST + 27)
+#define GADGET_ID_CUSTOM_SCORE_TEXT    (GADGET_ID_COUNTER_FIRST + 28)
+#define GADGET_ID_CUSTOM_SCORE_UP      (GADGET_ID_COUNTER_FIRST + 29)
+#define GADGET_ID_CUSTOM_GEMCOUNT_DOWN (GADGET_ID_COUNTER_FIRST + 30)
+#define GADGET_ID_CUSTOM_GEMCOUNT_TEXT (GADGET_ID_COUNTER_FIRST + 31)
+#define GADGET_ID_CUSTOM_GEMCOUNT_UP   (GADGET_ID_COUNTER_FIRST + 32)
+#define GADGET_ID_PUSH_DELAY_FIX_DOWN  (GADGET_ID_COUNTER_FIRST + 33)
+#define GADGET_ID_PUSH_DELAY_FIX_TEXT  (GADGET_ID_COUNTER_FIRST + 34)
+#define GADGET_ID_PUSH_DELAY_FIX_UP    (GADGET_ID_COUNTER_FIRST + 35)
+#define GADGET_ID_PUSH_DELAY_RND_DOWN  (GADGET_ID_COUNTER_FIRST + 36)
+#define GADGET_ID_PUSH_DELAY_RND_TEXT  (GADGET_ID_COUNTER_FIRST + 37)
+#define GADGET_ID_PUSH_DELAY_RND_UP    (GADGET_ID_COUNTER_FIRST + 38)
+#define GADGET_ID_MOVE_DELAY_FIX_DOWN  (GADGET_ID_COUNTER_FIRST + 39)
+#define GADGET_ID_MOVE_DELAY_FIX_TEXT  (GADGET_ID_COUNTER_FIRST + 40)
+#define GADGET_ID_MOVE_DELAY_FIX_UP    (GADGET_ID_COUNTER_FIRST + 41)
+#define GADGET_ID_MOVE_DELAY_RND_DOWN  (GADGET_ID_COUNTER_FIRST + 42)
+#define GADGET_ID_MOVE_DELAY_RND_TEXT  (GADGET_ID_COUNTER_FIRST + 43)
+#define GADGET_ID_MOVE_DELAY_RND_UP    (GADGET_ID_COUNTER_FIRST + 44)
+#define GADGET_ID_CHANGE_DELAY_FIX_DOWN        (GADGET_ID_COUNTER_FIRST + 45)
+#define GADGET_ID_CHANGE_DELAY_FIX_TEXT        (GADGET_ID_COUNTER_FIRST + 46)
+#define GADGET_ID_CHANGE_DELAY_FIX_UP  (GADGET_ID_COUNTER_FIRST + 47)
+#define GADGET_ID_CHANGE_DELAY_RND_DOWN        (GADGET_ID_COUNTER_FIRST + 48)
+#define GADGET_ID_CHANGE_DELAY_RND_TEXT        (GADGET_ID_COUNTER_FIRST + 49)
+#define GADGET_ID_CHANGE_DELAY_RND_UP  (GADGET_ID_COUNTER_FIRST + 50)
+#define GADGET_ID_CHANGE_CONT_RND_DOWN (GADGET_ID_COUNTER_FIRST + 51)
+#define GADGET_ID_CHANGE_CONT_RND_TEXT (GADGET_ID_COUNTER_FIRST + 52)
+#define GADGET_ID_CHANGE_CONT_RND_UP   (GADGET_ID_COUNTER_FIRST + 53)
 
 /* drawing area identifiers */
-#define GADGET_ID_DRAWING_LEVEL                49
-#define GADGET_ID_ELEM_CONTENT_0       50
-#define GADGET_ID_ELEM_CONTENT_1       51
-#define GADGET_ID_ELEM_CONTENT_2       52
-#define GADGET_ID_ELEM_CONTENT_3       53
-#define GADGET_ID_ELEM_CONTENT_4       54
-#define GADGET_ID_ELEM_CONTENT_5       55
-#define GADGET_ID_ELEM_CONTENT_6       56
-#define GADGET_ID_ELEM_CONTENT_7       57
-#define GADGET_ID_AMOEBA_CONTENT       58
+#define GADGET_ID_DRAWING_AREA_FIRST   (GADGET_ID_COUNTER_FIRST + 54)
+
+#define GADGET_ID_DRAWING_LEVEL                (GADGET_ID_DRAWING_AREA_FIRST + 0)
+#define GADGET_ID_ELEMENT_CONTENT_0    (GADGET_ID_DRAWING_AREA_FIRST + 1)
+#define GADGET_ID_ELEMENT_CONTENT_1    (GADGET_ID_DRAWING_AREA_FIRST + 2)
+#define GADGET_ID_ELEMENT_CONTENT_2    (GADGET_ID_DRAWING_AREA_FIRST + 3)
+#define GADGET_ID_ELEMENT_CONTENT_3    (GADGET_ID_DRAWING_AREA_FIRST + 4)
+#define GADGET_ID_ELEMENT_CONTENT_4    (GADGET_ID_DRAWING_AREA_FIRST + 5)
+#define GADGET_ID_ELEMENT_CONTENT_5    (GADGET_ID_DRAWING_AREA_FIRST + 6)
+#define GADGET_ID_ELEMENT_CONTENT_6    (GADGET_ID_DRAWING_AREA_FIRST + 7)
+#define GADGET_ID_ELEMENT_CONTENT_7    (GADGET_ID_DRAWING_AREA_FIRST + 8)
+#define GADGET_ID_AMOEBA_CONTENT       (GADGET_ID_DRAWING_AREA_FIRST + 9)
+#define GADGET_ID_CUSTOM_GRAPHIC       (GADGET_ID_DRAWING_AREA_FIRST + 10)
+#define GADGET_ID_CUSTOM_CONTENT       (GADGET_ID_DRAWING_AREA_FIRST + 11)
+#define GADGET_ID_CUSTOM_CHANGE_TARGET (GADGET_ID_DRAWING_AREA_FIRST + 12)
+#define GADGET_ID_CUSTOM_CHANGE_CONTENT        (GADGET_ID_DRAWING_AREA_FIRST + 13)
+#define GADGET_ID_CUSTOM_CHANGE_TRIGGER        (GADGET_ID_DRAWING_AREA_FIRST + 14)
+#define GADGET_ID_RANDOM_BACKGROUND    (GADGET_ID_DRAWING_AREA_FIRST + 15)
 
 /* text input identifiers */
-#define GADGET_ID_LEVEL_NAME           59
-#define GADGET_ID_LEVEL_AUTHOR         60
+#define GADGET_ID_TEXT_INPUT_FIRST     (GADGET_ID_DRAWING_AREA_FIRST + 16)
+
+#define GADGET_ID_LEVEL_NAME           (GADGET_ID_TEXT_INPUT_FIRST + 0)
+#define GADGET_ID_LEVEL_AUTHOR         (GADGET_ID_TEXT_INPUT_FIRST + 1)
+#define GADGET_ID_ELEMENT_NAME         (GADGET_ID_TEXT_INPUT_FIRST + 2)
+
+/* selectbox identifiers */
+#define GADGET_ID_SELECTBOX_FIRST      (GADGET_ID_TEXT_INPUT_FIRST + 3)
+
+#define GADGET_ID_CUSTOM_WALK_TO_ACTION        (GADGET_ID_SELECTBOX_FIRST + 0)
+#define GADGET_ID_CUSTOM_CONSISTENCY   (GADGET_ID_SELECTBOX_FIRST + 1)
+#define GADGET_ID_CUSTOM_DEADLINESS    (GADGET_ID_SELECTBOX_FIRST + 2)
+#define GADGET_ID_CUSTOM_MOVE_PATTERN  (GADGET_ID_SELECTBOX_FIRST + 3)
+#define GADGET_ID_CUSTOM_MOVE_DIRECTION        (GADGET_ID_SELECTBOX_FIRST + 4)
+#define GADGET_ID_CUSTOM_MOVE_STEPSIZE (GADGET_ID_SELECTBOX_FIRST + 5)
+#define GADGET_ID_CUSTOM_SMASH_TARGETS (GADGET_ID_SELECTBOX_FIRST + 6)
+#define GADGET_ID_CUSTOM_SLIPPERY_TYPE (GADGET_ID_SELECTBOX_FIRST + 7)
+#define GADGET_ID_CUSTOM_ACCESS_TYPE   (GADGET_ID_SELECTBOX_FIRST + 8)
+#define GADGET_ID_CUSTOM_ACCESS_LAYER  (GADGET_ID_SELECTBOX_FIRST + 9)
+#define GADGET_ID_CHANGE_TIME_UNITS    (GADGET_ID_SELECTBOX_FIRST + 10)
+#define GADGET_ID_CHANGE_PLAYER_ACTION (GADGET_ID_SELECTBOX_FIRST + 11)
+#define GADGET_ID_CHANGE_COLLIDE_ACTION        (GADGET_ID_SELECTBOX_FIRST + 12)
+#define GADGET_ID_CHANGE_OTHER_ACTION  (GADGET_ID_SELECTBOX_FIRST + 13)
+#define GADGET_ID_CHANGE_POWER         (GADGET_ID_SELECTBOX_FIRST + 14)
+
+/* textbutton identifiers */
+#define GADGET_ID_TEXTBUTTON_FIRST     (GADGET_ID_SELECTBOX_FIRST + 15)
+
+#define GADGET_ID_PROPERTIES_INFO      (GADGET_ID_TEXTBUTTON_FIRST + 0)
+#define GADGET_ID_PROPERTIES_CONFIG    (GADGET_ID_TEXTBUTTON_FIRST + 1)
+#define GADGET_ID_PROPERTIES_ADVANCED  (GADGET_ID_TEXTBUTTON_FIRST + 2)
+#define GADGET_ID_SAVE_AS_TEMPLATE     (GADGET_ID_TEXTBUTTON_FIRST + 3)
 
 /* gadgets for scrolling of drawing area */
-#define GADGET_ID_SCROLL_UP            61
-#define GADGET_ID_SCROLL_DOWN          62
-#define GADGET_ID_SCROLL_LEFT          63
-#define GADGET_ID_SCROLL_RIGHT         64
-#define GADGET_ID_SCROLL_HORIZONTAL    65
-#define GADGET_ID_SCROLL_VERTICAL      66
+#define GADGET_ID_SCROLLING_FIRST      (GADGET_ID_TEXTBUTTON_FIRST + 4)
+
+#define GADGET_ID_SCROLL_UP            (GADGET_ID_SCROLLING_FIRST + 0)
+#define GADGET_ID_SCROLL_DOWN          (GADGET_ID_SCROLLING_FIRST + 1)
+#define GADGET_ID_SCROLL_LEFT          (GADGET_ID_SCROLLING_FIRST + 2)
+#define GADGET_ID_SCROLL_RIGHT         (GADGET_ID_SCROLLING_FIRST + 3)
+#define GADGET_ID_SCROLL_HORIZONTAL    (GADGET_ID_SCROLLING_FIRST + 4)
+#define GADGET_ID_SCROLL_VERTICAL      (GADGET_ID_SCROLLING_FIRST + 5)
 
 /* gadgets for scrolling element list */
-#define GADGET_ID_SCROLL_LIST_UP       67
-#define GADGET_ID_SCROLL_LIST_DOWN     68
-#define GADGET_ID_SCROLL_LIST_VERTICAL 69
-
-/* buttons for level settings */
-#define GADGET_ID_RANDOM_PERCENTAGE    70
-#define GADGET_ID_RANDOM_QUANTITY      71
-#define GADGET_ID_RANDOM_RESTRICTED    72
-#define GADGET_ID_DOUBLE_SPEED         73
-#define GADGET_ID_GRAVITY              74
-#define GADGET_ID_STICK_ELEMENT                75
-#define GADGET_ID_EM_SLIPPERY_GEMS     76
-
-/* another drawing area for random placement */
-#define GADGET_ID_RANDOM_BACKGROUND    77
+#define GADGET_ID_SCROLLING_LIST_FIRST (GADGET_ID_SCROLLING_FIRST + 6)
+
+#define GADGET_ID_SCROLL_LIST_UP       (GADGET_ID_SCROLLING_LIST_FIRST + 0)
+#define GADGET_ID_SCROLL_LIST_DOWN     (GADGET_ID_SCROLLING_LIST_FIRST + 1)
+#define GADGET_ID_SCROLL_LIST_VERTICAL (GADGET_ID_SCROLLING_LIST_FIRST + 2)
+
+/* checkbuttons for level/element properties */
+#define GADGET_ID_CHECKBUTTON_FIRST    (GADGET_ID_SCROLLING_LIST_FIRST + 3)
+
+#define GADGET_ID_RANDOM_PERCENTAGE    (GADGET_ID_CHECKBUTTON_FIRST + 0)
+#define GADGET_ID_RANDOM_QUANTITY      (GADGET_ID_CHECKBUTTON_FIRST + 1)
+#define GADGET_ID_RANDOM_RESTRICTED    (GADGET_ID_CHECKBUTTON_FIRST + 2)
+#define GADGET_ID_DOUBLE_SPEED         (GADGET_ID_CHECKBUTTON_FIRST + 3)
+#define GADGET_ID_GRAVITY              (GADGET_ID_CHECKBUTTON_FIRST + 4)
+#define GADGET_ID_STICK_ELEMENT                (GADGET_ID_CHECKBUTTON_FIRST + 5)
+#define GADGET_ID_EM_SLIPPERY_GEMS     (GADGET_ID_CHECKBUTTON_FIRST + 6)
+#define GADGET_ID_CUSTOM_EXPLODE_RESULT        (GADGET_ID_CHECKBUTTON_FIRST + 7)
+#define GADGET_ID_CUSTOM_EXPLODE_FIRE  (GADGET_ID_CHECKBUTTON_FIRST + 8)
+#define GADGET_ID_CUSTOM_EXPLODE_SMASH (GADGET_ID_CHECKBUTTON_FIRST + 9)
+#define GADGET_ID_CUSTOM_EXPLODE_IMPACT        (GADGET_ID_CHECKBUTTON_FIRST + 10)
+#define GADGET_ID_CUSTOM_WALK_TO_OBJECT        (GADGET_ID_CHECKBUTTON_FIRST + 11)
+#define GADGET_ID_CUSTOM_DEADLY                (GADGET_ID_CHECKBUTTON_FIRST + 12)
+#define GADGET_ID_CUSTOM_CAN_MOVE      (GADGET_ID_CHECKBUTTON_FIRST + 13)
+#define GADGET_ID_CUSTOM_CAN_FALL      (GADGET_ID_CHECKBUTTON_FIRST + 14)
+#define GADGET_ID_CUSTOM_CAN_SMASH     (GADGET_ID_CHECKBUTTON_FIRST + 15)
+#define GADGET_ID_CUSTOM_SLIPPERY      (GADGET_ID_CHECKBUTTON_FIRST + 16)
+#define GADGET_ID_CUSTOM_ACCESSIBLE    (GADGET_ID_CHECKBUTTON_FIRST + 17)
+#define GADGET_ID_CUSTOM_USE_GRAPHIC   (GADGET_ID_CHECKBUTTON_FIRST + 18)
+#define GADGET_ID_CUSTOM_USE_TEMPLATE  (GADGET_ID_CHECKBUTTON_FIRST + 19)
+#define GADGET_ID_CUSTOM_CAN_CHANGE    (GADGET_ID_CHECKBUTTON_FIRST + 20)
+#define GADGET_ID_CHANGE_USE_CONTENT   (GADGET_ID_CHECKBUTTON_FIRST + 21)
+#define GADGET_ID_CHANGE_USE_EXPLOSION (GADGET_ID_CHECKBUTTON_FIRST + 22)
+#define GADGET_ID_CHANGE_ONLY_COMPLETE (GADGET_ID_CHECKBUTTON_FIRST + 23)
+#define GADGET_ID_CHANGE_USE_RANDOM    (GADGET_ID_CHECKBUTTON_FIRST + 24)
+#define GADGET_ID_CHANGE_DELAY         (GADGET_ID_CHECKBUTTON_FIRST + 25)
+#define GADGET_ID_CHANGE_BY_PLAYER     (GADGET_ID_CHECKBUTTON_FIRST + 26)
+#define GADGET_ID_CHANGE_BY_COLLISION  (GADGET_ID_CHECKBUTTON_FIRST + 27)
+#define GADGET_ID_CHANGE_BY_OTHER      (GADGET_ID_CHECKBUTTON_FIRST + 28)
 
 /* gadgets for buttons in element list */
-#define GADGET_ID_ELEMENTLIST_FIRST    78
-#define GADGET_ID_ELEMENTLIST_LAST     (78 + ED_NUM_ELEMENTLIST_BUTTONS - 1)
+#define GADGET_ID_ELEMENTLIST_FIRST    (GADGET_ID_CHECKBUTTON_FIRST + 29)
+#define GADGET_ID_ELEMENTLIST_LAST     (GADGET_ID_ELEMENTLIST_FIRST +  \
+                                       ED_NUM_ELEMENTLIST_BUTTONS - 1)
 
 #define NUM_EDITOR_GADGETS             (GADGET_ID_ELEMENTLIST_LAST + 1)
 
 #define RADIO_NR_RANDOM_ELEMENTS       2
 
 /* values for counter gadgets */
-#define ED_COUNTER_ID_ELEM_SCORE       0
-#define ED_COUNTER_ID_ELEM_CONTENT     1
-#define ED_COUNTER_ID_LEVEL_XSIZE      2
-#define ED_COUNTER_ID_LEVEL_YSIZE      3
-#define ED_COUNTER_ID_LEVEL_COLLECT    4
-#define ED_COUNTER_ID_LEVEL_TIMELIMIT  5
-#define ED_COUNTER_ID_LEVEL_TIMESCORE  6
-#define ED_COUNTER_ID_LEVEL_RANDOM     7
-#define ED_COUNTER_ID_SELECT_LEVEL     8
-
-#define ED_NUM_COUNTERBUTTONS          9
+#define ED_COUNTER_ID_SELECT_LEVEL     0
+#define ED_COUNTER_ID_LEVEL_XSIZE      1
+#define ED_COUNTER_ID_LEVEL_YSIZE      2
+#define ED_COUNTER_ID_LEVEL_GEMSLIMIT  3
+#define ED_COUNTER_ID_LEVEL_TIMELIMIT  4
+#define ED_COUNTER_ID_LEVEL_TIMESCORE  5
+#define ED_COUNTER_ID_LEVEL_RANDOM     6
+#define ED_COUNTER_ID_ELEMENT_SCORE    7
+#define ED_COUNTER_ID_ELEMENT_CONTENT  8
+#define ED_COUNTER_ID_CUSTOM_SCORE     9
+#define ED_COUNTER_ID_CUSTOM_GEMCOUNT  10
+#define ED_COUNTER_ID_PUSH_DELAY_FIX   11
+#define ED_COUNTER_ID_PUSH_DELAY_RND   12
+#define ED_COUNTER_ID_MOVE_DELAY_FIX   13
+#define ED_COUNTER_ID_MOVE_DELAY_RND   14
+#define ED_COUNTER_ID_CHANGE_DELAY_FIX 15
+#define ED_COUNTER_ID_CHANGE_DELAY_RND 16
+#define ED_COUNTER_ID_CHANGE_CONT_RND  17
+
+#define ED_NUM_COUNTERBUTTONS          18
 
 #define ED_COUNTER_ID_LEVEL_FIRST      ED_COUNTER_ID_LEVEL_XSIZE
 #define ED_COUNTER_ID_LEVEL_LAST       ED_COUNTER_ID_LEVEL_RANDOM
 
+#define ED_COUNTER_ID_CUSTOM_FIRST     ED_COUNTER_ID_CUSTOM_SCORE
+#define ED_COUNTER_ID_CUSTOM_LAST      ED_COUNTER_ID_MOVE_DELAY_RND
+
+#define ED_COUNTER_ID_CHANGE_FIRST     ED_COUNTER_ID_CHANGE_DELAY_FIX
+#define ED_COUNTER_ID_CHANGE_LAST      ED_COUNTER_ID_CHANGE_CONT_RND
+
 /* values for scrollbutton gadgets */
 #define ED_SCROLLBUTTON_ID_AREA_UP     0
 #define ED_SCROLLBUTTON_ID_AREA_DOWN   1
 /* values for text input gadgets */
 #define ED_TEXTINPUT_ID_LEVEL_NAME     0
 #define ED_TEXTINPUT_ID_LEVEL_AUTHOR   1
+#define ED_TEXTINPUT_ID_ELEMENT_NAME   2
 
-#define ED_NUM_TEXTINPUT               2
+#define ED_NUM_TEXTINPUT               3
 
 #define ED_TEXTINPUT_ID_LEVEL_FIRST    ED_TEXTINPUT_ID_LEVEL_NAME
 #define ED_TEXTINPUT_ID_LEVEL_LAST     ED_TEXTINPUT_ID_LEVEL_AUTHOR
 
+/* values for selectbox gadgets */
+#define ED_SELECTBOX_ID_CUSTOM_ACCESS_TYPE     0
+#define ED_SELECTBOX_ID_CUSTOM_ACCESS_LAYER    1
+#define ED_SELECTBOX_ID_CUSTOM_WALK_TO_ACTION  2
+#define ED_SELECTBOX_ID_CUSTOM_MOVE_PATTERN    3
+#define ED_SELECTBOX_ID_CUSTOM_MOVE_DIRECTION  4
+#define ED_SELECTBOX_ID_CUSTOM_MOVE_STEPSIZE   5
+#define ED_SELECTBOX_ID_CUSTOM_SMASH_TARGETS   6
+#define ED_SELECTBOX_ID_CUSTOM_SLIPPERY_TYPE   7
+#define ED_SELECTBOX_ID_CUSTOM_DEADLINESS      8
+#define ED_SELECTBOX_ID_CUSTOM_CONSISTENCY     9
+#define ED_SELECTBOX_ID_CHANGE_TIME_UNITS      10
+#define ED_SELECTBOX_ID_CHANGE_PLAYER_ACTION   11
+#define ED_SELECTBOX_ID_CHANGE_COLLIDE_ACTION  12
+#define ED_SELECTBOX_ID_CHANGE_OTHER_ACTION    13
+#define ED_SELECTBOX_ID_CHANGE_POWER           14
+
+#define ED_NUM_SELECTBOX                       15
+
+#define ED_SELECTBOX_ID_CUSTOM_FIRST   ED_SELECTBOX_ID_CUSTOM_ACCESS_TYPE
+#define ED_SELECTBOX_ID_CUSTOM_LAST    ED_SELECTBOX_ID_CUSTOM_CONSISTENCY
+
+#define ED_SELECTBOX_ID_CHANGE_FIRST   ED_SELECTBOX_ID_CHANGE_TIME_UNITS
+#define ED_SELECTBOX_ID_CHANGE_LAST    ED_SELECTBOX_ID_CHANGE_POWER
+
+/* values for textbutton gadgets */
+#define ED_TEXTBUTTON_ID_PROPERTIES_INFO       0
+#define ED_TEXTBUTTON_ID_PROPERTIES_CONFIG     1
+#define ED_TEXTBUTTON_ID_PROPERTIES_ADVANCED   2
+#define ED_TEXTBUTTON_ID_SAVE_AS_TEMPLATE      3
+
+#define ED_NUM_TEXTBUTTON                      4
+
 /* values for checkbutton gadgets */
 #define ED_CHECKBUTTON_ID_DOUBLE_SPEED         0
 #define ED_CHECKBUTTON_ID_GRAVITY              1
 #define ED_CHECKBUTTON_ID_RANDOM_RESTRICTED    2
 #define ED_CHECKBUTTON_ID_STICK_ELEMENT                3
 #define ED_CHECKBUTTON_ID_EM_SLIPPERY_GEMS     4
-
-#define ED_NUM_CHECKBUTTONS                    5
+#define ED_CHECKBUTTON_ID_CUSTOM_ACCESSIBLE    5
+#define ED_CHECKBUTTON_ID_CUSTOM_WALK_TO_OBJECT        6
+#define ED_CHECKBUTTON_ID_CUSTOM_CAN_MOVE      7
+#define ED_CHECKBUTTON_ID_CUSTOM_CAN_FALL      8
+#define ED_CHECKBUTTON_ID_CUSTOM_CAN_SMASH     9
+#define ED_CHECKBUTTON_ID_CUSTOM_SLIPPERY      10
+#define ED_CHECKBUTTON_ID_CUSTOM_DEADLY                11
+#define ED_CHECKBUTTON_ID_CUSTOM_EXPLODE_RESULT        12
+#define ED_CHECKBUTTON_ID_CUSTOM_EXPLODE_FIRE  13
+#define ED_CHECKBUTTON_ID_CUSTOM_EXPLODE_SMASH 14
+#define ED_CHECKBUTTON_ID_CUSTOM_EXPLODE_IMPACT        15
+#define ED_CHECKBUTTON_ID_CUSTOM_USE_GRAPHIC   16
+#define ED_CHECKBUTTON_ID_CUSTOM_CAN_CHANGE    17
+#define ED_CHECKBUTTON_ID_CHANGE_DELAY         18
+#define ED_CHECKBUTTON_ID_CHANGE_BY_PLAYER     19
+#define ED_CHECKBUTTON_ID_CHANGE_BY_COLLISION  20
+#define ED_CHECKBUTTON_ID_CHANGE_BY_OTHER      21
+#define ED_CHECKBUTTON_ID_CHANGE_USE_EXPLOSION 22
+#define ED_CHECKBUTTON_ID_CHANGE_USE_CONTENT   23
+#define ED_CHECKBUTTON_ID_CHANGE_ONLY_COMPLETE 24
+#define ED_CHECKBUTTON_ID_CHANGE_USE_RANDOM    25
+#define ED_CHECKBUTTON_ID_CUSTOM_USE_TEMPLATE  26
+
+#define ED_NUM_CHECKBUTTONS                    27
 
 #define ED_CHECKBUTTON_ID_LEVEL_FIRST  ED_CHECKBUTTON_ID_DOUBLE_SPEED
 #define ED_CHECKBUTTON_ID_LEVEL_LAST   ED_CHECKBUTTON_ID_RANDOM_RESTRICTED
 
+#define ED_CHECKBUTTON_ID_CUSTOM_FIRST ED_CHECKBUTTON_ID_CUSTOM_ACCESSIBLE
+#define ED_CHECKBUTTON_ID_CUSTOM_LAST  ED_CHECKBUTTON_ID_CUSTOM_EXPLODE_IMPACT
+
+#define ED_CHECKBUTTON_ID_CHANGE_FIRST ED_CHECKBUTTON_ID_CUSTOM_USE_GRAPHIC
+#define ED_CHECKBUTTON_ID_CHANGE_LAST  ED_CHECKBUTTON_ID_CUSTOM_USE_TEMPLATE
+
 /* values for radiobutton gadgets */
 #define ED_RADIOBUTTON_ID_PERCENTAGE   0
 #define ED_RADIOBUTTON_ID_QUANTITY     1
 #define ED_RADIOBUTTON_ID_LEVEL_FIRST  ED_RADIOBUTTON_ID_PERCENTAGE
 #define ED_RADIOBUTTON_ID_LEVEL_LAST   ED_RADIOBUTTON_ID_QUANTITY
 
+/* values for drawing area gadgets */
+#define ED_DRAWING_ID_DRAWING_LEVEL            0
+#define ED_DRAWING_ID_ELEMENT_CONTENT_0                1
+#define ED_DRAWING_ID_ELEMENT_CONTENT_1                2
+#define ED_DRAWING_ID_ELEMENT_CONTENT_2                3
+#define ED_DRAWING_ID_ELEMENT_CONTENT_3                4
+#define ED_DRAWING_ID_ELEMENT_CONTENT_4                5
+#define ED_DRAWING_ID_ELEMENT_CONTENT_5                6
+#define ED_DRAWING_ID_ELEMENT_CONTENT_6                7
+#define ED_DRAWING_ID_ELEMENT_CONTENT_7                8
+#define ED_DRAWING_ID_AMOEBA_CONTENT           9
+#define ED_DRAWING_ID_CUSTOM_GRAPHIC           10
+#define ED_DRAWING_ID_CUSTOM_CONTENT           11
+#define ED_DRAWING_ID_CUSTOM_CHANGE_TARGET     12
+#define ED_DRAWING_ID_CUSTOM_CHANGE_CONTENT    13
+#define ED_DRAWING_ID_CUSTOM_CHANGE_TRIGGER    14
+#define ED_DRAWING_ID_RANDOM_BACKGROUND                15
+
+#define ED_NUM_DRAWING_AREAS                   16
+
+
+/*
+  -----------------------------------------------------------------------------
+  some internally used definitions
+  -----------------------------------------------------------------------------
+*/
+
 /* values for CopyLevelToUndoBuffer() */
 #define UNDO_IMMEDIATE                 0
 #define UNDO_ACCUMULATE                        1
 
-/* values for ClearEditorGadgetInfoText() and HandleGadgetInfoText() */
-#define INFOTEXT_XPOS                  SX
-#define INFOTEXT_YPOS                  (SY + SYSIZE - MINI_TILEX + 2)
-#define INFOTEXT_XSIZE                 SXSIZE
-#define INFOTEXT_YSIZE                 MINI_TILEX
-#define MAX_INFOTEXT_LEN               (SXSIZE / FONT2_XSIZE)
+/* values for scrollbars */
+#define ED_SCROLL_NO                   0
+#define ED_SCROLL_LEFT                 1
+#define ED_SCROLL_RIGHT                        2
+#define ED_SCROLL_UP                   4
+#define ED_SCROLL_DOWN                 8
+
+/* screens in the level editor */
+#define ED_MODE_DRAWING                        0
+#define ED_MODE_INFO                   1
+#define ED_MODE_PROPERTIES             2
+
+/* sub-screens in the element properties section */
+#define ED_MODE_PROPERTIES_INFO                ED_TEXTBUTTON_ID_PROPERTIES_INFO
+#define ED_MODE_PROPERTIES_CONFIG      ED_TEXTBUTTON_ID_PROPERTIES_CONFIG
+#define ED_MODE_PROPERTIES_ADVANCED    ED_TEXTBUTTON_ID_PROPERTIES_ADVANCED
+
+/* how many steps can be cancelled */
+#define NUM_UNDO_STEPS                 (10 + 1)
+
+/* values for elements with score */
+#define MIN_SCORE                      0
+#define MAX_SCORE                      255
+
+/* values for elements with gem count */
+#define MIN_GEM_COUNT                  0
+#define MAX_GEM_COUNT                  100
+
+/* values for random placement */
+#define RANDOM_USE_PERCENTAGE          0
+#define RANDOM_USE_QUANTITY            1
+
+/* maximal size of level editor drawing area */
+#define MAX_ED_FIELDX          (2 * SCR_FIELDX)
+#define MAX_ED_FIELDY          (2 * SCR_FIELDY - 1)
+
+
+/*
+  -----------------------------------------------------------------------------
+  some internally used data structure definitions
+  -----------------------------------------------------------------------------
+*/
 
 static struct
 {
@@ -390,39 +693,38 @@ static struct
   char *text;
 } control_info[ED_NUM_CTRL_BUTTONS] =
 {
-  { 's', "draw single items" },
-  { 'd', "draw connected items" },
-  { 'l', "draw lines" },
-  { 'a', "draw arcs" },
-  { 'r', "draw outline rectangles" },
-  { 'R', "draw filled rectangles" },
-  { '\0', "wrap (rotate) level up" },
-  { 't', "enter text elements" },
-  { 'f', "flood fill" },
-  { '\0', "wrap (rotate) level left" },
-  { '?', "properties of drawing element" },
-  { '\0', "wrap (rotate) level right" },
-  { '\0', "random element placement" },
-  { 'b', "grab brush" },
-  { '\0', "wrap (rotate) level down" },
-  { ',', "pick drawing element" },
-  { 'U', "undo last operation" },
-  { 'I', "level properties" },
-  { 'S', "save level" },
-  { 'C', "clear level" },
-  { 'T', "test level" },
-  { 'E', "exit level editor" }
+  { 's',       "draw single items"             },
+  { 'd',       "draw connected items"          },
+  { 'l',       "draw lines"                    },
+  { 'a',       "draw arcs"                     },
+  { 'r',       "draw outline rectangles"       },
+  { 'R',       "draw filled rectangles"        },
+  { '\0',      "wrap (rotate) level up"        },
+  { 't',       "enter text elements"           },
+  { 'f',       "flood fill"                    },
+  { '\0',      "wrap (rotate) level left"      },
+  { '?',       "properties of drawing element" },
+  { '\0',      "wrap (rotate) level right"     },
+  { '\0',      "random element placement"      },
+  { 'b',       "grab brush"                    },
+  { '\0',      "wrap (rotate) level down"      },
+  { ',',       "pick drawing element"          },
+  { 'U',       "undo last operation"           },
+  { 'I',       "level properties"              },
+  { 'S',       "save level"                    },
+  { 'C',       "clear level"                   },
+  { 'T',       "test level"                    },
+  { 'E',       "exit level editor"             }
 };
 
-/* values for random placement */
-#define RANDOM_USE_PERCENTAGE          0
-#define RANDOM_USE_QUANTITY            1
-
 static int random_placement_value = 10;
 static int random_placement_method = RANDOM_USE_QUANTITY;
-static int random_placement_background_element = EL_ERDREICH;
+static int random_placement_background_element = EL_SAND;
 static boolean random_placement_background_restricted = FALSE;
 static boolean stick_element_properties_window = FALSE;
+static boolean custom_element_properties[NUM_ELEMENT_PROPERTIES];
+static boolean custom_element_change_events[NUM_CHANGE_EVENTS];
+static struct ElementInfo custom_element;
 
 static struct
 {
@@ -430,82 +732,166 @@ static struct
   int min_value, max_value;
   int gadget_id_down, gadget_id_up;
   int gadget_id_text;
+  int gadget_id_align;
   int *value;
-  char *infotext_above, *infotext_right;
+  char *text_above, *text_left, *text_right;
 } counterbutton_info[ED_NUM_COUNTERBUTTONS] =
 {
+  /* ---------- level and editor settings ---------------------------------- */
+
   {
-    ED_COUNT_ELEM_SCORE_XPOS,          ED_COUNT_ELEM_SCORE_YPOS,
-    MIN_SCORE,                         MAX_SCORE,
-    GADGET_ID_ELEM_SCORE_DOWN,         GADGET_ID_ELEM_SCORE_UP,
-    GADGET_ID_ELEM_SCORE_TEXT,
-    NULL,                              /* will be set when used */
-    "element score",                   NULL
-  },
-  {
-    ED_COUNT_ELEM_CONTENT_XPOS,                ED_COUNT_ELEM_CONTENT_YPOS,
-    MIN_ELEMENT_CONTENTS,              MAX_ELEMENT_CONTENTS,
-    GADGET_ID_ELEM_CONTENT_DOWN,       GADGET_ID_ELEM_CONTENT_UP,
-    GADGET_ID_ELEM_CONTENT_TEXT,
-    &level.num_yam_contents,
-    "element content",                 NULL
+    DX + 5 - SX,                       DY + 3 - SY,
+    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
   },
   {
-    ED_SETTINGS_XPOS,                  ED_COUNTER_YPOS(2),
+    ED_SETTINGS_XPOS(0),               ED_COUNTER_YPOS(2),
     MIN_LEV_FIELDX,                    MAX_LEV_FIELDX,
     GADGET_ID_LEVEL_XSIZE_DOWN,                GADGET_ID_LEVEL_XSIZE_UP,
-    GADGET_ID_LEVEL_XSIZE_TEXT,
+    GADGET_ID_LEVEL_XSIZE_TEXT,                GADGET_ID_NONE,
     &level.fieldx,
-    "playfield size",                  "width",
+    "playfield size:",                 NULL, "width",
   },
   {
-    ED_SETTINGS_XPOS + 2 * DXSIZE,     ED_COUNTER_YPOS(2),
+    ED_SETTINGS_XPOS(0) + 2 * DXSIZE,  ED_COUNTER_YPOS(2),
     MIN_LEV_FIELDY,                    MAX_LEV_FIELDY,
     GADGET_ID_LEVEL_YSIZE_DOWN,                GADGET_ID_LEVEL_YSIZE_UP,
-    GADGET_ID_LEVEL_YSIZE_TEXT,
+    GADGET_ID_LEVEL_YSIZE_TEXT,                GADGET_ID_LEVEL_XSIZE_UP,
     &level.fieldy,
-    NULL,                              "height",
+    NULL,                              " ", "height",
   },
   {
-    ED_SETTINGS_XPOS,                  ED_COUNTER_YPOS(3),
+    ED_SETTINGS_XPOS(0),               ED_COUNTER_YPOS(3),
     0,                                 999,
-    GADGET_ID_LEVEL_COLLECT_DOWN,      GADGET_ID_LEVEL_COLLECT_UP,
-    GADGET_ID_LEVEL_COLLECT_TEXT,
+    GADGET_ID_LEVEL_GEMSLIMIT_DOWN,    GADGET_ID_LEVEL_GEMSLIMIT_UP,
+    GADGET_ID_LEVEL_GEMSLIMIT_TEXT,    GADGET_ID_NONE,
     &level.gems_needed,
-    "number of emeralds to collect",   NULL
+    "number of emeralds to collect:",  NULL, NULL
   },
   {
-    ED_SETTINGS_XPOS,                  ED_COUNTER_YPOS(4),
+    ED_SETTINGS_XPOS(0),               ED_COUNTER_YPOS(4),
     0,                                 999,
     GADGET_ID_LEVEL_TIMELIMIT_DOWN,    GADGET_ID_LEVEL_TIMELIMIT_UP,
-    GADGET_ID_LEVEL_TIMELIMIT_TEXT,
+    GADGET_ID_LEVEL_TIMELIMIT_TEXT,    GADGET_ID_NONE,
     &level.time,
-    "time available to solve level",   "(0 => no time limit)"
+    "time available to solve level:",  NULL, "(0 => no time limit)"
   },
   {
-    ED_SETTINGS_XPOS,                  ED_COUNTER_YPOS(5),
+    ED_SETTINGS_XPOS(0),               ED_COUNTER_YPOS(5),
     0,                                 255,
     GADGET_ID_LEVEL_TIMESCORE_DOWN,    GADGET_ID_LEVEL_TIMESCORE_UP,
-    GADGET_ID_LEVEL_TIMESCORE_TEXT,
-    &level.score[SC_ZEITBONUS],
-    "score for each 10 seconds left",  NULL
+    GADGET_ID_LEVEL_TIMESCORE_TEXT,    GADGET_ID_NONE,
+    &level.score[SC_TIME_BONUS],
+    "score for each 10 seconds left:", NULL, NULL
   },
   {
-    ED_SETTINGS_XPOS,                  ED_COUNTER2_YPOS(8),
+    ED_SETTINGS_XPOS(0),               ED_COUNTER2_YPOS(8),
     1,                                 100,
     GADGET_ID_LEVEL_RANDOM_DOWN,       GADGET_ID_LEVEL_RANDOM_UP,
-    GADGET_ID_LEVEL_RANDOM_TEXT,
+    GADGET_ID_LEVEL_RANDOM_TEXT,       GADGET_ID_NONE,
     &random_placement_value,
-    "random element placement",                "in"
+    "random element placement:",       NULL, "in"
   },
+
+  /* ---------- element settings: configure (various elements) ------------- */
+
   {
-    DX + 5 - SX,                       DY + 3 - SY,
-    1,                                 100,
-    GADGET_ID_SELECT_LEVEL_DOWN,       GADGET_ID_SELECT_LEVEL_UP,
-    GADGET_ID_SELECT_LEVEL_TEXT,
-    &level_nr,
-    NULL,                              NULL
-  }
+    ED_SETTINGS_XPOS(0),               ED_SETTINGS_YPOS(0),
+    MIN_SCORE,                         MAX_SCORE,
+    GADGET_ID_ELEMENT_SCORE_DOWN,      GADGET_ID_ELEMENT_SCORE_UP,
+    GADGET_ID_ELEMENT_SCORE_TEXT,      GADGET_ID_NONE,
+    NULL,                              /* will be set when used */
+    NULL,                              NULL, NULL
+  },
+  {
+    ED_SETTINGS_XPOS(0),               ED_SETTINGS_YPOS(6),
+    MIN_ELEMENT_CONTENTS,              MAX_ELEMENT_CONTENTS,
+    GADGET_ID_ELEMENT_CONTENT_DOWN,    GADGET_ID_ELEMENT_CONTENT_UP,
+    GADGET_ID_ELEMENT_CONTENT_TEXT,    GADGET_ID_NONE,
+    &level.num_yamyam_contents,
+    NULL,                              NULL, "number of content areas"
+  },
+
+  /* ---------- element settings: configure (custom elements) ------------- */
+
+  {
+    ED_SETTINGS_XPOS(1),               ED_SETTINGS_YPOS(3),
+    MIN_SCORE,                         MAX_SCORE,
+    GADGET_ID_CUSTOM_SCORE_DOWN,       GADGET_ID_CUSTOM_SCORE_UP,
+    GADGET_ID_CUSTOM_SCORE_TEXT,       GADGET_ID_NONE,
+    &custom_element.score,
+    NULL,                              "collect score", NULL
+  },
+  {
+    ED_SETTINGS_XPOS(13) + 10,         ED_SETTINGS_YPOS(3),
+    MIN_GEM_COUNT,                     MAX_GEM_COUNT,
+    GADGET_ID_CUSTOM_GEMCOUNT_DOWN,    GADGET_ID_CUSTOM_GEMCOUNT_UP,
+    GADGET_ID_CUSTOM_GEMCOUNT_TEXT,    GADGET_ID_CUSTOM_SCORE_UP,
+    &custom_element.gem_count,
+    NULL,                              "gems", NULL
+  },
+  {
+    ED_SETTINGS_XPOS(1),               ED_SETTINGS_YPOS(4),
+    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
+  },
+  {
+    ED_COUNT_PUSH_DELAY_RND_XPOS,      ED_SETTINGS_YPOS(4),
+    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
+  },
+  {
+    ED_SETTINGS_XPOS(1),               ED_SETTINGS_YPOS(7),
+    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
+  },
+  {
+    ED_COUNT_MOVE_DELAY_RND_XPOS,      ED_SETTINGS_YPOS(7),
+    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
+  },
+
+  /* ---------- element settings: advanced (custom elements) --------------- */
+
+  {
+    ED_SETTINGS_XPOS(2),               ED_SETTINGS_YPOS(3),
+    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,                              "delay", NULL,
+  },
+  {
+    ED_COUNT_CHANGE_DELAY_RND_XPOS+20, ED_SETTINGS_YPOS(3),
+    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
+  },
+  {
+    ED_SETTINGS_XPOS(3),               ED_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,
+    NULL,                              "use random change:", "(%)"
+  },
 };
 
 static struct
@@ -518,24 +904,339 @@ static struct
 } textinput_info[ED_NUM_TEXTINPUT] =
 {
   {
-    ED_SETTINGS_XPOS,                  ED_COUNTER_YPOS(0),
+    ED_SETTINGS_XPOS(0),               ED_COUNTER_YPOS(0),
     GADGET_ID_LEVEL_NAME,
     MAX_LEVEL_NAME_LEN,
     level.name,
     "Title"
   },
   {
-    ED_SETTINGS_XPOS,                  ED_COUNTER_YPOS(1),
+    ED_SETTINGS_XPOS(0),               ED_COUNTER_YPOS(1),
     GADGET_ID_LEVEL_AUTHOR,
     MAX_LEVEL_AUTHOR_LEN,
     level.author,
     "Author"
+  },
+  {
+    5 * MINI_TILEX,                    5 * MINI_TILEY - ED_BORDER_SIZE,
+    GADGET_ID_ELEMENT_NAME,
+    MAX_ELEMENT_NAME_LEN - 2,          /* currently 2 chars less editable */
+    custom_element.description,
+    NULL
   }
 };
 
+static struct ValueTextInfo options_access_type[] =
+{
+  { EP_WALKABLE,               "walk"                          },
+  { EP_PASSABLE,               "pass"                          },
+  { -1,                                NULL                            }
+};
+
+static struct ValueTextInfo options_access_layer[] =
+{
+  { EP_ACCESSIBLE_OVER,                "over"                          },
+  { EP_ACCESSIBLE_INSIDE,      "inside"                        },
+  { EP_ACCESSIBLE_UNDER,       "under"                         },
+  { -1,                                NULL                            }
+};
+
+static struct ValueTextInfo options_walk_to_action[] =
+{
+  { EP_DIGGABLE,               "diggable"                      },
+  { EP_COLLECTIBLE,            "collectible"                   },
+  { EP_PUSHABLE,               "pushable"                      },
+  { -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_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"                 },
+  { -1,                                NULL                            }
+};
+
+static struct ValueTextInfo options_move_direction[] =
+{
+  { MV_NO_MOVING,              "automatic"                     },
+  { MV_LEFT,                   "left"                          },
+  { MV_RIGHT,                  "right"                         },
+  { MV_UP,                     "up"                            },
+  { MV_DOWN,                   "down"                          },
+  { -1,                                NULL                            }
+};
+
+static struct ValueTextInfo options_move_stepsize[] =
+{
+  { 1,                         "very slow"                     },
+  { 2,                         "slow"                          },
+  { 4,                         "normal"                        },
+  { 8,                         "fast"                          },
+  { 16,                                "very fast"                     },
+  { -1,                                NULL                            }
+};
+
+static struct ValueTextInfo options_smash_targets[] =
+{
+  { EP_CAN_SMASH_PLAYER,       "player"                        },
+#if 0
+  { EP_CAN_SMASH_ENEMIES,      "enemies"                       },
+#endif
+  { EP_CAN_SMASH_EVERYTHING,   "everything"                    },
+  { -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"                    },
+  { -1,                                NULL                            }
+};
+
+static struct ValueTextInfo options_deadliness[] =
+{
+  { EP_DONT_RUN_INTO,          "running into"                  },
+  { EP_DONT_COLLIDE_WITH,      "colliding with"                },
+  { EP_DONT_TOUCH,             "touching"                      },
+  { -1,                                NULL                            }
+};
+
+static struct ValueTextInfo options_consistency[] =
+{
+  { EP_CAN_EXPLODE,            "can explode"                   },
+  { EP_INDESTRUCTIBLE,         "indestructible"                },
+  { -1,                                NULL                            }
+};
+
+static struct ValueTextInfo options_time_units[] =
+{
+  { 50,                                "seconds"                       },
+  { 1,                         "frames"                        },
+  { -1,                                NULL                            }
+};
+
+static struct ValueTextInfo options_change_player_action[] =
+{
+  { CE_TOUCHED_BY_PLAYER,      "touched"                       },
+  { CE_PRESSED_BY_PLAYER,      "pressed"                       },
+  { CE_PUSHED_BY_PLAYER,       "pushed"                        },
+  { -1,                                NULL                            }
+};
+
+static struct ValueTextInfo options_change_collide_action[] =
+{
+  { CE_COLLISION,              "on collision"                  },
+  { CE_IMPACT,                 "on impact"                     },
+  { CE_SMASHED,                        "when smashed"                  },
+  { -1,                                NULL                            }
+};
+
+static struct ValueTextInfo options_change_other_action[] =
+{
+  { CE_OTHER_IS_TOUCHING,              "touching"                      },
+  { CE_OTHER_IS_CHANGING,              "change of"                     },
+  { CE_OTHER_IS_EXPLODING,             "explosion of"                  },
+  { CE_OTHER_GETS_TOUCHED,             "player touches"                },
+  { CE_OTHER_GETS_PRESSED,             "player presses"                },
+  { CE_OTHER_GETS_PUSHED,              "player pushes"                 },
+  { CE_OTHER_GETS_COLLECTED,           "player collects"               },
+  { -1,                                NULL                                    }
+};
+
+static struct ValueTextInfo options_change_power[] =
+{
+  { CP_NON_DESTRUCTIVE,                "non-destructive"               },
+  { CP_HALF_DESTRUCTIVE,       "half-destructive"              },
+  { CP_FULL_DESTRUCTIVE,       "full-destructive"              },
+  { -1,                                NULL                            }
+};
+
+static struct
+{
+  int x, y;
+  int gadget_id;
+  int gadget_id_align;
+  int size;    /* char size of selectbox or '-1' (dynamically determined) */
+  struct ValueTextInfo *options;
+  int *value;
+  char *text_left, *text_right, *infotext;
+} selectbox_info[ED_NUM_SELECTBOX] =
+{
+  /* ---------- element settings: configure (custom elements) ------------- */
+
+  {
+    ED_SETTINGS_XPOS(1),               ED_SETTINGS_YPOS(1),
+    GADGET_ID_CUSTOM_ACCESS_TYPE,      GADGET_ID_NONE,
+    -1,
+    options_access_type,
+    &custom_element.access_type,
+    "player can", NULL, "type of access to this field"
+  },
+  {
+    ED_SETTINGS_XPOS(11),              ED_SETTINGS_YPOS(1),
+    GADGET_ID_CUSTOM_ACCESS_LAYER,     GADGET_ID_CUSTOM_ACCESS_TYPE,
+    -1,
+    options_access_layer,
+    &custom_element.access_layer,
+    NULL, NULL, "layer of access for this field"
+  },
+  {
+    ED_SETTINGS_XPOS(1),               ED_SETTINGS_YPOS(2),
+    GADGET_ID_CUSTOM_WALK_TO_ACTION,   GADGET_ID_NONE,
+    -1,
+    options_walk_to_action,
+    &custom_element.walk_to_action,
+    NULL, NULL, "diggable/collectible/pushable"
+  },
+  {
+    ED_SETTINGS_XPOS(1),               ED_SETTINGS_YPOS(5),
+    GADGET_ID_CUSTOM_MOVE_PATTERN,     GADGET_ID_NONE,
+    -1,
+    options_move_pattern,
+    &custom_element.move_pattern,
+    "can move", NULL, "element move direction"
+  },
+  {
+    ED_SETTINGS_XPOS(1),               ED_SETTINGS_YPOS(6),
+    GADGET_ID_CUSTOM_MOVE_DIRECTION,   GADGET_ID_NONE,
+    -1,
+    options_move_direction,
+    &custom_element.move_direction_initial,
+    "starts moving", NULL, "initial element move direction"
+  },
+  {
+    ED_SETTINGS_XPOS(1),               ED_SETTINGS_YPOS(8),
+    GADGET_ID_CUSTOM_MOVE_STEPSIZE,    GADGET_ID_NONE,
+    -1,
+    options_move_stepsize,
+    &custom_element.move_stepsize,
+    "move/fall speed", NULL, "speed of element movement"
+  },
+  {
+    ED_SETTINGS_XPOS(7),               ED_SETTINGS_YPOS(9),
+    GADGET_ID_CUSTOM_SMASH_TARGETS,    GADGET_ID_CUSTOM_CAN_SMASH,
+    -1,
+    options_smash_targets,
+    &custom_element.smash_targets,
+    "can smash", NULL, "elements that can be smashed"
+  },
+  {
+    ED_SETTINGS_XPOS(1),               ED_SETTINGS_YPOS(10),
+    GADGET_ID_CUSTOM_SLIPPERY_TYPE,    GADGET_ID_NONE,
+    -1,
+    options_slippery_type,
+    &custom_element.slippery_type,
+    "slippery", NULL, "where other elements fall down"
+  },
+  {
+    ED_SETTINGS_XPOS(1),               ED_SETTINGS_YPOS(11),
+    GADGET_ID_CUSTOM_DEADLINESS,       GADGET_ID_NONE,
+    -1,
+    options_deadliness,
+    &custom_element.deadliness,
+    "deadly when", NULL, "deadliness of element"
+  },
+  {
+    ED_SETTINGS_XPOS(1),               ED_SETTINGS_YPOS(12),
+    GADGET_ID_CUSTOM_CONSISTENCY,      GADGET_ID_NONE,
+    -1,
+    options_consistency,
+    &custom_element.consistency,
+    NULL, "explodes to:", "consistency/destructibility"
+  },
+
+  /* ---------- element settings: advanced (custom elements) --------------- */
+
+  {
+    ED_SETTINGS_XPOS(2),               ED_SETTINGS_YPOS(4),
+    GADGET_ID_CHANGE_TIME_UNITS,       GADGET_ID_NONE,
+    -1,
+    options_time_units,
+    &custom_element.change.delay_frames,
+    "delay time given in", NULL, "delay time units for change"
+  },
+  {
+    ED_SETTINGS_XPOS(2),               ED_SETTINGS_YPOS(5),
+    GADGET_ID_CHANGE_PLAYER_ACTION,    GADGET_ID_NONE,
+    -1,
+    options_change_player_action,
+    &custom_element.change_player_action,
+    NULL, "by player", "type of player contact"
+  },
+  {
+    ED_SETTINGS_XPOS(2),               ED_SETTINGS_YPOS(6),
+    GADGET_ID_CHANGE_COLLIDE_ACTION,   GADGET_ID_NONE,
+    -1,
+    options_change_collide_action,
+    &custom_element.change_collide_action,
+    NULL, NULL, "change after impact or smash"
+  },
+  {
+    ED_SETTINGS_XPOS(2),               ED_SETTINGS_YPOS(7),
+    GADGET_ID_CHANGE_OTHER_ACTION,     GADGET_ID_NONE,
+    -1,
+    options_change_other_action,
+    &custom_element.change_other_action,
+    NULL, "element:", "type of other element action"
+  },
+  {
+    ED_SETTINGS_XPOS(2),               ED_SETTINGS_YPOS(10),
+    GADGET_ID_CHANGE_POWER,            GADGET_ID_NONE,
+    -1,
+    options_change_power,
+    &custom_element.change.power,
+    "power:", NULL, "power of extended change"
+  },
+};
+
+static struct
+{
+  int x, y;
+  int gadget_id;
+  int gadget_id_align;
+  int size;
+  char *text, *infotext;
+} textbutton_info[ED_NUM_TEXTBUTTON] =
+{
+  {
+    ED_SETTINGS_XPOS(0),               ED_COUNTER_YPOS(1),
+    GADGET_ID_PROPERTIES_INFO,         GADGET_ID_NONE,
+    11, "Information",                 "Show information about element"
+  },
+  {
+    ED_SETTINGS_XPOS(0) + 166,         ED_COUNTER_YPOS(1),
+    GADGET_ID_PROPERTIES_CONFIG,       GADGET_ID_NONE,
+    11, "Configure",                   "Configure element properties"
+  },
+  {
+    ED_SETTINGS_XPOS(0) + 332,         ED_COUNTER_YPOS(1),
+    GADGET_ID_PROPERTIES_ADVANCED,     GADGET_ID_NONE,
+    11, "Advanced",                    "Advanced element configuration"
+  },
+  {
+    ED_SETTINGS_XPOS(0) + 262,         ED_SETTINGS_YPOS(13),
+    GADGET_ID_SAVE_AS_TEMPLATE,                GADGET_ID_CUSTOM_USE_TEMPLATE,
+    -1, "Save as template",            "Save current settings as new template"
+  },
+};
+
 static struct
 {
-  int xpos, ypos;
+  int gd_x, gd_y;
   int x, y;
   int gadget_id;
   char *infotext;
@@ -581,7 +1282,7 @@ static struct
 
 static struct
 {
-  int xpos, ypos;
+  int gd_x, gd_y;
   int x, y;
   int width, height;
   int type;
@@ -619,25 +1320,26 @@ static struct
 {
   int x, y;
   int gadget_id;
+  int gadget_id_align;
   int radio_button_nr;
   int *value;
   int checked_value;
-  char *text, *infotext;
+  char *text_left, *text_right, *infotext;
 } radiobutton_info[ED_NUM_RADIOBUTTONS] =
 {
   {
-    ED_SETTINGS_XPOS + 160,            ED_COUNTER2_YPOS(8),
-    GADGET_ID_RANDOM_PERCENTAGE,
+    ED_SETTINGS_XPOS(0) + 160,         ED_COUNTER2_YPOS(8),
+    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"
+    " ", "percentage",                 "use percentage for random elements"
   },
   {
-    ED_SETTINGS_XPOS + 340,            ED_COUNTER2_YPOS(8),
-    GADGET_ID_RANDOM_QUANTITY,
+    ED_SETTINGS_XPOS(0) + 340,         ED_COUNTER2_YPOS(8),
+    GADGET_ID_RANDOM_QUANTITY,         GADGET_ID_RANDOM_PERCENTAGE,
     RADIO_NR_RANDOM_ELEMENTS,
     &random_placement_method,          RANDOM_USE_QUANTITY,
-    "quantity",                                "use quantity for random elements"
+    " ", "quantity",                   "use quantity for random elements"
   }
 };
 
@@ -645,45 +1347,328 @@ static struct
 {
   int x, y;
   int gadget_id;
+  int gadget_id_align;
   boolean *value;
-  char *text, *infotext;
+  char *text_left, *text_right, *infotext;
 } checkbutton_info[ED_NUM_CHECKBUTTONS] =
 {
+  /* ---------- level and editor settings ---------------------------------- */
+
   {
-    ED_SETTINGS_XPOS,                  ED_COUNTER_YPOS(6) - MINI_TILEY,
-    GADGET_ID_DOUBLE_SPEED,
+    ED_SETTINGS_XPOS(0),               ED_COUNTER_YPOS(6) - MINI_TILEY,
+    GADGET_ID_DOUBLE_SPEED,            GADGET_ID_NONE,
     &level.double_speed,
-    "double speed movement",           "set movement speed of player"
+    NULL, "double speed movement",     "set movement speed of player"
   },
   {
-    ED_SETTINGS_XPOS + 340,            ED_COUNTER_YPOS(6) - MINI_TILEY,
-    GADGET_ID_GRAVITY,
+    ED_SETTINGS_XPOS(0) + 340,         ED_COUNTER_YPOS(6) - MINI_TILEY,
+    GADGET_ID_GRAVITY,                 GADGET_ID_DOUBLE_SPEED,
     &level.gravity,
-    "gravity",                         "set level gravity"
+    " ", "gravity",                    "set level gravity"
   },
   {
-    ED_SETTINGS_XPOS,                  ED_COUNTER2_YPOS(9) - MINI_TILEY,
-    GADGET_ID_RANDOM_RESTRICTED,
+    ED_SETTINGS_XPOS(0),               ED_COUNTER2_YPOS(9) - MINI_TILEY,
+    GADGET_ID_RANDOM_RESTRICTED,       GADGET_ID_NONE,
     &random_placement_background_restricted,
-    "restrict random placement to",    "set random placement restriction"
+    NULL,
+    "restrict random placement to:",   "set random placement restriction"
   },
+
+  /* ---------- element settings: configure (various elements) ------------- */
+
   {
-    ED_SETTINGS_XPOS,                  ED_COUNTER_YPOS(4),
-    GADGET_ID_STICK_ELEMENT,
+    ED_SETTINGS_XPOS(0),               0,      /* set at runtime */
+    GADGET_ID_STICK_ELEMENT,           GADGET_ID_NONE,
     &stick_element_properties_window,
-    "stick window to edit content",    "stick window to edit content"
+    NULL,
+    "stick this screen to edit content","stick this screen to edit content"
   },
   {
-    ED_SETTINGS_XPOS,                  ED_COUNTER_YPOS(4),
-    GADGET_ID_EM_SLIPPERY_GEMS,
+    ED_SETTINGS_XPOS(0),               ED_COUNTER_YPOS(4),
+    GADGET_ID_EM_SLIPPERY_GEMS,                GADGET_ID_NONE,
     &level.em_slippery_gems,
+    NULL,
     "slip down from certain flat walls","use EM style slipping behaviour"
-  }
-};
+  },
 
-/* maximal size of level editor drawing area */
-#define MAX_ED_FIELDX          (2 * SCR_FIELDX)
-#define MAX_ED_FIELDY          (2 * SCR_FIELDY - 1)
+  /* ---------- element settings: configure (custom elements) ------------- */
+
+  {
+    ED_SETTINGS_XPOS(0),               ED_SETTINGS_YPOS(1),
+    GADGET_ID_CUSTOM_ACCESSIBLE,       GADGET_ID_NONE,
+    &custom_element_properties[EP_ACCESSIBLE],
+    NULL, NULL,                                "player can walk to or pass this field"
+  },
+  {
+    ED_SETTINGS_XPOS(0),               ED_SETTINGS_YPOS(2),
+    GADGET_ID_CUSTOM_WALK_TO_OBJECT,   GADGET_ID_NONE,
+    &custom_element_properties[EP_WALK_TO_OBJECT],
+    NULL, NULL,                                "player can dig/collect/push element"
+  },
+  {
+    ED_SETTINGS_XPOS(0),               ED_SETTINGS_YPOS(5),
+    GADGET_ID_CUSTOM_CAN_MOVE,         GADGET_ID_NONE,
+    &custom_element_properties[EP_CAN_MOVE],
+    NULL, NULL,                                "element can move in some direction"
+  },
+  {
+    ED_SETTINGS_XPOS(0),               ED_SETTINGS_YPOS(9),
+    GADGET_ID_CUSTOM_CAN_FALL,         GADGET_ID_NONE,
+    &custom_element_properties[EP_CAN_FALL],
+    NULL, "can fall",                  "element can fall down"
+  },
+  {
+    ED_SETTINGS_XPOS(6),               ED_SETTINGS_YPOS(9),
+    GADGET_ID_CUSTOM_CAN_SMASH,                GADGET_ID_CUSTOM_CAN_FALL,
+    &custom_element_properties[EP_CAN_SMASH],
+    " ", NULL,                         "element can smash other elements"
+  },
+  {
+    ED_SETTINGS_XPOS(0),               ED_SETTINGS_YPOS(10),
+    GADGET_ID_CUSTOM_SLIPPERY,         GADGET_ID_NONE,
+    &custom_element_properties[EP_SLIPPERY],
+    NULL, NULL,                                "other elements can fall down from it"
+  },
+  {
+    ED_SETTINGS_XPOS(0),               ED_SETTINGS_YPOS(11),
+    GADGET_ID_CUSTOM_DEADLY,           GADGET_ID_NONE,
+    &custom_element_properties[EP_DEADLY],
+    NULL, NULL,                                "element can kill the player"
+  },
+  {
+    ED_SETTINGS_XPOS(0),               ED_SETTINGS_YPOS(12),
+    GADGET_ID_CUSTOM_EXPLODE_RESULT,   GADGET_ID_NONE,
+    &custom_element_properties[EP_EXPLODE_RESULT],
+    NULL, NULL,                                "set consistency/destructibility"
+  },
+  {
+    ED_SETTINGS_XPOS(1),               ED_SETTINGS_YPOS(13),
+    GADGET_ID_CUSTOM_EXPLODE_FIRE,     GADGET_ID_NONE,
+    &custom_element.can_explode_by_fire,
+    NULL, "by fire",                   "element can explode by fire/explosion"
+  },
+  {
+    ED_SETTINGS_XPOS(7),               ED_SETTINGS_YPOS(13),
+    GADGET_ID_CUSTOM_EXPLODE_SMASH,    GADGET_ID_CUSTOM_EXPLODE_FIRE,
+    &custom_element.can_explode_smashed,
+    " ", "smashed",                    "element can explode when smashed"
+  },
+  {
+    ED_SETTINGS_XPOS(13),              ED_SETTINGS_YPOS(13),
+    GADGET_ID_CUSTOM_EXPLODE_IMPACT,   GADGET_ID_CUSTOM_EXPLODE_SMASH,
+    &custom_element.can_explode_impact,
+    " ", "impact",                     "element can explode on impact"
+  },
+
+  /* ---------- element settings: advanced (custom elements) --------------- */
+
+  {
+    ED_SETTINGS_XPOS(0),               ED_SETTINGS_YPOS(1),
+    GADGET_ID_CUSTOM_USE_GRAPHIC,      GADGET_ID_NONE,
+    &custom_element.use_gfx_element,
+    NULL, "use graphic of element:",   "use graphic for custom element"
+  },
+  {
+    ED_SETTINGS_XPOS(0),               ED_SETTINGS_YPOS(2),
+    GADGET_ID_CUSTOM_CAN_CHANGE,       GADGET_ID_NONE,
+    &custom_element_properties[EP_CAN_CHANGE],
+    NULL, "element changes to:",       "element can change to other element"
+  },
+  {
+    ED_SETTINGS_XPOS(1),               ED_SETTINGS_YPOS(3),
+    GADGET_ID_CHANGE_DELAY,            GADGET_ID_NONE,
+    &custom_element_change_events[CE_DELAY],
+    NULL, NULL,                                "element changes after delay"
+  },
+  {
+    ED_SETTINGS_XPOS(1),               ED_SETTINGS_YPOS(5),
+    GADGET_ID_CHANGE_BY_PLAYER,                GADGET_ID_NONE,
+    &custom_element_change_events[CE_BY_PLAYER],
+    NULL, NULL,                                "element changes by player contact"
+  },
+  {
+    ED_SETTINGS_XPOS(1),               ED_SETTINGS_YPOS(6),
+    GADGET_ID_CHANGE_BY_COLLISION,     GADGET_ID_NONE,
+    &custom_element_change_events[CE_BY_COLLISION],
+    NULL, NULL,                                "element changes by impact or smash"
+  },
+  {
+    ED_SETTINGS_XPOS(1),               ED_SETTINGS_YPOS(7),
+    GADGET_ID_CHANGE_BY_OTHER,         GADGET_ID_NONE,
+    &custom_element_change_events[CE_BY_OTHER],
+    NULL, NULL,                                "element changes by other element"
+  },
+  {
+    ED_SETTINGS_XPOS(1),               ED_SETTINGS_YPOS(8),
+    GADGET_ID_CHANGE_USE_EXPLOSION,    GADGET_ID_NONE,
+    &custom_element.change.explode,
+    NULL, "explode instead of change", "element explodes instead of change"
+  },
+  {
+    ED_SETTINGS_XPOS(1),               ED_SETTINGS_YPOS(9),
+    GADGET_ID_CHANGE_USE_CONTENT,      GADGET_ID_NONE,
+    &custom_element.change.use_content,
+    NULL, "use extended change target:","element changes to more elements"
+  },
+  {
+    ED_SETTINGS_XPOS(2),               ED_SETTINGS_YPOS(11),
+    GADGET_ID_CHANGE_ONLY_COMPLETE,    GADGET_ID_NONE,
+    &custom_element.change.only_complete,
+    NULL, "only use complete change",  "only use complete extended content"
+  },
+  {
+    ED_SETTINGS_XPOS(2),               ED_SETTINGS_YPOS(12),
+    GADGET_ID_CHANGE_USE_RANDOM,       GADGET_ID_NONE,
+    &custom_element.change.use_random_change,
+    NULL, NULL,                                "use random value for new content"
+  },
+  {
+    ED_SETTINGS_XPOS(0),               ED_SETTINGS_YPOS(13),
+    GADGET_ID_CUSTOM_USE_TEMPLATE,     GADGET_ID_NONE,
+    &level.use_custom_template,
+    NULL, "use template",              "use template for custom properties"
+  },
+};
+
+static struct
+{
+  int x, y;
+  int area_xsize, area_ysize;
+  int gadget_id;
+  int gadget_id_align;
+  char *text_left, *text_right;
+} drawingarea_info[ED_NUM_DRAWING_AREAS] =
+{
+  /* ---------- level playfield content ------------------------------------ */
+
+  {
+    0, 0,
+    MAX_ED_FIELDX, MAX_ED_FIELDY,
+    GADGET_ID_DRAWING_LEVEL,           GADGET_ID_NONE,
+    NULL, NULL
+  },
+
+  /* ---------- yam yam content -------------------------------------------- */
+
+  {
+    ED_AREA_YAMYAM_CONTENT_XPOS(0),    ED_AREA_YAMYAM_CONTENT_YPOS(0),
+    3, 3,
+    GADGET_ID_ELEMENT_CONTENT_0,       GADGET_ID_NONE,
+    NULL, NULL
+  },
+  {
+    ED_AREA_YAMYAM_CONTENT_XPOS(1),    ED_AREA_YAMYAM_CONTENT_YPOS(1),
+    3, 3,
+    GADGET_ID_ELEMENT_CONTENT_1,       GADGET_ID_NONE,
+    NULL, NULL
+  },
+  {
+    ED_AREA_YAMYAM_CONTENT_XPOS(2),    ED_AREA_YAMYAM_CONTENT_YPOS(2),
+    3, 3,
+    GADGET_ID_ELEMENT_CONTENT_2,       GADGET_ID_NONE,
+    NULL, NULL
+  },
+  {
+    ED_AREA_YAMYAM_CONTENT_XPOS(3),    ED_AREA_YAMYAM_CONTENT_YPOS(3),
+    3, 3,
+    GADGET_ID_ELEMENT_CONTENT_3,       GADGET_ID_NONE,
+    NULL, NULL
+  },
+  {
+    ED_AREA_YAMYAM_CONTENT_XPOS(4),    ED_AREA_YAMYAM_CONTENT_YPOS(4),
+    3, 3,
+    GADGET_ID_ELEMENT_CONTENT_4,       GADGET_ID_NONE,
+    NULL, NULL
+  },
+  {
+    ED_AREA_YAMYAM_CONTENT_XPOS(5),    ED_AREA_YAMYAM_CONTENT_YPOS(5),
+    3, 3,
+    GADGET_ID_ELEMENT_CONTENT_5,       GADGET_ID_NONE,
+    NULL, NULL
+  },
+  {
+    ED_AREA_YAMYAM_CONTENT_XPOS(6),    ED_AREA_YAMYAM_CONTENT_YPOS(6),
+    3, 3,
+    GADGET_ID_ELEMENT_CONTENT_6,       GADGET_ID_NONE,
+    NULL, NULL
+  },
+  {
+    ED_AREA_YAMYAM_CONTENT_XPOS(7),    ED_AREA_YAMYAM_CONTENT_YPOS(7),
+    3, 3,
+    GADGET_ID_ELEMENT_CONTENT_7,       GADGET_ID_NONE,
+    NULL, NULL
+  },
+
+  /* ---------- amoeba content --------------------------------------------- */
+
+  {
+    ED_AREA_ELEM_CONTENT_XPOS,         ED_AREA_ELEM_CONTENT_YPOS,
+    1, 1,
+    GADGET_ID_AMOEBA_CONTENT,          GADGET_ID_NONE,
+    NULL, NULL
+  },
+
+  /* ---------- custom graphic --------------------------------------------- */
+
+  {
+    ED_AREA_ELEM_CONTENT3_XPOS,                ED_AREA_ELEM_CONTENT3_YPOS,
+    1, 1,
+    GADGET_ID_CUSTOM_GRAPHIC,          GADGET_ID_CUSTOM_USE_GRAPHIC,
+    NULL, NULL
+  },
+
+  /* ---------- custom content (when exploding) ---------------------------- */
+
+  {
+    ED_AREA_ELEM_CONTENT4_XPOS,                ED_AREA_ELEM_CONTENT4_YPOS,
+    3, 3,
+    GADGET_ID_CUSTOM_CONTENT,          GADGET_ID_NONE, /* align three rows */
+    NULL, NULL
+  },
+
+  /* ---------- custom change target --------------------------------------- */
+
+  {
+    ED_AREA_ELEM_CONTENT2_XPOS,                ED_AREA_ELEM_CONTENT2_YPOS,
+    1, 1,
+    GADGET_ID_CUSTOM_CHANGE_TARGET,    GADGET_ID_CUSTOM_CAN_CHANGE,
+    NULL, "after/when:"
+  },
+
+  /* ---------- custom change content (extended change target) ------------- */
+
+  {
+    ED_AREA_ELEM_CONTENT6_XPOS,                ED_AREA_ELEM_CONTENT6_YPOS,
+    3, 3,
+    GADGET_ID_CUSTOM_CHANGE_CONTENT,   GADGET_ID_NONE, /* align three rows */
+    NULL, NULL
+  },
+
+  /* ---------- custom change trigger (element causing change) ------------- */
+
+  {
+    ED_AREA_ELEM_CONTENT5_XPOS,                ED_AREA_ELEM_CONTENT5_YPOS,
+    1, 1,
+    GADGET_ID_CUSTOM_CHANGE_TRIGGER,   GADGET_ID_CHANGE_OTHER_ACTION,
+    NULL, NULL
+  },
+
+  /* ---------- random background (for random painting) -------------------- */
+
+  {
+    ED_AREA_RANDOM_BACKGROUND_XPOS,    ED_AREA_RANDOM_BACKGROUND_YPOS,
+    1, 1,
+    GADGET_ID_RANDOM_BACKGROUND,       GADGET_ID_RANDOM_RESTRICTED,
+    NULL, NULL
+  },
+};
+
+
+/*
+  -----------------------------------------------------------------------------
+  some internally used variables
+  -----------------------------------------------------------------------------
+*/
 
 /* actual size of level editor drawing area */
 static int ed_fieldx = MAX_ED_FIELDX - 1, ed_fieldy = MAX_ED_FIELDY - 1;
@@ -694,50 +1679,55 @@ static int level_xpos = -1, level_ypos = -1;
 #define IN_ED_FIELD(x,y)  ((x)>=0 && (x)<ed_fieldx && (y)>=0 &&(y)<ed_fieldy)
 
 /* drawing elements on the three mouse buttons */
-static int new_element1 = EL_MAUERWERK;
-static int new_element2 = EL_LEERRAUM;
-static int new_element3 = EL_ERDREICH;
+static int new_element1 = EL_WALL;
+static int new_element2 = EL_EMPTY;
+static int new_element3 = EL_SAND;
 
 #define BUTTON_ELEMENT(button) ((button) == 1 ? new_element1 : \
                                (button) == 2 ? new_element2 : \
-                               (button) == 3 ? new_element3 : EL_LEERRAUM)
+                               (button) == 3 ? new_element3 : EL_EMPTY)
 #define BUTTON_STEPSIZE(button) ((button) == 1 ? 1 : (button) == 2 ? 5 : 10)
 
 /* forward declaration for internal use */
 static void ModifyEditorCounter(int, int);
 static void ModifyEditorCounterLimits(int, int, int);
+static void ModifyEditorSelectbox(int, int);
+static void ModifyEditorElementList();
+static void RedrawDrawingElements();
 static void DrawDrawingWindow();
 static void DrawLevelInfoWindow();
 static void DrawPropertiesWindow();
+static boolean checkPropertiesConfig();
 static void CopyLevelToUndoBuffer(int);
 static void HandleDrawingAreas(struct GadgetInfo *);
 static void HandleCounterButtons(struct GadgetInfo *);
 static void HandleTextInputGadgets(struct GadgetInfo *);
+static void HandleSelectboxGadgets(struct GadgetInfo *);
+static void HandleTextbuttonGadgets(struct GadgetInfo *);
 static void HandleRadiobuttons(struct GadgetInfo *);
 static void HandleCheckbuttons(struct GadgetInfo *);
 static void HandleControlButtons(struct GadgetInfo *);
 static void HandleDrawingAreaInfo(struct GadgetInfo *);
 
 static struct GadgetInfo *level_editor_gadget[NUM_EDITOR_GADGETS];
+static int right_gadget_border[NUM_EDITOR_GADGETS];
 
 static int drawing_function = GADGET_ID_SINGLE_ITEMS;
 static int last_drawing_function = GADGET_ID_SINGLE_ITEMS;
 static boolean draw_with_brush = FALSE;
 static int properties_element = 0;
 
-static short ElementContent[MAX_ELEMENT_CONTENTS][3][3];
 static short FieldBackup[MAX_LEV_FIELDX][MAX_LEV_FIELDY];
 static short UndoBuffer[NUM_UNDO_STEPS][MAX_LEV_FIELDX][MAX_LEV_FIELDY];
 static int undo_buffer_position = 0;
 static int undo_buffer_steps = 0;
 
 static int edit_mode;
+static int edit_mode_properties;
 
-static int counter_xsize = DXSIZE + FONT2_XSIZE - 2 * ED_GADGET_DISTANCE;
-
-int element_shift = 0;
+static int element_shift = 0;
 
-int editor_element[] =
+static int editor_el_boulderdash[] =
 {
   EL_CHAR('B'),
   EL_CHAR('O'),
@@ -754,31 +1744,35 @@ int editor_element[] =
   EL_CHAR('S'),
   EL_CHAR('H'),
 
-  EL_SPIELFIGUR,
-  EL_LEERRAUM,
-  EL_ERDREICH,
-  EL_BETON,
+  EL_PLAYER_1,
+  EL_EMPTY,
+  EL_SAND,
+  EL_STEELWALL,
 
   EL_BD_WALL,
-  EL_MAGIC_WALL_BD_OFF,
-  EL_AUSGANG_ZU,
-  EL_AUSGANG_AUF,
+  EL_BD_MAGIC_WALL,
+  EL_EXIT_CLOSED,
+  EL_EXIT_OPEN,
 
-  EL_EDELSTEIN_BD,
-  EL_BUTTERFLY_UP,
-  EL_FIREFLY_UP,
+  EL_BD_DIAMOND,
+  EL_BD_BUTTERFLY_UP,
+  EL_BD_FIREFLY_UP,
   EL_BD_ROCK,
 
-  EL_BUTTERFLY_LEFT,
-  EL_FIREFLY_LEFT,
-  EL_BUTTERFLY_RIGHT,
-  EL_FIREFLY_RIGHT,
+  EL_BD_BUTTERFLY_LEFT,
+  EL_BD_FIREFLY_LEFT,
+  EL_BD_BUTTERFLY_RIGHT,
+  EL_BD_FIREFLY_RIGHT,
 
-  EL_AMOEBE_BD,
-  EL_BUTTERFLY_DOWN,
-  EL_FIREFLY_DOWN,
-  EL_LEERRAUM,
+  EL_BD_AMOEBA,
+  EL_BD_BUTTERFLY_DOWN,
+  EL_BD_FIREFLY_DOWN,
+  EL_EMPTY,
+};
+static int num_editor_el_boulderdash = SIZEOF_ARRAY_INT(editor_el_boulderdash);
 
+static int editor_el_emerald_mine[] =
+{
   EL_CHAR('E'),
   EL_CHAR('M'),
   EL_CHAR('E'),
@@ -794,65 +1788,65 @@ int editor_element[] =
   EL_CHAR('N'),
   EL_CHAR('E'),
 
-  EL_SPIELER1,
-  EL_SPIELER2,
-  EL_SPIELER3,
-  EL_SPIELER4,
+  EL_PLAYER_1,
+  EL_PLAYER_2,
+  EL_PLAYER_3,
+  EL_PLAYER_4,
 
-  EL_SPIELFIGUR,
-  EL_LEERRAUM,
-  EL_ERDREICH,
-  EL_FELSBROCKEN,
+  EL_PLAYER_1,
+  EL_EMPTY,
+  EL_SAND,
+  EL_ROCK,
 
-  EL_BETON,
-  EL_MAUERWERK,
-  EL_FELSBODEN,
-  EL_MAGIC_WALL_OFF,
+  EL_STEELWALL,
+  EL_WALL,
+  EL_WALL_SLIPPERY,
+  EL_MAGIC_WALL,
 
-  EL_EDELSTEIN,
-  EL_DIAMANT,
-  EL_KOKOSNUSS,
-  EL_BOMBE,
+  EL_EMERALD,
+  EL_DIAMOND,
+  EL_NUT,
+  EL_BOMB,
 
-  EL_ERZ_EDEL,
-  EL_ERZ_DIAM,
-  EL_MORAST_LEER,
-  EL_MORAST_VOLL,
+  EL_WALL_EMERALD,
+  EL_WALL_DIAMOND,
+  EL_QUICKSAND_EMPTY,
+  EL_QUICKSAND_FULL,
 
-  EL_DYNAMITE_INACTIVE,
+  EL_DYNAMITE,
   EL_DYNAMITE_ACTIVE,
-  EL_AUSGANG_ZU,
-  EL_AUSGANG_AUF,
+  EL_EXIT_CLOSED,
+  EL_EXIT_OPEN,
 
-  EL_MAMPFER,
-  EL_KAEFER_UP,
-  EL_FLIEGER_UP,
+  EL_YAMYAM,
+  EL_BUG_UP,
+  EL_SPACESHIP_UP,
   EL_ROBOT,
 
-  EL_KAEFER_LEFT,
-  EL_FLIEGER_LEFT,
-  EL_KAEFER_RIGHT,
-  EL_FLIEGER_RIGHT,
+  EL_BUG_LEFT,
+  EL_SPACESHIP_LEFT,
+  EL_BUG_RIGHT,
+  EL_SPACESHIP_RIGHT,
 
-  EL_ABLENK_AUS,
-  EL_KAEFER_DOWN,
-  EL_FLIEGER_DOWN,
-  EL_UNSICHTBAR,
+  EL_ROBOT_WHEEL,
+  EL_BUG_DOWN,
+  EL_SPACESHIP_DOWN,
+  EL_INVISIBLE_WALL,
 
-  EL_BADEWANNE1,
-  EL_SALZSAEURE,
-  EL_BADEWANNE2,
-  EL_LEERRAUM,
+  EL_ACID_POOL_TOPLEFT,
+  EL_ACID,
+  EL_ACID_POOL_TOPRIGHT,
+  EL_EMPTY,
 
-  EL_BADEWANNE3,
-  EL_BADEWANNE4,
-  EL_BADEWANNE5,
-  EL_LEERRAUM,
+  EL_ACID_POOL_BOTTOMLEFT,
+  EL_ACID_POOL_BOTTOM,
+  EL_ACID_POOL_BOTTOMRIGHT,
+  EL_EMPTY,
 
-  EL_TROPFEN,
-  EL_AMOEBE_TOT,
-  EL_AMOEBE_NASS,
-  EL_AMOEBE_NORM,
+  EL_AMOEBA_DROP,
+  EL_AMOEBA_DEAD,
+  EL_AMOEBA_WET,
+  EL_AMOEBA_DRY,
 
   EL_EM_KEY_1_FILE,
   EL_EM_KEY_2_FILE,
@@ -864,102 +1858,106 @@ int editor_element[] =
   EL_EM_GATE_3,
   EL_EM_GATE_4,
 
-  EL_EM_GATE_1X,
-  EL_EM_GATE_2X,
-  EL_EM_GATE_3X,
-  EL_EM_GATE_4X,
+  EL_EM_GATE_1_GRAY,
+  EL_EM_GATE_2_GRAY,
+  EL_EM_GATE_3_GRAY,
+  EL_EM_GATE_4_GRAY,
+};
+static int num_editor_el_emerald_mine = SIZEOF_ARRAY_INT(editor_el_emerald_mine);
 
+static int editor_el_more[] =
+{
   EL_CHAR('M'),
   EL_CHAR('O'),
   EL_CHAR('R'),
   EL_CHAR('E'),
 
-  EL_SCHLUESSEL1,
-  EL_SCHLUESSEL2,
-  EL_SCHLUESSEL3,
-  EL_SCHLUESSEL4,
-
-  EL_PFORTE1,
-  EL_PFORTE2,
-  EL_PFORTE3,
-  EL_PFORTE4,
-
-  EL_PFORTE1X,
-  EL_PFORTE2X,
-  EL_PFORTE3X,
-  EL_PFORTE4X,
-
-  EL_PFEIL_LEFT,
-  EL_PFEIL_RIGHT,
-  EL_PFEIL_UP,
-  EL_PFEIL_DOWN,
-
-  EL_AMOEBE_VOLL,
-  EL_EDELSTEIN_GELB,
-  EL_EDELSTEIN_ROT,
-  EL_EDELSTEIN_LILA,
-
-  EL_ERZ_EDEL_BD,
-  EL_ERZ_EDEL_GELB,
-  EL_ERZ_EDEL_ROT,
-  EL_ERZ_EDEL_LILA,
-
-  EL_LIFE,
+  EL_KEY_1,
+  EL_KEY_2,
+  EL_KEY_3,
+  EL_KEY_4,
+
+  EL_GATE_1,
+  EL_GATE_2,
+  EL_GATE_3,
+  EL_GATE_4,
+
+  EL_GATE_1_GRAY,
+  EL_GATE_2_GRAY,
+  EL_GATE_3_GRAY,
+  EL_GATE_4_GRAY,
+
+  EL_ARROW_LEFT,
+  EL_ARROW_RIGHT,
+  EL_ARROW_UP,
+  EL_ARROW_DOWN,
+
+  EL_AMOEBA_FULL,
+  EL_EMERALD_YELLOW,
+  EL_EMERALD_RED,
+  EL_EMERALD_PURPLE,
+
+  EL_WALL_BD_DIAMOND,
+  EL_WALL_EMERALD_YELLOW,
+  EL_WALL_EMERALD_RED,
+  EL_WALL_EMERALD_PURPLE,
+
+  EL_GAME_OF_LIFE,
   EL_PACMAN_UP,
-  EL_ZEIT_VOLL,
-  EL_ZEIT_LEER,
+  EL_TIME_ORB_FULL,
+  EL_TIME_ORB_EMPTY,
 
   EL_PACMAN_LEFT,
-  EL_MAMPFER2,
+  EL_DARK_YAMYAM,
   EL_PACMAN_RIGHT,
-  EL_MAUER_LEBT,
+  EL_EXPANDABLE_WALL,
 
-  EL_LIFE_ASYNC,
+  EL_BIOMAZE,
   EL_PACMAN_DOWN,
-  EL_BIRNE_AUS,
-  EL_BIRNE_EIN,
+  EL_LAMP,
+  EL_LAMP_ACTIVE,
 
-  EL_DYNABOMB_NR,
-  EL_DYNABOMB_SZ,
-  EL_DYNABOMB_XL,
-  EL_BADEWANNE,
+  EL_DYNABOMB_INCREASE_NUMBER,
+  EL_DYNABOMB_INCREASE_SIZE,
+  EL_DYNABOMB_INCREASE_POWER,
+  EL_STONEBLOCK,
 
   EL_MOLE,
-  EL_PINGUIN,
-  EL_SCHWEIN,
-  EL_DRACHE,
+  EL_PENGUIN,
+  EL_PIG,
+  EL_DRAGON,
 
-  EL_LEERRAUM,
+  EL_EMPTY,
   EL_MOLE_UP,
-  EL_LEERRAUM,
-  EL_LEERRAUM,
+  EL_EMPTY,
+  EL_EMPTY,
 
   EL_MOLE_LEFT,
-  EL_LEERRAUM,
+  EL_EMPTY,
   EL_MOLE_RIGHT,
-  EL_LEERRAUM,
+  EL_EMPTY,
 
-  EL_LEERRAUM,
+  EL_EMPTY,
   EL_MOLE_DOWN,
   EL_BALLOON,
-  EL_BALLOON_SEND_ANY,
+  EL_BALLOON_SWITCH_ANY,
 
-  EL_BALLOON_SEND_LEFT,
-  EL_BALLOON_SEND_RIGHT,
-  EL_BALLOON_SEND_UP,
-  EL_BALLOON_SEND_DOWN,
+  EL_BALLOON_SWITCH_LEFT,
+  EL_BALLOON_SWITCH_RIGHT,
+  EL_BALLOON_SWITCH_UP,
+  EL_BALLOON_SWITCH_DOWN,
 
-  EL_SONDE,
-  EL_MAUER_X,
-  EL_MAUER_Y,
-  EL_MAUER_XY,
+  EL_SATELLITE,
+  EL_EXPANDABLE_WALL_HORIZONTAL,
+  EL_EXPANDABLE_WALL_VERTICAL,
+  EL_EXPANDABLE_WALL_ANY,
 
-  EL_INVISIBLE_STEEL,
-  EL_UNSICHTBAR,
+  EL_INVISIBLE_STEELWALL,
+  EL_INVISIBLE_WALL,
   EL_SPEED_PILL,
   EL_BLACK_ORB,
 
-  EL_EMC_STEEL_WALL_1,
+  EL_EMC_STEELWALL_1,
   EL_EMC_WALL_1,
   EL_EMC_WALL_2,
   EL_EMC_WALL_3,
@@ -968,8 +1966,11 @@ int editor_element[] =
   EL_EMC_WALL_5,
   EL_EMC_WALL_6,
   EL_EMC_WALL_7,
+};
+static int num_editor_el_more = SIZEOF_ARRAY_INT(editor_el_more);
 
-
+static int editor_el_sokoban[] =
+{
   EL_CHAR('S'),
   EL_CHAR('O'),
   EL_CHAR('K'),
@@ -980,11 +1981,15 @@ int editor_element[] =
   EL_CHAR('A'),
   EL_CHAR('N'),
 
-  EL_SOKOBAN_OBJEKT,
-  EL_SOKOBAN_FELD_LEER,
-  EL_SOKOBAN_FELD_VOLL,
-  EL_BETON,
+  EL_SOKOBAN_OBJECT,
+  EL_SOKOBAN_FIELD_EMPTY,
+  EL_SOKOBAN_FIELD_FULL,
+  EL_STEELWALL,
+};
+static int num_editor_el_sokoban = SIZEOF_ARRAY_INT(editor_el_sokoban);
 
+static int editor_el_supaplex[] =
+{
   EL_CHAR('S'),
   EL_CHAR('U'),
   EL_CHAR('P'),
@@ -1002,49 +2007,53 @@ int editor_element[] =
 
   EL_SP_INFOTRON,
   EL_SP_CHIP_SINGLE,
-  EL_SP_HARD_GRAY,
-  EL_SP_EXIT,
+  EL_SP_HARDWARE_GRAY,
+  EL_SP_EXIT_CLOSED,
 
   EL_SP_DISK_ORANGE,
-  EL_SP_PORT1_RIGHT,
-  EL_SP_PORT1_DOWN,
-  EL_SP_PORT1_LEFT,
+  EL_SP_PORT_RIGHT,
+  EL_SP_PORT_DOWN,
+  EL_SP_PORT_LEFT,
 
-  EL_SP_PORT1_UP,
-  EL_SP_PORT2_RIGHT,
-  EL_SP_PORT2_DOWN,
-  EL_SP_PORT2_LEFT,
+  EL_SP_PORT_UP,
+  EL_SP_GRAVITY_PORT_RIGHT,
+  EL_SP_GRAVITY_PORT_DOWN,
+  EL_SP_GRAVITY_PORT_LEFT,
 
-  EL_SP_PORT2_UP,
+  EL_SP_GRAVITY_PORT_UP,
   EL_SP_SNIKSNAK,
   EL_SP_DISK_YELLOW,
   EL_SP_TERMINAL,
 
   EL_SP_DISK_RED,
-  EL_SP_PORT_Y,
-  EL_SP_PORT_X,
-  EL_SP_PORT_XY,
+  EL_SP_PORT_VERTICAL,
+  EL_SP_PORT_HORIZONTAL,
+  EL_SP_PORT_ANY,
 
   EL_SP_ELECTRON,
-  EL_SP_BUG,
+  EL_SP_BUGGY_BASE,
   EL_SP_CHIP_LEFT,
   EL_SP_CHIP_RIGHT,
 
-  EL_SP_HARD_BASE1,
-  EL_SP_HARD_GREEN,
-  EL_SP_HARD_BLUE,
-  EL_SP_HARD_RED,
+  EL_SP_HARDWARE_BASE_1,
+  EL_SP_HARDWARE_GREEN,
+  EL_SP_HARDWARE_BLUE,
+  EL_SP_HARDWARE_RED,
 
-  EL_SP_HARD_YELLOW,
-  EL_SP_HARD_BASE2,
-  EL_SP_HARD_BASE3,
-  EL_SP_HARD_BASE4,
+  EL_SP_HARDWARE_YELLOW,
+  EL_SP_HARDWARE_BASE_2,
+  EL_SP_HARDWARE_BASE_3,
+  EL_SP_HARDWARE_BASE_4,
 
-  EL_SP_HARD_BASE5,
-  EL_SP_HARD_BASE6,
-  EL_SP_CHIP_UPPER,
-  EL_SP_CHIP_LOWER,
+  EL_SP_HARDWARE_BASE_5,
+  EL_SP_HARDWARE_BASE_6,
+  EL_SP_CHIP_TOP,
+  EL_SP_CHIP_BOTTOM,
+};
+static int num_editor_el_supaplex = SIZEOF_ARRAY_INT(editor_el_supaplex);
 
+static int editor_el_diamond_caves[] =
+{
   EL_CHAR('D'),
   EL_CHAR('I'),
   EL_CHAR('A'),
@@ -1070,61 +2079,65 @@ int editor_element[] =
   EL_WALL_PEARL,
   EL_WALL_CRYSTAL,
 
-  EL_BELT1_LEFT,
-  EL_BELT1_MIDDLE,
-  EL_BELT1_RIGHT,
-  EL_BELT1_SWITCH_MIDDLE,
+  EL_CONVEYOR_BELT_1_LEFT,
+  EL_CONVEYOR_BELT_1_MIDDLE,
+  EL_CONVEYOR_BELT_1_RIGHT,
+  EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
 
-  EL_BELT2_LEFT,
-  EL_BELT2_MIDDLE,
-  EL_BELT2_RIGHT,
-  EL_BELT2_SWITCH_MIDDLE,
+  EL_CONVEYOR_BELT_2_LEFT,
+  EL_CONVEYOR_BELT_2_MIDDLE,
+  EL_CONVEYOR_BELT_2_RIGHT,
+  EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
 
-  EL_BELT3_LEFT,
-  EL_BELT3_MIDDLE,
-  EL_BELT3_RIGHT,
-  EL_BELT3_SWITCH_MIDDLE,
+  EL_CONVEYOR_BELT_3_LEFT,
+  EL_CONVEYOR_BELT_3_MIDDLE,
+  EL_CONVEYOR_BELT_3_RIGHT,
+  EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
 
-  EL_BELT4_LEFT,
-  EL_BELT4_MIDDLE,
-  EL_BELT4_RIGHT,
-  EL_BELT4_SWITCH_MIDDLE,
+  EL_CONVEYOR_BELT_4_LEFT,
+  EL_CONVEYOR_BELT_4_MIDDLE,
+  EL_CONVEYOR_BELT_4_RIGHT,
+  EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
 
-  EL_BELT1_SWITCH_LEFT,
-  EL_BELT2_SWITCH_LEFT,
-  EL_BELT3_SWITCH_LEFT,
-  EL_BELT4_SWITCH_LEFT,
+  EL_CONVEYOR_BELT_1_SWITCH_LEFT,
+  EL_CONVEYOR_BELT_2_SWITCH_LEFT,
+  EL_CONVEYOR_BELT_3_SWITCH_LEFT,
+  EL_CONVEYOR_BELT_4_SWITCH_LEFT,
 
-  EL_BELT1_SWITCH_RIGHT,
-  EL_BELT2_SWITCH_RIGHT,
-  EL_BELT3_SWITCH_RIGHT,
-  EL_BELT4_SWITCH_RIGHT,
+  EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
+  EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
+  EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
+  EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
 
   EL_SWITCHGATE_OPEN,
   EL_SWITCHGATE_CLOSED,
-  EL_SWITCHGATE_SWITCH_1,
+  EL_SWITCHGATE_SWITCH_UP,
   EL_ENVELOPE,
 
   EL_TIMEGATE_CLOSED,
   EL_TIMEGATE_OPEN,
-  EL_TIMEGATE_SWITCH_OFF,
-  EL_LEERRAUM,
+  EL_TIMEGATE_SWITCH,
+  EL_EMPTY,
 
   EL_LANDMINE,
-  EL_SAND_INVISIBLE,
-  EL_STEEL_SLANTED,
-  EL_LEERRAUM,
+  EL_INVISIBLE_SAND,
+  EL_STEELWALL_SLIPPERY,
+  EL_EMPTY,
 
   EL_SIGN_EXCLAMATION,
   EL_SIGN_STOP,
-  EL_LIGHT_SWITCH_OFF,
-  EL_LIGHT_SWITCH_ON,
+  EL_LIGHT_SWITCH,
+  EL_LIGHT_SWITCH_ACTIVE,
 
-  EL_SHIELD_PASSIVE,
-  EL_SHIELD_ACTIVE,
+  EL_SHIELD_NORMAL,
+  EL_SHIELD_DEADLY,
   EL_EXTRA_TIME,
-  EL_LEERRAUM,
+  EL_EMPTY,
+};
+static int num_editor_el_diamond_caves = SIZEOF_ARRAY_INT(editor_el_diamond_caves);
 
+static int editor_el_dx_boulderdash[] =
+{
   EL_CHAR('D'),
   EL_CHAR('X'),
   EL_CHAR('-'),
@@ -1147,45 +2160,32 @@ int editor_element[] =
 
   EL_SPRING,
   EL_TUBE_RIGHT_DOWN,
-  EL_TUBE_HORIZ_DOWN,
+  EL_TUBE_HORIZONTAL_DOWN,
   EL_TUBE_LEFT_DOWN,
 
   EL_TUBE_HORIZONTAL,
-  EL_TUBE_VERT_RIGHT,
-  EL_TUBE_CROSS,
-  EL_TUBE_VERT_LEFT,
+  EL_TUBE_VERTICAL_RIGHT,
+  EL_TUBE_ANY,
+  EL_TUBE_VERTICAL_LEFT,
 
   EL_TUBE_VERTICAL,
   EL_TUBE_RIGHT_UP,
-  EL_TUBE_HORIZ_UP,
+  EL_TUBE_HORIZONTAL_UP,
   EL_TUBE_LEFT_UP,
 
-  EL_TRAP_INACTIVE,
+  EL_TRAP,
   EL_DX_SUPABOMB,
-  EL_LEERRAUM,
-  EL_LEERRAUM,
-
-  /*
-  EL_CHAR('D'),
-  EL_CHAR('Y'),
-  EL_CHAR('N'),
-  EL_CHAR('A'),
-
-  EL_CHAR('B'),
-  EL_CHAR('L'),
-  EL_CHAR('A'),
-  EL_CHAR('S'),
+  EL_EMPTY,
+  EL_EMPTY
+};
+static int num_editor_el_dx_boulderdash = SIZEOF_ARRAY_INT(editor_el_dx_boulderdash);
 
-  EL_CHAR_MINUS,
+static int editor_el_chars[] =
+{
   EL_CHAR('T'),
   EL_CHAR('E'),
-  EL_CHAR('R'),
-  */
-
-  EL_LEERRAUM,
-  EL_LEERRAUM,
-  EL_LEERRAUM,
-  EL_LEERRAUM,
+  EL_CHAR('X'),
+  EL_CHAR('T'),
 
   EL_CHAR(' '),
   EL_CHAR('!'),
@@ -1260,23 +2260,347 @@ int editor_element[] =
   EL_CHAR('X'),
   EL_CHAR('Y'),
   EL_CHAR('Z'),
-  EL_CHAR('Ä'),
+  EL_CHAR('['),
+
+  EL_CHAR('\\'),
+  EL_CHAR(']'),
+  EL_CHAR('^'),
+  EL_CHAR('_'),
 
+  EL_CHAR('©'),
+  EL_CHAR('Ä'),
   EL_CHAR('Ö'),
   EL_CHAR('Ãœ'),
-  EL_CHAR('^'),
+
+  EL_CHAR('°'),
+  EL_CHAR('®'),
+  EL_CHAR(FONT_ASCII_CURSOR),
   EL_CHAR(' ')
 };
-int elements_in_list = sizeof(editor_element)/sizeof(int);
+static int num_editor_el_chars = SIZEOF_ARRAY_INT(editor_el_chars);
+
+static int editor_el_custom[] =
+{
+  EL_CHAR('C'),
+  EL_CHAR('U'),
+  EL_CHAR('S'),
+  EL_CHAR('-'),
+
+  EL_CHAR('T'),
+  EL_CHAR('O'),
+  EL_CHAR('M'),
+  EL_CHAR(' '),
+
+  EL_CHAR('E'),
+  EL_CHAR('L'),
+  EL_CHAR('E'),
+  EL_CHAR('M'),
+
+  EL_CHAR('E'),
+  EL_CHAR('N'),
+  EL_CHAR('T'),
+  EL_CHAR('S'),
+
+  EL_CUSTOM_START + 0,
+  EL_CUSTOM_START + 1,
+  EL_CUSTOM_START + 2,
+  EL_CUSTOM_START + 3,
+
+  EL_CUSTOM_START + 4,
+  EL_CUSTOM_START + 5,
+  EL_CUSTOM_START + 6,
+  EL_CUSTOM_START + 7,
+
+  EL_CUSTOM_START + 8,
+  EL_CUSTOM_START + 9,
+  EL_CUSTOM_START + 10,
+  EL_CUSTOM_START + 11,
+
+  EL_CUSTOM_START + 12,
+  EL_CUSTOM_START + 13,
+  EL_CUSTOM_START + 14,
+  EL_CUSTOM_START + 15,
+
+  EL_CUSTOM_START + 16,
+  EL_CUSTOM_START + 17,
+  EL_CUSTOM_START + 18,
+  EL_CUSTOM_START + 19,
+
+  EL_CUSTOM_START + 20,
+  EL_CUSTOM_START + 21,
+  EL_CUSTOM_START + 22,
+  EL_CUSTOM_START + 23,
+
+  EL_CUSTOM_START + 24,
+  EL_CUSTOM_START + 25,
+  EL_CUSTOM_START + 26,
+  EL_CUSTOM_START + 27,
+
+  EL_CUSTOM_START + 28,
+  EL_CUSTOM_START + 29,
+  EL_CUSTOM_START + 30,
+  EL_CUSTOM_START + 31,
+
+  EL_CUSTOM_START + 32,
+  EL_CUSTOM_START + 33,
+  EL_CUSTOM_START + 34,
+  EL_CUSTOM_START + 35,
+
+  EL_CUSTOM_START + 36,
+  EL_CUSTOM_START + 37,
+  EL_CUSTOM_START + 38,
+  EL_CUSTOM_START + 39,
+
+  EL_CUSTOM_START + 40,
+  EL_CUSTOM_START + 41,
+  EL_CUSTOM_START + 42,
+  EL_CUSTOM_START + 43,
+
+  EL_CUSTOM_START + 44,
+  EL_CUSTOM_START + 45,
+  EL_CUSTOM_START + 46,
+  EL_CUSTOM_START + 47,
+
+  EL_CUSTOM_START + 48,
+  EL_CUSTOM_START + 49,
+  EL_CUSTOM_START + 50,
+  EL_CUSTOM_START + 51,
+
+  EL_CUSTOM_START + 52,
+  EL_CUSTOM_START + 53,
+  EL_CUSTOM_START + 54,
+  EL_CUSTOM_START + 55,
+
+  EL_CUSTOM_START + 56,
+  EL_CUSTOM_START + 57,
+  EL_CUSTOM_START + 58,
+  EL_CUSTOM_START + 59,
+
+  EL_CUSTOM_START + 60,
+  EL_CUSTOM_START + 61,
+  EL_CUSTOM_START + 62,
+  EL_CUSTOM_START + 63,
+
+  EL_CUSTOM_START + 64,
+  EL_CUSTOM_START + 65,
+  EL_CUSTOM_START + 66,
+  EL_CUSTOM_START + 67,
+
+  EL_CUSTOM_START + 68,
+  EL_CUSTOM_START + 69,
+  EL_CUSTOM_START + 70,
+  EL_CUSTOM_START + 71,
+
+  EL_CUSTOM_START + 72,
+  EL_CUSTOM_START + 73,
+  EL_CUSTOM_START + 74,
+  EL_CUSTOM_START + 75,
+
+  EL_CUSTOM_START + 76,
+  EL_CUSTOM_START + 77,
+  EL_CUSTOM_START + 78,
+  EL_CUSTOM_START + 79,
+
+  EL_CUSTOM_START + 80,
+  EL_CUSTOM_START + 81,
+  EL_CUSTOM_START + 82,
+  EL_CUSTOM_START + 83,
+
+  EL_CUSTOM_START + 84,
+  EL_CUSTOM_START + 85,
+  EL_CUSTOM_START + 86,
+  EL_CUSTOM_START + 87,
+
+  EL_CUSTOM_START + 88,
+  EL_CUSTOM_START + 89,
+  EL_CUSTOM_START + 90,
+  EL_CUSTOM_START + 91,
+
+  EL_CUSTOM_START + 92,
+  EL_CUSTOM_START + 93,
+  EL_CUSTOM_START + 94,
+  EL_CUSTOM_START + 95,
+
+  EL_CUSTOM_START + 96,
+  EL_CUSTOM_START + 97,
+  EL_CUSTOM_START + 98,
+  EL_CUSTOM_START + 99,
+
+  EL_CUSTOM_START + 100,
+  EL_CUSTOM_START + 101,
+  EL_CUSTOM_START + 102,
+  EL_CUSTOM_START + 103,
+
+  EL_CUSTOM_START + 104,
+  EL_CUSTOM_START + 105,
+  EL_CUSTOM_START + 106,
+  EL_CUSTOM_START + 107,
+
+  EL_CUSTOM_START + 108,
+  EL_CUSTOM_START + 109,
+  EL_CUSTOM_START + 110,
+  EL_CUSTOM_START + 111,
+
+  EL_CUSTOM_START + 112,
+  EL_CUSTOM_START + 113,
+  EL_CUSTOM_START + 114,
+  EL_CUSTOM_START + 115,
+
+  EL_CUSTOM_START + 116,
+  EL_CUSTOM_START + 117,
+  EL_CUSTOM_START + 118,
+  EL_CUSTOM_START + 119,
+
+  EL_CUSTOM_START + 120,
+  EL_CUSTOM_START + 121,
+  EL_CUSTOM_START + 122,
+  EL_CUSTOM_START + 123,
+
+  EL_CUSTOM_START + 124,
+  EL_CUSTOM_START + 125,
+  EL_CUSTOM_START + 126,
+  EL_CUSTOM_START + 127
+};
+static int num_editor_el_custom = SIZEOF_ARRAY_INT(editor_el_custom);
+
+static int *editor_elements = NULL;    /* dynamically allocated */
+static int num_editor_elements = 0;    /* dynamically determined */
+
+static struct
+{
+  boolean *setup_value;
+  int *element_list;
+  int *element_list_size;
+
+  boolean last_setup_value;
+}
+editor_elements_info[] =
+{
+  { &setup.editor.el_boulderdash,      editor_el_boulderdash,
+    &num_editor_el_boulderdash                                         },
+  { &setup.editor.el_emerald_mine,     editor_el_emerald_mine,
+    &num_editor_el_emerald_mine                                                },
+  { &setup.editor.el_more,             editor_el_more,
+    &num_editor_el_more                                                        },
+  { &setup.editor.el_sokoban,          editor_el_sokoban,
+    &num_editor_el_sokoban                                             },
+  { &setup.editor.el_supaplex,         editor_el_supaplex,
+    &num_editor_el_supaplex                                            },
+  { &setup.editor.el_diamond_caves,    editor_el_diamond_caves,
+    &num_editor_el_diamond_caves                                       },
+  { &setup.editor.el_dx_boulderdash,   editor_el_dx_boulderdash,
+    &num_editor_el_dx_boulderdash                                      },
+  { &setup.editor.el_chars,            editor_el_chars,
+    &num_editor_el_chars                                               },
+  { &setup.editor.el_custom,           editor_el_custom,
+    &num_editor_el_custom                                              },
+  { NULL,                              NULL,
+    NULL                                                               }
+};
+
+
+/*
+  -----------------------------------------------------------------------------
+  functions
+  -----------------------------------------------------------------------------
+*/
+
+static void ReinitializeElementList()
+{
+  int pos = 0;
+  int i, j;
+
+  if (editor_elements != NULL)
+    free(editor_elements);
+
+  num_editor_elements = 0;
+
+  /* determine size of element list */
+  for (i=0; editor_elements_info[i].setup_value != NULL; i++)
+    if (*editor_elements_info[i].setup_value)
+      num_editor_elements += *editor_elements_info[i].element_list_size;
+
+  if (num_editor_elements < ED_NUM_ELEMENTLIST_BUTTONS)
+  {
+    /* workaround: offer at least as many elements as element buttons exist */
+    int list_nr = 1;   /* see above: editor_elements_info for Emerald Mine */
+
+    *editor_elements_info[list_nr].setup_value = TRUE;
+    num_editor_elements += *editor_elements_info[list_nr].element_list_size;
+  }
+
+  editor_elements = checked_malloc(num_editor_elements * sizeof(int));
+
+  /* fill element list */
+  for (i=0; editor_elements_info[i].setup_value != NULL; i++)
+    if (*editor_elements_info[i].setup_value)
+      for (j=0; j<*editor_elements_info[i].element_list_size; j++)
+       editor_elements[pos++] = editor_elements_info[i].element_list[j];
+}
+
+static void ReinitializeElementListButtons()
+{
+  static boolean initialization_needed = TRUE;
+  int i;
+
+  if (!initialization_needed)  /* check if editor element setup has changed */
+    for (i=0; editor_elements_info[i].setup_value != NULL; i++)
+      if (editor_elements_info[i].last_setup_value !=
+         *editor_elements_info[i].setup_value)
+       initialization_needed = TRUE;
+
+  if (!initialization_needed)
+    return;
+
+  FreeLevelEditorGadgets();
+  CreateLevelEditorGadgets();
+
+  /* store current setup values for next invocation of this function */
+  for (i=0; editor_elements_info[i].setup_value != NULL; i++)
+    editor_elements_info[i].last_setup_value =
+      *editor_elements_info[i].setup_value;
+
+  initialization_needed = FALSE;
+}
+
+static int getMaxInfoTextLength()
+{
+  return (SXSIZE / getFontWidth(FONT_TEXT_2));
+}
+
+static int getFullTextWidth(char *text)
+{
+  if (text == NULL)
+    return 0;
+
+  return (strlen(text) * getFontWidth(FONT_TEXT_1) + ED_GADGET_TEXT_DISTANCE);
+}
+
+static int getRightGadgetBorder(struct GadgetInfo *gi, char *text)
+{
+  return (gi->x + gi->width + getFullTextWidth(text));
+}
 
 static char *getElementInfoText(int element)
 {
-  char *info_text = "unknown";
+  char *info_text = NULL;
+
+  if (element < NUM_FILE_ELEMENTS)
+  {
+    if (strlen(element_info[element].description) > 0)
+      info_text = element_info[element].description;
+    else if (element_info[element].custom_description != NULL)
+      info_text = element_info[element].custom_description;
+    else if (element_info[element].editor_description != NULL)
+      info_text = element_info[element].editor_description;
+  }
+
+  if (info_text == NULL)
+  {
+    info_text = "unknown";
 
-  if (element < NUM_LEVEL_ELEMENTS)
-    info_text = element_info[element].editor_description;
-  else
     Error(ERR_WARN, "no element description for element %d", element);
+  }
 
   return info_text;
 }
@@ -1313,7 +2637,7 @@ static void ScrollMiniLevel(int from_x, int from_y, int scroll)
 
 static void CreateControlButtons()
 {
-  Bitmap *gd_bitmap = pix[PIX_DOOR];
+  Bitmap *gd_bitmap = graphic_info[IMG_GLOBAL_DOOR].bitmap;
   struct GadgetInfo *gi;
   unsigned long event_mask;
   int i;
@@ -1431,8 +2755,8 @@ static void CreateControlButtons()
       y += DY;
       width = ED_SCROLLBUTTON2_XSIZE;
       height = ED_SCROLLBUTTON2_YSIZE;
-      gd_x1 = DOOR_GFX_PAGEX8 + scrollbutton_info[i].xpos;
-      gd_y1 = DOOR_GFX_PAGEY1 + scrollbutton_info[i].ypos;
+      gd_x1 = DOOR_GFX_PAGEX8 + scrollbutton_info[i].gd_x;
+      gd_y1 = DOOR_GFX_PAGEY1 + scrollbutton_info[i].gd_y;
       gd_x2 = gd_x1 - ED_SCROLLBUTTON2_XSIZE;
       gd_y2 = gd_y1;
     }
@@ -1442,8 +2766,8 @@ static void CreateControlButtons()
       y += SY;
       width = ED_SCROLLBUTTON_XSIZE;
       height = ED_SCROLLBUTTON_YSIZE;
-      gd_x1 = DOOR_GFX_PAGEX8 + scrollbutton_info[i].xpos;
-      gd_y1 = DOOR_GFX_PAGEY1 + scrollbutton_info[i].ypos;
+      gd_x1 = DOOR_GFX_PAGEX8 + scrollbutton_info[i].gd_x;
+      gd_y1 = DOOR_GFX_PAGEY1 + scrollbutton_info[i].gd_y;
       gd_x2 = gd_x1 - ED_SCROLLBUTTON_XSIZE;
       gd_y2 = gd_y1;
     }
@@ -1480,6 +2804,7 @@ static void CreateControlButtons()
     int x = i % ED_ELEMENTLIST_BUTTONS_HORIZ;
     int y = i / ED_ELEMENTLIST_BUTTONS_HORIZ;
     int id = GADGET_ID_ELEMENTLIST_FIRST + i;
+    int element = editor_elements[i];
 
     event_mask = GD_EVENT_RELEASED;
 
@@ -1490,14 +2815,13 @@ static void CreateControlButtons()
     gd_x2 = DOOR_GFX_PAGEX6 + ED_ELEMENTLIST_XPOS;
     gd_y  = DOOR_GFX_PAGEY1 + ED_ELEMENTLIST_YPOS;
 
-    getMiniGraphicSource(el2gfx(editor_element[i]),
-                        &deco_bitmap, &deco_x, &deco_y);
+    getMiniGraphicSource(el2edimg(element), &deco_bitmap, &deco_x, &deco_y);
     deco_xpos = (ED_ELEMENTLIST_XSIZE - MINI_TILEX) / 2;
     deco_ypos = (ED_ELEMENTLIST_YSIZE - MINI_TILEY) / 2;
 
     gi = CreateGadget(GDI_CUSTOM_ID, id,
                      GDI_CUSTOM_TYPE_ID, i,
-                     GDI_INFO_TEXT, getElementInfoText(editor_element[i]),
+                     GDI_INFO_TEXT, getElementInfoText(element),
                      GDI_X, DX + gd_xoffset,
                      GDI_Y, DY + gd_yoffset,
                      GDI_WIDTH, ED_ELEMENTLIST_XSIZE,
@@ -1524,17 +2848,28 @@ static void CreateControlButtons()
 
 static void CreateCounterButtons()
 {
+  int max_infotext_len = getMaxInfoTextLength();
   int i;
 
   for (i=0; i<ED_NUM_COUNTERBUTTONS; i++)
   {
     int j;
-    int xpos = SX + counterbutton_info[i].x;   /* xpos of down count button */
-    int ypos = SY + counterbutton_info[i].y;
+    int x = SX + counterbutton_info[i].x;      /* down count button */
+    int y = SY + counterbutton_info[i].y;
+
+    /* determine horizontal position to the right of specified gadget */
+    if (counterbutton_info[i].gadget_id_align != GADGET_ID_NONE)
+      x = (right_gadget_border[counterbutton_info[i].gadget_id_align] +
+          ED_GADGET_TEXT_DISTANCE);
+
+    /* determine horizontal offset for leading text */
+    if (counterbutton_info[i].text_left != NULL)
+      x += (getFontWidth(FONT_TEXT_1) * strlen(counterbutton_info[i].text_left)
+           + ED_GADGET_TEXT_DISTANCE);
 
     for (j=0; j<2; j++)
     {
-      Bitmap *gd_bitmap = pix[PIX_DOOR];
+      Bitmap *gd_bitmap = graphic_info[IMG_GLOBAL_DOOR].bitmap;
       struct GadgetInfo *gi;
       int id = (j == 0 ?
                counterbutton_info[i].gadget_id_down :
@@ -1543,7 +2878,7 @@ static void CreateCounterButtons()
       int gd_x, gd_x1, gd_x2, gd_y;
       int x_size, y_size;
       unsigned long event_mask;
-      char infotext[MAX_INFOTEXT_LEN + 1];
+      char infotext[max_infotext_len + 1];
 
       event_mask = GD_EVENT_PRESSED | GD_EVENT_REPEATED;
 
@@ -1556,12 +2891,12 @@ static void CreateCounterButtons()
        event_mask |= GD_EVENT_RELEASED;
 
        if (j == 1)
-         xpos += 2 * ED_GADGET_DISTANCE;
-       ypos += ED_GADGET_DISTANCE;
+         x += 2 * ED_GADGET_DISTANCE;
+       y += ED_GADGET_DISTANCE;
 
-       gd_x1 = DOOR_GFX_PAGEX8 + scrollbutton_info[sid].xpos;
+       gd_x1 = DOOR_GFX_PAGEX8 + scrollbutton_info[sid].gd_x;
        gd_x2 = gd_x1 - ED_SCROLLBUTTON_XSIZE;
-       gd_y  = DOOR_GFX_PAGEY1 + scrollbutton_info[sid].ypos;
+       gd_y  = DOOR_GFX_PAGEY1 + scrollbutton_info[sid].gd_y;
        x_size = ED_SCROLLBUTTON_XSIZE;
        y_size = ED_SCROLLBUTTON_YSIZE;
       }
@@ -1581,8 +2916,8 @@ static void CreateCounterButtons()
       gi = CreateGadget(GDI_CUSTOM_ID, id,
                        GDI_CUSTOM_TYPE_ID, i,
                        GDI_INFO_TEXT, infotext,
-                       GDI_X, xpos,
-                       GDI_Y, ypos,
+                       GDI_X, x,
+                       GDI_Y, y,
                        GDI_WIDTH, x_size,
                        GDI_HEIGHT, y_size,
                        GDI_TYPE, GD_TYPE_NORMAL_BUTTON,
@@ -1598,11 +2933,15 @@ static void CreateCounterButtons()
        Error(ERR_EXIT, "cannot create gadget");
 
       level_editor_gadget[id] = gi;
-      xpos += gi->width + ED_GADGET_DISTANCE;  /* xpos of text count button */
+      right_gadget_border[id] =
+       getRightGadgetBorder(gi, counterbutton_info[i].text_right);
+
+      x += gi->width + ED_GADGET_DISTANCE;     /* text count button */
 
       if (j == 0)
       {
-       int font_type = FC_YELLOW;
+       int font_type = FONT_INPUT_1;
+       int font_type_active = FONT_INPUT_1_ACTIVE;
        int gd_width = ED_WIN_COUNT_XSIZE;
 
        id = counterbutton_info[i].gadget_id_text;
@@ -1610,10 +2949,11 @@ static void CreateCounterButtons()
 
        if (i == ED_COUNTER_ID_SELECT_LEVEL)
        {
-         font_type = FC_SPECIAL3;
+         font_type = FONT_LEVEL_NUMBER;
+         font_type_active = FONT_LEVEL_NUMBER;
 
-         xpos += 2 * ED_GADGET_DISTANCE;
-         ypos -= ED_GADGET_DISTANCE;
+         x += 2 * ED_GADGET_DISTANCE;
+         y -= ED_GADGET_DISTANCE;
 
          gd_x = DOOR_GFX_PAGEX6 + ED_WIN_COUNT2_XPOS;
          gd_y = DOOR_GFX_PAGEY1 + ED_WIN_COUNT2_YPOS;
@@ -1628,18 +2968,19 @@ static void CreateCounterButtons()
        gi = CreateGadget(GDI_CUSTOM_ID, id,
                          GDI_CUSTOM_TYPE_ID, i,
                          GDI_INFO_TEXT, "enter counter value",
-                         GDI_X, xpos,
-                         GDI_Y, ypos,
+                         GDI_X, x,
+                         GDI_Y, y,
                          GDI_TYPE, GD_TYPE_TEXTINPUT_NUMERIC,
                          GDI_NUMBER_VALUE, 0,
                          GDI_NUMBER_MIN, counterbutton_info[i].min_value,
                          GDI_NUMBER_MAX, counterbutton_info[i].max_value,
                          GDI_TEXT_SIZE, 3,
                          GDI_TEXT_FONT, font_type,
+                         GDI_TEXT_FONT_ACTIVE, font_type_active,
                          GDI_DESIGN_UNPRESSED, gd_bitmap, gd_x, gd_y,
                          GDI_DESIGN_PRESSED, gd_bitmap, gd_x, gd_y,
-                         GDI_BORDER_SIZE, ED_BORDER_SIZE,
-                         GDI_TEXTINPUT_DESIGN_WIDTH, gd_width,
+                         GDI_BORDER_SIZE, ED_BORDER_SIZE, ED_BORDER_SIZE,
+                         GDI_DESIGN_WIDTH, gd_width,
                          GDI_EVENT_MASK, event_mask,
                          GDI_CALLBACK_INFO, HandleEditorGadgetInfoText,
                          GDI_CALLBACK_ACTION, HandleCounterButtons,
@@ -1649,7 +2990,10 @@ static void CreateCounterButtons()
          Error(ERR_EXIT, "cannot create gadget");
 
        level_editor_gadget[id] = gi;
-       xpos += gi->width + ED_GADGET_DISTANCE; /* xpos of up count button */
+       right_gadget_border[id] =
+         getRightGadgetBorder(gi, counterbutton_info[i].text_right);
+
+       x += gi->width + ED_GADGET_DISTANCE;    /* up count button */
       }
     }
   }
@@ -1657,47 +3001,38 @@ static void CreateCounterButtons()
 
 static void CreateDrawingAreas()
 {
-  struct GadgetInfo *gi;
-  unsigned long event_mask;
-  int id;
   int i;
 
-  event_mask =
-    GD_EVENT_PRESSED | GD_EVENT_RELEASED | GD_EVENT_MOVING |
-    GD_EVENT_OFF_BORDERS;
-
-  /* one for the level drawing area ... */
-  id = GADGET_ID_DRAWING_LEVEL;
-  gi = CreateGadget(GDI_CUSTOM_ID, id,
-                   GDI_X, SX,
-                   GDI_Y, SY,
-                   GDI_TYPE, GD_TYPE_DRAWING_AREA,
-                   GDI_AREA_SIZE, ed_fieldx, ed_fieldy,
-                   GDI_ITEM_SIZE, MINI_TILEX, MINI_TILEY,
-                   GDI_EVENT_MASK, event_mask,
-                   GDI_CALLBACK_INFO, HandleDrawingAreaInfo,
-                   GDI_CALLBACK_ACTION, HandleDrawingAreas,
-                   GDI_END);
-
-  if (gi == NULL)
-    Error(ERR_EXIT, "cannot create gadget");
-
-  level_editor_gadget[id] = gi;
-
-  /* ... up to eight areas for element content ... */
-  for (i=0; i<MAX_ELEMENT_CONTENTS; i++)
+  for (i=0; i<ED_NUM_DRAWING_AREAS; i++)
   {
-    int gx = SX + ED_AREA_ELEM_CONTENT_XPOS + 5 * (i % 4) * MINI_TILEX;
-    int gy = SX + ED_AREA_ELEM_CONTENT_YPOS + 6 * (i / 4) * MINI_TILEY;
+    struct GadgetInfo *gi;
+    unsigned long event_mask;
+    int id = drawingarea_info[i].gadget_id;
+    int x = SX + drawingarea_info[i].x;
+    int y = SY + drawingarea_info[i].y;
+    int area_xsize = drawingarea_info[i].area_xsize;
+    int area_ysize = drawingarea_info[i].area_ysize;
+
+    event_mask =
+      GD_EVENT_PRESSED | GD_EVENT_RELEASED | GD_EVENT_MOVING |
+      GD_EVENT_OFF_BORDERS;
+
+    /* 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] +
+          ED_GADGET_TEXT_DISTANCE + MINI_TILEX / 2);
+
+    /* determine horizontal offset for leading text */
+    if (drawingarea_info[i].text_left != NULL)
+      x += (getFontWidth(FONT_TEXT_1) * strlen(drawingarea_info[i].text_left) +
+           ED_GADGET_TEXT_DISTANCE + MINI_TILEX / 2);
 
-    id = GADGET_ID_ELEM_CONTENT_0 + i;
     gi = CreateGadget(GDI_CUSTOM_ID, id,
                      GDI_CUSTOM_TYPE_ID, i,
-                     GDI_X, gx,
-                     GDI_Y, gy,
-                     GDI_WIDTH, 3 * MINI_TILEX,
-                     GDI_HEIGHT, 3 * MINI_TILEY,
+                     GDI_X, x,
+                     GDI_Y, y,
                      GDI_TYPE, GD_TYPE_DRAWING_AREA,
+                     GDI_AREA_SIZE, area_xsize, area_ysize,
                      GDI_ITEM_SIZE, MINI_TILEX, MINI_TILEY,
                      GDI_EVENT_MASK, event_mask,
                      GDI_CALLBACK_INFO, HandleDrawingAreaInfo,
@@ -1708,59 +3043,23 @@ static void CreateDrawingAreas()
       Error(ERR_EXIT, "cannot create gadget");
 
     level_editor_gadget[id] = gi;
+    right_gadget_border[id] =
+      getRightGadgetBorder(gi, drawingarea_info[i].text_right);
   }
-
-  /* ... one for the amoeba content */
-  id = GADGET_ID_AMOEBA_CONTENT;
-  gi = CreateGadget(GDI_CUSTOM_ID, id,
-                   GDI_X, SX + ED_AREA_ELEM_CONTENT_XPOS,
-                   GDI_Y, SY + ED_AREA_ELEM_CONTENT_YPOS,
-                   GDI_WIDTH, MINI_TILEX,
-                   GDI_HEIGHT, MINI_TILEY,
-                   GDI_TYPE, GD_TYPE_DRAWING_AREA,
-                   GDI_ITEM_SIZE, MINI_TILEX, MINI_TILEY,
-                   GDI_EVENT_MASK, event_mask,
-                   GDI_CALLBACK_INFO, HandleDrawingAreaInfo,
-                   GDI_CALLBACK_ACTION, HandleDrawingAreas,
-                   GDI_END);
-
-  if (gi == NULL)
-    Error(ERR_EXIT, "cannot create gadget");
-
-  level_editor_gadget[id] = gi;
-
-  /* ... and one for random placement background restrictions */
-
-  id = GADGET_ID_RANDOM_BACKGROUND;
-  gi = CreateGadget(GDI_CUSTOM_ID, id,
-                   GDI_X, SX + ED_AREA_RANDOM_BACKGROUND_XPOS,
-                   GDI_Y, SY + ED_AREA_RANDOM_BACKGROUND_YPOS,
-                   GDI_WIDTH, MINI_TILEX,
-                   GDI_HEIGHT, MINI_TILEY,
-                   GDI_TYPE, GD_TYPE_DRAWING_AREA,
-                   GDI_ITEM_SIZE, MINI_TILEX, MINI_TILEY,
-                   GDI_EVENT_MASK, event_mask,
-                   GDI_CALLBACK_INFO, HandleDrawingAreaInfo,
-                   GDI_CALLBACK_ACTION, HandleDrawingAreas,
-                   GDI_END);
-
-  if (gi == NULL)
-    Error(ERR_EXIT, "cannot create gadget");
-
-  level_editor_gadget[id] = gi;
 }
 
 static void CreateTextInputGadgets()
 {
+  int max_infotext_len = getMaxInfoTextLength();
   int i;
 
   for (i=0; i<ED_NUM_TEXTINPUT; i++)
   {
-    Bitmap *gd_bitmap = pix[PIX_DOOR];
+    Bitmap *gd_bitmap = graphic_info[IMG_GLOBAL_DOOR].bitmap;
     int gd_x, gd_y;
     struct GadgetInfo *gi;
     unsigned long event_mask;
-    char infotext[1024];
+    char infotext[MAX_OUTPUT_LINESIZE + 1];
     int id = textinput_info[i].gadget_id;
 
     event_mask = GD_EVENT_TEXT_RETURN | GD_EVENT_TEXT_LEAVING;
@@ -1769,7 +3068,7 @@ static void CreateTextInputGadgets()
     gd_y = DOOR_GFX_PAGEY1 + ED_WIN_COUNT_YPOS;
 
     sprintf(infotext, "Enter %s", textinput_info[i].infotext);
-    infotext[MAX_INFOTEXT_LEN] = '\0';
+    infotext[max_infotext_len] = '\0';
 
     gi = CreateGadget(GDI_CUSTOM_ID, id,
                      GDI_CUSTOM_TYPE_ID, i,
@@ -1779,11 +3078,12 @@ static void CreateTextInputGadgets()
                      GDI_TYPE, GD_TYPE_TEXTINPUT_ALPHANUMERIC,
                      GDI_TEXT_VALUE, textinput_info[i].value,
                      GDI_TEXT_SIZE, textinput_info[i].size,
-                     GDI_TEXT_FONT, FC_YELLOW,
+                     GDI_TEXT_FONT, FONT_INPUT_1,
+                     GDI_TEXT_FONT_ACTIVE, FONT_INPUT_1_ACTIVE,
                      GDI_DESIGN_UNPRESSED, gd_bitmap, gd_x, gd_y,
                      GDI_DESIGN_PRESSED, gd_bitmap, gd_x, gd_y,
-                     GDI_BORDER_SIZE, ED_BORDER_SIZE,
-                     GDI_TEXTINPUT_DESIGN_WIDTH, ED_WIN_COUNT_XSIZE,
+                     GDI_BORDER_SIZE, ED_BORDER_SIZE, ED_BORDER_SIZE,
+                     GDI_DESIGN_WIDTH, ED_WIN_COUNT_XSIZE,
                      GDI_EVENT_MASK, event_mask,
                      GDI_CALLBACK_INFO, HandleEditorGadgetInfoText,
                      GDI_CALLBACK_ACTION, HandleTextInputGadgets,
@@ -1796,48 +3096,198 @@ static void CreateTextInputGadgets()
   }
 }
 
-static void CreateScrollbarGadgets()
+static void CreateSelectboxGadgets()
 {
-  int i;
+  int max_infotext_len = getMaxInfoTextLength();
+  int i, j;
 
-  for (i=0; i<ED_NUM_SCROLLBARS; i++)
+  for (i=0; i<ED_NUM_SELECTBOX; i++)
   {
-    int id = scrollbar_info[i].gadget_id;
-    Bitmap *gd_bitmap = pix[PIX_DOOR];
-    int gd_x1, gd_x2, gd_y1, gd_y2;
+    Bitmap *gd_bitmap = graphic_info[IMG_GLOBAL_DOOR].bitmap;
+    int gd_x, gd_y;
     struct GadgetInfo *gi;
-    int items_max, items_visible, item_position;
     unsigned long event_mask;
+    char infotext[MAX_OUTPUT_LINESIZE + 1];
+    int id = selectbox_info[i].gadget_id;
+    int x = SX + selectbox_info[i].x;
+    int y = SY + selectbox_info[i].y;
 
-    if (i == ED_SCROLLBAR_ID_LIST_VERTICAL)
-    {
-      items_max = elements_in_list / ED_ELEMENTLIST_BUTTONS_HORIZ;
-      items_visible = ED_ELEMENTLIST_BUTTONS_VERT;
-      item_position = 0;
-    }
-    else       /* drawing area scrollbars */
+    if (selectbox_info[i].size == -1)  /* dynamically determine size */
     {
-      if (scrollbar_info[i].type == GD_TYPE_SCROLLBAR_HORIZONTAL)
-      {
-       items_max = MAX(lev_fieldx + 2, ed_fieldx);
-       items_visible = ed_fieldx;
-       item_position = 0;
-      }
-      else
-      {
-       items_max = MAX(lev_fieldy + 2, ed_fieldy);
-       items_visible = ed_fieldy;
-       item_position = 0;
-      }
+      /* (we cannot use -1 for uninitialized values if we directly compare
+        with results from strlen(), because the '<' and '>' operation will
+        implicitely cast -1 to an unsigned integer value!) */
+      selectbox_info[i].size = 0;
+
+      for (j=0; selectbox_info[i].options[j].text != NULL; j++)
+       if (strlen(selectbox_info[i].options[j].text) > selectbox_info[i].size)
+         selectbox_info[i].size = strlen(selectbox_info[i].options[j].text);
+
+      selectbox_info[i].size++;                /* add one character empty space */
     }
 
-    event_mask = GD_EVENT_MOVING | GD_EVENT_OFF_BORDERS;
+    event_mask = GD_EVENT_RELEASED |
+      GD_EVENT_TEXT_RETURN | GD_EVENT_TEXT_LEAVING;
 
-    gd_x1 = DOOR_GFX_PAGEX8 + scrollbar_info[i].xpos;
-    gd_x2 = (gd_x1 - (scrollbar_info[i].type == GD_TYPE_SCROLLBAR_HORIZONTAL ?
-                     scrollbar_info[i].height : scrollbar_info[i].width));
-    gd_y1 = DOOR_GFX_PAGEY1 + scrollbar_info[i].ypos;
-    gd_y2 = DOOR_GFX_PAGEY1 + scrollbar_info[i].ypos;
+    gd_x = DOOR_GFX_PAGEX4 + ED_SELECTBOX_XPOS;
+    gd_y = DOOR_GFX_PAGEY1 + ED_SELECTBOX_YPOS;
+
+    /* 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] +
+          ED_GADGET_TEXT_DISTANCE);
+
+    /* determine horizontal offset for leading text */
+    if (selectbox_info[i].text_left != NULL)
+      x += (getFontWidth(FONT_TEXT_1) * strlen(selectbox_info[i].text_left) +
+           ED_GADGET_TEXT_DISTANCE);
+
+    sprintf(infotext, "Select %s", selectbox_info[i].infotext);
+    infotext[max_infotext_len] = '\0';
+
+    gi = CreateGadget(GDI_CUSTOM_ID, id,
+                     GDI_CUSTOM_TYPE_ID, i,
+                     GDI_INFO_TEXT, infotext,
+                     GDI_X, x,
+                     GDI_Y, y,
+                     GDI_TYPE, GD_TYPE_SELECTBOX,
+                     GDI_SELECTBOX_OPTIONS, selectbox_info[i].options,
+                     GDI_TEXT_SIZE, selectbox_info[i].size,
+                     GDI_TEXT_FONT, FONT_INPUT_1,
+                     GDI_TEXT_FONT_ACTIVE, FONT_INPUT_1_ACTIVE,
+                     GDI_DESIGN_UNPRESSED, gd_bitmap, gd_x, gd_y,
+                     GDI_DESIGN_PRESSED, gd_bitmap, gd_x, gd_y,
+                     GDI_BORDER_SIZE, ED_BORDER_SIZE, ED_BORDER_SIZE,
+                     GDI_BORDER_SIZE_SELECTBUTTON, ED_SELECTBOX_BUTTON_XSIZE,
+                     GDI_DESIGN_WIDTH, ED_WIN_COUNT_XSIZE,
+                     GDI_EVENT_MASK, event_mask,
+                     GDI_CALLBACK_INFO, HandleEditorGadgetInfoText,
+                     GDI_CALLBACK_ACTION, HandleSelectboxGadgets,
+                     GDI_END);
+
+    if (gi == NULL)
+      Error(ERR_EXIT, "cannot create gadget");
+
+    level_editor_gadget[id] = gi;
+    right_gadget_border[id] =
+      getRightGadgetBorder(gi, selectbox_info[i].text_right);
+  }
+}
+
+static void CreateTextbuttonGadgets()
+{
+  int max_infotext_len = getMaxInfoTextLength();
+  int i;
+
+  for (i=0; i<ED_NUM_TEXTBUTTON; i++)
+  {
+    Bitmap *gd_bitmap = graphic_info[IMG_GLOBAL_DOOR].bitmap;
+    int gd_x1, gd_x2, gd_y1, gd_y2;
+    struct GadgetInfo *gi;
+    unsigned long event_mask;
+    char infotext[MAX_OUTPUT_LINESIZE + 1];
+    int id = textbutton_info[i].gadget_id;
+    int x = SX + textbutton_info[i].x;
+    int y = SY + textbutton_info[i].y;
+
+    if (textbutton_info[i].size == -1) /* dynamically determine size */
+      textbutton_info[i].size = strlen(textbutton_info[i].text);
+
+    event_mask = GD_EVENT_RELEASED;
+
+    if (id >= GADGET_ID_PROPERTIES_INFO && id <= GADGET_ID_PROPERTIES_ADVANCED)
+    {
+      gd_x1 = DOOR_GFX_PAGEX4 + ED_TEXTBUTTON_TAB_XPOS;
+      gd_x2 = DOOR_GFX_PAGEX3 + ED_TEXTBUTTON_TAB_XPOS;
+      gd_y1 = DOOR_GFX_PAGEY1 + ED_TEXTBUTTON_TAB_YPOS;
+      gd_y2 = DOOR_GFX_PAGEY1 + ED_TEXTBUTTON_TAB_INACTIVE_YPOS;
+    }
+    else
+    {
+      gd_x1 = DOOR_GFX_PAGEX4 + ED_TEXTBUTTON_XPOS;
+      gd_x2 = DOOR_GFX_PAGEX3 + ED_TEXTBUTTON_XPOS;
+      gd_y1 = DOOR_GFX_PAGEY1 + ED_TEXTBUTTON_YPOS;
+      gd_y2 = DOOR_GFX_PAGEY1 + ED_TEXTBUTTON_INACTIVE_YPOS;
+    }
+
+    sprintf(infotext, "%s", textbutton_info[i].infotext);
+    infotext[max_infotext_len] = '\0';
+
+    /* determine horizontal position to the right of specified gadget */
+    if (textbutton_info[i].gadget_id_align != GADGET_ID_NONE)
+      x = (right_gadget_border[textbutton_info[i].gadget_id_align] +
+          ED_GADGET_TEXT_DISTANCE);
+
+    gi = CreateGadget(GDI_CUSTOM_ID, id,
+                     GDI_CUSTOM_TYPE_ID, i,
+                     GDI_INFO_TEXT, infotext,
+                     GDI_X, x,
+                     GDI_Y, y,
+                     GDI_TYPE, GD_TYPE_TEXT_BUTTON,
+                     GDI_TEXT_VALUE, textbutton_info[i].text,
+                     GDI_TEXT_SIZE, textbutton_info[i].size,
+                     GDI_TEXT_FONT, FONT_INPUT_2_ACTIVE,
+                     GDI_TEXT_FONT_ACTIVE, FONT_INPUT_2,
+                     GDI_DESIGN_UNPRESSED, gd_bitmap, gd_x1, gd_y1,
+                     GDI_DESIGN_PRESSED, gd_bitmap, gd_x2, gd_y1,
+                     GDI_ALT_DESIGN_UNPRESSED, gd_bitmap, gd_x1, gd_y2,
+                     GDI_BORDER_SIZE, ED_BORDER_TEXT_XSIZE, ED_BORDER_SIZE,
+                     GDI_DESIGN_WIDTH, ED_WIN_COUNT_XSIZE,
+                     GDI_DECORATION_SHIFTING, 1, 1,
+                     GDI_EVENT_MASK, event_mask,
+                     GDI_CALLBACK_INFO, HandleEditorGadgetInfoText,
+                     GDI_CALLBACK_ACTION, HandleTextbuttonGadgets,
+                     GDI_END);
+
+    if (gi == NULL)
+      Error(ERR_EXIT, "cannot create gadget");
+
+    level_editor_gadget[id] = gi;
+  }
+}
+
+static void CreateScrollbarGadgets()
+{
+  int i;
+
+  for (i=0; i<ED_NUM_SCROLLBARS; i++)
+  {
+    int id = scrollbar_info[i].gadget_id;
+    Bitmap *gd_bitmap = graphic_info[IMG_GLOBAL_DOOR].bitmap;
+    int gd_x1, gd_x2, gd_y1, gd_y2;
+    struct GadgetInfo *gi;
+    int items_max, items_visible, item_position;
+    unsigned long event_mask;
+
+    if (i == ED_SCROLLBAR_ID_LIST_VERTICAL)
+    {
+      items_max = num_editor_elements / ED_ELEMENTLIST_BUTTONS_HORIZ;
+      items_visible = ED_ELEMENTLIST_BUTTONS_VERT;
+      item_position = element_shift / ED_ELEMENTLIST_BUTTONS_HORIZ;
+    }
+    else       /* drawing area scrollbars */
+    {
+      if (scrollbar_info[i].type == GD_TYPE_SCROLLBAR_HORIZONTAL)
+      {
+       items_max = MAX(lev_fieldx + 2, ed_fieldx);
+       items_visible = ed_fieldx;
+       item_position = 0;
+      }
+      else
+      {
+       items_max = MAX(lev_fieldy + 2, ed_fieldy);
+       items_visible = ed_fieldy;
+       item_position = 0;
+      }
+    }
+
+    event_mask = GD_EVENT_MOVING | GD_EVENT_OFF_BORDERS;
+
+    gd_x1 = DOOR_GFX_PAGEX8 + scrollbar_info[i].gd_x;
+    gd_x2 = (gd_x1 - (scrollbar_info[i].type == GD_TYPE_SCROLLBAR_HORIZONTAL ?
+                     scrollbar_info[i].height : scrollbar_info[i].width));
+    gd_y1 = DOOR_GFX_PAGEY1 + scrollbar_info[i].gd_y;
+    gd_y2 = DOOR_GFX_PAGEY1 + scrollbar_info[i].gd_y;
 
     gi = CreateGadget(GDI_CUSTOM_ID, id,
                      GDI_CUSTOM_TYPE_ID, i,
@@ -1853,7 +3303,7 @@ static void CreateScrollbarGadgets()
                      GDI_STATE, GD_BUTTON_UNPRESSED,
                      GDI_DESIGN_UNPRESSED, gd_bitmap, gd_x1, gd_y1,
                      GDI_DESIGN_PRESSED, gd_bitmap, gd_x2, gd_y2,
-                     GDI_BORDER_SIZE, ED_BORDER_SIZE,
+                     GDI_BORDER_SIZE, ED_BORDER_SIZE, ED_BORDER_SIZE,
                      GDI_EVENT_MASK, event_mask,
                      GDI_CALLBACK_INFO, HandleEditorGadgetInfoText,
                      GDI_CALLBACK_ACTION, HandleControlButtons,
@@ -1868,11 +3318,10 @@ static void CreateScrollbarGadgets()
 
 static void CreateCheckbuttonGadgets()
 {
-  Bitmap *gd_bitmap = pix[PIX_DOOR];
+  Bitmap *gd_bitmap = graphic_info[IMG_GLOBAL_DOOR].bitmap;
   struct GadgetInfo *gi;
   unsigned long event_mask;
   int gd_x1, gd_x2, gd_x3, gd_x4, gd_y;
-  boolean checked;
   int i;
 
   event_mask = GD_EVENT_PRESSED;
@@ -1883,84 +3332,185 @@ static void CreateCheckbuttonGadgets()
   gd_x4 = DOOR_GFX_PAGEX3 + ED_CHECKBUTTON_CHECKED_XPOS;
   gd_y  = DOOR_GFX_PAGEY1 + ED_RADIOBUTTON_YPOS;
 
-  for (i=0; i<ED_NUM_RADIOBUTTONS; i++)
+  for (i=0; i<ED_NUM_CHECKBUTTONS; i++)
   {
-    int id = radiobutton_info[i].gadget_id;
+    int id = checkbutton_info[i].gadget_id;
+    int x = SX + checkbutton_info[i].x;
+    int y = SY + checkbutton_info[i].y;
 
-    checked =
-      (*radiobutton_info[i].value == radiobutton_info[i].checked_value);
+    if (id == GADGET_ID_STICK_ELEMENT)
+      gd_y  = DOOR_GFX_PAGEY1 + ED_STICKYBUTTON_YPOS;
+    else
+      gd_y  = DOOR_GFX_PAGEY1 + ED_CHECKBUTTON_YPOS;
+
+    /* determine horizontal position to the right of specified gadget */
+    if (checkbutton_info[i].gadget_id_align != GADGET_ID_NONE)
+      x = (right_gadget_border[checkbutton_info[i].gadget_id_align] +
+          ED_GADGET_TEXT_DISTANCE);
+
+    /* determine horizontal offset for leading text */
+    if (checkbutton_info[i].text_left != NULL)
+      x += (getFontWidth(FONT_TEXT_1) * strlen(checkbutton_info[i].text_left) +
+           ED_GADGET_TEXT_DISTANCE);
 
     gi = CreateGadget(GDI_CUSTOM_ID, id,
                      GDI_CUSTOM_TYPE_ID, i,
-                     GDI_INFO_TEXT, radiobutton_info[i].infotext,
-                     GDI_X, SX + radiobutton_info[i].x,
-                     GDI_Y, SY + radiobutton_info[i].y,
+                     GDI_INFO_TEXT, checkbutton_info[i].infotext,
+                     GDI_X, x,
+                     GDI_Y, y,
                      GDI_WIDTH, ED_CHECKBUTTON_XSIZE,
                      GDI_HEIGHT, ED_CHECKBUTTON_YSIZE,
-                     GDI_TYPE, GD_TYPE_RADIO_BUTTON,
-                     GDI_RADIO_NR, radiobutton_info[i].radio_button_nr,
-                     GDI_CHECKED, checked,
+                     GDI_TYPE, GD_TYPE_CHECK_BUTTON,
+                     GDI_CHECKED, *checkbutton_info[i].value,
                      GDI_DESIGN_UNPRESSED, gd_bitmap, gd_x1, gd_y,
                      GDI_DESIGN_PRESSED, gd_bitmap, gd_x2, gd_y,
                      GDI_ALT_DESIGN_UNPRESSED, gd_bitmap, gd_x3, gd_y,
                      GDI_ALT_DESIGN_PRESSED, gd_bitmap, gd_x4, gd_y,
                      GDI_EVENT_MASK, event_mask,
                      GDI_CALLBACK_INFO, HandleEditorGadgetInfoText,
-                     GDI_CALLBACK_ACTION, HandleRadiobuttons,
+                     GDI_CALLBACK_ACTION, HandleCheckbuttons,
                      GDI_END);
 
     if (gi == NULL)
       Error(ERR_EXIT, "cannot create gadget");
 
     level_editor_gadget[id] = gi;
+    right_gadget_border[id] =
+      getRightGadgetBorder(gi, checkbutton_info[i].text_right);
   }
+}
 
-  for (i=0; i<ED_NUM_CHECKBUTTONS; i++)
+static void CreateRadiobuttonGadgets()
+{
+  Bitmap *gd_bitmap = graphic_info[IMG_GLOBAL_DOOR].bitmap;
+  struct GadgetInfo *gi;
+  unsigned long event_mask;
+  int gd_x1, gd_x2, gd_x3, gd_x4, gd_y;
+  int i;
+
+  event_mask = GD_EVENT_PRESSED;
+
+  gd_x1 = DOOR_GFX_PAGEX4 + ED_CHECKBUTTON_UNCHECKED_XPOS;
+  gd_x2 = DOOR_GFX_PAGEX3 + ED_CHECKBUTTON_UNCHECKED_XPOS;
+  gd_x3 = DOOR_GFX_PAGEX4 + ED_CHECKBUTTON_CHECKED_XPOS;
+  gd_x4 = DOOR_GFX_PAGEX3 + ED_CHECKBUTTON_CHECKED_XPOS;
+  gd_y  = DOOR_GFX_PAGEY1 + ED_RADIOBUTTON_YPOS;
+
+  for (i=0; i<ED_NUM_RADIOBUTTONS; i++)
   {
-    int id = checkbutton_info[i].gadget_id;
+    int id = radiobutton_info[i].gadget_id;
+    int x = SX + radiobutton_info[i].x;
+    int y = SY + radiobutton_info[i].y;
 
-    if (id == GADGET_ID_STICK_ELEMENT)
-      gd_y  = DOOR_GFX_PAGEY1 + ED_STICKYBUTTON_YPOS;
-    else
-      gd_y  = DOOR_GFX_PAGEY1 + ED_CHECKBUTTON_YPOS;
+    int checked =
+      (*radiobutton_info[i].value == radiobutton_info[i].checked_value);
+
+    /* determine horizontal position to the right of specified gadget */
+    if (radiobutton_info[i].gadget_id_align != GADGET_ID_NONE)
+      x = (right_gadget_border[radiobutton_info[i].gadget_id_align] +
+          ED_GADGET_TEXT_DISTANCE);
+
+    /* determine horizontal offset for leading text */
+    if (radiobutton_info[i].text_left != NULL)
+      x += (getFontWidth(FONT_TEXT_1) * strlen(radiobutton_info[i].text_left) +
+           ED_GADGET_TEXT_DISTANCE);
 
     gi = CreateGadget(GDI_CUSTOM_ID, id,
                      GDI_CUSTOM_TYPE_ID, i,
-                     GDI_INFO_TEXT, checkbutton_info[i].infotext,
-                     GDI_X, SX + checkbutton_info[i].x,
-                     GDI_Y, SY + checkbutton_info[i].y,
+                     GDI_INFO_TEXT, radiobutton_info[i].infotext,
+                     GDI_X, x,
+                     GDI_Y, y,
                      GDI_WIDTH, ED_CHECKBUTTON_XSIZE,
                      GDI_HEIGHT, ED_CHECKBUTTON_YSIZE,
-                     GDI_TYPE, GD_TYPE_CHECK_BUTTON,
-                     GDI_CHECKED, *checkbutton_info[i].value,
+                     GDI_TYPE, GD_TYPE_RADIO_BUTTON,
+                     GDI_RADIO_NR, radiobutton_info[i].radio_button_nr,
+                     GDI_CHECKED, checked,
                      GDI_DESIGN_UNPRESSED, gd_bitmap, gd_x1, gd_y,
                      GDI_DESIGN_PRESSED, gd_bitmap, gd_x2, gd_y,
                      GDI_ALT_DESIGN_UNPRESSED, gd_bitmap, gd_x3, gd_y,
                      GDI_ALT_DESIGN_PRESSED, gd_bitmap, gd_x4, gd_y,
                      GDI_EVENT_MASK, event_mask,
                      GDI_CALLBACK_INFO, HandleEditorGadgetInfoText,
-                     GDI_CALLBACK_ACTION, HandleCheckbuttons,
+                     GDI_CALLBACK_ACTION, HandleRadiobuttons,
                      GDI_END);
 
     if (gi == NULL)
       Error(ERR_EXIT, "cannot create gadget");
 
     level_editor_gadget[id] = gi;
+    right_gadget_border[id] =
+      getRightGadgetBorder(gi, radiobutton_info[i].text_right);
   }
 }
 
 void CreateLevelEditorGadgets()
 {
+  int old_game_status = game_status;
+
+  /* setting 'game_status' is needed to get the right fonts for the editor */
+  game_status = GAME_MODE_EDITOR;
+
+  ReinitializeElementList();
+
   CreateControlButtons();
-  CreateCounterButtons();
-  CreateDrawingAreas();
-  CreateTextInputGadgets();
   CreateScrollbarGadgets();
+
+  /* order of function calls is important because of cross-references */
   CreateCheckbuttonGadgets();
+  CreateCounterButtons();
+  CreateRadiobuttonGadgets();
+  CreateTextInputGadgets();
+  CreateTextbuttonGadgets();
+  CreateSelectboxGadgets();
+  CreateDrawingAreas();
+
+  game_status = old_game_status;
+}
+
+void FreeLevelEditorGadgets()
+{
+  int i;
+
+  for (i=0; i<NUM_EDITOR_GADGETS; i++)
+    FreeGadget(level_editor_gadget[i]);
 }
 
 static void MapCounterButtons(int id)
 {
+  int gadget_id_down = counterbutton_info[id].gadget_id_down;
+  int gadget_id_up   = counterbutton_info[id].gadget_id_up;
+  struct GadgetInfo *gi_down = level_editor_gadget[gadget_id_down];
+  struct GadgetInfo *gi_up   = level_editor_gadget[gadget_id_up];
+#if 0
+  char infotext[MAX_OUTPUT_LINESIZE + 1];
+  int max_infotext_len = getMaxInfoTextLength();
+  int xoffset_left = 0;
+  int yoffset_left = ED_BORDER_SIZE;
+  int xoffset_right = getCounterGadgetWidth();
+  int yoffset_right = ED_BORDER_SIZE;
+#else
+  int xoffset_left = getFullTextWidth(counterbutton_info[id].text_left);
+  int xoffset_right = ED_GADGET_TEXT_DISTANCE;
+  int yoffset_above = MINI_TILEX + ED_GADGET_DISTANCE;
+  int yoffset = ED_BORDER_SIZE;
+  int x_left = gi_down->x - xoffset_left;
+  int x_right = gi_up->x + gi_up->width + xoffset_right;
+  int y_above = gi_down->y - yoffset_above;
+  int x = gi_down->x;
+  int y = gi_up->y + yoffset;
+#endif
+
+  if (counterbutton_info[id].text_above)
+    DrawText(x, y_above, counterbutton_info[id].text_above, FONT_TEXT_1);
+
+  if (counterbutton_info[id].text_left)
+    DrawText(x_left, y, counterbutton_info[id].text_left, FONT_TEXT_1);
+
+  if (counterbutton_info[id].text_right)
+    DrawText(x_right, y, counterbutton_info[id].text_right, FONT_TEXT_1);
+
+  ModifyEditorCounter(id, *counterbutton_info[id].value);
+
   MapGadget(level_editor_gadget[counterbutton_info[id].gadget_id_down]);
   MapGadget(level_editor_gadget[counterbutton_info[id].gadget_id_text]);
   MapGadget(level_editor_gadget[counterbutton_info[id].gadget_id_up]);
@@ -1987,27 +3537,131 @@ static void MapControlButtons()
   ModifyEditorCounterLimits(counter_id,
                            leveldir_current->first_level,
                            leveldir_current->last_level);
-  ModifyEditorCounter(counter_id, *counterbutton_info[counter_id].value);
   MapCounterButtons(counter_id);
 }
 
 static void MapDrawingArea(int id)
 {
-  MapGadget(level_editor_gadget[id]);
+  MapGadget(level_editor_gadget[drawingarea_info[id].gadget_id]);
 }
 
 static void MapTextInputGadget(int id)
 {
+  char infotext[MAX_OUTPUT_LINESIZE + 1];
+  int max_infotext_len = getMaxInfoTextLength();
+  int xoffset_above = 0;
+  int yoffset_above = -(MINI_TILEX + ED_GADGET_DISTANCE);
+  int x = textinput_info[id].x + xoffset_above;
+  int y = textinput_info[id].y + yoffset_above;
+
+  if (textinput_info[id].infotext)
+  {
+    sprintf(infotext, "%s:", textinput_info[id].infotext);
+    infotext[max_infotext_len] = '\0';
+    DrawTextF(x, y, FONT_TEXT_1, infotext);
+  }
+
+  ModifyGadget(level_editor_gadget[textinput_info[id].gadget_id],
+              GDI_TEXT_VALUE, textinput_info[id].value, GDI_END);
+
   MapGadget(level_editor_gadget[textinput_info[id].gadget_id]);
 }
 
+static void MapSelectboxGadget(int id)
+{
+  struct GadgetInfo *gi = level_editor_gadget[selectbox_info[id].gadget_id];
+#if 0
+  int xoffset_left = 0;
+  int yoffset_left = ED_BORDER_SIZE;
+  int xoffset_right = ED_GADGET_TEXT_DISTANCE;
+  int yoffset_right = ED_BORDER_SIZE;
+  int x = selectbox_info[id].x + xoffset_left;
+  int y = selectbox_info[id].y + yoffset_left;
+#else
+  int xoffset_left = getFullTextWidth(selectbox_info[id].text_left);
+  int xoffset_right = ED_GADGET_TEXT_DISTANCE;
+  int yoffset = ED_BORDER_SIZE;
+  int x_left = gi->x - xoffset_left;
+  int x_right = gi->x + gi->width + xoffset_right;
+  int y = gi->y + yoffset;
+#endif
+
+  if (selectbox_info[id].text_left)
+    DrawText(x_left, y, selectbox_info[id].text_left, FONT_TEXT_1);
+
+  if (selectbox_info[id].text_right)
+    DrawText(x_right, y, selectbox_info[id].text_right, FONT_TEXT_1);
+
+  ModifyEditorSelectbox(id, *selectbox_info[id].value);
+
+  MapGadget(level_editor_gadget[selectbox_info[id].gadget_id]);
+}
+
+static void MapTextbuttonGadget(int id)
+{
+  MapGadget(level_editor_gadget[textbutton_info[id].gadget_id]);
+}
+
 static void MapRadiobuttonGadget(int id)
 {
+  struct GadgetInfo *gi = level_editor_gadget[radiobutton_info[id].gadget_id];
+#if 0
+  int xoffset_right = ED_XOFFSET_CHECKBOX;
+  int yoffset_right = ED_BORDER_SIZE;
+  int x = radiobutton_info[id].x + xoffset_right;
+  int y = radiobutton_info[id].y + yoffset_right;
+#else
+  int xoffset_left = getFullTextWidth(checkbutton_info[id].text_left);
+  int xoffset_right = ED_GADGET_TEXT_DISTANCE;
+  int yoffset = ED_BORDER_SIZE;
+  int x_left = gi->x - xoffset_left;
+  int x_right = gi->x + gi->width + xoffset_right;
+  int y = gi->y + yoffset;
+#endif
+  boolean checked =
+    (*radiobutton_info[id].value == radiobutton_info[id].checked_value);
+
+  if (radiobutton_info[id].text_left)
+    DrawText(x_left, y, radiobutton_info[id].text_left, FONT_TEXT_1);
+
+  if (radiobutton_info[id].text_right)
+    DrawText(x_right, y, radiobutton_info[id].text_right, FONT_TEXT_1);
+
+  ModifyGadget(level_editor_gadget[radiobutton_info[id].gadget_id],
+              GDI_CHECKED, checked, GDI_END);
+
   MapGadget(level_editor_gadget[radiobutton_info[id].gadget_id]);
 }
 
 static void MapCheckbuttonGadget(int id)
 {
+  struct GadgetInfo *gi = level_editor_gadget[checkbutton_info[id].gadget_id];
+#if 0
+  int xoffset_right = ED_XOFFSET_CHECKBOX;
+  int yoffset_right = ED_BORDER_SIZE;
+  int x = checkbutton_info[id].x + xoffset_right;
+  int y = checkbutton_info[id].y + yoffset_right;
+#else
+  int xoffset_left = getFullTextWidth(checkbutton_info[id].text_left);
+  int xoffset_right = ED_GADGET_TEXT_DISTANCE;
+  int yoffset = ED_BORDER_SIZE;
+  int x_left = gi->x - xoffset_left;
+  int x_right = gi->x + gi->width + xoffset_right;
+  int y = gi->y + yoffset;
+#endif
+
+  /* special case needed for "sticky" gadget */
+  ModifyGadget(level_editor_gadget[checkbutton_info[id].gadget_id],
+              GDI_CHECKED, *checkbutton_info[id].value,
+              GDI_Y, SY + checkbutton_info[id].y, GDI_END);
+  y = gi->y + yoffset;
+
+  if (checkbutton_info[id].text_left)
+    DrawText(x_left, y, checkbutton_info[id].text_left, FONT_TEXT_1);
+
+  if (checkbutton_info[id].text_right)
+    DrawText(x_right, y, checkbutton_info[id].text_right, FONT_TEXT_1);
+
   MapGadget(level_editor_gadget[checkbutton_info[id].gadget_id]);
 }
 
@@ -2039,7 +3693,7 @@ static void MapMainDrawingArea()
     MapGadget(level_editor_gadget[scrollbar_info[i].gadget_id]);
   }
 
-  MapDrawingArea(GADGET_ID_DRAWING_LEVEL);
+  MapDrawingArea(ED_DRAWING_ID_DRAWING_LEVEL);
 }
 
 static void UnmapDrawingArea(int id)
@@ -2073,6 +3727,9 @@ static void ResetUndoBuffer()
 
 static void DrawEditModeWindow()
 {
+  ModifyEditorElementList();
+  RedrawDrawingElements();
+
   if (edit_mode == ED_MODE_INFO)
     DrawLevelInfoWindow();
   else if (edit_mode == ED_MODE_PROPERTIES)
@@ -2088,7 +3745,7 @@ static boolean LevelChanged()
 
   for(y=0; y<lev_fieldy; y++) 
     for(x=0; x<lev_fieldx; x++)
-      if (Feld[x][y] != Ur[x][y])
+      if (Feld[x][y] != level.field[x][y])
        level_changed = TRUE;
 
   return level_changed;
@@ -2101,14 +3758,249 @@ static boolean LevelContainsPlayer()
 
   for(y=0; y<lev_fieldy; y++) 
     for(x=0; x<lev_fieldx; x++)
-      if (Feld[x][y] == EL_SPIELFIGUR ||
-         Feld[x][y] == EL_SPIELER1 ||
+      if (Feld[x][y] == EL_PLAYER_1 ||
          Feld[x][y] == EL_SP_MURPHY) 
        player_found = TRUE;
 
   return player_found;
 }
 
+static void CopyPlayfield(short src[MAX_LEV_FIELDX][MAX_LEV_FIELDY],
+                         short dst[MAX_LEV_FIELDX][MAX_LEV_FIELDY])
+{
+  int x, y;
+
+  for(x=0; x<lev_fieldx; x++)
+    for(y=0; y<lev_fieldy; y++) 
+      dst[x][y] = src[x][y];
+}
+
+static void CopyCustomElementPropertiesToEditor(int element)
+{
+  int i;
+
+  /* needed here to initialize combined element properties */
+  InitElementPropertiesEngine(level.game_version);
+
+  custom_element = element_info[element];
+
+  for (i=0; i < NUM_ELEMENT_PROPERTIES; i++)
+    custom_element_properties[i] = HAS_PROPERTY(element, i);
+
+  for (i=0; i < NUM_CHANGE_EVENTS; i++)
+    custom_element_change_events[i] = HAS_CHANGE_EVENT(element, i);
+
+  /* ---------- element settings: configure (custom elements) ------------- */
+
+  /* set accessible layer selectbox help value */
+  custom_element.access_type =
+    (IS_WALKABLE(element) ? EP_WALKABLE :
+     IS_PASSABLE(element) ? EP_PASSABLE :
+     custom_element.access_type);
+  custom_element.access_layer =
+    (IS_ACCESSIBLE_OVER(element) ? EP_ACCESSIBLE_OVER :
+     IS_ACCESSIBLE_INSIDE(element) ? EP_ACCESSIBLE_INSIDE :
+     IS_ACCESSIBLE_UNDER(element) ? EP_ACCESSIBLE_UNDER :
+     custom_element.access_layer);
+  custom_element_properties[EP_ACCESSIBLE] =
+    (IS_ACCESSIBLE_OVER(element) ||
+     IS_ACCESSIBLE_INSIDE(element) ||
+     IS_ACCESSIBLE_UNDER(element));
+
+  /* set walk-to-object action selectbox help value */
+  custom_element.walk_to_action =
+    (IS_DIGGABLE(element) ? EP_DIGGABLE :
+     IS_COLLECTIBLE(element) ? EP_COLLECTIBLE :
+     IS_PUSHABLE(element) ? EP_PUSHABLE :
+     custom_element.walk_to_action);
+  custom_element_properties[EP_WALK_TO_OBJECT] =
+    (IS_DIGGABLE(element) ||
+     IS_COLLECTIBLE(element) ||
+     IS_PUSHABLE(element));
+
+  /* set smash targets selectbox help value */
+  custom_element.smash_targets =
+    (CAN_SMASH_EVERYTHING(element) ? EP_CAN_SMASH_EVERYTHING :
+     CAN_SMASH_ENEMIES(element) ? EP_CAN_SMASH_ENEMIES :
+     CAN_SMASH_PLAYER(element) ? EP_CAN_SMASH_PLAYER :
+     custom_element.smash_targets);
+  custom_element_properties[EP_CAN_SMASH] =
+    (CAN_SMASH_EVERYTHING(element) ||
+     CAN_SMASH_ENEMIES(element) ||
+     CAN_SMASH_PLAYER(element));
+
+  /* set deadliness selectbox help value */
+  custom_element.deadliness =
+    (DONT_TOUCH(element) ? EP_DONT_TOUCH :
+     DONT_COLLIDE_WITH(element) ? EP_DONT_COLLIDE_WITH :
+     DONT_RUN_INTO(element) ? EP_DONT_RUN_INTO :
+     custom_element.deadliness);
+  custom_element_properties[EP_DEADLY] =
+    (DONT_TOUCH(element) ||
+     DONT_COLLIDE_WITH(element) ||
+     DONT_RUN_INTO(element));
+
+  /* set consistency selectbox help value */
+  custom_element.consistency =
+    (IS_INDESTRUCTIBLE(element) ? EP_INDESTRUCTIBLE :
+     CAN_EXPLODE(element) ? EP_CAN_EXPLODE :
+     custom_element.consistency);
+  custom_element_properties[EP_EXPLODE_RESULT] =
+    (IS_INDESTRUCTIBLE(element) ||
+     CAN_EXPLODE(element));
+
+  /* special case: sub-settings dependent from main setting */
+  if (CAN_EXPLODE_BY_FIRE(element))
+    custom_element.can_explode_by_fire = TRUE;
+  if (CAN_EXPLODE_SMASHED(element))
+    custom_element.can_explode_smashed = TRUE;
+  if (CAN_EXPLODE_IMPACT(element))
+    custom_element.can_explode_impact  = TRUE;
+
+  /* ---------- element settings: advanced (custom elements) --------------- */
+
+  /* set change by player selectbox help value */
+  custom_element.change_player_action =
+    (HAS_CHANGE_EVENT(element, CE_PUSHED_BY_PLAYER) ? CE_PUSHED_BY_PLAYER :
+     HAS_CHANGE_EVENT(element, CE_PRESSED_BY_PLAYER) ? CE_PRESSED_BY_PLAYER :
+     HAS_CHANGE_EVENT(element, CE_TOUCHED_BY_PLAYER) ? CE_TOUCHED_BY_PLAYER :
+     custom_element.change_player_action);
+
+  /* set change by collision selectbox help value */
+  custom_element.change_collide_action =
+    (HAS_CHANGE_EVENT(element, CE_SMASHED) ? CE_SMASHED :
+     HAS_CHANGE_EVENT(element, CE_IMPACT) ? CE_IMPACT :
+     HAS_CHANGE_EVENT(element, CE_COLLISION) ? CE_COLLISION :
+     custom_element.change_collide_action);
+
+  /* set change by other element action selectbox help value */
+  custom_element.change_other_action =
+    (HAS_CHANGE_EVENT(element, CE_OTHER_GETS_COLLECTED) ? CE_OTHER_GETS_COLLECTED :
+     HAS_CHANGE_EVENT(element, CE_OTHER_GETS_PUSHED) ? CE_OTHER_GETS_PUSHED :
+     HAS_CHANGE_EVENT(element, CE_OTHER_GETS_PRESSED) ? CE_OTHER_GETS_PRESSED :
+     HAS_CHANGE_EVENT(element, CE_OTHER_GETS_TOUCHED) ? CE_OTHER_GETS_TOUCHED :
+     HAS_CHANGE_EVENT(element, CE_OTHER_IS_EXPLODING) ? CE_OTHER_IS_EXPLODING :
+     HAS_CHANGE_EVENT(element, CE_OTHER_IS_CHANGING) ? CE_OTHER_IS_CHANGING :
+     HAS_CHANGE_EVENT(element, CE_OTHER_IS_TOUCHING) ? CE_OTHER_IS_TOUCHING :
+     custom_element.change_other_action);
+}
+
+static void CopyCustomElementPropertiesToGame(int element)
+{
+  int i;
+  int access_type_and_layer;
+
+  if (level.use_custom_template)
+  {
+    if (Request("Copy and modify level tem- plate ?", REQ_ASK))
+    {
+      level.use_custom_template = FALSE;
+      ModifyGadget(level_editor_gadget[GADGET_ID_CUSTOM_USE_TEMPLATE],
+                  GDI_CHECKED, FALSE, GDI_END);
+    }
+    else
+    {
+      LoadLevelTemplate(-1);
+
+      DrawEditModeWindow();
+    }
+  }
+
+  element_info[element] = custom_element;
+
+  /* ---------- element settings: configure (custom elements) ------------- */
+
+  /* set accessible property from checkbox and selectbox */
+  custom_element_properties[EP_WALKABLE_OVER] = FALSE;
+  custom_element_properties[EP_WALKABLE_INSIDE] = FALSE;
+  custom_element_properties[EP_WALKABLE_UNDER] = FALSE;
+  custom_element_properties[EP_PASSABLE_OVER] = FALSE;
+  custom_element_properties[EP_PASSABLE_INSIDE] = FALSE;
+  custom_element_properties[EP_PASSABLE_UNDER] = FALSE;
+  access_type_and_layer = ((custom_element.access_type == EP_WALKABLE ?
+                           EP_WALKABLE_OVER : EP_PASSABLE_OVER) +
+                          (custom_element.access_layer - EP_ACCESSIBLE_OVER));
+  custom_element_properties[access_type_and_layer] =
+    custom_element_properties[EP_ACCESSIBLE];
+
+  /* set walk-to-object property from checkbox and selectbox */
+  custom_element_properties[EP_DIGGABLE] = FALSE;
+  custom_element_properties[EP_COLLECTIBLE] = FALSE;
+  custom_element_properties[EP_PUSHABLE] = FALSE;
+  custom_element_properties[custom_element.walk_to_action] =
+    custom_element_properties[EP_WALK_TO_OBJECT];
+
+  /* set smash property from checkbox and selectbox */
+  custom_element_properties[EP_CAN_SMASH_PLAYER] = FALSE;
+  custom_element_properties[EP_CAN_SMASH_ENEMIES] = FALSE;
+  custom_element_properties[EP_CAN_SMASH_EVERYTHING] = FALSE;
+  custom_element_properties[custom_element.smash_targets] =
+    custom_element_properties[EP_CAN_SMASH];
+
+  /* set deadliness property from checkbox and selectbox */
+  custom_element_properties[EP_DONT_RUN_INTO] = FALSE;
+  custom_element_properties[EP_DONT_COLLIDE_WITH] = FALSE;
+  custom_element_properties[EP_DONT_TOUCH] = FALSE;
+  custom_element_properties[custom_element.deadliness] =
+    custom_element_properties[EP_DEADLY];
+
+  /* set consistency property from checkbox and selectbox */
+  custom_element_properties[EP_INDESTRUCTIBLE] = FALSE;
+  custom_element_properties[EP_CAN_EXPLODE] = FALSE;
+  custom_element_properties[EP_CAN_EXPLODE_BY_FIRE] = FALSE;
+  custom_element_properties[EP_CAN_EXPLODE_SMASHED] = FALSE;
+  custom_element_properties[EP_CAN_EXPLODE_IMPACT] = FALSE;
+  custom_element_properties[custom_element.consistency] =
+    custom_element_properties[EP_EXPLODE_RESULT];
+
+  /* special case: sub-settings dependent from main setting */
+  if (custom_element_properties[EP_CAN_EXPLODE])
+  {
+    custom_element_properties[EP_CAN_EXPLODE_BY_FIRE] =
+      custom_element.can_explode_by_fire;
+    custom_element_properties[EP_CAN_EXPLODE_SMASHED] =
+      custom_element.can_explode_smashed;
+    custom_element_properties[EP_CAN_EXPLODE_IMPACT] =
+      custom_element.can_explode_impact;
+  }
+
+  /* ---------- element settings: advanced (custom elements) --------------- */
+
+  /* set player change event from checkbox and selectbox */
+  custom_element_change_events[CE_TOUCHED_BY_PLAYER] = FALSE;
+  custom_element_change_events[CE_PRESSED_BY_PLAYER] = FALSE;
+  custom_element_change_events[CE_PUSHED_BY_PLAYER] = FALSE;
+  custom_element_change_events[custom_element.change_player_action] =
+    custom_element_change_events[CE_BY_PLAYER];
+
+  /* set collision change event from checkbox and selectbox */
+  custom_element_change_events[CE_COLLISION] = FALSE;
+  custom_element_change_events[CE_IMPACT] = FALSE;
+  custom_element_change_events[CE_SMASHED] = FALSE;
+  custom_element_change_events[custom_element.change_collide_action] =
+    custom_element_change_events[CE_BY_COLLISION];
+
+  /* set other element action change event from checkbox and selectbox */
+  custom_element_change_events[CE_OTHER_IS_TOUCHING] = FALSE;
+  custom_element_change_events[CE_OTHER_IS_CHANGING] = FALSE;
+  custom_element_change_events[CE_OTHER_IS_EXPLODING] = FALSE;
+  custom_element_change_events[CE_OTHER_GETS_TOUCHED] = FALSE;
+  custom_element_change_events[CE_OTHER_GETS_PRESSED] = FALSE;
+  custom_element_change_events[CE_OTHER_GETS_PUSHED] = FALSE;
+  custom_element_change_events[CE_OTHER_GETS_COLLECTED] = FALSE;
+  custom_element_change_events[custom_element.change_other_action] =
+    custom_element_change_events[CE_BY_OTHER];
+
+  for (i=0; i < NUM_ELEMENT_PROPERTIES; i++)
+    SET_PROPERTY(element, i, custom_element_properties[i]);
+
+  for (i=0; i < NUM_CHANGE_EVENTS; i++)
+    SET_CHANGE_EVENT(element, i, custom_element_change_events[i]);
+
+  /* copy change events also to special level editor variable */
+  custom_element = element_info[element];
+}
+
 void DrawLevelEd()
 {
   CloseDoor(DOOR_CLOSE_ALL);
@@ -2116,69 +4008,55 @@ void DrawLevelEd()
 
   if (level_editor_test_game)
   {
-    int x, y;
-
-    for(x=0; x<lev_fieldx; x++)
-      for(y=0; y<lev_fieldy; y++)
-       Feld[x][y] = Ur[x][y];
-
-    for(x=0; x<lev_fieldx; x++)
-      for(y=0; y<lev_fieldy; y++)
-       Ur[x][y] = FieldBackup[x][y];
+    CopyPlayfield(level.field, Feld);
+    CopyPlayfield(FieldBackup, level.field);
 
     level_editor_test_game = FALSE;
   }
   else
   {
     edit_mode = ED_MODE_DRAWING;
+    edit_mode_properties = ED_MODE_PROPERTIES_INFO;
 
     ResetUndoBuffer();
+
     level_xpos = -1;
     level_ypos = -1;
   }
 
   /* copy default editor door content to main double buffer */
-  BlitBitmap(pix[PIX_DOOR], drawto,
+  BlitBitmap(graphic_info[IMG_GLOBAL_DOOR].bitmap, drawto,
             DOOR_GFX_PAGEX6, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE, DX, DY);
 
+#if 0
   /* draw mouse button brush elements */
-  DrawMiniGraphicExt(drawto,
-                    DX + ED_WIN_MB_LEFT_XPOS, DY + ED_WIN_MB_LEFT_YPOS,
-                    el2gfx(new_element1));
-  DrawMiniGraphicExt(drawto,
-                    DX + ED_WIN_MB_MIDDLE_XPOS, DY + ED_WIN_MB_MIDDLE_YPOS,
-                    el2gfx(new_element2));
-  DrawMiniGraphicExt(drawto,
-                    DX + ED_WIN_MB_RIGHT_XPOS, DY + ED_WIN_MB_RIGHT_YPOS,
-                    el2gfx(new_element3));
+  RedrawDrawingElements();
+#endif
 
   /* draw bigger door */
   DrawSpecialEditorDoor();
 
   /* draw new control window */
-  BlitBitmap(pix[PIX_DOOR], drawto,
+  BlitBitmap(graphic_info[IMG_GLOBAL_DOOR].bitmap, drawto,
             DOOR_GFX_PAGEX8, 236, EXSIZE, EYSIZE, EX, EY);
 
   redraw_mask |= REDRAW_ALL;
 
+  ReinitializeElementListButtons();    /* only needed after setup changes */
+#if 0
+  ModifyEditorElementList();           /* may be needed for custom elements */
+#endif
+
+  UnmapTapeButtons();
   MapControlButtons();
 
-  /* copy actual editor door content to door double buffer for OpenDoor() */
-  BlitBitmap(drawto, pix[PIX_DB_DOOR],
-            DX, DY, DXSIZE, DYSIZE, DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
-
   DrawEditModeWindow();
 
-  /*
-  FadeToFront();
-  */
-
+  /* copy actual editor door content to door double buffer for OpenDoor() */
+  BlitBitmap(drawto, bitmap_db_door,
+            DX, DY, DXSIZE, DYSIZE, DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
 
   OpenDoor(DOOR_OPEN_1);
-
-  /*
-  OpenDoor(DOOR_OPEN_1 | DOOR_OPEN_2);
-  */
 }
 
 static void AdjustDrawingAreaGadgets()
@@ -2285,14 +4163,6 @@ static void AdjustEditorScrollbar(int id)
               GDI_SCROLLBAR_ITEM_POSITION, item_position, GDI_END);
 }
 
-static void ModifyEditorTextInput(int textinput_id, char *new_text)
-{
-  int gadget_id = textinput_info[textinput_id].gadget_id;
-  struct GadgetInfo *gi = level_editor_gadget[gadget_id];
-
-  ModifyGadget(gi, GDI_TEXT_VALUE, new_text, GDI_END);
-}
-
 static void ModifyEditorCounter(int counter_id, int new_value)
 {
   int *counter_value = counterbutton_info[counter_id].value;
@@ -2313,6 +4183,41 @@ static void ModifyEditorCounterLimits(int counter_id, int min, int max)
   ModifyGadget(gi, GDI_NUMBER_MIN, min, GDI_NUMBER_MAX, max, GDI_END);
 }
 
+static void ModifyEditorSelectbox(int selectbox_id, int new_value)
+{
+  int gadget_id = selectbox_info[selectbox_id].gadget_id;
+  struct GadgetInfo *gi = level_editor_gadget[gadget_id];
+  int new_index_value = 0;
+  int i;
+
+  for(i=0; selectbox_info[selectbox_id].options[i].text != NULL; i++)
+    if (selectbox_info[selectbox_id].options[i].value == new_value)
+      new_index_value = i;
+
+  *selectbox_info[selectbox_id].value =
+    selectbox_info[selectbox_id].options[new_index_value].value;
+
+  ModifyGadget(gi, GDI_SELECTBOX_INDEX, new_index_value, GDI_END);
+}
+
+static void ModifyEditorElementList()
+{
+  int i;
+
+  for (i=0; i<ED_NUM_ELEMENTLIST_BUTTONS; i++)
+  {
+    int gadget_id = GADGET_ID_ELEMENTLIST_FIRST + i;
+    struct GadgetInfo *gi = level_editor_gadget[gadget_id];
+    struct GadgetDesign *gd = &gi->deco.design;
+    int element = editor_elements[element_shift + i];
+
+    UnmapGadget(gi);
+    getMiniGraphicSource(el2edimg(element), &gd->bitmap, &gd->x, &gd->y);
+    ModifyGadget(gi, GDI_INFO_TEXT, getElementInfoText(element), GDI_END);
+    MapGadget(gi);
+  }
+}
+
 static void PickDrawingElement(int button, int element)
 {
   if (button < 1 || button > 3)
@@ -2323,265 +4228,669 @@ static void PickDrawingElement(int button, int element)
     new_element1 = element;
     DrawMiniGraphicExt(drawto,
                       DX + ED_WIN_MB_LEFT_XPOS, DY + ED_WIN_MB_LEFT_YPOS,
-                      el2gfx(new_element1));
+                      el2edimg(new_element1));
   }
   else if (button == 2)
   {
     new_element2 = element;
     DrawMiniGraphicExt(drawto,
                       DX + ED_WIN_MB_MIDDLE_XPOS, DY + ED_WIN_MB_MIDDLE_YPOS,
-                      el2gfx(new_element2));
+                      el2edimg(new_element2));
   }
   else
   {
     new_element3 = element;
     DrawMiniGraphicExt(drawto,
                       DX + ED_WIN_MB_RIGHT_XPOS, DY + ED_WIN_MB_RIGHT_YPOS,
-                      el2gfx(new_element3));
+                      el2edimg(new_element3));
   }
 
   redraw_mask |= REDRAW_DOOR_1;
 }
 
+static void RedrawDrawingElements()
+{
+  PickDrawingElement(1, new_element1);
+  PickDrawingElement(2, new_element2);
+  PickDrawingElement(3, new_element3);
+}
+
 static void DrawDrawingWindow()
 {
+  stick_element_properties_window = FALSE;
+
+  SetMainBackgroundImage(IMG_UNDEFINED);
   ClearWindow();
   UnmapLevelEditorWindowGadgets();
+
   AdjustDrawingAreaGadgets();
   AdjustLevelScrollPosition();
   AdjustEditorScrollbar(GADGET_ID_SCROLL_HORIZONTAL);
   AdjustEditorScrollbar(GADGET_ID_SCROLL_VERTICAL);
+
   DrawMiniLevel(ed_fieldx, ed_fieldy, level_xpos, level_ypos);
   MapMainDrawingArea();
 }
 
-static void DrawRandomPlacementBackgroundArea()
+static void DrawElementBorder(int dest_x, int dest_y, int width, int height,
+                             boolean input)
 {
-  int area_x = ED_AREA_RANDOM_BACKGROUND_XPOS / MINI_TILEX;
-  int area_y = ED_AREA_RANDOM_BACKGROUND_YPOS / MINI_TILEY;
-  int area_sx = SX + ED_AREA_RANDOM_BACKGROUND_XPOS;
-  int area_sy = SY + ED_AREA_RANDOM_BACKGROUND_YPOS;
+  int border_graphic =
+    (input ? IMG_EDITOR_ELEMENT_BORDER_INPUT : IMG_EDITOR_ELEMENT_BORDER);
+  Bitmap *src_bitmap;
+  int src_x, src_y;
+  int num_mini_tilex = width / MINI_TILEX + 1;
+  int num_mini_tiley = width / MINI_TILEY + 1;
   int x, y;
 
-  ElementContent[0][0][0] = random_placement_background_element;
+  getMiniGraphicSource(border_graphic, &src_bitmap, &src_x, &src_y);
 
-  /* draw decorative border for the object */
-  for (y=0; y<2; y++)
-    for (x=0; x<2; x++)
-      DrawMiniElement(area_x + x, area_y + y, EL_ERDREICH);
+  for (y=0; y < num_mini_tiley; y++)
+    for (x=0; x < num_mini_tilex; x++)
+      BlitBitmap(src_bitmap, drawto, src_x, src_y, MINI_TILEX, MINI_TILEY,
+                dest_x - MINI_TILEX / 2 + x * MINI_TILEX,
+                dest_y - MINI_TILEY / 2 + y * MINI_TILEY);
 
-  ClearRectangle(drawto,
-                area_sx + MINI_TILEX/2 - 1, area_sy + MINI_TILEY/2 - 1,
-                MINI_TILEX + 2, MINI_TILEY + 2);
+  ClearRectangle(drawto, dest_x - 1, dest_y - 1, width + 2, height + 2);
+}
 
-  /* copy border to the right location */
-  BlitBitmap(drawto, drawto,
-            area_sx, area_sy, 3 * MINI_TILEX, 3 * MINI_TILEY,
-            area_sx - MINI_TILEX/2, area_sy - MINI_TILEY/2);
+static void DrawRandomPlacementBackgroundArea()
+{
+  struct GadgetInfo *gi = level_editor_gadget[GADGET_ID_RANDOM_BACKGROUND];
+#if 0
+  int area_x = ED_AREA_RANDOM_BACKGROUND_XPOS / MINI_TILEX;
+  int area_y = ED_AREA_RANDOM_BACKGROUND_YPOS / MINI_TILEY;
+  int area_sx = SX + ED_AREA_RANDOM_BACKGROUND_XPOS;
+  int area_sy = SY + ED_AREA_RANDOM_BACKGROUND_YPOS;
+#endif
 
-  DrawMiniElement(area_x, area_y, ElementContent[0][0][0]);
+  DrawElementBorder(gi->x, gi->y, MINI_TILEX, MINI_TILEY, TRUE);
+  DrawMiniElement(gi->x, gi->y, random_placement_background_element);
 
-  MapDrawingArea(GADGET_ID_RANDOM_BACKGROUND);
+  MapDrawingArea(ED_DRAWING_ID_RANDOM_BACKGROUND);
 }
 
 static void DrawLevelInfoWindow()
 {
-  char infotext[1024];
-  int xoffset_above = 0;
-  int yoffset_above = -(MINI_TILEX + ED_GADGET_DISTANCE);
-  int xoffset_right = counter_xsize;
-  int yoffset_right = ED_BORDER_SIZE;
-  int xoffset_right2 = ED_CHECKBUTTON_XSIZE + 2 * ED_GADGET_DISTANCE;
-  int yoffset_right2 = ED_BORDER_SIZE;
-  int font_color = FC_GREEN;
-  int i, x, y;
+  int i;
 
+  stick_element_properties_window = FALSE;
+
+  SetMainBackgroundImage(IMG_BACKGROUND_EDITOR);
   ClearWindow();
   UnmapLevelEditorWindowGadgets();
 
-  DrawText(SX + ED_SETTINGS2_XPOS, SY + ED_SETTINGS_YPOS,
-          "Level Settings", FS_BIG, FC_YELLOW);
+  DrawText(SX + ED_SETTINGS2_XPOS, SY + ED_SETTINGS1_YPOS,
+          "Level Settings", FONT_TITLE_1);
   DrawText(SX + ED_SETTINGS2_XPOS, SY + ED_SETTINGS2_YPOS,
-          "Editor Settings", FS_BIG, FC_YELLOW);
+          "Editor Settings", FONT_TITLE_1);
 
   /* draw counter gadgets */
   for (i=ED_COUNTER_ID_LEVEL_FIRST; i<=ED_COUNTER_ID_LEVEL_LAST; i++)
-  {
-    if (counterbutton_info[i].infotext_above)
-    {
-      x = counterbutton_info[i].x + xoffset_above;
-      y = counterbutton_info[i].y + yoffset_above;
-
-      sprintf(infotext, "%s:", counterbutton_info[i].infotext_above);
-      infotext[MAX_INFOTEXT_LEN] = '\0';
-      DrawTextF(x, y, font_color, infotext);
-    }
-
-    if (counterbutton_info[i].infotext_right)
-    {
-      x = counterbutton_info[i].x + xoffset_right;
-      y = counterbutton_info[i].y + yoffset_right;
+    MapCounterButtons(i);
 
-      sprintf(infotext, "%s", counterbutton_info[i].infotext_right);
-      infotext[MAX_INFOTEXT_LEN] = '\0';
-      DrawTextF(x, y, font_color, infotext);
-    }
+  /* draw checkbutton gadgets */
+  for (i=ED_CHECKBUTTON_ID_LEVEL_FIRST; i<=ED_CHECKBUTTON_ID_LEVEL_LAST; i++)
+    MapCheckbuttonGadget(i);
 
-    ModifyEditorCounter(i, *counterbutton_info[i].value);
-    MapCounterButtons(i);
-  }
+  /* draw radiobutton gadgets */
+  for (i=ED_RADIOBUTTON_ID_LEVEL_FIRST; i<=ED_RADIOBUTTON_ID_LEVEL_LAST; i++)
+    MapRadiobuttonGadget(i);
 
   /* draw text input gadgets */
   for (i=ED_TEXTINPUT_ID_LEVEL_FIRST; i<=ED_TEXTINPUT_ID_LEVEL_LAST; i++)
-  {
-    x = textinput_info[i].x + xoffset_above;
-    y = textinput_info[i].y + yoffset_above;
+    MapTextInputGadget(i);
 
-    sprintf(infotext, "%s:", textinput_info[i].infotext);
-    infotext[MAX_INFOTEXT_LEN] = '\0';
+  /* draw drawing area */
+  DrawRandomPlacementBackgroundArea();
+}
 
-    DrawTextF(x, y, font_color, infotext);
-    ModifyEditorTextInput(i, textinput_info[i].value);
-    MapTextInputGadget(i);
-  }
+static void DrawAmoebaContentArea()
+{
+  int area_x = ED_AREA_ELEM_CONTENT_XPOS / MINI_TILEX;
+  int area_y = ED_AREA_ELEM_CONTENT_YPOS / MINI_TILEY;
+  int area_sx = SX + ED_AREA_ELEM_CONTENT_XPOS;
+  int area_sy = SY + ED_AREA_ELEM_CONTENT_YPOS;
 
-  /* draw radiobutton gadgets */
-  for (i=ED_RADIOBUTTON_ID_LEVEL_FIRST; i<=ED_RADIOBUTTON_ID_LEVEL_LAST; i++)
+  DrawElementBorder(area_sx, area_sy, MINI_TILEX, MINI_TILEY, TRUE);
+  DrawMiniElement(area_x, area_y, level.amoeba_content);
+
+  DrawText(area_sx + TILEX, area_sy + 1, "Content of amoeba", FONT_TEXT_1);
+
+  MapDrawingArea(ED_DRAWING_ID_AMOEBA_CONTENT);
+}
+
+static void DrawCustomGraphicElementArea()
+{
+  struct GadgetInfo *gi = level_editor_gadget[GADGET_ID_CUSTOM_GRAPHIC];
+#if 0
+  int xpos = ED_AREA_ELEM_CONTENT3_XPOS;
+  int ypos = ED_AREA_ELEM_CONTENT3_YPOS;
+  int area_sx = SX + xpos;
+  int area_sy = SY + ypos;
+#endif
+
+  if (!IS_CUSTOM_ELEMENT(properties_element))
   {
-    boolean checked =
-      (*radiobutton_info[i].value == radiobutton_info[i].checked_value);
+    /* this should never happen */
+    Error(ERR_WARN, "element %d is no custom element", properties_element);
 
-    x = radiobutton_info[i].x + xoffset_right2;
-    y = radiobutton_info[i].y + yoffset_right2;
+    return;
+  }
 
-    DrawTextF(x, y, font_color, radiobutton_info[i].text);
-    ModifyGadget(level_editor_gadget[radiobutton_info[i].gadget_id],
-                GDI_CHECKED, checked, GDI_END);
-    MapRadiobuttonGadget(i);
+  DrawElementBorder(gi->x, gi->y, MINI_TILEX, MINI_TILEY, TRUE);
+  DrawMiniGraphicExt(drawto, gi->x, gi->y,
+                    el2edimg(custom_element.gfx_element));
+
+  MapDrawingArea(ED_DRAWING_ID_CUSTOM_GRAPHIC);
+}
+
+static void DrawCustomContentArea()
+{
+  struct GadgetInfo *gi = level_editor_gadget[GADGET_ID_CUSTOM_CONTENT];
+#if 0
+  int area_sx = SX + ED_AREA_ELEM_CONTENT4_XPOS;
+  int area_sy = SY + ED_AREA_ELEM_CONTENT4_YPOS;
+#endif
+  int x1 = right_gadget_border[GADGET_ID_CUSTOM_DEADLINESS];
+  int x2 = right_gadget_border[GADGET_ID_CUSTOM_CONSISTENCY];
+  int x3 = right_gadget_border[GADGET_ID_CUSTOM_EXPLODE_IMPACT];
+  int xoffset = ED_GADGET_TEXT_DISTANCE + MINI_TILEX / 2;
+  int x, y;
+
+  if (!IS_CUSTOM_ELEMENT(properties_element))
+  {
+    /* this should never happen */
+    Error(ERR_WARN, "element %d is no custom element", properties_element);
+
+    return;
   }
 
-  /* draw checkbutton gadgets */
-  for (i=ED_CHECKBUTTON_ID_LEVEL_FIRST; i<=ED_CHECKBUTTON_ID_LEVEL_LAST; i++)
+  ModifyGadget(gi, GDI_X, MAX(x1, MAX(x2, x3)) + xoffset, GDI_END);
+
+  DrawElementBorder(gi->x, gi->y, 3 * MINI_TILEX, 3 * MINI_TILEY, TRUE);
+
+  for (y=0; y<3; y++)
+    for (x=0; x<3; x++)
+      DrawMiniGraphicExt(drawto, gi->x + x * MINI_TILEX,gi->y + y * MINI_TILEY,
+                        el2edimg(custom_element.content[x][y]));
+
+  MapDrawingArea(ED_DRAWING_ID_CUSTOM_CONTENT);
+}
+
+static void DrawCustomChangeTargetArea()
+{
+  int id = ED_DRAWING_ID_CUSTOM_CHANGE_TARGET;
+  int gadget_id = drawingarea_info[id].gadget_id;
+  struct GadgetInfo *gi = level_editor_gadget[gadget_id];
+#if 0
+  int xpos = ED_AREA_ELEM_CONTENT2_XPOS;
+  int ypos = ED_AREA_ELEM_CONTENT2_YPOS;
+  int area_sx = SX + xpos;
+  int area_sy = SY + ypos;
+#endif
+  int xoffset_left = 0;
+  int yoffset_left = ED_BORDER_AREA_YSIZE;
+  int xoffset_right = ED_GADGET_TEXT_DISTANCE + MINI_TILEX / 2;
+  int yoffset_right = ED_BORDER_AREA_YSIZE;
+  int x = drawingarea_info[id].x + xoffset_left;
+  int y = drawingarea_info[id].y + yoffset_left;
+
+  if (!IS_CUSTOM_ELEMENT(properties_element))
   {
-    x = checkbutton_info[i].x + xoffset_right2;
-    y = checkbutton_info[i].y + yoffset_right2;
+    /* this should never happen */
+    Error(ERR_WARN, "element %d is no custom element", properties_element);
 
-    DrawTextF(x, y, font_color, checkbutton_info[i].text);
-    ModifyGadget(level_editor_gadget[checkbutton_info[i].gadget_id],
-                GDI_CHECKED, *checkbutton_info[i].value, GDI_END);
-    MapCheckbuttonGadget(i);
+    return;
   }
 
-  /* draw drawing area */
-  DrawRandomPlacementBackgroundArea();
+  DrawElementBorder(gi->x, gi->y, MINI_TILEX, MINI_TILEY, TRUE);
+  DrawMiniGraphicExt(drawto, gi->x, gi->y,
+                    el2edimg(custom_element.change.target_element));
+
+  MapDrawingArea(ED_DRAWING_ID_CUSTOM_CHANGE_TARGET);
+
+  if (drawingarea_info[id].text_left)
+    DrawTextF(x, y, FONT_TEXT_1, drawingarea_info[id].text_left);
+
+  if (drawingarea_info[id].text_right)
+  {
+    x = gi->x + gi->width + xoffset_right;
+    y = SY + drawingarea_info[id].y + yoffset_right;
+
+    DrawText(x, y, drawingarea_info[id].text_right, FONT_TEXT_1);
+  }
 }
 
-static void DrawAmoebaContentArea()
+static void DrawCustomChangeContentArea()
 {
-  int area_x = ED_AREA_ELEM_CONTENT_XPOS / MINI_TILEX;
-  int area_y = ED_AREA_ELEM_CONTENT_YPOS / MINI_TILEY;
-  int area_sx = SX + ED_AREA_ELEM_CONTENT_XPOS;
-  int area_sy = SY + ED_AREA_ELEM_CONTENT_YPOS;
-  int font_color = FC_GREEN;
+  struct GadgetInfo *gi = level_editor_gadget[GADGET_ID_CUSTOM_CHANGE_CONTENT];
+#if 0
+  int area_sx = SX + ED_AREA_ELEM_CONTENT6_XPOS;
+  int area_sy = SY + ED_AREA_ELEM_CONTENT6_YPOS;
+#endif
+  int x1 = right_gadget_border[GADGET_ID_CHANGE_USE_CONTENT];
+  int x2 = right_gadget_border[GADGET_ID_CHANGE_POWER];
+  int x3 = right_gadget_border[GADGET_ID_CHANGE_ONLY_COMPLETE];
+  int xoffset = ED_GADGET_TEXT_DISTANCE + MINI_TILEX / 2;
   int x, y;
 
-  ElementContent[0][0][0] = level.amoeba_content;
+  if (!IS_CUSTOM_ELEMENT(properties_element))
+  {
+    /* this should never happen */
+    Error(ERR_WARN, "element %d is no custom element", properties_element);
 
-  /* draw decorative border for the object */
-  for (y=0; y<2; y++)
-    for (x=0; x<2; x++)
-      DrawMiniElement(area_x + x, area_y + y, EL_ERDREICH);
+    return;
+  }
 
-  ClearRectangle(drawto,
-                area_sx + MINI_TILEX/2 - 1, area_sy + MINI_TILEY/2 - 1,
-                MINI_TILEX + 2, MINI_TILEY + 2);
+  ModifyGadget(gi, GDI_X, MAX(x1, MAX(x2, x3)) + xoffset, GDI_END);
 
-  /* copy border to the right location */
-  BlitBitmap(drawto, drawto,
-            area_sx, area_sy, 3 * MINI_TILEX, 3 * MINI_TILEY,
-            area_sx - MINI_TILEX/2, area_sy - MINI_TILEY/2);
+  DrawElementBorder(gi->x, gi->y, 3 * MINI_TILEX, 3 * MINI_TILEY, TRUE);
+
+  for (y=0; y<3; y++)
+    for (x=0; x<3; x++)
+      DrawMiniGraphicExt(drawto, gi->x + x * MINI_TILEX,gi->y + y * MINI_TILEY,
+                        el2edimg(custom_element.change.content[x][y]));
+
+  MapDrawingArea(ED_DRAWING_ID_CUSTOM_CHANGE_CONTENT);
+}
+
+static void DrawCustomChangeTriggerArea()
+{
+  struct GadgetInfo *gi = level_editor_gadget[GADGET_ID_CUSTOM_CHANGE_TRIGGER];
+#if 0
+  int xpos = ED_AREA_ELEM_CONTENT5_XPOS;
+  int ypos = ED_AREA_ELEM_CONTENT5_YPOS;
+  int area_sx = SX + xpos;
+  int area_sy = SY + ypos;
+#endif
+
+  if (!IS_CUSTOM_ELEMENT(properties_element))
+  {
+    /* this should never happen */
+    Error(ERR_WARN, "element %d is no custom element", properties_element);
 
-  DrawText(area_sx + TILEX, area_sy + 1, "Content of amoeba",
-          FS_SMALL, font_color);
+    return;
+  }
 
-  DrawMiniElement(area_x, area_y, ElementContent[0][0][0]);
+  DrawElementBorder(gi->x, gi->y, MINI_TILEX, MINI_TILEY, TRUE);
+  DrawMiniGraphicExt(drawto, gi->x, gi->y,
+                    el2edimg(custom_element.change.trigger_element));
 
-  MapDrawingArea(GADGET_ID_AMOEBA_CONTENT);
+  MapDrawingArea(ED_DRAWING_ID_CUSTOM_CHANGE_TRIGGER);
 }
 
 static void DrawElementContentAreas()
 {
-  int counter_id = ED_COUNTER_ID_ELEM_CONTENT;
   int area_x = ED_AREA_ELEM_CONTENT_XPOS / MINI_TILEX;
   int area_y = ED_AREA_ELEM_CONTENT_YPOS / MINI_TILEY;
   int area_sx = SX + ED_AREA_ELEM_CONTENT_XPOS;
   int area_sy = SY + ED_AREA_ELEM_CONTENT_YPOS;
-  int xoffset_right = counter_xsize;
-  int yoffset_right = ED_BORDER_SIZE;
-  int font_color = FC_GREEN;
   int i, x, y;
 
-  for (i=0; i<MAX_ELEMENT_CONTENTS; i++)
-    for (y=0; y<3; y++)
-      for (x=0; x<3; x++)
-       ElementContent[i][x][y] = level.yam_content[i][x][y];
+  for (i=0; i<MAX_ELEMENT_CONTENTS; i++)
+    UnmapDrawingArea(GADGET_ID_ELEMENT_CONTENT_0 + i);
+
+  /* display counter to choose number of element content areas */
+  MapCounterButtons(ED_COUNTER_ID_ELEMENT_CONTENT);
+
+  /* delete content areas in case of reducing number of them */
+  DrawBackground(SX, area_sy - MINI_TILEX, SXSIZE, 12 * MINI_TILEY);
+
+  for (i=0; i<level.num_yamyam_contents; i++)
+    DrawElementBorder(area_sx + 5 * (i % 4) * MINI_TILEX,
+                     area_sy + 6 * (i / 4) * MINI_TILEY,
+                     3 * MINI_TILEX, 3 * MINI_TILEY, TRUE);
+
+  DrawText(area_sx + (5 * 4 - 1) * MINI_TILEX, area_sy + 0 * MINI_TILEY + 1,
+          "Content", FONT_TEXT_1);
+  DrawText(area_sx + (5 * 4 - 1) * MINI_TILEX, area_sy + 1 * MINI_TILEY + 1,
+          "when",    FONT_TEXT_1);
+  DrawText(area_sx + (5 * 4 - 1) * MINI_TILEX, area_sy + 2 * MINI_TILEY + 1,
+          "smashed", FONT_TEXT_1);
+
+  for (i=0; i<level.num_yamyam_contents; i++)
+  {
+    for (y=0; y<3; y++)
+      for (x=0; x<3; x++)
+       DrawMiniElement(area_x + 5 * (i % 4) + x, area_y + 6 * (i / 4) + y,
+                       level.yamyam_content[i][x][y]);
+
+    DrawTextF(area_sx - SX + 5 * (i % 4) * MINI_TILEX + MINI_TILEX + 1,
+             area_sy - SY + 6 * (i / 4) * MINI_TILEY + 4 * MINI_TILEY - 4,
+             FONT_TEXT_1, "%d", i + 1);
+  }
+
+  for (i=0; i<level.num_yamyam_contents; i++)
+    MapDrawingArea(ED_DRAWING_ID_ELEMENT_CONTENT_0 + i);
+}
+
+char *getElementDescriptionFilename(int element)
+{
+  char *docs_dir = options.docs_directory;
+  char *elements_subdir = "elements";
+  static char *filename = NULL;
+  char basename[MAX_FILENAME_LEN];
+
+  if (filename != NULL)
+    free(filename);
+
+  /* 1st try: look for element description file for exactly this element */
+  sprintf(basename, "%s.txt", element_info[element].token_name);
+  filename = getPath3(docs_dir, elements_subdir, basename);
+  if (fileExists(filename))
+    return filename;
+
+  free(filename);
+
+  /* 2nd try: look for element description file for this element's class */
+  sprintf(basename, "%s.txt", element_info[element].class_name);
+  filename = getPath3(docs_dir, elements_subdir, basename);
+  if (fileExists(filename))
+    return filename;
+
+  return NULL;
+}
+
+static boolean PrintInfoText(char *text, int font_nr, int screen_line)
+{
+  int font_height = getFontHeight(font_nr);
+  int pad_x = ED_SETTINGS_XPOS(0);
+  int pad_y = ED_SETTINGS_YPOS(0) + ED_BORDER_SIZE;
+  int sx = SX + pad_x;
+  int sy = SY + pad_y;
+  int max_lines_per_screen = (SYSIZE - pad_y) / font_height - 1;
+
+  if (screen_line >= max_lines_per_screen)
+    return FALSE;
+
+  DrawText(sx, sy + screen_line * font_height, text, font_nr);
+
+  return TRUE;
+}
+
+static int PrintElementDescriptionFromFile(char *filename, int screen_line)
+{
+  int font_nr = FONT_TEXT_2;
+  int font_width = getFontWidth(font_nr);
+  int pad_x = ED_SETTINGS_XPOS(0);
+  int max_chars_per_line = (SXSIZE - 2 * pad_x) / font_width;
+  char line[MAX_LINE_LEN];
+  char buffer[max_chars_per_line + 1];
+  int buffer_len;
+  int lines_printed = 0;
+  FILE *file;
+
+  if (filename == NULL)
+    return 0;
+
+  if (!(file = fopen(filename, MODE_READ)))
+    return 0;
+
+  buffer[0] = '\0';
+  buffer_len = 0;
+
+  while(!feof(file))
+  {
+    char *line_ptr, *word_ptr;
+    boolean last_line_was_empty = TRUE;
+
+    /* read next line of input file */
+    if (!fgets(line, MAX_LINE_LEN, file))
+      break;
+
+    /* skip comments (lines directly beginning with '#') */
+    if (line[0] == '#')
+      continue;
+
+    /* cut trailing newline from input line */
+    for (line_ptr = line; *line_ptr; line_ptr++)
+    {
+      if (*line_ptr == '\n' || *line_ptr == '\r')
+      {
+       *line_ptr = '\0';
+       break;
+      }
+    }
+
+    if (strlen(line) == 0)             /* special case: force empty line */
+      strcpy(line, "\n");
+
+    word_ptr = line;
+
+    while (*word_ptr)
+    {
+      boolean print_buffer = FALSE;
+      int word_len;
+
+      /* skip leading whitespaces */
+      while (*word_ptr == ' ' || *word_ptr == '\t')
+       word_ptr++;
+
+      line_ptr = word_ptr;
+      word_len = 0;
+
+      /* look for end of next word */
+      while (*line_ptr != ' ' && *line_ptr != '\t' && *line_ptr != '\0')
+      {
+       line_ptr++;
+       word_len++;
+      }
+
+      if (word_len == 0)
+      {
+       continue;
+      }
+      else if (*word_ptr == '\n')      /* special case: force empty line */
+      {
+       if (buffer_len == 0)
+         word_ptr++;
+
+       /* prevent printing of multiple empty lines */
+       if (buffer_len > 0 || !last_line_was_empty)
+         print_buffer = TRUE;
+      }
+      else if (word_len < max_chars_per_line - buffer_len)
+      {
+       /* word fits into text buffer -- add word */
+
+       if (buffer_len > 0)
+         buffer[buffer_len++] = ' ';
+
+       strncpy(&buffer[buffer_len], word_ptr, word_len);
+       buffer_len += word_len;
+       buffer[buffer_len] = '\0';
+       word_ptr += word_len;
+      }
+      else if (buffer_len > 0)
+      {
+       /* not enough space left for word in text buffer -- print buffer */
+
+       print_buffer = TRUE;
+      }
+      else
+      {
+       /* word does not fit at all into empty text buffer -- cut word */
+
+       strncpy(buffer, word_ptr, max_chars_per_line);
+       buffer[max_chars_per_line] = '\0';
+       word_ptr += max_chars_per_line;
+       print_buffer = TRUE;
+      }
+
+      if (print_buffer)
+      {
+       if (!PrintInfoText(buffer, font_nr, screen_line + lines_printed))
+         return lines_printed;
+
+       last_line_was_empty = (buffer_len == 0);
+       lines_printed++;
+
+       buffer[0] = '\0';
+       buffer_len = 0;
+       print_buffer = FALSE;
+      }
+    }
+  }
+
+  fclose(file);
+
+  if (buffer_len > 0)
+    if (PrintInfoText(buffer, font_nr, screen_line + lines_printed))
+      lines_printed++;
+
+  return lines_printed;
+}
+
+static void DrawPropertiesTabulatorGadgets()
+{
+  struct GadgetInfo *gd_gi = level_editor_gadget[GADGET_ID_PROPERTIES_INFO];
+  struct GadgetDesign *gd = &gd_gi->alt_design[GD_BUTTON_UNPRESSED];
+  int gd_x = gd->x + gd_gi->border.width / 2;
+  int gd_y = gd->y + gd_gi->height - 1;
+  Pixel tab_color = GetPixel(gd->bitmap, gd_x, gd_y);
+  int id_first = ED_TEXTBUTTON_ID_PROPERTIES_INFO;
+  int id_last  = ED_TEXTBUTTON_ID_PROPERTIES_CONFIG;
+  int i;
+
+  /* draw additional "advanced" tabulator for custom elements */
+  if (IS_CUSTOM_ELEMENT(properties_element))
+    id_last = ED_TEXTBUTTON_ID_PROPERTIES_ADVANCED;
+
+  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_properties);
+
+    /* 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,1, 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_gi->x, gd_gi->y + gd_gi->height + 1,
+                 3 * gd_gi->width + 2 * ED_GADGET_DISTANCE,
+                 ED_GADGET_DISTANCE, tab_color);
+}
+
+static void DrawPropertiesInfo()
+{
+  static struct
+  {
+    int value;
+    char *text;
+  }
+  properties[] =
+  {
+    /* configurable properties */
+
+    { EP_WALKABLE_OVER,                "- player can walk over it"             },
+    { EP_WALKABLE_INSIDE,      "- player can walk inside it"           },
+    { EP_WALKABLE_UNDER,       "- player can walk under it"            },
+    { EP_PASSABLE_OVER,                "- player can pass over it"             },
+    { EP_PASSABLE_INSIDE,      "- player can pass through it"          },
+    { EP_PASSABLE_UNDER,       "- player can pass under it"            },
+
+    { EP_DIGGABLE,             "- diggable"                            },
+    { EP_COLLECTIBLE,          "- collectible"                         },
+    { EP_PUSHABLE,             "- pushable"                            },
+
+    { EP_CAN_MOVE,             "- can move"                            },
+    { EP_CAN_FALL,             "- can fall"                            },
+
+    { EP_CAN_SMASH_PLAYER,     "- can smash player"                    },
+#if 0
+    { EP_CAN_SMASH_ENEMIES,    "- can smash good and bad guys"         },
+#endif
+    { EP_CAN_SMASH_EVERYTHING, "- can smash everything smashable"      },
+
+    { EP_SLIPPERY,             "- slippery for falling objects"        },
+    { EP_EM_SLIPPERY_WALL,     "- slippery for some gems (EM style)"   },
+
+    { EP_DONT_RUN_INTO,                "- deadly when running into"            },
+    { EP_DONT_COLLIDE_WITH,    "- deadly when colliding with"          },
+    { EP_DONT_TOUCH,           "- deadly when touching"                },
+
+    { EP_INDESTRUCTIBLE,       "- undestructible"                      },
+
+    { EP_CAN_EXPLODE_BY_FIRE,  "- can explode by fire or explosions"   },
+    { EP_CAN_EXPLODE_SMASHED,  "- can explode when smashed"            },
+    { EP_CAN_EXPLODE_IMPACT,   "- can explode on impact"               },
 
-  for (i=0; i<MAX_ELEMENT_CONTENTS; i++)
-    UnmapDrawingArea(GADGET_ID_ELEM_CONTENT_0 + i);
+    { EP_CAN_CHANGE,           "- can change to other element"         },
 
-  /* display counter to choose number of element content areas */
-  x = counterbutton_info[counter_id].x + xoffset_right;
-  y = counterbutton_info[counter_id].y + yoffset_right;
-  DrawTextF(x, y, font_color, "number of content areas");
+    /* pre-defined properties */
+    { EP_CAN_PASS_MAGIC_WALL,  "- can pass magic walls"                },
+    { EP_HAS_CONTENT,          "- can contain other elements"          },
 
-  ModifyEditorCounter(counter_id, *counterbutton_info[counter_id].value);
-  MapCounterButtons(counter_id);
+    { -1,                      NULL                                    }
+  };
+  char *filename = getElementDescriptionFilename(properties_element);
+  char *percentage_text = "In this level:";
+  char *properties_text = "Standard properties:";
+  float percentage;
+  int num_elements_in_level;
+  int num_standard_properties = 0;
+  int font1_nr = FONT_TEXT_1;
+  int font2_nr = FONT_TEXT_2;
+  int font1_width = getFontWidth(font1_nr);
+  int font2_height = getFontHeight(font2_nr);
+  int pad_x = ED_SETTINGS_XPOS(0);
+  int pad_y = ED_SETTINGS_YPOS(0) + ED_BORDER_SIZE;
+  int screen_line = 0;
+  int i, x, y;
 
-  /* delete content areas in case of reducing number of them */
-  ClearRectangle(backbuffer,
-                SX, area_sy - MINI_TILEX,
-                SXSIZE, 12 * MINI_TILEY);
+  /* ----- print number of elements / percentage of this element in level */
 
-  /* draw some decorative border for the objects */
-  for (i=0; i<level.num_yam_contents; i++)
-  {
-    for (y=0; y<4; y++)
-      for (x=0; x<4; x++)
-       DrawMiniElement(area_x + 5 * (i % 4) + x, area_y + 6 * (i / 4) + y,
-                       EL_ERDREICH);
+  num_elements_in_level = 0;
+  for (y=0; y<lev_fieldy; y++) 
+    for (x=0; x<lev_fieldx; x++)
+      if (Feld[x][y] == properties_element)
+       num_elements_in_level++;
+  percentage = num_elements_in_level * 100.0 / (lev_fieldx * lev_fieldy);
 
-    ClearRectangle(drawto,
-                  area_sx + 5 * (i % 4) * MINI_TILEX + MINI_TILEX/2 - 1,
-                  area_sy + 6 * (i / 4) * MINI_TILEY + MINI_TILEY/2 - 1,
-                  3 * MINI_TILEX + 2, 3 * MINI_TILEY + 2);
-  }
+  DrawTextF(pad_x, pad_y + screen_line * font2_height, font1_nr,
+           percentage_text);
+  DrawTextF(pad_x + strlen(percentage_text) * font1_width,
+           pad_y + screen_line++ * font2_height, font2_nr,
+           "%d (%.2f%%)", num_elements_in_level, percentage);
 
-  /* copy border to the right location */
-  BlitBitmap(drawto, drawto,
-            area_sx, area_sy, (5 * 4 + 1) * MINI_TILEX, 11 * MINI_TILEY,
-            area_sx - MINI_TILEX/2, area_sy - MINI_TILEY/2);
+  screen_line++;
 
-  DrawText(area_sx + (5 * 4 - 1) * MINI_TILEX, area_sy + 0 * MINI_TILEY + 1,
-          "Content", FS_SMALL, font_color);
-  DrawText(area_sx + (5 * 4 - 1) * MINI_TILEX, area_sy + 1 * MINI_TILEY + 1,
-          "when", FS_SMALL, font_color);
-  DrawText(area_sx + (5 * 4 - 1) * MINI_TILEX, area_sy + 2 * MINI_TILEY + 1,
-          "smashed", FS_SMALL, font_color);
+  /* ----- print standard properties of this element */
+
+  DrawTextF(pad_x, pad_y + screen_line++ * font2_height, font1_nr,
+           properties_text);
 
-  for (i=0; i<level.num_yam_contents; i++)
+  for (i=0; properties[i].value != -1; i++)
   {
-    for (y=0; y<3; y++)
-      for (x=0; x<3; x++)
-       DrawMiniElement(area_x + 5 * (i % 4) + x, area_y + 6 * (i / 4) + y,
-                       ElementContent[i][x][y]);
+    if (!HAS_PROPERTY(properties_element, properties[i].value))
+      continue;
 
-    DrawTextF(area_sx - SX + 5 * (i % 4) * MINI_TILEX + MINI_TILEX + 1,
-             area_sy - SY + 6 * (i / 4) * MINI_TILEY + 4 * MINI_TILEY - 4,
-             font_color, "%d", i + 1);
+    DrawTextF(pad_x, pad_y + screen_line++ * font2_height, font2_nr,
+             properties[i].text);
+    num_standard_properties++;
   }
 
-  for (i=0; i<level.num_yam_contents; i++)
-    MapDrawingArea(GADGET_ID_ELEM_CONTENT_0 + i);
+  if (num_standard_properties == 0)
+    DrawTextF(pad_x + strlen(properties_text) * font1_width,
+             pad_y + (screen_line - 1) * font2_height, font2_nr, "none");
+
+  screen_line++;
+
+  /* ----- print special description of this element */
+
+  PrintInfoText("Description:", FONT_TEXT_1, screen_line);
+  if (PrintElementDescriptionFromFile(filename, screen_line + 1) == 0)
+    PrintInfoText("No description available.", FONT_TEXT_1, screen_line);
 }
 
 #define TEXT_COLLECTING                "Score for collecting"
@@ -2590,135 +4899,110 @@ static void DrawElementContentAreas()
 #define TEXT_SPEED             "Speed of amoeba growth"
 #define TEXT_DURATION          "Duration when activated"
 
-static void DrawPropertiesWindow()
+static struct
 {
-  int counter_id = ED_COUNTER_ID_ELEM_SCORE;
-  int num_elements_in_level;
-  float percentage;
-  int xoffset_right = counter_xsize;
-  int yoffset_right = ED_BORDER_SIZE;
-  int xoffset_right2 = ED_CHECKBUTTON_XSIZE + 2 * ED_GADGET_DISTANCE;
-  int yoffset_right2 = ED_BORDER_SIZE;
-  int xstart = 2;
-  int ystart = 4;
-  int font_color = FC_GREEN;
-  int i, x, y;
-  static struct
-  {
-    int element;
-    int *value;
-    char *text;
-  } elements_with_counter[] =
-  {
-    { EL_EDELSTEIN,    &level.score[SC_EDELSTEIN],     TEXT_COLLECTING },
-    { EL_EDELSTEIN_BD, &level.score[SC_EDELSTEIN],     TEXT_COLLECTING },
-    { EL_EDELSTEIN_GELB,&level.score[SC_EDELSTEIN],    TEXT_COLLECTING },
-    { EL_EDELSTEIN_ROT,        &level.score[SC_EDELSTEIN],     TEXT_COLLECTING },
-    { EL_EDELSTEIN_LILA,&level.score[SC_EDELSTEIN],    TEXT_COLLECTING },
-    { EL_DIAMANT,      &level.score[SC_DIAMANT],       TEXT_COLLECTING },
-    { EL_KAEFER_RIGHT, &level.score[SC_KAEFER],        TEXT_SMASHING },
-    { EL_KAEFER_UP,    &level.score[SC_KAEFER],        TEXT_SMASHING },
-    { EL_KAEFER_LEFT,  &level.score[SC_KAEFER],        TEXT_SMASHING },
-    { EL_KAEFER_DOWN,  &level.score[SC_KAEFER],        TEXT_SMASHING },
-    { EL_BUTTERFLY_RIGHT,&level.score[SC_KAEFER],      TEXT_SMASHING },
-    { EL_BUTTERFLY_UP, &level.score[SC_KAEFER],        TEXT_SMASHING },
-    { EL_BUTTERFLY_LEFT,&level.score[SC_KAEFER],       TEXT_SMASHING },
-    { EL_BUTTERFLY_DOWN,&level.score[SC_KAEFER],       TEXT_SMASHING },
-    { EL_FLIEGER_RIGHT,        &level.score[SC_FLIEGER],       TEXT_SMASHING },
-    { EL_FLIEGER_UP,   &level.score[SC_FLIEGER],       TEXT_SMASHING },
-    { EL_FLIEGER_LEFT, &level.score[SC_FLIEGER],       TEXT_SMASHING },
-    { EL_FLIEGER_DOWN, &level.score[SC_FLIEGER],       TEXT_SMASHING },
-    { EL_FIREFLY_RIGHT,        &level.score[SC_FLIEGER],       TEXT_SMASHING },
-    { EL_FIREFLY_UP,   &level.score[SC_FLIEGER],       TEXT_SMASHING },
-    { EL_FIREFLY_LEFT, &level.score[SC_FLIEGER],       TEXT_SMASHING },
-    { EL_FIREFLY_DOWN, &level.score[SC_FLIEGER],       TEXT_SMASHING },
-    { EL_MAMPFER,      &level.score[SC_MAMPFER],       TEXT_SMASHING },
-    { EL_MAMPFER2,     &level.score[SC_MAMPFER],       TEXT_SMASHING },
-    { EL_ROBOT,                &level.score[SC_ROBOT],         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_KOKOSNUSS,    &level.score[SC_KOKOSNUSS],     TEXT_CRACKING },
-    { EL_DYNAMITE_INACTIVE,&level.score[SC_DYNAMIT],   TEXT_COLLECTING },
-    { EL_SCHLUESSEL1,  &level.score[SC_SCHLUESSEL],    TEXT_COLLECTING },
-    { EL_SCHLUESSEL2,  &level.score[SC_SCHLUESSEL],    TEXT_COLLECTING },
-    { EL_SCHLUESSEL3,  &level.score[SC_SCHLUESSEL],    TEXT_COLLECTING },
-    { EL_SCHLUESSEL4,  &level.score[SC_SCHLUESSEL],    TEXT_COLLECTING },
-    { EL_EM_KEY_1_FILE,        &level.score[SC_SCHLUESSEL],    TEXT_COLLECTING },
-    { EL_EM_KEY_2_FILE,        &level.score[SC_SCHLUESSEL],    TEXT_COLLECTING },
-    { EL_EM_KEY_3_FILE,        &level.score[SC_SCHLUESSEL],    TEXT_COLLECTING },
-    { EL_EM_KEY_4_FILE,        &level.score[SC_SCHLUESSEL],    TEXT_COLLECTING },
-    { EL_AMOEBE_NASS,  &level.amoeba_speed,            TEXT_SPEED },
-    { EL_AMOEBE_NORM,  &level.amoeba_speed,            TEXT_SPEED },
-    { EL_AMOEBE_VOLL,  &level.amoeba_speed,            TEXT_SPEED },
-    { EL_AMOEBE_BD,    &level.amoeba_speed,            TEXT_SPEED },
-    { EL_MAGIC_WALL_OFF,&level.time_magic_wall,                TEXT_DURATION },
-    { EL_ABLENK_AUS,   &level.time_wheel,              TEXT_DURATION },
-    { -1, NULL, NULL }
-  };
-
-  ClearWindow();
-  UnmapLevelEditorWindowGadgets();
-
-  DrawText(SX + ED_SETTINGS2_XPOS, SY + ED_SETTINGS_YPOS,
-          "Element Settings", FS_BIG, FC_YELLOW);
-
-  /* draw some decorative border for the object */
-  for (y=0; y<3; y++)
-    for (x=0; x<3; x++)
-      DrawMiniElement(xstart + x , ystart + y, EL_ERDREICH);
-
-  ClearRectangle(drawto,
-                SX + xstart * MINI_TILEX + MINI_TILEX/2 - 1,
-                SY + ystart * MINI_TILEY + MINI_TILEY/2 - 1,
-                TILEX + 2, TILEY + 2);
+  int element;
+  int *value;
+  char *text;
+} 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_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_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_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_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_DARK_YAMYAM,    &level.score[SC_YAMYAM],        TEXT_SMASHING   },
+  { EL_ROBOT,          &level.score[SC_ROBOT],         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_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.score[SC_TIME_BONUS],    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_FILE,  &level.score[SC_KEY],           TEXT_COLLECTING },
+  { EL_EM_KEY_2_FILE,  &level.score[SC_KEY],           TEXT_COLLECTING },
+  { EL_EM_KEY_3_FILE,  &level.score[SC_KEY],           TEXT_COLLECTING },
+  { EL_EM_KEY_4_FILE,  &level.score[SC_KEY],           TEXT_COLLECTING },
+  { EL_AMOEBA_WET,     &level.amoeba_speed,            TEXT_SPEED      },
+  { EL_AMOEBA_DRY,     &level.amoeba_speed,            TEXT_SPEED      },
+  { EL_AMOEBA_FULL,    &level.amoeba_speed,            TEXT_SPEED      },
+  { EL_BD_AMOEBA,      &level.amoeba_speed,            TEXT_SPEED      },
+  { EL_MAGIC_WALL,     &level.time_magic_wall,         TEXT_DURATION   },
+  { EL_ROBOT_WHEEL,    &level.time_wheel,              TEXT_DURATION   },
+  { -1,                        NULL,                           NULL            }
+};
 
-  /* copy border to the right location */
-  BlitBitmap(drawto, drawto,
-            SX + xstart * MINI_TILEX,
-            SY + ystart * MINI_TILEY,
-            2 * TILEX, 2 * TILEY,
-            SX + xstart * MINI_TILEX - MINI_TILEX/2,
-            SY + ystart * MINI_TILEY - MINI_TILEY/2);
+static boolean checkPropertiesConfig()
+{
+  int i;
 
-  DrawGraphic(xstart/2, ystart/2, el2gfx(properties_element));
+  if (IS_GEM(properties_element) ||
+      IS_CUSTOM_ELEMENT(properties_element) ||
+      HAS_CONTENT(properties_element))
+    return TRUE;
+  else
+    for (i=0; elements_with_counter[i].element != -1; i++)
+      if (elements_with_counter[i].element == properties_element)
+       return TRUE;
 
-  /* copy the whole stuff to the definitive location */
-  BlitBitmap(drawto, drawto,
-            SX + xstart * MINI_TILEX - MINI_TILEX/2,
-            SY + ystart * MINI_TILEY - MINI_TILEY,
-            2 * TILEX, 2 * TILEY,
-            SX + xstart * MINI_TILEX - MINI_TILEX/2,
-            SY + ystart * MINI_TILEY - MINI_TILEY/2);
+  return FALSE;
+}
 
-  DrawTextF((xstart + 3) * MINI_TILEX, (ystart + 1) * MINI_TILEY,
-           font_color, getElementInfoText(properties_element));
+static void DrawPropertiesConfig()
+{
+  int i;
 
-  num_elements_in_level = 0;
-  for (y=0; y<lev_fieldy; y++) 
-    for (x=0; x<lev_fieldx; x++)
-      if (Feld[x][y] == properties_element)
-       num_elements_in_level++;
-  percentage = num_elements_in_level * 100.0 / (lev_fieldx * lev_fieldy);
+  if (!checkPropertiesConfig())
+  {
+    PrintInfoText("No configuration options available.", FONT_TEXT_1, 0);
 
-  DrawTextF(ED_SETTINGS_XPOS, 5 * TILEY, font_color, "In this level:");
-  DrawTextF(ED_SETTINGS_XPOS + 15 * FONT2_XSIZE, 5 * TILEY, FC_YELLOW,
-           "%d (%.2f%%)", num_elements_in_level, percentage);
+    return;
+  }
 
   /* check if there are elements where a score can be chosen for */
   for (i=0; elements_with_counter[i].element != -1; i++)
   {
     if (elements_with_counter[i].element == properties_element)
     {
-      int x = counterbutton_info[counter_id].x + xoffset_right;
-      int y = counterbutton_info[counter_id].y + yoffset_right;
+      int counter_id = ED_COUNTER_ID_ELEMENT_SCORE;
 
       counterbutton_info[counter_id].value = elements_with_counter[i].value;
-      DrawTextF(x, y, font_color, elements_with_counter[i].text);
-
-      ModifyEditorCounter(counter_id,  *counterbutton_info[counter_id].value);
+      counterbutton_info[counter_id].text_right= elements_with_counter[i].text;
       MapCounterButtons(counter_id);
+
       break;
     }
   }
@@ -2727,12 +5011,7 @@ static void DrawPropertiesWindow()
   {
     /* draw stickybutton gadget */
     i = ED_CHECKBUTTON_ID_STICK_ELEMENT;
-    x = checkbutton_info[i].x + xoffset_right2;
-    y = checkbutton_info[i].y + yoffset_right2;
-
-    DrawTextF(x, y, font_color, checkbutton_info[i].text);
-    ModifyGadget(level_editor_gadget[checkbutton_info[i].gadget_id],
-                GDI_CHECKED, *checkbutton_info[i].value, GDI_END);
+    checkbutton_info[i].y = ED_COUNTER_YPOS(4);
     MapCheckbuttonGadget(i);
 
     if (IS_AMOEBOID(properties_element))
@@ -2742,19 +5021,176 @@ static void DrawPropertiesWindow()
   }
 
   if (IS_GEM(properties_element))
+    MapCheckbuttonGadget(ED_CHECKBUTTON_ID_EM_SLIPPERY_GEMS);
+
+  if (IS_CUSTOM_ELEMENT(properties_element))
   {
-    /* draw checkbutton gadget */
-    i = ED_CHECKBUTTON_ID_EM_SLIPPERY_GEMS;
-    x = checkbutton_info[i].x + xoffset_right2;
-    y = checkbutton_info[i].y + yoffset_right2;
+    /* draw stickybutton gadget */
+    i = ED_CHECKBUTTON_ID_STICK_ELEMENT;
+    checkbutton_info[i].y = ED_SETTINGS_YPOS(0);
+    MapCheckbuttonGadget(i);
+
+    /* draw checkbutton gadgets */
+    for (i =  ED_CHECKBUTTON_ID_CUSTOM_FIRST;
+        i <= ED_CHECKBUTTON_ID_CUSTOM_LAST; i++)
+      MapCheckbuttonGadget(i);
+
+    /* draw counter gadgets */
+    for (i=ED_COUNTER_ID_CUSTOM_FIRST; i<=ED_COUNTER_ID_CUSTOM_LAST; i++)
+      MapCounterButtons(i);
+
+    /* draw selectbox gadgets */
+    for (i=ED_SELECTBOX_ID_CUSTOM_FIRST; i <= ED_SELECTBOX_ID_CUSTOM_LAST; i++)
+      MapSelectboxGadget(i);
+
+    /* draw drawing area gadgets */
+    DrawCustomContentArea();
+
+    /* draw text input gadgets */
+    MapTextInputGadget(ED_TEXTINPUT_ID_ELEMENT_NAME);
+  }
+}
+
+static void DrawPropertiesAdvancedDrawingAreas()
+{
+  DrawCustomGraphicElementArea();
+  DrawCustomChangeTargetArea();
+  DrawCustomChangeTriggerArea();
+  DrawCustomChangeContentArea();
+
+  redraw_mask |= REDRAW_FIELD;
+}
 
-    DrawTextF(x, y, font_color, checkbutton_info[i].text);
-    ModifyGadget(level_editor_gadget[checkbutton_info[i].gadget_id],
-                GDI_CHECKED, *checkbutton_info[i].value, GDI_END);
+static void DrawPropertiesAdvanced()
+{
+  int i;
+
+  /* draw stickybutton gadget */
+  i = ED_CHECKBUTTON_ID_STICK_ELEMENT;
+  checkbutton_info[i].y = ED_SETTINGS_YPOS(0);
+  MapCheckbuttonGadget(i);
+
+  /* draw checkbutton gadgets */
+  for (i =  ED_CHECKBUTTON_ID_CHANGE_FIRST;
+       i <= ED_CHECKBUTTON_ID_CHANGE_LAST; i++)
     MapCheckbuttonGadget(i);
+
+  /* draw counter gadgets */
+  for (i=ED_COUNTER_ID_CHANGE_FIRST; i<=ED_COUNTER_ID_CHANGE_LAST; i++)
+    MapCounterButtons(i);
+
+  /* draw selectbox gadgets */
+  for (i=ED_SELECTBOX_ID_CHANGE_FIRST; i<=ED_SELECTBOX_ID_CHANGE_LAST; i++)
+    MapSelectboxGadget(i);
+
+  /* draw textbutton gadgets */
+  MapTextbuttonGadget(ED_TEXTBUTTON_ID_SAVE_AS_TEMPLATE);
+
+  /* draw drawing area gadgets */
+  DrawPropertiesAdvancedDrawingAreas();
+}
+
+static void DrawElementName(int x, int y, int element)
+{
+  char *element_name = getElementInfoText(element);
+  int font_nr = FONT_TEXT_1;
+  int font_width = getFontWidth(font_nr);
+  int font_height = getFontHeight(font_nr);
+  int max_text_width = SXSIZE - x - ED_SETTINGS_XPOS(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)
+    DrawTextF(x, y, font_nr, element_name);
+  else
+  {
+    int next_pos = max_chars_per_line;
+
+    strncpy(buffer, element_name, max_chars_per_line);
+    buffer[max_chars_per_line] = '\0';
+
+    if (element_name[max_chars_per_line] == ' ')
+      next_pos++;
+    else
+    {
+      int i;
+
+      for (i = max_chars_per_line - 1; i >= 0; i--)
+       if (buffer[i] == ' ')
+         break;
+
+      if (strlen(&element_name[i + 1]) <= max_chars_per_line)
+      {
+       buffer[i] = '\0';
+       next_pos = i + 1;
+      }
+    }
+
+    DrawTextF(x, y - font_height / 2, font_nr, buffer);
+
+    strncpy(buffer, &element_name[next_pos], max_chars_per_line);
+    buffer[max_chars_per_line] = '\0';
+
+    DrawTextF(x, y + font_height / 2, font_nr, buffer);
   }
 }
 
+static void DrawPropertiesWindow()
+{
+  int xstart = 2;
+  int ystart = 4;
+
+  stick_element_properties_window = FALSE;
+
+  /* make sure that previous properties edit mode exists for this element */
+  if (edit_mode_properties == ED_MODE_PROPERTIES_ADVANCED &&
+      !IS_CUSTOM_ELEMENT(properties_element))
+    edit_mode_properties = ED_MODE_PROPERTIES_CONFIG;
+
+  if (IS_CUSTOM_ELEMENT(properties_element))
+    CopyCustomElementPropertiesToEditor(properties_element);
+
+  UnmapLevelEditorWindowGadgets();
+
+  SetMainBackgroundImage(IMG_BACKGROUND_EDITOR);
+  ClearWindow();
+
+  DrawText(SX + ED_SETTINGS2_XPOS, SY + ED_SETTINGS1_YPOS,
+          "Element Settings", FONT_TITLE_1);
+
+  DrawElementBorder(SX + xstart * MINI_TILEX,
+                   SY + ystart * MINI_TILEY + MINI_TILEY / 2,
+                   TILEX, TILEY, FALSE);
+  DrawGraphicAnimationExt(drawto,
+                         SX + xstart * MINI_TILEX,
+                         SY + ystart * MINI_TILEY + MINI_TILEY / 2,
+                         el2img(properties_element), -1, NO_MASKING);
+
+  FrameCounter = 0;    /* restart animation frame counter */
+
+  DrawElementName((xstart + 3) * MINI_TILEX, (ystart + 1) * MINI_TILEY,
+                 properties_element);
+
+  DrawPropertiesTabulatorGadgets();
+
+  if (edit_mode_properties == ED_MODE_PROPERTIES_INFO)
+    DrawPropertiesInfo();
+  else if (edit_mode_properties == ED_MODE_PROPERTIES_CONFIG)
+    DrawPropertiesConfig();
+  else /* edit_mode_properties == ED_MODE_PROPERTIES_ADVANCED */
+    DrawPropertiesAdvanced();
+}
+
+static void UpdateCustomElementGraphicGadgets()
+{
+  ModifyEditorElementList();
+  RedrawDrawingElements();
+
+  if (edit_mode == ED_MODE_PROPERTIES &&
+      edit_mode_properties == ED_MODE_PROPERTIES_ADVANCED)
+    DrawPropertiesAdvancedDrawingAreas();
+}
+
 static void DrawLineElement(int sx, int sy, int element, boolean change_level)
 {
   int lx = sx + level_xpos;
@@ -2826,8 +5262,8 @@ static void DrawLine(int from_x, int from_y, int to_x, int to_y,
   }
 }
 
-static void DrawRectangle(int from_x, int from_y, int to_x, int to_y,
-                         int element, boolean change_level)
+static void DrawBox(int from_x, int from_y, int to_x, int to_y,
+                   int element, boolean change_level)
 {
   DrawLine(from_x, from_y, from_x, to_y, element, change_level);
   DrawLine(from_x, to_y, to_x, to_y, element, change_level);
@@ -2949,7 +5385,7 @@ static void SelectArea(int from_x, int from_y, int to_x, int to_y,
                       int element, boolean change_level)
 {
   if (element == -1 || change_level)
-    DrawRectangle(from_x, from_y, to_x, to_y, -1, FALSE);
+    DrawBox(from_x, from_y, to_x, to_y, -1, FALSE);
   else
     DrawAreaBorder(from_x, from_y, to_x, to_y);
 }
@@ -3137,13 +5573,13 @@ static int DrawLevelText(int sx, int sy, char letter, int mode)
   if (letter >= 'a' && letter <= 'z')
     letter_element = EL_CHAR_ASCII0 + letter + (int)('A' - 'a');
   else if (letter == 'ä' || letter == 'Ä')
-    letter_element = EL_CHAR_AE;
+    letter_element = EL_CHAR_AUMLAUT;
   else if (letter == 'ö' || letter == 'Ö')
-    letter_element = EL_CHAR_OE;
+    letter_element = EL_CHAR_OUMLAUT;
   else if (letter == 'ü' || letter == 'Ãœ')
-    letter_element = EL_CHAR_UE;
+    letter_element = EL_CHAR_UUMLAUT;
   else if (letter == '^')
-    letter_element = EL_CHAR_COPY;
+    letter_element = EL_CHAR_COPYRIGHT;
   else
     letter_element = EL_CHAR_ASCII0 + letter;
 
@@ -3281,12 +5717,6 @@ static void CopyLevelToUndoBuffer(int mode)
   SetBorderElement();
   if (BorderElement != last_border_element)
     DrawMiniLevel(ed_fieldx, ed_fieldy, level_xpos, level_ypos);
-
-#if 0
-#ifdef DEBUG
-  printf("level saved to undo buffer\n");
-#endif
-#endif
 }
 
 static void RandomPlacement(int new_element)
@@ -3377,6 +5807,7 @@ static void HandleDrawingAreas(struct GadgetInfo *gi)
   int sx = gi->event.x, sy = gi->event.y;
   int min_sx = 0, min_sy = 0;
   int max_sx = gi->drawing.area_xsize - 1, max_sy = gi->drawing.area_ysize - 1;
+  int item_xsize = gi->drawing.item_xsize, item_ysize = gi->drawing.item_ysize;
   int lx = 0, ly = 0;
   int min_lx = 0, min_ly = 0;
   int max_lx = lev_fieldx - 1, max_ly = lev_fieldy - 1;
@@ -3421,7 +5852,12 @@ static void HandleDrawingAreas(struct GadgetInfo *gi)
 
   /* automatically switch to 'single item' drawing mode, if needed */
   actual_drawing_function =
-    (draw_level ? drawing_function : GADGET_ID_SINGLE_ITEMS);
+    (draw_level || drawing_function == GADGET_ID_PICK_ELEMENT ?
+     drawing_function : GADGET_ID_SINGLE_ITEMS);
+
+  /* clicking into drawing area with pressed Control key picks element */
+  if (GetKeyModState() & KMOD_Control)
+    actual_drawing_function = GADGET_ID_PICK_ELEMENT;
 
   switch (actual_drawing_function)
   {
@@ -3447,20 +5883,20 @@ static void HandleDrawingAreas(struct GadgetInfo *gi)
        }
        else if (new_element != Feld[lx][ly])
        {
-         if (new_element == EL_SPIELFIGUR)
+         if (new_element == EL_PLAYER_1)
          {
            /* remove player at old position */
            for(y=0; y<lev_fieldy; y++)
            {
              for(x=0; x<lev_fieldx; x++)
              {
-               if (Feld[x][y] == EL_SPIELFIGUR || Feld[x][y] == EL_SPIELER1)
+               if (Feld[x][y] == EL_PLAYER_1)
                {
-                 Feld[x][y] = EL_LEERRAUM;
+                 Feld[x][y] = EL_EMPTY;
                  if (x - level_xpos >= 0 && x - level_xpos < ed_fieldx &&
                      y - level_ypos >= 0 && y - level_ypos < ed_fieldy)
                    DrawMiniElement(x - level_xpos, y - level_ypos,
-                                   EL_LEERRAUM);
+                                   EL_EMPTY);
                }
              }
            }
@@ -3472,22 +5908,59 @@ static void HandleDrawingAreas(struct GadgetInfo *gi)
       }
       else
       {
-       DrawMiniGraphicExt(drawto,
-                          gi->x + sx * MINI_TILEX,
-                          gi->y + sy * MINI_TILEY,
-                          el2gfx(new_element));
-       DrawMiniGraphicExt(window,
-                          gi->x + sx * MINI_TILEX,
-                          gi->y + sy * MINI_TILEY,
-                          el2gfx(new_element));
+       if (item_xsize == MINI_TILEX && item_ysize == MINI_TILEY)
+         DrawMiniGraphicExt(drawto,
+                            gi->x + sx * MINI_TILEX,
+                            gi->y + sy * MINI_TILEY,
+                            el2edimg(new_element));
+       else
+         DrawGraphicExt(drawto,
+                        gi->x + sx * TILEX,
+                        gi->y + sy * TILEY,
+                        el2img(new_element), 0);
 
        if (id == GADGET_ID_AMOEBA_CONTENT)
          level.amoeba_content = new_element;
+       else if (id == GADGET_ID_CUSTOM_GRAPHIC)
+       {
+         new_element = GFX_ELEMENT(new_element);
+         custom_element.gfx_element = new_element;
+
+         CopyCustomElementPropertiesToGame(properties_element);
+
+         UpdateCustomElementGraphicGadgets();
+
+         FrameCounter = 0;     /* restart animation frame counter */
+       }
+       else if (id == GADGET_ID_CUSTOM_CONTENT)
+       {
+         custom_element.content[sx][sy] = new_element;
+
+         CopyCustomElementPropertiesToGame(properties_element);
+       }
+       else if (id == GADGET_ID_CUSTOM_CHANGE_TARGET)
+       {
+         custom_element.change.target_element = new_element;
+
+         CopyCustomElementPropertiesToGame(properties_element);
+       }
+       else if (id == GADGET_ID_CUSTOM_CHANGE_CONTENT)
+       {
+         custom_element.change.content[sx][sy] = new_element;
+
+         CopyCustomElementPropertiesToGame(properties_element);
+       }
+       else if (id == GADGET_ID_CUSTOM_CHANGE_TRIGGER)
+       {
+         custom_element.change.trigger_element = new_element;
+
+         CopyCustomElementPropertiesToGame(properties_element);
+       }
        else if (id == GADGET_ID_RANDOM_BACKGROUND)
          random_placement_background_element = new_element;
-       else if (id >= GADGET_ID_ELEM_CONTENT_0 &&
-                id <= GADGET_ID_ELEM_CONTENT_7)
-         level.yam_content[id - GADGET_ID_ELEM_CONTENT_0][sx][sy] =
+       else if (id >= GADGET_ID_ELEMENT_CONTENT_0 &&
+                id <= GADGET_ID_ELEMENT_CONTENT_7)
+         level.yamyam_content[id - GADGET_ID_ELEMENT_CONTENT_0][sx][sy] =
            new_element;
       }
       break;
@@ -3529,7 +6002,7 @@ static void HandleDrawingAreas(struct GadgetInfo *gi)
        else if (drawing_function == GADGET_ID_ARC)
          draw_func = DrawArc;
        else if (drawing_function == GADGET_ID_RECTANGLE)
-         draw_func = DrawRectangle;
+         draw_func = DrawBox;
        else if (drawing_function == GADGET_ID_FILLED_BOX)
          draw_func = DrawFilledBox;
        else if (drawing_function == GADGET_ID_GRAB_BRUSH)
@@ -3585,8 +6058,29 @@ static void HandleDrawingAreas(struct GadgetInfo *gi)
       if (button_release_event)
        ClickOnGadget(level_editor_gadget[last_drawing_function],
                      MB_LEFTBUTTON);
-      else
+      else if (draw_level)
        PickDrawingElement(button, Feld[lx][ly]);
+      else if (id == GADGET_ID_AMOEBA_CONTENT)
+       PickDrawingElement(button, level.amoeba_content);
+      else if (id == GADGET_ID_CUSTOM_GRAPHIC)
+       PickDrawingElement(button, custom_element.gfx_element);
+      else if (id == GADGET_ID_CUSTOM_CONTENT)
+       PickDrawingElement(button, custom_element.content[sx][sy]);
+      else if (id == GADGET_ID_CUSTOM_CHANGE_TARGET)
+       PickDrawingElement(button, custom_element.change.target_element);
+      else if (id == GADGET_ID_CUSTOM_CHANGE_CONTENT)
+       PickDrawingElement(button, custom_element.change.content[sx][sy]);
+      else if (id == GADGET_ID_CUSTOM_CHANGE_TRIGGER)
+       PickDrawingElement(button, custom_element.change.trigger_element);
+      else if (id == GADGET_ID_RANDOM_BACKGROUND)
+       PickDrawingElement(button, random_placement_background_element);
+      else if (id >= GADGET_ID_ELEMENT_CONTENT_0 &&
+              id <= GADGET_ID_ELEMENT_CONTENT_7)
+      {
+       int i = id - GADGET_ID_ELEMENT_CONTENT_0;
+
+       PickDrawingElement(button, level.yamyam_content[i][sx][sy]);
+      }
 
       break;
 
@@ -3629,7 +6123,7 @@ static void HandleCounterButtons(struct GadgetInfo *gi)
 
   switch (counter_id)
   {
-    case ED_COUNTER_ID_ELEM_CONTENT:
+    case ED_COUNTER_ID_ELEMENT_CONTENT:
       DrawElementContentAreas();
       break;
 
@@ -3649,11 +6143,64 @@ static void HandleCounterButtons(struct GadgetInfo *gi)
     default:
       break;
   }
+
+  if ((counter_id >= ED_COUNTER_ID_CUSTOM_FIRST &&
+       counter_id <= ED_COUNTER_ID_CUSTOM_LAST) ||
+      (counter_id >= ED_COUNTER_ID_CHANGE_FIRST &&
+       counter_id <= ED_COUNTER_ID_CHANGE_LAST))
+    CopyCustomElementPropertiesToGame(properties_element);
 }
 
 static void HandleTextInputGadgets(struct GadgetInfo *gi)
 {
-  strcpy(textinput_info[gi->custom_type_id].value, gi->text.value);
+  int type_id = gi->custom_type_id;
+
+  strcpy(textinput_info[type_id].value, gi->text.value);
+
+  if (type_id == ED_TEXTINPUT_ID_ELEMENT_NAME)
+  {
+    CopyCustomElementPropertiesToGame(properties_element);
+
+    ModifyEditorElementList(); /* update changed button info text */
+  }
+}
+
+static void HandleSelectboxGadgets(struct GadgetInfo *gi)
+{
+  int type_id = gi->custom_type_id;
+
+  *selectbox_info[type_id].value =
+    selectbox_info[type_id].options[gi->selectbox.index].value;
+
+  if ((type_id >= ED_SELECTBOX_ID_CUSTOM_FIRST &&
+       type_id <= ED_SELECTBOX_ID_CUSTOM_LAST) ||
+      (type_id >= ED_SELECTBOX_ID_CHANGE_FIRST &&
+       type_id <= ED_SELECTBOX_ID_CHANGE_LAST))
+    CopyCustomElementPropertiesToGame(properties_element);
+}
+
+static void HandleTextbuttonGadgets(struct GadgetInfo *gi)
+{
+  int type_id = gi->custom_type_id;
+
+  if (type_id >= ED_TEXTBUTTON_ID_PROPERTIES_INFO &&
+      type_id <= ED_TEXTBUTTON_ID_PROPERTIES_ADVANCED)
+  {
+    edit_mode_properties = gi->custom_type_id;
+
+    DrawPropertiesWindow();
+  }
+  else if (type_id == ED_TEXTBUTTON_ID_SAVE_AS_TEMPLATE)
+  {
+    boolean new_template = (!LevelFileExists(-1));
+
+    if (new_template ||
+       Request("Save this tem- plate and kill the old ?", REQ_ASK))
+      SaveLevelTemplate();
+
+    if (new_template)
+      Request("Tem- plate saved !", REQ_CONFIRM);
+  }
 }
 
 static void HandleRadiobuttons(struct GadgetInfo *gi)
@@ -3664,7 +6211,39 @@ static void HandleRadiobuttons(struct GadgetInfo *gi)
 
 static void HandleCheckbuttons(struct GadgetInfo *gi)
 {
-  *checkbutton_info[gi->custom_type_id].value ^= TRUE;
+  int type_id = gi->custom_type_id;
+
+  *checkbutton_info[type_id].value ^= TRUE;
+
+  if ((type_id >= ED_CHECKBUTTON_ID_CUSTOM_FIRST &&
+       type_id <= ED_CHECKBUTTON_ID_CUSTOM_LAST) ||
+      (type_id >= ED_CHECKBUTTON_ID_CHANGE_FIRST &&
+       type_id <= ED_CHECKBUTTON_ID_CHANGE_LAST &&
+       type_id != ED_CHECKBUTTON_ID_CUSTOM_USE_TEMPLATE))
+  {
+    CopyCustomElementPropertiesToGame(properties_element);
+  }
+
+  if (type_id == ED_CHECKBUTTON_ID_CUSTOM_USE_GRAPHIC)
+  {
+    UpdateCustomElementGraphicGadgets();
+  }
+  else if (type_id == ED_CHECKBUTTON_ID_CUSTOM_USE_TEMPLATE)
+  {
+    if (level.use_custom_template && !LevelFileExists(-1))
+    {
+      Request("No level tem- plate found !", REQ_CONFIRM);
+
+      level.use_custom_template = FALSE;
+      ModifyGadget(gi, GDI_CHECKED, FALSE, GDI_END);
+
+      return;
+    }
+
+    LoadLevelTemplate(level.use_custom_template ? -1 : level_nr);
+
+    DrawEditModeWindow();
+  }
 }
 
 static void HandleControlButtons(struct GadgetInfo *gi)
@@ -3673,13 +6252,15 @@ static void HandleControlButtons(struct GadgetInfo *gi)
   int button = gi->event.button;
   int step = BUTTON_STEPSIZE(button);
   int new_element = BUTTON_ELEMENT(button);
-  int i, x, y;
+  int x, y;
 
   if (edit_mode == ED_MODE_DRAWING && drawing_function == GADGET_ID_TEXT)
     DrawLevelText(0, 0, 0, TEXT_END);
 
   if (id < ED_NUM_CTRL1_BUTTONS && id != GADGET_ID_PROPERTIES &&
-      edit_mode != ED_MODE_DRAWING)
+      id != GADGET_ID_PICK_ELEMENT && edit_mode != ED_MODE_DRAWING &&
+      drawing_function != GADGET_ID_PICK_ELEMENT &&
+      !(GetKeyModState() & KMOD_Control))
   {
     DrawDrawingWindow();
     edit_mode = ED_MODE_DRAWING;
@@ -3785,26 +6366,16 @@ static void HandleControlButtons(struct GadgetInfo *gi)
 
        if (element_shift < 0)
          element_shift = 0;
-       if (element_shift > elements_in_list - ED_NUM_ELEMENTLIST_BUTTONS)
-         element_shift = elements_in_list - ED_NUM_ELEMENTLIST_BUTTONS;
+       if (element_shift > num_editor_elements - ED_NUM_ELEMENTLIST_BUTTONS)
+         element_shift = num_editor_elements - ED_NUM_ELEMENTLIST_BUTTONS;
 
        ModifyGadget(level_editor_gadget[GADGET_ID_SCROLL_LIST_VERTICAL],
                     GDI_SCROLLBAR_ITEM_POSITION,
                     element_shift / ED_ELEMENTLIST_BUTTONS_HORIZ, GDI_END);
       }
 
-      for (i=0; i<ED_NUM_ELEMENTLIST_BUTTONS; i++)
-      {
-       int gadget_id = GADGET_ID_ELEMENTLIST_FIRST + i;
-       struct GadgetInfo *gi = level_editor_gadget[gadget_id];
-       struct GadgetDesign *gd = &gi->deco.design;
-       int element = editor_element[element_shift + i];
-
-       UnmapGadget(gi);
-       getMiniGraphicSource(el2gfx(element), &gd->bitmap, &gd->x, &gd->y);
-       ModifyGadget(gi, GDI_INFO_TEXT, getElementInfoText(element), GDI_END);
-       MapGadget(gi);
-      }
+      ModifyEditorElementList();
+
       break;
 
     case GADGET_ID_WRAP_LEFT:
@@ -3833,7 +6404,8 @@ static void HandleControlButtons(struct GadgetInfo *gi)
     case GADGET_ID_FLOOD_FILL:
     case GADGET_ID_GRAB_BRUSH:
     case GADGET_ID_PICK_ELEMENT:
-      last_drawing_function = drawing_function;
+      if (drawing_function != GADGET_ID_PICK_ELEMENT)
+       last_drawing_function = drawing_function;
       drawing_function = id;
       draw_with_brush = FALSE;
       break;
@@ -3863,6 +6435,12 @@ static void HandleControlButtons(struct GadgetInfo *gi)
        break;
       }
 
+      if (edit_mode != ED_MODE_DRAWING)
+      {
+       DrawDrawingWindow();
+       edit_mode = ED_MODE_DRAWING;
+      }
+
       undo_buffer_position =
        (undo_buffer_position - 1 + NUM_UNDO_STEPS) % NUM_UNDO_STEPS;
       undo_buffer_steps--;
@@ -3887,9 +6465,15 @@ static void HandleControlButtons(struct GadgetInfo *gi)
       break;
 
     case GADGET_ID_CLEAR:
+      if (edit_mode != ED_MODE_DRAWING)
+      {
+       DrawDrawingWindow();
+       edit_mode = ED_MODE_DRAWING;
+      }
+
       for(x=0; x<MAX_LEV_FIELDX; x++) 
        for(y=0; y<MAX_LEV_FIELDY; y++) 
-         Feld[x][y] = (button == 1 ? EL_LEERRAUM : new_element);
+         Feld[x][y] = (button == 1 ? EL_EMPTY : new_element);
       CopyLevelToUndoBuffer(GADGET_ID_CLEAR);
 
       DrawMiniLevel(ed_fieldx, ed_fieldy, level_xpos, level_ypos);
@@ -3906,13 +6490,18 @@ static void HandleControlButtons(struct GadgetInfo *gi)
        Request("No Level without Gregor Mc Duffin please !", REQ_CONFIRM);
       else
       {
-       if (Request("Save this level and kill the old ?", REQ_ASK))
+       boolean new_level = (!LevelFileExists(level_nr));
+
+       if (new_level ||
+           Request("Save this level and kill the old ?", REQ_ASK))
        {
-         for(x=0; x<lev_fieldx; x++)
-           for(y=0; y<lev_fieldy; y++) 
-             Ur[x][y] = Feld[x][y];
+         CopyPlayfield(Feld, level.field);
+
          SaveLevel(level_nr);
        }
+
+       if (new_level)
+         Request("Level saved !", REQ_CONFIRM);
       }
       break;
 
@@ -3924,13 +6513,8 @@ static void HandleControlButtons(struct GadgetInfo *gi)
        if (LevelChanged())
          level.game_version = GAME_VERSION_ACTUAL;
 
-       for(x=0; x<lev_fieldx; x++)
-         for(y=0; y<lev_fieldy; y++)
-           FieldBackup[x][y] = Ur[x][y];
-
-       for(x=0; x<lev_fieldx; x++)
-         for(y=0; y<lev_fieldy; y++)
-           Ur[x][y] = Feld[x][y];
+       CopyPlayfield(level.field, FieldBackup);
+       CopyPlayfield(Feld, level.field);
 
        UnmapLevelEditorGadgets();
        UndrawSpecialEditorDoor();
@@ -3943,7 +6527,7 @@ static void HandleControlButtons(struct GadgetInfo *gi)
          TapeStartRecording();
 
        level_editor_test_game = TRUE;
-       game_status = PLAYING;
+       game_status = GAME_MODE_PLAYING;
 
        InitGame();
       }
@@ -3958,12 +6542,13 @@ static void HandleControlButtons(struct GadgetInfo *gi)
          id <= GADGET_ID_ELEMENTLIST_LAST)
       {
        int element_position = id - GADGET_ID_ELEMENTLIST_FIRST;
-       int new_element = editor_element[element_position + element_shift];
+       int new_element = editor_elements[element_position + element_shift];
 
        PickDrawingElement(button, new_element);
 
-       if (!HAS_CONTENT(properties_element) ||
-           !stick_element_properties_window)
+       if (!stick_element_properties_window &&
+           drawing_function != GADGET_ID_PICK_ELEMENT &&
+           !(GetKeyModState() & KMOD_Control))
        {
          properties_element = new_element;
          if (edit_mode == ED_MODE_PROPERTIES)
@@ -4062,20 +6647,42 @@ void HandleLevelEditorKeyInput(Key key)
   }
 }
 
+void HandleLevelEditorIdle()
+{
+  static unsigned long action_delay = 0;
+  unsigned long action_delay_value = GameFrameDelay;
+  int xpos = 1, ypos = 2;
+
+  if (edit_mode != ED_MODE_PROPERTIES)
+    return;
+
+  if (!DelayReached(&action_delay, action_delay_value))
+    return;
+
+  DrawGraphicAnimationExt(drawto,
+                         SX + xpos * TILEX,
+                         SY + ypos * TILEY + MINI_TILEY / 2,
+                         el2img(properties_element), -1, NO_MASKING);
+
+  MarkTileDirty(xpos, ypos);
+  MarkTileDirty(xpos, ypos + 1);
+
+  FrameCounter++;      /* increase animation frame counter */
+}
+
 void ClearEditorGadgetInfoText()
 {
-  ClearRectangle(drawto,
-                INFOTEXT_XPOS, INFOTEXT_YPOS, INFOTEXT_XSIZE, INFOTEXT_YSIZE);
-  redraw_mask |= REDRAW_FIELD;
+  DrawBackground(INFOTEXT_XPOS, INFOTEXT_YPOS, INFOTEXT_XSIZE, INFOTEXT_YSIZE);
 }
 
 void HandleEditorGadgetInfoText(void *ptr)
 {
   struct GadgetInfo *gi = (struct GadgetInfo *)ptr;
-  char infotext[MAX_INFOTEXT_LEN + 1];
-  char shortcut[MAX_INFOTEXT_LEN + 1];
+  char infotext[MAX_OUTPUT_LINESIZE + 1];
+  char shortcut[MAX_OUTPUT_LINESIZE + 1];
+  int max_infotext_len = getMaxInfoTextLength();
 
-  if (game_status != LEVELED)
+  if (game_status != GAME_MODE_EDITOR)
     return;
 
   ClearEditorGadgetInfoText();
@@ -4090,8 +6697,8 @@ void HandleEditorGadgetInfoText(void *ptr)
   if (gi == NULL || gi->info_text == NULL)
     return;
 
-  strncpy(infotext, gi->info_text, MAX_INFOTEXT_LEN);
-  infotext[MAX_INFOTEXT_LEN] = '\0';
+  strncpy(infotext, gi->info_text, max_infotext_len);
+  infotext[max_infotext_len] = '\0';
 
   if (gi->custom_id < ED_NUM_CTRL_BUTTONS)
   {
@@ -4101,18 +6708,20 @@ void HandleEditorGadgetInfoText(void *ptr)
     {
       if (gi->custom_id == GADGET_ID_SINGLE_ITEMS)     /* special case 1 */
        sprintf(shortcut, " ('.' or '%c')", key);
-      else if (gi->custom_id == GADGET_ID_TEST)                /* special case 2 */
+      else if (gi->custom_id == GADGET_ID_PICK_ELEMENT)        /* special case 2 */
+       sprintf(shortcut, " ('%c' or 'Ctrl')", key);
+      else if (gi->custom_id == GADGET_ID_TEST)                /* special case 3 */
        sprintf(shortcut, " ('Enter' or 'Shift-%c')", key);
       else                                             /* normal case */
        sprintf(shortcut, " ('%s%c')",
                (key >= 'A' && key <= 'Z' ? "Shift-" : ""), key);
 
-      if (strlen(infotext) + strlen(shortcut) <= MAX_INFOTEXT_LEN)
+      if (strlen(infotext) + strlen(shortcut) <= max_infotext_len)
        strcat(infotext, shortcut);
     }
   }
 
-  DrawText(INFOTEXT_XPOS, INFOTEXT_YPOS, infotext, FS_SMALL, FC_YELLOW);
+  DrawText(INFOTEXT_XPOS, INFOTEXT_YPOS, infotext, FONT_TEXT_2);
 }
 
 static void HandleDrawingAreaInfo(struct GadgetInfo *gi)
@@ -4127,6 +6736,11 @@ static void HandleDrawingAreaInfo(struct GadgetInfo *gi)
   int min_sx = 0, min_sy = 0;
   int max_sx = gi->drawing.area_xsize - 1;
   int max_sy = gi->drawing.area_ysize - 1;
+  int actual_drawing_function = drawing_function;
+
+  /* pressed Control key: simulate picking element */
+  if (GetKeyModState() & KMOD_Control)
+    actual_drawing_function = GADGET_ID_PICK_ELEMENT;
 
   ClearEditorGadgetInfoText();
 
@@ -4167,7 +6781,7 @@ static void HandleDrawingAreaInfo(struct GadgetInfo *gi)
          start_ly = ly;
        }
 
-       switch (drawing_function)
+       switch (actual_drawing_function)
        {
          case GADGET_ID_SINGLE_ITEMS:
            infotext = "Drawing single items";
@@ -4205,19 +6819,19 @@ static void HandleDrawingAreaInfo(struct GadgetInfo *gi)
            break;
        }
 
-       if (drawing_function == GADGET_ID_PICK_ELEMENT)
-         DrawTextF(INFOTEXT_XPOS - SX, INFOTEXT_YPOS - SY, FC_YELLOW,
+       if (actual_drawing_function == GADGET_ID_PICK_ELEMENT)
+         DrawTextF(INFOTEXT_XPOS - SX, INFOTEXT_YPOS - SY, FONT_TEXT_2,
                    "%s: %d, %d", infotext, lx, ly);
        else
-         DrawTextF(INFOTEXT_XPOS - SX, INFOTEXT_YPOS - SY, FC_YELLOW,
+         DrawTextF(INFOTEXT_XPOS - SX, INFOTEXT_YPOS - SY, FONT_TEXT_2,
                    "%s: %d, %d", infotext,
                    ABS(lx - start_lx) + 1, ABS(ly - start_ly) + 1);
       }
-      else if (drawing_function == GADGET_ID_PICK_ELEMENT)
-       DrawTextF(INFOTEXT_XPOS - SX, INFOTEXT_YPOS - SY, FC_YELLOW,
+      else if (actual_drawing_function == GADGET_ID_PICK_ELEMENT)
+       DrawTextF(INFOTEXT_XPOS - SX, INFOTEXT_YPOS - SY, FONT_TEXT_2,
                  "%s", getElementInfoText(Feld[lx][ly]));
       else
-       DrawTextF(INFOTEXT_XPOS - SX, INFOTEXT_YPOS - SY, FC_YELLOW,
+       DrawTextF(INFOTEXT_XPOS - SX, INFOTEXT_YPOS - SY, FONT_TEXT_2,
                  "Level position: %d, %d", lx, ly);
     }
 
@@ -4230,16 +6844,67 @@ static void HandleDrawingAreaInfo(struct GadgetInfo *gi)
        DeleteBrushFromCursor();
     }
   }
-  else if (id == GADGET_ID_AMOEBA_CONTENT)
-    DrawTextF(INFOTEXT_XPOS - SX, INFOTEXT_YPOS - SY, FC_YELLOW,
-             "Amoeba content");
-  else if (id == GADGET_ID_RANDOM_BACKGROUND)
-    DrawTextF(INFOTEXT_XPOS - SX, INFOTEXT_YPOS - SY, FC_YELLOW,
-             "Random placement background");
+  else if (actual_drawing_function == GADGET_ID_PICK_ELEMENT)
+  {
+    if (id == GADGET_ID_AMOEBA_CONTENT)
+      DrawTextF(INFOTEXT_XPOS - SX, INFOTEXT_YPOS - SY, FONT_TEXT_2, "%s",
+               getElementInfoText(level.amoeba_content));
+    else if (id == GADGET_ID_CUSTOM_GRAPHIC)
+      DrawTextF(INFOTEXT_XPOS - SX, INFOTEXT_YPOS - SY, FONT_TEXT_2, "%s",
+               getElementInfoText(custom_element.gfx_element));
+    else if (id == GADGET_ID_CUSTOM_CONTENT)
+      DrawTextF(INFOTEXT_XPOS - SX, INFOTEXT_YPOS - SY, FONT_TEXT_2, "%s",
+               getElementInfoText(custom_element.content[sx][sy]));
+    else if (id == GADGET_ID_CUSTOM_CHANGE_TARGET)
+      DrawTextF(INFOTEXT_XPOS - SX, INFOTEXT_YPOS - SY, FONT_TEXT_2, "%s",
+               getElementInfoText(custom_element.change.target_element));
+    else if (id == GADGET_ID_CUSTOM_CHANGE_CONTENT)
+      DrawTextF(INFOTEXT_XPOS - SX, INFOTEXT_YPOS - SY, FONT_TEXT_2, "%s",
+               getElementInfoText(custom_element.change.content[sx][sy]));
+    else if (id == GADGET_ID_CUSTOM_CHANGE_TRIGGER)
+      DrawTextF(INFOTEXT_XPOS - SX, INFOTEXT_YPOS - SY, FONT_TEXT_2, "%s",
+               getElementInfoText(custom_element.change.trigger_element));
+    else if (id == GADGET_ID_RANDOM_BACKGROUND)
+      DrawTextF(INFOTEXT_XPOS - SX, INFOTEXT_YPOS - SY, FONT_TEXT_2, "%s",
+               getElementInfoText(random_placement_background_element));
+    else if (id >= GADGET_ID_ELEMENT_CONTENT_0 &&
+            id <= GADGET_ID_ELEMENT_CONTENT_7)
+    {
+      int i = id - GADGET_ID_ELEMENT_CONTENT_0;
+
+      DrawTextF(INFOTEXT_XPOS - SX, INFOTEXT_YPOS - SY, FONT_TEXT_2, "%s",
+               getElementInfoText(level.yamyam_content[i][sx][sy]));
+    }
+  }
   else
-    DrawTextF(INFOTEXT_XPOS - SX, INFOTEXT_YPOS - SY, FC_YELLOW,
-             "Content area %d position: %d, %d",
-             id - GADGET_ID_ELEM_CONTENT_0 + 1, sx, sy);
+  {
+    if (id == GADGET_ID_AMOEBA_CONTENT)
+      DrawTextF(INFOTEXT_XPOS - SX, INFOTEXT_YPOS - SY, FONT_TEXT_2,
+               "Amoeba content");
+    else if (id == GADGET_ID_CUSTOM_GRAPHIC)
+      DrawTextF(INFOTEXT_XPOS - SX, INFOTEXT_YPOS - SY, FONT_TEXT_2,
+               "Custom graphic element");
+    else if (id == GADGET_ID_CUSTOM_CONTENT)
+      DrawTextF(INFOTEXT_XPOS - SX, INFOTEXT_YPOS - SY, FONT_TEXT_2,
+               "Custom element content position: %d, %d", sx, sy);
+    else if (id == GADGET_ID_CUSTOM_CHANGE_TARGET)
+      DrawTextF(INFOTEXT_XPOS - SX, INFOTEXT_YPOS - SY, FONT_TEXT_2,
+               "New element after change");
+    else if (id == GADGET_ID_CUSTOM_CHANGE_CONTENT)
+      DrawTextF(INFOTEXT_XPOS - SX, INFOTEXT_YPOS - SY, FONT_TEXT_2,
+               "New extended elements after change");
+    else if (id == GADGET_ID_CUSTOM_CHANGE_TRIGGER)
+      DrawTextF(INFOTEXT_XPOS - SX, INFOTEXT_YPOS - SY, FONT_TEXT_2,
+               "Other element triggering change");
+    else if (id == GADGET_ID_RANDOM_BACKGROUND)
+      DrawTextF(INFOTEXT_XPOS - SX, INFOTEXT_YPOS - SY, FONT_TEXT_2,
+               "Random placement background");
+    else if (id >= GADGET_ID_ELEMENT_CONTENT_0 &&
+            id <= GADGET_ID_ELEMENT_CONTENT_7)
+      DrawTextF(INFOTEXT_XPOS - SX, INFOTEXT_YPOS - SY, FONT_TEXT_2,
+               "Content area %d position: %d, %d",
+               id - GADGET_ID_ELEMENT_CONTENT_0 + 1, sx, sy);
+  }
 }
 
 void RequestExitLevelEditor(boolean ask_if_level_has_changed)
@@ -4253,13 +6918,13 @@ void RequestExitLevelEditor(boolean ask_if_level_has_changed)
     /*
     CloseDoor(DOOR_CLOSE_ALL);
     */
-    game_status = MAINMENU;
+    game_status = GAME_MODE_MAIN;
     DrawMainMenu();
   }
   else
   {
     CloseDoor(DOOR_CLOSE_1);
-    BlitBitmap(pix[PIX_DB_DOOR], pix[PIX_DB_DOOR],
+    BlitBitmap(bitmap_db_door, bitmap_db_door,
               DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY1, DXSIZE,DYSIZE,
               DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
     OpenDoor(DOOR_OPEN_1);
index 7966bda17b2a315539162db11d50cb6aba62c831..3213c4528fdbc101e3c8d40dbddf96475683fdfb 100644 (file)
@@ -25,9 +25,11 @@ extern int editor_element[];
 extern int elements_in_list;
 
 void CreateLevelEditorGadgets();
+void FreeLevelEditorGadgets();
 void UnmapLevelEditorGadgets();
 void DrawLevelEd(void);
 void HandleLevelEditorKeyInput(Key);
+void HandleLevelEditorIdle();
 void HandleEditorGadgetInfoText(void *ptr);
 void RequestExitLevelEditor(boolean);
 
index fc6140fc84a0c959d5eaaeb5966acdd1c3fa2d95..0dec9df9a52d62b89705f83f9ac61f39f4c560c6 100644 (file)
 #include "tape.h"
 #include "network.h"
 
-/* values for key_status */
-#define KEY_NOT_PRESSED                FALSE
-#define KEY_RELEASED           FALSE
-#define KEY_PRESSED            TRUE
+
+static boolean cursor_inside_playfield = FALSE;
+static boolean playfield_cursor_set = FALSE;
+static unsigned long playfield_cursor_delay = 0;
 
 
 /* event filter especially needed for SDL event filtering due to
-   delay problems with lots of mouse motion events when mouse
-   button not pressed */
+   delay problems with lots of mouse motion events when mouse button
+   not pressed (X11 can handle this with 'PointerMotionHintMask') */
 
 int FilterMouseMotionEvents(const Event *event)
 {
+  MotionEvent *motion;
+
+  /* non-motion events are directly passed to event handler functions */
   if (event->type != EVENT_MOTIONNOTIFY)
     return 1;
 
-  /* get mouse motion events without pressed button only in level editor */
-  if (button_status == MB_RELEASED && game_status != LEVELED)
+  motion = (MotionEvent *)event;
+  cursor_inside_playfield = (motion->x >= SX && motion->x < SX + SXSIZE &&
+                            motion->y >= SY && motion->y < SY + SYSIZE);
+
+  if (game_status == GAME_MODE_PLAYING && playfield_cursor_set)
+  {
+    SetMouseCursor(CURSOR_DEFAULT);
+    playfield_cursor_set = FALSE;
+    DelayReached(&playfield_cursor_delay, 0);
+  }
+
+  /* skip mouse motion events without pressed button outside level editor */
+  if (button_status == MB_RELEASED && game_status != GAME_MODE_EDITOR &&
+      game_status != GAME_MODE_PLAYING)
     return 0;
   else
     return 1;
@@ -95,12 +110,30 @@ void EventLoop(void)
       }
     }
     else
+    {
+      /* when playing, display a special mouse pointer inside the playfield */
+      if (game_status == GAME_MODE_PLAYING)
+      {
+       if (!playfield_cursor_set && cursor_inside_playfield &&
+           DelayReached(&playfield_cursor_delay, 1000))
+       {
+         SetMouseCursor(CURSOR_PLAYFIELD);
+         playfield_cursor_set = TRUE;
+       }
+      }
+      else if (playfield_cursor_set)
+      {
+       SetMouseCursor(CURSOR_DEFAULT);
+       playfield_cursor_set = FALSE;
+      }
+
       HandleNoEvent();
+    }
 
     /* don't use all CPU time when idle; the main loop while playing
        has its own synchronization and is CPU friendly, too */
 
-    if (game_status == PLAYING)
+    if (game_status == GAME_MODE_PLAYING)
       HandleGameActions();
     else
     {
@@ -112,7 +145,7 @@ void EventLoop(void)
     /* refresh window contents from drawing buffer, if needed */
     BackToFront();
 
-    if (game_status == EXITGAME)
+    if (game_status == GAME_MODE_QUIT)
       return;
   }
 }
@@ -126,7 +159,11 @@ void HandleOtherEvents(Event *event)
       break;
 
     case EVENT_UNMAPNOTIFY:
+#if 0
+      /* This causes the game to stop not only when iconified, but also
+        when on another virtual desktop, which might be not desired. */
       SleepWhileUnmapped();
+#endif
       break;
 
     case EVENT_FOCUSIN:
@@ -225,8 +262,8 @@ void SleepWhileUnmapped()
     }
   }
 
-  if (game_status == PLAYING)
-    KeyboardAutoRepeatOff();
+  if (game_status == GAME_MODE_PLAYING)
+    KeyboardAutoRepeatOffUnlessAutoplay();
 }
 
 void HandleExposeEvent(ExposeEvent *event)
@@ -255,7 +292,7 @@ void HandleMotionEvent(MotionEvent *event)
     return;    /* window and pointer are on different screens */
 
 #if 1
-  if (button_status == MB_RELEASED && game_status != LEVELED)
+  if (button_status == MB_RELEASED && game_status != GAME_MODE_EDITOR)
     return;
 #endif
 
@@ -267,9 +304,11 @@ void HandleMotionEvent(MotionEvent *event)
 void HandleKeyEvent(KeyEvent *event)
 {
   int key_status = (event->type==EVENT_KEYPRESS ? KEY_PRESSED : KEY_RELEASED);
-  boolean with_modifiers = (game_status == PLAYING ? FALSE : TRUE);
+  boolean with_modifiers = (game_status == GAME_MODE_PLAYING ? FALSE : TRUE);
   Key key = GetEventKey(event, with_modifiers);
+  Key keymod = (with_modifiers ? GetEventKey(event, FALSE) : key);
 
+  HandleKeyModState(keymod, key_status);
   HandleKey(key, key_status);
 }
 
@@ -298,15 +337,15 @@ void HandleFocusEvent(FocusChangeEvent *event)
        because unfortunately this is a global setting and not (which
        would be far better) set for each X11 window individually.
        The effect would be keyboard auto repeat while playing the game
-       (game_status == PLAYING), which is not desired.
+       (game_status == GAME_MODE_PLAYING), which is not desired.
        To avoid this special case, we just wait 1/10 second before
        processing the 'FocusIn' event.
     */
 
-    if (game_status == PLAYING)
+    if (game_status == GAME_MODE_PLAYING)
     {
       Delay(100);
-      KeyboardAutoRepeatOff();
+      KeyboardAutoRepeatOffUnlessAutoplay();
     }
     if (old_joystick_status != -1)
       joystick.status = old_joystick_status;
@@ -339,34 +378,34 @@ void HandleButton(int mx, int my, int button)
 
   switch(game_status)
   {
-    case MAINMENU:
+    case GAME_MODE_MAIN:
       HandleMainMenu(mx,my, 0,0, button);
       break;
 
-    case TYPENAME:
+    case GAME_MODE_PSEUDO_TYPENAME:
       HandleTypeName(0, KSYM_Return);
       break;
 
-    case CHOOSELEVEL:
+    case GAME_MODE_LEVELS:
       HandleChooseLevel(mx,my, 0,0, button);
       break;
 
-    case HALLOFFAME:
+    case GAME_MODE_SCORES:
       HandleHallOfFame(0,0, 0,0, button);
       break;
 
-    case LEVELED:
+    case GAME_MODE_EDITOR:
       break;
 
-    case HELPSCREEN:
+    case GAME_MODE_INFO:
       HandleHelpScreen(button);
       break;
 
-    case SETUP:
+    case GAME_MODE_SETUP:
       HandleSetupScreen(mx,my, 0,0, button);
       break;
 
-    case PLAYING:
+    case GAME_MODE_PLAYING:
 #ifdef DEBUG
       if (button == MB_RELEASED)
       {
@@ -383,13 +422,17 @@ void HandleButton(int mx, int my, int button)
          if (!IN_LEV_FIELD(x, y))
            break;
 
-         printf("      Feld[%d][%d] == %d\n", x,y, Feld[x][y]);
+         printf("      Feld[%d][%d] == %d ('%s')\n", x,y, Feld[x][y],
+                element_info[Feld[x][y]].token_name);
          printf("      Store[%d][%d] == %d\n", x,y, Store[x][y]);
          printf("      Store2[%d][%d] == %d\n", x,y, Store2[x][y]);
          printf("      StorePlayer[%d][%d] == %d\n", x,y, StorePlayer[x][y]);
          printf("      MovPos[%d][%d] == %d\n", x,y, MovPos[x][y]);
          printf("      MovDir[%d][%d] == %d\n", x,y, MovDir[x][y]);
          printf("      MovDelay[%d][%d] == %d\n", x,y, MovDelay[x][y]);
+         printf("      ChangeDelay[%d][%d] == %d\n", x,y, ChangeDelay[x][y]);
+         printf("      GfxElement[%d][%d] == %d\n", x,y, GfxElement[x][y]);
+         printf("      GfxAction[%d][%d] == %d\n", x,y, GfxAction[x][y]);
          printf("\n");
        }
       }
@@ -421,7 +464,7 @@ void HandleKey(Key key, int key_status)
     { &custom_key.bomb,  DEFAULT_KEY_BOMB,  JOY_BUTTON_2 }
   };
 
-  if (game_status == PLAYING)
+  if (game_status == GAME_MODE_PLAYING)
   {
     /* only needed for single-step tape recording mode */
     static boolean clear_button_2[MAX_PLAYERS] = { FALSE,FALSE,FALSE,FALSE };
@@ -503,36 +546,36 @@ void HandleKey(Key key, int key_status)
     HandleJoystick();
   }
 
-  if (game_status != PLAYING)
+  if (game_status != GAME_MODE_PLAYING)
     key_joystick_mapping = 0;
 
   if (key_status == KEY_RELEASED)
     return;
 
   if ((key == KSYM_Return || key == setup.shortcut.toggle_pause) &&
-      game_status == PLAYING && AllPlayersGone)
+      game_status == GAME_MODE_PLAYING && AllPlayersGone)
   {
     CloseDoor(DOOR_CLOSE_1);
-    game_status = MAINMENU;
+    game_status = GAME_MODE_MAIN;
     DrawMainMenu();
     return;
   }
 
   /* allow quick escape to the main menu with the Escape key */
   if (key == KSYM_Escape &&
-      game_status != MAINMENU &&
-      game_status != PLAYING &&
-      game_status != LEVELED &&
-      game_status != CHOOSELEVEL &&
-      game_status != SETUP)
+      game_status != GAME_MODE_MAIN &&
+      game_status != GAME_MODE_PLAYING &&
+      game_status != GAME_MODE_EDITOR &&
+      game_status != GAME_MODE_LEVELS &&
+      game_status != GAME_MODE_SETUP)
   {
-    game_status = MAINMENU;
+    game_status = GAME_MODE_MAIN;
     DrawMainMenu();
     return;
   }
 
   /* special key shortcuts */
-  if (game_status == MAINMENU || game_status == PLAYING)
+  if (game_status == GAME_MODE_MAIN || game_status == GAME_MODE_PLAYING)
   {
     if (key == setup.shortcut.save_game)
       TapeQuickSave();
@@ -542,57 +585,57 @@ void HandleKey(Key key, int key_status)
       TapeTogglePause(TAPE_TOGGLE_MANUAL);
   }
 
-
+#if 0
 #ifndef DEBUG
 
-  if (game_status == PLAYING && (tape.playing || tape.pausing))
+  if (game_status == GAME_MODE_PLAYING && (tape.playing || tape.pausing))
     return;
 
 #endif
-
+#endif
 
 
   HandleGadgetsKeyInput(key);
 
   switch(game_status)
   {
-    case TYPENAME:
+    case GAME_MODE_PSEUDO_TYPENAME:
       HandleTypeName(0, key);
       break;
 
-    case MAINMENU:
-    case CHOOSELEVEL:
-    case SETUP:
+    case GAME_MODE_MAIN:
+    case GAME_MODE_LEVELS:
+    case GAME_MODE_SETUP:
       switch(key)
       {
        case KSYM_Return:
-         if (game_status == MAINMENU)
+         if (game_status == GAME_MODE_MAIN)
            HandleMainMenu(0,0, 0,0, MB_MENU_CHOICE);
-          else if (game_status == CHOOSELEVEL)
+          else if (game_status == GAME_MODE_LEVELS)
             HandleChooseLevel(0,0, 0,0, MB_MENU_CHOICE);
-         else if (game_status == SETUP)
+         else if (game_status == GAME_MODE_SETUP)
            HandleSetupScreen(0,0, 0,0, MB_MENU_CHOICE);
          break;
 
        case KSYM_Escape:
-          if (game_status == CHOOSELEVEL)
+          if (game_status == GAME_MODE_LEVELS)
             HandleChooseLevel(0,0, 0,0, MB_MENU_LEAVE);
-         else if (game_status == SETUP)
+         else if (game_status == GAME_MODE_SETUP)
            HandleSetupScreen(0,0, 0,0, MB_MENU_LEAVE);
          break;
 
         case KSYM_Page_Up:
-          if (game_status == CHOOSELEVEL)
-            HandleChooseLevel(0,0, 0,-SCR_FIELDY, MB_MENU_MARK);
-         else if (game_status == SETUP)
-           HandleSetupScreen(0,0, 0,-SCR_FIELDY, MB_MENU_MARK);
+          if (game_status == GAME_MODE_LEVELS)
+            HandleChooseLevel(0,0, 0, -1 * SCROLL_PAGE, MB_MENU_MARK);
+         else if (game_status == GAME_MODE_SETUP)
+           HandleSetupScreen(0,0, 0, -1 * SCROLL_PAGE, MB_MENU_MARK);
          break;
 
         case KSYM_Page_Down:
-          if (game_status == CHOOSELEVEL)
-            HandleChooseLevel(0,0, 0,SCR_FIELDY, MB_MENU_MARK);
-         else if (game_status == SETUP)
-           HandleSetupScreen(0,0, 0,SCR_FIELDY, MB_MENU_MARK);
+          if (game_status == GAME_MODE_LEVELS)
+            HandleChooseLevel(0,0, 0, +1 * SCROLL_PAGE, MB_MENU_MARK);
+         else if (game_status == GAME_MODE_SETUP)
+           HandleSetupScreen(0,0, 0, +1 * SCROLL_PAGE, MB_MENU_MARK);
          break;
 
 #ifdef DEBUG
@@ -606,25 +649,25 @@ void HandleKey(Key key, int key_status)
       }
       break;
 
-    case HELPSCREEN:
+    case GAME_MODE_INFO:
       HandleHelpScreen(MB_RELEASED);
       break;
 
-    case HALLOFFAME:
+    case GAME_MODE_SCORES:
       switch(key)
       {
        case KSYM_Return:
-         game_status = MAINMENU;
+         game_status = GAME_MODE_MAIN;
          DrawMainMenu();
          BackToFront();
          break;
 
         case KSYM_Page_Up:
-         HandleHallOfFame(0,0, 0,-SCR_FIELDY, MB_MENU_MARK);
+         HandleHallOfFame(0,0, 0, -1 * SCROLL_PAGE, MB_MENU_MARK);
          break;
 
         case KSYM_Page_Down:
-         HandleHallOfFame(0,0, 0,SCR_FIELDY, MB_MENU_MARK);
+         HandleHallOfFame(0,0, 0, +1 * SCROLL_PAGE, MB_MENU_MARK);
          break;
 
        default:
@@ -632,12 +675,12 @@ void HandleKey(Key key, int key_status)
       }
       break;
 
-    case LEVELED:
+    case GAME_MODE_EDITOR:
       if (!anyTextGadgetActiveOrJustFinished || key == KSYM_Escape)
        HandleLevelEditorKeyInput(key);
       break;
 
-    case PLAYING:
+    case GAME_MODE_PLAYING:
     {
       switch(key)
       {
@@ -788,7 +831,7 @@ void HandleKey(Key key, int key_status)
 
 void HandleNoEvent()
 {
-  if (button_status && game_status != PLAYING)
+  if (button_status && game_status != GAME_MODE_PLAYING)
   {
     HandleButton(0, 0, -button_status);
     return;
@@ -844,9 +887,9 @@ void HandleJoystick()
 
   switch(game_status)
   {
-    case MAINMENU:
-    case CHOOSELEVEL:
-    case SETUP:
+    case GAME_MODE_MAIN:
+    case GAME_MODE_LEVELS:
+    case GAME_MODE_SETUP:
     {
       static unsigned long joystickmove_delay = 0;
 
@@ -854,31 +897,35 @@ void HandleJoystick()
          !DelayReached(&joystickmove_delay, GADGET_FRAME_DELAY))
        newbutton = dx = dy = 0;
 
-      if (game_status == MAINMENU)
+      if (game_status == GAME_MODE_MAIN)
        HandleMainMenu(0,0,dx,dy,newbutton ? MB_MENU_CHOICE : MB_MENU_MARK);
-      else if (game_status == CHOOSELEVEL)
+      else if (game_status == GAME_MODE_LEVELS)
         HandleChooseLevel(0,0,dx,dy,newbutton ? MB_MENU_CHOICE : MB_MENU_MARK);
-      else if (game_status == SETUP)
+      else if (game_status == GAME_MODE_SETUP)
        HandleSetupScreen(0,0,dx,dy,newbutton ? MB_MENU_CHOICE : MB_MENU_MARK);
       break;
     }
 
-    case HALLOFFAME:
+    case GAME_MODE_SCORES:
       HandleHallOfFame(0,0, dx,dy, !newbutton);
       break;
 
-    case HELPSCREEN:
+    case GAME_MODE_INFO:
       HandleHelpScreen(!newbutton);
       break;
 
-    case PLAYING:
+    case GAME_MODE_EDITOR:
+      HandleLevelEditorIdle();
+      break;
+
+    case GAME_MODE_PLAYING:
       if (tape.playing || keyboard)
        newbutton = ((joy & JOY_BUTTON) != 0);
 
       if (AllPlayersGone && newbutton)
       {
        CloseDoor(DOOR_CLOSE_1);
-       game_status = MAINMENU;
+       game_status = GAME_MODE_MAIN;
        DrawMainMenu();
        return;
       }
index 58cc705c9c1c6f227ca7df73e3ad9065d5cda033..bd2539b8ef19ac6cb8a5ac35eeca23952bd27d7b 100644 (file)
@@ -17,6 +17,7 @@
 #include "libgame/libgame.h"
 
 #include "files.h"
+#include "init.h"
 #include "tools.h"
 #include "tape.h"
 
 #define CHUNK_SIZE_NONE                -1      /* do not write chunk size    */
 #define FILE_VERS_CHUNK_SIZE   8       /* size of file version chunk */
 #define LEVEL_HEADER_SIZE      80      /* size of level file header  */
-#define LEVEL_HEADER_UNUSED    14      /* unused level header bytes  */
+#define LEVEL_HEADER_UNUSED    13      /* unused level header bytes  */
 #define LEVEL_CHUNK_CNT2_SIZE  160     /* size of level CNT2 chunk   */
 #define LEVEL_CHUNK_CNT2_UNUSED        11      /* unused CNT2 chunk bytes    */
+#define LEVEL_CPART_CUS3_SIZE  134     /* size of CUS3 chunk part    */
+#define LEVEL_CPART_CUS3_UNUSED        15      /* unused CUS3 bytes / part   */
 #define TAPE_HEADER_SIZE       20      /* size of tape file header   */
 #define TAPE_HEADER_UNUSED     3       /* unused tape header bytes   */
 
+#define LEVEL_CHUNK_CUS3_SIZE(x) (2 + x * LEVEL_CPART_CUS3_SIZE)
+
 /* file identifier strings */
 #define LEVEL_COOKIE_TMPL      "ROCKSNDIAMONDS_LEVEL_FILE_VERSION_x.x"
 #define TAPE_COOKIE_TMPL       "ROCKSNDIAMONDS_TAPE_FILE_VERSION_x.x"
 /* level file functions                                                      */
 /* ========================================================================= */
 
-static void setLevelInfoToDefaults()
+static void setLevelInfoToDefaults(struct LevelInfo *level)
 {
-  int i, x, y;
+  int i, j, x, y;
 
-  level.file_version = FILE_VERSION_ACTUAL;
-  level.game_version = GAME_VERSION_ACTUAL;
+  level->file_version = FILE_VERSION_ACTUAL;
+  level->game_version = GAME_VERSION_ACTUAL;
 
-  level.encoding_16bit_field = FALSE;  /* default: only 8-bit elements */
-  level.encoding_16bit_yamyam = FALSE; /* default: only 8-bit elements */
-  level.encoding_16bit_amoeba = FALSE; /* default: only 8-bit elements */
+  level->encoding_16bit_field  = FALSE;        /* default: only 8-bit elements */
+  level->encoding_16bit_yamyam = FALSE;        /* default: only 8-bit elements */
+  level->encoding_16bit_amoeba = FALSE;        /* default: only 8-bit elements */
 
-  lev_fieldx = level.fieldx = STD_LEV_FIELDX;
-  lev_fieldy = level.fieldy = STD_LEV_FIELDY;
+  level->fieldx = STD_LEV_FIELDX;
+  level->fieldy = STD_LEV_FIELDY;
 
   for(x=0; x<MAX_LEV_FIELDX; x++)
     for(y=0; y<MAX_LEV_FIELDY; y++)
-      Feld[x][y] = Ur[x][y] = EL_ERDREICH;
-
-  level.time = 100;
-  level.gems_needed = 0;
-  level.amoeba_speed = 10;
-  level.time_magic_wall = 10;
-  level.time_wheel = 10;
-  level.time_light = 10;
-  level.time_timegate = 10;
-  level.amoeba_content = EL_DIAMANT;
-  level.double_speed = FALSE;
-  level.gravity = FALSE;
-  level.em_slippery_gems = FALSE;
+      level->field[x][y] = EL_SAND;
+
+  level->time = 100;
+  level->gems_needed = 0;
+  level->amoeba_speed = 10;
+  level->time_magic_wall = 10;
+  level->time_wheel = 10;
+  level->time_light = 10;
+  level->time_timegate = 10;
+  level->amoeba_content = EL_DIAMOND;
+  level->double_speed = FALSE;
+  level->gravity = FALSE;
+  level->em_slippery_gems = FALSE;
+
+  level->use_custom_template = FALSE;
 
   for(i=0; i<MAX_LEVEL_NAME_LEN; i++)
-    level.name[i] = '\0';
+    level->name[i] = '\0';
   for(i=0; i<MAX_LEVEL_AUTHOR_LEN; i++)
-    level.author[i] = '\0';
+    level->author[i] = '\0';
 
-  strcpy(level.name, NAMELESS_LEVEL_NAME);
-  strcpy(level.author, ANONYMOUS_NAME);
+  strcpy(level->name, NAMELESS_LEVEL_NAME);
+  strcpy(level->author, ANONYMOUS_NAME);
 
   for(i=0; i<LEVEL_SCORE_ELEMENTS; i++)
-    level.score[i] = 10;
+    level->score[i] = 10;
 
-  level.num_yam_contents = STD_ELEMENT_CONTENTS;
+  level->num_yamyam_contents = STD_ELEMENT_CONTENTS;
   for(i=0; i<MAX_ELEMENT_CONTENTS; i++)
     for(x=0; x<3; x++)
       for(y=0; y<3; y++)
-       level.yam_content[i][x][y] =
-         (i < STD_ELEMENT_CONTENTS ? EL_FELSBROCKEN : EL_LEERRAUM);
+       level->yamyam_content[i][x][y] =
+         (i < STD_ELEMENT_CONTENTS ? EL_ROCK : EL_EMPTY);
+
+  level->field[0][0] = EL_PLAYER_1;
+  level->field[STD_LEV_FIELDX - 1][STD_LEV_FIELDY - 1] = EL_EXIT_CLOSED;
+
+  for (i=0; i < NUM_CUSTOM_ELEMENTS; i++)
+  {
+    int element = EL_CUSTOM_START + i;
+
+    for(j=0; j<MAX_ELEMENT_NAME_LEN + 1; j++)
+      element_info[element].description[j] = '\0';
+    if (element_info[element].custom_description != NULL)
+      strncpy(element_info[element].description,
+             element_info[element].custom_description, MAX_ELEMENT_NAME_LEN);
+    else
+      strcpy(element_info[element].description,
+            element_info[element].editor_description);
+
+    element_info[element].use_gfx_element = FALSE;
+    element_info[element].gfx_element = EL_EMPTY_SPACE;
+
+    element_info[element].score = 0;
+    element_info[element].gem_count = 0;
+
+    element_info[element].push_delay_fixed = 2;                /* special default */
+    element_info[element].push_delay_random = 8;       /* special default */
+    element_info[element].move_delay_fixed = 0;
+    element_info[element].move_delay_random = 0;
+
+    element_info[element].move_pattern = MV_ALL_DIRECTIONS;
+    element_info[element].move_direction_initial = MV_NO_MOVING;
+    element_info[element].move_stepsize = TILEX / 8;
+
+    element_info[element].slippery_type = SLIPPERY_ANY_RANDOM;
+
+    for(x=0; x<3; x++)
+      for(y=0; y<3; y++)
+       element_info[element].content[x][y] = EL_EMPTY_SPACE;
+
+    element_info[element].change.events = CE_BITMASK_DEFAULT;
+    element_info[element].change.target_element = EL_EMPTY_SPACE;
+
+    element_info[element].change.delay_fixed = 0;
+    element_info[element].change.delay_random = 0;
+    element_info[element].change.delay_frames = -1;    /* use default */
+
+    element_info[element].change.trigger_element = EL_EMPTY_SPACE;
 
-  Feld[0][0] = Ur[0][0] = EL_SPIELFIGUR;
-  Feld[STD_LEV_FIELDX-1][STD_LEV_FIELDY-1] =
-    Ur[STD_LEV_FIELDX-1][STD_LEV_FIELDY-1] = EL_AUSGANG_ZU;
+    element_info[element].change.explode = FALSE;
+    element_info[element].change.use_content = FALSE;
+    element_info[element].change.only_complete = FALSE;
+    element_info[element].change.use_random_change = FALSE;
+    element_info[element].change.random = 0;
+    element_info[element].change.power = CP_NON_DESTRUCTIVE;
 
-  BorderElement = EL_BETON;
+    for(x=0; x<3; x++)
+      for(y=0; y<3; y++)
+       element_info[element].change.content[x][y] = EL_EMPTY_SPACE;
+
+    element_info[element].access_type = 0;
+    element_info[element].access_layer = 0;
+    element_info[element].walk_to_action = 0;
+    element_info[element].smash_targets = 0;
+    element_info[element].deadliness = 0;
+    element_info[element].consistency = 0;
+    element_info[element].change_player_action = 0;
+    element_info[element].change_collide_action = 0;
+    element_info[element].change_other_action = 0;
+
+    element_info[element].can_explode_by_fire = FALSE;
+    element_info[element].can_explode_smashed = FALSE;
+    element_info[element].can_explode_impact = FALSE;
+
+    /* start with no properties at all */
+    for (j=0; j < NUM_EP_BITFIELDS; j++)
+      Properties[element][j] = EP_BITMASK_DEFAULT;
+  }
+
+  BorderElement = EL_STEELWALL;
+
+  level->no_level_file = FALSE;
+
+  if (leveldir_current == NULL)                /* only when dumping level */
+    return;
 
   /* try to determine better author name than 'anonymous' */
   if (strcmp(leveldir_current->author, ANONYMOUS_NAME) != 0)
   {
-    strncpy(level.author, leveldir_current->author, MAX_LEVEL_AUTHOR_LEN);
-    level.author[MAX_LEVEL_AUTHOR_LEN] = '\0';
+    strncpy(level->author, leveldir_current->author, MAX_LEVEL_AUTHOR_LEN);
+    level->author[MAX_LEVEL_AUTHOR_LEN] = '\0';
   }
   else
   {
     switch (LEVELCLASS(leveldir_current))
     {
       case LEVELCLASS_TUTORIAL:
-       strcpy(level.author, PROGRAM_AUTHOR_STRING);
+       strcpy(level->author, PROGRAM_AUTHOR_STRING);
        break;
 
       case LEVELCLASS_CONTRIBUTION:
-       strncpy(level.author, leveldir_current->name,MAX_LEVEL_AUTHOR_LEN);
-       level.author[MAX_LEVEL_AUTHOR_LEN] = '\0';
+       strncpy(level->author, leveldir_current->name,MAX_LEVEL_AUTHOR_LEN);
+       level->author[MAX_LEVEL_AUTHOR_LEN] = '\0';
        break;
 
       case LEVELCLASS_USER:
-       strncpy(level.author, getRealName(), MAX_LEVEL_AUTHOR_LEN);
-       level.author[MAX_LEVEL_AUTHOR_LEN] = '\0';
+       strncpy(level->author, getRealName(), MAX_LEVEL_AUTHOR_LEN);
+       level->author[MAX_LEVEL_AUTHOR_LEN] = '\0';
        break;
 
       default:
@@ -127,13 +211,31 @@ static void setLevelInfoToDefaults()
   }
 }
 
+static void ActivateLevelTemplate()
+{
+  /* Currently there is no special action needed to activate the template
+     data, because 'element_info' and 'Properties' overwrite the original
+     level data, while all other variables do not change. */
+}
+
+boolean LevelFileExists(int level_nr)
+{
+  char *filename = getLevelFilename(level_nr);
+
+  return (access(filename, F_OK) == 0);
+}
+
 static int checkLevelElement(int element)
 {
-  if (element >= EL_FIRST_RUNTIME_EL)
+  if (element >= NUM_FILE_ELEMENTS)
   {
     Error(ERR_WARN, "invalid level element %d", element);
-    element = EL_CHAR_FRAGE;
+    element = EL_CHAR_QUESTION;
   }
+  else if (element == EL_PLAYER_OBSOLETE)
+    element = EL_PLAYER_1;
+  else if (element == EL_KEY_OBSOLETE)
+    element = EL_KEY_1;
 
   return element;
 }
@@ -150,33 +252,35 @@ static int LoadLevel_HEAD(FILE *file, int chunk_size, struct LevelInfo *level)
 {
   int i, x, y;
 
-  lev_fieldx = level->fieldx = fgetc(file);
-  lev_fieldy = level->fieldy = fgetc(file);
+  level->fieldx = getFile8Bit(file);
+  level->fieldy = getFile8Bit(file);
 
   level->time          = getFile16BitBE(file);
   level->gems_needed   = getFile16BitBE(file);
 
   for(i=0; i<MAX_LEVEL_NAME_LEN; i++)
-    level->name[i] = fgetc(file);
+    level->name[i] = getFile8Bit(file);
   level->name[MAX_LEVEL_NAME_LEN] = 0;
 
   for(i=0; i<LEVEL_SCORE_ELEMENTS; i++)
-    level->score[i] = fgetc(file);
+    level->score[i] = getFile8Bit(file);
 
-  level->num_yam_contents = STD_ELEMENT_CONTENTS;
+  level->num_yamyam_contents = STD_ELEMENT_CONTENTS;
   for(i=0; i<STD_ELEMENT_CONTENTS; i++)
     for(y=0; y<3; y++)
       for(x=0; x<3; x++)
-       level->yam_content[i][x][y] = checkLevelElement(fgetc(file));
+       level->yamyam_content[i][x][y] = checkLevelElement(getFile8Bit(file));
+
+  level->amoeba_speed          = getFile8Bit(file);
+  level->time_magic_wall       = getFile8Bit(file);
+  level->time_wheel            = getFile8Bit(file);
+  level->amoeba_content                = checkLevelElement(getFile8Bit(file));
+  level->double_speed          = (getFile8Bit(file) == 1 ? TRUE : FALSE);
+  level->gravity               = (getFile8Bit(file) == 1 ? TRUE : FALSE);
+  level->encoding_16bit_field  = (getFile8Bit(file) == 1 ? TRUE : FALSE);
+  level->em_slippery_gems      = (getFile8Bit(file) == 1 ? TRUE : FALSE);
 
-  level->amoeba_speed          = fgetc(file);
-  level->time_magic_wall       = fgetc(file);
-  level->time_wheel            = fgetc(file);
-  level->amoeba_content                = checkLevelElement(fgetc(file));
-  level->double_speed          = (fgetc(file) == 1 ? TRUE : FALSE);
-  level->gravity               = (fgetc(file) == 1 ? TRUE : FALSE);
-  level->encoding_16bit_field  = (fgetc(file) == 1 ? TRUE : FALSE);
-  level->em_slippery_gems      = (fgetc(file) == 1 ? TRUE : FALSE);
+  level->use_custom_template   = (getFile8Bit(file) == 1 ? TRUE : FALSE);
 
   ReadUnusedBytesFromFile(file, LEVEL_HEADER_UNUSED);
 
@@ -188,18 +292,16 @@ static int LoadLevel_AUTH(FILE *file, int chunk_size, struct LevelInfo *level)
   int i;
 
   for(i=0; i<MAX_LEVEL_AUTHOR_LEN; i++)
-    level->author[i] = fgetc(file);
+    level->author[i] = getFile8Bit(file);
   level->author[MAX_LEVEL_NAME_LEN] = 0;
 
   return chunk_size;
 }
 
-static int LoadLevel_CONT(FILE *file, int chunk_size, struct LevelInfo *level)
+static int LoadLevel_BODY(FILE *file, int chunk_size, struct LevelInfo *level)
 {
-  int i, x, y;
-  int header_size = 4;
-  int content_size = MAX_ELEMENT_CONTENTS * 3 * 3;
-  int chunk_size_expected = header_size + content_size;
+  int x, y;
+  int chunk_size_expected = level->fieldx * level->fieldy;
 
   /* Note: "chunk_size" was wrong before version 2.0 when elements are
      stored with 16-bit encoding (and should be twice as big then).
@@ -207,7 +309,7 @@ static int LoadLevel_CONT(FILE *file, int chunk_size, struct LevelInfo *level)
      contained 16-bit elements and vice versa. */
 
   if (level->encoding_16bit_field && level->file_version >= FILE_VERSION_2_0)
-    chunk_size_expected += content_size;
+    chunk_size_expected *= 2;
 
   if (chunk_size_expected != chunk_size)
   {
@@ -215,29 +317,20 @@ static int LoadLevel_CONT(FILE *file, int chunk_size, struct LevelInfo *level)
     return chunk_size_expected;
   }
 
-  fgetc(file);
-  level->num_yam_contents = fgetc(file);
-  fgetc(file);
-  fgetc(file);
-
-  /* correct invalid number of content fields -- should never happen */
-  if (level->num_yam_contents < 1 ||
-      level->num_yam_contents > MAX_ELEMENT_CONTENTS)
-    level->num_yam_contents = STD_ELEMENT_CONTENTS;
-
-  for(i=0; i<MAX_ELEMENT_CONTENTS; i++)
-    for(y=0; y<3; y++)
-      for(x=0; x<3; x++)
-       level->yam_content[i][x][y] =
-         checkLevelElement(level->encoding_16bit_field ?
-                           getFile16BitBE(file) : fgetc(file));
+  for(y=0; y<level->fieldy; y++)
+    for(x=0; x<level->fieldx; x++)
+      level->field[x][y] =
+       checkLevelElement(level->encoding_16bit_field ? getFile16BitBE(file) :
+                         getFile8Bit(file));
   return chunk_size;
 }
 
-static int LoadLevel_BODY(FILE *file, int chunk_size, struct LevelInfo *level)
+static int LoadLevel_CONT(FILE *file, int chunk_size, struct LevelInfo *level)
 {
-  int x, y;
-  int chunk_size_expected = level->fieldx * level->fieldy;
+  int i, x, y;
+  int header_size = 4;
+  int content_size = MAX_ELEMENT_CONTENTS * 3 * 3;
+  int chunk_size_expected = header_size + content_size;
 
   /* Note: "chunk_size" was wrong before version 2.0 when elements are
      stored with 16-bit encoding (and should be twice as big then).
@@ -245,7 +338,7 @@ static int LoadLevel_BODY(FILE *file, int chunk_size, struct LevelInfo *level)
      contained 16-bit elements and vice versa. */
 
   if (level->encoding_16bit_field && level->file_version >= FILE_VERSION_2_0)
-    chunk_size_expected *= 2;
+    chunk_size_expected += content_size;
 
   if (chunk_size_expected != chunk_size)
   {
@@ -253,11 +346,22 @@ static int LoadLevel_BODY(FILE *file, int chunk_size, struct LevelInfo *level)
     return chunk_size_expected;
   }
 
-  for(y=0; y<level->fieldy; y++)
-    for(x=0; x<level->fieldx; x++)
-      Feld[x][y] = Ur[x][y] =
-       checkLevelElement(level->encoding_16bit_field ?
-                         getFile16BitBE(file) : fgetc(file));
+  getFile8Bit(file);
+  level->num_yamyam_contents = getFile8Bit(file);
+  getFile8Bit(file);
+  getFile8Bit(file);
+
+  /* correct invalid number of content fields -- should never happen */
+  if (level->num_yamyam_contents < 1 ||
+      level->num_yamyam_contents > MAX_ELEMENT_CONTENTS)
+    level->num_yamyam_contents = STD_ELEMENT_CONTENTS;
+
+  for(i=0; i<MAX_ELEMENT_CONTENTS; i++)
+    for(y=0; y<3; y++)
+      for(x=0; x<3; x++)
+       level->yamyam_content[i][x][y] =
+         checkLevelElement(level->encoding_16bit_field ?
+                           getFile16BitBE(file) : getFile8Bit(file));
   return chunk_size;
 }
 
@@ -269,9 +373,9 @@ static int LoadLevel_CNT2(FILE *file, int chunk_size, struct LevelInfo *level)
   int content_array[MAX_ELEMENT_CONTENTS][3][3];
 
   element = checkLevelElement(getFile16BitBE(file));
-  num_contents = fgetc(file);
-  content_xsize = fgetc(file);
-  content_ysize = fgetc(file);
+  num_contents = getFile8Bit(file);
+  content_xsize = getFile8Bit(file);
+  content_ysize = getFile8Bit(file);
   ReadUnusedBytesFromFile(file, LEVEL_CHUNK_CNT2_UNUSED);
 
   for(i=0; i<MAX_ELEMENT_CONTENTS; i++)
@@ -283,16 +387,16 @@ static int LoadLevel_CNT2(FILE *file, int chunk_size, struct LevelInfo *level)
   if (num_contents < 1 || num_contents > MAX_ELEMENT_CONTENTS)
     num_contents = STD_ELEMENT_CONTENTS;
 
-  if (element == EL_MAMPFER)
+  if (element == EL_YAMYAM)
   {
-    level->num_yam_contents = num_contents;
+    level->num_yamyam_contents = num_contents;
 
     for(i=0; i<num_contents; i++)
       for(y=0; y<3; y++)
        for(x=0; x<3; x++)
-         level->yam_content[i][x][y] = content_array[i][x][y];
+         level->yamyam_content[i][x][y] = content_array[i][x][y];
   }
-  else if (element == EL_AMOEBE_BD)
+  else if (element == EL_BD_AMOEBA)
   {
     level->amoeba_content = content_array[0][0][0];
   }
@@ -304,20 +408,162 @@ static int LoadLevel_CNT2(FILE *file, int chunk_size, struct LevelInfo *level)
   return chunk_size;
 }
 
-void LoadLevel(int level_nr)
+static int LoadLevel_CUS1(FILE *file, int chunk_size, struct LevelInfo *level)
+{
+  int num_changed_custom_elements = getFile16BitBE(file);
+  int chunk_size_expected = 2 + num_changed_custom_elements * 6;
+  int i;
+
+  if (chunk_size_expected != chunk_size)
+  {
+    ReadUnusedBytesFromFile(file, chunk_size - 2);
+    return chunk_size_expected;
+  }
+
+  for (i=0; i < num_changed_custom_elements; i++)
+  {
+    int element = getFile16BitBE(file);
+    int properties = getFile32BitBE(file);
+
+    if (IS_CUSTOM_ELEMENT(element))
+      Properties[element][EP_BITFIELD_BASE] = properties;
+    else
+      Error(ERR_WARN, "invalid custom element number %d", element);
+  }
+
+  return chunk_size;
+}
+
+static int LoadLevel_CUS2(FILE *file, int chunk_size, struct LevelInfo *level)
+{
+  int num_changed_custom_elements = getFile16BitBE(file);
+  int chunk_size_expected = 2 + num_changed_custom_elements * 4;
+  int i;
+
+  if (chunk_size_expected != chunk_size)
+  {
+    ReadUnusedBytesFromFile(file, chunk_size - 2);
+    return chunk_size_expected;
+  }
+
+  for (i=0; i < num_changed_custom_elements; i++)
+  {
+    int element = getFile16BitBE(file);
+    int custom_target_element = getFile16BitBE(file);
+
+    if (IS_CUSTOM_ELEMENT(element))
+      element_info[element].change.target_element = custom_target_element;
+    else
+      Error(ERR_WARN, "invalid custom element number %d", element);
+  }
+
+  return chunk_size;
+}
+
+static int LoadLevel_CUS3(FILE *file, int chunk_size, struct LevelInfo *level)
+{
+  int num_changed_custom_elements = getFile16BitBE(file);
+  int chunk_size_expected = LEVEL_CHUNK_CUS3_SIZE(num_changed_custom_elements);
+  int i, j, x, y;
+
+  if (chunk_size_expected != chunk_size)
+  {
+    ReadUnusedBytesFromFile(file, chunk_size - 2);
+    return chunk_size_expected;
+  }
+
+  for (i=0; i < num_changed_custom_elements; i++)
+  {
+    int element = getFile16BitBE(file);
+
+    if (!IS_CUSTOM_ELEMENT(element))
+    {
+      Error(ERR_WARN, "invalid custom element number %d", element);
+
+      element = EL_DEFAULT;    /* dummy element used for artwork config */
+    }
+
+    for(j=0; j<MAX_ELEMENT_NAME_LEN; j++)
+      element_info[element].description[j] = getFile8Bit(file);
+    element_info[element].description[MAX_ELEMENT_NAME_LEN] = 0;
+
+    Properties[element][EP_BITFIELD_BASE] = getFile32BitBE(file);
+
+    /* some free bytes for future properties and padding */
+    ReadUnusedBytesFromFile(file, 7);
+
+    element_info[element].use_gfx_element = getFile8Bit(file);
+    element_info[element].gfx_element =
+      checkLevelElement(getFile16BitBE(file));
+
+    element_info[element].score = getFile8Bit(file);
+    element_info[element].gem_count = getFile8Bit(file);
+
+    element_info[element].push_delay_fixed = getFile16BitBE(file);
+    element_info[element].push_delay_random = getFile16BitBE(file);
+    element_info[element].move_delay_fixed = getFile16BitBE(file);
+    element_info[element].move_delay_random = getFile16BitBE(file);
+
+    element_info[element].move_pattern = getFile16BitBE(file);
+    element_info[element].move_direction_initial = getFile8Bit(file);
+    element_info[element].move_stepsize = getFile8Bit(file);
+
+    for(y=0; y<3; y++)
+      for(x=0; x<3; x++)
+       element_info[element].content[x][y] =
+         checkLevelElement(getFile16BitBE(file));
+
+    element_info[element].change.events = getFile32BitBE(file);
+
+    element_info[element].change.target_element =
+      checkLevelElement(getFile16BitBE(file));
+
+    element_info[element].change.delay_fixed = getFile16BitBE(file);
+    element_info[element].change.delay_random = getFile16BitBE(file);
+    element_info[element].change.delay_frames = getFile16BitBE(file);
+
+    element_info[element].change.trigger_element =
+      checkLevelElement(getFile16BitBE(file));
+
+    element_info[element].change.explode = getFile8Bit(file);
+    element_info[element].change.use_content = getFile8Bit(file);
+    element_info[element].change.only_complete = getFile8Bit(file);
+    element_info[element].change.use_random_change = getFile8Bit(file);
+
+    element_info[element].change.random = getFile8Bit(file);
+    element_info[element].change.power = getFile8Bit(file);
+
+    for(y=0; y<3; y++)
+      for(x=0; x<3; x++)
+       element_info[element].change.content[x][y] =
+         checkLevelElement(getFile16BitBE(file));
+
+    element_info[element].slippery_type = getFile8Bit(file);
+
+    /* some free bytes for future properties and padding */
+    ReadUnusedBytesFromFile(file, LEVEL_CPART_CUS3_UNUSED);
+  }
+
+  return chunk_size;
+}
+
+void LoadLevelFromFilename(struct LevelInfo *level, char *filename)
 {
-  char *filename = getLevelFilename(level_nr);
   char cookie[MAX_LINE_LEN];
   char chunk_name[CHUNK_ID_LEN + 1];
   int chunk_size;
   FILE *file;
 
   /* always start with reliable default values */
-  setLevelInfoToDefaults();
+  setLevelInfoToDefaults(level);
 
   if (!(file = fopen(filename, MODE_READ)))
   {
-    Error(ERR_WARN, "cannot read level '%s' - creating new level", filename);
+    level->no_level_file = TRUE;
+
+    if (level != &level_template)
+      Error(ERR_WARN, "cannot read level '%s' - creating new level", filename);
+
     return;
   }
 
@@ -348,7 +594,7 @@ void LoadLevel(int level_nr)
       return;
     }
 
-    if ((level.file_version = getFileVersionFromCookieString(cookie)) == -1)
+    if ((level->file_version = getFileVersionFromCookieString(cookie)) == -1)
     {
       Error(ERR_WARN, "unsupported version of level file '%s'", filename);
       fclose(file);
@@ -356,14 +602,14 @@ void LoadLevel(int level_nr)
     }
 
     /* pre-2.0 level files have no game version, so use file version here */
-    level.game_version = level.file_version;
+    level->game_version = level->file_version;
   }
 
-  if (level.file_version < FILE_VERSION_1_2)
+  if (level->file_version < FILE_VERSION_1_2)
   {
     /* level files from versions before 1.2.0 without chunk structure */
-    LoadLevel_HEAD(file, LEVEL_HEADER_SIZE,           &level);
-    LoadLevel_BODY(file, level.fieldx * level.fieldy, &level);
+    LoadLevel_HEAD(file, LEVEL_HEADER_SIZE,             level);
+    LoadLevel_BODY(file, level->fieldx * level->fieldy, level);
   }
   else
   {
@@ -378,9 +624,12 @@ void LoadLevel(int level_nr)
       { "VERS", FILE_VERS_CHUNK_SIZE,  LoadLevel_VERS },
       { "HEAD", LEVEL_HEADER_SIZE,     LoadLevel_HEAD },
       { "AUTH", MAX_LEVEL_AUTHOR_LEN,  LoadLevel_AUTH },
-      { "CONT", -1,                    LoadLevel_CONT },
       { "BODY", -1,                    LoadLevel_BODY },
+      { "CONT", -1,                    LoadLevel_CONT },
       { "CNT2", LEVEL_CHUNK_CNT2_SIZE, LoadLevel_CNT2 },
+      { "CUS1", -1,                    LoadLevel_CUS1 },
+      { "CUS2", -1,                    LoadLevel_CUS2 },
+      { "CUS3", -1,                    LoadLevel_CUS3 },
       {  NULL,  0,                     NULL }
     };
 
@@ -409,7 +658,7 @@ void LoadLevel(int level_nr)
       {
        /* call function to load this level chunk */
        int chunk_size_expected =
-         (chunk_info[i].loader)(file, chunk_size, &level);
+         (chunk_info[i].loader)(file, chunk_size, level);
 
        /* the size of some chunks cannot be checked before reading other
           chunks first (like "HEAD" and "BODY") that contain some header
@@ -424,10 +673,22 @@ void LoadLevel(int level_nr)
   }
 
   fclose(file);
+}
+
+static void LoadLevel_InitLevel(struct LevelInfo *level, char *filename)
+{
+  int x, y;
+
+  if (leveldir_current == NULL)                /* only when dumping level */
+    return;
 
   if (IS_LEVELCLASS_CONTRIBUTION(leveldir_current) ||
       IS_LEVELCLASS_USER(leveldir_current))
   {
+#if 0
+    printf("::: This level is private or contributed: '%s'\n", filename);
+#endif
+
     /* For user contributed and private levels, use the version of
        the game engine the levels were created for.
        Since 2.0.1, the game engine version is now directly stored
@@ -437,21 +698,26 @@ void LoadLevel(int level_nr)
        file format version used to store the level -- see above). */
 
     /* do some special adjustments to support older level versions */
-    if (level.file_version == FILE_VERSION_1_0)
+    if (level->file_version == FILE_VERSION_1_0)
     {
-      Error(ERR_WARN, "level file '%s' has version number 1.0", filename);
+      Error(ERR_WARN, "level file '%s'has version number 1.0", filename);
       Error(ERR_WARN, "using high speed movement for player");
 
       /* player was faster than monsters in (pre-)1.0 levels */
-      level.double_speed = TRUE;
+      level->double_speed = TRUE;
     }
 
     /* Default behaviour for EM style gems was "slippery" only in 2.0.1 */
-    if (level.game_version == VERSION_IDENT(2,0,1))
-      level.em_slippery_gems = TRUE;
+    if (level->game_version == VERSION_IDENT(2,0,1))
+      level->em_slippery_gems = TRUE;
   }
   else
   {
+#if 0
+    printf("::: ALWAYS USE LATEST ENGINE FOR THIS LEVEL: [%d] '%s'\n",
+          leveldir_current->sort_priority, filename);
+#endif
+
     /* Always use the latest version of the game engine for all but
        user contributed and private levels; this allows for actual
        corrections in the game engine to take effect for existing,
@@ -459,7 +725,7 @@ void LoadLevel(int level_nr)
        make the game emulation more accurate, while (hopefully) not
        breaking existing levels created from other players. */
 
-    level.game_version = GAME_VERSION_ACTUAL;
+    level->game_version = GAME_VERSION_ACTUAL;
 
     /* Set special EM style gems behaviour: EM style gems slip down from
        normal, steel and growing wall. As this is a more fundamental change,
@@ -468,12 +734,75 @@ void LoadLevel(int level_nr)
        of gem style elements). Already existing converted levels (neither
        private nor contributed levels) are changed to the new behaviour. */
 
-    if (level.file_version < FILE_VERSION_2_0)
-      level.em_slippery_gems = TRUE;
+    if (level->file_version < FILE_VERSION_2_0)
+      level->em_slippery_gems = TRUE;
+  }
+
+  /* map elements which have changed in newer versions */
+  for(y=0; y<level->fieldy; y++)
+  {
+    for(x=0; x<level->fieldx; x++)
+    {
+      int element = level->field[x][y];
+
+      if (level->game_version <= VERSION_IDENT(2,2,0))
+      {
+       /* map game font elements */
+       element = (element == EL_CHAR('[')  ? EL_CHAR_AUMLAUT :
+                  element == EL_CHAR('\\') ? EL_CHAR_OUMLAUT :
+                  element == EL_CHAR(']')  ? EL_CHAR_UUMLAUT :
+                  element == EL_CHAR('^')  ? EL_CHAR_COPYRIGHT : element);
+      }
+
+      if (level->game_version < VERSION_IDENT(3,0,0))
+      {
+       /* map Supaplex gravity tube elements */
+       element = (element == EL_SP_GRAVITY_PORT_LEFT  ? EL_SP_PORT_LEFT  :
+                  element == EL_SP_GRAVITY_PORT_RIGHT ? EL_SP_PORT_RIGHT :
+                  element == EL_SP_GRAVITY_PORT_UP    ? EL_SP_PORT_UP    :
+                  element == EL_SP_GRAVITY_PORT_DOWN  ? EL_SP_PORT_DOWN  :
+                  element);
+      }
+
+      level->field[x][y] = element;
+    }
   }
 
+  /* copy elements to runtime playfield array */
+  for(x=0; x<MAX_LEV_FIELDX; x++)
+    for(y=0; y<MAX_LEV_FIELDY; y++)
+      Feld[x][y] = level->field[x][y];
+
+  /* initialize level size variables for faster access */
+  lev_fieldx = level->fieldx;
+  lev_fieldy = level->fieldy;
+
   /* determine border element for this level */
   SetBorderElement();
+
+  /* initialize element properties for level editor etc. */
+  InitElementPropertiesEngine(level->game_version);
+}
+
+void LoadLevelTemplate(int level_nr)
+{
+  char *filename = getLevelFilename(level_nr);
+
+  LoadLevelFromFilename(&level_template, filename);
+
+  ActivateLevelTemplate();
+}
+
+void LoadLevel(int level_nr)
+{
+  char *filename = getLevelFilename(level_nr);
+
+  LoadLevelFromFilename(&level, filename);
+
+  if (level.use_custom_template)
+    LoadLevelTemplate(-1);
+
+  LoadLevel_InitLevel(&level, filename);
 }
 
 static void SaveLevel_VERS(FILE *file, struct LevelInfo *level)
@@ -486,33 +815,34 @@ static void SaveLevel_HEAD(FILE *file, struct LevelInfo *level)
 {
   int i, x, y;
 
-  fputc(level->fieldx, file);
-  fputc(level->fieldy, file);
+  putFile8Bit(file, level->fieldx);
+  putFile8Bit(file, level->fieldy);
 
   putFile16BitBE(file, level->time);
   putFile16BitBE(file, level->gems_needed);
 
   for(i=0; i<MAX_LEVEL_NAME_LEN; i++)
-    fputc(level->name[i], file);
+    putFile8Bit(file, level->name[i]);
 
   for(i=0; i<LEVEL_SCORE_ELEMENTS; i++)
-    fputc(level->score[i], file);
+    putFile8Bit(file, level->score[i]);
 
   for(i=0; i<STD_ELEMENT_CONTENTS; i++)
     for(y=0; y<3; y++)
       for(x=0; x<3; x++)
-       fputc((level->encoding_16bit_yamyam ? EL_LEERRAUM :
-              level->yam_content[i][x][y]),
-             file);
-  fputc(level->amoeba_speed, file);
-  fputc(level->time_magic_wall, file);
-  fputc(level->time_wheel, file);
-  fputc((level->encoding_16bit_amoeba ? EL_LEERRAUM : level->amoeba_content),
-       file);
-  fputc((level->double_speed ? 1 : 0), file);
-  fputc((level->gravity ? 1 : 0), file);
-  fputc((level->encoding_16bit_field ? 1 : 0), file);
-  fputc((level->em_slippery_gems ? 1 : 0), file);
+       putFile8Bit(file, (level->encoding_16bit_yamyam ? EL_EMPTY :
+                          level->yamyam_content[i][x][y]));
+  putFile8Bit(file, level->amoeba_speed);
+  putFile8Bit(file, level->time_magic_wall);
+  putFile8Bit(file, level->time_wheel);
+  putFile8Bit(file, (level->encoding_16bit_amoeba ? EL_EMPTY :
+                    level->amoeba_content));
+  putFile8Bit(file, (level->double_speed ? 1 : 0));
+  putFile8Bit(file, (level->gravity ? 1 : 0));
+  putFile8Bit(file, (level->encoding_16bit_field ? 1 : 0));
+  putFile8Bit(file, (level->em_slippery_gems ? 1 : 0));
+
+  putFile8Bit(file, (level->use_custom_template ? 1 : 0));
 
   WriteUnusedBytesToFile(file, LEVEL_HEADER_UNUSED);
 }
@@ -522,7 +852,19 @@ static void SaveLevel_AUTH(FILE *file, struct LevelInfo *level)
   int i;
 
   for(i=0; i<MAX_LEVEL_AUTHOR_LEN; i++)
-    fputc(level->author[i], file);
+    putFile8Bit(file, level->author[i]);
+}
+
+static void SaveLevel_BODY(FILE *file, struct LevelInfo *level)
+{
+  int x, y;
+
+  for(y=0; y<level->fieldy; y++) 
+    for(x=0; x<level->fieldx; x++) 
+      if (level->encoding_16bit_field)
+       putFile16BitBE(file, level->field[x][y]);
+      else
+       putFile8Bit(file, level->field[x][y]);
 }
 
 #if 0
@@ -530,51 +872,39 @@ static void SaveLevel_CONT(FILE *file, struct LevelInfo *level)
 {
   int i, x, y;
 
-  fputc(EL_MAMPFER, file);
-  fputc(level->num_yam_contents, file);
-  fputc(0, file);
-  fputc(0, file);
+  putFile8Bit(file, EL_YAMYAM);
+  putFile8Bit(file, level->num_yamyam_contents);
+  putFile8Bit(file, 0);
+  putFile8Bit(file, 0);
 
   for(i=0; i<MAX_ELEMENT_CONTENTS; i++)
     for(y=0; y<3; y++)
       for(x=0; x<3; x++)
        if (level->encoding_16bit_field)
-         putFile16BitBE(file, level->yam_content[i][x][y]);
+         putFile16BitBE(file, level->yamyam_content[i][x][y]);
        else
-         fputc(level->yam_content[i][x][y], file);
+         putFile8Bit(file, level->yamyam_content[i][x][y]);
 }
 #endif
 
-static void SaveLevel_BODY(FILE *file, struct LevelInfo *level)
-{
-  int x, y;
-
-  for(y=0; y<level->fieldy; y++) 
-    for(x=0; x<level->fieldx; x++) 
-      if (level->encoding_16bit_field)
-       putFile16BitBE(file, Ur[x][y]);
-      else
-       fputc(Ur[x][y], file);
-}
-
 static void SaveLevel_CNT2(FILE *file, struct LevelInfo *level, int element)
 {
   int i, x, y;
   int num_contents, content_xsize, content_ysize;
   int content_array[MAX_ELEMENT_CONTENTS][3][3];
 
-  if (element == EL_MAMPFER)
+  if (element == EL_YAMYAM)
   {
-    num_contents = level->num_yam_contents;
+    num_contents = level->num_yamyam_contents;
     content_xsize = 3;
     content_ysize = 3;
 
     for(i=0; i<MAX_ELEMENT_CONTENTS; i++)
       for(y=0; y<3; y++)
        for(x=0; x<3; x++)
-         content_array[i][x][y] = level->yam_content[i][x][y];
+         content_array[i][x][y] = level->yamyam_content[i][x][y];
   }
-  else if (element == EL_AMOEBE_BD)
+  else if (element == EL_BD_AMOEBA)
   {
     num_contents = 1;
     content_xsize = 1;
@@ -583,7 +913,7 @@ static void SaveLevel_CNT2(FILE *file, struct LevelInfo *level, int element)
     for(i=0; i<MAX_ELEMENT_CONTENTS; i++)
       for(y=0; y<3; y++)
        for(x=0; x<3; x++)
-         content_array[i][x][y] = EL_LEERRAUM;
+         content_array[i][x][y] = EL_EMPTY;
     content_array[0][0][0] = level->amoeba_content;
   }
   else
@@ -596,9 +926,9 @@ static void SaveLevel_CNT2(FILE *file, struct LevelInfo *level, int element)
   }
 
   putFile16BitBE(file, element);
-  fputc(num_contents, file);
-  fputc(content_xsize, file);
-  fputc(content_ysize, file);
+  putFile8Bit(file, num_contents);
+  putFile8Bit(file, content_xsize);
+  putFile8Bit(file, content_ysize);
 
   WriteUnusedBytesToFile(file, LEVEL_CHUNK_CNT2_UNUSED);
 
@@ -608,11 +938,150 @@ static void SaveLevel_CNT2(FILE *file, struct LevelInfo *level, int element)
        putFile16BitBE(file, content_array[i][x][y]);
 }
 
-void SaveLevel(int level_nr)
+#if 0
+static void SaveLevel_CUS1(FILE *file, struct LevelInfo *level,
+                          int num_changed_custom_elements)
+{
+  int i, check = 0;
+
+  putFile16BitBE(file, num_changed_custom_elements);
+
+  for (i=0; i < NUM_CUSTOM_ELEMENTS; i++)
+  {
+    int element = EL_CUSTOM_START + i;
+
+    if (Properties[element][EP_BITFIELD_BASE] != EP_BITMASK_DEFAULT)
+    {
+      if (check < num_changed_custom_elements)
+      {
+       putFile16BitBE(file, element);
+       putFile32BitBE(file, Properties[element][EP_BITFIELD_BASE]);
+      }
+
+      check++;
+    }
+  }
+
+  if (check != num_changed_custom_elements)    /* should not happen */
+    Error(ERR_WARN, "inconsistent number of custom element properties");
+}
+#endif
+
+#if 0
+static void SaveLevel_CUS2(FILE *file, struct LevelInfo *level,
+                          int num_changed_custom_elements)
+{
+  int i, check = 0;
+
+  putFile16BitBE(file, num_changed_custom_elements);
+
+  for (i=0; i < NUM_CUSTOM_ELEMENTS; i++)
+  {
+    int element = EL_CUSTOM_START + i;
+
+    if (element_info[element].change.target_element != EL_EMPTY_SPACE)
+    {
+      if (check < num_changed_custom_elements)
+      {
+       putFile16BitBE(file, element);
+       putFile16BitBE(file, element_info[element].change.target_element);
+      }
+
+      check++;
+    }
+  }
+
+  if (check != num_changed_custom_elements)    /* should not happen */
+    Error(ERR_WARN, "inconsistent number of custom target elements");
+}
+#endif
+
+static void SaveLevel_CUS3(FILE *file, struct LevelInfo *level,
+                          int num_changed_custom_elements)
+{
+  int i, j, x, y, check = 0;
+
+  putFile16BitBE(file, num_changed_custom_elements);
+
+  for (i=0; i < NUM_CUSTOM_ELEMENTS; i++)
+  {
+    int element = EL_CUSTOM_START + i;
+
+    if (Properties[element][EP_BITFIELD_BASE] != EP_BITMASK_DEFAULT)
+    {
+      if (check < num_changed_custom_elements)
+      {
+       putFile16BitBE(file, element);
+
+       for(j=0; j<MAX_ELEMENT_NAME_LEN; j++)
+         putFile8Bit(file, element_info[element].description[j]);
+
+       putFile32BitBE(file, Properties[element][EP_BITFIELD_BASE]);
+
+       /* some free bytes for future properties and padding */
+       WriteUnusedBytesToFile(file, 7);
+
+       putFile8Bit(file, element_info[element].use_gfx_element);
+       putFile16BitBE(file, element_info[element].gfx_element);
+
+       putFile8Bit(file, element_info[element].score);
+       putFile8Bit(file, element_info[element].gem_count);
+
+       putFile16BitBE(file, element_info[element].push_delay_fixed);
+       putFile16BitBE(file, element_info[element].push_delay_random);
+       putFile16BitBE(file, element_info[element].move_delay_fixed);
+       putFile16BitBE(file, element_info[element].move_delay_random);
+
+       putFile16BitBE(file, element_info[element].move_pattern);
+       putFile8Bit(file, element_info[element].move_direction_initial);
+       putFile8Bit(file, element_info[element].move_stepsize);
+
+       for(y=0; y<3; y++)
+         for(x=0; x<3; x++)
+           putFile16BitBE(file, element_info[element].content[x][y]);
+
+       putFile32BitBE(file, element_info[element].change.events);
+
+       putFile16BitBE(file, element_info[element].change.target_element);
+
+       putFile16BitBE(file, element_info[element].change.delay_fixed);
+       putFile16BitBE(file, element_info[element].change.delay_random);
+       putFile16BitBE(file, element_info[element].change.delay_frames);
+
+       putFile16BitBE(file, element_info[element].change.trigger_element);
+
+       putFile8Bit(file, element_info[element].change.explode);
+       putFile8Bit(file, element_info[element].change.use_content);
+       putFile8Bit(file, element_info[element].change.only_complete);
+       putFile8Bit(file, element_info[element].change.use_random_change);
+
+       putFile8Bit(file, element_info[element].change.random);
+       putFile8Bit(file, element_info[element].change.power);
+
+       for(y=0; y<3; y++)
+         for(x=0; x<3; x++)
+           putFile16BitBE(file, element_info[element].change.content[x][y]);
+
+       putFile8Bit(file, element_info[element].slippery_type);
+
+       /* some free bytes for future properties and padding */
+       WriteUnusedBytesToFile(file, LEVEL_CPART_CUS3_UNUSED);
+      }
+
+      check++;
+    }
+  }
+
+  if (check != num_changed_custom_elements)    /* should not happen */
+    Error(ERR_WARN, "inconsistent number of custom element properties");
+}
+
+static void SaveLevelFromFilename(struct LevelInfo *level, char *filename)
 {
-  int i, x, y;
-  char *filename = getLevelFilename(level_nr);
   int body_chunk_size;
+  int num_changed_custom_elements = 0;
+  int level_chunk_CUS3_size;
+  int i, x, y;
   FILE *file;
 
   if (!(file = fopen(filename, MODE_WRITE)))
@@ -621,58 +1090,71 @@ void SaveLevel(int level_nr)
     return;
   }
 
-  level.file_version = FILE_VERSION_ACTUAL;
-  level.game_version = GAME_VERSION_ACTUAL;
+  level->file_version = FILE_VERSION_ACTUAL;
+  level->game_version = GAME_VERSION_ACTUAL;
 
   /* check level field for 16-bit elements */
-  level.encoding_16bit_field = FALSE;
-  for(y=0; y<level.fieldy; y++) 
-    for(x=0; x<level.fieldx; x++) 
-      if (Ur[x][y] > 255)
-       level.encoding_16bit_field = TRUE;
+  level->encoding_16bit_field = FALSE;
+  for(y=0; y<level->fieldy; y++) 
+    for(x=0; x<level->fieldx; x++) 
+      if (level->field[x][y] > 255)
+       level->encoding_16bit_field = TRUE;
 
   /* check yamyam content for 16-bit elements */
-  level.encoding_16bit_yamyam = FALSE;
-  for(i=0; i<level.num_yam_contents; i++)
+  level->encoding_16bit_yamyam = FALSE;
+  for(i=0; i<level->num_yamyam_contents; i++)
     for(y=0; y<3; y++)
       for(x=0; x<3; x++)
-       if (level.yam_content[i][x][y] > 255)
-         level.encoding_16bit_yamyam = TRUE;
+       if (level->yamyam_content[i][x][y] > 255)
+         level->encoding_16bit_yamyam = TRUE;
 
   /* check amoeba content for 16-bit elements */
-  level.encoding_16bit_amoeba = FALSE;
-  if (level.amoeba_content > 255)
-    level.encoding_16bit_amoeba = TRUE;
+  level->encoding_16bit_amoeba = FALSE;
+  if (level->amoeba_content > 255)
+    level->encoding_16bit_amoeba = TRUE;
 
+  /* calculate size of "BODY" chunk */
   body_chunk_size =
-    level.fieldx * level.fieldy * (level.encoding_16bit_field ? 2 : 1);
+    level->fieldx * level->fieldy * (level->encoding_16bit_field ? 2 : 1);
+
+  /* check for non-standard custom elements and calculate "CUS3" chunk size */
+  for (i=0; i < NUM_CUSTOM_ELEMENTS; i++)
+    if (Properties[EL_CUSTOM_START +i][EP_BITFIELD_BASE] != EP_BITMASK_DEFAULT)
+      num_changed_custom_elements++;
+  level_chunk_CUS3_size = LEVEL_CHUNK_CUS3_SIZE(num_changed_custom_elements);
 
   putFileChunkBE(file, "RND1", CHUNK_SIZE_UNDEFINED);
   putFileChunkBE(file, "CAVE", CHUNK_SIZE_NONE);
 
   putFileChunkBE(file, "VERS", FILE_VERS_CHUNK_SIZE);
-  SaveLevel_VERS(file, &level);
+  SaveLevel_VERS(file, level);
 
   putFileChunkBE(file, "HEAD", LEVEL_HEADER_SIZE);
-  SaveLevel_HEAD(file, &level);
+  SaveLevel_HEAD(file, level);
 
   putFileChunkBE(file, "AUTH", MAX_LEVEL_AUTHOR_LEN);
-  SaveLevel_AUTH(file, &level);
+  SaveLevel_AUTH(file, level);
 
   putFileChunkBE(file, "BODY", body_chunk_size);
-  SaveLevel_BODY(file, &level);
+  SaveLevel_BODY(file, level);
 
-  if (level.encoding_16bit_yamyam ||
-      level.num_yam_contents != STD_ELEMENT_CONTENTS)
+  if (level->encoding_16bit_yamyam ||
+      level->num_yamyam_contents != STD_ELEMENT_CONTENTS)
   {
     putFileChunkBE(file, "CNT2", LEVEL_CHUNK_CNT2_SIZE);
-    SaveLevel_CNT2(file, &level, EL_MAMPFER);
+    SaveLevel_CNT2(file, level, EL_YAMYAM);
   }
 
-  if (level.encoding_16bit_amoeba)
+  if (level->encoding_16bit_amoeba)
   {
     putFileChunkBE(file, "CNT2", LEVEL_CHUNK_CNT2_SIZE);
-    SaveLevel_CNT2(file, &level, EL_AMOEBE_BD);
+    SaveLevel_CNT2(file, level, EL_BD_AMOEBA);
+  }
+
+  if (num_changed_custom_elements > 0 && !level->use_custom_template)
+  {
+    putFileChunkBE(file, "CUS3", level_chunk_CUS3_size);
+    SaveLevel_CUS3(file, level, num_changed_custom_elements);
   }
 
   fclose(file);
@@ -680,6 +1162,49 @@ void SaveLevel(int level_nr)
   SetFilePermissions(filename, PERMS_PRIVATE);
 }
 
+void SaveLevel(int level_nr)
+{
+  char *filename = getLevelFilename(level_nr);
+
+  SaveLevelFromFilename(&level, filename);
+}
+
+void SaveLevelTemplate()
+{
+  char *filename = getLevelFilename(-1);
+
+  SaveLevelFromFilename(&level, filename);
+}
+
+void DumpLevel(struct LevelInfo *level)
+{
+  printf_line("-", 79);
+  printf("Level xxx (file version %08d, game version %08d)\n",
+        level->file_version, level->game_version);
+  printf_line("-", 79);
+
+  printf("Level Author: '%s'\n", level->author);
+  printf("Level Title:  '%s'\n", level->name);
+  printf("\n");
+  printf("Playfield Size: %d x %d\n", level->fieldx, level->fieldy);
+  printf("\n");
+  printf("Level Time:  %d seconds\n", level->time);
+  printf("Gems needed: %d\n", level->gems_needed);
+  printf("\n");
+  printf("Time for Magic Wall: %d seconds\n", level->time_magic_wall);
+  printf("Time for Wheel:      %d seconds\n", level->time_wheel);
+  printf("Time for Light:      %d seconds\n", level->time_light);
+  printf("Time for Timegate:   %d seconds\n", level->time_timegate);
+  printf("\n");
+  printf("Amoeba Speed: %d\n", level->amoeba_speed);
+  printf("\n");
+  printf("Gravity:                %s\n", (level->gravity ? "yes" : "no"));
+  printf("Double Speed Movement:  %s\n", (level->double_speed ? "yes" : "no"));
+  printf("EM style slippery gems: %s\n", (level->em_slippery_gems ? "yes" : "no"));
+
+  printf_line("-", 79);
+}
+
 
 /* ========================================================================= */
 /* tape file functions                                                       */
@@ -728,7 +1253,7 @@ static int LoadTape_HEAD(FILE *file, int chunk_size, struct TapeInfo *tape)
   /* read header fields that are new since version 1.2 */
   if (tape->file_version >= FILE_VERSION_1_2)
   {
-    byte store_participating_players = fgetc(file);
+    byte store_participating_players = getFile8Bit(file);
     int engine_version;
 
     /* since version 1.2, tapes store which players participate in the tape */
@@ -754,6 +1279,26 @@ static int LoadTape_HEAD(FILE *file, int chunk_size, struct TapeInfo *tape)
   return chunk_size;
 }
 
+static int LoadTape_INFO(FILE *file, int chunk_size, struct TapeInfo *tape)
+{
+  int level_identifier_size;
+  int i;
+
+  level_identifier_size = getFile16BitBE(file);
+
+  tape->level_identifier =
+    checked_realloc(tape->level_identifier, level_identifier_size);
+
+  for(i=0; i < level_identifier_size; i++)
+    tape->level_identifier[i] = getFile8Bit(file);
+
+  tape->level_nr = getFile16BitBE(file);
+
+  chunk_size = 2 + level_identifier_size + 2;
+
+  return chunk_size;
+}
+
 static int LoadTape_BODY(FILE *file, int chunk_size, struct TapeInfo *tape)
 {
   int i, j;
@@ -776,10 +1321,10 @@ static int LoadTape_BODY(FILE *file, int chunk_size, struct TapeInfo *tape)
       tape->pos[i].action[j] = MV_NO_MOVING;
 
       if (tape->player_participates[j])
-       tape->pos[i].action[j] = fgetc(file);
+       tape->pos[i].action[j] = getFile8Bit(file);
     }
 
-    tape->pos[i].delay = fgetc(file);
+    tape->pos[i].delay = getFile8Bit(file);
 
     if (tape->file_version == FILE_VERSION_1_0)
     {
@@ -838,9 +1383,8 @@ static int LoadTape_BODY(FILE *file, int chunk_size, struct TapeInfo *tape)
   return chunk_size;
 }
 
-void LoadTape(int level_nr)
+void LoadTapeFromFilename(char *filename)
 {
-  char *filename = getTapeFilename(level_nr);
   char cookie[MAX_LINE_LEN];
   char chunk_name[CHUNK_ID_LEN + 1];
   FILE *file;
@@ -908,6 +1452,7 @@ void LoadTape(int level_nr)
     {
       { "VERS", FILE_VERS_CHUNK_SIZE,  LoadTape_VERS },
       { "HEAD", TAPE_HEADER_SIZE,      LoadTape_HEAD },
+      { "INFO", -1,                    LoadTape_INFO },
       { "BODY", -1,                    LoadTape_BODY },
       {  NULL,  0,                     NULL }
     };
@@ -954,6 +1499,17 @@ void LoadTape(int level_nr)
   fclose(file);
 
   tape.length_seconds = GetTapeLength();
+
+#if 0
+  printf("tape version: %d\n", tape.game_version);
+#endif
+}
+
+void LoadTape(int level_nr)
+{
+  char *filename = getTapeFilename(level_nr);
+
+  LoadTapeFromFilename(filename);
 }
 
 static void SaveTape_VERS(FILE *file, struct TapeInfo *tape)
@@ -976,7 +1532,7 @@ static void SaveTape_HEAD(FILE *file, struct TapeInfo *tape)
   putFile32BitBE(file, tape->date);
   putFile32BitBE(file, tape->length);
 
-  fputc(store_participating_players, file);
+  putFile8Bit(file, store_participating_players);
 
   /* unused bytes not at the end here for 4-byte alignment of engine_version */
   WriteUnusedBytesToFile(file, TAPE_HEADER_UNUSED);
@@ -984,6 +1540,19 @@ static void SaveTape_HEAD(FILE *file, struct TapeInfo *tape)
   putFileVersion(file, tape->engine_version);
 }
 
+static void SaveTape_INFO(FILE *file, struct TapeInfo *tape)
+{
+  int level_identifier_size = strlen(tape->level_identifier) + 1;
+  int i;
+
+  putFile16BitBE(file, level_identifier_size);
+
+  for(i=0; i < level_identifier_size; i++)
+    putFile8Bit(file, tape->level_identifier[i]);
+
+  putFile16BitBE(file, tape->level_nr);
+}
+
 static void SaveTape_BODY(FILE *file, struct TapeInfo *tape)
 {
   int i, j;
@@ -992,20 +1561,21 @@ static void SaveTape_BODY(FILE *file, struct TapeInfo *tape)
   {
     for(j=0; j<MAX_PLAYERS; j++)
       if (tape->player_participates[j])
-       fputc(tape->pos[i].action[j], file);
+       putFile8Bit(file, tape->pos[i].action[j]);
 
-    fputc(tape->pos[i].delay, file);
+    putFile8Bit(file, tape->pos[i].delay);
   }
 }
 
 void SaveTape(int level_nr)
 {
-  int i;
   char *filename = getTapeFilename(level_nr);
   FILE *file;
   boolean new_tape = TRUE;
   int num_participating_players = 0;
+  int info_chunk_size;
   int body_chunk_size;
+  int i;
 
   InitTapeDirectory(leveldir_current->filename);
 
@@ -1031,6 +1601,7 @@ void SaveTape(int level_nr)
     if (tape.player_participates[i])
       num_participating_players++;
 
+  info_chunk_size = 2 + (strlen(tape.level_identifier) + 1) + 2;
   body_chunk_size = (num_participating_players + 1) * tape.length;
 
   putFileChunkBE(file, "RND1", CHUNK_SIZE_UNDEFINED);
@@ -1042,6 +1613,9 @@ void SaveTape(int level_nr)
   putFileChunkBE(file, "HEAD", TAPE_HEADER_SIZE);
   SaveTape_HEAD(file, &tape);
 
+  putFileChunkBE(file, "INFO", info_chunk_size);
+  SaveTape_INFO(file, &tape);
+
   putFileChunkBE(file, "BODY", body_chunk_size);
   SaveTape_BODY(file, &tape);
 
@@ -1065,17 +1639,19 @@ void DumpTape(struct TapeInfo *tape)
     return;
   }
 
-  printf("\n");
-  printf("-------------------------------------------------------------------------------\n");
-  printf("Tape of Level %d (file version %06d, game version %06d)\n",
+  printf_line("-", 79);
+  printf("Tape of Level %03d (file version %08d, game version %08d)\n",
         tape->level_nr, tape->file_version, tape->game_version);
-  printf("-------------------------------------------------------------------------------\n");
+  printf("Level series identifier: '%s'\n", tape->level_identifier);
+  printf_line("-", 79);
 
   for(i=0; i<tape->length; i++)
   {
     if (i >= MAX_TAPELEN)
       break;
 
+    printf("%03d: ", i);
+
     for(j=0; j<MAX_PLAYERS; j++)
     {
       if (tape->player_participates[j])
@@ -1096,7 +1672,7 @@ void DumpTape(struct TapeInfo *tape)
     printf("(%03d)\n", tape->pos[i].delay);
   }
 
-  printf("-------------------------------------------------------------------------------\n");
+  printf_line("-", 79);
 }
 
 
@@ -1214,40 +1790,67 @@ void SaveScore(int level_nr)
 
 #define NUM_GLOBAL_SETUP_TOKENS                        22
 
+/* editor setup */
+#define SETUP_TOKEN_EDITOR_EL_BOULDERDASH      0
+#define SETUP_TOKEN_EDITOR_EL_EMERALD_MINE     1
+#define SETUP_TOKEN_EDITOR_EL_MORE             2
+#define SETUP_TOKEN_EDITOR_EL_SOKOBAN          3
+#define SETUP_TOKEN_EDITOR_EL_SUPAPLEX         4
+#define SETUP_TOKEN_EDITOR_EL_DIAMOND_CAVES    5
+#define SETUP_TOKEN_EDITOR_EL_DX_BOULDERDASH   6
+#define SETUP_TOKEN_EDITOR_EL_CHARS            7
+#define SETUP_TOKEN_EDITOR_EL_CUSTOM           8
+
+#define NUM_EDITOR_SETUP_TOKENS                        9
+
 /* shortcut setup */
-#define SETUP_TOKEN_SAVE_GAME                  0
-#define SETUP_TOKEN_LOAD_GAME                  1
-#define SETUP_TOKEN_TOGGLE_PAUSE               2
+#define SETUP_TOKEN_SHORTCUT_SAVE_GAME         0
+#define SETUP_TOKEN_SHORTCUT_LOAD_GAME         1
+#define SETUP_TOKEN_SHORTCUT_TOGGLE_PAUSE      2
 
 #define NUM_SHORTCUT_SETUP_TOKENS              3
 
 /* player setup */
-#define SETUP_TOKEN_USE_JOYSTICK               0
-#define SETUP_TOKEN_JOY_DEVICE_NAME            1
-#define SETUP_TOKEN_JOY_XLEFT                  2
-#define SETUP_TOKEN_JOY_XMIDDLE                        3
-#define SETUP_TOKEN_JOY_XRIGHT                 4
-#define SETUP_TOKEN_JOY_YUPPER                 5
-#define SETUP_TOKEN_JOY_YMIDDLE                        6
-#define SETUP_TOKEN_JOY_YLOWER                 7
-#define SETUP_TOKEN_JOY_SNAP                   8
-#define SETUP_TOKEN_JOY_BOMB                   9
-#define SETUP_TOKEN_KEY_LEFT                   10
-#define SETUP_TOKEN_KEY_RIGHT                  11
-#define SETUP_TOKEN_KEY_UP                     12
-#define SETUP_TOKEN_KEY_DOWN                   13
-#define SETUP_TOKEN_KEY_SNAP                   14
-#define SETUP_TOKEN_KEY_BOMB                   15
+#define SETUP_TOKEN_PLAYER_USE_JOYSTICK                0
+#define SETUP_TOKEN_PLAYER_JOY_DEVICE_NAME     1
+#define SETUP_TOKEN_PLAYER_JOY_XLEFT           2
+#define SETUP_TOKEN_PLAYER_JOY_XMIDDLE         3
+#define SETUP_TOKEN_PLAYER_JOY_XRIGHT          4
+#define SETUP_TOKEN_PLAYER_JOY_YUPPER          5
+#define SETUP_TOKEN_PLAYER_JOY_YMIDDLE         6
+#define SETUP_TOKEN_PLAYER_JOY_YLOWER          7
+#define SETUP_TOKEN_PLAYER_JOY_SNAP            8
+#define SETUP_TOKEN_PLAYER_JOY_BOMB            9
+#define SETUP_TOKEN_PLAYER_KEY_LEFT            10
+#define SETUP_TOKEN_PLAYER_KEY_RIGHT           11
+#define SETUP_TOKEN_PLAYER_KEY_UP              12
+#define SETUP_TOKEN_PLAYER_KEY_DOWN            13
+#define SETUP_TOKEN_PLAYER_KEY_SNAP            14
+#define SETUP_TOKEN_PLAYER_KEY_BOMB            15
 
 #define NUM_PLAYER_SETUP_TOKENS                        16
 
+/* system setup */
+#define SETUP_TOKEN_SYSTEM_SDL_AUDIODRIVER     0
+#define SETUP_TOKEN_SYSTEM_AUDIO_FRAGMENT_SIZE 1
+
+#define NUM_SYSTEM_SETUP_TOKENS                        2
+
+/* options setup */
+#define SETUP_TOKEN_OPTIONS_VERBOSE            0
+
+#define NUM_OPTIONS_SETUP_TOKENS               1
+
+
 static struct SetupInfo si;
+static struct SetupEditorInfo sei;
 static struct SetupShortcutInfo ssi;
 static struct SetupInputInfo sii;
+static struct SetupSystemInfo syi;
+static struct OptionInfo soi;
 
 static struct TokenInfo global_setup_tokens[] =
 {
-  /* global setup */
   { TYPE_STRING, &si.player_name,      "player_name"                   },
   { TYPE_SWITCH, &si.sound,            "sound"                         },
   { TYPE_SWITCH, &si.sound_loops,      "repeating_sound_loops"         },
@@ -1272,9 +1875,21 @@ static struct TokenInfo global_setup_tokens[] =
   { TYPE_SWITCH, &si.override_level_music,    "override_level_music"   },
 };
 
+static struct TokenInfo editor_setup_tokens[] =
+{
+  { TYPE_SWITCH, &sei.el_boulderdash,  "editor.el_boulderdash"         },
+  { TYPE_SWITCH, &sei.el_emerald_mine, "editor.el_emerald_mine"        },
+  { TYPE_SWITCH, &sei.el_more,         "editor.el_more"                },
+  { TYPE_SWITCH, &sei.el_sokoban,      "editor.el_sokoban"             },
+  { TYPE_SWITCH, &sei.el_supaplex,     "editor.el_supaplex"            },
+  { TYPE_SWITCH, &sei.el_diamond_caves,        "editor.el_diamond_caves"       },
+  { TYPE_SWITCH, &sei.el_dx_boulderdash,"editor.el_dx_boulderdash"     },
+  { TYPE_SWITCH, &sei.el_chars,                "editor.el_chars"               },
+  { TYPE_SWITCH, &sei.el_custom,       "editor.el_custom"              },
+};
+
 static struct TokenInfo shortcut_setup_tokens[] =
 {
-  /* shortcut setup */
   { TYPE_KEY_X11, &ssi.save_game,      "shortcut.save_game"            },
   { TYPE_KEY_X11, &ssi.load_game,      "shortcut.load_game"            },
   { TYPE_KEY_X11, &ssi.toggle_pause,   "shortcut.toggle_pause"         }
@@ -1282,7 +1897,6 @@ static struct TokenInfo shortcut_setup_tokens[] =
 
 static struct TokenInfo player_setup_tokens[] =
 {
-  /* player setup */
   { TYPE_BOOLEAN, &sii.use_joystick,   ".use_joystick"                 },
   { TYPE_STRING,  &sii.joy.device_name,        ".joy.device_name"              },
   { TYPE_INTEGER, &sii.joy.xleft,      ".joy.xleft"                    },
@@ -1301,11 +1915,37 @@ static struct TokenInfo player_setup_tokens[] =
   { TYPE_KEY_X11, &sii.key.bomb,       ".key.place_bomb"               }
 };
 
+static struct TokenInfo system_setup_tokens[] =
+{
+  { TYPE_STRING,  &syi.sdl_audiodriver,        "system.sdl_audiodriver"        },
+  { TYPE_INTEGER, &syi.audio_fragment_size,"system.audio_fragment_size"        }
+};
+
+static struct TokenInfo options_setup_tokens[] =
+{
+  { TYPE_BOOLEAN, &soi.verbose,                "options.verbose"               }
+};
+
+static char *get_corrected_login_name(char *login_name)
+{
+  /* needed because player name must be a fixed length string */
+  char *login_name_new = checked_malloc(MAX_PLAYER_NAME_LEN + 1);
+
+  strncpy(login_name_new, login_name, MAX_PLAYER_NAME_LEN);
+  login_name_new[MAX_PLAYER_NAME_LEN] = '\0';
+
+  if (strlen(login_name) > MAX_PLAYER_NAME_LEN)                /* name has been cut */
+    if (strchr(login_name_new, ' '))
+      *strchr(login_name_new, ' ') = '\0';
+
+  return login_name_new;
+}
+
 static void setSetupInfoToDefaults(struct SetupInfo *si)
 {
   int i;
 
-  si->player_name = getStringCopy(getLoginName());
+  si->player_name = get_corrected_login_name(getLoginName());
 
   si->sound = TRUE;
   si->sound_loops = TRUE;
@@ -1332,6 +1972,16 @@ static void setSetupInfoToDefaults(struct SetupInfo *si)
   si->override_level_sounds = FALSE;
   si->override_level_music = FALSE;
 
+  si->editor.el_boulderdash = TRUE;
+  si->editor.el_emerald_mine = TRUE;
+  si->editor.el_more = TRUE;
+  si->editor.el_sokoban = TRUE;
+  si->editor.el_supaplex = TRUE;
+  si->editor.el_diamond_caves = TRUE;
+  si->editor.el_dx_boulderdash = TRUE;
+  si->editor.el_chars = TRUE;
+  si->editor.el_custom = TRUE;
+
   si->shortcut.save_game = DEFAULT_KEY_SAVE_GAME;
   si->shortcut.load_game = DEFAULT_KEY_LOAD_GAME;
   si->shortcut.toggle_pause = DEFAULT_KEY_TOGGLE_PAUSE;
@@ -1355,27 +2005,39 @@ static void setSetupInfoToDefaults(struct SetupInfo *si)
     si->input[i].key.snap  = (i == 0 ? DEFAULT_KEY_SNAP  : KSYM_UNDEFINED);
     si->input[i].key.bomb  = (i == 0 ? DEFAULT_KEY_BOMB  : KSYM_UNDEFINED);
   }
+
+  si->system.sdl_audiodriver = getStringCopy(ARG_DEFAULT);
+  si->system.audio_fragment_size = DEFAULT_AUDIO_FRAGMENT_SIZE;
+
+  si->options.verbose = FALSE;
 }
 
-static void decodeSetupFileList(struct SetupFileList *setup_file_list)
+static void decodeSetupFileHash(SetupFileHash *setup_file_hash)
 {
   int i, pnr;
 
-  if (!setup_file_list)
+  if (!setup_file_hash)
     return;
 
   /* global setup */
   si = setup;
   for (i=0; i<NUM_GLOBAL_SETUP_TOKENS; i++)
     setSetupInfo(global_setup_tokens, i,
-                getTokenValue(setup_file_list, global_setup_tokens[i].text));
+                getHashEntry(setup_file_hash, global_setup_tokens[i].text));
   setup = si;
 
+  /* editor setup */
+  sei = setup.editor;
+  for (i=0; i<NUM_EDITOR_SETUP_TOKENS; i++)
+    setSetupInfo(editor_setup_tokens, i,
+                getHashEntry(setup_file_hash,editor_setup_tokens[i].text));
+  setup.editor = sei;
+
   /* shortcut setup */
   ssi = setup.shortcut;
   for (i=0; i<NUM_SHORTCUT_SETUP_TOKENS; i++)
     setSetupInfo(shortcut_setup_tokens, i,
-                getTokenValue(setup_file_list,shortcut_setup_tokens[i].text));
+                getHashEntry(setup_file_hash,shortcut_setup_tokens[i].text));
   setup.shortcut = ssi;
 
   /* player setup */
@@ -1392,42 +2054,51 @@ static void decodeSetupFileList(struct SetupFileList *setup_file_list)
 
       sprintf(full_token, "%s%s", prefix, player_setup_tokens[i].text);
       setSetupInfo(player_setup_tokens, i,
-                  getTokenValue(setup_file_list, full_token));
+                  getHashEntry(setup_file_hash, full_token));
     }
     setup.input[pnr] = sii;
   }
+
+  /* system setup */
+  syi = setup.system;
+  for (i=0; i<NUM_SYSTEM_SETUP_TOKENS; i++)
+    setSetupInfo(system_setup_tokens, i,
+                getHashEntry(setup_file_hash, system_setup_tokens[i].text));
+  setup.system = syi;
+
+  /* options setup */
+  soi = setup.options;
+  for (i=0; i<NUM_OPTIONS_SETUP_TOKENS; i++)
+    setSetupInfo(options_setup_tokens, i,
+                getHashEntry(setup_file_hash, options_setup_tokens[i].text));
+  setup.options = soi;
 }
 
 void LoadSetup()
 {
   char *filename = getSetupFilename();
-  struct SetupFileList *setup_file_list = NULL;
+  SetupFileHash *setup_file_hash = NULL;
 
   /* always start with reliable default values */
   setSetupInfoToDefaults(&setup);
 
-  setup_file_list = loadSetupFileList(filename);
+  setup_file_hash = loadSetupFileHash(filename);
 
-  if (setup_file_list)
+  if (setup_file_hash)
   {
-    checkSetupFileListIdentifier(setup_file_list, getCookie("SETUP"));
-    decodeSetupFileList(setup_file_list);
+    char *player_name_new;
+
+    checkSetupFileHashIdentifier(setup_file_hash, getCookie("SETUP"));
+    decodeSetupFileHash(setup_file_hash);
 
     setup.direct_draw = !setup.double_buffering;
 
-    freeSetupFileList(setup_file_list);
+    freeSetupFileHash(setup_file_hash);
 
     /* needed to work around problems with fixed length strings */
-    if (strlen(setup.player_name) > MAX_PLAYER_NAME_LEN)
-      setup.player_name[MAX_PLAYER_NAME_LEN] = '\0';
-    else if (strlen(setup.player_name) < MAX_PLAYER_NAME_LEN)
-    {
-      char *new_name = checked_malloc(MAX_PLAYER_NAME_LEN + 1);
-
-      strcpy(new_name, setup.player_name);
-      free(setup.player_name);
-      setup.player_name = new_name;
-    }
+    player_name_new = get_corrected_login_name(setup.player_name);
+    free(setup.player_name);
+    setup.player_name = player_name_new;
   }
   else
     Error(ERR_WARN, "using default setup values");
@@ -1455,13 +2126,20 @@ void SaveSetup()
   si = setup;
   for (i=0; i<NUM_GLOBAL_SETUP_TOKENS; i++)
   {
-    fprintf(file, "%s\n", getSetupLine(global_setup_tokens, "", i));
-
     /* just to make things nicer :) */
-    if (i == SETUP_TOKEN_PLAYER_NAME || i == SETUP_TOKEN_GRAPHICS_SET - 1)
+    if (i == SETUP_TOKEN_PLAYER_NAME + 1 ||
+       i == SETUP_TOKEN_GRAPHICS_SET)
       fprintf(file, "\n");
+
+    fprintf(file, "%s\n", getSetupLine(global_setup_tokens, "", i));
   }
 
+  /* editor setup */
+  sei = setup.editor;
+  fprintf(file, "\n");
+  for (i=0; i<NUM_EDITOR_SETUP_TOKENS; i++)
+    fprintf(file, "%s\n", getSetupLine(editor_setup_tokens, "", i));
+
   /* shortcut setup */
   ssi = setup.shortcut;
   fprintf(file, "\n");
@@ -1481,7 +2159,94 @@ void SaveSetup()
       fprintf(file, "%s\n", getSetupLine(player_setup_tokens, prefix, i));
   }
 
+  /* system setup */
+  syi = setup.system;
+  fprintf(file, "\n");
+  for (i=0; i<NUM_SYSTEM_SETUP_TOKENS; i++)
+    fprintf(file, "%s\n", getSetupLine(system_setup_tokens, "", i));
+
+  /* options setup */
+  soi = setup.options;
+  fprintf(file, "\n");
+  for (i=0; i<NUM_OPTIONS_SETUP_TOKENS; i++)
+    fprintf(file, "%s\n", getSetupLine(options_setup_tokens, "", i));
+
   fclose(file);
 
   SetFilePermissions(filename, PERMS_PRIVATE);
 }
+
+void LoadCustomElementDescriptions()
+{
+  char *filename = getCustomArtworkConfigFilename(ARTWORK_TYPE_GRAPHICS);
+  SetupFileHash *setup_file_hash;
+  int i;
+
+  for (i=0; i<NUM_FILE_ELEMENTS; i++)
+  {
+    if (element_info[i].custom_description != NULL)
+    {
+      free(element_info[i].custom_description);
+      element_info[i].custom_description = NULL;
+    }
+  }
+
+  if ((setup_file_hash = loadSetupFileHash(filename)) == NULL)
+    return;
+
+  for (i=0; i<NUM_FILE_ELEMENTS; i++)
+  {
+    char *token = getStringCat2(element_info[i].token_name, ".name");
+    char *value = getHashEntry(setup_file_hash, token);
+
+    if (value != NULL)
+      element_info[i].custom_description = getStringCopy(value);
+
+    free(token);
+  }
+
+  freeSetupFileHash(setup_file_hash);
+}
+
+void LoadSpecialMenuDesignSettings()
+{
+  char *filename = getCustomArtworkConfigFilename(ARTWORK_TYPE_GRAPHICS);
+  SetupFileHash *setup_file_hash;
+  int i, j;
+
+  /* always start with reliable default values from default config */
+  for (i=0; image_config_vars[i].token != NULL; i++)
+    for (j=0; image_config[j].token != NULL; j++)
+      if (strcmp(image_config_vars[i].token, image_config[j].token) == 0)
+       *image_config_vars[i].value =
+         get_integer_from_string(image_config[j].value);
+
+  if ((setup_file_hash = loadSetupFileHash(filename)) == NULL)
+    return;
+
+  /* special case: initialize with default values that may be overwritten */
+  for (i=0; i < NUM_SPECIAL_GFX_ARGS; i++)
+  {
+    char *value_x = getHashEntry(setup_file_hash, "menu.draw_xoffset");
+    char *value_y = getHashEntry(setup_file_hash, "menu.draw_yoffset");
+    char *list_size = getHashEntry(setup_file_hash, "menu.list_size");
+
+    if (value_x != NULL)
+      menu.draw_xoffset[i] = get_integer_from_string(value_x);
+    if (value_y != NULL)
+      menu.draw_yoffset[i] = get_integer_from_string(value_y);
+    if (list_size != NULL)
+      menu.list_size[i] = get_integer_from_string(list_size);
+  }
+
+  /* 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);
+
+    if (value != NULL)
+      *image_config_vars[i].value = get_integer_from_string(value);
+  }
+
+  freeSetupFileHash(setup_file_hash);
+}
index 1409ba9c3063a0fcd0ebcd88da50d3fef1bbba4b..5f5f67dc74cebda330e7159e949724e9e337a4b9 100644 (file)
 
 #include "main.h"
 
+boolean LevelFileExists(int);
+void LoadLevelFromFilename(struct LevelInfo *, char *);
 void LoadLevel(int);
+void LoadLevelTemplate(int);
 void SaveLevel(int);
+void SaveLevelTemplate();
+void DumpLevel(struct LevelInfo *);
 
+void LoadTapeFromFilename(char *);
 void LoadTape(int);
 void SaveTape(int);
 void DumpTape(struct TapeInfo *);
@@ -26,7 +32,10 @@ void DumpTape(struct TapeInfo *);
 void LoadScore(int);
 void SaveScore(int);
 
-void LoadSetup(void);
-void SaveSetup(void);
+void LoadSetup();
+void SaveSetup();
+
+void LoadCustomElementDescriptions();
+void LoadSpecialMenuDesignSettings();
 
 #endif /* FILES_H */
index bc31c194de0672b1a07164c40710502c6d7562ca..a9256de700b26165492684b984d700a492895e22 100644 (file)
@@ -14,9 +14,9 @@
 #include "libgame/libgame.h"
 
 #include "game.h"
+#include "init.h"
 #include "tools.h"
 #include "screens.h"
-#include "init.h"
 #include "files.h"
 #include "tape.h"
 #include "network.h"
 #define DOUBLE_PLAYER_SPEED(p) (HALVE_MOVE_DELAY((p)->move_delay_value))
 #define HALVE_PLAYER_SPEED(p)  (DOUBLE_MOVE_DELAY((p)->move_delay_value))
 
+/* values for other actions */
+#define MOVE_STEPSIZE_NORMAL   (TILEX / MOVE_DELAY_NORMAL_SPEED)
+
+#define        INIT_GFX_RANDOM()       (SimpleRND(1000000))
+
+#define GET_NEW_PUSH_DELAY(e)  (   (element_info[e].push_delay_fixed) + \
+                                RND(element_info[e].push_delay_random))
+#define GET_NEW_MOVE_DELAY(e)  (   (element_info[e].move_delay_fixed) + \
+                                RND(element_info[e].move_delay_random))
+
+#define ELEMENT_CAN_ENTER_FIELD_GENERIC(e, x, y, condition)            \
+               (IN_LEV_FIELD(x, y) && (IS_FREE(x, y) ||                \
+                                       (condition) ||                  \
+                                       (DONT_COLLIDE_WITH(e) &&        \
+                                        IS_FREE_OR_PLAYER(x, y))))
+
+#define ELEMENT_CAN_ENTER_FIELD_GENERIC_2(x, y, condition)             \
+               (IN_LEV_FIELD(x, y) && (IS_FREE(x, y) ||                \
+                                       (condition)))
+
+#define ELEMENT_CAN_ENTER_FIELD(e, x, y)                               \
+       ELEMENT_CAN_ENTER_FIELD_GENERIC(e, x, y, 0)
+
+#define ELEMENT_CAN_ENTER_FIELD_OR_ACID(e, x, y)                       \
+       ELEMENT_CAN_ENTER_FIELD_GENERIC(e, x, y, (Feld[x][y] == EL_ACID))
+
+#define ELEMENT_CAN_ENTER_FIELD_OR_ACID_2(x, y)                                \
+       ELEMENT_CAN_ENTER_FIELD_GENERIC_2(x, y, (Feld[x][y] == EL_ACID))
+
+#define ENEMY_CAN_ENTER_FIELD(x, y) (IN_LEV_FIELD(x, y) && IS_FREE(x, y))
+
+#define YAMYAM_CAN_ENTER_FIELD(x, y)                                   \
+               (IN_LEV_FIELD(x, y) && (IS_FREE_OR_PLAYER(x, y) ||      \
+                                       Feld[x][y] == EL_DIAMOND))
+
+#define DARK_YAMYAM_CAN_ENTER_FIELD(x, y)                              \
+               (IN_LEV_FIELD(x, y) && (IS_FREE_OR_PLAYER(x, y) ||      \
+                                       IS_FOOD_DARK_YAMYAM(Feld[x][y])))
+
+#define PACMAN_CAN_ENTER_FIELD(x, y)                                   \
+               (IN_LEV_FIELD(x, y) && (IS_FREE_OR_PLAYER(x, y) ||      \
+                                       IS_AMOEBOID(Feld[x][y])))
+
+#define PIG_CAN_ENTER_FIELD(x, y)                                      \
+               (IN_LEV_FIELD(x, y) && (IS_FREE(x, y) ||                \
+                                       IS_FOOD_PIG(Feld[x][y])))
+
+#define PENGUIN_CAN_ENTER_FIELD(x, y)                                  \
+               (IN_LEV_FIELD(x, y) && (IS_FREE(x, y) ||                \
+                                       IS_FOOD_PENGUIN(Feld[x][y]) ||  \
+                                       Feld[x][y] == EL_EXIT_OPEN ||   \
+                                       Feld[x][y] == EL_ACID))
+
+#define MOLE_CAN_ENTER_FIELD(x, y, condition)                          \
+               (IN_LEV_FIELD(x, y) && (IS_FREE(x, y) || (condition)))
+
+#define IN_LEV_FIELD_AND_IS_FREE(x, y)  (IN_LEV_FIELD(x, y) &&  IS_FREE(x, y))
+#define IN_LEV_FIELD_AND_NOT_FREE(x, y) (IN_LEV_FIELD(x, y) && !IS_FREE(x, y))
+
 /* game button identifiers */
 #define GAME_CTRL_ID_STOP              0
 #define GAME_CTRL_ID_PAUSE             1
 
 #define NUM_GAME_BUTTONS               6
 
+
 /* forward declaration for internal use */
+
+static void InitBeltMovement(void);
 static void CloseAllOpenTimegates(void);
 static void CheckGravityMovement(struct PlayerInfo *);
 static void KillHeroUnlessProtected(int, int);
 
-void PlaySoundLevel(int, int, int);
-void PlaySoundLevelAction(int, int, int);
-void PlaySoundLevelElementAction(int, int, int, int);
+static void TestIfPlayerTouchesCustomElement(int, int);
+static void TestIfElementTouchesCustomElement(int, int);
+
+static boolean CheckTriggeredElementChange(int, int, int, int);
+static boolean CheckElementChange(int, int, int, int);
+static void ChangeElementNow(int, int, int);
+
+static void PlaySoundLevel(int, int, int);
+static void PlaySoundLevelNearest(int, int, int);
+static void PlaySoundLevelAction(int, int, int);
+static void PlaySoundLevelElementAction(int, int, int, int);
+static void PlaySoundLevelActionIfLoop(int, int, int);
+static void StopSoundLevelActionIfLoop(int, int, int);
 
 static void MapGameButtons();
 static void HandleGameButtons(struct GadgetInfo *);
 
 static struct GadgetInfo *game_gadget[NUM_GAME_BUTTONS];
 
-#define SND_ACTION_UNKNOWN             0
-#define SND_ACTION_WAITING             1
-#define SND_ACTION_MOVING              2
-#define SND_ACTION_DIGGING             3
-#define SND_ACTION_COLLECTING          4
-#define SND_ACTION_PASSING             5
-#define SND_ACTION_IMPACT              6
-#define SND_ACTION_PUSHING             7
-#define SND_ACTION_ACTIVATING          8
-#define SND_ACTION_BURNING             9
 
-#define NUM_SND_ACTIONS                        10
+/* ------------------------------------------------------------------------- */
+/* definition of elements that automatically change to other elements after  */
+/* a specified time, eventually calling a function when changing             */
+/* ------------------------------------------------------------------------- */
 
-static struct
-{
-  char *text;
-  int value;
-  boolean is_loop;
-} sound_action_properties[] =
-{
-  /* insert _all_ loop sound actions here */
-  { ".waiting",                SND_ACTION_WAITING,     TRUE },
-  { ".moving",         SND_ACTION_MOVING,      TRUE }, /* continuos moving */
-  { ".running",                SND_ACTION_UNKNOWN,     TRUE },
-  { ".burning",                SND_ACTION_BURNING,     TRUE },
-  { ".growing",                SND_ACTION_UNKNOWN,     TRUE },
-  { ".attacking",      SND_ACTION_UNKNOWN,     TRUE },
-  { ".activated",      SND_ACTION_UNKNOWN,     TRUE },
-
-  /* other (non-loop) sound actions are optional */
-  { ".stepping",       SND_ACTION_MOVING,      FALSE }, /* discrete moving */
-  { ".digging",                SND_ACTION_DIGGING,     FALSE },
-  { ".collecting",     SND_ACTION_COLLECTING,  FALSE },
-  { ".passing",                SND_ACTION_PASSING,     FALSE },
-  { ".impact",         SND_ACTION_IMPACT,      FALSE },
-  { ".pushing",                SND_ACTION_PUSHING,     FALSE },
-  { ".activating",     SND_ACTION_ACTIVATING,  FALSE },
-  { NULL,              0,                      0 },
-};
-static int element_action_sound[NUM_LEVEL_ELEMENTS][NUM_SND_ACTIONS];
-static boolean is_loop_sound[NUM_SOUND_EFFECTS];
+/* forward declaration for changer functions */
+static void InitBuggyBase(int x, int y);
+static void WarnBuggyBase(int x, int y);
 
-#define IS_LOOP_SOUND(x)       (is_loop_sound[x])
+static void InitTrap(int x, int y);
+static void ActivateTrap(int x, int y);
+static void ChangeActiveTrap(int x, int y);
 
+static void InitRobotWheel(int x, int y);
+static void RunRobotWheel(int x, int y);
+static void StopRobotWheel(int x, int y);
 
-#ifdef DEBUG
-#if 0
-static unsigned int getStateCheckSum(int counter)
+static void InitTimegateWheel(int x, int y);
+static void RunTimegateWheel(int x, int y);
+
+struct ChangingElementInfo
 {
-  int x, y;
-  unsigned int mult = 1;
-  unsigned int checksum = 0;
-  /*
-  static short lastFeld[MAX_LEV_FIELDX][MAX_LEV_FIELDY];
-  */
-  static boolean first_game = TRUE;
+  int element;
+  int target_element;
+  int change_delay;
+  void (*pre_change_function)(int x, int y);
+  void (*change_function)(int x, int y);
+  void (*post_change_function)(int x, int y);
+};
 
-  for (y=0; y<lev_fieldy; y++) for(x=0; x<lev_fieldx; x++)
+static struct ChangingElementInfo changing_element_list[] =
+{
   {
-    /*
-    if (counter == 3)
-    {
-      if (first_game)
-       lastFeld[x][y] = Feld[x][y];
-      else if (lastFeld[x][y] != Feld[x][y])
-       printf("DIFF: [%d][%d]: lastFeld == %d != %d == Feld\n",
-              x, y, lastFeld[x][y], Feld[x][y]);
-    }
-    */
+    EL_NUT_BREAKING,
+    EL_EMERALD,
+    6,
+    NULL,
+    NULL,
+    NULL
+  },
+  {
+    EL_PEARL_BREAKING,
+    EL_EMPTY,
+    8,
+    NULL,
+    NULL,
+    NULL
+  },
+  {
+    EL_EXIT_OPENING,
+    EL_EXIT_OPEN,
+    29,
+    NULL,
+    NULL,
+    NULL
+  },
+  {
+    EL_SWITCHGATE_OPENING,
+    EL_SWITCHGATE_OPEN,
+    29,
+    NULL,
+    NULL,
+    NULL
+  },
+  {
+    EL_SWITCHGATE_CLOSING,
+    EL_SWITCHGATE_CLOSED,
+    29,
+    NULL,
+    NULL,
+    NULL
+  },
+  {
+    EL_TIMEGATE_OPENING,
+    EL_TIMEGATE_OPEN,
+    29,
+    NULL,
+    NULL,
+    NULL
+  },
+  {
+    EL_TIMEGATE_CLOSING,
+    EL_TIMEGATE_CLOSED,
+    29,
+    NULL,
+    NULL,
+    NULL
+  },
 
-    checksum += mult++ * Ur[x][y];
-    checksum += mult++ * Feld[x][y];
+  {
+    EL_ACID_SPLASH_LEFT,
+    EL_EMPTY,
+    8,
+    NULL,
+    NULL,
+    NULL
+  },
+  {
+    EL_ACID_SPLASH_RIGHT,
+    EL_EMPTY,
+    8,
+    NULL,
+    NULL,
+    NULL
+  },
+  {
+    EL_SP_BUGGY_BASE,
+    EL_SP_BUGGY_BASE_ACTIVATING,
+    0,
+    InitBuggyBase,
+    NULL,
+    NULL
+  },
+  {
+    EL_SP_BUGGY_BASE_ACTIVATING,
+    EL_SP_BUGGY_BASE_ACTIVE,
+    0,
+    InitBuggyBase,
+    NULL,
+    NULL
+  },
+  {
+    EL_SP_BUGGY_BASE_ACTIVE,
+    EL_SP_BUGGY_BASE,
+    0,
+    InitBuggyBase,
+    WarnBuggyBase,
+    NULL
+  },
+  {
+    EL_TRAP,
+    EL_TRAP_ACTIVE,
+    0,
+    InitTrap,
+    NULL,
+    ActivateTrap
+  },
+  {
+    EL_TRAP_ACTIVE,
+    EL_TRAP,
+    31,
+    NULL,
+    ChangeActiveTrap,
+    NULL
+  },
+  {
+    EL_ROBOT_WHEEL_ACTIVE,
+    EL_ROBOT_WHEEL,
+    0,
+    InitRobotWheel,
+    RunRobotWheel,
+    StopRobotWheel
+  },
+  {
+    EL_TIMEGATE_SWITCH_ACTIVE,
+    EL_TIMEGATE_SWITCH,
+    0,
+    InitTimegateWheel,
+    RunTimegateWheel,
+    NULL
+  },
 
-    /*
-    checksum += mult++ * MovPos[x][y];
-    checksum += mult++ * MovDir[x][y];
-    checksum += mult++ * MovDelay[x][y];
-    checksum += mult++ * Store[x][y];
-    checksum += mult++ * Store2[x][y];
-    checksum += mult++ * StorePlayer[x][y];
-    checksum += mult++ * Frame[x][y];
-    checksum += mult++ * AmoebaNr[x][y];
-    checksum += mult++ * JustStopped[x][y];
-    checksum += mult++ * Stop[x][y];
-    */
+  {
+    EL_UNDEFINED,
+    EL_UNDEFINED,
+    -1,
+    NULL,
+    NULL,
+    NULL
   }
+};
+
+struct
+{
+  int element;
+  int push_delay_fixed, push_delay_random;
+}
+push_delay_list[] =
+{
+  { EL_SPRING,                 0, 0 },
+  { EL_BALLOON,                        0, 0 },
 
-  if (counter == 3 && first_game)
-    first_game = FALSE;
+  { EL_SOKOBAN_OBJECT,         2, 0 },
+  { EL_SOKOBAN_FIELD_FULL,     2, 0 },
+  { EL_SATELLITE,              2, 0 },
+  { EL_SP_DISK_YELLOW,         2, 0 },
+
+  { EL_UNDEFINED,              0, 0 },
+};
+
+struct
+{
+  int element;
+  int move_stepsize;
+}
+move_stepsize_list[] =
+{
+  { EL_AMOEBA_DROP,            2 },
+  { EL_AMOEBA_DROPPING,                2 },
+  { EL_QUICKSAND_FILLING,      1 },
+  { EL_QUICKSAND_EMPTYING,     1 },
+  { EL_MAGIC_WALL_FILLING,     2 },
+  { EL_BD_MAGIC_WALL_FILLING,  2 },
+  { EL_MAGIC_WALL_EMPTYING,    2 },
+  { EL_BD_MAGIC_WALL_EMPTYING, 2 },
+
+  { EL_UNDEFINED,              0 },
+};
 
-  return checksum;
+struct
+{
+  int element;
+  int gem_count;
 }
-#endif
-#endif
+gem_count_list[] =
+{
+  { EL_EMERALD,                        1 },
+  { EL_BD_DIAMOND,             1 },
+  { EL_EMERALD_YELLOW,         1 },
+  { EL_EMERALD_RED,            1 },
+  { EL_EMERALD_PURPLE,         1 },
+  { EL_DIAMOND,                        3 },
+  { EL_SP_INFOTRON,            1 },
+  { EL_PEARL,                  5 },
+  { EL_CRYSTAL,                        8 },
+
+  { EL_UNDEFINED,              0 },
+};
 
+static boolean changing_element[MAX_NUM_ELEMENTS];
+static unsigned long trigger_events[MAX_NUM_ELEMENTS];
 
+#define IS_AUTO_CHANGING(e)    (changing_element[e])
+#define IS_JUST_CHANGING(x, y) (ChangeDelay[x][y] != 0)
+#define IS_CHANGING(x, y)      (IS_AUTO_CHANGING(Feld[x][y]) || \
+                                IS_JUST_CHANGING(x, y))
 
 
 void GetPlayerConfig()
@@ -231,37 +444,44 @@ void GetPlayerConfig()
   InitJoysticks();
 }
 
-static int getBeltNrFromElement(int element)
+static int getBeltNrFromBeltElement(int element)
+{
+  return (element < EL_CONVEYOR_BELT_2_LEFT ? 0 :
+         element < EL_CONVEYOR_BELT_3_LEFT ? 1 :
+         element < EL_CONVEYOR_BELT_4_LEFT ? 2 : 3);
+}
+
+static int getBeltNrFromBeltActiveElement(int element)
 {
-  return (element < EL_BELT2_LEFT ? 0 :
-         element < EL_BELT3_LEFT ? 1 :
-         element < EL_BELT4_LEFT ? 2 : 3);
+  return (element < EL_CONVEYOR_BELT_2_LEFT_ACTIVE ? 0 :
+         element < EL_CONVEYOR_BELT_3_LEFT_ACTIVE ? 1 :
+         element < EL_CONVEYOR_BELT_4_LEFT_ACTIVE ? 2 : 3);
 }
 
-static int getBeltNrFromSwitchElement(int element)
+static int getBeltNrFromBeltSwitchElement(int element)
 {
-  return (element < EL_BELT2_SWITCH_LEFT ? 0 :
-         element < EL_BELT3_SWITCH_LEFT ? 1 :
-         element < EL_BELT4_SWITCH_LEFT ? 2 : 3);
+  return (element < EL_CONVEYOR_BELT_2_SWITCH_LEFT ? 0 :
+         element < EL_CONVEYOR_BELT_3_SWITCH_LEFT ? 1 :
+         element < EL_CONVEYOR_BELT_4_SWITCH_LEFT ? 2 : 3);
 }
 
-static int getBeltDirNrFromSwitchElement(int element)
+static int getBeltDirNrFromBeltSwitchElement(int element)
 {
   static int belt_base_element[4] =
   {
-    EL_BELT1_SWITCH_LEFT,
-    EL_BELT2_SWITCH_LEFT,
-    EL_BELT3_SWITCH_LEFT,
-    EL_BELT4_SWITCH_LEFT
+    EL_CONVEYOR_BELT_1_SWITCH_LEFT,
+    EL_CONVEYOR_BELT_2_SWITCH_LEFT,
+    EL_CONVEYOR_BELT_3_SWITCH_LEFT,
+    EL_CONVEYOR_BELT_4_SWITCH_LEFT
   };
 
-  int belt_nr = getBeltNrFromSwitchElement(element);
+  int belt_nr = getBeltNrFromBeltSwitchElement(element);
   int belt_dir_nr = element - belt_base_element[belt_nr];
 
   return (belt_dir_nr % 3);
 }
 
-static int getBeltDirFromSwitchElement(int element)
+static int getBeltDirFromBeltSwitchElement(int element)
 {
   static int belt_move_dir[3] =
   {
@@ -270,14 +490,16 @@ static int getBeltDirFromSwitchElement(int element)
     MV_RIGHT
   };
 
-  int belt_dir_nr = getBeltDirNrFromSwitchElement(element);
+  int belt_dir_nr = getBeltDirNrFromBeltSwitchElement(element);
 
   return belt_move_dir[belt_dir_nr];
 }
 
 static void InitField(int x, int y, boolean init_game)
 {
-  switch (Feld[x][y])
+  int element = Feld[x][y];
+
+  switch (element)
   {
     case EL_SP_MURPHY:
       if (init_game)
@@ -287,19 +509,21 @@ static void InitField(int x, int y, boolean init_game)
          Feld[x][y] = EL_SP_MURPHY_CLONE;
          break;
        }
+       else
+       {
+         stored_player[0].use_murphy_graphic = TRUE;
+       }
+
+       Feld[x][y] = EL_PLAYER_1;
       }
       /* no break! */
-    case EL_SPIELFIGUR:
-      if (init_game)
-       Feld[x][y] = EL_SPIELER1;
-      /* no break! */
-    case EL_SPIELER1:
-    case EL_SPIELER2:
-    case EL_SPIELER3:
-    case EL_SPIELER4:
+    case EL_PLAYER_1:
+    case EL_PLAYER_2:
+    case EL_PLAYER_3:
+    case EL_PLAYER_4:
       if (init_game)
       {
-       struct PlayerInfo *player = &stored_player[Feld[x][y] - EL_SPIELER1];
+       struct PlayerInfo *player = &stored_player[Feld[x][y] - EL_PLAYER_1];
        int jx = player->jx, jy = player->jy;
 
        player->present = TRUE;
@@ -323,51 +547,51 @@ static void InitField(int x, int y, boolean init_game)
          }
        }
 
-       Feld[x][y] = EL_LEERRAUM;
+       Feld[x][y] = EL_EMPTY;
        player->jx = player->last_jx = x;
        player->jy = player->last_jy = y;
       }
       break;
 
-    case EL_BADEWANNE:
-      if (x < lev_fieldx-1 && Feld[x+1][y] == EL_SALZSAEURE)
-       Feld[x][y] = EL_BADEWANNE1;
-      else if (x > 0 && Feld[x-1][y] == EL_SALZSAEURE)
-       Feld[x][y] = EL_BADEWANNE2;
-      else if (y > 0 && Feld[x][y-1] == EL_BADEWANNE1)
-       Feld[x][y] = EL_BADEWANNE3;
-      else if (y > 0 && Feld[x][y-1] == EL_SALZSAEURE)
-       Feld[x][y] = EL_BADEWANNE4;
-      else if (y > 0 && Feld[x][y-1] == EL_BADEWANNE2)
-       Feld[x][y] = EL_BADEWANNE5;
+    case EL_STONEBLOCK:
+      if (x < lev_fieldx-1 && Feld[x+1][y] == EL_ACID)
+       Feld[x][y] = EL_ACID_POOL_TOPLEFT;
+      else if (x > 0 && Feld[x-1][y] == EL_ACID)
+       Feld[x][y] = EL_ACID_POOL_TOPRIGHT;
+      else if (y > 0 && Feld[x][y-1] == EL_ACID_POOL_TOPLEFT)
+       Feld[x][y] = EL_ACID_POOL_BOTTOMLEFT;
+      else if (y > 0 && Feld[x][y-1] == EL_ACID)
+       Feld[x][y] = EL_ACID_POOL_BOTTOM;
+      else if (y > 0 && Feld[x][y-1] == EL_ACID_POOL_TOPRIGHT)
+       Feld[x][y] = EL_ACID_POOL_BOTTOMRIGHT;
       break;
 
-    case EL_KAEFER_RIGHT:
-    case EL_KAEFER_UP:
-    case EL_KAEFER_LEFT:
-    case EL_KAEFER_DOWN:
-    case EL_KAEFER:
-    case EL_FLIEGER_RIGHT:
-    case EL_FLIEGER_UP:
-    case EL_FLIEGER_LEFT:
-    case EL_FLIEGER_DOWN:
-    case EL_FLIEGER:
-    case EL_BUTTERFLY_RIGHT:
-    case EL_BUTTERFLY_UP:
-    case EL_BUTTERFLY_LEFT:
-    case EL_BUTTERFLY_DOWN:
-    case EL_BUTTERFLY:
-    case EL_FIREFLY_RIGHT:
-    case EL_FIREFLY_UP:
-    case EL_FIREFLY_LEFT:
-    case EL_FIREFLY_DOWN:
-    case EL_FIREFLY:
+    case EL_BUG_RIGHT:
+    case EL_BUG_UP:
+    case EL_BUG_LEFT:
+    case EL_BUG_DOWN:
+    case EL_BUG:
+    case EL_SPACESHIP_RIGHT:
+    case EL_SPACESHIP_UP:
+    case EL_SPACESHIP_LEFT:
+    case EL_SPACESHIP_DOWN:
+    case EL_SPACESHIP:
+    case EL_BD_BUTTERFLY_RIGHT:
+    case EL_BD_BUTTERFLY_UP:
+    case EL_BD_BUTTERFLY_LEFT:
+    case EL_BD_BUTTERFLY_DOWN:
+    case EL_BD_BUTTERFLY:
+    case EL_BD_FIREFLY_RIGHT:
+    case EL_BD_FIREFLY_UP:
+    case EL_BD_FIREFLY_LEFT:
+    case EL_BD_FIREFLY_DOWN:
+    case EL_BD_FIREFLY:
     case EL_PACMAN_RIGHT:
     case EL_PACMAN_UP:
     case EL_PACMAN_LEFT:
     case EL_PACMAN_DOWN:
-    case EL_MAMPFER:
-    case EL_MAMPFER2:
+    case EL_YAMYAM:
+    case EL_DARK_YAMYAM:
     case EL_ROBOT:
     case EL_PACMAN:
     case EL_SP_SNIKSNAK:
@@ -380,16 +604,16 @@ static void InitField(int x, int y, boolean init_game)
       InitMovDir(x, y);
       break;
 
-    case EL_AMOEBE_VOLL:
-    case EL_AMOEBE_BD:
+    case EL_AMOEBA_FULL:
+    case EL_BD_AMOEBA:
       InitAmoebaNr(x, y);
       break;
 
-    case EL_TROPFEN:
+    case EL_AMOEBA_DROP:
       if (y == lev_fieldy - 1)
       {
-       Feld[x][y] = EL_AMOEBING;
-       Store[x][y] = EL_AMOEBE_NASS;
+       Feld[x][y] = EL_AMOEBA_GROWING;
+       Store[x][y] = EL_AMOEBA_WET;
       }
       break;
 
@@ -397,25 +621,25 @@ static void InitField(int x, int y, boolean init_game)
       MovDelay[x][y] = 96;
       break;
 
-    case EL_BIRNE_AUS:
+    case EL_LAMP:
       local_player->lights_still_needed++;
       break;
 
-    case EL_SOKOBAN_FELD_LEER:
+    case EL_SOKOBAN_FIELD_EMPTY:
       local_player->sokobanfields_still_needed++;
       break;
 
-    case EL_PINGUIN:
+    case EL_PENGUIN:
       local_player->friends_still_needed++;
       break;
 
-    case EL_SCHWEIN:
-    case EL_DRACHE:
+    case EL_PIG:
+    case EL_DRAGON:
       MovDir[x][y] = 1 << RND(4);
       break;
 
     case EL_SP_EMPTY:
-      Feld[x][y] = EL_LEERRAUM;
+      Feld[x][y] = EL_EMPTY;
       break;
 
     case EL_EM_KEY_1_FILE:
@@ -431,23 +655,23 @@ static void InitField(int x, int y, boolean init_game)
       Feld[x][y] = EL_EM_KEY_4;
       break;
 
-    case EL_BELT1_SWITCH_LEFT:
-    case EL_BELT1_SWITCH_MIDDLE:
-    case EL_BELT1_SWITCH_RIGHT:
-    case EL_BELT2_SWITCH_LEFT:
-    case EL_BELT2_SWITCH_MIDDLE:
-    case EL_BELT2_SWITCH_RIGHT:
-    case EL_BELT3_SWITCH_LEFT:
-    case EL_BELT3_SWITCH_MIDDLE:
-    case EL_BELT3_SWITCH_RIGHT:
-    case EL_BELT4_SWITCH_LEFT:
-    case EL_BELT4_SWITCH_MIDDLE:
-    case EL_BELT4_SWITCH_RIGHT:
+    case EL_CONVEYOR_BELT_1_SWITCH_LEFT:
+    case EL_CONVEYOR_BELT_1_SWITCH_MIDDLE:
+    case EL_CONVEYOR_BELT_1_SWITCH_RIGHT:
+    case EL_CONVEYOR_BELT_2_SWITCH_LEFT:
+    case EL_CONVEYOR_BELT_2_SWITCH_MIDDLE:
+    case EL_CONVEYOR_BELT_2_SWITCH_RIGHT:
+    case EL_CONVEYOR_BELT_3_SWITCH_LEFT:
+    case EL_CONVEYOR_BELT_3_SWITCH_MIDDLE:
+    case EL_CONVEYOR_BELT_3_SWITCH_RIGHT:
+    case EL_CONVEYOR_BELT_4_SWITCH_LEFT:
+    case EL_CONVEYOR_BELT_4_SWITCH_MIDDLE:
+    case EL_CONVEYOR_BELT_4_SWITCH_RIGHT:
       if (init_game)
       {
-       int belt_nr = getBeltNrFromSwitchElement(Feld[x][y]);
-       int belt_dir = getBeltDirFromSwitchElement(Feld[x][y]);
-       int belt_dir_nr = getBeltDirNrFromSwitchElement(Feld[x][y]);
+       int belt_nr = getBeltNrFromBeltSwitchElement(Feld[x][y]);
+       int belt_dir = getBeltDirFromBeltSwitchElement(Feld[x][y]);
+       int belt_dir_nr = getBeltDirNrFromBeltSwitchElement(Feld[x][y]);
 
        if (game.belt_dir_nr[belt_nr] == 3)     /* initial value */
        {
@@ -461,17 +685,19 @@ static void InitField(int x, int y, boolean init_game)
       }
       break;
 
-    case EL_SWITCHGATE_SWITCH_2:       /* always start with same switch pos */
+    case EL_SWITCHGATE_SWITCH_DOWN:    /* always start with same switch pos */
       if (init_game)
-       Feld[x][y] = EL_SWITCHGATE_SWITCH_1;
+       Feld[x][y] = EL_SWITCHGATE_SWITCH_UP;
       break;
 
-    case EL_LIGHT_SWITCH_ON:
+    case EL_LIGHT_SWITCH_ACTIVE:
       if (init_game)
        game.light_time_left = level.time_light * FRAMES_PER_SECOND;
       break;
 
     default:
+      if (IS_CUSTOM_ELEMENT(element) && CAN_MOVE(element))
+       InitMovDir(x, y);
       break;
   }
 }
@@ -484,109 +710,16 @@ void DrawGameDoorValues()
     for (j=0; j<4; j++)
       if (stored_player[i].key[j])
        DrawMiniGraphicExt(drawto, DX_KEYS + j * MINI_TILEX, DY_KEYS,
-                          GFX_SCHLUESSEL1 + j);
+                          el2edimg(EL_KEY_1 + j));
 
   DrawText(DX + XX_EMERALDS, DY + YY_EMERALDS,
-          int2str(local_player->gems_still_needed, 3), FS_SMALL, FC_YELLOW);
+          int2str(local_player->gems_still_needed, 3), FONT_TEXT_2);
   DrawText(DX + XX_DYNAMITE, DY + YY_DYNAMITE,
-          int2str(local_player->dynamite, 3), FS_SMALL, FC_YELLOW);
+          int2str(local_player->dynamite, 3), FONT_TEXT_2);
   DrawText(DX + XX_SCORE, DY + YY_SCORE,
-          int2str(local_player->score, 5), FS_SMALL, FC_YELLOW);
+          int2str(local_player->score, 5), FONT_TEXT_2);
   DrawText(DX + XX_TIME, DY + YY_TIME,
-          int2str(TimeLeft, 3), FS_SMALL, FC_YELLOW);
-}
-
-
-/*
-  =============================================================================
-  InitGameSound()
-  -----------------------------------------------------------------------------
-  initialize sound effect lookup table for element actions
-  =============================================================================
-*/
-
-void InitGameSound()
-{
-  int sound_effect_properties[NUM_SOUND_EFFECTS];
-  int i, j;
-
-#if 0
-  debug_print_timestamp(0, NULL);
-#endif
-
-  for (i=0; i<NUM_SND_ACTIONS; i++)
-    for (j=0; j<NUM_LEVEL_ELEMENTS; j++)
-      element_action_sound[j][i] = -1;
-
-  for (i=0; i<NUM_SOUND_EFFECTS; i++)
-  {
-    int len_effect_text = strlen(sound_effects[i].text);
-
-    sound_effect_properties[i] = SND_ACTION_UNKNOWN;
-    is_loop_sound[i] = FALSE;
-
-    /* determine all loop sounds and identify certain sound classes */
-
-    j = 0;
-    while (sound_action_properties[j].text)
-    {
-      int len_action_text = strlen(sound_action_properties[j].text);
-
-      if (len_action_text < len_effect_text &&
-         strcmp(&sound_effects[i].text[len_effect_text - len_action_text],
-                sound_action_properties[j].text) == 0)
-      {
-       sound_effect_properties[i] = sound_action_properties[j].value;
-
-       if (sound_action_properties[j].is_loop)
-         is_loop_sound[i] = TRUE;
-      }
-
-      j++;
-    }
-
-    /* associate elements and some selected sound actions */
-
-    for (j=0; j<NUM_LEVEL_ELEMENTS; j++)
-    {
-      if (element_info[j].sound_class_name)
-      {
-       int len_class_text = strlen(element_info[j].sound_class_name);
-
-       if (len_class_text + 1 < len_effect_text &&
-           strncmp(sound_effects[i].text,
-                   element_info[j].sound_class_name, len_class_text) == 0 &&
-           sound_effects[i].text[len_class_text] == '.')
-       {
-         int sound_action_value = sound_effect_properties[i];
-
-         element_action_sound[j][sound_action_value] = i;
-       }
-      }
-    }
-  }
-
-#if 0
-  debug_print_timestamp(0, "InitGameEngine");
-#endif
-
-#if 0
-  /* TEST ONLY */
-  {
-    int element = EL_ERDREICH;
-    int sound_action = SND_ACTION_DIGGING;
-    int j = 0;
-
-    while (sound_action_properties[j].text)
-    {
-      if (sound_action_properties[j].value == sound_action)
-       printf("element %d, sound action '%s'  == %d\n",
-              element, sound_action_properties[j].text,
-              element_action_sound[element][sound_action]);
-      j++;
-    }
-  }
-#endif
+          int2str(TimeLeft, 3), FONT_TEXT_2);
 }
 
 
@@ -602,9 +735,13 @@ static void InitGameEngine()
 {
   int i;
 
+  /* set game engine from tape file when re-playing, else from level file */
   game.engine_version = (tape.playing ? tape.engine_version :
                         level.game_version);
 
+  /* dynamically adjust element properties according to game engine version */
+  InitElementPropertiesEngine(game.engine_version);
+
 #if 0
     printf("level %d: level version == %06d\n", level_nr, level.game_version);
     printf("          tape version == %06d [%s] [file: %06d]\n",
@@ -613,6 +750,8 @@ static void InitGameEngine()
     printf("       => game.engine_version == %06d\n", game.engine_version);
 #endif
 
+  /* ---------- initialize player's initial move delay --------------------- */
+
   /* dynamically adjust player properties according to game engine version */
   game.initial_move_delay =
     (game.engine_version <= VERSION_IDENT(2,0,1) ? INITIAL_MOVE_DELAY_ON :
@@ -622,35 +761,141 @@ static void InitGameEngine()
   game.initial_move_delay_value =
     (level.double_speed ? MOVE_DELAY_HIGH_SPEED : MOVE_DELAY_NORMAL_SPEED);
 
-  /* dynamically adjust element properties according to game engine version */
+  /* ---------- initialize changing elements ------------------------------- */
+
+  /* initialize changing elements information */
+  for (i=0; i<MAX_NUM_ELEMENTS; i++)
   {
-    static int ep_em_slippery_wall[] =
+#if 1
+    element_info[i].change.pre_change_function = NULL;
+    element_info[i].change.change_function = NULL;
+    element_info[i].change.post_change_function = NULL;
+
+    if (!IS_CUSTOM_ELEMENT(i))
     {
-      EL_BETON,
-      EL_MAUERWERK,
-      EL_MAUER_LEBT,
-      EL_MAUER_X,
-      EL_MAUER_Y,
-      EL_MAUER_XY
-    };
-    static int ep_em_slippery_wall_num = SIZEOF_ARRAY_INT(ep_em_slippery_wall);
+      element_info[i].change.target_element = EL_EMPTY_SPACE;
+      element_info[i].change.delay_fixed = 0;
+      element_info[i].change.delay_random = 0;
+      element_info[i].change.delay_frames = 1;
+    }
 
-    for (i=0; i<ep_em_slippery_wall_num; i++)
+    changing_element[i] = FALSE;
+#else
+    changing_element[i].base_element = EL_UNDEFINED;
+    changing_element[i].next_element = EL_UNDEFINED;
+    changing_element[i].change_delay = -1;
+    changing_element[i].pre_change_function = NULL;
+    changing_element[i].change_function = NULL;
+    changing_element[i].post_change_function = NULL;
+#endif
+  }
+
+  /* add changing elements from pre-defined list */
+  for (i=0; changing_element_list[i].element != EL_UNDEFINED; i++)
+  {
+    int element = changing_element_list[i].element;
+    struct ChangingElementInfo *ce = &changing_element_list[i];
+    struct ElementChangeInfo *change = &element_info[element].change;
+
+#if 1
+    change->target_element       = ce->target_element;
+    change->delay_fixed          = ce->change_delay;
+    change->pre_change_function  = ce->pre_change_function;
+    change->change_function      = ce->change_function;
+    change->post_change_function = ce->post_change_function;
+
+    changing_element[element] = TRUE;
+#else
+    changing_element[element].base_element         = ce->base_element;
+    changing_element[element].next_element         = ce->next_element;
+    changing_element[element].change_delay         = ce->change_delay;
+    changing_element[element].pre_change_function  = ce->pre_change_function;
+    changing_element[element].change_function      = ce->change_function;
+    changing_element[element].post_change_function = ce->post_change_function;
+#endif
+  }
+
+  /* add changing elements from custom element configuration */
+  for (i=0; i < NUM_CUSTOM_ELEMENTS; i++)
+  {
+    int element = EL_CUSTOM_START + i;
+#if 0
+    struct ElementChangeInfo *change = &element_info[element].change;
+#endif
+
+    /* only add custom elements that change after fixed/random frame delay */
+    if (!CAN_CHANGE(element) || !HAS_CHANGE_EVENT(element, CE_DELAY))
+      continue;
+
+#if 1
+    changing_element[element] = TRUE;
+#else
+    changing_element[element].base_element = element;
+    changing_element[element].next_element = change->target_element;
+    changing_element[element].change_delay = (change->delay_fixed *
+                                             change->delay_frames);
+#endif
+  }
+
+  /* ---------- initialize trigger events ---------------------------------- */
+
+  /* initialize trigger events information */
+  for (i=0; i<MAX_NUM_ELEMENTS; i++)
+    trigger_events[i] = EP_BITMASK_DEFAULT;
+
+  /* add trigger events from element change event properties */
+  for (i=0; i<MAX_NUM_ELEMENTS; i++)
+    if (HAS_CHANGE_EVENT(i, CE_BY_OTHER))
+      trigger_events[element_info[i].change.trigger_element] |=
+       element_info[i].change.events;
+
+  /* ---------- initialize push delay -------------------------------------- */
+
+  /* initialize push delay values to default */
+  for (i=0; i<MAX_NUM_ELEMENTS; i++)
+  {
+    if (!IS_CUSTOM_ELEMENT(i))
     {
-      if (level.em_slippery_gems)      /* special EM style gems behaviour */
-       Elementeigenschaften2[ep_em_slippery_wall[i]] |=
-         EP_BIT_EM_SLIPPERY_WALL;
-      else
-       Elementeigenschaften2[ep_em_slippery_wall[i]] &=
-         ~EP_BIT_EM_SLIPPERY_WALL;
+      element_info[i].push_delay_fixed = 2;
+      element_info[i].push_delay_random = 8;
     }
+  }
 
-    /* "EL_MAUERND" was not slippery for EM gems in version 2.0.1 */
-    if (level.em_slippery_gems && game.engine_version > VERSION_IDENT(2,0,1))
-      Elementeigenschaften2[EL_MAUERND] |=  EP_BIT_EM_SLIPPERY_WALL;
-    else
-      Elementeigenschaften2[EL_MAUERND] &= ~EP_BIT_EM_SLIPPERY_WALL;
+  /* set push delay value for certain elements from pre-defined list */
+  for (i=0; push_delay_list[i].element != EL_UNDEFINED; i++)
+  {
+    int e = push_delay_list[i].element;
+
+    element_info[e].push_delay_fixed  = push_delay_list[i].push_delay_fixed;
+    element_info[e].push_delay_random = push_delay_list[i].push_delay_random;
+  }
+
+  /* ---------- initialize move stepsize ----------------------------------- */
+
+  /* initialize move stepsize values to default */
+  for (i=0; i<MAX_NUM_ELEMENTS; i++)
+    if (!IS_CUSTOM_ELEMENT(i))
+      element_info[i].move_stepsize = MOVE_STEPSIZE_NORMAL;
+
+  /* set move stepsize value for certain elements from pre-defined list */
+  for (i=0; move_stepsize_list[i].element != EL_UNDEFINED; i++)
+  {
+    int e = move_stepsize_list[i].element;
+
+    element_info[e].move_stepsize = move_stepsize_list[i].move_stepsize;
   }
+
+  /* ---------- initialize gem count --------------------------------------- */
+
+  /* initialize gem count values for each element */
+  for (i=0; i<MAX_NUM_ELEMENTS; i++)
+    if (!IS_CUSTOM_ELEMENT(i))
+      element_info[i].gem_count = 0;
+
+  /* add gem count values for all elements from pre-defined list */
+  for (i=0; gem_count_list[i].element != EL_UNDEFINED; i++)
+    element_info[gem_count_list[i].element].gem_count =
+      gem_count_list[i].gem_count;
 }
 
 
@@ -671,12 +916,14 @@ void InitGame()
 
   InitGameEngine();
 
+#if 0
 #if DEBUG
 #if USE_NEW_AMOEBA_CODE
   printf("Using new amoeba code.\n");
 #else
   printf("Using old amoeba code.\n");
 #endif
+#endif
 #endif
 
   /* don't play tapes over network */
@@ -687,7 +934,7 @@ void InitGame()
     struct PlayerInfo *player = &stored_player[i];
 
     player->index_nr = i;
-    player->element_nr = EL_SPIELER1 + i;
+    player->element_nr = EL_PLAYER_1 + i;
 
     player->present = FALSE;
     player->active = FALSE;
@@ -716,14 +963,22 @@ void InitGame()
     player->Pushing = FALSE;
     player->Switching = FALSE;
     player->GfxPos = 0;
+    player->GfxDir = MV_NO_MOVING;
+    player->GfxAction = ACTION_DEFAULT;
     player->Frame = 0;
+    player->StepFrame = 0;
 
-    player->actual_frame_counter = 0;
+    player->use_murphy_graphic = FALSE;
+    player->use_disk_red_graphic = FALSE;
 
-    player->frame_reset_delay = 0;
+    player->actual_frame_counter = 0;
 
     player->last_move_dir = MV_NO_MOVING;
+
     player->is_moving = FALSE;
+    player->is_waiting = FALSE;
+    player->is_digging = FALSE;
+    player->is_collecting = FALSE;
 
     player->move_delay       = game.initial_move_delay;
     player->move_delay_value = game.initial_move_delay_value;
@@ -736,8 +991,8 @@ void InitGame()
     player->last_jx = player->last_jy = 0;
     player->jx = player->jy = 0;
 
-    player->shield_passive_time_left = 0;
-    player->shield_active_time_left = 0;
+    player->shield_normal_time_left = 0;
+    player->shield_deadly_time_left = 0;
 
     DigField(player, 0, 0, 0, 0, DF_NO_PUSH);
     SnapField(player, 0, 0);
@@ -769,7 +1024,7 @@ void InitGame()
 
   AllPlayersGone = FALSE;
 
-  game.yam_content_nr = 0;
+  game.yamyam_content_nr = 0;
   game.magic_wall_active = FALSE;
   game.magic_wall_time_left = 0;
   game.light_time_left = 0;
@@ -791,14 +1046,22 @@ void InitGame()
   {
     for (y=0; y<lev_fieldy; y++)
     {
-      Feld[x][y] = Ur[x][y];
+      Feld[x][y] = level.field[x][y];
       MovPos[x][y] = MovDir[x][y] = MovDelay[x][y] = 0;
-      Store[x][y] = Store2[x][y] = StorePlayer[x][y] = 0;
-      Frame[x][y] = 0;
+      ChangeDelay[x][y] = 0;
+      Store[x][y] = Store2[x][y] = StorePlayer[x][y] = Back[x][y] = 0;
       AmoebaNr[x][y] = 0;
       JustStopped[x][y] = 0;
       Stop[x][y] = FALSE;
+      Pushed[x][y] = FALSE;
+      Changing[x][y] = FALSE;
+      ExplodePhase[x][y] = 0;
       ExplodeField[x][y] = EX_NO_EXPLOSION;
+
+      GfxFrame[x][y] = 0;
+      GfxAction[x][y] = ACTION_DEFAULT;
+      GfxRandom[x][y] = INIT_GFX_RANDOM();
+      GfxElement[x][y] = EL_UNDEFINED;
     }
   }
 
@@ -817,6 +1080,8 @@ void InitGame()
     }
   }
 
+  InitBeltMovement();
+
   game.emulation = (emulate_bd ? EMU_BOULDERDASH :
                    emulate_sb ? EMU_SOKOBAN :
                    emulate_sp ? EMU_SUPAPLEX : EMU_NONE);
@@ -868,7 +1133,7 @@ void InitGame()
 
        player->active = FALSE;
        StorePlayer[jx][jy] = 0;
-       Feld[jx][jy] = EL_LEERRAUM;
+       Feld[jx][jy] = EL_EMPTY;
       }
     }
   }
@@ -889,7 +1154,7 @@ void InitGame()
 
            player->active = FALSE;
            StorePlayer[jx][jy] = 0;
-           Feld[jx][jy] = EL_LEERRAUM;
+           Feld[jx][jy] = EL_EMPTY;
          }
        }
       }
@@ -920,7 +1185,7 @@ void InitGame()
     }
   }
 
-  if (BorderElement == EL_LEERRAUM)
+  if (BorderElement == EL_EMPTY)
   {
     SBX_Left = 0;
     SBX_Right = lev_fieldx - SCR_FIELDX;
@@ -956,7 +1221,6 @@ void InitGame()
 
   DrawLevel();
   DrawAllPlayers();
-  FadeToFront();
 
   /* after drawing the level, correct some elements */
   if (game.timegate_time_left == 0)
@@ -966,21 +1230,22 @@ void InitGame()
     BlitBitmap(fieldbuffer, backbuffer, FX, FY, SXSIZE, SYSIZE, SX, SY);
 
   redraw_mask |= REDRAW_FROM_BACKBUFFER;
+  FadeToFront();
 
   /* copy default game door content to main double buffer */
-  BlitBitmap(pix[PIX_DOOR], drawto,
+  BlitBitmap(graphic_info[IMG_GLOBAL_DOOR].bitmap, drawto,
             DOOR_GFX_PAGEX5, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE, DX, DY);
 
   if (level_nr < 100)
-    DrawText(DX + XX_LEVEL, DY + YY_LEVEL,
-            int2str(level_nr, 2), FS_SMALL, FC_YELLOW);
+    DrawText(DX + XX_LEVEL, DY + YY_LEVEL, int2str(level_nr, 2), FONT_TEXT_2);
   else
   {
     DrawTextExt(drawto, DX + XX_EMERALDS, DY + YY_EMERALDS,
-               int2str(level_nr, 3), FS_SMALL, FC_SPECIAL3);
+               int2str(level_nr, 3), FONT_LEVEL_NUMBER, BLIT_OPAQUE);
     BlitBitmap(drawto, drawto,
               DX + XX_EMERALDS, DY + YY_EMERALDS + 1,
-              FONT5_XSIZE * 3, FONT5_YSIZE - 1,
+              getFontWidth(FONT_LEVEL_NUMBER) * 3,
+              getFontHeight(FONT_LEVEL_NUMBER) - 1,
               DX + XX_LEVEL - 1, DY + YY_LEVEL + 1);
   }
 
@@ -995,16 +1260,16 @@ void InitGame()
   MapTapeButtons();
 
   /* copy actual game door content to door double buffer for OpenDoor() */
-  BlitBitmap(drawto, pix[PIX_DB_DOOR],
+  BlitBitmap(drawto, bitmap_db_door,
             DX, DY, DXSIZE, DYSIZE, DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
 
   OpenDoor(DOOR_OPEN_ALL);
 
-  PlaySoundStereo(SND_GAME_STARTING, SOUND_MAX_RIGHT);
+  PlaySoundStereo(SND_GAME_STARTING, SOUND_MIDDLE);
   if (setup.sound_music)
     PlayMusic(level_nr);
 
-  KeyboardAutoRepeatOff();
+  KeyboardAutoRepeatOffUnlessAutoplay();
 
   if (options.debug)
   {
@@ -1033,36 +1298,36 @@ void InitMovDir(int x, int y)
 
   switch(element)
   {
-    case EL_KAEFER_RIGHT:
-    case EL_KAEFER_UP:
-    case EL_KAEFER_LEFT:
-    case EL_KAEFER_DOWN:
-      Feld[x][y] = EL_KAEFER;
-      MovDir[x][y] = direction[0][element - EL_KAEFER_RIGHT];
+    case EL_BUG_RIGHT:
+    case EL_BUG_UP:
+    case EL_BUG_LEFT:
+    case EL_BUG_DOWN:
+      Feld[x][y] = EL_BUG;
+      MovDir[x][y] = direction[0][element - EL_BUG_RIGHT];
       break;
 
-    case EL_FLIEGER_RIGHT:
-    case EL_FLIEGER_UP:
-    case EL_FLIEGER_LEFT:
-    case EL_FLIEGER_DOWN:
-      Feld[x][y] = EL_FLIEGER;
-      MovDir[x][y] = direction[0][element - EL_FLIEGER_RIGHT];
+    case EL_SPACESHIP_RIGHT:
+    case EL_SPACESHIP_UP:
+    case EL_SPACESHIP_LEFT:
+    case EL_SPACESHIP_DOWN:
+      Feld[x][y] = EL_SPACESHIP;
+      MovDir[x][y] = direction[0][element - EL_SPACESHIP_RIGHT];
       break;
 
-    case EL_BUTTERFLY_RIGHT:
-    case EL_BUTTERFLY_UP:
-    case EL_BUTTERFLY_LEFT:
-    case EL_BUTTERFLY_DOWN:
-      Feld[x][y] = EL_BUTTERFLY;
-      MovDir[x][y] = direction[0][element - EL_BUTTERFLY_RIGHT];
+    case EL_BD_BUTTERFLY_RIGHT:
+    case EL_BD_BUTTERFLY_UP:
+    case EL_BD_BUTTERFLY_LEFT:
+    case EL_BD_BUTTERFLY_DOWN:
+      Feld[x][y] = EL_BD_BUTTERFLY;
+      MovDir[x][y] = direction[0][element - EL_BD_BUTTERFLY_RIGHT];
       break;
 
-    case EL_FIREFLY_RIGHT:
-    case EL_FIREFLY_UP:
-    case EL_FIREFLY_LEFT:
-    case EL_FIREFLY_DOWN:
-      Feld[x][y] = EL_FIREFLY;
-      MovDir[x][y] = direction[0][element - EL_FIREFLY_RIGHT];
+    case EL_BD_FIREFLY_RIGHT:
+    case EL_BD_FIREFLY_UP:
+    case EL_BD_FIREFLY_LEFT:
+    case EL_BD_FIREFLY_DOWN:
+      Feld[x][y] = EL_BD_FIREFLY;
+      MovDir[x][y] = direction[0][element - EL_BD_FIREFLY_RIGHT];
       break;
 
     case EL_PACMAN_RIGHT:
@@ -1090,30 +1355,68 @@ void InitMovDir(int x, int y)
       break;
 
     default:
-      MovDir[x][y] = 1 << RND(4);
-      if (element != EL_KAEFER &&
-         element != EL_FLIEGER &&
-         element != EL_BUTTERFLY &&
-         element != EL_FIREFLY)
-       break;
-
-      for (i=0; i<4; i++)
+      if (IS_CUSTOM_ELEMENT(element))
       {
-       int x1 = x + xy[i][0];
-       int y1 = y + xy[i][1];
-
-       if (!IN_LEV_FIELD(x1, y1) || !IS_FREE(x1, y1))
+       if (element_info[element].move_direction_initial != MV_NO_MOVING)
+         MovDir[x][y] = element_info[element].move_direction_initial;
+       else if (element_info[element].move_pattern == MV_ALL_DIRECTIONS ||
+                element_info[element].move_pattern == MV_TURNING_LEFT ||
+                element_info[element].move_pattern == MV_TURNING_RIGHT)
+         MovDir[x][y] = 1 << RND(4);
+       else if (element_info[element].move_pattern == MV_HORIZONTAL)
+         MovDir[x][y] = (RND(2) ? MV_LEFT : MV_RIGHT);
+       else if (element_info[element].move_pattern == MV_VERTICAL)
+         MovDir[x][y] = (RND(2) ? MV_UP : MV_DOWN);
+       else if (element_info[element].move_pattern & MV_ANY_DIRECTION)
+         MovDir[x][y] = element_info[element].move_pattern;
+       else if (element_info[element].move_pattern == MV_ALONG_LEFT_SIDE ||
+                element_info[element].move_pattern == MV_ALONG_RIGHT_SIDE)
        {
-         if (element == EL_KAEFER || element == EL_BUTTERFLY)
+         for (i=0; i<4; i++)
          {
-           MovDir[x][y] = direction[0][i];
-           break;
+           int x1 = x + xy[i][0];
+           int y1 = y + xy[i][1];
+
+           if (!IN_LEV_FIELD(x1, y1) || !IS_FREE(x1, y1))
+           {
+             if (element_info[element].move_pattern == MV_ALONG_RIGHT_SIDE)
+               MovDir[x][y] = direction[0][i];
+             else
+               MovDir[x][y] = direction[1][i];
+
+             break;
+           }
          }
-         else if (element == EL_FLIEGER || element == EL_FIREFLY ||
-                  element == EL_SP_SNIKSNAK || element == EL_SP_ELECTRON)
+       }                
+      }
+      else
+      {
+       MovDir[x][y] = 1 << RND(4);
+
+       if (element != EL_BUG &&
+           element != EL_SPACESHIP &&
+           element != EL_BD_BUTTERFLY &&
+           element != EL_BD_FIREFLY)
+         break;
+
+       for (i=0; i<4; i++)
+       {
+         int x1 = x + xy[i][0];
+         int y1 = y + xy[i][1];
+
+         if (!IN_LEV_FIELD(x1, y1) || !IS_FREE(x1, y1))
          {
-           MovDir[x][y] = direction[1][i];
-           break;
+           if (element == EL_BUG || element == EL_BD_BUTTERFLY)
+           {
+             MovDir[x][y] = direction[0][i];
+             break;
+           }
+           else if (element == EL_SPACESHIP || element == EL_BD_FIREFLY ||
+                    element == EL_SP_SNIKSNAK || element == EL_SP_ELECTRON)
+           {
+             MovDir[x][y] = direction[1][i];
+             break;
+           }
          }
        }
       }
@@ -1151,27 +1454,30 @@ void GameWon()
   if (local_player->MovPos)
     return;
 
+  if (tape.playing && tape.auto_play)
+    tape.auto_play_level_solved = TRUE;
+
   local_player->LevelSolved = FALSE;
 
-  PlaySoundStereo(SND_GAME_WINNING, SOUND_MAX_RIGHT);
+  PlaySoundStereo(SND_GAME_WINNING, SOUND_MIDDLE);
 
   if (TimeLeft)
   {
     if (!tape.playing && setup.sound_loops)
-      PlaySoundExt(SND_GAME_LEVELTIME_BONUS, SOUND_MAX_VOLUME, SOUND_MAX_RIGHT,
+      PlaySoundExt(SND_GAME_LEVELTIME_BONUS, SOUND_MAX_VOLUME, SOUND_MIDDLE,
                   SND_CTRL_PLAY_LOOP);
 
     while (TimeLeft > 0)
     {
       if (!tape.playing && !setup.sound_loops)
-       PlaySoundStereo(SND_GAME_LEVELTIME_BONUS, SOUND_MAX_RIGHT);
+       PlaySoundStereo(SND_GAME_LEVELTIME_BONUS, SOUND_MIDDLE);
       if (TimeLeft > 0 && !(TimeLeft % 10))
-       RaiseScore(level.score[SC_ZEITBONUS]);
+       RaiseScore(level.score[SC_TIME_BONUS]);
       if (TimeLeft > 100 && !(TimeLeft % 10))
        TimeLeft -= 10;
       else
        TimeLeft--;
-      DrawText(DX_TIME, DY_TIME, int2str(TimeLeft, 3), FS_SMALL, FC_YELLOW);
+      DrawText(DX_TIME, DY_TIME, int2str(TimeLeft, 3), FONT_TEXT_2);
       BackToFront();
 
       if (!tape.playing)
@@ -1184,20 +1490,20 @@ void GameWon()
   else if (level.time == 0)            /* level without time limit */
   {
     if (!tape.playing && setup.sound_loops)
-      PlaySoundExt(SND_GAME_LEVELTIME_BONUS, SOUND_MAX_VOLUME, SOUND_MAX_RIGHT,
+      PlaySoundExt(SND_GAME_LEVELTIME_BONUS, SOUND_MAX_VOLUME, SOUND_MIDDLE,
                   SND_CTRL_PLAY_LOOP);
 
     while (TimePlayed < 999)
     {
       if (!tape.playing && !setup.sound_loops)
-       PlaySoundStereo(SND_GAME_LEVELTIME_BONUS, SOUND_MAX_RIGHT);
+       PlaySoundStereo(SND_GAME_LEVELTIME_BONUS, SOUND_MIDDLE);
       if (TimePlayed < 999 && !(TimePlayed % 10))
-       RaiseScore(level.score[SC_ZEITBONUS]);
+       RaiseScore(level.score[SC_TIME_BONUS]);
       if (TimePlayed < 900 && !(TimePlayed % 10))
        TimePlayed += 10;
       else
        TimePlayed++;
-      DrawText(DX_TIME, DY_TIME, int2str(TimePlayed, 3), FS_SMALL, FC_YELLOW);
+      DrawText(DX_TIME, DY_TIME, int2str(TimePlayed, 3), FONT_TEXT_2);
       BackToFront();
 
       if (!tape.playing)
@@ -1208,10 +1514,6 @@ void GameWon()
       StopSound(SND_GAME_LEVELTIME_BONUS);
   }
 
-#if 0
-  FadeSounds();
-#endif
-
   /* Hero disappears */
   DrawLevelField(ExitX, ExitY);
   BackToFront();
@@ -1240,7 +1542,7 @@ void GameWon()
 
   if ((hi_pos = NewHiScore()) >= 0) 
   {
-    game_status = HALLOFFAME;
+    game_status = GAME_MODE_SCORES;
     DrawHallOfFame(hi_pos);
     if (raise_level)
     {
@@ -1250,7 +1552,7 @@ void GameWon()
   }
   else
   {
-    game_status = MAINMENU;
+    game_status = GAME_MODE_MAIN;
     if (raise_level)
     {
       level_nr++;
@@ -1322,15 +1624,57 @@ int NewHiScore()
   return position;
 }
 
+void InitPlayerGfxAnimation(struct PlayerInfo *player, int action, int dir)
+{
+  if (player->GfxAction != action || player->GfxDir != dir)
+  {
+#if 0
+    printf("Player frame reset! (%d => %d, %d => %d)\n",
+          player->GfxAction, action, player->GfxDir, dir);
+#endif
+
+    player->GfxAction = action;
+    player->GfxDir = dir;
+    player->Frame = 0;
+    player->StepFrame = 0;
+  }
+}
+
+static void ResetRandomAnimationValue(int x, int y)
+{
+  GfxRandom[x][y] = INIT_GFX_RANDOM();
+}
+
+static void ResetGfxAnimation(int x, int y)
+{
+  GfxFrame[x][y] = 0;
+  GfxAction[x][y] = ACTION_DEFAULT;
+}
+
 void InitMovingField(int x, int y, int direction)
 {
-  int newx = x + (direction == MV_LEFT ? -1 : direction == MV_RIGHT ? +1 : 0);
-  int newy = y + (direction == MV_UP   ? -1 : direction == MV_DOWN  ? +1 : 0);
+  int element = Feld[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 newx = x + dx;
+  int newy = y + dy;
+
+  if (!JustStopped[x][y] || direction != MovDir[x][y])
+    ResetGfxAnimation(x, y);
 
-  MovDir[x][y] = direction;
-  MovDir[newx][newy] = direction;
-  if (Feld[newx][newy] == EL_LEERRAUM)
+  MovDir[newx][newy] = MovDir[x][y] = direction;
+
+  if (Feld[newx][newy] == EL_EMPTY)
     Feld[newx][newy] = EL_BLOCKED;
+
+  if (direction == MV_DOWN && CAN_FALL(element))
+    GfxAction[x][y] = ACTION_FALLING;
+  else
+    GfxAction[x][y] = ACTION_MOVING;
+
+  GfxFrame[newx][newy] = GfxFrame[x][y];
+  GfxAction[newx][newy] = GfxAction[x][y];
+  GfxRandom[newx][newy] = GfxRandom[x][y];
 }
 
 void Moving2Blocked(int x, int y, int *goes_to_x, int *goes_to_y)
@@ -1401,17 +1745,27 @@ static int MovingOrBlocked2ElementIfNotLeaving(int x, int y)
 
 static void RemoveField(int x, int y)
 {
-  Feld[x][y] = EL_LEERRAUM;
+  Feld[x][y] = EL_EMPTY;
+
   MovPos[x][y] = 0;
   MovDir[x][y] = 0;
   MovDelay[x][y] = 0;
+
+  AmoebaNr[x][y] = 0;
+  ChangeDelay[x][y] = 0;
+  Pushed[x][y] = FALSE;
+
+  GfxElement[x][y] = EL_UNDEFINED;
+  GfxAction[x][y] = ACTION_DEFAULT;
 }
 
 void RemoveMovingField(int x, int y)
 {
   int oldx = x, oldy = y, newx = x, newy = y;
+  int element = Feld[x][y];
+  int next_element = EL_UNDEFINED;
 
-  if (Feld[x][y] != EL_BLOCKED && !IS_MOVING(x, y))
+  if (element != EL_BLOCKED && !IS_MOVING(x, y))
     return;
 
   if (IS_MOVING(x, y))
@@ -1420,27 +1774,27 @@ void RemoveMovingField(int x, int y)
     if (Feld[newx][newy] != EL_BLOCKED)
       return;
   }
-  else if (Feld[x][y] == EL_BLOCKED)
+  else if (element == EL_BLOCKED)
   {
     Blocked2Moving(x, y, &oldx, &oldy);
     if (!IS_MOVING(oldx, oldy))
       return;
   }
 
-  if (Feld[x][y] == EL_BLOCKED &&
+  if (element == EL_BLOCKED &&
       (Feld[oldx][oldy] == EL_QUICKSAND_EMPTYING ||
        Feld[oldx][oldy] == EL_MAGIC_WALL_EMPTYING ||
-       Feld[oldx][oldy] == EL_MAGIC_WALL_BD_EMPTYING ||
-       Feld[oldx][oldy] == EL_AMOEBA_DRIPPING))
-    Feld[oldx][oldy] = get_next_element(Feld[oldx][oldy]);
-  else
-    Feld[oldx][oldy] = EL_LEERRAUM;
+       Feld[oldx][oldy] == EL_BD_MAGIC_WALL_EMPTYING ||
+       Feld[oldx][oldy] == EL_AMOEBA_DROPPING))
+    next_element = get_next_element(Feld[oldx][oldy]);
+
+  RemoveField(oldx, oldy);
+  RemoveField(newx, newy);
 
   Store[oldx][oldy] = Store2[oldx][oldy] = 0;
 
-  Feld[newx][newy] = EL_LEERRAUM;
-  MovPos[oldx][oldy] = MovDir[oldx][oldy] = MovDelay[oldx][oldy] = 0;
-  MovPos[newx][newy] = MovDir[newx][newy] = MovDelay[newx][newy] = 0;
+  if (next_element != EL_UNDEFINED)
+    Feld[oldx][oldy] = next_element;
 
   DrawLevelField(oldx, oldy);
   DrawLevelField(newx, newy);
@@ -1449,60 +1803,61 @@ void RemoveMovingField(int x, int y)
 void DrawDynamite(int x, int y)
 {
   int sx = SCREENX(x), sy = SCREENY(y);
-  int graphic = el2gfx(Feld[x][y]);
-  int phase;
+  int graphic = el2img(Feld[x][y]);
+  int frame;
 
   if (!IN_SCR_FIELD(sx, sy) || IS_PLAYER(x, y))
     return;
 
-  if (Store[x][y])
-    DrawGraphic(sx, sy, el2gfx(Store[x][y]));
+  if (IS_WALKABLE_INSIDE(Back[x][y]))
+    return;
 
-  if (Feld[x][y] == EL_DYNAMITE_ACTIVE)
-  {
-    if ((phase = (96 - MovDelay[x][y]) / 12) > 6)
-      phase = 6;
-  }
-  else
-  {
-    if ((phase = ((96 - MovDelay[x][y]) / 6) % 8) > 3)
-      phase = 7 - phase;
-  }
+  if (Back[x][y])
+    DrawGraphic(sx, sy, el2img(Back[x][y]), 0);
+  else if (Store[x][y])
+    DrawGraphic(sx, sy, el2img(Store[x][y]), 0);
+
+  frame = getGraphicAnimationFrame(graphic, GfxFrame[x][y]);
 
+#if 1
+  if (Back[x][y] || Store[x][y])
+    DrawGraphicThruMask(sx, sy, graphic, frame);
+  else
+    DrawGraphic(sx, sy, graphic, frame);
+#else
   if (game.emulation == EMU_SUPAPLEX)
-    DrawGraphic(sx, sy, GFX_SP_DISK_RED);
+    DrawGraphic(sx, sy, IMG_SP_DISK_RED, frame);
   else if (Store[x][y])
-    DrawGraphicThruMask(sx, sy, graphic + phase);
+    DrawGraphicThruMask(sx, sy, graphic, frame);
   else
-    DrawGraphic(sx, sy, graphic + phase);
+    DrawGraphic(sx, sy, graphic, frame);
+#endif
 }
 
 void CheckDynamite(int x, int y)
 {
-  if (MovDelay[x][y])          /* dynamite is still waiting to explode */
+  if (MovDelay[x][y] != 0)     /* dynamite is still waiting to explode */
   {
     MovDelay[x][y]--;
-    if (MovDelay[x][y])
-    {
-      if (!(MovDelay[x][y] % 6))
-       PlaySoundLevelAction(x, y, SND_ACTION_BURNING);
-
-      if (IS_ACTIVE_BOMB(Feld[x][y]))
-      {
-       int delay = (Feld[x][y] == EL_DYNAMITE_ACTIVE ? 12 : 6);
 
-       if (!(MovDelay[x][y] % delay))
-         DrawDynamite(x, y);
-      }
+    if (MovDelay[x][y] != 0)
+    {
+      DrawDynamite(x, y);
+      PlaySoundLevelActionIfLoop(x, y, ACTION_ACTIVE);
 
       return;
     }
   }
 
-  if (Feld[x][y] == EL_DYNAMITE_ACTIVE)
-    StopSound(SND_DYNAMITE_BURNING);
+#if 1
+  StopSoundLevelActionIfLoop(x, y, ACTION_ACTIVE);
+#else
+  if (Feld[x][y] == EL_DYNAMITE_ACTIVE ||
+      Feld[x][y] == EL_SP_DISK_RED_ACTIVE)
+    StopSound(SND_DYNAMITE_ACTIVE);
   else
-    StopSound(SND_DYNABOMB_BURNING);
+    StopSound(SND_DYNABOMB_ACTIVE);
+#endif
 
   Bang(x, y);
 }
@@ -1510,7 +1865,8 @@ void CheckDynamite(int x, int y)
 void Explode(int ex, int ey, int phase, int mode)
 {
   int x, y;
-  int num_phase = 9, delay = (game.emulation == EMU_SUPAPLEX ? 3 : 2);
+  int num_phase = 9;
+  int delay = (game.emulation == EMU_SUPAPLEX ? 3 : 2);
   int last_phase = num_phase * delay;
   int half_phase = (num_phase / 2) * delay;
   int first_phase_after_start = EX_PHASE_START + 1;
@@ -1525,6 +1881,21 @@ void Explode(int ex, int ey, int phase, int mode)
   {
     int center_element = Feld[ex][ey];
 
+#if 0
+    /* --- This is only really needed (and now handled) in "Impact()". --- */
+    /* do not explode moving elements that left the explode field in time */
+    if (game.engine_version >= RELEASE_IDENT(2,2,0,7) &&
+       center_element == EL_EMPTY && (mode == EX_NORMAL || mode == EX_CENTER))
+      return;
+#endif
+
+    if (mode == EX_NORMAL || mode == EX_CENTER)
+      PlaySoundLevelAction(ex, ey, ACTION_EXPLODING);
+
+    /* remove things displayed in background while burning dynamite */
+    if (Back[ex][ey] != EL_EMPTY && !IS_INDESTRUCTIBLE(Back[ex][ey]))
+      Back[ex][ey] = 0;
+
     if (IS_MOVING(ex, ey) || IS_BLOCKED(ex, ey))
     {
       /* put moving element to center field (and let it explode there) */
@@ -1533,12 +1904,14 @@ void Explode(int ex, int ey, int phase, int mode)
       Feld[ex][ey] = center_element;
     }
 
-    for (y=ey-1; y<=ey+1; y++) for(x=ex-1; x<=ex+1; x++)
+    for (y = ey - 1; y <= ey + 1; y++) for(x = ex - 1; x <= ex + 1; x++)
     {
+      int xx = x - ex + 1;
+      int yy = y - ey + 1;
       int element;
 
       if (!IN_LEV_FIELD(x, y) ||
-         ((mode != EX_NORMAL || center_element == EL_AMOEBA2DIAM) &&
+         ((mode != EX_NORMAL || center_element == EL_AMOEBA_TO_DIAMOND) &&
           (x != ex || y != ey)))
        continue;
 
@@ -1547,104 +1920,165 @@ void Explode(int ex, int ey, int phase, int mode)
       if (IS_MOVING(x, y) || IS_BLOCKED(x, y))
       {
        element = MovingOrBlocked2Element(x, y);
-       RemoveMovingField(x, y);
+
+       if (!IS_EXPLOSION_PROOF(element))
+         RemoveMovingField(x, y);
       }
 
-      if (IS_MASSIVE(element) || element == EL_BURNING)
+#if 1
+
+#if 0
+      if (IS_EXPLOSION_PROOF(element))
+       continue;
+#else
+      /* indestructible elements can only explode in center (but not flames) */
+      if ((IS_EXPLOSION_PROOF(element) && (x != ex || y != ey)) ||
+         element == EL_FLAMES)
+       continue;
+#endif
+
+#else
+      if ((IS_INDESTRUCTIBLE(element) &&
+          (game.engine_version < VERSION_IDENT(2,2,0) ||
+           (!IS_WALKABLE_OVER(element) && !IS_WALKABLE_UNDER(element)))) ||
+         element == EL_FLAMES)
        continue;
+#endif
 
       if (IS_PLAYER(x, y) && SHIELD_ON(PLAYERINFO(x, y)))
       {
        if (IS_ACTIVE_BOMB(element))
        {
          /* re-activate things under the bomb like gate or penguin */
-         Feld[x][y] = (Store[x][y] ? Store[x][y] : EL_LEERRAUM);
+         Feld[x][y] = (Store[x][y] ? Store[x][y] : EL_EMPTY);
          Store[x][y] = 0;
        }
 
        continue;
       }
 
-      if (element == EL_EXPLODING)
+      /* save walkable background elements while explosion on same tile */
+#if 0
+      if (IS_INDESTRUCTIBLE(element))
+       Back[x][y] = element;
+#else
+      if (IS_WALKABLE(element) && IS_INDESTRUCTIBLE(element))
+       Back[x][y] = element;
+#endif
+
+      /* ignite explodable elements reached by other explosion */
+      if (element == EL_EXPLOSION)
        element = Store2[x][y];
 
+#if 1
+      if (AmoebaNr[x][y] &&
+         (element == EL_AMOEBA_FULL ||
+          element == EL_BD_AMOEBA ||
+          element == EL_AMOEBA_GROWING))
+      {
+       AmoebaCnt[AmoebaNr[x][y]]--;
+       AmoebaCnt2[AmoebaNr[x][y]]--;
+      }
+
+      RemoveField(x, y);
+#endif
+
       if (IS_PLAYER(ex, ey) && !PLAYER_PROTECTED(ex, ey))
       {
        switch(StorePlayer[ex][ey])
        {
-         case EL_SPIELER2:
-           Store[x][y] = EL_EDELSTEIN_ROT;
+         case EL_PLAYER_2:
+           Store[x][y] = EL_EMERALD_RED;
            break;
-         case EL_SPIELER3:
-           Store[x][y] = EL_EDELSTEIN;
+         case EL_PLAYER_3:
+           Store[x][y] = EL_EMERALD;
            break;
-         case EL_SPIELER4:
-           Store[x][y] = EL_EDELSTEIN_LILA;
+         case EL_PLAYER_4:
+           Store[x][y] = EL_EMERALD_PURPLE;
            break;
-         case EL_SPIELER1:
+         case EL_PLAYER_1:
          default:
-           Store[x][y] = EL_EDELSTEIN_GELB;
+           Store[x][y] = EL_EMERALD_YELLOW;
            break;
        }
 
        if (game.emulation == EMU_SUPAPLEX)
-         Store[x][y] = EL_LEERRAUM;
+         Store[x][y] = EL_EMPTY;
       }
       else if (center_element == EL_MOLE)
-       Store[x][y] = EL_EDELSTEIN_ROT;
-      else if (center_element == EL_PINGUIN)
-       Store[x][y] = EL_EDELSTEIN_LILA;
-      else if (center_element == EL_KAEFER)
-       Store[x][y] = ((x == ex && y == ey) ? EL_DIAMANT : EL_EDELSTEIN);
-      else if (center_element == EL_BUTTERFLY)
-       Store[x][y] = EL_EDELSTEIN_BD;
+       Store[x][y] = EL_EMERALD_RED;
+      else if (center_element == EL_PENGUIN)
+       Store[x][y] = EL_EMERALD_PURPLE;
+      else if (center_element == EL_BUG)
+       Store[x][y] = ((x == ex && y == ey) ? EL_DIAMOND : EL_EMERALD);
+      else if (center_element == EL_BD_BUTTERFLY)
+       Store[x][y] = EL_BD_DIAMOND;
       else if (center_element == EL_SP_ELECTRON)
        Store[x][y] = EL_SP_INFOTRON;
-      else if (center_element == EL_MAMPFER)
-       Store[x][y] = level.yam_content[game.yam_content_nr][x-ex+1][y-ey+1];
-      else if (center_element == EL_AMOEBA2DIAM)
+      else if (center_element == EL_AMOEBA_TO_DIAMOND)
        Store[x][y] = level.amoeba_content;
-      else if (element == EL_ERZ_EDEL)
-       Store[x][y] = EL_EDELSTEIN;
-      else if (element == EL_ERZ_DIAM)
-       Store[x][y] = EL_DIAMANT;
-      else if (element == EL_ERZ_EDEL_BD)
-       Store[x][y] = EL_EDELSTEIN_BD;
-      else if (element == EL_ERZ_EDEL_GELB)
-       Store[x][y] = EL_EDELSTEIN_GELB;
-      else if (element == EL_ERZ_EDEL_ROT)
-       Store[x][y] = EL_EDELSTEIN_ROT;
-      else if (element == EL_ERZ_EDEL_LILA)
-       Store[x][y] = EL_EDELSTEIN_LILA;
+      else if (center_element == EL_YAMYAM)
+       Store[x][y] = level.yamyam_content[game.yamyam_content_nr][xx][yy];
+      else if (IS_CUSTOM_ELEMENT(center_element) &&
+              element_info[center_element].content[xx][yy] != EL_EMPTY)
+       Store[x][y] = element_info[center_element].content[xx][yy];
+      else if (element == EL_WALL_EMERALD)
+       Store[x][y] = EL_EMERALD;
+      else if (element == EL_WALL_DIAMOND)
+       Store[x][y] = EL_DIAMOND;
+      else if (element == EL_WALL_BD_DIAMOND)
+       Store[x][y] = EL_BD_DIAMOND;
+      else if (element == EL_WALL_EMERALD_YELLOW)
+       Store[x][y] = EL_EMERALD_YELLOW;
+      else if (element == EL_WALL_EMERALD_RED)
+       Store[x][y] = EL_EMERALD_RED;
+      else if (element == EL_WALL_EMERALD_PURPLE)
+       Store[x][y] = EL_EMERALD_PURPLE;
       else if (element == EL_WALL_PEARL)
        Store[x][y] = EL_PEARL;
       else if (element == EL_WALL_CRYSTAL)
        Store[x][y] = EL_CRYSTAL;
-      else if (!IS_PFORTE(Store[x][y]))
-       Store[x][y] = EL_LEERRAUM;
+      else if (IS_CUSTOM_ELEMENT(element))
+       Store[x][y] = element_info[element].content[1][1];
+      else
+       Store[x][y] = EL_EMPTY;
 
       if (x != ex || y != ey ||
-         center_element == EL_AMOEBA2DIAM || mode == EX_BORDER)
+         center_element == EL_AMOEBA_TO_DIAMOND || mode == EX_BORDER)
        Store2[x][y] = element;
 
+#if 0
       if (AmoebaNr[x][y] &&
-         (element == EL_AMOEBE_VOLL ||
-          element == EL_AMOEBE_BD ||
-          element == EL_AMOEBING))
+         (element == EL_AMOEBA_FULL ||
+          element == EL_BD_AMOEBA ||
+          element == EL_AMOEBA_GROWING))
       {
        AmoebaCnt[AmoebaNr[x][y]]--;
        AmoebaCnt2[AmoebaNr[x][y]]--;
       }
 
-      Feld[x][y] = EL_EXPLODING;
+#if 1
+      RemoveField(x, y);
+#else
       MovDir[x][y] = MovPos[x][y] = 0;
       AmoebaNr[x][y] = 0;
-      Frame[x][y] = 1;
+#endif
+#endif
+
+      Feld[x][y] = EL_EXPLOSION;
+#if 1
+      GfxElement[x][y] = center_element;
+#else
+      GfxElement[x][y] = EL_UNDEFINED;
+#endif
+
+      ExplodePhase[x][y] = 1;
       Stop[x][y] = TRUE;
     }
 
-    if (center_element == EL_MAMPFER)
-      game.yam_content_nr = (game.yam_content_nr + 1) % level.num_yam_contents;
+    if (center_element == EL_YAMYAM)
+      game.yamyam_content_nr =
+       (game.yamyam_content_nr + 1) % level.num_yamyam_contents;
 
     return;
   }
@@ -1655,7 +2089,7 @@ void Explode(int ex, int ey, int phase, int mode)
   x = ex;
   y = ey;
 
-  Frame[x][y] = (phase < last_phase ? phase + 1 : 0);
+  ExplodePhase[x][y] = (phase < last_phase ? phase + 1 : 0);
 
   if (phase == first_phase_after_start)
   {
@@ -1674,13 +2108,13 @@ void Explode(int ex, int ey, int phase, int mode)
 
     if (IS_PLAYER(x, y))
       KillHeroUnlessProtected(x, y);
-    else if (IS_EXPLOSIVE(element))
+    else if (CAN_EXPLODE_BY_FIRE(element))
     {
       Feld[x][y] = Store2[x][y];
       Store2[x][y] = 0;
       Bang(x, y);
     }
-    else if (element == EL_AMOEBA2DIAM)
+    else if (element == EL_AMOEBA_TO_DIAMOND)
       AmoebeUmwandeln(x, y);
   }
 
@@ -1690,36 +2124,51 @@ void Explode(int ex, int ey, int phase, int mode)
 
     element = Feld[x][y] = Store[x][y];
     Store[x][y] = Store2[x][y] = 0;
-    MovDir[x][y] = MovPos[x][y] = MovDelay[x][y] = 0;
+    GfxElement[x][y] = EL_UNDEFINED;
+
+    if (Back[x][y] && IS_INDESTRUCTIBLE(Back[x][y]))
+      element = Feld[x][y] = Back[x][y];
+    Back[x][y] = 0;
+
+    MovDir[x][y] = MovPos[x][y] = MovDelay[x][y] = ChangeDelay[x][y] = 0;
     InitField(x, y, FALSE);
-    if (CAN_MOVE(element) || COULD_MOVE(element))
+    if (CAN_MOVE(element))
       InitMovDir(x, y);
     DrawLevelField(x, y);
 
+    if (CAN_BE_CRUMBLED(element))
+      DrawLevelFieldCrumbledSandNeighbours(x, y);
+
     if (IS_PLAYER(x, y) && !PLAYERINFO(x,y)->present)
       StorePlayer[x][y] = 0;
   }
-  else if (!(phase % delay) && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
+  else if (phase >= delay && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
   {
-    int graphic = GFX_EXPLOSION;
-
-    if (game.emulation == EMU_SUPAPLEX)
-      graphic = (Store[x][y] == EL_SP_INFOTRON ?
-                GFX_SP_EXPLODE_INFOTRON :
-                GFX_SP_EXPLODE_EMPTY);
+#if 1
+    int graphic = el_act2img(GfxElement[x][y], ACTION_EXPLODING);
+#else
+    int stored = Store[x][y];
+    int graphic = (game.emulation != EMU_SUPAPLEX ? IMG_EXPLOSION :
+                  stored == EL_SP_INFOTRON ? IMG_SP_EXPLOSION_INFOTRON :
+                  IMG_SP_EXPLOSION);
+#endif
+    int frame = getGraphicAnimationFrame(graphic, phase - delay);
 
     if (phase == delay)
-      ErdreichAnbroeckeln(SCREENX(x), SCREENY(y));
+      DrawLevelFieldCrumbledSand(x, y);
 
-    graphic += (phase / delay - 1);
-
-    if (IS_PFORTE(Store[x][y]))
+    if (IS_WALKABLE_OVER(Back[x][y]) && Back[x][y] != EL_EMPTY)
     {
-      DrawLevelElement(x, y, Store[x][y]);
-      DrawGraphicThruMask(SCREENX(x), SCREENY(y), graphic);
+      DrawLevelElement(x, y, Back[x][y]);
+      DrawGraphicThruMask(SCREENX(x), SCREENY(y), graphic, frame);
     }
-    else
-      DrawGraphic(SCREENX(x), SCREENY(y), graphic);
+    else if (IS_WALKABLE_UNDER(Back[x][y]))
+    {
+      DrawGraphic(SCREENX(x), SCREENY(y), graphic, frame);
+      DrawLevelElementThruMask(x, y, Back[x][y]);
+    }
+    else if (!IS_WALKABLE_INSIDE(Back[x][y]))
+      DrawGraphic(SCREENX(x), SCREENY(y), graphic, frame);
   }
 }
 
@@ -1739,7 +2188,7 @@ void DynaExplode(int ex, int ey)
 
   if (IS_ACTIVE_BOMB(Feld[ex][ey]))
   {
-    player = &stored_player[Feld[ex][ey] - EL_DYNABOMB_ACTIVE_1];
+    player = &stored_player[Feld[ex][ey] - EL_DYNABOMB_PLAYER_1_ACTIVE];
     dynabomb_size = player->dynabomb_size;
     dynabomb_xl = player->dynabomb_xl;
     player->dynabombs_left++;
@@ -1755,20 +2204,21 @@ void DynaExplode(int ex, int ey)
       int y = ey + j * xy[i % 4][1];
       int element;
 
-      if (!IN_LEV_FIELD(x, y) || IS_MASSIVE(Feld[x][y]))
+      if (!IN_LEV_FIELD(x, y) || IS_INDESTRUCTIBLE(Feld[x][y]))
        break;
 
       element = Feld[x][y];
 
       /* do not restart explosions of fields with active bombs */
-      if (element == EL_EXPLODING && IS_ACTIVE_BOMB(Store2[x][y]))
+      if (element == EL_EXPLOSION && IS_ACTIVE_BOMB(Store2[x][y]))
        continue;
 
       Explode(x, y, EX_PHASE_START, EX_BORDER);
 
-      if (element != EL_LEERRAUM &&
-         element != EL_ERDREICH &&
-         element != EL_EXPLODING &&
+      /* !!! extend EL_SAND to anything diggable (but maybe not SP_BASE) !!! */
+      if (element != EL_EMPTY &&
+         element != EL_SAND &&
+         element != EL_EXPLOSION &&
          !dynabomb_xl)
        break;
     }
@@ -1777,44 +2227,62 @@ void DynaExplode(int ex, int ey)
 
 void Bang(int x, int y)
 {
+#if 1
+  int element = MovingOrBlocked2Element(x, y);
+#else
   int element = Feld[x][y];
+#endif
+
+  if (IS_PLAYER(x, y))
+  {
+    struct PlayerInfo *player = PLAYERINFO(x, y);
+
+    element = Feld[x][y] = (player->use_murphy_graphic ? EL_SP_MURPHY :
+                           player->element_nr);
+  }
 
+#if 0
+#if 1
+  PlaySoundLevelAction(x, y, ACTION_EXPLODING);
+#else
   if (game.emulation == EMU_SUPAPLEX)
     PlaySoundLevel(x, y, SND_SP_ELEMENT_EXPLODING);
   else
     PlaySoundLevel(x, y, SND_ELEMENT_EXPLODING);
+#endif
+#endif
 
 #if 0
   if (IS_PLAYER(x, y)) /* remove objects that might cause smaller explosion */
-    element = EL_LEERRAUM;
+    element = EL_EMPTY;
 #endif
 
   switch(element)
   {
-    case EL_KAEFER:
-    case EL_FLIEGER:
-    case EL_BUTTERFLY:
-    case EL_FIREFLY:
-    case EL_MAMPFER:
-    case EL_MAMPFER2:
+    case EL_BUG:
+    case EL_SPACESHIP:
+    case EL_BD_BUTTERFLY:
+    case EL_BD_FIREFLY:
+    case EL_YAMYAM:
+    case EL_DARK_YAMYAM:
     case EL_ROBOT:
     case EL_PACMAN:
     case EL_MOLE:
       RaiseScoreElement(element);
       Explode(x, y, EX_PHASE_START, EX_NORMAL);
       break;
-    case EL_DYNABOMB_ACTIVE_1:
-    case EL_DYNABOMB_ACTIVE_2:
-    case EL_DYNABOMB_ACTIVE_3:
-    case EL_DYNABOMB_ACTIVE_4:
-    case EL_DYNABOMB_NR:
-    case EL_DYNABOMB_SZ:
-    case EL_DYNABOMB_XL:
+    case EL_DYNABOMB_PLAYER_1_ACTIVE:
+    case EL_DYNABOMB_PLAYER_2_ACTIVE:
+    case EL_DYNABOMB_PLAYER_3_ACTIVE:
+    case EL_DYNABOMB_PLAYER_4_ACTIVE:
+    case EL_DYNABOMB_INCREASE_NUMBER:
+    case EL_DYNABOMB_INCREASE_SIZE:
+    case EL_DYNABOMB_INCREASE_POWER:
       DynaExplode(x, y);
       break;
-    case EL_PINGUIN:
-    case EL_BIRNE_AUS:
-    case EL_BIRNE_EIN:
+    case EL_PENGUIN:
+    case EL_LAMP:
+    case EL_LAMP_ACTIVE:
       if (IS_PLAYER(x, y))
        Explode(x, y, EX_PHASE_START, EX_NORMAL);
       else
@@ -1824,45 +2292,87 @@ void Bang(int x, int y)
       Explode(x, y, EX_PHASE_START, EX_NORMAL);
       break;
   }
+
+  CheckTriggeredElementChange(x, y, element, CE_OTHER_IS_EXPLODING);
 }
 
-void Blurb(int x, int y)
+void SplashAcid(int x, int y)
 {
   int element = Feld[x][y];
 
-  if (element != EL_BLURB_LEFT && element != EL_BLURB_RIGHT)   /* start */
+  if (element != EL_ACID_SPLASH_LEFT &&
+      element != EL_ACID_SPLASH_RIGHT)
   {
     PlaySoundLevel(x, y, SND_ACID_SPLASHING);
+
     if (IN_LEV_FIELD(x-1, y) && IS_FREE(x-1, y) &&
        (!IN_LEV_FIELD(x-1, y-1) ||
         !CAN_FALL(MovingOrBlocked2Element(x-1, y-1))))
-    {
-      Feld[x-1][y] = EL_BLURB_LEFT;
-    }
+      Feld[x-1][y] = EL_ACID_SPLASH_LEFT;
+
     if (IN_LEV_FIELD(x+1, y) && IS_FREE(x+1, y) &&
        (!IN_LEV_FIELD(x+1, y-1) ||
         !CAN_FALL(MovingOrBlocked2Element(x+1, y-1))))
-    {
-      Feld[x+1][y] = EL_BLURB_RIGHT;
-    }
+      Feld[x+1][y] = EL_ACID_SPLASH_RIGHT;
   }
-  else                                                         /* go on */
+}
+
+static void InitBeltMovement()
+{
+  static int belt_base_element[4] =
+  {
+    EL_CONVEYOR_BELT_1_LEFT,
+    EL_CONVEYOR_BELT_2_LEFT,
+    EL_CONVEYOR_BELT_3_LEFT,
+    EL_CONVEYOR_BELT_4_LEFT
+  };
+  static int belt_base_active_element[4] =
   {
-    int graphic = (element==EL_BLURB_LEFT ? GFX_BLURB_LEFT : GFX_BLURB_RIGHT);
+    EL_CONVEYOR_BELT_1_LEFT_ACTIVE,
+    EL_CONVEYOR_BELT_2_LEFT_ACTIVE,
+    EL_CONVEYOR_BELT_3_LEFT_ACTIVE,
+    EL_CONVEYOR_BELT_4_LEFT_ACTIVE
+  };
 
-    if (!MovDelay[x][y])       /* initialize animation counter */
-      MovDelay[x][y] = 9;
+  int x, y, i, j;
+
+  /* set frame order for belt animation graphic according to belt direction */
+  for (i=0; i<4; i++)
+  {
+    int belt_nr = i;
 
-    if (MovDelay[x][y])                /* continue animation */
+    for (j=0; j<3; j++)
     {
-      MovDelay[x][y]--;
-      if (MovDelay[x][y]/2 && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
-       DrawGraphic(SCREENX(x), SCREENY(y), graphic+4-MovDelay[x][y]/2);
+      int element = belt_base_active_element[belt_nr] + j;
+      int graphic = el2img(element);
+
+      if (game.belt_dir[i] == MV_LEFT)
+       graphic_info[graphic].anim_mode &= ~ANIM_REVERSE;
+      else
+       graphic_info[graphic].anim_mode |=  ANIM_REVERSE;
+    }
+  }
+
+  for(y=0; y<lev_fieldy; y++)
+  {
+    for(x=0; x<lev_fieldx; x++)
+    {
+      int element = Feld[x][y];
 
-      if (!MovDelay[x][y])
+      for (i=0; i<4; i++)
       {
-       Feld[x][y] = EL_LEERRAUM;
-       DrawLevelField(x, y);
+       if (IS_BELT(element) && game.belt_dir[i] != MV_NO_MOVING)
+       {
+         int e_belt_nr = getBeltNrFromBeltElement(element);
+         int belt_nr = i;
+
+         if (e_belt_nr == belt_nr)
+         {
+           int belt_part = Feld[x][y] - belt_base_element[belt_nr];
+
+           Feld[x][y] = belt_base_active_element[belt_nr] + belt_part;
+         }
+       }
       }
     }
   }
@@ -1872,10 +2382,24 @@ static void ToggleBeltSwitch(int x, int y)
 {
   static int belt_base_element[4] =
   {
-    EL_BELT1_SWITCH_LEFT,
-    EL_BELT2_SWITCH_LEFT,
-    EL_BELT3_SWITCH_LEFT,
-    EL_BELT4_SWITCH_LEFT
+    EL_CONVEYOR_BELT_1_LEFT,
+    EL_CONVEYOR_BELT_2_LEFT,
+    EL_CONVEYOR_BELT_3_LEFT,
+    EL_CONVEYOR_BELT_4_LEFT
+  };
+  static int belt_base_active_element[4] =
+  {
+    EL_CONVEYOR_BELT_1_LEFT_ACTIVE,
+    EL_CONVEYOR_BELT_2_LEFT_ACTIVE,
+    EL_CONVEYOR_BELT_3_LEFT_ACTIVE,
+    EL_CONVEYOR_BELT_4_LEFT_ACTIVE
+  };
+  static int belt_base_switch_element[4] =
+  {
+    EL_CONVEYOR_BELT_1_SWITCH_LEFT,
+    EL_CONVEYOR_BELT_2_SWITCH_LEFT,
+    EL_CONVEYOR_BELT_3_SWITCH_LEFT,
+    EL_CONVEYOR_BELT_4_SWITCH_LEFT
   };
   static int belt_move_dir[4] =
   {
@@ -1886,10 +2410,10 @@ static void ToggleBeltSwitch(int x, int y)
   };
 
   int element = Feld[x][y];
-  int belt_nr = getBeltNrFromSwitchElement(element);
+  int belt_nr = getBeltNrFromBeltSwitchElement(element);
   int belt_dir_nr = (game.belt_dir_nr[belt_nr] + 1) % 4;
   int belt_dir = belt_move_dir[belt_dir_nr];
-  int xx, yy;
+  int xx, yy, i;
 
   if (!IS_BELT_SWITCH(element))
     return;
@@ -1900,6 +2424,18 @@ static void ToggleBeltSwitch(int x, int y)
   if (belt_dir_nr == 3)
     belt_dir_nr = 1;
 
+  /* set frame order for belt animation graphic according to belt direction */
+  for (i=0; i<3; i++)
+  {
+    int element = belt_base_active_element[belt_nr] + i;
+    int graphic = el2img(element);
+
+    if (belt_dir == MV_LEFT)
+      graphic_info[graphic].anim_mode &= ~ANIM_REVERSE;
+    else
+      graphic_info[graphic].anim_mode |=  ANIM_REVERSE;
+  }
+
   for (yy=0; yy<lev_fieldy; yy++)
   {
     for (xx=0; xx<lev_fieldx; xx++)
@@ -1908,20 +2444,37 @@ static void ToggleBeltSwitch(int x, int y)
 
       if (IS_BELT_SWITCH(element))
       {
-       int e_belt_nr = getBeltNrFromSwitchElement(element);
+       int e_belt_nr = getBeltNrFromBeltSwitchElement(element);
+
+       if (e_belt_nr == belt_nr)
+       {
+         Feld[xx][yy] = belt_base_switch_element[belt_nr] + belt_dir_nr;
+         DrawLevelField(xx, yy);
+       }
+      }
+      else if (IS_BELT(element) && belt_dir != MV_NO_MOVING)
+      {
+       int e_belt_nr = getBeltNrFromBeltElement(element);
 
        if (e_belt_nr == belt_nr)
        {
-         Feld[xx][yy] = belt_base_element[belt_nr] + belt_dir_nr;
+         int belt_part = Feld[xx][yy] - belt_base_element[belt_nr];
+
+         Feld[xx][yy] = belt_base_active_element[belt_nr] + belt_part;
          DrawLevelField(xx, yy);
        }
       }
-      else if (belt_dir == MV_NO_MOVING && IS_BELT(element))
+      else if (IS_BELT_ACTIVE(element) && belt_dir == MV_NO_MOVING)
       {
-       int e_belt_nr = getBeltNrFromElement(element);
+       int e_belt_nr = getBeltNrFromBeltActiveElement(element);
 
        if (e_belt_nr == belt_nr)
-         DrawLevelField(xx, yy);    /* set belt to parking position */
+       {
+         int belt_part = Feld[xx][yy] - belt_base_active_element[belt_nr];
+
+         Feld[xx][yy] = belt_base_element[belt_nr] + belt_part;
+         DrawLevelField(xx, yy);
+       }
       }
     }
   }
@@ -1939,28 +2492,52 @@ static void ToggleSwitchgateSwitch(int x, int y)
     {
       int element = Feld[xx][yy];
 
-      if (element == EL_SWITCHGATE_SWITCH_1 ||
-         element == EL_SWITCHGATE_SWITCH_2)
+      if (element == EL_SWITCHGATE_SWITCH_UP ||
+         element == EL_SWITCHGATE_SWITCH_DOWN)
       {
-       Feld[xx][yy] = EL_SWITCHGATE_SWITCH_1 + game.switchgate_pos;
+       Feld[xx][yy] = EL_SWITCHGATE_SWITCH_UP + game.switchgate_pos;
        DrawLevelField(xx, yy);
       }
       else if (element == EL_SWITCHGATE_OPEN ||
               element == EL_SWITCHGATE_OPENING)
       {
        Feld[xx][yy] = EL_SWITCHGATE_CLOSING;
+#if 1
+       PlaySoundLevelAction(xx, yy, ACTION_CLOSING);
+#else
        PlaySoundLevel(xx, yy, SND_SWITCHGATE_CLOSING);
+#endif
       }
       else if (element == EL_SWITCHGATE_CLOSED ||
               element == EL_SWITCHGATE_CLOSING)
       {
        Feld[xx][yy] = EL_SWITCHGATE_OPENING;
+#if 1
+       PlaySoundLevelAction(xx, yy, ACTION_OPENING);
+#else
        PlaySoundLevel(xx, yy, SND_SWITCHGATE_OPENING);
+#endif
       }
     }
   }
 }
 
+static int getInvisibleActiveFromInvisibleElement(int element)
+{
+  return (element == EL_INVISIBLE_STEELWALL ? EL_INVISIBLE_STEELWALL_ACTIVE :
+         element == EL_INVISIBLE_WALL      ? EL_INVISIBLE_WALL_ACTIVE :
+         element == EL_INVISIBLE_SAND      ? EL_INVISIBLE_SAND_ACTIVE :
+         element);
+}
+
+static int getInvisibleFromInvisibleActiveElement(int element)
+{
+  return (element == EL_INVISIBLE_STEELWALL_ACTIVE ? EL_INVISIBLE_STEELWALL :
+         element == EL_INVISIBLE_WALL_ACTIVE      ? EL_INVISIBLE_WALL :
+         element == EL_INVISIBLE_SAND_ACTIVE      ? EL_INVISIBLE_SAND :
+         element);
+}
+
 static void RedrawAllLightSwitchesAndInvisibleElements()
 {
   int x, y;
@@ -1971,23 +2548,36 @@ static void RedrawAllLightSwitchesAndInvisibleElements()
     {
       int element = Feld[x][y];
 
-      if (element == EL_LIGHT_SWITCH_OFF &&
+      if (element == EL_LIGHT_SWITCH &&
          game.light_time_left > 0)
       {
-       Feld[x][y] = EL_LIGHT_SWITCH_ON;
+       Feld[x][y] = EL_LIGHT_SWITCH_ACTIVE;
        DrawLevelField(x, y);
       }
-      else if (element == EL_LIGHT_SWITCH_ON &&
+      else if (element == EL_LIGHT_SWITCH_ACTIVE &&
               game.light_time_left == 0)
       {
-       Feld[x][y] = EL_LIGHT_SWITCH_OFF;
+       Feld[x][y] = EL_LIGHT_SWITCH;
+       DrawLevelField(x, y);
+      }
+      else if (element == EL_INVISIBLE_STEELWALL ||
+              element == EL_INVISIBLE_WALL ||
+              element == EL_INVISIBLE_SAND)
+      {
+       if (game.light_time_left > 0)
+         Feld[x][y] = getInvisibleActiveFromInvisibleElement(element);
+
        DrawLevelField(x, y);
       }
+      else if (element == EL_INVISIBLE_STEELWALL_ACTIVE ||
+              element == EL_INVISIBLE_WALL_ACTIVE ||
+              element == EL_INVISIBLE_SAND_ACTIVE)
+      {
+       if (game.light_time_left == 0)
+         Feld[x][y] = getInvisibleFromInvisibleActiveElement(element);
 
-      if (element == EL_INVISIBLE_STEEL ||
-         element == EL_UNSICHTBAR ||
-         element == EL_SAND_INVISIBLE)
        DrawLevelField(x, y);
+      }
     }
   }
 }
@@ -1997,7 +2587,7 @@ static void ToggleLightSwitch(int x, int y)
   int element = Feld[x][y];
 
   game.light_time_left =
-    (element == EL_LIGHT_SWITCH_OFF ?
+    (element == EL_LIGHT_SWITCH ?
      level.time_light * FRAMES_PER_SECOND : 0);
 
   RedrawAllLightSwitchesAndInvisibleElements();
@@ -2023,9 +2613,9 @@ static void ActivateTimegateSwitch(int x, int y)
       }
 
       /*
-      else if (element == EL_TIMEGATE_SWITCH_ON)
+      else if (element == EL_TIMEGATE_SWITCH_ACTIVE)
       {
-       Feld[xx][yy] = EL_TIMEGATE_SWITCH_OFF;
+       Feld[xx][yy] = EL_TIMEGATE_SWITCH;
        DrawLevelField(xx, yy);
       }
       */
@@ -2033,72 +2623,128 @@ static void ActivateTimegateSwitch(int x, int y)
     }
   }
 
-  Feld[x][y] = EL_TIMEGATE_SWITCH_ON;
+  Feld[x][y] = EL_TIMEGATE_SWITCH_ACTIVE;
+}
+
+inline static int getElementMoveStepsize(int x, int y)
+{
+  int element = Feld[x][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 sign = (horiz_move ? dx : dy);
+  int step = sign * element_info[element].move_stepsize;
+
+  /* special values for move stepsize for spring and things on conveyor belt */
+  if (horiz_move)
+  {
+    if (CAN_FALL(element) &&
+       y < lev_fieldy - 1 && IS_BELT_ACTIVE(Feld[x][y + 1]))
+      step = sign * MOVE_STEPSIZE_NORMAL / 2;
+    else if (element == EL_SPRING)
+      step = sign * MOVE_STEPSIZE_NORMAL * 2;
+  }
+
+  return step;
 }
 
 void Impact(int x, int y)
 {
   boolean lastline = (y == lev_fieldy-1);
   boolean object_hit = FALSE;
+  boolean impact = (lastline || object_hit);
   int element = Feld[x][y];
-  int smashed = 0;
+  int smashed = EL_UNDEFINED;
 
   if (!lastline)       /* check if element below was hit */
   {
-    if (Feld[x][y+1] == EL_PLAYER_IS_LEAVING)
+    if (Feld[x][y + 1] == EL_PLAYER_IS_LEAVING)
       return;
 
-    object_hit = (!IS_FREE(x, y+1) && (!IS_MOVING(x, y+1) ||
-                                     MovDir[x][y+1]!=MV_DOWN ||
-                                     MovPos[x][y+1]<=TILEY/2));
+    object_hit = (!IS_FREE(x, y + 1) && (!IS_MOVING(x, y + 1) ||
+                                        MovDir[x][y + 1] != MV_DOWN ||
+                                        MovPos[x][y + 1] <= TILEY / 2));
+
+    /* do not smash moving elements that left the smashed field in time */
+    if (game.engine_version >= RELEASE_IDENT(2,2,0,7) && IS_MOVING(x, y + 1) &&
+       ABS(MovPos[x][y + 1] + getElementMoveStepsize(x, y + 1)) >= TILEX)
+      object_hit = FALSE;
+
     if (object_hit)
-      smashed = MovingOrBlocked2Element(x, y+1);
+      smashed = MovingOrBlocked2Element(x, y + 1);
+
+    impact = (lastline || object_hit);
   }
 
-  if (!lastline && smashed == EL_SALZSAEURE)   /* element falls into acid */
+  if (!lastline && smashed == EL_ACID) /* element falls into acid */
   {
-    Blurb(x, y);
+    SplashAcid(x, y);
     return;
   }
 
-  if ((element == EL_BOMBE ||
-       element == EL_SP_DISK_ORANGE ||
-       element == EL_DX_SUPABOMB) &&
-      (lastline || object_hit))        /* element is bomb */
+  if (impact)
+  {
+    ResetGfxAnimation(x, y);
+    DrawLevelField(x, y);
+  }
+
+  if (impact && CAN_EXPLODE_IMPACT(element))
   {
     Bang(x, y);
     return;
   }
-  else if (element == EL_PEARL)
+  else if (impact && element == EL_PEARL)
   {
     Feld[x][y] = EL_PEARL_BREAKING;
     PlaySoundLevel(x, y, SND_PEARL_BREAKING);
     return;
   }
+#if 1
+  else if (impact && CheckElementChange(x, y, element, CE_IMPACT))
+  {
+    PlaySoundLevelElementAction(x, y, element, ACTION_IMPACT);
+
+    return;
+  }
+#else
+  else if (impact && CAN_CHANGE(element) &&
+          HAS_CHANGE_EVENT(element, CE_IMPACT))
+  {
+    PlaySoundLevelElementAction(x, y, element, ACTION_IMPACT);
+
+    ChangeElementNow(x, y, element);
+
+    return;
+  }
+#endif
 
-  if (element == EL_TROPFEN && (lastline || object_hit))       /* acid drop */
+  if (impact && element == EL_AMOEBA_DROP)
   {
-    if (object_hit && IS_PLAYER(x, y+1))
-      KillHeroUnlessProtected(x, y+1);
-    else if (object_hit && smashed == EL_PINGUIN)
-      Bang(x, y+1);
+    if (object_hit && IS_PLAYER(x, y + 1))
+      KillHeroUnlessProtected(x, y + 1);
+    else if (object_hit && smashed == EL_PENGUIN)
+      Bang(x, y + 1);
     else
     {
-      Feld[x][y] = EL_AMOEBING;
-      Store[x][y] = EL_AMOEBE_NASS;
+      Feld[x][y] = EL_AMOEBA_GROWING;
+      Store[x][y] = EL_AMOEBA_WET;
+
+      ResetRandomAnimationValue(x, y);
     }
     return;
   }
 
-  if (!lastline && object_hit)         /* check which object was hit */
+  if (object_hit)              /* check which object was hit */
   {
-    if (CAN_CHANGE(element) && 
-       (smashed == EL_MAGIC_WALL_OFF || smashed == EL_MAGIC_WALL_BD_OFF))
+    if (CAN_PASS_MAGIC_WALL(element) && 
+       (smashed == EL_MAGIC_WALL ||
+        smashed == EL_BD_MAGIC_WALL))
     {
       int xx, yy;
       int activated_magic_wall =
-       (smashed == EL_MAGIC_WALL_OFF ? EL_MAGIC_WALL_EMPTY :
-        EL_MAGIC_WALL_BD_EMPTY);
+       (smashed == EL_MAGIC_WALL ? EL_MAGIC_WALL_ACTIVE :
+        EL_BD_MAGIC_WALL_ACTIVE);
 
       /* activate magic wall / mill */
       for (yy=0; yy<lev_fieldy; yy++)
@@ -2109,109 +2755,135 @@ void Impact(int x, int y)
       game.magic_wall_time_left = level.time_magic_wall * FRAMES_PER_SECOND;
       game.magic_wall_active = TRUE;
 
-      PlaySoundLevel(x, y, (smashed == EL_MAGIC_WALL_OFF ?
+      PlaySoundLevel(x, y, (smashed == EL_MAGIC_WALL ?
                            SND_MAGIC_WALL_ACTIVATING :
                            SND_BD_MAGIC_WALL_ACTIVATING));
     }
 
-    if (IS_PLAYER(x, y+1))
+    if (IS_PLAYER(x, y + 1))
     {
-      KillHeroUnlessProtected(x, y+1);
-      return;
+      if (CAN_SMASH_PLAYER(element))
+      {
+       KillHeroUnlessProtected(x, y + 1);
+       return;
+      }
     }
-    else if (smashed == EL_PINGUIN)
+    else if (smashed == EL_PENGUIN)
     {
-      Bang(x, y+1);
-      return;
+      if (CAN_SMASH_PLAYER(element))
+      {
+       Bang(x, y + 1);
+       return;
+      }
     }
-    else if (element == EL_EDELSTEIN_BD)
+    else if (element == EL_BD_DIAMOND)
     {
-      if (IS_ENEMY(smashed) && IS_BD_ELEMENT(smashed))
+      if (IS_CLASSIC_ENEMY(smashed) && IS_BD_ELEMENT(smashed))
       {
-       Bang(x, y+1);
+       Bang(x, y + 1);
        return;
       }
     }
-    else if ((element == EL_SP_INFOTRON || element == EL_SP_ZONK) &&
-            (smashed == EL_SP_SNIKSNAK || smashed == EL_SP_ELECTRON ||
+    else if ((element == EL_SP_INFOTRON ||
+             element == EL_SP_ZONK) &&
+            (smashed == EL_SP_SNIKSNAK ||
+             smashed == EL_SP_ELECTRON ||
              smashed == EL_SP_DISK_ORANGE))
     {
-      Bang(x, y+1);
+      Bang(x, y + 1);
       return;
     }
-    else if (element == EL_FELSBROCKEN ||
-            element == EL_SP_ZONK ||
-            element == EL_BD_ROCK)
+#if 0
+    else if (CAN_SMASH_ENEMIES(element) && IS_CLASSIC_ENEMY(smashed))
+    {
+      Bang(x, y + 1);
+      return;
+    }
+#endif
+    else if (CAN_SMASH_EVERYTHING(element))
     {
-      if (IS_ENEMY(smashed) ||
-         smashed == EL_BOMBE || smashed == EL_SP_DISK_ORANGE ||
-         smashed == EL_DX_SUPABOMB ||
-         smashed == EL_SONDE || smashed == EL_SCHWEIN ||
-         smashed == EL_DRACHE || smashed == EL_MOLE)
+      if (IS_CLASSIC_ENEMY(smashed) ||
+         CAN_EXPLODE_SMASHED(smashed))
       {
-       Bang(x, y+1);
+       Bang(x, y + 1);
        return;
       }
-      else if (!IS_MOVING(x, y+1))
+      else if (!IS_MOVING(x, y + 1) && !IS_BLOCKED(x, y + 1))
       {
-       if (smashed == EL_BIRNE_AUS || smashed == EL_BIRNE_EIN)
+       if (smashed == EL_LAMP ||
+           smashed == EL_LAMP_ACTIVE)
        {
-         Bang(x, y+1);
+         Bang(x, y + 1);
          return;
        }
-       else if (smashed == EL_KOKOSNUSS)
+       else if (smashed == EL_NUT)
        {
-         Feld[x][y+1] = EL_CRACKINGNUT;
-         PlaySoundLevel(x, y, SND_NUT_CRACKING);
-         RaiseScoreElement(EL_KOKOSNUSS);
+         Feld[x][y + 1] = EL_NUT_BREAKING;
+         PlaySoundLevel(x, y, SND_NUT_BREAKING);
+         RaiseScoreElement(EL_NUT);
          return;
        }
        else if (smashed == EL_PEARL)
        {
-         Feld[x][y+1] = EL_PEARL_BREAKING;
+         Feld[x][y + 1] = EL_PEARL_BREAKING;
          PlaySoundLevel(x, y, SND_PEARL_BREAKING);
          return;
        }
-       else if (smashed == EL_DIAMANT)
+       else if (smashed == EL_DIAMOND)
        {
-         Feld[x][y+1] = EL_LEERRAUM;
+         Feld[x][y + 1] = EL_DIAMOND_BREAKING;
          PlaySoundLevel(x, y, SND_DIAMOND_BREAKING);
          return;
        }
        else if (IS_BELT_SWITCH(smashed))
        {
-         ToggleBeltSwitch(x, y+1);
+         ToggleBeltSwitch(x, y + 1);
+       }
+       else if (smashed == EL_SWITCHGATE_SWITCH_UP ||
+                smashed == EL_SWITCHGATE_SWITCH_DOWN)
+       {
+         ToggleSwitchgateSwitch(x, y + 1);
+       }
+       else if (smashed == EL_LIGHT_SWITCH ||
+                smashed == EL_LIGHT_SWITCH_ACTIVE)
+       {
+         ToggleLightSwitch(x, y + 1);
        }
-       else if (smashed == EL_SWITCHGATE_SWITCH_1 ||
-                smashed == EL_SWITCHGATE_SWITCH_2)
+#if 1
+       else
        {
-         ToggleSwitchgateSwitch(x, y+1);
+         CheckElementChange(x, y + 1, smashed, CE_SMASHED);
        }
-       else if (smashed == EL_LIGHT_SWITCH_OFF ||
-                smashed == EL_LIGHT_SWITCH_ON)
+#else
+       else if (CAN_CHANGE(smashed) && HAS_CHANGE_EVENT(smashed, CE_SMASHED))
        {
-         ToggleLightSwitch(x, y+1);
+         ChangeElementNow(x, y + 1, smashed);
        }
+#endif
+      }
+      else
+      {
+       CheckElementChange(x, y + 1, smashed, CE_SMASHED);
       }
     }
   }
 
   /* play sound of magic wall / mill */
   if (!lastline &&
-      (Feld[x][y+1] == EL_MAGIC_WALL_EMPTY ||
-       Feld[x][y+1] == EL_MAGIC_WALL_BD_EMPTY))
+      (Feld[x][y + 1] == EL_MAGIC_WALL_ACTIVE ||
+       Feld[x][y + 1] == EL_BD_MAGIC_WALL_ACTIVE))
   {
-    if (Feld[x][y+1] == EL_MAGIC_WALL_EMPTY)
-      PlaySoundLevel(x, y, SND_MAGIC_WALL_CHANGING);
-    else if (Feld[x][y+1] == EL_MAGIC_WALL_BD_EMPTY)
-      PlaySoundLevel(x, y, SND_BD_MAGIC_WALL_CHANGING);
+    if (Feld[x][y + 1] == EL_MAGIC_WALL_ACTIVE)
+      PlaySoundLevel(x, y, SND_MAGIC_WALL_FILLING);
+    else if (Feld[x][y + 1] == EL_BD_MAGIC_WALL_ACTIVE)
+      PlaySoundLevel(x, y, SND_BD_MAGIC_WALL_FILLING);
 
     return;
   }
 
   /* play sound of object that hits the ground */
   if (lastline || object_hit)
-    PlaySoundLevelElementAction(x, y, element, SND_ACTION_IMPACT);
+    PlaySoundLevelElementAction(x, y, element, ACTION_IMPACT);
 }
 
 void TurnRound(int x, int y)
@@ -2221,90 +2893,83 @@ void TurnRound(int x, int y)
     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 = Feld[x][y];
   int old_move_dir = MovDir[x][y];
-  int left_dir = turn[old_move_dir].left;
+  int left_dir  = turn[old_move_dir].left;
   int right_dir = turn[old_move_dir].right;
-  int back_dir = turn[old_move_dir].back;
+  int back_dir  = turn[old_move_dir].back;
 
-  int left_dx = move_xy[left_dir].x, left_dy = move_xy[left_dir].y;
-  int right_dx = move_xy[right_dir].x, right_dy = move_xy[right_dir].y;
-  int move_dx = move_xy[old_move_dir].x, move_dy = move_xy[old_move_dir].y;
-  int back_dx = move_xy[back_dir].x, back_dy = move_xy[back_dir].y;
+  int left_dx  = move_xy[left_dir].x,     left_dy  = move_xy[left_dir].y;
+  int right_dx = move_xy[right_dir].x,    right_dy = move_xy[right_dir].y;
+  int move_dx  = move_xy[old_move_dir].x, move_dy  = move_xy[old_move_dir].y;
+  int back_dx  = move_xy[back_dir].x,     back_dy  = move_xy[back_dir].y;
 
-  int left_x = x+left_dx, left_y = y+left_dy;
-  int right_x = x+right_dx, right_y = y+right_dy;
-  int move_x = x+move_dx, move_y = y+move_dy;
+  int left_x  = x + left_dx,  left_y  = y + left_dy;
+  int right_x = x + right_dx, right_y = y + right_dy;
+  int move_x  = x + move_dx,  move_y  = y + move_dy;
 
-  if (element == EL_KAEFER || element == EL_BUTTERFLY)
+  int xx, yy;
+
+  if (element == EL_BUG || element == EL_BD_BUTTERFLY)
   {
     TestIfBadThingTouchesOtherBadThing(x, y);
 
-    if (IN_LEV_FIELD(right_x, right_y) &&
-       IS_FREE(right_x, right_y))
+    if (ENEMY_CAN_ENTER_FIELD(right_x, right_y))
       MovDir[x][y] = right_dir;
-    else if (!IN_LEV_FIELD(move_x, move_y) ||
-            !IS_FREE(move_x, move_y))
+    else if (!ENEMY_CAN_ENTER_FIELD(move_x, move_y))
       MovDir[x][y] = left_dir;
 
-    if (element == EL_KAEFER && MovDir[x][y] != old_move_dir)
+    if (element == EL_BUG && MovDir[x][y] != old_move_dir)
       MovDelay[x][y] = 9;
-    else if (element == EL_BUTTERFLY)  /* && MovDir[x][y] == left_dir) */
+    else if (element == EL_BD_BUTTERFLY)     /* && MovDir[x][y] == left_dir) */
       MovDelay[x][y] = 1;
   }
-  else if (element == EL_FLIEGER || element == EL_FIREFLY ||
+  else if (element == EL_SPACESHIP || element == EL_BD_FIREFLY ||
           element == EL_SP_SNIKSNAK || element == EL_SP_ELECTRON)
   {
     TestIfBadThingTouchesOtherBadThing(x, y);
 
-    if (IN_LEV_FIELD(left_x, left_y) &&
-       IS_FREE(left_x, left_y))
+    if (ENEMY_CAN_ENTER_FIELD(left_x, left_y))
       MovDir[x][y] = left_dir;
-    else if (!IN_LEV_FIELD(move_x, move_y) ||
-            !IS_FREE(move_x, move_y))
+    else if (!ENEMY_CAN_ENTER_FIELD(move_x, move_y))
       MovDir[x][y] = right_dir;
 
-    if ((element == EL_FLIEGER ||
-        element == EL_SP_SNIKSNAK || element == EL_SP_ELECTRON)
+    if ((element == EL_SPACESHIP ||
+        element == EL_SP_SNIKSNAK ||
+        element == EL_SP_ELECTRON)
        && MovDir[x][y] != old_move_dir)
       MovDelay[x][y] = 9;
-    else if (element == EL_FIREFLY)    /* && MovDir[x][y] == right_dir) */
+    else if (element == EL_BD_FIREFLY)     /* && MovDir[x][y] == right_dir) */
       MovDelay[x][y] = 1;
   }
-  else if (element == EL_MAMPFER)
+  else if (element == EL_YAMYAM)
   {
-    boolean can_turn_left = FALSE, can_turn_right = FALSE;
-
-    if (IN_LEV_FIELD(left_x, left_y) &&
-       (IS_FREE_OR_PLAYER(left_x, left_y) ||
-        Feld[left_x][left_y] == EL_DIAMANT))
-      can_turn_left = TRUE;
-    if (IN_LEV_FIELD(right_x, right_y) &&
-       (IS_FREE_OR_PLAYER(right_x, right_y) ||
-        Feld[right_x][right_y] == EL_DIAMANT))
-      can_turn_right = TRUE;
+    boolean can_turn_left  = YAMYAM_CAN_ENTER_FIELD(left_x, left_y);
+    boolean can_turn_right = YAMYAM_CAN_ENTER_FIELD(right_x, right_y);
 
     if (can_turn_left && can_turn_right)
       MovDir[x][y] = (RND(3) ? (RND(2) ? left_dir : right_dir) : back_dir);
@@ -2315,20 +2980,12 @@ void TurnRound(int x, int y)
     else
       MovDir[x][y] = back_dir;
 
-    MovDelay[x][y] = 16+16*RND(3);
+    MovDelay[x][y] = 16 + 16 * RND(3);
   }
-  else if (element == EL_MAMPFER2)
+  else if (element == EL_DARK_YAMYAM)
   {
-    boolean can_turn_left = FALSE, can_turn_right = FALSE;
-
-    if (IN_LEV_FIELD(left_x, left_y) &&
-       (IS_FREE_OR_PLAYER(left_x, left_y) ||
-        IS_MAMPF2(Feld[left_x][left_y])))
-      can_turn_left = TRUE;
-    if (IN_LEV_FIELD(right_x, right_y) &&
-       (IS_FREE_OR_PLAYER(right_x, right_y) ||
-        IS_MAMPF2(Feld[right_x][right_y])))
-      can_turn_right = TRUE;
+    boolean can_turn_left  = DARK_YAMYAM_CAN_ENTER_FIELD(left_x, left_y);
+    boolean can_turn_right = DARK_YAMYAM_CAN_ENTER_FIELD(right_x, right_y);
 
     if (can_turn_left && can_turn_right)
       MovDir[x][y] = (RND(3) ? (RND(2) ? left_dir : right_dir) : back_dir);
@@ -2339,20 +2996,12 @@ void TurnRound(int x, int y)
     else
       MovDir[x][y] = back_dir;
 
-    MovDelay[x][y] = 16+16*RND(3);
+    MovDelay[x][y] = 16 + 16 * RND(3);
   }
   else if (element == EL_PACMAN)
   {
-    boolean can_turn_left = FALSE, can_turn_right = FALSE;
-
-    if (IN_LEV_FIELD(left_x, left_y) &&
-       (IS_FREE_OR_PLAYER(left_x, left_y) ||
-        IS_AMOEBOID(Feld[left_x][left_y])))
-      can_turn_left = TRUE;
-    if (IN_LEV_FIELD(right_x, right_y) &&
-       (IS_FREE_OR_PLAYER(right_x, right_y) ||
-        IS_AMOEBOID(Feld[right_x][right_y])))
-      can_turn_right = TRUE;
+    boolean can_turn_left  = PACMAN_CAN_ENTER_FIELD(left_x, left_y);
+    boolean can_turn_right = PACMAN_CAN_ENTER_FIELD(right_x, right_y);
 
     if (can_turn_left && can_turn_right)
       MovDir[x][y] = (RND(3) ? (RND(2) ? left_dir : right_dir) : back_dir);
@@ -2363,56 +3012,45 @@ void TurnRound(int x, int y)
     else
       MovDir[x][y] = back_dir;
 
-    MovDelay[x][y] = 6+RND(40);
+    MovDelay[x][y] = 6 + RND(40);
   }
-  else if (element == EL_SCHWEIN)
+  else if (element == EL_PIG)
   {
-    boolean can_turn_left = FALSE, can_turn_right = FALSE, can_move_on = FALSE;
-    boolean should_turn_left = FALSE, should_turn_right = FALSE;
-    boolean should_move_on = FALSE;
+    boolean can_turn_left  = PIG_CAN_ENTER_FIELD(left_x, left_y);
+    boolean can_turn_right = PIG_CAN_ENTER_FIELD(right_x, right_y);
+    boolean can_move_on    = PIG_CAN_ENTER_FIELD(move_x, move_y);
+    boolean should_turn_left, should_turn_right, should_move_on;
     int rnd_value = 24;
     int rnd = RND(rnd_value);
 
-    if (IN_LEV_FIELD(left_x, left_y) &&
-       (IS_FREE(left_x, left_y) || IS_GEM(Feld[left_x][left_y])))
-      can_turn_left = TRUE;
-    if (IN_LEV_FIELD(right_x, right_y) &&
-       (IS_FREE(right_x, right_y) || IS_GEM(Feld[right_x][right_y])))
-      can_turn_right = TRUE;
-    if (IN_LEV_FIELD(move_x, move_y) &&
-       (IS_FREE(move_x, move_y) || IS_GEM(Feld[move_x][move_y])))
-      can_move_on = TRUE;
-
-    if (can_turn_left &&
-       (!can_move_on ||
-        (IN_LEV_FIELD(x+back_dx+left_dx, y+back_dy+left_dy) &&
-         !IS_FREE(x+back_dx+left_dx, y+back_dy+left_dy))))
-      should_turn_left = TRUE;
-    if (can_turn_right &&
-       (!can_move_on ||
-        (IN_LEV_FIELD(x+back_dx+right_dx, y+back_dy+right_dy) &&
-         !IS_FREE(x+back_dx+right_dx, y+back_dy+right_dy))))
-      should_turn_right = TRUE;
-    if (can_move_on &&
-       (!can_turn_left || !can_turn_right ||
-        (IN_LEV_FIELD(x+move_dx+left_dx, y+move_dy+left_dy) &&
-         !IS_FREE(x+move_dx+left_dx, y+move_dy+left_dy)) ||
-        (IN_LEV_FIELD(x+move_dx+right_dx, y+move_dy+right_dy) &&
-         !IS_FREE(x+move_dx+right_dx, y+move_dy+right_dy))))
-      should_move_on = TRUE;
+    should_turn_left = (can_turn_left &&
+                       (!can_move_on ||
+                        IN_LEV_FIELD_AND_NOT_FREE(x + back_dx + left_dx,
+                                                  y + back_dy + left_dy)));
+    should_turn_right = (can_turn_right &&
+                        (!can_move_on ||
+                         IN_LEV_FIELD_AND_NOT_FREE(x + back_dx + right_dx,
+                                                   y + back_dy + right_dy)));
+    should_move_on = (can_move_on &&
+                     (!can_turn_left ||
+                      !can_turn_right ||
+                      IN_LEV_FIELD_AND_NOT_FREE(x + move_dx + left_dx,
+                                                y + move_dy + left_dy) ||
+                      IN_LEV_FIELD_AND_NOT_FREE(x + move_dx + right_dx,
+                                                y + move_dy + right_dy)));
 
     if (should_turn_left || should_turn_right || should_move_on)
     {
       if (should_turn_left && should_turn_right && should_move_on)
-       MovDir[x][y] = (rnd < rnd_value/3 ? left_dir :
-                       rnd < 2*rnd_value/3 ? right_dir :
+       MovDir[x][y] = (rnd < rnd_value / 3     ? left_dir :
+                       rnd < 2 * rnd_value / 3 ? right_dir :
                        old_move_dir);
       else if (should_turn_left && should_turn_right)
-       MovDir[x][y] = (rnd < rnd_value/2 ? left_dir : right_dir);
+       MovDir[x][y] = (rnd < rnd_value / 2 ? left_dir : right_dir);
       else if (should_turn_left && should_move_on)
-       MovDir[x][y] = (rnd < rnd_value/2 ? left_dir : old_move_dir);
+       MovDir[x][y] = (rnd < rnd_value / 2 ? left_dir : old_move_dir);
       else if (should_turn_right && should_move_on)
-       MovDir[x][y] = (rnd < rnd_value/2 ? right_dir : old_move_dir);
+       MovDir[x][y] = (rnd < rnd_value / 2 ? right_dir : old_move_dir);
       else if (should_turn_left)
        MovDir[x][y] = left_dir;
       else if (should_turn_right)
@@ -2420,69 +3058,67 @@ void TurnRound(int x, int y)
       else if (should_move_on)
        MovDir[x][y] = old_move_dir;
     }
-    else if (can_move_on && rnd > rnd_value/8)
+    else if (can_move_on && rnd > rnd_value / 8)
       MovDir[x][y] = old_move_dir;
     else if (can_turn_left && can_turn_right)
-      MovDir[x][y] = (rnd < rnd_value/2 ? left_dir : right_dir);
-    else if (can_turn_left && rnd > rnd_value/8)
+      MovDir[x][y] = (rnd < rnd_value / 2 ? left_dir : right_dir);
+    else if (can_turn_left && rnd > rnd_value / 8)
       MovDir[x][y] = left_dir;
     else if (can_turn_right && rnd > rnd_value/8)
       MovDir[x][y] = right_dir;
     else
       MovDir[x][y] = back_dir;
 
-    if (!IS_FREE(x+move_xy[MovDir[x][y]].x, y+move_xy[MovDir[x][y]].y) &&
-       !IS_GEM(Feld[x+move_xy[MovDir[x][y]].x][y+move_xy[MovDir[x][y]].y]))
+    xx = x + move_xy[MovDir[x][y]].x;
+    yy = y + move_xy[MovDir[x][y]].y;
+
+    if (!IS_FREE(xx, yy) && !IS_FOOD_PIG(Feld[xx][yy]))
       MovDir[x][y] = old_move_dir;
 
     MovDelay[x][y] = 0;
   }
-  else if (element == EL_DRACHE)
+  else if (element == EL_DRAGON)
   {
-    boolean can_turn_left = FALSE, can_turn_right = FALSE, can_move_on = FALSE;
+    boolean can_turn_left  = IN_LEV_FIELD_AND_IS_FREE(left_x, left_y);
+    boolean can_turn_right = IN_LEV_FIELD_AND_IS_FREE(right_x, right_y);
+    boolean can_move_on    = IN_LEV_FIELD_AND_IS_FREE(move_x, move_y);
     int rnd_value = 24;
     int rnd = RND(rnd_value);
 
-    if (IN_LEV_FIELD(left_x, left_y) && IS_FREE(left_x, left_y))
-      can_turn_left = TRUE;
-    if (IN_LEV_FIELD(right_x, right_y) && IS_FREE(right_x, right_y))
-      can_turn_right = TRUE;
-    if (IN_LEV_FIELD(move_x, move_y) && IS_FREE(move_x, move_y))
-      can_move_on = TRUE;
-
-    if (can_move_on && rnd > rnd_value/8)
+    if (can_move_on && rnd > rnd_value / 8)
       MovDir[x][y] = old_move_dir;
     else if (can_turn_left && can_turn_right)
-      MovDir[x][y] = (rnd < rnd_value/2 ? left_dir : right_dir);
-    else if (can_turn_left && rnd > rnd_value/8)
+      MovDir[x][y] = (rnd < rnd_value / 2 ? left_dir : right_dir);
+    else if (can_turn_left && rnd > rnd_value / 8)
       MovDir[x][y] = left_dir;
-    else if (can_turn_right && rnd > rnd_value/8)
+    else if (can_turn_right && rnd > rnd_value / 8)
       MovDir[x][y] = right_dir;
     else
       MovDir[x][y] = back_dir;
 
-    if (!IS_FREE(x+move_xy[MovDir[x][y]].x, y+move_xy[MovDir[x][y]].y))
+    xx = x + move_xy[MovDir[x][y]].x;
+    yy = y + move_xy[MovDir[x][y]].y;
+
+    if (!IS_FREE(xx, yy))
       MovDir[x][y] = old_move_dir;
 
     MovDelay[x][y] = 0;
   }
   else if (element == EL_MOLE)
   {
-    boolean can_turn_left = FALSE, can_turn_right = FALSE, can_move_on = FALSE;
-
-    if (IN_LEV_FIELD(move_x, move_y) &&
-       (IS_FREE(move_x, move_y) || IS_AMOEBOID(Feld[move_x][move_y]) ||
-        Feld[move_x][move_y] == EL_DEAMOEBING))
-      can_move_on = TRUE;
-
+    boolean can_move_on =
+      (MOLE_CAN_ENTER_FIELD(move_x, move_y,
+                           IS_AMOEBOID(Feld[move_x][move_y]) ||
+                           Feld[move_x][move_y] == EL_AMOEBA_SHRINKING));
     if (!can_move_on)
     {
-      if (IN_LEV_FIELD(left_x, left_y) &&
-         (IS_FREE(left_x, left_y) || IS_AMOEBOID(Feld[left_x][left_y])))
-       can_turn_left = TRUE;
-      if (IN_LEV_FIELD(right_x, right_y) &&
-         (IS_FREE(right_x, right_y) || IS_AMOEBOID(Feld[right_x][right_y])))
-       can_turn_right = TRUE;
+      boolean can_turn_left =
+       (MOLE_CAN_ENTER_FIELD(left_x, left_y,
+                             IS_AMOEBOID(Feld[left_x][left_y])));
+
+      boolean can_turn_right =
+       (MOLE_CAN_ENTER_FIELD(right_x, right_y,
+                             IS_AMOEBOID(Feld[right_x][right_y])));
 
       if (can_turn_left && can_turn_right)
        MovDir[x][y] = (RND(2) ? left_dir : right_dir);
@@ -2500,17 +3136,18 @@ void TurnRound(int x, int y)
     MovDir[x][y] = game.balloon_dir;
     MovDelay[x][y] = 0;
   }
-  else if (element == EL_SPRING_MOVING)
+  else if (element == EL_SPRING)
   {
-    if (!IN_LEV_FIELD(move_x, move_y) || !IS_FREE(move_x, move_y) ||
-       (IN_LEV_FIELD(x, y+1) && IS_FREE(x, y+1)))
-    {
-      Feld[x][y] = EL_SPRING;
+    if (MovDir[x][y] & MV_HORIZONTAL &&
+       (!IN_LEV_FIELD_AND_IS_FREE(move_x, move_y) ||
+        IN_LEV_FIELD_AND_IS_FREE(x, y + 1)))
       MovDir[x][y] = MV_NO_MOVING;
-    }
+
     MovDelay[x][y] = 0;
   }
-  else if (element == EL_ROBOT || element == EL_SONDE || element == EL_PINGUIN)
+  else if (element == EL_ROBOT ||
+          element == EL_SATELLITE ||
+          element == EL_PENGUIN)
   {
     int attr_x = -1, attr_y = -1;
 
@@ -2531,7 +3168,8 @@ void TurnRound(int x, int y)
        if (!player->active)
          continue;
 
-       if (attr_x == -1 || ABS(jx-x)+ABS(jy-y) < ABS(attr_x-x)+ABS(attr_y-y))
+       if (attr_x == -1 ||
+           ABS(jx - x) + ABS(jy - y) < ABS(attr_x - x) + ABS(attr_y - y))
        {
          attr_x = jx;
          attr_y = jy;
@@ -2539,13 +3177,13 @@ void TurnRound(int x, int y)
       }
     }
 
-    if (element == EL_ROBOT && ZX>=0 && ZY>=0)
+    if (element == EL_ROBOT && ZX >= 0 && ZY >= 0)
     {
       attr_x = ZX;
       attr_y = ZY;
     }
 
-    if (element == EL_PINGUIN)
+    if (element == EL_PENGUIN)
     {
       int i;
       static int xy[4][2] =
@@ -2558,10 +3196,10 @@ void TurnRound(int x, int y)
 
       for (i=0; i<4; i++)
       {
-       int ex = x + xy[i%4][0];
-       int ey = y + xy[i%4][1];
+       int ex = x + xy[i % 4][0];
+       int ey = y + xy[i % 4][1];
 
-       if (IN_LEV_FIELD(ex, ey) && Feld[ex][ey] == EL_AUSGANG_AUF)
+       if (IN_LEV_FIELD(ex, ey) && Feld[ex][ey] == EL_EXIT_OPEN)
        {
          attr_x = ex;
          attr_y = ey;
@@ -2571,77 +3209,223 @@ void TurnRound(int x, int y)
     }
 
     MovDir[x][y] = MV_NO_MOVING;
-    if (attr_x<x)
+    if (attr_x < x)
       MovDir[x][y] |= (AllPlayersGone ? MV_RIGHT : MV_LEFT);
-    else if (attr_x>x)
+    else if (attr_x > x)
       MovDir[x][y] |= (AllPlayersGone ? MV_LEFT : MV_RIGHT);
-    if (attr_y<y)
+    if (attr_y < y)
       MovDir[x][y] |= (AllPlayersGone ? MV_DOWN : MV_UP);
-    else if (attr_y>y)
+    else if (attr_y > y)
       MovDir[x][y] |= (AllPlayersGone ? MV_UP : MV_DOWN);
 
     if (element == EL_ROBOT)
     {
       int newx, newy;
 
-      if ((MovDir[x][y]&(MV_LEFT|MV_RIGHT)) && (MovDir[x][y]&(MV_UP|MV_DOWN)))
-       MovDir[x][y] &= (RND(2) ? (MV_LEFT|MV_RIGHT) : (MV_UP|MV_DOWN));
+      if (MovDir[x][y] & MV_HORIZONTAL && MovDir[x][y] & MV_VERTICAL)
+       MovDir[x][y] &= (RND(2) ? MV_HORIZONTAL : MV_VERTICAL);
       Moving2Blocked(x, y, &newx, &newy);
 
       if (IN_LEV_FIELD(newx, newy) && IS_FREE_OR_PLAYER(newx, newy))
-       MovDelay[x][y] = 8+8*!RND(3);
+       MovDelay[x][y] = 8 + 8 * !RND(3);
       else
        MovDelay[x][y] = 16;
     }
-    else
+    else if (element == EL_PENGUIN)
     {
       int newx, newy;
 
       MovDelay[x][y] = 1;
 
-      if ((MovDir[x][y]&(MV_LEFT|MV_RIGHT)) && (MovDir[x][y]&(MV_UP|MV_DOWN)))
+      if (MovDir[x][y] & MV_HORIZONTAL && MovDir[x][y] & MV_VERTICAL)
       {
        boolean first_horiz = RND(2);
        int new_move_dir = MovDir[x][y];
 
        MovDir[x][y] =
-         new_move_dir & (first_horiz ? (MV_LEFT|MV_RIGHT) : (MV_UP|MV_DOWN));
+         new_move_dir & (first_horiz ? MV_HORIZONTAL : MV_VERTICAL);
        Moving2Blocked(x, y, &newx, &newy);
 
-       if (IN_LEV_FIELD(newx, newy) &&
-           (IS_FREE(newx, newy) ||
-            Feld[newx][newy] == EL_SALZSAEURE ||
-            (element == EL_PINGUIN &&
-             (Feld[newx][newy] == EL_AUSGANG_AUF ||
-              IS_MAMPF3(Feld[newx][newy])))))
+       if (PENGUIN_CAN_ENTER_FIELD(newx, newy))
          return;
 
        MovDir[x][y] =
-         new_move_dir & (!first_horiz ? (MV_LEFT|MV_RIGHT) : (MV_UP|MV_DOWN));
+         new_move_dir & (!first_horiz ? MV_HORIZONTAL : MV_VERTICAL);
        Moving2Blocked(x, y, &newx, &newy);
 
-       if (IN_LEV_FIELD(newx, newy) &&
-           (IS_FREE(newx, newy) ||
-            Feld[newx][newy] == EL_SALZSAEURE ||
-            (element == EL_PINGUIN &&
-             (Feld[newx][newy] == EL_AUSGANG_AUF ||
-              IS_MAMPF3(Feld[newx][newy])))))
+       if (PENGUIN_CAN_ENTER_FIELD(newx, newy))
          return;
 
        MovDir[x][y] = old_move_dir;
        return;
       }
     }
-  }
-}
-
-static boolean JustBeingPushed(int x, int y)
-{
-  int i;
+    else       /* (element == EL_SATELLITE) */
+    {
+      int newx, newy;
 
-  for (i=0; i<MAX_PLAYERS; i++)
-  {
-    struct PlayerInfo *player = &stored_player[i];
+      MovDelay[x][y] = 1;
+
+      if (MovDir[x][y] & MV_HORIZONTAL && MovDir[x][y] & MV_VERTICAL)
+      {
+       boolean first_horiz = RND(2);
+       int new_move_dir = MovDir[x][y];
+
+       MovDir[x][y] =
+         new_move_dir & (first_horiz ? MV_HORIZONTAL : MV_VERTICAL);
+       Moving2Blocked(x, y, &newx, &newy);
+
+       if (ELEMENT_CAN_ENTER_FIELD_OR_ACID_2(newx, newy))
+         return;
+
+       MovDir[x][y] =
+         new_move_dir & (!first_horiz ? MV_HORIZONTAL : MV_VERTICAL);
+       Moving2Blocked(x, y, &newx, &newy);
+
+       if (ELEMENT_CAN_ENTER_FIELD_OR_ACID_2(newx, newy))
+         return;
+
+       MovDir[x][y] = old_move_dir;
+       return;
+      }
+    }
+  }
+  else if (element_info[element].move_pattern == MV_ALL_DIRECTIONS ||
+          element_info[element].move_pattern == MV_TURNING_LEFT ||
+          element_info[element].move_pattern == MV_TURNING_RIGHT)
+  {
+    boolean can_turn_left  = ELEMENT_CAN_ENTER_FIELD(element, left_x, left_y);
+    boolean can_turn_right = ELEMENT_CAN_ENTER_FIELD(element, right_x,right_y);
+
+    if (element_info[element].move_pattern == MV_TURNING_LEFT)
+      MovDir[x][y] = left_dir;
+    else if (element_info[element].move_pattern == MV_TURNING_RIGHT)
+      MovDir[x][y] = right_dir;
+    else if (can_turn_left && can_turn_right)
+      MovDir[x][y] = (RND(3) ? (RND(2) ? left_dir : right_dir) : back_dir);
+    else if (can_turn_left)
+      MovDir[x][y] = (RND(2) ? left_dir : back_dir);
+    else if (can_turn_right)
+      MovDir[x][y] = (RND(2) ? right_dir : back_dir);
+    else
+      MovDir[x][y] = back_dir;
+
+    MovDelay[x][y] = GET_NEW_MOVE_DELAY(element);
+  }
+  else if (element_info[element].move_pattern == MV_HORIZONTAL ||
+          element_info[element].move_pattern == MV_VERTICAL)
+  {
+    if (element_info[element].move_pattern & old_move_dir)
+      MovDir[x][y] = back_dir;
+    else if (element_info[element].move_pattern == MV_HORIZONTAL)
+      MovDir[x][y] = (RND(2) ? MV_LEFT : MV_RIGHT);
+    else if (element_info[element].move_pattern == MV_VERTICAL)
+      MovDir[x][y] = (RND(2) ? MV_UP : MV_DOWN);
+
+    MovDelay[x][y] = GET_NEW_MOVE_DELAY(element);
+  }
+  else if (element_info[element].move_pattern & MV_ANY_DIRECTION)
+  {
+    MovDir[x][y] = element_info[element].move_pattern;
+    MovDelay[x][y] = GET_NEW_MOVE_DELAY(element);
+  }
+  else if (element_info[element].move_pattern == MV_ALONG_LEFT_SIDE)
+  {
+    if (ELEMENT_CAN_ENTER_FIELD(element, left_x, left_y))
+      MovDir[x][y] = left_dir;
+    else if (!ELEMENT_CAN_ENTER_FIELD(element, move_x, move_y))
+      MovDir[x][y] = right_dir;
+
+    if (MovDir[x][y] != old_move_dir)
+      MovDelay[x][y] = GET_NEW_MOVE_DELAY(element);
+  }
+  else if (element_info[element].move_pattern == MV_ALONG_RIGHT_SIDE)
+  {
+    if (ELEMENT_CAN_ENTER_FIELD(element, right_x, right_y))
+      MovDir[x][y] = right_dir;
+    else if (!ELEMENT_CAN_ENTER_FIELD(element, move_x, move_y))
+      MovDir[x][y] = left_dir;
+
+    if (MovDir[x][y] != old_move_dir)
+      MovDelay[x][y] = GET_NEW_MOVE_DELAY(element);
+  }
+  else if (element_info[element].move_pattern == MV_TOWARDS_PLAYER ||
+          element_info[element].move_pattern == MV_AWAY_FROM_PLAYER)
+  {
+    int attr_x = -1, attr_y = -1;
+    int newx, newy;
+    boolean move_away =
+      (element_info[element].move_pattern == MV_AWAY_FROM_PLAYER);
+
+    if (AllPlayersGone)
+    {
+      attr_x = ExitX;
+      attr_y = ExitY;
+    }
+    else
+    {
+      int i;
+
+      for (i=0; i<MAX_PLAYERS; i++)
+      {
+       struct PlayerInfo *player = &stored_player[i];
+       int jx = player->jx, jy = player->jy;
+
+       if (!player->active)
+         continue;
+
+       if (attr_x == -1 ||
+           ABS(jx - x) + ABS(jy - y) < ABS(attr_x - x) + ABS(attr_y - y))
+       {
+         attr_x = jx;
+         attr_y = jy;
+       }
+      }
+    }
+
+    MovDir[x][y] = MV_NO_MOVING;
+    if (attr_x < x)
+      MovDir[x][y] |= (move_away ? MV_RIGHT : MV_LEFT);
+    else if (attr_x > x)
+      MovDir[x][y] |= (move_away ? MV_LEFT : MV_RIGHT);
+    if (attr_y < y)
+      MovDir[x][y] |= (move_away ? MV_DOWN : MV_UP);
+    else if (attr_y > y)
+      MovDir[x][y] |= (move_away ? MV_UP : MV_DOWN);
+
+    MovDelay[x][y] = GET_NEW_MOVE_DELAY(element);
+
+    if (MovDir[x][y] & MV_HORIZONTAL && MovDir[x][y] & MV_VERTICAL)
+    {
+      boolean first_horiz = RND(2);
+      int new_move_dir = MovDir[x][y];
+
+      MovDir[x][y] =
+       new_move_dir & (first_horiz ? MV_HORIZONTAL : MV_VERTICAL);
+      Moving2Blocked(x, y, &newx, &newy);
+
+      if (ELEMENT_CAN_ENTER_FIELD_OR_ACID(element, newx, newy))
+       return;
+
+      MovDir[x][y] =
+       new_move_dir & (!first_horiz ? MV_HORIZONTAL : MV_VERTICAL);
+      Moving2Blocked(x, y, &newx, &newy);
+
+      if (ELEMENT_CAN_ENTER_FIELD_OR_ACID(element, newx, newy))
+       return;
+
+      MovDir[x][y] = old_move_dir;
+    }
+  }
+}
+
+static boolean JustBeingPushed(int x, int y)
+{
+  int i;
+
+  for (i=0; i<MAX_PLAYERS; i++)
+  {
+    struct PlayerInfo *player = &stored_player[i];
 
     if (player->active && player->Pushing && player->MovPos)
     {
@@ -2658,27 +3442,39 @@ static boolean JustBeingPushed(int x, int y)
 
 void StartMoving(int x, int y)
 {
+  boolean use_spring_bug = (game.engine_version < VERSION_IDENT(2,2,0));
+  boolean started_moving = FALSE;      /* some elements can fall _and_ move */
   int element = Feld[x][y];
 
   if (Stop[x][y])
     return;
 
-  if (CAN_FALL(element) && y<lev_fieldy-1)
+  /* !!! this should be handled more generic (not only for mole) !!! */
+  if (element != EL_MOLE && GfxAction[x][y] != ACTION_DIGGING)
+    GfxAction[x][y] = ACTION_DEFAULT;
+
+  if (CAN_FALL(element) && y < lev_fieldy - 1)
   {
     if ((x>0 && IS_PLAYER(x-1, y)) || (x<lev_fieldx-1 && IS_PLAYER(x+1, y)))
       if (JustBeingPushed(x, y))
        return;
 
-    if (element == EL_MORAST_VOLL)
+    if (element == EL_QUICKSAND_FULL)
     {
-      if (IS_FREE(x, y+1))
+      if (IS_FREE(x, y + 1))
       {
        InitMovingField(x, y, MV_DOWN);
+       started_moving = TRUE;
+
        Feld[x][y] = EL_QUICKSAND_EMPTYING;
-       Store[x][y] = EL_FELSBROCKEN;
+       Store[x][y] = EL_ROCK;
+#if 1
+       PlaySoundLevelAction(x, y, ACTION_EMPTYING);
+#else
        PlaySoundLevel(x, y, SND_QUICKSAND_EMPTYING);
+#endif
       }
-      else if (Feld[x][y+1] == EL_MORAST_LEER)
+      else if (Feld[x][y + 1] == EL_QUICKSAND_EMPTY)
       {
        if (!MovDelay[x][y])
          MovDelay[x][y] = TILEY + 1;
@@ -2690,30 +3486,42 @@ void StartMoving(int x, int y)
            return;
        }
 
-       Feld[x][y] = EL_MORAST_LEER;
-       Feld[x][y+1] = EL_MORAST_VOLL;
-       Store[x][y+1] = Store[x][y];
+       Feld[x][y] = EL_QUICKSAND_EMPTY;
+       Feld[x][y + 1] = EL_QUICKSAND_FULL;
+       Store[x][y + 1] = Store[x][y];
        Store[x][y] = 0;
-       PlaySoundLevel(x, y, SND_QUICKSAND_SLIPPING_THROUGH);
+#if 1
+       PlaySoundLevelAction(x, y, ACTION_FILLING);
+#else
+       PlaySoundLevel(x, y, SND_QUICKSAND_FILLING);
+#endif
       }
     }
-    else if ((element == EL_FELSBROCKEN || element == EL_BD_ROCK) &&
-            Feld[x][y+1] == EL_MORAST_LEER)
+    else if ((element == EL_ROCK || element == EL_BD_ROCK) &&
+            Feld[x][y + 1] == EL_QUICKSAND_EMPTY)
     {
       InitMovingField(x, y, MV_DOWN);
+      started_moving = TRUE;
+
       Feld[x][y] = EL_QUICKSAND_FILLING;
       Store[x][y] = element;
+#if 1
+      PlaySoundLevelAction(x, y, ACTION_FILLING);
+#else
       PlaySoundLevel(x, y, SND_QUICKSAND_FILLING);
+#endif
     }
     else if (element == EL_MAGIC_WALL_FULL)
     {
-      if (IS_FREE(x, y+1))
+      if (IS_FREE(x, y + 1))
       {
        InitMovingField(x, y, MV_DOWN);
+       started_moving = TRUE;
+
        Feld[x][y] = EL_MAGIC_WALL_EMPTYING;
        Store[x][y] = EL_CHANGED(Store[x][y]);
       }
-      else if (Feld[x][y+1] == EL_MAGIC_WALL_EMPTY)
+      else if (Feld[x][y + 1] == EL_MAGIC_WALL_ACTIVE)
       {
        if (!MovDelay[x][y])
          MovDelay[x][y] = TILEY/4 + 1;
@@ -2725,21 +3533,23 @@ void StartMoving(int x, int y)
            return;
        }
 
-       Feld[x][y] = EL_MAGIC_WALL_EMPTY;
-       Feld[x][y+1] = EL_MAGIC_WALL_FULL;
-       Store[x][y+1] = EL_CHANGED(Store[x][y]);
+       Feld[x][y] = EL_MAGIC_WALL_ACTIVE;
+       Feld[x][y + 1] = EL_MAGIC_WALL_FULL;
+       Store[x][y + 1] = EL_CHANGED(Store[x][y]);
        Store[x][y] = 0;
       }
     }
-    else if (element == EL_MAGIC_WALL_BD_FULL)
+    else if (element == EL_BD_MAGIC_WALL_FULL)
     {
-      if (IS_FREE(x, y+1))
+      if (IS_FREE(x, y + 1))
       {
        InitMovingField(x, y, MV_DOWN);
-       Feld[x][y] = EL_MAGIC_WALL_BD_EMPTYING;
+       started_moving = TRUE;
+
+       Feld[x][y] = EL_BD_MAGIC_WALL_EMPTYING;
        Store[x][y] = EL_CHANGED2(Store[x][y]);
       }
-      else if (Feld[x][y+1] == EL_MAGIC_WALL_BD_EMPTY)
+      else if (Feld[x][y + 1] == EL_BD_MAGIC_WALL_ACTIVE)
       {
        if (!MovDelay[x][y])
          MovDelay[x][y] = TILEY/4 + 1;
@@ -2751,107 +3561,196 @@ void StartMoving(int x, int y)
            return;
        }
 
-       Feld[x][y] = EL_MAGIC_WALL_BD_EMPTY;
-       Feld[x][y+1] = EL_MAGIC_WALL_BD_FULL;
-       Store[x][y+1] = EL_CHANGED2(Store[x][y]);
+       Feld[x][y] = EL_BD_MAGIC_WALL_ACTIVE;
+       Feld[x][y + 1] = EL_BD_MAGIC_WALL_FULL;
+       Store[x][y + 1] = EL_CHANGED2(Store[x][y]);
        Store[x][y] = 0;
       }
     }
-    else if (CAN_CHANGE(element) &&
-            (Feld[x][y+1] == EL_MAGIC_WALL_EMPTY ||
-             Feld[x][y+1] == EL_MAGIC_WALL_BD_EMPTY))
+    else if (CAN_PASS_MAGIC_WALL(element) &&
+            (Feld[x][y + 1] == EL_MAGIC_WALL_ACTIVE ||
+             Feld[x][y + 1] == EL_BD_MAGIC_WALL_ACTIVE))
     {
       InitMovingField(x, y, MV_DOWN);
+      started_moving = TRUE;
+
       Feld[x][y] =
-       (Feld[x][y+1] == EL_MAGIC_WALL_EMPTY ? EL_MAGIC_WALL_FILLING :
-        EL_MAGIC_WALL_BD_FILLING);
+       (Feld[x][y + 1] == EL_MAGIC_WALL_ACTIVE ? EL_MAGIC_WALL_FILLING :
+        EL_BD_MAGIC_WALL_FILLING);
       Store[x][y] = element;
     }
-    else if (CAN_SMASH(element) && Feld[x][y+1] == EL_SALZSAEURE)
+#if 0
+    else if (CAN_SMASH(element) && Feld[x][y + 1] == EL_ACID)
+#else
+    else if (CAN_FALL(element) && Feld[x][y + 1] == EL_ACID)
+#endif
     {
-      Blurb(x, y);
+      SplashAcid(x, y);
+
       InitMovingField(x, y, MV_DOWN);
-      Store[x][y] = EL_SALZSAEURE;
+      started_moving = TRUE;
+
+      Store[x][y] = EL_ACID;
+#if 0
+      /* !!! TEST !!! better use "_FALLING" etc. !!! */
+      GfxAction[x][y + 1] = ACTION_ACTIVE;
+#endif
     }
-    else if (CAN_SMASH(element) && Feld[x][y+1] == EL_BLOCKED &&
+#if 1
+#if 1
+    else if (game.engine_version < RELEASE_IDENT(2,2,0,7) &&
+            CAN_SMASH(element) && Feld[x][y + 1] == EL_BLOCKED &&
+            JustStopped[x][y] && !Pushed[x][y + 1])
+#else
+    else if (CAN_SMASH(element) && Feld[x][y + 1] == EL_BLOCKED &&
             JustStopped[x][y])
+#endif
     {
+      /* calling "Impact()" here is not only completely unneccessary
+        (because it already gets called from "ContinueMoving()" in
+        all relevant situations), but also completely bullshit, because
+        "JustStopped" also indicates a finished *horizontal* movement;
+        we must keep this trash for backwards compatibility with older
+        tapes */
+
       Impact(x, y);
     }
-    else if (IS_FREE(x, y+1))
+#endif
+    else if (IS_FREE(x, y + 1) && element == EL_SPRING && use_spring_bug)
+    {
+      if (MovDir[x][y] == MV_NO_MOVING)
+      {
+       InitMovingField(x, y, MV_DOWN);
+       started_moving = TRUE;
+      }
+    }
+    else if (IS_FREE(x, y + 1) || Feld[x][y + 1] == EL_DIAMOND_BREAKING)
     {
+      if (JustStopped[x][y])   /* prevent animation from being restarted */
+       MovDir[x][y] = MV_DOWN;
+
       InitMovingField(x, y, MV_DOWN);
+      started_moving = TRUE;
     }
-    else if (element == EL_TROPFEN)
+    else if (element == EL_AMOEBA_DROP)
     {
-      Feld[x][y] = EL_AMOEBING;
-      Store[x][y] = EL_AMOEBE_NASS;
+      Feld[x][y] = EL_AMOEBA_GROWING;
+      Store[x][y] = EL_AMOEBA_WET;
     }
-    /* Store[x][y+1] must be zero, because:
-       (EL_MORAST_VOLL -> EL_FELSBROCKEN): Store[x][y+1] == EL_MORAST_LEER
+    /* Store[x][y + 1] must be zero, because:
+       (EL_QUICKSAND_FULL -> EL_ROCK): Store[x][y + 1] == EL_QUICKSAND_EMPTY
     */
 #if 0
 #if OLD_GAME_BEHAVIOUR
-    else if (IS_SLIPPERY(Feld[x][y+1]) && !Store[x][y+1])
+    else if (IS_SLIPPERY(Feld[x][y + 1]) && !Store[x][y + 1])
 #else
-    else if (IS_SLIPPERY(Feld[x][y+1]) && !Store[x][y+1] &&
-            !IS_FALLING(x, y+1) && !JustStopped[x][y+1] &&
+    else if (IS_SLIPPERY(Feld[x][y + 1]) && !Store[x][y + 1] &&
+            !IS_FALLING(x, y + 1) && !JustStopped[x][y + 1] &&
             element != EL_DX_SUPABOMB)
 #endif
 #else
-    else if ((IS_SLIPPERY(Feld[x][y+1]) ||
-             (IS_EM_SLIPPERY_WALL(Feld[x][y+1]) && IS_GEM(element))) &&
-            !IS_FALLING(x, y+1) && !JustStopped[x][y+1] &&
+    else if (((IS_SLIPPERY(Feld[x][y + 1]) && !IS_PLAYER(x, y + 1)) ||
+             (IS_EM_SLIPPERY_WALL(Feld[x][y + 1]) && IS_GEM(element))) &&
+            !IS_FALLING(x, y + 1) && !JustStopped[x][y + 1] &&
             element != EL_DX_SUPABOMB && element != EL_SP_DISK_ORANGE)
 #endif
     {
-      boolean left  = (x>0 && IS_FREE(x-1, y) &&
-                      (IS_FREE(x-1, y+1) || Feld[x-1][y+1] == EL_SALZSAEURE));
-      boolean right = (x<lev_fieldx-1 && IS_FREE(x+1, y) &&
-                      (IS_FREE(x+1, y+1) || Feld[x+1][y+1] == EL_SALZSAEURE));
+      boolean can_fall_left  = (x > 0 && IS_FREE(x - 1, y) &&
+                               (IS_FREE(x - 1, y + 1) ||
+                                Feld[x - 1][y + 1] == EL_ACID));
+      boolean can_fall_right = (x < lev_fieldx - 1 && IS_FREE(x + 1, y) &&
+                               (IS_FREE(x + 1, y + 1) ||
+                                Feld[x + 1][y + 1] == EL_ACID));
+      boolean can_fall_any  = (can_fall_left || can_fall_right);
+      boolean can_fall_both = (can_fall_left && can_fall_right);
+
+      if (can_fall_any && IS_CUSTOM_ELEMENT(Feld[x][y + 1]))
+      {
+       int slippery_type = element_info[Feld[x][y + 1]].slippery_type;
+
+       if (slippery_type == SLIPPERY_ONLY_LEFT)
+         can_fall_right = FALSE;
+       else if (slippery_type == SLIPPERY_ONLY_RIGHT)
+         can_fall_left = FALSE;
+       else if (slippery_type == SLIPPERY_ANY_LEFT_RIGHT && can_fall_both)
+         can_fall_right = FALSE;
+       else if (slippery_type == SLIPPERY_ANY_RIGHT_LEFT && can_fall_both)
+         can_fall_left = FALSE;
+
+       can_fall_any  = (can_fall_left || can_fall_right);
+       can_fall_both = (can_fall_left && can_fall_right);
+      }
 
-      if (left || right)
+      if (can_fall_any)
       {
-       if (left && right &&
+       if (can_fall_both &&
            (game.emulation != EMU_BOULDERDASH &&
-            element != EL_BD_ROCK && element != EL_EDELSTEIN_BD))
-         left = !(right = RND(2));
+            element != EL_BD_ROCK && element != EL_BD_DIAMOND))
+         can_fall_left = !(can_fall_right = RND(2));
 
-       InitMovingField(x, y, left ? MV_LEFT : MV_RIGHT);
+       InitMovingField(x, y, can_fall_left ? MV_LEFT : MV_RIGHT);
+       started_moving = TRUE;
       }
     }
-    else if (IS_BELT(Feld[x][y+1]))
+    else if (IS_BELT_ACTIVE(Feld[x][y + 1]))
     {
-      boolean left_is_free  = (x>0 && IS_FREE(x-1, y));
-      boolean right_is_free = (x<lev_fieldx-1 && IS_FREE(x+1, y));
-      int belt_nr = getBeltNrFromElement(Feld[x][y+1]);
+      boolean left_is_free  = (x > 0 && IS_FREE(x - 1, y));
+      boolean right_is_free = (x < lev_fieldx - 1 && IS_FREE(x + 1, y));
+      int belt_nr = getBeltNrFromBeltActiveElement(Feld[x][y + 1]);
       int belt_dir = game.belt_dir[belt_nr];
 
       if ((belt_dir == MV_LEFT  && left_is_free) ||
          (belt_dir == MV_RIGHT && right_is_free))
+      {
        InitMovingField(x, y, belt_dir);
+       started_moving = TRUE;
+
+       GfxAction[x][y] = ACTION_DEFAULT;
+      }
     }
   }
-  else if (CAN_MOVE(element))
+
+  /* not "else if" because of elements that can fall and move (EL_SPRING) */
+  if (CAN_MOVE(element) && !started_moving)
   {
     int newx, newy;
 
-    if ((element == EL_SONDE || element == EL_BALLOON ||
-        element == EL_SPRING_MOVING)
+    if ((element == EL_SATELLITE ||
+        element == EL_BALLOON ||
+        element == EL_SPRING)
        && JustBeingPushed(x, y))
       return;
 
+#if 0
+#if 0
+    if (element == EL_SPRING && MovDir[x][y] == MV_DOWN)
+      Feld[x][y + 1] = EL_EMPTY;       /* was set to EL_BLOCKED above */
+#else
+    if (element == EL_SPRING && MovDir[x][y] != MV_NO_MOVING)
+    {
+      Moving2Blocked(x, y, &newx, &newy);
+      if (Feld[newx][newy] == EL_BLOCKED)
+       Feld[newx][newy] = EL_EMPTY;    /* was set to EL_BLOCKED above */
+    }
+#endif
+#endif
+
     if (!MovDelay[x][y])       /* start new movement phase */
     {
-      /* all objects that can change their move direction after each step */
-      /* (MAMPFER, MAMPFER2 and PACMAN go straight until they hit a wall  */
+      /* all objects that can change their move direction after each step
+        (YAMYAM, DARK_YAMYAM and PACMAN go straight until they hit a wall */
 
-      if (element!=EL_MAMPFER && element!=EL_MAMPFER2 && element!=EL_PACMAN)
+      if (element != EL_YAMYAM &&
+         element != EL_DARK_YAMYAM &&
+         element != EL_PACMAN &&
+         !(element_info[element].move_pattern & MV_ANY_DIRECTION) &&
+         element_info[element].move_pattern != MV_TURNING_LEFT &&
+         element_info[element].move_pattern != MV_TURNING_RIGHT)
       {
        TurnRound(x, y);
 
-       if (MovDelay[x][y] && (element == EL_KAEFER ||
-                              element == EL_FLIEGER ||
+       if (MovDelay[x][y] && (element == EL_BUG ||
+                              element == EL_SPACESHIP ||
                               element == EL_SP_SNIKSNAK ||
                               element == EL_SP_ELECTRON ||
                               element == EL_MOLE))
@@ -2863,65 +3762,78 @@ void StartMoving(int x, int y)
     {
       MovDelay[x][y]--;
 
-      if (element == EL_ROBOT ||
-         element == EL_MAMPFER || element == EL_MAMPFER2)
+#if 0
+      if (element == EL_YAMYAM)
       {
-       int phase = MovDelay[x][y] % 8;
-
-       if (phase > 3)
-         phase = 7 - phase;
+       printf("::: %d\n",
+              el_act_dir2img(EL_YAMYAM, ACTION_WAITING, MV_LEFT));
+       DrawLevelElementAnimation(x, y, element);
+      }
+#endif
 
-       if (IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
-         DrawGraphic(SCREENX(x), SCREENY(y), el2gfx(element) + phase);
+      if (MovDelay[x][y])      /* element still has to wait some time */
+      {
+#if 0
+       /* !!! PLACE THIS SOMEWHERE AFTER "TurnRound()" !!! */
+       ResetGfxAnimation(x, y);
+#endif
+       GfxAction[x][y] = ACTION_WAITING;
+      }
 
-       if (MovDelay[x][y] % 4 == 3)
-       {
-         if (element == EL_MAMPFER)
-           PlaySoundLevel(x, y, SND_YAMYAM_WAITING);
-         else if (element == EL_MAMPFER2)
-           PlaySoundLevel(x, y, SND_DARK_YAMYAM_WAITING);
-       }
+      if (element == EL_ROBOT ||
+#if 0
+         element == EL_PACMAN ||
+#endif
+         element == EL_YAMYAM ||
+         element == EL_DARK_YAMYAM)
+      {
+#if 0
+       DrawLevelElementAnimation(x, y, element);
+#else
+       DrawLevelElementAnimationIfNeeded(x, y, element);
+#endif
+       PlaySoundLevelAction(x, y, ACTION_WAITING);
       }
       else if (element == EL_SP_ELECTRON)
-       DrawGraphicAnimation(x, y, GFX2_SP_ELECTRON, 8, 2, ANIM_NORMAL);
-      else if (element == EL_DRACHE)
+       DrawLevelElementAnimationIfNeeded(x, y, element);
+      else if (element == EL_DRAGON)
       {
        int i;
        int dir = MovDir[x][y];
        int dx = (dir == MV_LEFT ? -1 : dir == MV_RIGHT ? +1 : 0);
        int dy = (dir == MV_UP   ? -1 : dir == MV_DOWN  ? +1 : 0);
-       int graphic = (dir == MV_LEFT   ? GFX_FLAMMEN_LEFT :
-                      dir == MV_RIGHT  ? GFX_FLAMMEN_RIGHT :
-                      dir == MV_UP     ? GFX_FLAMMEN_UP :
-                      dir == MV_DOWN   ? GFX_FLAMMEN_DOWN : GFX_LEERRAUM);
-       int phase = FrameCounter % 2;
+       int graphic = (dir == MV_LEFT   ? IMG_FLAMES_1_LEFT :
+                      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, -1);
 
        for (i=1; i<=3; i++)
        {
          int xx = x + i*dx, yy = y + i*dy;
          int sx = SCREENX(xx), sy = SCREENY(yy);
+         int flame_graphic = graphic + (i - 1);
 
-         if (!IN_LEV_FIELD(xx, yy) ||
-             IS_SOLID(Feld[xx][yy]) || Feld[xx][yy] == EL_EXPLODING)
+         if (!IN_LEV_FIELD(xx, yy) || IS_DRAGONFIRE_PROOF(Feld[xx][yy]))
            break;
 
          if (MovDelay[x][y])
          {
            int flamed = MovingOrBlocked2Element(xx, yy);
 
-           if (IS_ENEMY(flamed) || IS_EXPLOSIVE(flamed))
+           if (IS_CLASSIC_ENEMY(flamed) || CAN_EXPLODE_BY_FIRE(flamed))
              Bang(xx, yy);
            else
              RemoveMovingField(xx, yy);
 
-           Feld[xx][yy] = EL_BURNING;
+           Feld[xx][yy] = EL_FLAMES;
            if (IN_SCR_FIELD(sx, sy))
-             DrawGraphic(sx, sy, graphic + phase*3 + i-1);
+             DrawGraphic(sx, sy, flame_graphic, frame);
          }
          else
          {
-           if (Feld[xx][yy] == EL_BURNING)
-             Feld[xx][yy] = EL_LEERRAUM;
+           if (Feld[xx][yy] == EL_FLAMES)
+             Feld[xx][yy] = EL_EMPTY;
            DrawLevelField(xx, yy);
          }
        }
@@ -2929,49 +3841,56 @@ void StartMoving(int x, int y)
 
       if (MovDelay[x][y])      /* element still has to wait some time */
       {
-       PlaySoundLevelAction(x, y, SND_ACTION_WAITING);
+       PlaySoundLevelAction(x, y, ACTION_WAITING);
 
        return;
       }
+
+      /* special case of "moving" animation of waiting elements (FIX THIS !!!);
+        for all other elements GfxAction will be set by InitMovingField() */
+      if (element == EL_BD_BUTTERFLY || element == EL_BD_FIREFLY)
+       GfxAction[x][y] = ACTION_MOVING;
     }
 
     /* now make next step */
 
     Moving2Blocked(x, y, &newx, &newy);        /* get next screen position */
 
-    if (IS_ENEMY(element) && IS_PLAYER(newx, newy) &&
+    if (DONT_COLLIDE_WITH(element) && IS_PLAYER(newx, newy) &&
        !PLAYER_PROTECTED(newx, newy))
     {
-
 #if 1
       TestIfBadThingRunsIntoHero(x, y, MovDir[x][y]);
       return;
 #else
-      /* enemy got the player */
+      /* player killed by element which is deadly when colliding with */
       MovDir[x][y] = 0;
       KillHero(PLAYERINFO(newx, newy));
       return;
 #endif
 
     }
-    else if ((element == EL_PINGUIN || element == EL_ROBOT ||
-             element == EL_SONDE || element == EL_BALLOON) &&
+    else if ((element == EL_PENGUIN ||
+             element == EL_ROBOT ||
+             element == EL_SATELLITE ||
+             element == EL_BALLOON ||
+             IS_CUSTOM_ELEMENT(element)) &&
             IN_LEV_FIELD(newx, newy) &&
-            MovDir[x][y] == MV_DOWN && Feld[newx][newy] == EL_SALZSAEURE)
+            MovDir[x][y] == MV_DOWN && Feld[newx][newy] == EL_ACID)
     {
-      Blurb(x, y);
-      Store[x][y] = EL_SALZSAEURE;
+      SplashAcid(x, y);
+      Store[x][y] = EL_ACID;
     }
-    else if (element == EL_PINGUIN && IN_LEV_FIELD(newx, newy))
+    else if (element == EL_PENGUIN && IN_LEV_FIELD(newx, newy))
     {
-      if (Feld[newx][newy] == EL_AUSGANG_AUF)
+      if (Feld[newx][newy] == EL_EXIT_OPEN)
       {
-       Feld[x][y] = EL_LEERRAUM;
+       Feld[x][y] = EL_EMPTY;
        DrawLevelField(x, y);
 
-       PlaySoundLevel(newx, newy, SND_PENGUIN_ENTERING_EXIT);
+       PlaySoundLevel(newx, newy, SND_PENGUIN_PASSING);
        if (IN_SCR_FIELD(SCREENX(newx), SCREENY(newy)))
-         DrawGraphicThruMask(SCREENX(newx), SCREENY(newy), el2gfx(element));
+         DrawGraphicThruMask(SCREENX(newx),SCREENY(newy), el2img(element), 0);
 
        local_player->friends_still_needed--;
        if (!local_player->friends_still_needed &&
@@ -2980,7 +3899,7 @@ void StartMoving(int x, int y)
 
        return;
       }
-      else if (IS_MAMPF3(Feld[newx][newy]))
+      else if (IS_FOOD_PENGUIN(Feld[newx][newy]))
       {
        if (DigField(local_player, newx, newy, 0, 0, DF_DIG) == MF_MOVING)
          DrawLevelField(newx, newy);
@@ -2989,6 +3908,8 @@ void StartMoving(int x, int y)
       }
       else if (!IS_FREE(newx, newy))
       {
+       GfxAction[x][y] = ACTION_WAITING;
+
        if (IS_PLAYER(x, y))
          DrawPlayerField(x, y);
        else
@@ -2996,19 +3917,19 @@ void StartMoving(int x, int y)
        return;
       }
     }
-    else if (element == EL_SCHWEIN && IN_LEV_FIELD(newx, newy))
+    else if (element == EL_PIG && IN_LEV_FIELD(newx, newy))
     {
-      if (IS_GEM(Feld[newx][newy]))
+      if (IS_FOOD_PIG(Feld[newx][newy]))
       {
        if (IS_MOVING(newx, newy))
          RemoveMovingField(newx, newy);
        else
        {
-         Feld[newx][newy] = EL_LEERRAUM;
+         Feld[newx][newy] = EL_EMPTY;
          DrawLevelField(newx, newy);
        }
 
-       PlaySoundLevel(x, y, SND_PIG_EATING_GEM);
+       PlaySoundLevel(x, y, SND_PIG_DIGGING);
       }
       else if (!IS_FREE(newx, newy))
       {
@@ -3019,7 +3940,7 @@ void StartMoving(int x, int y)
        return;
       }
     }
-    else if (element == EL_DRACHE && IN_LEV_FIELD(newx, newy))
+    else if (element == EL_DRAGON && IN_LEV_FIELD(newx, newy))
     {
       if (!IS_FREE(newx, newy))
       {
@@ -3036,13 +3957,15 @@ void StartMoving(int x, int y)
        int newx1 = newx+1*dx, newy1 = newy+1*dy;
        int newx2 = newx+2*dx, newy2 = newy+2*dy;
        int element1 = (IN_LEV_FIELD(newx1, newy1) ?
-                       MovingOrBlocked2Element(newx1, newy1) : EL_BETON);
+                       MovingOrBlocked2Element(newx1, newy1) : EL_STEELWALL);
        int element2 = (IN_LEV_FIELD(newx2, newy2) ?
-                       MovingOrBlocked2Element(newx2, newy2) : EL_BETON);
+                       MovingOrBlocked2Element(newx2, newy2) : EL_STEELWALL);
 
-       if ((wanna_flame || IS_ENEMY(element1) || IS_ENEMY(element2)) &&
-           element1 != EL_DRACHE && element2 != EL_DRACHE &&
-           element1 != EL_BURNING && element2 != EL_BURNING)
+       if ((wanna_flame ||
+            IS_CLASSIC_ENEMY(element1) ||
+            IS_CLASSIC_ENEMY(element2)) &&
+           element1 != EL_DRAGON && element2 != EL_DRAGON &&
+           element1 != EL_FLAMES && element2 != EL_FLAMES)
        {
          if (IS_PLAYER(x, y))
            DrawPlayerField(x, y);
@@ -3052,36 +3975,36 @@ void StartMoving(int x, int y)
          PlaySoundLevel(x, y, SND_DRAGON_ATTACKING);
 
          MovDelay[x][y] = 50;
-         Feld[newx][newy] = EL_BURNING;
-         if (IN_LEV_FIELD(newx1, newy1) && Feld[newx1][newy1] == EL_LEERRAUM)
-           Feld[newx1][newy1] = EL_BURNING;
-         if (IN_LEV_FIELD(newx2, newy2) && Feld[newx2][newy2] == EL_LEERRAUM)
-           Feld[newx2][newy2] = EL_BURNING;
+         Feld[newx][newy] = EL_FLAMES;
+         if (IN_LEV_FIELD(newx1, newy1) && Feld[newx1][newy1] == EL_EMPTY)
+           Feld[newx1][newy1] = EL_FLAMES;
+         if (IN_LEV_FIELD(newx2, newy2) && Feld[newx2][newy2] == EL_EMPTY)
+           Feld[newx2][newy2] = EL_FLAMES;
          return;
        }
       }
     }
-    else if (element == EL_MAMPFER && IN_LEV_FIELD(newx, newy) &&
-            Feld[newx][newy] == EL_DIAMANT)
+    else if (element == EL_YAMYAM && IN_LEV_FIELD(newx, newy) &&
+            Feld[newx][newy] == EL_DIAMOND)
     {
       if (IS_MOVING(newx, newy))
        RemoveMovingField(newx, newy);
       else
       {
-       Feld[newx][newy] = EL_LEERRAUM;
+       Feld[newx][newy] = EL_EMPTY;
        DrawLevelField(newx, newy);
       }
 
-      PlaySoundLevel(x, y, SND_YAMYAM_EATING_DIAMOND);
+      PlaySoundLevel(x, y, SND_YAMYAM_DIGGING);
     }
-    else if (element == EL_MAMPFER2 && IN_LEV_FIELD(newx, newy) &&
-            IS_MAMPF2(Feld[newx][newy]))
+    else if (element == EL_DARK_YAMYAM && IN_LEV_FIELD(newx, newy) &&
+            IS_FOOD_DARK_YAMYAM(Feld[newx][newy]))
     {
       if (AmoebaNr[newx][newy])
       {
        AmoebaCnt2[AmoebaNr[newx][newy]]--;
-       if (Feld[newx][newy] == EL_AMOEBE_VOLL ||
-           Feld[newx][newy] == EL_AMOEBE_BD)
+       if (Feld[newx][newy] == EL_AMOEBA_FULL ||
+           Feld[newx][newy] == EL_BD_AMOEBA)
          AmoebaCnt[AmoebaNr[newx][newy]]--;
       }
 
@@ -3089,11 +4012,11 @@ void StartMoving(int x, int y)
        RemoveMovingField(newx, newy);
       else
       {
-       Feld[newx][newy] = EL_LEERRAUM;
+       Feld[newx][newy] = EL_EMPTY;
        DrawLevelField(newx, newy);
       }
 
-      PlaySoundLevel(x, y, SND_DARK_YAMYAM_EATING_ANY);
+      PlaySoundLevel(x, y, SND_DARK_YAMYAM_DIGGING);
     }
     else if ((element == EL_PACMAN || element == EL_MOLE)
             && IN_LEV_FIELD(newx, newy) && IS_AMOEBOID(Feld[newx][newy]))
@@ -3101,28 +4024,33 @@ void StartMoving(int x, int y)
       if (AmoebaNr[newx][newy])
       {
        AmoebaCnt2[AmoebaNr[newx][newy]]--;
-       if (Feld[newx][newy] == EL_AMOEBE_VOLL ||
-           Feld[newx][newy] == EL_AMOEBE_BD)
+       if (Feld[newx][newy] == EL_AMOEBA_FULL ||
+           Feld[newx][newy] == EL_BD_AMOEBA)
          AmoebaCnt[AmoebaNr[newx][newy]]--;
       }
 
       if (element == EL_MOLE)
       {
-       Feld[newx][newy] = EL_DEAMOEBING;
-       PlaySoundLevel(x, y, SND_MOLE_EATING_AMOEBA);
+       Feld[newx][newy] = EL_AMOEBA_SHRINKING;
+       PlaySoundLevel(x, y, SND_MOLE_DIGGING);
+
+       ResetGfxAnimation(x, y);
+       GfxAction[x][y] = ACTION_DIGGING;
+       DrawLevelField(x, y);
+
        MovDelay[newx][newy] = 0;       /* start amoeba shrinking delay */
        return;                         /* wait for shrinking amoeba */
       }
       else     /* element == EL_PACMAN */
       {
-       Feld[newx][newy] = EL_LEERRAUM;
+       Feld[newx][newy] = EL_EMPTY;
        DrawLevelField(newx, newy);
-       PlaySoundLevel(x, y, SND_PACMAN_EATING_AMOEBA);
+       PlaySoundLevel(x, y, SND_PACMAN_DIGGING);
       }
     }
     else if (element == EL_MOLE && IN_LEV_FIELD(newx, newy) &&
-            (Feld[newx][newy] == EL_DEAMOEBING ||
-             (Feld[newx][newy] == EL_LEERRAUM && Stop[newx][newy])))
+            (Feld[newx][newy] == EL_AMOEBA_SHRINKING ||
+             (Feld[newx][newy] == EL_EMPTY && Stop[newx][newy])))
     {
       /* wait for shrinking amoeba to completely disappear */
       return;
@@ -3133,27 +4061,38 @@ void StartMoving(int x, int y)
 
       TurnRound(x, y);
 
-      if (element == EL_KAEFER || element == EL_FLIEGER ||
-         element == EL_SP_SNIKSNAK || element == EL_MOLE)
+#if 1
+      if (GFX_ELEMENT(element) != EL_SAND)     /* !!! FIX THIS (crumble) !!! */
+       DrawLevelElementAnimation(x, y, element);
+#else
+      if (element == EL_BUG ||
+         element == EL_SPACESHIP ||
+         element == EL_SP_SNIKSNAK)
        DrawLevelField(x, y);
-      else if (element == EL_BUTTERFLY || element == EL_FIREFLY)
-       DrawGraphicAnimation(x, y, el2gfx(element), 2, 4, ANIM_NORMAL);
-      else if (element == EL_SONDE)
-       DrawGraphicAnimation(x, y, GFX_SONDE_START, 8, 2, ANIM_NORMAL);
+      else if (element == EL_MOLE)
+       DrawLevelField(x, y);
+      else if (element == EL_BD_BUTTERFLY ||
+              element == EL_BD_FIREFLY)
+       DrawLevelElementAnimationIfNeeded(x, y, element);
+      else if (element == EL_SATELLITE)
+       DrawLevelElementAnimationIfNeeded(x, y, element);
       else if (element == EL_SP_ELECTRON)
-       DrawGraphicAnimation(x, y, GFX2_SP_ELECTRON, 8, 2, ANIM_NORMAL);
+       DrawLevelElementAnimationIfNeeded(x, y, element);
+#endif
 
       if (DONT_TOUCH(element))
        TestIfBadThingTouchesHero(x, y);
 
-      PlaySoundLevelAction(x, y, SND_ACTION_WAITING);
+#if 0
+      PlaySoundLevelAction(x, y, ACTION_WAITING);
+#endif
 
       return;
     }
 
     InitMovingField(x, y, MovDir[x][y]);
 
-    PlaySoundLevelAction(x, y, SND_ACTION_MOVING);
+    PlaySoundLevelAction(x, y, ACTION_MOVING);
   }
 
   if (MovDir[x][y])
@@ -3166,65 +4105,28 @@ void ContinueMoving(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 newx = x + dx, newy = y + dy;
-  int step = (horiz_move ? dx : dy) * TILEX / 8;
-
-  if (element == EL_TROPFEN || element == EL_AMOEBA_DRIPPING)
-    step /= 2;
-  else if (element == EL_QUICKSAND_FILLING ||
-          element == EL_QUICKSAND_EMPTYING)
-    step /= 4;
-  else if (element == EL_MAGIC_WALL_FILLING ||
-          element == EL_MAGIC_WALL_BD_FILLING ||
-          element == EL_MAGIC_WALL_EMPTYING ||
-          element == EL_MAGIC_WALL_BD_EMPTYING)
-    step /= 2;
-  else if (CAN_FALL(element) && horiz_move &&
-          y < lev_fieldy-1 && IS_BELT(Feld[x][y+1]))
-    step /= 2;
-  else if (element == EL_SPRING_MOVING)
-    step*=2;
+  int nextx = newx + dx, nexty = newy + dy;
+  boolean pushed = Pushed[x][y];
 
-#if OLD_GAME_BEHAVIOUR
-  else if (CAN_FALL(element) && horiz_move && !IS_SP_ELEMENT(element))
-    step*=2;
-#endif
+  MovPos[x][y] += getElementMoveStepsize(x, y);
 
-  MovPos[x][y] += step;
+  if (pushed)          /* special case: moving object pushed by player */
+    MovPos[x][y] = SIGN(MovPos[x][y]) * (TILEX - ABS(PLAYERINFO(x,y)->MovPos));
 
   if (ABS(MovPos[x][y]) >= TILEX)      /* object reached its destination */
   {
-    Feld[x][y] = EL_LEERRAUM;
+    Feld[x][y] = EL_EMPTY;
     Feld[newx][newy] = element;
+    MovPos[x][y] = 0;  /* force "not moving" for "crumbled sand" */
 
     if (element == EL_MOLE)
     {
-      int i;
-      static int xy[4][2] =
-      {
-       { 0, -1 },
-       { -1, 0 },
-       { +1, 0 },
-       { 0, +1 }
-      };
-
-      Feld[x][y] = EL_ERDREICH;
-      DrawLevelField(x, y);
-
-      for(i=0; i<4; i++)
-      {
-       int xx, yy;
+      Feld[x][y] = EL_SAND;
 
-       xx = x + xy[i][0];
-       yy = y + xy[i][1];
-
-       if (IN_LEV_FIELD(xx, yy) && Feld[xx][yy] == EL_ERDREICH)
-         DrawLevelField(xx, yy);       /* for "ErdreichAnbroeckeln()" */
-      }
+      DrawLevelFieldCrumbledSandNeighbours(x, y);
     }
-
-    if (element == EL_QUICKSAND_FILLING)
+    else if (element == EL_QUICKSAND_FILLING)
     {
       element = Feld[newx][newy] = get_next_element(element);
       Store[newx][newy] = Store[x][y];
@@ -3248,42 +4150,86 @@ void ContinueMoving(int x, int y)
        Feld[x][y] = EL_MAGIC_WALL_DEAD;
       element = Feld[newx][newy] = Store[x][y];
     }
-    else if (element == EL_MAGIC_WALL_BD_FILLING)
+    else if (element == EL_BD_MAGIC_WALL_FILLING)
     {
       element = Feld[newx][newy] = get_next_element(element);
       if (!game.magic_wall_active)
-       element = Feld[newx][newy] = EL_MAGIC_WALL_BD_DEAD;
+       element = Feld[newx][newy] = EL_BD_MAGIC_WALL_DEAD;
       Store[newx][newy] = Store[x][y];
     }
-    else if (element == EL_MAGIC_WALL_BD_EMPTYING)
+    else if (element == EL_BD_MAGIC_WALL_EMPTYING)
     {
       Feld[x][y] = get_next_element(element);
       if (!game.magic_wall_active)
-       Feld[x][y] = EL_MAGIC_WALL_BD_DEAD;
+       Feld[x][y] = EL_BD_MAGIC_WALL_DEAD;
       element = Feld[newx][newy] = Store[x][y];
     }
-    else if (element == EL_AMOEBA_DRIPPING)
+    else if (element == EL_AMOEBA_DROPPING)
     {
       Feld[x][y] = get_next_element(element);
       element = Feld[newx][newy] = Store[x][y];
     }
-    else if (Store[x][y] == EL_SALZSAEURE)
+    else if (element == EL_SOKOBAN_OBJECT)
+    {
+      if (Back[x][y])
+       Feld[x][y] = Back[x][y];
+
+      if (Back[newx][newy])
+       Feld[newx][newy] = EL_SOKOBAN_FIELD_FULL;
+
+      Back[x][y] = Back[newx][newy] = 0;
+    }
+    else if (Store[x][y] == EL_ACID)
     {
-      element = Feld[newx][newy] = EL_SALZSAEURE;
+      element = Feld[newx][newy] = EL_ACID;
     }
 
     Store[x][y] = 0;
     MovPos[x][y] = MovDir[x][y] = MovDelay[x][y] = 0;
     MovDelay[newx][newy] = 0;
 
+    /* copy element change control values to new field */
+    ChangeDelay[newx][newy] = ChangeDelay[x][y];
+
+    /* copy animation control values to new field */
+    GfxFrame[newx][newy]  = GfxFrame[x][y];
+    GfxAction[newx][newy] = GfxAction[x][y];   /* keep action one frame */
+    GfxRandom[newx][newy] = GfxRandom[x][y];   /* keep same random value */
+
+    Pushed[x][y] = Pushed[newx][newy] = FALSE;
+
+    ResetGfxAnimation(x, y);   /* reset animation values for old field */
+
+#if 0
+    /* 2.1.1 (does not work correctly for spring) */
     if (!CAN_MOVE(element))
       MovDir[newx][newy] = 0;
+#else
+
+#if 0
+    /* (does not work for falling objects that slide horizontally) */
+    if (CAN_FALL(element) && MovDir[newx][newy] == MV_DOWN)
+      MovDir[newx][newy] = 0;
+#else
+    /*
+    if (!CAN_MOVE(element) ||
+       (element == EL_SPRING && MovDir[newx][newy] == MV_DOWN))
+      MovDir[newx][newy] = 0;
+    */
+
+    if (!CAN_MOVE(element) ||
+       (CAN_FALL(element) && MovDir[newx][newy] == MV_DOWN))
+      MovDir[newx][newy] = 0;
+#endif
+#endif
 
     DrawLevelField(x, y);
     DrawLevelField(newx, newy);
 
-    Stop[newx][newy] = TRUE;
-    JustStopped[newx][newy] = 3;
+    Stop[newx][newy] = TRUE;   /* ignore this element until the next frame */
+
+    if (!pushed)       /* special case: moving object pushed by player */
+      JustStopped[newx][newy] = 3;
 
     if (DONT_TOUCH(element))   /* object may be nasty to player or others */
     {
@@ -3291,15 +4237,23 @@ void ContinueMoving(int x, int y)
       TestIfBadThingTouchesFriend(newx, newy);
       TestIfBadThingTouchesOtherBadThing(newx, newy);
     }
-    else if (element == EL_PINGUIN)
+    else if (element == EL_PENGUIN)
       TestIfFriendTouchesBadThing(newx, newy);
 
-    if (CAN_SMASH(element) && direction == MV_DOWN &&
-       (newy == lev_fieldy-1 || !IS_FREE(x, newy+1)))
+    if (CAN_FALL(element) && direction == MV_DOWN &&
+       (newy == lev_fieldy - 1 || !IS_FREE(x, newy + 1)))
       Impact(x, newy);
+
+    if (!IN_LEV_FIELD(nextx, nexty) || !IS_FREE(nextx, nexty))
+      CheckElementChange(newx, newy, element, CE_COLLISION);
+
+    TestIfPlayerTouchesCustomElement(newx, newy);
+    TestIfElementTouchesCustomElement(newx, newy);
   }
   else                         /* still moving on */
+  {
     DrawLevelField(x, y);
+  }
 }
 
 int AmoebeNachbarNr(int ax, int ay)
@@ -3353,9 +4307,9 @@ void AmoebenVereinigen(int ax, int ay)
     if (!IN_LEV_FIELD(x, y))
       continue;
 
-    if ((Feld[x][y] == EL_AMOEBE_VOLL ||
-        Feld[x][y] == EL_AMOEBE_BD ||
-        Feld[x][y] == EL_AMOEBE_TOT) &&
+    if ((Feld[x][y] == EL_AMOEBA_FULL ||
+        Feld[x][y] == EL_BD_AMOEBA ||
+        Feld[x][y] == EL_AMOEBA_DEAD) &&
        AmoebaNr[x][y] != new_group_nr)
     {
       int old_group_nr = AmoebaNr[x][y];
@@ -3384,7 +4338,7 @@ void AmoebeUmwandeln(int ax, int ay)
 {
   int i, x, y;
 
-  if (Feld[ax][ay] == EL_AMOEBE_TOT)
+  if (Feld[ax][ay] == EL_AMOEBA_DEAD)
   {
     int group_nr = AmoebaNr[ax][ay];
 
@@ -3401,10 +4355,10 @@ void AmoebeUmwandeln(int ax, int ay)
     {
       for (x=0; x<lev_fieldx; x++)
       {
-       if (Feld[x][y] == EL_AMOEBE_TOT && AmoebaNr[x][y] == group_nr)
+       if (Feld[x][y] == EL_AMOEBA_DEAD && AmoebaNr[x][y] == group_nr)
        {
          AmoebaNr[x][y] = 0;
-         Feld[x][y] = EL_AMOEBA2DIAM;
+         Feld[x][y] = EL_AMOEBA_TO_DIAMOND;
        }
       }
     }
@@ -3431,7 +4385,7 @@ void AmoebeUmwandeln(int ax, int ay)
       if (!IN_LEV_FIELD(x, y))
        continue;
 
-      if (Feld[x][y] == EL_AMOEBA2DIAM)
+      if (Feld[x][y] == EL_AMOEBA_TO_DIAMOND)
       {
        PlaySoundLevel(x, y, (IS_GEM(level.amoeba_content) ?
                              SND_AMOEBA_TURNING_TO_GEM :
@@ -3462,9 +4416,9 @@ void AmoebeUmwandelnBD(int ax, int ay, int new_element)
     for (x=0; x<lev_fieldx; x++)
     {
       if (AmoebaNr[x][y] == group_nr &&
-         (Feld[x][y] == EL_AMOEBE_TOT ||
-          Feld[x][y] == EL_AMOEBE_BD ||
-          Feld[x][y] == EL_AMOEBING))
+         (Feld[x][y] == EL_AMOEBA_DEAD ||
+          Feld[x][y] == EL_BD_AMOEBA ||
+          Feld[x][y] == EL_AMOEBA_GROWING))
       {
        AmoebaNr[x][y] = 0;
        Feld[x][y] = new_element;
@@ -3492,10 +4446,14 @@ void AmoebeWaechst(int x, int y)
 
     if (DelayReached(&sound_delay, sound_delay_value))
     {
-      if (Store[x][y] == EL_AMOEBE_BD)
-       PlaySoundLevel(x, y, SND_BD_AMOEBA_CREATING);
+#if 1
+      PlaySoundLevelElementAction(x, y, Store[x][y], ACTION_GROWING);
+#else
+      if (Store[x][y] == EL_BD_AMOEBA)
+       PlaySoundLevel(x, y, SND_BD_AMOEBA_GROWING);
       else
-       PlaySoundLevel(x, y, SND_AMOEBA_CREATING);
+       PlaySoundLevel(x, y, SND_AMOEBA_GROWING);
+#endif
       sound_delay_value = 30;
     }
   }
@@ -3504,7 +4462,12 @@ void AmoebeWaechst(int x, int y)
   {
     MovDelay[x][y]--;
     if (MovDelay[x][y]/2 && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
-      DrawGraphic(SCREENX(x), SCREENY(y), GFX_AMOEBING + 3 - MovDelay[x][y]/2);
+    {
+      int frame = getGraphicAnimationFrame(IMG_AMOEBA_GROWING,
+                                          6 - MovDelay[x][y]);
+
+      DrawGraphic(SCREENX(x), SCREENY(y), IMG_AMOEBA_GROWING, frame);
+    }
 
     if (!MovDelay[x][y])
     {
@@ -3532,11 +4495,16 @@ void AmoebaDisappearing(int x, int y)
   {
     MovDelay[x][y]--;
     if (MovDelay[x][y]/2 && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
-      DrawGraphic(SCREENX(x), SCREENY(y), GFX_AMOEBING + MovDelay[x][y]/2);
+    {
+      int frame = getGraphicAnimationFrame(IMG_AMOEBA_SHRINKING,
+                                          6 - MovDelay[x][y]);
+
+      DrawGraphic(SCREENX(x), SCREENY(y), IMG_AMOEBA_SHRINKING, frame);
+    }
 
     if (!MovDelay[x][y])
     {
-      Feld[x][y] = EL_LEERRAUM;
+      Feld[x][y] = EL_EMPTY;
       DrawLevelField(x, y);
 
       /* don't let mole enter this field in this cycle;
@@ -3550,6 +4518,7 @@ void AmoebeAbleger(int ax, int ay)
 {
   int i;
   int element = Feld[ax][ay];
+  int graphic = el2img(element);
   int newax = ax, neway = ay;
   static int xy[4][2] =
   {
@@ -3561,11 +4530,14 @@ void AmoebeAbleger(int ax, int ay)
 
   if (!level.amoeba_speed)
   {
-    Feld[ax][ay] = EL_AMOEBE_TOT;
+    Feld[ax][ay] = EL_AMOEBA_DEAD;
     DrawLevelField(ax, ay);
     return;
   }
 
+  if (IS_ANIMATED(graphic))
+    DrawLevelGraphicAnimationIfNeeded(ax, ay, graphic);
+
   if (!MovDelay[ax][ay])       /* start making new amoeba field */
     MovDelay[ax][ay] = RND(FRAMES_PER_SECOND * 25 / (1 + level.amoeba_speed));
 
@@ -3576,7 +4548,7 @@ void AmoebeAbleger(int ax, int ay)
       return;
   }
 
-  if (element == EL_AMOEBE_NASS)       /* object is an acid / amoeba drop */
+  if (element == EL_AMOEBA_WET)        /* object is an acid / amoeba drop */
   {
     int start = RND(4);
     int x = ax + xy[start][0];
@@ -3585,8 +4557,9 @@ void AmoebeAbleger(int ax, int ay)
     if (!IN_LEV_FIELD(x, y))
       return;
 
+    /* !!! extend EL_SAND to anything diggable (but maybe not SP_BASE) !!! */
     if (IS_FREE(x, y) ||
-       Feld[x][y] == EL_ERDREICH || Feld[x][y] == EL_MORAST_LEER)
+       Feld[x][y] == EL_SAND || Feld[x][y] == EL_QUICKSAND_EMPTY)
     {
       newax = x;
       neway = y;
@@ -3609,8 +4582,9 @@ void AmoebeAbleger(int ax, int ay)
       if (!IN_LEV_FIELD(x, y))
        continue;
 
+      /* !!! extend EL_SAND to anything diggable (but maybe not SP_BASE) !!! */
       if (IS_FREE(x, y) ||
-         Feld[x][y] == EL_ERDREICH || Feld[x][y] == EL_MORAST_LEER)
+         Feld[x][y] == EL_SAND || Feld[x][y] == EL_QUICKSAND_EMPTY)
       {
        newax = x;
        neway = y;
@@ -3624,21 +4598,21 @@ void AmoebeAbleger(int ax, int ay)
     {
       if (i == 4 && (!waiting_for_player || game.emulation == EMU_BOULDERDASH))
       {
-       Feld[ax][ay] = EL_AMOEBE_TOT;
+       Feld[ax][ay] = EL_AMOEBA_DEAD;
        DrawLevelField(ax, ay);
        AmoebaCnt[AmoebaNr[ax][ay]]--;
 
        if (AmoebaCnt[AmoebaNr[ax][ay]] <= 0)   /* amoeba is completely dead */
        {
-         if (element == EL_AMOEBE_VOLL)
+         if (element == EL_AMOEBA_FULL)
            AmoebeUmwandeln(ax, ay);
-         else if (element == EL_AMOEBE_BD)
+         else if (element == EL_BD_AMOEBA)
            AmoebeUmwandelnBD(ax, ay, level.amoeba_content);
        }
       }
       return;
     }
-    else if (element == EL_AMOEBE_VOLL || element == EL_AMOEBE_BD)
+    else if (element == EL_AMOEBA_FULL || element == EL_BD_AMOEBA)
     {
       /* amoeba gets larger by growing in some direction */
 
@@ -3660,7 +4634,7 @@ void AmoebeAbleger(int ax, int ay)
       /* if amoeba touches other amoeba(s) after growing, unify them */
       AmoebenVereinigen(newax, neway);
 
-      if (element == EL_AMOEBE_BD && AmoebaCnt2[new_group_nr] >= 200)
+      if (element == EL_BD_AMOEBA && AmoebaCnt2[new_group_nr] >= 200)
       {
        AmoebeUmwandelnBD(newax, neway, EL_BD_ROCK);
        return;
@@ -3668,22 +4642,26 @@ void AmoebeAbleger(int ax, int ay)
     }
   }
 
-  if (element != EL_AMOEBE_NASS || neway < ay || !IS_FREE(newax, neway) ||
+  if (element != EL_AMOEBA_WET || neway < ay || !IS_FREE(newax, neway) ||
       (neway == lev_fieldy - 1 && newax != ax))
   {
-    Feld[newax][neway] = EL_AMOEBING;  /* simple growth of new amoeba tile */
+    Feld[newax][neway] = EL_AMOEBA_GROWING;    /* creation of new amoeba */
     Store[newax][neway] = element;
   }
   else if (neway == ay)
   {
-    Feld[newax][neway] = EL_TROPFEN;   /* drop left or right from amoeba */
-    PlaySoundLevel(newax, neway, SND_AMOEBA_DROPPING);
+    Feld[newax][neway] = EL_AMOEBA_DROP;       /* drop left/right of amoeba */
+#if 1
+    PlaySoundLevelAction(newax, neway, ACTION_GROWING);
+#else
+    PlaySoundLevel(newax, neway, SND_AMOEBA_GROWING);
+#endif
   }
   else
   {
-    InitMovingField(ax, ay, MV_DOWN);  /* drop dripping out of amoeba */
-    Feld[ax][ay] = EL_AMOEBA_DRIPPING;
-    Store[ax][ay] = EL_TROPFEN;
+    InitMovingField(ax, ay, MV_DOWN);          /* drop dripping from amoeba */
+    Feld[ax][ay] = EL_AMOEBA_DROPPING;
+    Store[ax][ay] = EL_AMOEBA_DROP;
     ContinueMoving(ax, ay);
     return;
   }
@@ -3697,8 +4675,12 @@ void Life(int ax, int ay)
   static int life[4] = { 2, 3, 3, 3 }; /* parameters for "game of life" */
   int life_time = 40;
   int element = Feld[ax][ay];
+  int graphic = el2img(element);
   boolean changed = FALSE;
 
+  if (IS_ANIMATED(graphic))
+    DrawLevelGraphicAnimationIfNeeded(ax, ay, graphic);
+
   if (Stop[ax][ay])
     return;
 
@@ -3728,7 +4710,7 @@ void Life(int ax, int ay)
        continue;
 
       if (((Feld[x][y] == element ||
-           (element == EL_LIFE && IS_PLAYER(x, y))) &&
+           (element == EL_GAME_OF_LIFE && IS_PLAYER(x, y))) &&
           !Stop[x][y]) ||
          (IS_FREE(x, y) && Stop[x][y]))
        nachbarn++;
@@ -3738,19 +4720,20 @@ void Life(int ax, int ay)
     {
       if (nachbarn < life[0] || nachbarn > life[1])
       {
-       Feld[xx][yy] = EL_LEERRAUM;
+       Feld[xx][yy] = EL_EMPTY;
        if (!Stop[xx][yy])
          DrawLevelField(xx, yy);
        Stop[xx][yy] = TRUE;
        changed = TRUE;
       }
     }
-    else if (IS_FREE(xx, yy) || Feld[xx][yy] == EL_ERDREICH)
+    /* !!! extend EL_SAND to anything diggable (but maybe not SP_BASE) !!! */
+    else if (IS_FREE(xx, yy) || Feld[xx][yy] == EL_SAND)
     {                                  /* free border field */
       if (nachbarn >= life[2] && nachbarn <= life[3])
       {
        Feld[xx][yy] = element;
-       MovDelay[xx][yy] = (element == EL_LIFE ? 0 : life_time-1);
+       MovDelay[xx][yy] = (element == EL_GAME_OF_LIFE ? 0 : life_time-1);
        if (!Stop[xx][yy])
          DrawLevelField(xx, yy);
        Stop[xx][yy] = TRUE;
@@ -3760,282 +4743,72 @@ void Life(int ax, int ay)
   }
 
   if (changed)
-    PlaySoundLevel(ax, ay, element == EL_LIFE ? SND_GAMEOFLIFE_CREATING :
-                  SND_BIOMAZE_CREATING);
+    PlaySoundLevel(ax, ay, element == EL_BIOMAZE ? SND_BIOMAZE_GROWING :
+                  SND_GAME_OF_LIFE_GROWING);
 }
 
-void RobotWheel(int x, int y)
+static void InitRobotWheel(int x, int y)
 {
-  if (!MovDelay[x][y])         /* next animation frame */
-    MovDelay[x][y] = level.time_wheel * FRAMES_PER_SECOND;
+  ChangeDelay[x][y] = level.time_wheel * FRAMES_PER_SECOND;
+}
 
-  if (MovDelay[x][y])          /* wait some time before next frame */
-  {
-    MovDelay[x][y]--;
-    if (MovDelay[x][y])
-    {
-      if (IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
-       DrawGraphic(SCREENX(x), SCREENY(y), GFX_ABLENK+MovDelay[x][y]%4);
-      if (!(MovDelay[x][y]%4))
-       PlaySoundLevel(x, y, SND_ROBOT_WHEEL_RUNNING);
-      return;
-    }
-  }
+static void RunRobotWheel(int x, int y)
+{
+  PlaySoundLevel(x, y, SND_ROBOT_WHEEL_ACTIVE);
+}
 
-  Feld[x][y] = EL_ABLENK_AUS;
-  DrawLevelField(x, y);
-  if (ZX == x && ZY == y)
-    ZX = ZY = -1;
-}
-
-void TimegateWheel(int x, int y)
+static void StopRobotWheel(int x, int y)
 {
-  if (!MovDelay[x][y])         /* next animation frame */
-    MovDelay[x][y] = level.time_wheel * FRAMES_PER_SECOND;
-
-  if (MovDelay[x][y])          /* wait some time before next frame */
-  {
-    MovDelay[x][y]--;
-    if (MovDelay[x][y])
-    {
-      if (IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
-       DrawGraphic(SCREENX(x), SCREENY(y),
-                   GFX_TIMEGATE_SWITCH + MovDelay[x][y]%4);
-      if (!(MovDelay[x][y]%4))
-       PlaySoundLevel(x, y, SND_TIMEGATE_WHEEL_RUNNING);
-      return;
-    }
-  }
-
-  Feld[x][y] = EL_TIMEGATE_SWITCH_OFF;
-  DrawLevelField(x, y);
   if (ZX == x && ZY == y)
     ZX = ZY = -1;
 }
 
-void Birne(int x, int y)
+static void InitTimegateWheel(int x, int y)
 {
-  if (!MovDelay[x][y])         /* next animation frame */
-    MovDelay[x][y] = 800;
-
-  if (MovDelay[x][y])          /* wait some time before next frame */
-  {
-    MovDelay[x][y]--;
-    if (MovDelay[x][y])
-    {
-      if (!(MovDelay[x][y]%5))
-      {
-       if (!(MovDelay[x][y]%10))
-         Feld[x][y]=EL_ABLENK_EIN;
-       else
-         Feld[x][y]=EL_ABLENK_AUS;
-       DrawLevelField(x, y);
-       Feld[x][y]=EL_ABLENK_EIN;
-      }
-      return;
-    }
-  }
-
-  Feld[x][y]=EL_ABLENK_AUS;
-  DrawLevelField(x, y);
-  if (ZX == x && ZY == y)
-    ZX=ZY=-1;
+  ChangeDelay[x][y] = level.time_wheel * FRAMES_PER_SECOND;
 }
 
-void Blubber(int x, int y)
+static void RunTimegateWheel(int x, int y)
 {
-  if (y > 0 && IS_MOVING(x, y-1) && MovDir[x][y-1] == MV_DOWN)
-    DrawLevelField(x, y-1);
-  else
-    DrawGraphicAnimation(x, y, GFX_GEBLUBBER, 4, 10, ANIM_NORMAL);
+  PlaySoundLevel(x, y, SND_TIMEGATE_SWITCH_ACTIVE);
 }
 
-void NussKnacken(int x, int y)
+void CheckExit(int x, int y)
 {
-  if (!MovDelay[x][y])         /* next animation frame */
-    MovDelay[x][y] = 7;
-
-  if (MovDelay[x][y])          /* wait some time before next frame */
+  if (local_player->gems_still_needed > 0 ||
+      local_player->sokobanfields_still_needed > 0 ||
+      local_player->lights_still_needed > 0)
   {
-    MovDelay[x][y]--;
-    if (MovDelay[x][y]/2 && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
-      DrawGraphic(SCREENX(x), SCREENY(y),
-                 GFX_CRACKINGNUT + 3 - MovDelay[x][y]/2);
+    int element = Feld[x][y];
+    int graphic = el2img(element);
 
-    if (!MovDelay[x][y])
-    {
-      Feld[x][y] = EL_EDELSTEIN;
-      DrawLevelField(x, y);
-    }
-  }
-}
+    if (IS_ANIMATED(graphic))
+      DrawLevelGraphicAnimationIfNeeded(x, y, graphic);
 
-void BreakingPearl(int x, int y)
-{
-  if (!MovDelay[x][y])         /* next animation frame */
-    MovDelay[x][y] = 9;
-
-  if (MovDelay[x][y])          /* wait some time before next frame */
-  {
-    MovDelay[x][y]--;
-    if (MovDelay[x][y]/2 && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
-      DrawGraphic(SCREENX(x), SCREENY(y),
-                 GFX_PEARL_BREAKING + 4 - MovDelay[x][y]/2);
-
-    if (!MovDelay[x][y])
-    {
-      Feld[x][y] = EL_LEERRAUM;
-      DrawLevelField(x, y);
-    }
-  }
-}
-
-void SiebAktivieren(int x, int y, int typ)
-{
-  int graphic = (typ == 1 ? GFX_MAGIC_WALL_FULL : GFX_MAGIC_WALL_BD_FULL) + 3;
-
-  DrawGraphicAnimation(x, y, graphic, 4, 4, ANIM_REVERSE);
-}
-
-void AusgangstuerPruefen(int x, int y)
-{
-  if (!local_player->gems_still_needed &&
-      !local_player->sokobanfields_still_needed &&
-      !local_player->lights_still_needed)
-  {
-    Feld[x][y] = EL_AUSGANG_ACT;
-
-    PlaySoundLevel(x < LEVELX(BX1) ? LEVELX(BX1) :
-                  (x > LEVELX(BX2) ? LEVELX(BX2) : x),
-                  y < LEVELY(BY1) ? LEVELY(BY1) :
-                  (y > LEVELY(BY2) ? LEVELY(BY2) : y),
-                  SND_EXIT_OPENING);
-  }
-}
-
-void AusgangstuerOeffnen(int x, int y)
-{
-  int delay = 6;
-
-  if (!MovDelay[x][y])         /* next animation frame */
-    MovDelay[x][y] = 5*delay;
-
-  if (MovDelay[x][y])          /* wait some time before next frame */
-  {
-    int tuer;
-
-    MovDelay[x][y]--;
-    tuer = MovDelay[x][y]/delay;
-    if (!(MovDelay[x][y]%delay) && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
-      DrawGraphic(SCREENX(x), SCREENY(y), GFX_AUSGANG_AUF-tuer);
-
-    if (!MovDelay[x][y])
-    {
-      Feld[x][y] = EL_AUSGANG_AUF;
-      DrawLevelField(x, y);
-    }
+    return;
   }
-}
-
-void AusgangstuerBlinken(int x, int y)
-{
-  DrawGraphicAnimation(x, y, GFX_AUSGANG_AUF, 4, 4, ANIM_OSCILLATE);
-}
-
-void OpenSwitchgate(int x, int y)
-{
-  int delay = 6;
 
-  if (!MovDelay[x][y])         /* next animation frame */
-    MovDelay[x][y] = 5 * delay;
-
-  if (MovDelay[x][y])          /* wait some time before next frame */
-  {
-    int phase;
+  Feld[x][y] = EL_EXIT_OPENING;
 
-    MovDelay[x][y]--;
-    phase = MovDelay[x][y] / delay;
-    if (!(MovDelay[x][y] % delay) && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
-      DrawGraphic(SCREENX(x), SCREENY(y), GFX_SWITCHGATE_OPEN - phase);
-
-    if (!MovDelay[x][y])
-    {
-      Feld[x][y] = EL_SWITCHGATE_OPEN;
-      DrawLevelField(x, y);
-    }
-  }
+  PlaySoundLevelNearest(x, y, SND_CLASS_EXIT_OPENING);
 }
 
-void CloseSwitchgate(int x, int y)
+void CheckExitSP(int x, int y)
 {
-  int delay = 6;
-
-  if (!MovDelay[x][y])         /* next animation frame */
-    MovDelay[x][y] = 5 * delay;
-
-  if (MovDelay[x][y])          /* wait some time before next frame */
+  if (local_player->gems_still_needed > 0)
   {
-    int phase;
-
-    MovDelay[x][y]--;
-    phase = MovDelay[x][y] / delay;
-    if (!(MovDelay[x][y] % delay) && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
-      DrawGraphic(SCREENX(x), SCREENY(y), GFX_SWITCHGATE_CLOSED + phase);
+    int element = Feld[x][y];
+    int graphic = el2img(element);
 
-    if (!MovDelay[x][y])
-    {
-      Feld[x][y] = EL_SWITCHGATE_CLOSED;
-      DrawLevelField(x, y);
-    }
-  }
-}
+    if (IS_ANIMATED(graphic))
+      DrawLevelGraphicAnimationIfNeeded(x, y, graphic);
 
-void OpenTimegate(int x, int y)
-{
-  int delay = 6;
-
-  if (!MovDelay[x][y])         /* next animation frame */
-    MovDelay[x][y] = 5 * delay;
-
-  if (MovDelay[x][y])          /* wait some time before next frame */
-  {
-    int phase;
-
-    MovDelay[x][y]--;
-    phase = MovDelay[x][y] / delay;
-    if (!(MovDelay[x][y] % delay) && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
-      DrawGraphic(SCREENX(x), SCREENY(y), GFX_TIMEGATE_OPEN - phase);
-
-    if (!MovDelay[x][y])
-    {
-      Feld[x][y] = EL_TIMEGATE_OPEN;
-      DrawLevelField(x, y);
-    }
+    return;
   }
-}
 
-void CloseTimegate(int x, int y)
-{
-  int delay = 6;
-
-  if (!MovDelay[x][y])         /* next animation frame */
-    MovDelay[x][y] = 5 * delay;
-
-  if (MovDelay[x][y])          /* wait some time before next frame */
-  {
-    int phase;
+  Feld[x][y] = EL_SP_EXIT_OPEN;
 
-    MovDelay[x][y]--;
-    phase = MovDelay[x][y] / delay;
-    if (!(MovDelay[x][y] % delay) && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
-      DrawGraphic(SCREENX(x), SCREENY(y), GFX_TIMEGATE_CLOSED + phase);
-
-    if (!MovDelay[x][y])
-    {
-      Feld[x][y] = EL_TIMEGATE_CLOSED;
-      DrawLevelField(x, y);
-    }
-  }
+  PlaySoundLevelNearest(x, y, SND_CLASS_SP_EXIT_OPENING);
 }
 
 static void CloseAllOpenTimegates()
@@ -4051,7 +4824,11 @@ static void CloseAllOpenTimegates()
       if (element == EL_TIMEGATE_OPEN || element == EL_TIMEGATE_OPENING)
       {
        Feld[x][y] = EL_TIMEGATE_CLOSING;
+#if 1
+       PlaySoundLevelAction(x, y, ACTION_CLOSING);
+#else
        PlaySoundLevel(x, y, SND_TIMEGATE_CLOSING);
+#endif
       }
     }
   }
@@ -4062,42 +4839,38 @@ void EdelsteinFunkeln(int x, int y)
   if (!IN_SCR_FIELD(SCREENX(x), SCREENY(y)) || IS_MOVING(x, y))
     return;
 
-  if (Feld[x][y] == EL_EDELSTEIN_BD)
-    DrawGraphicAnimation(x, y, GFX_EDELSTEIN_BD, 4, 4, ANIM_REVERSE);
-  else
-  {
-    if (!MovDelay[x][y])       /* next animation frame */
-      MovDelay[x][y] = 11 * !SimpleRND(500);
+  if (Feld[x][y] == EL_BD_DIAMOND)
+    return;
 
-    if (MovDelay[x][y])                /* wait some time before next frame */
-    {
-      MovDelay[x][y]--;
+  if (MovDelay[x][y] == 0)     /* next animation frame */
+    MovDelay[x][y] = 11 * !SimpleRND(500);
 
-      if (setup.direct_draw && MovDelay[x][y])
-       SetDrawtoField(DRAW_BUFFERED);
+  if (MovDelay[x][y] != 0)     /* wait some time before next frame */
+  {
+    MovDelay[x][y]--;
 
-      DrawGraphic(SCREENX(x), SCREENY(y), el2gfx(Feld[x][y]));
+    if (setup.direct_draw && MovDelay[x][y])
+      SetDrawtoField(DRAW_BUFFERED);
 
-      if (MovDelay[x][y])
-      {
-       int phase = (MovDelay[x][y]-1)/2;
+    DrawLevelElementAnimation(x, y, Feld[x][y]);
 
-       if (phase > 2)
-         phase = 4-phase;
+    if (MovDelay[x][y] != 0)
+    {
+      int frame = getGraphicAnimationFrame(IMG_TWINKLE_WHITE,
+                                          10 - MovDelay[x][y]);
 
-       DrawGraphicThruMask(SCREENX(x), SCREENY(y), GFX_FUNKELN_WEISS + phase);
+      DrawGraphicThruMask(SCREENX(x), SCREENY(y), IMG_TWINKLE_WHITE, frame);
 
-       if (setup.direct_draw)
-       {
-         int dest_x, dest_y;
+      if (setup.direct_draw)
+      {
+       int dest_x, dest_y;
 
-         dest_x = FX + SCREENX(x)*TILEX;
-         dest_y = FY + SCREENY(y)*TILEY;
+       dest_x = FX + SCREENX(x) * TILEX;
+       dest_y = FY + SCREENY(y) * TILEY;
 
-         BlitBitmap(drawto_field, window,
-                    dest_x, dest_y, TILEX, TILEY, dest_x, dest_y);
-         SetDrawtoField(DRAW_DIRECT);
-       }
+       BlitBitmap(drawto_field, window,
+                  dest_x, dest_y, TILEX, TILEY, dest_x, dest_y);
+       SetDrawtoField(DRAW_DIRECT);
       }
     }
   }
@@ -4108,42 +4881,41 @@ void MauerWaechst(int x, int y)
   int delay = 6;
 
   if (!MovDelay[x][y])         /* next animation frame */
-    MovDelay[x][y] = 3*delay;
+    MovDelay[x][y] = 3 * delay;
 
   if (MovDelay[x][y])          /* wait some time before next frame */
   {
-    int phase;
-
     MovDelay[x][y]--;
-    phase = 2-MovDelay[x][y]/delay;
-    if (!(MovDelay[x][y]%delay) && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
-      DrawGraphic(SCREENX(x), SCREENY(y),
-                 (MovDir[x][y] == MV_LEFT  ? GFX_MAUER_LEFT  :
-                  MovDir[x][y] == MV_RIGHT ? GFX_MAUER_RIGHT :
-                  MovDir[x][y] == MV_UP    ? GFX_MAUER_UP    :
-                                             GFX_MAUER_DOWN  ) + phase);
+
+    if (IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
+    {
+      int graphic = el_dir2img(Feld[x][y], MovDir[x][y]);
+      int frame = getGraphicAnimationFrame(graphic, 17 - MovDelay[x][y]);
+
+      DrawGraphic(SCREENX(x), SCREENY(y), graphic, frame);
+    }
 
     if (!MovDelay[x][y])
     {
       if (MovDir[x][y] == MV_LEFT)
       {
-       if (IN_LEV_FIELD(x-1, y) && IS_MAUER(Feld[x-1][y]))
-         DrawLevelField(x-1, y);
+       if (IN_LEV_FIELD(x - 1, y) && IS_WALL(Feld[x - 1][y]))
+         DrawLevelField(x - 1, y);
       }
       else if (MovDir[x][y] == MV_RIGHT)
       {
-       if (IN_LEV_FIELD(x+1, y) && IS_MAUER(Feld[x+1][y]))
-         DrawLevelField(x+1, y);
+       if (IN_LEV_FIELD(x + 1, y) && IS_WALL(Feld[x + 1][y]))
+         DrawLevelField(x + 1, y);
       }
       else if (MovDir[x][y] == MV_UP)
       {
-       if (IN_LEV_FIELD(x, y-1) && IS_MAUER(Feld[x][y-1]))
-         DrawLevelField(x, y-1);
+       if (IN_LEV_FIELD(x, y - 1) && IS_WALL(Feld[x][y - 1]))
+         DrawLevelField(x, y - 1);
       }
       else
       {
-       if (IN_LEV_FIELD(x, y+1) && IS_MAUER(Feld[x][y+1]))
-         DrawLevelField(x, y+1);
+       if (IN_LEV_FIELD(x, y + 1) && IS_WALL(Feld[x][y + 1]))
+         DrawLevelField(x, y + 1);
       }
 
       Feld[x][y] = Store[x][y];
@@ -4157,12 +4929,16 @@ void MauerWaechst(int x, int y)
 void MauerAbleger(int ax, int ay)
 {
   int element = Feld[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;
 
@@ -4182,72 +4958,83 @@ void MauerAbleger(int ax, int ay)
   if (IN_LEV_FIELD(ax+1, ay) && IS_FREE(ax+1, ay))
     rechts_frei = TRUE;
 
-  if (element == EL_MAUER_Y || element == EL_MAUER_XY)
+  if (element == EL_EXPANDABLE_WALL_VERTICAL ||
+      element == EL_EXPANDABLE_WALL_ANY)
   {
     if (oben_frei)
     {
-      Feld[ax][ay-1] = EL_MAUERND;
+      Feld[ax][ay-1] = EL_EXPANDABLE_WALL_GROWING;
       Store[ax][ay-1] = element;
       MovDir[ax][ay-1] = MV_UP;
       if (IN_SCR_FIELD(SCREENX(ax), SCREENY(ay-1)))
-       DrawGraphic(SCREENX(ax), SCREENY(ay-1), GFX_MAUER_UP);
+       DrawGraphic(SCREENX(ax), SCREENY(ay - 1),
+                   IMG_EXPANDABLE_WALL_GROWING_UP, 0);
       new_wall = TRUE;
     }
     if (unten_frei)
     {
-      Feld[ax][ay+1] = EL_MAUERND;
+      Feld[ax][ay+1] = EL_EXPANDABLE_WALL_GROWING;
       Store[ax][ay+1] = element;
       MovDir[ax][ay+1] = MV_DOWN;
       if (IN_SCR_FIELD(SCREENX(ax), SCREENY(ay+1)))
-       DrawGraphic(SCREENX(ax), SCREENY(ay+1), GFX_MAUER_DOWN);
+       DrawGraphic(SCREENX(ax), SCREENY(ay + 1),
+                   IMG_EXPANDABLE_WALL_GROWING_DOWN, 0);
       new_wall = TRUE;
     }
   }
 
-  if (element == EL_MAUER_X || element == EL_MAUER_XY ||
-      element == EL_MAUER_LEBT)
+  if (element == EL_EXPANDABLE_WALL_HORIZONTAL ||
+      element == EL_EXPANDABLE_WALL_ANY ||
+      element == EL_EXPANDABLE_WALL)
   {
     if (links_frei)
     {
-      Feld[ax-1][ay] = EL_MAUERND;
+      Feld[ax-1][ay] = EL_EXPANDABLE_WALL_GROWING;
       Store[ax-1][ay] = element;
       MovDir[ax-1][ay] = MV_LEFT;
       if (IN_SCR_FIELD(SCREENX(ax-1), SCREENY(ay)))
-       DrawGraphic(SCREENX(ax-1), SCREENY(ay), GFX_MAUER_LEFT);
+       DrawGraphic(SCREENX(ax - 1), SCREENY(ay),
+                   IMG_EXPANDABLE_WALL_GROWING_LEFT, 0);
       new_wall = TRUE;
     }
 
     if (rechts_frei)
     {
-      Feld[ax+1][ay] = EL_MAUERND;
+      Feld[ax+1][ay] = EL_EXPANDABLE_WALL_GROWING;
       Store[ax+1][ay] = element;
       MovDir[ax+1][ay] = MV_RIGHT;
       if (IN_SCR_FIELD(SCREENX(ax+1), SCREENY(ay)))
-       DrawGraphic(SCREENX(ax+1), SCREENY(ay), GFX_MAUER_RIGHT);
+       DrawGraphic(SCREENX(ax + 1), SCREENY(ay),
+                   IMG_EXPANDABLE_WALL_GROWING_RIGHT, 0);
       new_wall = TRUE;
     }
   }
 
-  if (element == EL_MAUER_LEBT && (links_frei || rechts_frei))
+  if (element == EL_EXPANDABLE_WALL && (links_frei || rechts_frei))
     DrawLevelField(ax, ay);
 
-  if (!IN_LEV_FIELD(ax, ay-1) || IS_MAUER(Feld[ax][ay-1]))
+  if (!IN_LEV_FIELD(ax, ay-1) || IS_WALL(Feld[ax][ay-1]))
     oben_massiv = TRUE;
-  if (!IN_LEV_FIELD(ax, ay+1) || IS_MAUER(Feld[ax][ay+1]))
+  if (!IN_LEV_FIELD(ax, ay+1) || IS_WALL(Feld[ax][ay+1]))
     unten_massiv = TRUE;
-  if (!IN_LEV_FIELD(ax-1, ay) || IS_MAUER(Feld[ax-1][ay]))
+  if (!IN_LEV_FIELD(ax-1, ay) || IS_WALL(Feld[ax-1][ay]))
     links_massiv = TRUE;
-  if (!IN_LEV_FIELD(ax+1, ay) || IS_MAUER(Feld[ax+1][ay]))
+  if (!IN_LEV_FIELD(ax+1, ay) || IS_WALL(Feld[ax+1][ay]))
     rechts_massiv = TRUE;
 
   if (((oben_massiv && unten_massiv) ||
-       element == EL_MAUER_X || element == EL_MAUER_LEBT) &&
+       element == EL_EXPANDABLE_WALL_HORIZONTAL ||
+       element == EL_EXPANDABLE_WALL) &&
       ((links_massiv && rechts_massiv) ||
-       element == EL_MAUER_Y))
-    Feld[ax][ay] = EL_MAUERWERK;
+       element == EL_EXPANDABLE_WALL_VERTICAL))
+    Feld[ax][ay] = EL_WALL;
 
   if (new_wall)
-    PlaySoundLevel(ax, ay, SND_WALL_GROWING);
+#if 1
+    PlaySoundLevelAction(ax, ay, ACTION_GROWING);
+#else
+    PlaySoundLevel(ax, ay, SND_EXPANDABLE_WALL_GROWING);
+#endif
 }
 
 void CheckForDragon(int x, int y)
@@ -4269,9 +5056,9 @@ void CheckForDragon(int x, int y)
       int xx = x + j*xy[i][0], yy = y + j*xy[i][1];
 
       if (IN_LEV_FIELD(xx, yy) &&
-         (Feld[xx][yy] == EL_BURNING || Feld[xx][yy] == EL_DRACHE))
+         (Feld[xx][yy] == EL_FLAMES || Feld[xx][yy] == EL_DRAGON))
       {
-       if (Feld[xx][yy] == EL_DRACHE)
+       if (Feld[xx][yy] == EL_DRAGON)
          dragon_found = TRUE;
       }
       else
@@ -4287,9 +5074,9 @@ void CheckForDragon(int x, int y)
       {
        int xx = x + j*xy[i][0], yy = y + j*xy[i][1];
   
-       if (IN_LEV_FIELD(xx, yy) && Feld[xx][yy] == EL_BURNING)
+       if (IN_LEV_FIELD(xx, yy) && Feld[xx][yy] == EL_FLAMES)
        {
-         Feld[xx][yy] = EL_LEERRAUM;
+         Feld[xx][yy] = EL_EMPTY;
          DrawLevelField(xx, yy);
        }
        else
@@ -4299,149 +5086,334 @@ void CheckForDragon(int x, int y)
   }
 }
 
-static void CheckBuggyBase(int x, int y)
+static void InitBuggyBase(int x, int y)
 {
   int element = Feld[x][y];
+  int activating_delay = FRAMES_PER_SECOND / 4;
+
+  ChangeDelay[x][y] =
+    (element == EL_SP_BUGGY_BASE ?
+     2 * FRAMES_PER_SECOND + RND(5 * FRAMES_PER_SECOND) - activating_delay :
+     element == EL_SP_BUGGY_BASE_ACTIVATING ?
+     activating_delay :
+     element == EL_SP_BUGGY_BASE_ACTIVE ?
+     1 * FRAMES_PER_SECOND + RND(1 * FRAMES_PER_SECOND) : 1);
+}
+
+static void WarnBuggyBase(int x, int y)
+{
+  int i;
+  static int xy[4][2] =
+  {
+    { 0, -1 },
+    { -1, 0 },
+    { +1, 0 },
+    { 0, +1 }
+  };
 
-  if (element == EL_SP_BUG)
+  for (i=0; i<4; i++)
   {
-    if (!MovDelay[x][y])       /* wait some time before activating base */
-      MovDelay[x][y] = 2 * FRAMES_PER_SECOND + RND(5 * FRAMES_PER_SECOND);
+    int xx = x + xy[i][0], yy = y + xy[i][1];
 
-    if (MovDelay[x][y])
+    if (IS_PLAYER(xx, yy))
     {
-      MovDelay[x][y]--;
-      if (MovDelay[x][y] < 5 && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
-       DrawGraphic(SCREENX(x), SCREENY(y), GFX_SP_BUG_WARNING);
-      if (MovDelay[x][y])
-       return;
+      PlaySoundLevel(x, y, SND_SP_BUGGY_BASE_ACTIVE);
 
-      Feld[x][y] = EL_SP_BUG_ACTIVE;
+      break;
     }
   }
-  else if (element == EL_SP_BUG_ACTIVE)
+}
+
+static void InitTrap(int x, int y)
+{
+  ChangeDelay[x][y] = 2 * FRAMES_PER_SECOND + RND(5 * FRAMES_PER_SECOND);
+}
+
+static void ActivateTrap(int x, int y)
+{
+  PlaySoundLevel(x, y, SND_TRAP_ACTIVATING);
+}
+
+static void ChangeActiveTrap(int x, int y)
+{
+  int graphic = IMG_TRAP_ACTIVE;
+
+  /* if new animation frame was drawn, correct crumbled sand border */
+  if (IS_NEW_FRAME(GfxFrame[x][y], graphic))
+    DrawLevelFieldCrumbledSand(x, y);
+}
+
+static void ChangeElementNowExt(int x, int y, int target_element)
+{
+  if (IS_PLAYER(x, y) && !IS_ACCESSIBLE(target_element))
+  {
+    Bang(x, y);
+    return;
+  }
+
+  RemoveField(x, y);
+  Feld[x][y] = target_element;
+
+  ResetGfxAnimation(x, y);
+  ResetRandomAnimationValue(x, y);
+
+  InitField(x, y, FALSE);
+  if (CAN_MOVE(Feld[x][y]))
+    InitMovDir(x, y);
+
+  DrawLevelField(x, y);
+
+  if (CAN_BE_CRUMBLED(Feld[x][y]))
+    DrawLevelFieldCrumbledSandNeighbours(x, y);
+
+  TestIfBadThingTouchesHero(x, y);
+  TestIfPlayerTouchesCustomElement(x, y);
+  TestIfElementTouchesCustomElement(x, y);
+}
+
+static void ChangeElementNow(int x, int y, int element)
+{
+  struct ElementChangeInfo *change = &element_info[element].change;
+
+  /* prevent CheckTriggeredElementChange() from looping */
+  Changing[x][y] = TRUE;
+
+  CheckTriggeredElementChange(x, y, Feld[x][y], CE_OTHER_IS_CHANGING);
+
+  Changing[x][y] = FALSE;
+
+  if (change->explode)
+  {
+    Bang(x, y);
+    return;
+  }
+
+  if (change->use_content)
   {
-    if (!MovDelay[x][y])       /* start activating buggy base */
-      MovDelay[x][y] = 1 * FRAMES_PER_SECOND + RND(1 * FRAMES_PER_SECOND);
+    boolean complete_change = TRUE;
+    boolean can_change[3][3];
+    int xx, yy;
 
-    if (MovDelay[x][y])
+    for (yy = 0; yy < 3; yy++) for(xx = 0; xx < 3 ; xx++)
     {
-      MovDelay[x][y]--;
-      if (MovDelay[x][y])
+      boolean half_destructible;
+      int ex = x + xx - 1;
+      int ey = y + yy - 1;
+      int e;
+
+      can_change[xx][yy] = TRUE;
+
+      if (ex == x && ey == y)  /* do not check changing element itself */
+       continue;
+
+      if (change->content[xx][yy] == EL_EMPTY_SPACE)
       {
-       int i;
-       static int xy[4][2] =
-       {
-         { 0, -1 },
-         { -1, 0 },
-         { +1, 0 },
-         { 0, +1 }
-       };
+       can_change[xx][yy] = FALSE;     /* do not change empty borders */
 
-       if (IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
-         DrawGraphic(SCREENX(x),SCREENY(y), GFX_SP_BUG_ACTIVE + SimpleRND(4));
+       continue;
+      }
 
-       for (i=0; i<4; i++)
-       {
-         int xx = x + xy[i][0], yy = y + xy[i][1];
+      if (!IN_LEV_FIELD(ex, ey))
+      {
+       can_change[xx][yy] = FALSE;
+       complete_change = FALSE;
 
-         if (IS_PLAYER(xx, yy))
-         {
-           PlaySoundLevel(x, y, SND_SP_BUGGY_BASE_ACTIVATING);
-           break;
-         }
-       }
+       continue;
+      }
+
+      e = Feld[ex][ey];
+
+      if (IS_MOVING(ex, ey) || IS_BLOCKED(ex, ey))
+       e = MovingOrBlocked2Element(ex, ey);
+
+      half_destructible = (IS_FREE(ex, ey) || IS_DIGGABLE(e));
+
+      if ((change->power <= CP_NON_DESTRUCTIVE  && !IS_FREE(ex, ey)) ||
+         (change->power <= CP_HALF_DESTRUCTIVE && !half_destructible) ||
+         (change->power <= CP_FULL_DESTRUCTIVE && IS_INDESTRUCTIBLE(e)))
+      {
+       can_change[xx][yy] = FALSE;
+       complete_change = FALSE;
+      }
+    }
+
+    if (!change->only_complete || complete_change)
+    {
+      boolean something_has_changed = FALSE;
 
+      if (change->only_complete && change->use_random_change &&
+         RND(100) < change->random)
        return;
+
+      for (yy = 0; yy < 3; yy++) for(xx = 0; xx < 3 ; xx++)
+      {
+       int ex = x + xx - 1;
+       int ey = y + yy - 1;
+
+       if (can_change[xx][yy] && (!change->use_random_change ||
+                                  RND(100) < change->random))
+       {
+         if (IS_MOVING(ex, ey) || IS_BLOCKED(ex, ey))
+           RemoveMovingField(ex, ey);
+
+         ChangeElementNowExt(ex, ey, change->content[xx][yy]);
+
+         something_has_changed = TRUE;
+
+         /* for symmetry reasons, stop newly created border elements */
+         if (ex != x || ey != y)
+           Stop[ex][ey] = TRUE;
+       }
       }
 
-      Feld[x][y] = EL_SP_BUG;
-      DrawLevelField(x, y);
+      if (something_has_changed)
+       PlaySoundLevelElementAction(x, y, element, ACTION_CHANGING);
     }
   }
+  else
+  {
+    ChangeElementNowExt(x, y, change->target_element);
+
+    PlaySoundLevelElementAction(x, y, element, ACTION_CHANGING);
+  }
 }
 
-static void CheckTrap(int x, int y)
+static void ChangeElement(int x, int y)
 {
+#if 1
+  int element = MovingOrBlocked2Element(x, y);
+#else
   int element = Feld[x][y];
+#endif
+  struct ElementChangeInfo *change = &element_info[element].change;
 
-  if (element == EL_TRAP_INACTIVE)
+  if (ChangeDelay[x][y] == 0)          /* initialize element change */
   {
-    if (!MovDelay[x][y])       /* wait some time before activating trap */
-      MovDelay[x][y] = 2 * FRAMES_PER_SECOND + RND(5 * FRAMES_PER_SECOND);
+#if 1
+    ChangeDelay[x][y] = (    change->delay_fixed  * change->delay_frames +
+                        RND(change->delay_random * change->delay_frames)) + 1;
+#else
+    ChangeDelay[x][y] = changing_element[element].change_delay + 1;
 
-    if (MovDelay[x][y])
+    if (IS_CUSTOM_ELEMENT(element) && HAS_CHANGE_EVENT(element, CE_DELAY))
     {
-      MovDelay[x][y]--;
-      if (MovDelay[x][y])
-       return;
+      int max_random_delay = element_info[element].change.delay_random;
+      int delay_frames = element_info[element].change.delay_frames;
 
-      Feld[x][y] = EL_TRAP_ACTIVE;
-      PlaySoundLevel(x, y, SND_TRAP_ACTIVATING);
+      ChangeDelay[x][y] += RND(max_random_delay * delay_frames);
     }
+#endif
+
+    ResetGfxAnimation(x, y);
+    ResetRandomAnimationValue(x, y);
+
+#if 1
+    if (change->pre_change_function)
+      change->pre_change_function(x, y);
+#else
+    if (changing_element[element].pre_change_function)
+      changing_element[element].pre_change_function(x, y);
+#endif
   }
-  else if (element == EL_TRAP_ACTIVE)
+
+  ChangeDelay[x][y]--;
+
+  if (ChangeDelay[x][y] != 0)          /* continue element change */
   {
-    int delay = 4;
-    int num_frames = 8;
+    int graphic = el_act_dir2img(element, GfxAction[x][y], MovDir[x][y]);
 
-    if (!MovDelay[x][y])       /* start activating trap */
-      MovDelay[x][y] = num_frames * delay;
+    if (IS_ANIMATED(graphic))
+      DrawLevelGraphicAnimationIfNeeded(x, y, graphic);
 
-    if (MovDelay[x][y])
-    {
-      MovDelay[x][y]--;
+#if 1
+    if (change->change_function)
+      change->change_function(x, y);
+#else
+    if (changing_element[element].change_function)
+      changing_element[element].change_function(x, y);
+#endif
+  }
+  else                                 /* finish element change */
+  {
+#if 0
+    int next_element = changing_element[element].next_element;
+#endif
 
-      if (MovDelay[x][y])
-      {
-       if (!(MovDelay[x][y] % delay))
-       {
-         int phase = MovDelay[x][y]/delay;
+    if (IS_MOVING(x, y))               /* never change a running system ;-) */
+    {
+      ChangeDelay[x][y] = 1;           /* try change after next move step */
 
-         if (phase >= num_frames/2)
-           phase = num_frames - phase;
+      return;
+    }
 
-         if (IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
-         {
-           DrawGraphic(SCREENX(x),SCREENY(y), GFX_TRAP_INACTIVE + phase - 1);
-           ErdreichAnbroeckeln(SCREENX(x), SCREENY(y));
-         }
-       }
+#if 1
+    ChangeElementNow(x, y, element);
 
-       return;
-      }
+    if (change->post_change_function)
+      change->post_change_function(x, y);
+#else
+    if (next_element != EL_UNDEFINED)
+      ChangeElementNow(x, y, next_element);
+    else
+      ChangeElementNow(x, y, element_info[element].change.target_element);
 
-      Feld[x][y] = EL_TRAP_INACTIVE;
-      DrawLevelField(x, y);
-    }
+    if (changing_element[element].post_change_function)
+      changing_element[element].post_change_function(x, y);
+#endif
   }
 }
 
-static void DrawBeltAnimation(int x, int y, int element)
+static boolean CheckTriggeredElementChange(int lx, int ly, int trigger_element,
+                                          int trigger_event)
 {
-  int belt_nr = getBeltNrFromElement(element);
-  int belt_dir = game.belt_dir[belt_nr];
+  int i, x, y;
 
-  if (belt_dir != MV_NO_MOVING)
+  if (!(trigger_events[trigger_element] & CH_EVENT_BIT(trigger_event)))
+    return FALSE;
+
+  for (i=0; i<MAX_NUM_ELEMENTS; i++)
   {
-    int delay = 2;
-    int mode = (belt_dir == MV_LEFT ? ANIM_NORMAL : ANIM_REVERSE);
-    int graphic = el2gfx(element) + (belt_dir == MV_LEFT ? 0 : 7);
+    if (!CAN_CHANGE(i) || !HAS_CHANGE_EVENT(i, trigger_event) ||
+       element_info[i].change.trigger_element != trigger_element)
+      continue;
 
-    DrawGraphicAnimation(x, y, graphic, 8, delay, mode);
+    for (y=0; y<lev_fieldy; y++) for (x=0; x<lev_fieldx; x++)
+    {
+      if (x == lx && y == ly)  /* do not change trigger element itself */
+       continue;
+
+      if (Changing[x][y])      /* do not change just changing elements */
+       continue;
 
-    if (!(FrameCounter % 2))
-      PlaySoundLevel(x, y, SND_CONVEYOR_BELT_RUNNING);
+      if (Feld[x][y] == i)
+      {
+       ChangeDelay[x][y] = 1;
+       ChangeElement(x, y);
+      }
+    }
   }
+
+  return TRUE;
+}
+
+static boolean CheckElementChange(int x, int y, int element, int trigger_event)
+{
+  if (!CAN_CHANGE(element) || !HAS_CHANGE_EVENT(element, trigger_event))
+    return FALSE;
+
+  if (Feld[x][y] == EL_BLOCKED)
+    Blocked2Moving(x, y, &x, &y);
+
+  ChangeDelay[x][y] = 1;
+  ChangeElement(x, y);
+
+  return TRUE;
 }
 
 static void PlayerActions(struct PlayerInfo *player, byte player_action)
 {
   static byte stored_player_action[MAX_PLAYERS];
   static int num_stored_actions = 0;
-#if 0
-  static boolean save_tape_entry = FALSE;
-#endif
   boolean moved = FALSE, snapped = FALSE, bombed = FALSE;
   int left     = player_action & JOY_LEFT;
   int right    = player_action & JOY_RIGHT;
@@ -4460,11 +5432,6 @@ static void PlayerActions(struct PlayerInfo *player, byte player_action)
 
   if (player_action)
   {
-#if 0
-    save_tape_entry = TRUE;
-#endif
-    player->frame_reset_delay = 0;
-
     if (button1)
       snapped = SnapField(player, dx, dy);
     else
@@ -4483,20 +5450,7 @@ static void PlayerActions(struct PlayerInfo *player, byte player_action)
       }
     }
 
-#if 0
-    if (tape.recording && (moved || snapped || bombed))
-    {
-      if (bombed && !moved)
-       player_action &= JOY_BUTTON;
-
-      stored_player_action[player->index_nr] = player_action;
-      save_tape_entry = TRUE;
-    }
-    else if (tape.playing && snapped)
-      SnapField(player, 0, 0);                 /* stop snapping */
-#else
     stored_player_action[player->index_nr] = player_action;
-#endif
   }
   else
   {
@@ -4506,85 +5460,36 @@ static void PlayerActions(struct PlayerInfo *player, byte player_action)
     SnapField(player, 0, 0);
     CheckGravityMovement(player);
 
-#if 1
-    if (player->MovPos == 0)   /* needed for tape.playing */
-      player->is_moving = FALSE;
-#endif
+    if (player->MovPos == 0)
+    {
 #if 0
-    if (player->MovPos == 0)   /* needed for tape.playing */
-      player->last_move_dir = MV_NO_MOVING;
-
-    /* !!! CHECK THIS AGAIN !!!
-       (Seems to be needed for some EL_ROBOT stuff, but breaks
-       tapes when walking through pipes!)
-    */
+      printf("Trying... Player frame reset\n");
+#endif
 
-    /* it seems that "player->last_move_dir" is misused as some sort of
-       "player->is_just_moving_in_this_moment", which is needed for the
-       robot stuff (robots don't kill players when they are moving)
-    */
-#endif 
+      InitPlayerGfxAnimation(player, ACTION_DEFAULT, player->MovDir);
+    }
 
-    if (++player->frame_reset_delay > player->move_delay_value)
-      player->Frame = 0;
+    if (player->MovPos == 0)   /* needed for tape.playing */
+      player->is_moving = FALSE;
   }
 
-#if 0
-  if (tape.recording && num_stored_actions >= MAX_PLAYERS && save_tape_entry)
-  {
-    TapeRecordAction(stored_player_action);
-    num_stored_actions = 0;
-    save_tape_entry = FALSE;
-  }
-#else
   if (tape.recording && num_stored_actions >= MAX_PLAYERS)
   {
     TapeRecordAction(stored_player_action);
     num_stored_actions = 0;
   }
-#endif
-
-#if 0
-  if (tape.playing && !tape.pausing && !player_action &&
-      tape.counter < tape.length)
-  {
-    int jx = player->jx, jy = player->jy;
-    int next_joy =
-      tape.pos[tape.counter].action[player->index_nr] & (JOY_LEFT|JOY_RIGHT);
-
-    if ((next_joy == JOY_LEFT || next_joy == JOY_RIGHT) &&
-       (player->MovDir != JOY_UP && player->MovDir != JOY_DOWN))
-    {
-      int dx = (next_joy == JOY_LEFT ? -1 : +1);
-
-      if (IN_LEV_FIELD(jx+dx, jy) && IS_PUSHABLE(Feld[jx+dx][jy]))
-      {
-       int el = Feld[jx+dx][jy];
-       int push_delay = (IS_SB_ELEMENT(el) || el == EL_SONDE ? 2 :
-                         (el == EL_BALLOON || el == EL_SPRING) ? 0 : 10);
-
-       if (tape.delay_played + push_delay >= tape.pos[tape.counter].delay)
-       {
-         player->MovDir = next_joy;
-         player->Frame = FrameCounter % 4;
-         player->Pushing = TRUE;
-       }
-      }
-    }
-  }
-#endif
 }
 
 void GameActions()
 {
   static unsigned long action_delay = 0;
   unsigned long action_delay_value;
-  int sieb_x = 0, sieb_y = 0;
-  int i, x, y, element;
+  int magic_wall_x = 0, magic_wall_y = 0;
+  int i, x, y, element, graphic;
   byte *recorded_player_action;
   byte summarized_player_action = 0;
 
-  if (game_status != PLAYING)
+  if (game_status != GAME_MODE_PLAYING)
     return;
 
   action_delay_value =
@@ -4610,7 +5515,7 @@ void GameActions()
     HandleNetworking();
 #endif
 
-    if (game_status != PLAYING)
+    if (game_status != GAME_MODE_PLAYING)
       return;
 
     if (!network_player_action_received)
@@ -4663,31 +5568,37 @@ void GameActions()
 
   ScrollScreen(NULL, SCROLL_GO_ON);
 
-
-
-#ifdef DEBUG
 #if 0
-  if (TimeFrames == 0 && local_player->active)
-  {
-    extern unsigned int last_RND();
-
-    printf("DEBUG: %03d last RND was %d \t [state checksum is %d]\n",
-          TimePlayed, last_RND(), getStateCheckSum(TimePlayed));
-  }
-#endif
-#endif
+  FrameCounter++;
+  TimeFrames++;
 
-#ifdef DEBUG
-#if 0
-  if (GameFrameDelay >= 500)
-    printf("FrameCounter == %d\n", FrameCounter);
-#endif
+  for (i=0; i<MAX_PLAYERS; i++)
+    stored_player[i].Frame++;
 #endif
 
+#if 1
+  if (game.engine_version < RELEASE_IDENT(2,2,0,7))
+  {
+    for (i=0; i<MAX_PLAYERS; i++)
+    {
+      struct PlayerInfo *player = &stored_player[i];
+      int x = player->jx;
+      int y = player->jy;
 
+      if (player->active && player->Pushing && player->is_moving &&
+         IS_MOVING(x, y))
+      {
+       ContinueMoving(x, y);
 
-  FrameCounter++;
-  TimeFrames++;
+       /* continue moving after pushing (this is actually a bug) */
+       if (!IS_MOVING(x, y))
+       {
+         Stop[x][y] = FALSE;
+       }
+      }
+    }
+  }
+#endif
 
   for (y=0; y<lev_fieldy; y++) for (x=0; x<lev_fieldx; x++)
   {
@@ -4695,6 +5606,18 @@ void GameActions()
     if (JustStopped[x][y] > 0)
       JustStopped[x][y]--;
 
+    GfxFrame[x][y]++;
+
+#if 1
+    /* reset finished pushing action (not done in ContinueMoving() to allow
+       continous pushing animation for elements without push delay) */
+    if (GfxAction[x][y] == ACTION_PUSHING && !IS_MOVING(x, y))
+    {
+      ResetGfxAnimation(x, y);
+      DrawLevelField(x, y);
+    }
+#endif
+
 #if DEBUG
     if (IS_BLOCKED(x, y))
     {
@@ -4715,28 +5638,107 @@ void GameActions()
   for (y=0; y<lev_fieldy; y++) for (x=0; x<lev_fieldx; x++)
   {
     element = Feld[x][y];
+#if 1
+    graphic = el_act_dir2img(element, GfxAction[x][y], MovDir[x][y]);
+#else
+    graphic = el2img(element);
+#endif
+
+#if 0
+    if (element == -1)
+    {
+      printf("::: %d,%d: %d [%d]\n", x, y, element, FrameCounter);
+
+      element = graphic = 0;
+    }
+#endif
+
+    if (graphic_info[graphic].anim_global_sync)
+      GfxFrame[x][y] = FrameCounter;
+
+    if (ANIM_MODE(graphic) == ANIM_RANDOM &&
+       IS_NEXT_FRAME(GfxFrame[x][y], graphic))
+      ResetRandomAnimationValue(x, y);
+
+    SetRandomAnimationValue(x, y);
+
+#if 1
+    PlaySoundLevelActionIfLoop(x, y, GfxAction[x][y]);
+#endif
 
     if (IS_INACTIVE(element))
+    {
+      if (IS_ANIMATED(graphic))
+       DrawLevelGraphicAnimationIfNeeded(x, y, graphic);
+
       continue;
+    }
+
+#if 1
+    /* this may take place after moving, so 'element' may have changed */
+    if (IS_CHANGING(x, y))
+    {
+      ChangeElement(x, y);
+      element = Feld[x][y];
+      graphic = el_act_dir2img(element, GfxAction[x][y], MovDir[x][y]);
+    }
+#endif
 
     if (!IS_MOVING(x, y) && (CAN_FALL(element) || CAN_MOVE(element)))
     {
       StartMoving(x, y);
 
+#if 1
+      graphic = el_act_dir2img(element, GfxAction[x][y], MovDir[x][y]);
+#if 0
+      if (element == EL_MOLE)
+       printf("::: %d, %d, %d [%d]\n",
+              IS_ANIMATED(graphic), IS_MOVING(x, y), Stop[x][y],
+              GfxAction[x][y]);
+#endif
+#if 0
+      if (element == EL_YAMYAM)
+       printf("::: %d, %d, %d\n",
+              IS_ANIMATED(graphic), IS_MOVING(x, y), Stop[x][y]);
+#endif
+#endif
+
+      if (IS_ANIMATED(graphic) &&
+         !IS_MOVING(x, y) &&
+         !Stop[x][y])
+      {
+       DrawLevelGraphicAnimationIfNeeded(x, y, graphic);
+
+#if 0
+       if (element == EL_MOLE)
+         printf("::: %d, %d\n", graphic, GfxFrame[x][y]);
+#endif
+      }
+
       if (IS_GEM(element) || element == EL_SP_INFOTRON)
        EdelsteinFunkeln(x, y);
     }
+    else if ((element == EL_ACID ||
+             element == EL_EXIT_OPEN ||
+             element == EL_SP_EXIT_OPEN ||
+             element == EL_SP_TERMINAL ||
+             element == EL_SP_TERMINAL_ACTIVE ||
+             element == EL_EXTRA_TIME ||
+             element == EL_SHIELD_NORMAL ||
+             element == EL_SHIELD_DEADLY) &&
+            IS_ANIMATED(graphic))
+      DrawLevelGraphicAnimationIfNeeded(x, y, graphic);
     else if (IS_MOVING(x, y))
       ContinueMoving(x, y);
     else if (IS_ACTIVE_BOMB(element))
       CheckDynamite(x, y);
 #if 0
-    else if (element == EL_EXPLODING && !game.explosions_delayed)
-      Explode(x, y, Frame[x][y], EX_NORMAL);
+    else if (element == EL_EXPLOSION && !game.explosions_delayed)
+      Explode(x, y, ExplodePhase[x][y], EX_NORMAL);
 #endif
-    else if (element == EL_AMOEBING)
+    else if (element == EL_AMOEBA_GROWING)
       AmoebeWaechst(x, y);
-    else if (element == EL_DEAMOEBING)
+    else if (element == EL_AMOEBA_SHRINKING)
       AmoebaDisappearing(x, y);
 
 #if !USE_NEW_AMOEBA_CODE
@@ -4744,97 +5746,54 @@ void GameActions()
       AmoebeAbleger(x, y);
 #endif
 
-    else if (element == EL_LIFE || element == EL_LIFE_ASYNC)
+    else if (element == EL_GAME_OF_LIFE || element == EL_BIOMAZE)
       Life(x, y);
-    else if (element == EL_ABLENK_EIN)
-      RobotWheel(x, y);
-    else if (element == EL_TIMEGATE_SWITCH_ON)
-      TimegateWheel(x, y);
-    else if (element == EL_SALZSAEURE)
-      Blubber(x, y);
-    else if (element == EL_BLURB_LEFT || element == EL_BLURB_RIGHT)
-      Blurb(x, y);
-    else if (element == EL_CRACKINGNUT)
-      NussKnacken(x, y);
-    else if (element == EL_PEARL_BREAKING)
-      BreakingPearl(x, y);
-    else if (element == EL_AUSGANG_ZU)
-      AusgangstuerPruefen(x, y);
-    else if (element == EL_AUSGANG_ACT)
-      AusgangstuerOeffnen(x, y);
-    else if (element == EL_AUSGANG_AUF)
-      AusgangstuerBlinken(x, y);
-    else if (element == EL_MAUERND)
+    else if (element == EL_EXIT_CLOSED)
+      CheckExit(x, y);
+    else if (element == EL_SP_EXIT_CLOSED)
+      CheckExitSP(x, y);
+    else if (element == EL_EXPANDABLE_WALL_GROWING)
       MauerWaechst(x, y);
-    else if (element == EL_MAUER_LEBT ||
-            element == EL_MAUER_X ||
-            element == EL_MAUER_Y ||
-            element == EL_MAUER_XY)
+    else if (element == EL_EXPANDABLE_WALL ||
+            element == EL_EXPANDABLE_WALL_HORIZONTAL ||
+            element == EL_EXPANDABLE_WALL_VERTICAL ||
+            element == EL_EXPANDABLE_WALL_ANY)
       MauerAbleger(x, y);
-    else if (element == EL_BURNING)
+    else if (element == EL_FLAMES)
       CheckForDragon(x, y);
-    else if (element == EL_SP_BUG || element == EL_SP_BUG_ACTIVE)
-      CheckBuggyBase(x, y);
-    else if (element == EL_TRAP_INACTIVE || element == EL_TRAP_ACTIVE)
-      CheckTrap(x, y);
-    else if (element == EL_SP_TERMINAL)
-      DrawGraphicAnimation(x, y, GFX2_SP_TERMINAL, 7, 12, ANIM_NORMAL);
-    else if (element == EL_SP_TERMINAL_ACTIVE)
-      DrawGraphicAnimation(x, y, GFX2_SP_TERMINAL_ACTIVE, 7, 4, ANIM_NORMAL);
-    else if (IS_BELT(element))
-      DrawBeltAnimation(x, y, element);
-    else if (element == EL_SWITCHGATE_OPENING)
-      OpenSwitchgate(x, y);
-    else if (element == EL_SWITCHGATE_CLOSING)
-      CloseSwitchgate(x, y);
-    else if (element == EL_TIMEGATE_OPENING)
-      OpenTimegate(x, y);
-    else if (element == EL_TIMEGATE_CLOSING)
-      CloseTimegate(x, y);
-    else if (element == EL_EXTRA_TIME)
-      DrawGraphicAnimation(x, y, GFX_EXTRA_TIME, 6, 4, ANIM_NORMAL);
-    else if (element == EL_SHIELD_PASSIVE)
-    {
-      DrawGraphicAnimation(x, y, GFX_SHIELD_PASSIVE, 6, 4, ANIM_NORMAL);
 #if 0
-      if (!(FrameCounter % 4))
-       PlaySoundLevel(x, y, SND_SHIELD_PASSIVE_ACTIVATED);
+    else if (IS_AUTO_CHANGING(element))
+      ChangeElement(x, y);
 #endif
-    }
-    else if (element == EL_SHIELD_ACTIVE)
-    {
-      DrawGraphicAnimation(x, y, GFX_SHIELD_ACTIVE, 6, 4, ANIM_NORMAL);
+    else if (element == EL_EXPLOSION)
+      ;        /* drawing of correct explosion animation is handled separately */
+    else if (IS_ANIMATED(graphic) && !IS_CHANGING(x, y))
+      DrawLevelGraphicAnimationIfNeeded(x, y, graphic);
+
 #if 0
-      if (!(FrameCounter % 4))
-       PlaySoundLevel(x, y, SND_SHIELD_ACTIVE_ACTIVATED);
+    /* this may take place after moving, so 'element' may have changed */
+    if (IS_AUTO_CHANGING(Feld[x][y]))
+      ChangeElement(x, y);
 #endif
-    }
+
+    if (IS_BELT_ACTIVE(element))
+      PlaySoundLevelAction(x, y, ACTION_ACTIVE);
 
     if (game.magic_wall_active)
     {
-      boolean sieb = FALSE;
       int jx = local_player->jx, jy = local_player->jy;
 
-      if (element == EL_MAGIC_WALL_FULL ||
-         element == EL_MAGIC_WALL_EMPTY ||
-         element == EL_MAGIC_WALL_EMPTYING)
-      {
-       SiebAktivieren(x, y, 1);
-       sieb = TRUE;
-      }
-      else if (element == EL_MAGIC_WALL_BD_FULL ||
-              element == EL_MAGIC_WALL_BD_EMPTY ||
-              element == EL_MAGIC_WALL_BD_EMPTYING)
-      {
-       SiebAktivieren(x, y, 2);
-       sieb = TRUE;
-      }
-
       /* play the element sound at the position nearest to the player */
-      if (sieb && ABS(x-jx)+ABS(y-jy) < ABS(sieb_x-jx)+ABS(sieb_y-jy))
+      if ((element == EL_MAGIC_WALL_FULL ||
+          element == EL_MAGIC_WALL_ACTIVE ||
+          element == EL_MAGIC_WALL_EMPTYING ||
+          element == EL_BD_MAGIC_WALL_FULL ||
+          element == EL_BD_MAGIC_WALL_ACTIVE ||
+          element == EL_BD_MAGIC_WALL_EMPTYING) &&
+         ABS(x-jx) + ABS(y-jy) < ABS(magic_wall_x-jx) + ABS(magic_wall_y-jy))
       {
-       sieb_x = x;
-       sieb_y = y;
+       magic_wall_x = x;
+       magic_wall_y = y;
       }
     }
   }
@@ -4858,18 +5817,19 @@ void GameActions()
 #endif
       element = Feld[x][y];
 
+      /* !!! extend EL_SAND to anything diggable (but maybe not SP_BASE) !!! */
       if (!IS_PLAYER(x,y) &&
-         (element == EL_LEERRAUM ||
-          element == EL_ERDREICH ||
-          element == EL_MORAST_LEER ||
-          element == EL_BLURB_LEFT ||
-          element == EL_BLURB_RIGHT))
+         (element == EL_EMPTY ||
+          element == EL_SAND ||
+          element == EL_QUICKSAND_EMPTY ||
+          element == EL_ACID_SPLASH_LEFT ||
+          element == EL_ACID_SPLASH_RIGHT))
       {
-       if ((IN_LEV_FIELD(x, y-1) && Feld[x][y-1] == EL_AMOEBE_NASS) ||
-           (IN_LEV_FIELD(x-1, y) && Feld[x-1][y] == EL_AMOEBE_NASS) ||
-           (IN_LEV_FIELD(x+1, y) && Feld[x+1][y] == EL_AMOEBE_NASS) ||
-           (IN_LEV_FIELD(x, y+1) && Feld[x][y+1] == EL_AMOEBE_NASS))
-         Feld[x][y] = EL_TROPFEN;
+       if ((IN_LEV_FIELD(x, y-1) && Feld[x][y-1] == EL_AMOEBA_WET) ||
+           (IN_LEV_FIELD(x-1, y) && Feld[x-1][y] == EL_AMOEBA_WET) ||
+           (IN_LEV_FIELD(x+1, y) && Feld[x+1][y] == EL_AMOEBA_WET) ||
+           (IN_LEV_FIELD(x, y+1) && Feld[x][y+1] == EL_AMOEBA_WET))
+         Feld[x][y] = EL_AMOEBA_DROP;
       }
 
       random = random * 129 + 1;
@@ -4889,8 +5849,8 @@ void GameActions()
 
       if (ExplodeField[x][y])
        Explode(x, y, EX_PHASE_START, ExplodeField[x][y]);
-      else if (element == EL_EXPLODING)
-       Explode(x, y, Frame[x][y], EX_NORMAL);
+      else if (element == EL_EXPLOSION)
+       Explode(x, y, ExplodePhase[x][y], EX_NORMAL);
 
       ExplodeField[x][y] = EX_NO_EXPLOSION;
     }
@@ -4902,14 +5862,14 @@ void GameActions()
   {
     if (!(game.magic_wall_time_left % 4))
     {
-      int element = Feld[sieb_x][sieb_y];
+      int element = Feld[magic_wall_x][magic_wall_y];
 
-      if (element == EL_MAGIC_WALL_BD_FULL ||
-         element == EL_MAGIC_WALL_BD_EMPTY ||
-         element == EL_MAGIC_WALL_BD_EMPTYING)
-       PlaySoundLevel(sieb_x, sieb_y, SND_BD_MAGIC_WALL_RUNNING);
+      if (element == EL_BD_MAGIC_WALL_FULL ||
+         element == EL_BD_MAGIC_WALL_ACTIVE ||
+         element == EL_BD_MAGIC_WALL_EMPTYING)
+       PlaySoundLevel(magic_wall_x, magic_wall_y, SND_BD_MAGIC_WALL_ACTIVE);
       else
-       PlaySoundLevel(sieb_x, sieb_y, SND_MAGIC_WALL_RUNNING);
+       PlaySoundLevel(magic_wall_x, magic_wall_y, SND_MAGIC_WALL_ACTIVE);
     }
 
     if (game.magic_wall_time_left > 0)
@@ -4921,16 +5881,16 @@ void GameActions()
        {
          element = Feld[x][y];
 
-         if (element == EL_MAGIC_WALL_EMPTY ||
+         if (element == EL_MAGIC_WALL_ACTIVE ||
              element == EL_MAGIC_WALL_FULL)
          {
            Feld[x][y] = EL_MAGIC_WALL_DEAD;
            DrawLevelField(x, y);
          }
-         else if (element == EL_MAGIC_WALL_BD_EMPTY ||
-                  element == EL_MAGIC_WALL_BD_FULL)
+         else if (element == EL_BD_MAGIC_WALL_ACTIVE ||
+                  element == EL_BD_MAGIC_WALL_FULL)
          {
-           Feld[x][y] = EL_MAGIC_WALL_BD_DEAD;
+           Feld[x][y] = EL_BD_MAGIC_WALL_DEAD;
            DrawLevelField(x, y);
          }
        }
@@ -4944,23 +5904,8 @@ void GameActions()
   {
     game.light_time_left--;
 
-    if (game.light_time_left == 0)
-    {
-      for (y=0; y<lev_fieldy; y++) for (x=0; x<lev_fieldx; x++)
-      {
-       element = Feld[x][y];
-
-       if (element == EL_LIGHT_SWITCH_ON)
-       {
-         Feld[x][y] = EL_LIGHT_SWITCH_OFF;
-         DrawLevelField(x, y);
-       }
-       else if (element == EL_INVISIBLE_STEEL ||
-                element == EL_UNSICHTBAR ||
-                element == EL_SAND_INVISIBLE)
-         DrawLevelField(x, y);
-      }
-    }
+    if (game.light_time_left == 0)
+      RedrawAllLightSwitchesAndInvisibleElements();
   }
 
   if (game.timegate_time_left > 0)
@@ -4977,10 +5922,10 @@ void GameActions()
 
     if (SHIELD_ON(player))
     {
-      if (player->shield_active_time_left)
-       PlaySoundLevel(player->jx, player->jy, SND_SHIELD_ACTIVE_ACTIVATED);
-      else if (player->shield_passive_time_left)
-       PlaySoundLevel(player->jx, player->jy, SND_SHIELD_PASSIVE_ACTIVATED);
+      if (player->shield_deadly_time_left)
+       PlaySoundLevel(player->jx, player->jy, SND_SHIELD_DEADLY_ACTIVE);
+      else if (player->shield_normal_time_left)
+       PlaySoundLevel(player->jx, player->jy, SND_SHIELD_NORMAL_ACTIVE);
     }
   }
 
@@ -4995,10 +5940,10 @@ void GameActions()
 
       if (SHIELD_ON(player))
       {
-       player->shield_passive_time_left--;
+       player->shield_normal_time_left--;
 
-       if (player->shield_active_time_left > 0)
-         player->shield_active_time_left--;
+       if (player->shield_deadly_time_left > 0)
+         player->shield_deadly_time_left--;
       }
     }
 
@@ -5010,16 +5955,16 @@ void GameActions()
       TimeLeft--;
 
       if (TimeLeft <= 10 && setup.time_limit)
-       PlaySoundStereo(SND_GAME_RUNNING_OUT_OF_TIME, SOUND_MAX_RIGHT);
+       PlaySoundStereo(SND_GAME_RUNNING_OUT_OF_TIME, SOUND_MIDDLE);
 
-      DrawText(DX_TIME, DY_TIME, int2str(TimeLeft, 3), FS_SMALL, FC_YELLOW);
+      DrawText(DX_TIME, DY_TIME, int2str(TimeLeft, 3), FONT_TEXT_2);
 
       if (!TimeLeft && setup.time_limit)
        for (i=0; i<MAX_PLAYERS; i++)
          KillHero(&stored_player[i]);
     }
     else if (level.time == 0 && !AllPlayersGone) /* level without time limit */
-      DrawText(DX_TIME, DY_TIME, int2str(TimePlayed, 3), FS_SMALL, FC_YELLOW);
+      DrawText(DX_TIME, DY_TIME, int2str(TimePlayed, 3), FONT_TEXT_2);
   }
 
   DrawAllPlayers();
@@ -5042,6 +5987,33 @@ void GameActions()
 
     redraw_mask |= REDRAW_FPS;
   }
+
+#if 0
+  if (stored_player[0].jx != stored_player[0].last_jx ||
+      stored_player[0].jy != stored_player[0].last_jy)
+    printf("::: %d, %d, %d, %d, %d\n",
+          stored_player[0].MovDir,
+          stored_player[0].MovPos,
+          stored_player[0].GfxPos,
+          stored_player[0].Frame,
+          stored_player[0].StepFrame);
+#endif
+
+#if 1
+  FrameCounter++;
+  TimeFrames++;
+
+  for (i=0; i<MAX_PLAYERS; i++)
+  {
+    int move_frames =
+      MOVE_DELAY_NORMAL_SPEED /  stored_player[i].move_delay_value;
+
+    stored_player[i].Frame += move_frames;
+
+    if (stored_player[i].MovPos != 0)
+      stored_player[i].StepFrame += move_frames;
+  }
+#endif
 }
 
 static boolean AllPlayersInSight(struct PlayerInfo *player, int x, int y)
@@ -5102,6 +6074,7 @@ void ScrollLevel(int dx, int dy)
     for (y=BY1; y<=BY2; y++)
       DrawScreenField(x, y);
   }
+
   if (dy)
   {
     y = (dy == 1 ? BY1 : BY2);
@@ -5131,15 +6104,23 @@ static void CheckGravityMovement(struct PlayerInfo *player)
     boolean player_is_moving_to_valid_field =
       (IN_LEV_FIELD(new_jx, new_jy) &&
        (Feld[new_jx][new_jy] == EL_SP_BASE ||
-       Feld[new_jx][new_jy] == EL_ERDREICH));
+       Feld[new_jx][new_jy] == EL_SAND));
+    /* !!! extend EL_SAND to anything diggable !!! */
 
     if (field_under_player_is_free &&
        !player_is_moving_to_valid_field &&
-       !IS_TUBE(Feld[jx][jy]))
+       !IS_WALKABLE_INSIDE(Feld[jx][jy]))
       player->programmed_action = MV_DOWN;
   }
 }
 
+/*
+  MoveFigureOneStep()
+  -----------------------------------------------------------------------------
+  dx, dy:              direction (non-diagonal) to try to move the player to
+  real_dx, real_dy:    direction as read from input device (can be diagonal)
+*/
+
 boolean MoveFigureOneStep(struct PlayerInfo *player,
                          int dx, int dy, int real_dx, int real_dy)
 {
@@ -5168,14 +6149,14 @@ boolean MoveFigureOneStep(struct PlayerInfo *player,
   element = MovingOrBlocked2ElementIfNotLeaving(new_jx, new_jy);
 #endif
 
-  if (DONT_GO_TO(element))
+  if (DONT_RUN_INTO(element))
   {
-    if (element == EL_SALZSAEURE && dx == 0 && dy == 1)
+    if (element == EL_ACID && dx == 0 && dy == 1)
     {
-      Blurb(jx, jy);
-      Feld[jx][jy] = EL_SPIELFIGUR;
+      SplashAcid(jx, jy);
+      Feld[jx][jy] = EL_PLAYER_1;
       InitMovingField(jx, jy, MV_DOWN);
-      Store[jx][jy] = EL_SALZSAEURE;
+      Store[jx][jy] = EL_ACID;
       ContinueMoving(jx, jy);
       BuryHero(player);
     }
@@ -5234,7 +6215,8 @@ boolean MoveFigure(struct PlayerInfo *player, int dx, int dy)
     int original_move_delay_value = player->move_delay_value;
 
 #if DEBUG
-    printf("THIS SHOULD ONLY HAPPEN WITH PRE-1.2 LEVEL TAPES.\n");
+    printf("THIS SHOULD ONLY HAPPEN WITH PRE-1.2 LEVEL TAPES. [%ld]\n",
+          tape.counter);
 #endif
 
     /* scroll remaining steps with finest movement resolution */
@@ -5335,10 +6317,16 @@ boolean MoveFigure(struct PlayerInfo *player, int dx, int dy)
     }
   }
 
+#if 0
+#if 1
+  InitPlayerGfxAnimation(player, ACTION_DEFAULT);
+#else
   if (!(moved & MF_MOVING) && !player->Pushing)
     player->Frame = 0;
-  else
-    player->Frame = (player->Frame + 1) % 4;
+#endif
+#endif
+
+  player->StepFrame = 0;
 
   if (moved & MF_MOVING)
   {
@@ -5347,7 +6335,7 @@ boolean MoveFigure(struct PlayerInfo *player, int dx, int dy)
     else if (old_jx == jx && old_jy != jy)
       player->MovDir = (old_jy < jy ? MV_DOWN : MV_UP);
 
-    DrawLevelField(jx, jy);    /* for "ErdreichAnbroeckeln()" */
+    DrawLevelField(jx, jy);    /* for "crumbled sand" */
 
     player->last_move_dir = player->MovDir;
     player->is_moving = TRUE;
@@ -5363,6 +6351,7 @@ boolean MoveFigure(struct PlayerInfo *player, int dx, int dy)
   }
 
   TestIfHeroTouchesBadThing(jx, jy);
+  TestIfPlayerTouchesCustomElement(jx, jy);
 
   if (!player->active)
     RemoveHero(player);
@@ -5384,10 +6373,12 @@ void ScrollFigure(struct PlayerInfo *player, int mode)
     player->actual_frame_counter = FrameCounter;
     player->GfxPos = move_stepsize * (player->MovPos / move_stepsize);
 
-    if (Feld[last_jx][last_jy] == EL_LEERRAUM)
+    if (Feld[last_jx][last_jy] == EL_EMPTY)
       Feld[last_jx][last_jy] = EL_PLAYER_IS_LEAVING;
 
+#if 0
     DrawPlayer(player);
+#endif
     return;
   }
   else if (!FrameReached(&player->actual_frame_counter, 1))
@@ -5397,17 +6388,19 @@ void ScrollFigure(struct PlayerInfo *player, int mode)
   player->GfxPos = move_stepsize * (player->MovPos / move_stepsize);
 
   if (Feld[last_jx][last_jy] == EL_PLAYER_IS_LEAVING)
-    Feld[last_jx][last_jy] = EL_LEERRAUM;
+    Feld[last_jx][last_jy] = EL_EMPTY;
 
   /* before DrawPlayer() to draw correct player graphic for this case */
   if (player->MovPos == 0)
     CheckGravityMovement(player);
 
-  DrawPlayer(player);
+#if 0
+  DrawPlayer(player);  /* needed here only to cleanup last field */
+#endif
 
   if (player->MovPos == 0)
   {
-    if (IS_QUICK_GATE(Feld[last_jx][last_jy]))
+    if (IS_PASSABLE(Feld[last_jx][last_jy]))
     {
       /* continue with normal speed after quickly moving through gate */
       HALVE_PLAYER_SPEED(player);
@@ -5419,11 +6412,13 @@ void ScrollFigure(struct PlayerInfo *player, int mode)
     player->last_jx = jx;
     player->last_jy = jy;
 
-    if (Feld[jx][jy] == EL_AUSGANG_AUF)
+    if (Feld[jx][jy] == EL_EXIT_OPEN ||
+       Feld[jx][jy] == EL_SP_EXIT_OPEN)
     {
       RemoveHero(player);
 
-      if (!local_player->friends_still_needed)
+      if (local_player->friends_still_needed == 0 ||
+         Feld[jx][jy] == EL_SP_EXIT_OPEN)
        player->LevelSolved = player->GameOver = TRUE;
     }
 
@@ -5461,6 +6456,93 @@ void ScrollScreen(struct PlayerInfo *player, int mode)
     ScreenMovDir = MV_NO_MOVING;
 }
 
+void TestIfPlayerTouchesCustomElement(int x, int y)
+{
+  static boolean check_changing = FALSE;
+  static int xy[4][2] =
+  {
+    { 0, -1 },
+    { -1, 0 },
+    { +1, 0 },
+    { 0, +1 }
+  };
+  boolean center_is_player = (IS_PLAYER(x, y));
+  int i;
+
+  /* prevent TestIfPlayerTouchesCustomElement() from looping */
+  if (check_changing)
+    return;
+
+  check_changing = TRUE;
+
+  for (i=0; i<4; i++)
+  {
+    int xx = x + xy[i][0];
+    int yy = y + xy[i][1];
+
+    if (!IN_LEV_FIELD(xx, yy))
+      continue;
+
+    if (center_is_player)
+    {
+      CheckTriggeredElementChange(xx, yy, Feld[xx][yy], CE_OTHER_GETS_TOUCHED);
+      CheckElementChange(xx, yy, Feld[xx][yy], CE_TOUCHED_BY_PLAYER);
+    }
+    else if (IS_PLAYER(xx, yy))
+    {
+      CheckTriggeredElementChange(x, y, Feld[x][y], CE_OTHER_GETS_TOUCHED);
+      CheckElementChange(x, y, Feld[x][y], CE_TOUCHED_BY_PLAYER);
+
+      break;
+    }
+  }
+
+  check_changing = FALSE;
+}
+
+void TestIfElementTouchesCustomElement(int x, int y)
+{
+  static boolean check_changing = FALSE;
+  static int xy[4][2] =
+  {
+    { 0, -1 },
+    { -1, 0 },
+    { +1, 0 },
+    { 0, +1 }
+  };
+  boolean center_is_custom = (IS_CUSTOM_ELEMENT(Feld[x][y]));
+  int i;
+
+  /* prevent TestIfElementTouchesCustomElement() from looping */
+  if (check_changing)
+    return;
+
+  check_changing = TRUE;
+
+  for (i=0; i<4; i++)
+  {
+    int xx = x + xy[i][0];
+    int yy = y + xy[i][1];
+
+    if (!IN_LEV_FIELD(xx, yy))
+      continue;
+
+    if (center_is_custom &&
+       Feld[xx][yy] == element_info[Feld[x][y]].change.trigger_element)
+    {
+      CheckElementChange(x, y, Feld[x][y], CE_OTHER_IS_TOUCHING);
+    }
+
+    if (IS_CUSTOM_ELEMENT(Feld[xx][yy]) &&
+       Feld[x][y] == element_info[Feld[xx][yy]].change.trigger_element)
+    {
+      CheckElementChange(xx, yy, Feld[xx][yy], CE_OTHER_IS_TOUCHING);
+    }
+  }
+
+  check_changing = FALSE;
+}
+
 void TestIfGoodThingHitsBadThing(int good_x, int good_y, int good_move_dir)
 {
   int i, kill_x = -1, kill_y = -1;
@@ -5497,11 +6579,11 @@ void TestIfGoodThingHitsBadThing(int good_x, int good_y, int good_move_dir)
     test_element = MovingOrBlocked2ElementIfNotLeaving(test_x, test_y);
 #endif
 
-    /* 1st case: good thing is moving towards DONT_GO_TO style bad thing;
+    /* 1st case: good thing is moving towards DONT_RUN_INTO style bad thing;
        2nd case: DONT_TOUCH style bad thing does not move away from good thing
     */
-    if ((DONT_GO_TO(test_element) && good_move_dir == test_dir[i]) ||
-       (DONT_TOUCH(test_element) && test_move_dir != test_dir[i]))
+    if ((DONT_RUN_INTO(test_element) && good_move_dir == test_dir[i]) ||
+       (DONT_TOUCH(test_element)    && test_move_dir != test_dir[i]))
     {
       kill_x = test_x;
       kill_y = test_y;
@@ -5515,7 +6597,7 @@ void TestIfGoodThingHitsBadThing(int good_x, int good_y, int good_move_dir)
     {
       struct PlayerInfo *player = PLAYERINFO(good_x, good_y);
 
-      if (player->shield_active_time_left > 0)
+      if (player->shield_deadly_time_left > 0)
        Bang(kill_x, kill_y);
       else if (!PLAYER_PROTECTED(good_x, good_y))
        KillHero(player);
@@ -5544,7 +6626,7 @@ void TestIfBadThingHitsGoodThing(int bad_x, int bad_y, int bad_move_dir)
     MV_DOWN
   };
 
-  if (bad_element == EL_EXPLODING)     /* skip just exploding bad things */
+  if (bad_element == EL_EXPLOSION)     /* skip just exploding bad things */
     return;
 
   for (i=0; i<4; i++)
@@ -5561,11 +6643,11 @@ void TestIfBadThingHitsGoodThing(int bad_x, int bad_y, int bad_move_dir)
 
     test_element = Feld[test_x][test_y];
 
-    /* 1st case: good thing is moving towards DONT_GO_TO style bad thing;
+    /* 1st case: good thing is moving towards DONT_RUN_INTO style bad thing;
        2nd case: DONT_TOUCH style bad thing does not move away from good thing
     */
-    if ((DONT_GO_TO(bad_element) &&  bad_move_dir == test_dir[i]) ||
-       (DONT_TOUCH(bad_element) && test_move_dir != test_dir[i]))
+    if ((DONT_RUN_INTO(bad_element) &&  bad_move_dir == test_dir[i]) ||
+       (DONT_TOUCH(bad_element)    && test_move_dir != test_dir[i]))
     {
       /* good thing is player or penguin that does not move away */
       if (IS_PLAYER(test_x, test_y))
@@ -5579,7 +6661,7 @@ void TestIfBadThingHitsGoodThing(int bad_x, int bad_y, int bad_move_dir)
        kill_y = test_y;
        break;
       }
-      else if (test_element == EL_PINGUIN)
+      else if (test_element == EL_PENGUIN)
       {
        kill_x = test_x;
        kill_y = test_y;
@@ -5612,7 +6694,7 @@ void TestIfBadThingHitsGoodThing(int bad_x, int bad_y, int bad_move_dir)
        ;
 #endif
 
-      if (player->shield_active_time_left > 0)
+      if (player->shield_deadly_time_left > 0)
        Bang(bad_x, bad_y);
       else if (!PLAYER_PROTECTED(kill_x, kill_y))
        KillHero(player);
@@ -5673,8 +6755,8 @@ void TestIfBadThingTouchesOtherBadThing(int bad_x, int bad_y)
       continue;
 
     element = Feld[x][y];
-    if (IS_AMOEBOID(element) || element == EL_LIFE ||
-       element == EL_AMOEBING || element == EL_TROPFEN)
+    if (IS_AMOEBOID(element) || element == EL_GAME_OF_LIFE ||
+       element == EL_AMOEBA_GROWING || element == EL_AMOEBA_DROP)
     {
       kill_x = x;
       kill_y = y;
@@ -5693,12 +6775,12 @@ void KillHero(struct PlayerInfo *player)
   if (!player->active)
     return;
 
-  if (IS_PFORTE(Feld[jx][jy]))
-    Feld[jx][jy] = EL_LEERRAUM;
+  /* remove accessible field at the player's position */
+  Feld[jx][jy] = EL_EMPTY;
 
   /* deactivate shield (else Bang()/Explode() would not work right) */
-  player->shield_passive_time_left = 0;
-  player->shield_active_time_left = 0;
+  player->shield_normal_time_left = 0;
+  player->shield_deadly_time_left = 0;
 
   Bang(jx, jy);
   BuryHero(player);
@@ -5717,7 +6799,11 @@ void BuryHero(struct PlayerInfo *player)
   if (!player->active)
     return;
 
-  PlaySoundLevel(jx, jy, SND_PLAYER_DYING);
+#if 1
+  PlaySoundLevelElementAction(jx, jy, player->element_nr, ACTION_DYING);
+#else
+  PlaySoundLevel(jx, jy, SND_CLASS_PLAYER_DYING);
+#endif
   PlaySoundLevel(jx, jy, SND_GAME_LOSING);
 
   player->GameOver = TRUE;
@@ -5746,11 +6832,50 @@ void RemoveHero(struct PlayerInfo *player)
   ExitY = ZY = jy;
 }
 
+/*
+  =============================================================================
+  checkDiagonalPushing()
+  -----------------------------------------------------------------------------
+  check if diagonal input device direction results in pushing of object
+  (by checking if the alternative direction is walkable, diggable, ...)
+  =============================================================================
+*/
+
+static boolean checkDiagonalPushing(struct PlayerInfo *player,
+                                   int x, int y, int real_dx, int real_dy)
+{
+  int jx, jy, dx, dy, xx, yy;
+
+  if (real_dx == 0 || real_dy == 0)    /* no diagonal direction => push */
+    return TRUE;
+
+  /* diagonal direction: check alternative direction */
+  jx = player->jx;
+  jy = player->jy;
+  dx = x - jx;
+  dy = y - jy;
+  xx = jx + (dx == 0 ? real_dx : 0);
+  yy = jy + (dy == 0 ? real_dy : 0);
+
+  return (!IN_LEV_FIELD(xx, yy) || IS_SOLID_FOR_PUSHING(Feld[xx][yy]));
+}
+
+/*
+  =============================================================================
+  DigField()
+  -----------------------------------------------------------------------------
+  x, y:                        field next to player (non-diagonal) to try to dig to
+  real_dx, real_dy:    direction as read from input device (can be diagonal)
+  =============================================================================
+*/
+
 int DigField(struct PlayerInfo *player,
             int x, int y, int real_dx, int real_dy, int mode)
 {
+  boolean use_spring_bug = (game.engine_version < VERSION_IDENT(2,2,0));
   int jx = player->jx, jy = player->jy;
   int dx = x - jx, dy = y - jy;
+  int nextx = x + dx, nexty = y + dy;
   int move_direction = (dx == -1 ? MV_LEFT :
                        dx == +1 ? MV_RIGHT :
                        dy == -1 ? MV_UP :
@@ -5758,38 +6883,51 @@ int DigField(struct PlayerInfo *player,
   int element;
 
   if (player->MovPos == 0)
+  {
+    player->is_digging = FALSE;
+    player->is_collecting = FALSE;
+  }
+
+  if (player->MovPos == 0)     /* last pushing move finished */
     player->Pushing = FALSE;
 
-  if (mode == DF_NO_PUSH)
+  if (mode == DF_NO_PUSH)      /* player just stopped pushing */
   {
     player->Switching = FALSE;
     player->push_delay = 0;
+
     return MF_NO_ACTION;
   }
 
   if (IS_MOVING(x, y) || IS_PLAYER(x, y))
     return MF_NO_ACTION;
 
-  if (IS_TUBE(Feld[jx][jy]))
+#if 0
+  if (IS_TUBE(Feld[jx][jy]) || IS_TUBE(Back[jx][jy]))
+#else
+  if (IS_TUBE(Feld[jx][jy]) ||
+      (IS_TUBE(Back[jx][jy]) && game.engine_version >= VERSION_IDENT(2,2,0)))
+#endif
   {
     int i = 0;
+    int tube_element = (IS_TUBE(Feld[jx][jy]) ? Feld[jx][jy] : Back[jx][jy]);
     int tube_leave_directions[][2] =
     {
-      { EL_TUBE_CROSS,         MV_LEFT | MV_RIGHT | MV_UP | MV_DOWN },
-      { EL_TUBE_VERTICAL,                           MV_UP | MV_DOWN },
-      { EL_TUBE_HORIZONTAL,    MV_LEFT | MV_RIGHT                   },
-      { EL_TUBE_VERT_LEFT,     MV_LEFT |            MV_UP | MV_DOWN },
-      { EL_TUBE_VERT_RIGHT,              MV_RIGHT | MV_UP | MV_DOWN },
-      { EL_TUBE_HORIZ_UP,      MV_LEFT | MV_RIGHT | MV_UP           },
-      { EL_TUBE_HORIZ_DOWN,    MV_LEFT | MV_RIGHT |         MV_DOWN },
-      { EL_TUBE_LEFT_UP,       MV_LEFT |            MV_UP           },
-      { EL_TUBE_LEFT_DOWN,     MV_LEFT |                    MV_DOWN },
-      { EL_TUBE_RIGHT_UP,                MV_RIGHT | MV_UP           },
-      { EL_TUBE_RIGHT_DOWN,              MV_RIGHT |         MV_DOWN },
-      { -1,                     MV_LEFT | MV_RIGHT | MV_UP | MV_DOWN }
+      { EL_TUBE_ANY,                   MV_LEFT | MV_RIGHT | MV_UP | MV_DOWN },
+      { EL_TUBE_VERTICAL,                                   MV_UP | MV_DOWN },
+      { EL_TUBE_HORIZONTAL,            MV_LEFT | MV_RIGHT                   },
+      { EL_TUBE_VERTICAL_LEFT,         MV_LEFT |            MV_UP | MV_DOWN },
+      { EL_TUBE_VERTICAL_RIGHT,                          MV_RIGHT | MV_UP | MV_DOWN },
+      { EL_TUBE_HORIZONTAL_UP,         MV_LEFT | MV_RIGHT | MV_UP           },
+      { EL_TUBE_HORIZONTAL_DOWN,       MV_LEFT | MV_RIGHT |         MV_DOWN },
+      { EL_TUBE_LEFT_UP,               MV_LEFT |            MV_UP           },
+      { EL_TUBE_LEFT_DOWN,             MV_LEFT |                    MV_DOWN },
+      { EL_TUBE_RIGHT_UP,                        MV_RIGHT | MV_UP           },
+      { EL_TUBE_RIGHT_DOWN,                      MV_RIGHT |         MV_DOWN },
+      { -1,                            MV_LEFT | MV_RIGHT | MV_UP | MV_DOWN }
     };
 
-    while (tube_leave_directions[i][0] != Feld[jx][jy])
+    while (tube_leave_directions[i][0] != tube_element)
     {
       i++;
       if (tube_leave_directions[i][0] == -1)   /* should not happen */
@@ -5802,145 +6940,14 @@ int DigField(struct PlayerInfo *player,
 
   element = Feld[x][y];
 
+  if (mode == DF_SNAP && !IS_SNAPPABLE(element) &&
+      game.engine_version >= VERSION_IDENT(2,2,0))
+    return MF_NO_ACTION;
+
   switch (element)
   {
-    case EL_LEERRAUM:
-    case EL_ERDREICH:
-    case EL_SAND_INVISIBLE:
-    case EL_TRAP_INACTIVE:
-    case EL_SP_BASE:
-    case EL_SP_BUG:
-      RemoveField(x, y);
-      PlaySoundLevelElementAction(x, y, element, SND_ACTION_DIGGING);
-      break;
-
-    case EL_EDELSTEIN:
-    case EL_EDELSTEIN_BD:
-    case EL_EDELSTEIN_GELB:
-    case EL_EDELSTEIN_ROT:
-    case EL_EDELSTEIN_LILA:
-    case EL_DIAMANT:
-    case EL_SP_INFOTRON:
-    case EL_PEARL:
-    case EL_CRYSTAL:
-      RemoveField(x, y);
-      local_player->gems_still_needed -= (element == EL_DIAMANT ? 3 :
-                                         element == EL_PEARL ? 5 :
-                                         element == EL_CRYSTAL ? 8 : 1);
-      if (local_player->gems_still_needed < 0)
-       local_player->gems_still_needed = 0;
-      RaiseScoreElement(element);
-      DrawText(DX_EMERALDS, DY_EMERALDS,
-              int2str(local_player->gems_still_needed, 3),
-              FS_SMALL, FC_YELLOW);
-      PlaySoundLevelElementAction(x, y, element, SND_ACTION_COLLECTING);
-      break;
-
-    case EL_SPEED_PILL:
-      RemoveField(x, y);
-      player->move_delay_value = MOVE_DELAY_HIGH_SPEED;
-      PlaySoundLevel(x, y, SND_SPEED_PILL_COLLECTING);
-      break;
-
-    case EL_ENVELOPE:
-      Feld[x][y] = EL_LEERRAUM;
-      PlaySoundLevel(x, y, SND_ENVELOPE_COLLECTING);
-      break;
-
-    case EL_EXTRA_TIME:
-      RemoveField(x, y);
-      if (level.time > 0)
-      {
-       TimeLeft += 10;
-       DrawText(DX_TIME, DY_TIME, int2str(TimeLeft, 3), FS_SMALL, FC_YELLOW);
-      }
-      PlaySoundStereo(SND_EXTRA_TIME_COLLECTING, SOUND_MAX_RIGHT);
-      break;
-
-    case EL_SHIELD_PASSIVE:
-      RemoveField(x, y);
-      player->shield_passive_time_left += 10;
-      PlaySoundLevel(x, y, SND_SHIELD_PASSIVE_COLLECTING);
-      break;
-
-    case EL_SHIELD_ACTIVE:
-      RemoveField(x, y);
-      player->shield_passive_time_left += 10;
-      player->shield_active_time_left += 10;
-      PlaySoundLevel(x, y, SND_SHIELD_ACTIVE_COLLECTING);
-      break;
-
-    case EL_DYNAMITE_INACTIVE:
-    case EL_SP_DISK_RED:
-      RemoveField(x, y);
-      player->dynamite++;
-      RaiseScoreElement(EL_DYNAMITE_INACTIVE);
-      DrawText(DX_DYNAMITE, DY_DYNAMITE,
-              int2str(local_player->dynamite, 3),
-              FS_SMALL, FC_YELLOW);
-      PlaySoundLevelElementAction(x, y, element, SND_ACTION_COLLECTING);
-      break;
-
-    case EL_DYNABOMB_NR:
-      RemoveField(x, y);
-      player->dynabomb_count++;
-      player->dynabombs_left++;
-      RaiseScoreElement(EL_DYNAMITE_INACTIVE);
-      PlaySoundLevel(x, y, SND_DYNABOMB_NR_COLLECTING);
-      break;
-
-    case EL_DYNABOMB_SZ:
-      RemoveField(x, y);
-      player->dynabomb_size++;
-      RaiseScoreElement(EL_DYNAMITE_INACTIVE);
-      PlaySoundLevel(x, y, SND_DYNABOMB_SZ_COLLECTING);
-      break;
-
-    case EL_DYNABOMB_XL:
-      RemoveField(x, y);
-      player->dynabomb_xl = TRUE;
-      RaiseScoreElement(EL_DYNAMITE_INACTIVE);
-      PlaySoundLevel(x, y, SND_DYNABOMB_XL_COLLECTING);
-      break;
-
-    case EL_SCHLUESSEL1:
-    case EL_SCHLUESSEL2:
-    case EL_SCHLUESSEL3:
-    case EL_SCHLUESSEL4:
-    {
-      int key_nr = element - EL_SCHLUESSEL1;
-
-      RemoveField(x, y);
-      player->key[key_nr] = TRUE;
-      RaiseScoreElement(EL_SCHLUESSEL);
-      DrawMiniGraphicExt(drawto, DX_KEYS + key_nr * MINI_TILEX, DY_KEYS,
-                        GFX_SCHLUESSEL1 + key_nr);
-      DrawMiniGraphicExt(window, DX_KEYS + key_nr * MINI_TILEX, DY_KEYS,
-                        GFX_SCHLUESSEL1 + key_nr);
-      PlaySoundLevel(x, y, SND_KEY_COLLECTING);
-      break;
-    }
-
-    case EL_EM_KEY_1:
-    case EL_EM_KEY_2:
-    case EL_EM_KEY_3:
-    case EL_EM_KEY_4:
-    {
-      int key_nr = element - EL_EM_KEY_1;
-
-      RemoveField(x, y);
-      player->key[key_nr] = TRUE;
-      RaiseScoreElement(EL_SCHLUESSEL);
-      DrawMiniGraphicExt(drawto, DX_KEYS + key_nr * MINI_TILEX, DY_KEYS,
-                        GFX_SCHLUESSEL1 + key_nr);
-      DrawMiniGraphicExt(window, DX_KEYS + key_nr * MINI_TILEX, DY_KEYS,
-                        GFX_SCHLUESSEL1 + key_nr);
-      PlaySoundLevel(x, y, SND_KEY_COLLECTING);
-      break;
-    }
-
-    case EL_ABLENK_AUS:
-      Feld[x][y] = EL_ABLENK_EIN;
+    case EL_ROBOT_WHEEL:
+      Feld[x][y] = EL_ROBOT_WHEEL_ACTIVE;
       ZX = x;
       ZY = y;
       DrawLevelField(x, y);
@@ -5952,274 +6959,148 @@ int DigField(struct PlayerInfo *player,
       {
        int xx, yy;
 
-       PlaySoundLevel(x, y, SND_SP_TERMINAL_ACTIVATING);
-
-       for (yy=0; yy<lev_fieldy; yy++)
-       {
-         for (xx=0; xx<lev_fieldx; xx++)
-         {
-           if (Feld[xx][yy] == EL_SP_DISK_YELLOW)
-             Bang(xx, yy);
-           else if (Feld[xx][yy] == EL_SP_TERMINAL)
-             Feld[xx][yy] = EL_SP_TERMINAL_ACTIVE;
-         }
-       }
-
-       return MF_ACTION;
-      }
-      break;
-
-    case EL_BELT1_SWITCH_LEFT:
-    case EL_BELT1_SWITCH_MIDDLE:
-    case EL_BELT1_SWITCH_RIGHT:
-    case EL_BELT2_SWITCH_LEFT:
-    case EL_BELT2_SWITCH_MIDDLE:
-    case EL_BELT2_SWITCH_RIGHT:
-    case EL_BELT3_SWITCH_LEFT:
-    case EL_BELT3_SWITCH_MIDDLE:
-    case EL_BELT3_SWITCH_RIGHT:
-    case EL_BELT4_SWITCH_LEFT:
-    case EL_BELT4_SWITCH_MIDDLE:
-    case EL_BELT4_SWITCH_RIGHT:
-      if (!player->Switching)
-      {
-       player->Switching = TRUE;
-       ToggleBeltSwitch(x, y);
-       PlaySoundLevel(x, y, SND_CONVEYOR_BELT_SWITCH_ACTIVATING);
-      }
-      return MF_ACTION;
-      break;
-
-    case EL_SWITCHGATE_SWITCH_1:
-    case EL_SWITCHGATE_SWITCH_2:
-      if (!player->Switching)
-      {
-       player->Switching = TRUE;
-       ToggleSwitchgateSwitch(x, y);
-       PlaySoundLevel(x, y, SND_SWITCHGATE_SWITCH_ACTIVATING);
-      }
-      return MF_ACTION;
-      break;
-
-    case EL_LIGHT_SWITCH_OFF:
-    case EL_LIGHT_SWITCH_ON:
-      if (!player->Switching)
-      {
-       player->Switching = TRUE;
-       ToggleLightSwitch(x, y);
-       PlaySoundLevel(x, y, element == EL_LIGHT_SWITCH_OFF ?
-                      SND_LIGHT_SWITCH_ACTIVATING :
-                      SND_LIGHT_SWITCH_DEACTIVATING);
-      }
-      return MF_ACTION;
-      break;
-
-    case EL_TIMEGATE_SWITCH_OFF:
-      ActivateTimegateSwitch(x, y);
-      PlaySoundLevel(x, y, SND_TIMEGATE_WHEEL_ACTIVATING);
-
-      return MF_ACTION;
-      break;
-
-    case EL_BALLOON_SEND_LEFT:
-    case EL_BALLOON_SEND_RIGHT:
-    case EL_BALLOON_SEND_UP:
-    case EL_BALLOON_SEND_DOWN:
-    case EL_BALLOON_SEND_ANY:
-      if (element == EL_BALLOON_SEND_ANY)
-       game.balloon_dir = move_direction;
-      else
-       game.balloon_dir = (element == EL_BALLOON_SEND_LEFT  ? MV_LEFT :
-                           element == EL_BALLOON_SEND_RIGHT ? MV_RIGHT :
-                           element == EL_BALLOON_SEND_UP    ? MV_UP :
-                           element == EL_BALLOON_SEND_DOWN  ? MV_DOWN :
-                           MV_NO_MOVING);
-      PlaySoundLevel(x, y, SND_BALLOON_SWITCH_ACTIVATING);
-
-      return MF_ACTION;
-      break;
-
-    case EL_SP_EXIT:
-      if (local_player->gems_still_needed > 0)
-       return MF_NO_ACTION;
-
-      player->LevelSolved = player->GameOver = TRUE;
-      PlaySoundStereo(SND_SP_EXIT_ENTERING, SOUND_MAX_RIGHT);
-      break;
-
-      /* the following elements cannot be pushed by "snapping" */
-    case EL_FELSBROCKEN:
-    case EL_BOMBE:
-    case EL_DX_SUPABOMB:
-    case EL_KOKOSNUSS:
-    case EL_ZEIT_LEER:
-    case EL_SP_ZONK:
-    case EL_SP_DISK_ORANGE:
-    case EL_SPRING:
-      if (mode == DF_SNAP)
-       return MF_NO_ACTION;
-      /* no "break" -- fall through to next case */
-      /* the following elements can be pushed by "snapping" */
-    case EL_BD_ROCK:
-      if (dy)
-       return MF_NO_ACTION;
-
-      player->Pushing = TRUE;
-
-      if (!IN_LEV_FIELD(x+dx, y+dy) || !IS_FREE(x+dx, y+dy))
-       return MF_NO_ACTION;
-
-      if (real_dy)
-      {
-       if (IN_LEV_FIELD(jx, jy+real_dy) && !IS_SOLID(Feld[jx][jy+real_dy]))
-         return MF_NO_ACTION;
-      }
-
-      if (player->push_delay == 0)
-       player->push_delay = FrameCounter;
-#if 0
-      if (!FrameReached(&player->push_delay, player->push_delay_value) &&
-         !tape.playing && element != EL_SPRING)
-       return MF_NO_ACTION;
-#else
-      if (!FrameReached(&player->push_delay, player->push_delay_value) &&
-         !(tape.playing && tape.file_version < FILE_VERSION_2_0) &&
-         element != EL_SPRING)
-       return MF_NO_ACTION;
-#endif
-
-      if (mode == DF_SNAP)
-      {
-       InitMovingField(x, y, move_direction);
-       ContinueMoving(x, y);
-      }
-      else
-      {
-       RemoveField(x, y);
-       Feld[x+dx][y+dy] = element;
-      }
-
-      if (element == EL_SPRING)
-      {
-       Feld[x+dx][y+dy] = EL_SPRING_MOVING;
-       MovDir[x+dx][y+dy] = move_direction;
-      }
+       PlaySoundLevel(x, y, SND_SP_TERMINAL_ACTIVATING);
 
-      player->push_delay_value = (element == EL_SPRING ? 0 : 2 + RND(8));
+       for (yy=0; yy<lev_fieldy; yy++)
+       {
+         for (xx=0; xx<lev_fieldx; xx++)
+         {
+           if (Feld[xx][yy] == EL_SP_DISK_YELLOW)
+             Bang(xx, yy);
+           else if (Feld[xx][yy] == EL_SP_TERMINAL)
+             Feld[xx][yy] = EL_SP_TERMINAL_ACTIVE;
+         }
+       }
 
-      DrawLevelField(x+dx, y+dy);
-      PlaySoundLevelElementAction(x, y, element, SND_ACTION_PUSHING);
+       return MF_ACTION;
+      }
       break;
 
-    case EL_PFORTE1:
-    case EL_PFORTE2:
-    case EL_PFORTE3:
-    case EL_PFORTE4:
-      if (!player->key[element - EL_PFORTE1])
-       return MF_NO_ACTION;
+    case EL_CONVEYOR_BELT_1_SWITCH_LEFT:
+    case EL_CONVEYOR_BELT_1_SWITCH_MIDDLE:
+    case EL_CONVEYOR_BELT_1_SWITCH_RIGHT:
+    case EL_CONVEYOR_BELT_2_SWITCH_LEFT:
+    case EL_CONVEYOR_BELT_2_SWITCH_MIDDLE:
+    case EL_CONVEYOR_BELT_2_SWITCH_RIGHT:
+    case EL_CONVEYOR_BELT_3_SWITCH_LEFT:
+    case EL_CONVEYOR_BELT_3_SWITCH_MIDDLE:
+    case EL_CONVEYOR_BELT_3_SWITCH_RIGHT:
+    case EL_CONVEYOR_BELT_4_SWITCH_LEFT:
+    case EL_CONVEYOR_BELT_4_SWITCH_MIDDLE:
+    case EL_CONVEYOR_BELT_4_SWITCH_RIGHT:
+      if (!player->Switching)
+      {
+       player->Switching = TRUE;
+       ToggleBeltSwitch(x, y);
+       PlaySoundLevel(x, y, SND_CLASS_CONVEYOR_BELT_SWITCH_ACTIVATING);
+      }
+      return MF_ACTION;
       break;
 
-    case EL_PFORTE1X:
-    case EL_PFORTE2X:
-    case EL_PFORTE3X:
-    case EL_PFORTE4X:
-      if (!player->key[element - EL_PFORTE1X])
-       return MF_NO_ACTION;
+    case EL_SWITCHGATE_SWITCH_UP:
+    case EL_SWITCHGATE_SWITCH_DOWN:
+      if (!player->Switching)
+      {
+       player->Switching = TRUE;
+       ToggleSwitchgateSwitch(x, y);
+       PlaySoundLevel(x, y, SND_CLASS_SWITCHGATE_SWITCH_ACTIVATING);
+      }
+      return MF_ACTION;
       break;
 
-    case EL_EM_GATE_1:
-    case EL_EM_GATE_2:
-    case EL_EM_GATE_3:
-    case EL_EM_GATE_4:
-      if (!player->key[element - EL_EM_GATE_1])
-       return MF_NO_ACTION;
-      if (!IN_LEV_FIELD(x + dx, y + dy) || !IS_FREE(x + dx, y + dy))
-       return MF_NO_ACTION;
-
-      /* automatically move to the next field with double speed */
-      player->programmed_action = move_direction;
-      DOUBLE_PLAYER_SPEED(player);
-
-      PlaySoundLevel(x, y, SND_GATE_PASSING);
+    case EL_LIGHT_SWITCH:
+    case EL_LIGHT_SWITCH_ACTIVE:
+      if (!player->Switching)
+      {
+       player->Switching = TRUE;
+       ToggleLightSwitch(x, y);
+       PlaySoundLevel(x, y, element == EL_LIGHT_SWITCH ?
+                      SND_LIGHT_SWITCH_ACTIVATING :
+                      SND_LIGHT_SWITCH_DEACTIVATING);
+      }
+      return MF_ACTION;
       break;
 
-    case EL_EM_GATE_1X:
-    case EL_EM_GATE_2X:
-    case EL_EM_GATE_3X:
-    case EL_EM_GATE_4X:
-      if (!player->key[element - EL_EM_GATE_1X])
-       return MF_NO_ACTION;
-      if (!IN_LEV_FIELD(x + dx, y + dy) || !IS_FREE(x + dx, y + dy))
-       return MF_NO_ACTION;
-
-      /* automatically move to the next field with double speed */
-      player->programmed_action = move_direction;
-      DOUBLE_PLAYER_SPEED(player);
+    case EL_TIMEGATE_SWITCH:
+      ActivateTimegateSwitch(x, y);
+      PlaySoundLevel(x, y, SND_TIMEGATE_SWITCH_ACTIVATING);
 
-      PlaySoundLevel(x, y, SND_GATE_PASSING);
+      return MF_ACTION;
       break;
 
-    case EL_SWITCHGATE_OPEN:
-    case EL_TIMEGATE_OPEN:
-      if (!IN_LEV_FIELD(x + dx, y + dy) || !IS_FREE(x + dx, y + dy))
-       return MF_NO_ACTION;
-
-      /* automatically move to the next field with double speed */
-      player->programmed_action = move_direction;
-      DOUBLE_PLAYER_SPEED(player);
+    case EL_BALLOON_SWITCH_LEFT:
+    case EL_BALLOON_SWITCH_RIGHT:
+    case EL_BALLOON_SWITCH_UP:
+    case EL_BALLOON_SWITCH_DOWN:
+    case EL_BALLOON_SWITCH_ANY:
+      if (element == EL_BALLOON_SWITCH_ANY)
+       game.balloon_dir = move_direction;
+      else
+       game.balloon_dir = (element == EL_BALLOON_SWITCH_LEFT  ? MV_LEFT :
+                           element == EL_BALLOON_SWITCH_RIGHT ? MV_RIGHT :
+                           element == EL_BALLOON_SWITCH_UP    ? MV_UP :
+                           element == EL_BALLOON_SWITCH_DOWN  ? MV_DOWN :
+                           MV_NO_MOVING);
+      PlaySoundLevel(x, y, SND_CLASS_BALLOON_SWITCH_ACTIVATING);
 
-      PlaySoundLevelElementAction(x, y, element, SND_ACTION_PASSING);
+      return MF_ACTION;
       break;
 
-    case EL_SP_PORT1_LEFT:
-    case EL_SP_PORT2_LEFT:
-    case EL_SP_PORT1_RIGHT:
-    case EL_SP_PORT2_RIGHT:
-    case EL_SP_PORT1_UP:
-    case EL_SP_PORT2_UP:
-    case EL_SP_PORT1_DOWN:
-    case EL_SP_PORT2_DOWN:
-    case EL_SP_PORT_X:
-    case EL_SP_PORT_Y:
-    case EL_SP_PORT_XY:
+    case EL_SP_PORT_LEFT:
+    case EL_SP_PORT_RIGHT:
+    case EL_SP_PORT_UP:
+    case EL_SP_PORT_DOWN:
+    case EL_SP_PORT_HORIZONTAL:
+    case EL_SP_PORT_VERTICAL:
+    case EL_SP_PORT_ANY:
+    case EL_SP_GRAVITY_PORT_LEFT:
+    case EL_SP_GRAVITY_PORT_RIGHT:
+    case EL_SP_GRAVITY_PORT_UP:
+    case EL_SP_GRAVITY_PORT_DOWN:
       if ((dx == -1 &&
-          element != EL_SP_PORT1_LEFT &&
-          element != EL_SP_PORT2_LEFT &&
-          element != EL_SP_PORT_X &&
-          element != EL_SP_PORT_XY) ||
+          element != EL_SP_PORT_LEFT &&
+          element != EL_SP_GRAVITY_PORT_LEFT &&
+          element != EL_SP_PORT_HORIZONTAL &&
+          element != EL_SP_PORT_ANY) ||
          (dx == +1 &&
-          element != EL_SP_PORT1_RIGHT &&
-          element != EL_SP_PORT2_RIGHT &&
-          element != EL_SP_PORT_X &&
-          element != EL_SP_PORT_XY) ||
+          element != EL_SP_PORT_RIGHT &&
+          element != EL_SP_GRAVITY_PORT_RIGHT &&
+          element != EL_SP_PORT_HORIZONTAL &&
+          element != EL_SP_PORT_ANY) ||
          (dy == -1 &&
-          element != EL_SP_PORT1_UP &&
-          element != EL_SP_PORT2_UP &&
-          element != EL_SP_PORT_Y &&
-          element != EL_SP_PORT_XY) ||
+          element != EL_SP_PORT_UP &&
+          element != EL_SP_GRAVITY_PORT_UP &&
+          element != EL_SP_PORT_VERTICAL &&
+          element != EL_SP_PORT_ANY) ||
          (dy == +1 &&
-          element != EL_SP_PORT1_DOWN &&
-          element != EL_SP_PORT2_DOWN &&
-          element != EL_SP_PORT_Y &&
-          element != EL_SP_PORT_XY) ||
-         !IN_LEV_FIELD(x + dx, y + dy) ||
-         !IS_FREE(x + dx, y + dy))
+          element != EL_SP_PORT_DOWN &&
+          element != EL_SP_GRAVITY_PORT_DOWN &&
+          element != EL_SP_PORT_VERTICAL &&
+          element != EL_SP_PORT_ANY) ||
+         !IN_LEV_FIELD(nextx, nexty) ||
+         !IS_FREE(nextx, nexty))
        return MF_NO_ACTION;
 
+      if (element == EL_SP_GRAVITY_PORT_LEFT ||
+         element == EL_SP_GRAVITY_PORT_RIGHT ||
+         element == EL_SP_GRAVITY_PORT_UP ||
+         element == EL_SP_GRAVITY_PORT_DOWN)
+       level.gravity = !level.gravity;
+
       /* automatically move to the next field with double speed */
       player->programmed_action = move_direction;
       DOUBLE_PLAYER_SPEED(player);
 
-      PlaySoundLevel(x, y, SND_SP_PORT_PASSING);
+      PlaySoundLevel(x, y, SND_CLASS_SP_PORT_PASSING);
       break;
 
-    case EL_TUBE_CROSS:
+    case EL_TUBE_ANY:
     case EL_TUBE_VERTICAL:
     case EL_TUBE_HORIZONTAL:
-    case EL_TUBE_VERT_LEFT:
-    case EL_TUBE_VERT_RIGHT:
-    case EL_TUBE_HORIZ_UP:
-    case EL_TUBE_HORIZ_DOWN:
+    case EL_TUBE_VERTICAL_LEFT:
+    case EL_TUBE_VERTICAL_RIGHT:
+    case EL_TUBE_HORIZONTAL_UP:
+    case EL_TUBE_HORIZONTAL_DOWN:
     case EL_TUBE_LEFT_UP:
     case EL_TUBE_LEFT_DOWN:
     case EL_TUBE_RIGHT_UP:
@@ -6228,18 +7109,18 @@ int DigField(struct PlayerInfo *player,
        int i = 0;
        int tube_enter_directions[][2] =
        {
-         { EL_TUBE_CROSS,      MV_LEFT | MV_RIGHT | MV_UP | MV_DOWN },
-         { EL_TUBE_VERTICAL,                        MV_UP | MV_DOWN },
-         { EL_TUBE_HORIZONTAL, MV_LEFT | MV_RIGHT                   },
-         { EL_TUBE_VERT_LEFT,            MV_RIGHT | MV_UP | MV_DOWN },
-         { EL_TUBE_VERT_RIGHT, MV_LEFT            | MV_UP | MV_DOWN },
-         { EL_TUBE_HORIZ_UP,   MV_LEFT | MV_RIGHT |         MV_DOWN },
-         { EL_TUBE_HORIZ_DOWN, MV_LEFT | MV_RIGHT | MV_UP           },
-         { EL_TUBE_LEFT_UP,              MV_RIGHT |         MV_DOWN },
-         { EL_TUBE_LEFT_DOWN,            MV_RIGHT | MV_UP           },
-         { EL_TUBE_RIGHT_UP,   MV_LEFT |                    MV_DOWN },
-         { EL_TUBE_RIGHT_DOWN, MV_LEFT |            MV_UP           },
-         { -1,                 MV_NO_MOVING                         }
+         { EL_TUBE_ANY,                MV_LEFT | MV_RIGHT | MV_UP | MV_DOWN },
+         { EL_TUBE_VERTICAL,                                MV_UP | MV_DOWN },
+         { EL_TUBE_HORIZONTAL,         MV_LEFT | MV_RIGHT                   },
+         { EL_TUBE_VERTICAL_LEFT,                MV_RIGHT | MV_UP | MV_DOWN },
+         { EL_TUBE_VERTICAL_RIGHT,     MV_LEFT            | MV_UP | MV_DOWN },
+         { EL_TUBE_HORIZONTAL_UP,      MV_LEFT | MV_RIGHT |         MV_DOWN },
+         { EL_TUBE_HORIZONTAL_DOWN,    MV_LEFT | MV_RIGHT | MV_UP           },
+         { EL_TUBE_LEFT_UP,                      MV_RIGHT |         MV_DOWN },
+         { EL_TUBE_LEFT_DOWN,                    MV_RIGHT | MV_UP           },
+         { EL_TUBE_RIGHT_UP,           MV_LEFT |                    MV_DOWN },
+         { EL_TUBE_RIGHT_DOWN,         MV_LEFT |            MV_UP           },
+         { -1,                         MV_NO_MOVING                         }
        };
 
        while (tube_enter_directions[i][0] != element)
@@ -6252,145 +7133,283 @@ int DigField(struct PlayerInfo *player,
        if (!(tube_enter_directions[i][1] & move_direction))
          return MF_NO_ACTION;  /* tube has no opening in this direction */
 
-       PlaySoundLevel(x, y, SND_TUBE_PASSING);
+       PlaySoundLevel(x, y, SND_CLASS_TUBE_WALKING);
       }
       break;
 
-    case EL_AUSGANG_ZU:
-    case EL_AUSGANG_ACT:
-      /* door is not (yet) open */
-      return MF_NO_ACTION;
-      break;
-
-    case EL_AUSGANG_AUF:
-      if (mode == DF_SNAP)
-       return MF_NO_ACTION;
-
-      PlaySoundLevel(x, y, SND_EXIT_ENTERING);
-
-      break;
-
-    case EL_BIRNE_AUS:
-      Feld[x][y] = EL_BIRNE_EIN;
+    case EL_LAMP:
+      Feld[x][y] = EL_LAMP_ACTIVE;
       local_player->lights_still_needed--;
       DrawLevelField(x, y);
       PlaySoundLevel(x, y, SND_LAMP_ACTIVATING);
       return MF_ACTION;
       break;
 
-    case EL_ZEIT_VOLL:
-      Feld[x][y] = EL_ZEIT_LEER;
+    case EL_TIME_ORB_FULL:
+      Feld[x][y] = EL_TIME_ORB_EMPTY;
       TimeLeft += 10;
-      DrawText(DX_TIME, DY_TIME, int2str(TimeLeft, 3), FS_SMALL, FC_YELLOW);
+      DrawText(DX_TIME, DY_TIME, int2str(TimeLeft, 3), FONT_TEXT_2);
       DrawLevelField(x, y);
-      PlaySoundStereo(SND_TIME_ORB_FULL_COLLECTING, SOUND_MAX_RIGHT);
+      PlaySoundStereo(SND_TIME_ORB_FULL_COLLECTING, SOUND_MIDDLE);
       return MF_ACTION;
       break;
 
-    case EL_SOKOBAN_FELD_LEER:
-      break;
+    default:
 
-    case EL_SOKOBAN_OBJEKT:
-    case EL_SOKOBAN_FELD_VOLL:
-    case EL_SONDE:
-    case EL_SP_DISK_YELLOW:
-    case EL_BALLOON:
-      if (mode == DF_SNAP)
-       return MF_NO_ACTION;
+      if (IS_WALKABLE(element))
+      {
+       int sound_action = ACTION_WALKING;
 
-      player->Pushing = TRUE;
+       if (element >= EL_GATE_1 && element <= EL_GATE_4)
+       {
+         if (!player->key[element - EL_GATE_1])
+           return MF_NO_ACTION;
+       }
+       else if (element >= EL_GATE_1_GRAY && element <= EL_GATE_4_GRAY)
+       {
+         if (!player->key[element - EL_GATE_1_GRAY])
+           return MF_NO_ACTION;
+       }
+       else if (element == EL_EXIT_OPEN || element == EL_SP_EXIT_OPEN)
+       {
+         sound_action = ACTION_PASSING;        /* player is passing exit */
+       }
+       else if (element == EL_EMPTY)
+       {
+         sound_action = ACTION_MOVING;         /* nothing to walk on */
+       }
 
-      if (!IN_LEV_FIELD(x+dx, y+dy)
-         || (!IS_FREE(x+dx, y+dy)
-             && (Feld[x+dx][y+dy] != EL_SOKOBAN_FELD_LEER
-                 || !IS_SB_ELEMENT(element))))
-       return MF_NO_ACTION;
+       /* play sound from background or player, whatever is available */
+       if (element_info[element].sound[sound_action] != SND_UNDEFINED)
+         PlaySoundLevelElementAction(x, y, element, sound_action);
+       else
+         PlaySoundLevelElementAction(x, y, player->element_nr, sound_action);
 
-      if (dx && real_dy)
-      {
-       if (IN_LEV_FIELD(jx, jy+real_dy) && !IS_SOLID(Feld[jx][jy+real_dy]))
-         return MF_NO_ACTION;
+       break;
       }
-      else if (dy && real_dx)
+      else if (IS_PASSABLE(element))
       {
-       if (IN_LEV_FIELD(jx+real_dx, jy) && !IS_SOLID(Feld[jx+real_dx][jy]))
+       if (!IN_LEV_FIELD(nextx, nexty) || !IS_FREE(nextx, nexty))
          return MF_NO_ACTION;
+
+       if (element >= EL_EM_GATE_1 && element <= EL_EM_GATE_4)
+       {
+         if (!player->key[element - EL_EM_GATE_1])
+           return MF_NO_ACTION;
+       }
+       else if (element >= EL_EM_GATE_1_GRAY && element <= EL_EM_GATE_4_GRAY)
+       {
+         if (!player->key[element - EL_EM_GATE_1_GRAY])
+           return MF_NO_ACTION;
+       }
+
+       /* automatically move to the next field with double speed */
+       player->programmed_action = move_direction;
+       DOUBLE_PLAYER_SPEED(player);
+
+       PlaySoundLevelAction(x, y, ACTION_PASSING);
+
+       break;
       }
+      else if (IS_DIGGABLE(element))
+      {
+       RemoveField(x, y);
 
-      if (player->push_delay == 0)
-       player->push_delay = FrameCounter;
-#if 0
-      if (!FrameReached(&player->push_delay, player->push_delay_value) &&
-         !tape.playing && element != EL_BALLOON)
-       return MF_NO_ACTION;
+       if (mode != DF_SNAP)
+       {
+#if 1
+         GfxElement[x][y] = GFX_ELEMENT(element);
 #else
-      if (!FrameReached(&player->push_delay, player->push_delay_value) &&
-         !(tape.playing && tape.file_version < FILE_VERSION_2_0) &&
-         element != EL_BALLOON)
-       return MF_NO_ACTION;
+         GfxElement[x][y] =
+           (CAN_BE_CRUMBLED(element) ? EL_SAND : GFX_ELEMENT(element));
 #endif
+         player->is_digging = TRUE;
+       }
 
-      if (IS_SB_ELEMENT(element))
+       PlaySoundLevelElementAction(x, y, element, ACTION_DIGGING);
+
+       break;
+      }
+      else if (IS_COLLECTIBLE(element))
       {
-       if (element == EL_SOKOBAN_FELD_VOLL)
+       RemoveField(x, y);
+
+       if (mode != DF_SNAP)
        {
-         Feld[x][y] = EL_SOKOBAN_FELD_LEER;
-         local_player->sokobanfields_still_needed++;
+         GfxElement[x][y] = element;
+         player->is_collecting = TRUE;
        }
-       else
-         RemoveField(x, y);
 
-       if (Feld[x+dx][y+dy] == EL_SOKOBAN_FELD_LEER)
+       if (element == EL_SPEED_PILL)
+         player->move_delay_value = MOVE_DELAY_HIGH_SPEED;
+       else if (element == EL_EXTRA_TIME && level.time > 0)
        {
-         Feld[x+dx][y+dy] = EL_SOKOBAN_FELD_VOLL;
-         local_player->sokobanfields_still_needed--;
-         if (element == EL_SOKOBAN_OBJEKT)
-           PlaySoundLevel(x, y, SND_SOKOBAN_FIELD_FILLING);
-         else
-           PlaySoundLevel(x, y, SND_SOKOBAN_OBJECT_PUSHING);
+         TimeLeft += 10;
+         DrawText(DX_TIME, DY_TIME, int2str(TimeLeft, 3), FONT_TEXT_2);
        }
-       else
+       else if (element == EL_SHIELD_NORMAL || element == EL_SHIELD_DEADLY)
        {
-         Feld[x+dx][y+dy] = EL_SOKOBAN_OBJEKT;
-         if (element == EL_SOKOBAN_FELD_VOLL)
-           PlaySoundLevel(x, y, SND_SOKOBAN_FIELD_CLEARING);
-         else
-           PlaySoundLevel(x, y, SND_SOKOBAN_OBJECT_PUSHING);
+         player->shield_normal_time_left += 10;
+         if (element == EL_SHIELD_DEADLY)
+           player->shield_deadly_time_left += 10;
+       }
+       else if (element == EL_DYNAMITE || element == EL_SP_DISK_RED)
+       {
+         player->dynamite++;
+         player->use_disk_red_graphic = (element == EL_SP_DISK_RED);
+
+         DrawText(DX_DYNAMITE, DY_DYNAMITE,
+                  int2str(local_player->dynamite, 3), FONT_TEXT_2);
+       }
+       else if (element == EL_DYNABOMB_INCREASE_NUMBER)
+       {
+         player->dynabomb_count++;
+         player->dynabombs_left++;
+       }
+       else if (element == EL_DYNABOMB_INCREASE_SIZE)
+       {
+         player->dynabomb_size++;
+       }
+       else if (element == EL_DYNABOMB_INCREASE_POWER)
+       {
+         player->dynabomb_xl = TRUE;
+       }
+       else if ((element >= EL_KEY_1 && element <= EL_KEY_4) ||
+                (element >= EL_EM_KEY_1 && element <= EL_EM_KEY_4))
+       {
+         int key_nr = (element >= EL_KEY_1 && element <= EL_KEY_4 ?
+                       element - EL_KEY_1 : element - EL_EM_KEY_1);
+
+         player->key[key_nr] = TRUE;
+
+         DrawMiniGraphicExt(drawto, DX_KEYS + key_nr * MINI_TILEX, DY_KEYS,
+                            el2edimg(EL_KEY_1 + key_nr));
+         redraw_mask |= REDRAW_DOOR_1;
+       }
+       else if (element_info[element].gem_count > 0)
+       {
+         local_player->gems_still_needed -=
+           element_info[element].gem_count;
+         if (local_player->gems_still_needed < 0)
+           local_player->gems_still_needed = 0;
+
+         DrawText(DX_EMERALDS, DY_EMERALDS,
+                  int2str(local_player->gems_still_needed, 3), FONT_TEXT_2);
        }
+
+       RaiseScoreElement(element);
+       PlaySoundLevelElementAction(x, y, element, ACTION_COLLECTING);
+
+       CheckTriggeredElementChange(x, y, element, CE_OTHER_GETS_COLLECTED);
+
+       break;
       }
-      else
+      else if (IS_PUSHABLE(element))
       {
-       RemoveField(x, y);
-       Feld[x+dx][y+dy] = element;
-       PlaySoundLevelElementAction(x, y, element, SND_ACTION_PUSHING);
-      }
+       if (mode == DF_SNAP && element != EL_BD_ROCK)
+         return MF_NO_ACTION;
 
-      player->push_delay_value = (element == EL_BALLOON ? 0 : 2);
+       if (CAN_FALL(element) && dy)
+         return MF_NO_ACTION;
 
-      DrawLevelField(x, y);
-      DrawLevelField(x+dx, y+dy);
+       if (CAN_FALL(element) && IN_LEV_FIELD(x, y + 1) && IS_FREE(x, y + 1) &&
+           !(element == EL_SPRING && use_spring_bug))
+         return MF_NO_ACTION;
 
-      if (IS_SB_ELEMENT(element) &&
-         local_player->sokobanfields_still_needed == 0 &&
-         game.emulation == EMU_SOKOBAN)
-      {
-       player->LevelSolved = player->GameOver = TRUE;
-       PlaySoundLevel(x, y, SND_SOKOBAN_GAME_SOLVING);
-      }
+       if (element == EL_SPRING && MovDir[x][y] != MV_NO_MOVING)
+         return MF_NO_ACTION;
 
-      break;
+       if (!player->Pushing &&
+           game.engine_version >= RELEASE_IDENT(2,2,0,7))
+         player->push_delay_value = GET_NEW_PUSH_DELAY(element);
 
-    case EL_PINGUIN:
-    case EL_SCHWEIN:
-    case EL_DRACHE:
-      break;
+       player->Pushing = TRUE;
+
+       if (!(IN_LEV_FIELD(nextx, nexty) &&
+             (IS_FREE(nextx, nexty) ||
+              (Feld[nextx][nexty] == EL_SOKOBAN_FIELD_EMPTY &&
+               IS_SB_ELEMENT(element)))))
+         return MF_NO_ACTION;
+
+       if (!checkDiagonalPushing(player, x, y, real_dx, real_dy))
+         return MF_NO_ACTION;
+
+       if (player->push_delay == 0)    /* new pushing; restart delay */
+         player->push_delay = FrameCounter;
+
+       if (!FrameReached(&player->push_delay, player->push_delay_value) &&
+           !(tape.playing && tape.file_version < FILE_VERSION_2_0) &&
+           element != EL_SPRING && element != EL_BALLOON)
+         return MF_NO_ACTION;
+
+       if (IS_SB_ELEMENT(element))
+       {
+         if (element == EL_SOKOBAN_FIELD_FULL)
+         {
+           Back[x][y] = EL_SOKOBAN_FIELD_EMPTY;
+           local_player->sokobanfields_still_needed++;
+         }
+
+         if (Feld[nextx][nexty] == EL_SOKOBAN_FIELD_EMPTY)
+         {
+           Back[nextx][nexty] = EL_SOKOBAN_FIELD_EMPTY;
+           local_player->sokobanfields_still_needed--;
+         }
+
+         Feld[x][y] = EL_SOKOBAN_OBJECT;
+
+         if (Back[x][y] == Back[nextx][nexty])
+           PlaySoundLevelAction(x, y, ACTION_PUSHING);
+         else if (Back[x][y] != 0)
+           PlaySoundLevelElementAction(x, y, EL_SOKOBAN_FIELD_FULL,
+                                       ACTION_EMPTYING);
+         else
+           PlaySoundLevelElementAction(nextx, nexty, EL_SOKOBAN_FIELD_EMPTY,
+                                       ACTION_FILLING);
+
+         if (local_player->sokobanfields_still_needed == 0 &&
+             game.emulation == EMU_SOKOBAN)
+         {
+           player->LevelSolved = player->GameOver = TRUE;
+           PlaySoundLevel(x, y, SND_GAME_SOKOBAN_SOLVING);
+         }
+       }
+       else
+         PlaySoundLevelElementAction(x, y, element, ACTION_PUSHING);
+
+       InitMovingField(x, y, move_direction);
+       GfxAction[x][y] = ACTION_PUSHING;
+
+       if (mode == DF_SNAP)
+         ContinueMoving(x, y);
+       else
+         MovPos[x][y] = (dx != 0 ? dx : dy);
+
+       Pushed[x][y] = TRUE;
+       Pushed[nextx][nexty] = TRUE;
+
+       if (game.engine_version < RELEASE_IDENT(2,2,0,7))
+         player->push_delay_value = GET_NEW_PUSH_DELAY(element);
+
+       CheckTriggeredElementChange(x, y, element, CE_OTHER_GETS_PUSHED);
+       CheckElementChange(x, y, element, CE_PUSHED_BY_PLAYER);
+
+       break;
+      }
+      else
+      {
+       CheckTriggeredElementChange(x, y, element, CE_OTHER_GETS_PRESSED);
+       CheckElementChange(x, y, element, CE_PRESSED_BY_PLAYER);
+      }
 
-    default:
       return MF_NO_ACTION;
   }
 
   player->push_delay = 0;
 
+  if (Feld[x][y] != element)           /* really digged/collected something */
+    player->is_collecting = !player->is_digging;
+
   return MF_MOVING;
 }
 
@@ -6398,6 +7417,13 @@ boolean SnapField(struct PlayerInfo *player, int dx, int dy)
 {
   int jx = player->jx, jy = player->jy;
   int x = jx + dx, y = jy + dy;
+  int snap_direction = (dx == -1 ? MV_LEFT :
+                       dx == +1 ? MV_RIGHT :
+                       dy == -1 ? MV_UP :
+                       dy == +1 ? MV_DOWN : MV_NO_MOVING);
+
+  if (player->MovPos && game.engine_version >= VERSION_IDENT(2,2,0))
+    return FALSE;
 
   if (!player->active || !IN_LEV_FIELD(x, y))
     return FALSE;
@@ -6411,21 +7437,28 @@ boolean SnapField(struct PlayerInfo *player, int dx, int dy)
       player->Pushing = FALSE;
 
     player->snapped = FALSE;
+
+    if (player->MovPos == 0)
+    {
+      player->is_digging = FALSE;
+      player->is_collecting = FALSE;
+    }
+
     return FALSE;
   }
 
   if (player->snapped)
     return FALSE;
 
-  player->MovDir = (dx < 0 ? MV_LEFT :
-                   dx > 0 ? MV_RIGHT :
-                   dy < 0 ? MV_UP :
-                   dy > 0 ? MV_DOWN :  MV_NO_MOVING);
+  player->MovDir = snap_direction;
 
-  if (!DigField(player, x, y, 0, 0, DF_SNAP))
+  if (DigField(player, x, y, 0, 0, DF_SNAP) == MF_NO_ACTION)
     return FALSE;
 
   player->snapped = TRUE;
+  player->is_digging = FALSE;
+  player->is_collecting = FALSE;
+
   DrawLevelField(x, y);
   BackToFront();
 
@@ -6443,47 +7476,88 @@ boolean PlaceBomb(struct PlayerInfo *player)
   element = Feld[jx][jy];
 
   if ((player->dynamite == 0 && player->dynabombs_left == 0) ||
-      IS_ACTIVE_BOMB(element) || element == EL_EXPLODING)
+      IS_ACTIVE_BOMB(element) || element == EL_EXPLOSION)
+    return FALSE;
+
+#if 0
+  if (element != EL_EMPTY)
     return FALSE;
+#endif
 
-  if (element != EL_LEERRAUM)
+  if (element != EL_EMPTY)
+  {
+#if 0
     Store[jx][jy] = element;
+#else
+    Back[jx][jy] = element;
+#endif
+  }
+
+  MovDelay[jx][jy] = 96;
+
+  ResetGfxAnimation(jx, jy);
+  ResetRandomAnimationValue(jx, jy);
 
   if (player->dynamite)
   {
-    Feld[jx][jy] = EL_DYNAMITE_ACTIVE;
-    MovDelay[jx][jy] = 96;
+    Feld[jx][jy] = (player->use_disk_red_graphic ? EL_SP_DISK_RED_ACTIVE :
+                   EL_DYNAMITE_ACTIVE);
     player->dynamite--;
+
     DrawText(DX_DYNAMITE, DY_DYNAMITE, int2str(local_player->dynamite, 3),
-            FS_SMALL, FC_YELLOW);
+            FONT_TEXT_2);
     if (IN_SCR_FIELD(SCREENX(jx), SCREENY(jy)))
     {
+#if 1
+      DrawGraphicThruMask(SCREENX(jx), SCREENY(jy), el2img(Feld[jx][jy]), 0);
+#else
       if (game.emulation == EMU_SUPAPLEX)
-       DrawGraphic(SCREENX(jx), SCREENY(jy), GFX_SP_DISK_RED);
+       DrawGraphic(SCREENX(jx), SCREENY(jy), IMG_SP_DISK_RED, 0);
       else
-       DrawGraphicThruMask(SCREENX(jx), SCREENY(jy), GFX_DYNAMIT);
+       DrawGraphicThruMask(SCREENX(jx), SCREENY(jy), IMG_DYNAMITE_ACTIVE, 0);
+#endif
     }
 
-    PlaySoundLevel(jx, jy, SND_DYNAMITE_PLACING);
+    PlaySoundLevelAction(jx, jy, ACTION_DROPPING);
   }
   else
   {
-    Feld[jx][jy] = EL_DYNABOMB_ACTIVE_1 + (player->element_nr - EL_SPIELER1);
-    MovDelay[jx][jy] = 96;
+    Feld[jx][jy] =
+      EL_DYNABOMB_PLAYER_1_ACTIVE + (player->element_nr - EL_PLAYER_1);
     player->dynabombs_left--;
+
     if (IN_SCR_FIELD(SCREENX(jx), SCREENY(jy)))
-      DrawGraphicThruMask(SCREENX(jx), SCREENY(jy), GFX_DYNABOMB);
+      DrawGraphicThruMask(SCREENX(jx), SCREENY(jy), el2img(Feld[jx][jy]), 0);
 
-    PlaySoundLevel(jx, jy, SND_DYNABOMB_PLACING);
+    PlaySoundLevelAction(jx, jy, ACTION_DROPPING);
   }
 
   return TRUE;
 }
 
-void PlaySoundLevel(int x, int y, int nr)
+/* ------------------------------------------------------------------------- */
+/* game sound playing functions                                              */
+/* ------------------------------------------------------------------------- */
+
+static int *loop_sound_frame = NULL;
+static int *loop_sound_volume = NULL;
+
+void InitPlaySoundLevel()
+{
+  int num_sounds = getSoundListSize();
+
+  if (loop_sound_frame != NULL)
+    free(loop_sound_frame);
+
+  if (loop_sound_volume != NULL)
+    free(loop_sound_volume);
+
+  loop_sound_frame = checked_calloc(num_sounds * sizeof(int));
+  loop_sound_volume = checked_calloc(num_sounds * sizeof(int));
+}
+
+static void PlaySoundLevel(int x, int y, int nr)
 {
-  static int loop_sound_frame[NUM_SOUND_EFFECTS];
-  static int loop_sound_volume[NUM_SOUND_EFFECTS];
   int sx = SCREENX(x), sy = SCREENY(y);
   int volume, stereo_position;
   int max_distance = 8;
@@ -6527,51 +7601,84 @@ void PlaySoundLevel(int x, int y, int nr)
   PlaySoundExt(nr, volume, stereo_position, type);
 }
 
-void PlaySoundLevelAction(int x, int y, int sound_action)
+static void PlaySoundLevelNearest(int x, int y, int sound_action)
+{
+  PlaySoundLevel(x < LEVELX(BX1) ? LEVELX(BX1) :
+                x > LEVELX(BX2) ? LEVELX(BX2) : x,
+                y < LEVELY(BY1) ? LEVELY(BY1) :
+                y > LEVELY(BY2) ? LEVELY(BY2) : y,
+                sound_action);
+}
+
+static void PlaySoundLevelAction(int x, int y, int action)
+{
+  PlaySoundLevelElementAction(x, y, Feld[x][y], action);
+}
+
+static void PlaySoundLevelElementAction(int x, int y, int element, int action)
 {
-  PlaySoundLevelElementAction(x, y, Feld[x][y], sound_action);
+  int sound_effect = element_info[element].sound[action];
+
+  if (sound_effect != SND_UNDEFINED)
+    PlaySoundLevel(x, y, sound_effect);
 }
 
-void PlaySoundLevelElementAction(int x, int y, int element, int sound_action)
+static void PlaySoundLevelActionIfLoop(int x, int y, int action)
 {
-  int sound_effect = element_action_sound[element][sound_action];
+  int sound_effect = element_info[Feld[x][y]].sound[action];
 
-  if (sound_effect != -1)
+  if (sound_effect != SND_UNDEFINED && IS_LOOP_SOUND(sound_effect))
     PlaySoundLevel(x, y, sound_effect);
 }
 
+static void StopSoundLevelActionIfLoop(int x, int y, int action)
+{
+  int sound_effect = element_info[Feld[x][y]].sound[action];
+
+  if (sound_effect != SND_UNDEFINED && IS_LOOP_SOUND(sound_effect))
+    StopSoundExt(sound_effect, SND_CTRL_STOP_SOUND);
+}
+
 void RaiseScore(int value)
 {
   local_player->score += value;
-  DrawText(DX_SCORE, DY_SCORE, int2str(local_player->score, 5),
-          FS_SMALL, FC_YELLOW);
+  DrawText(DX_SCORE, DY_SCORE, int2str(local_player->score, 5), FONT_TEXT_2);
 }
 
 void RaiseScoreElement(int element)
 {
   switch(element)
   {
-    case EL_EDELSTEIN:
-    case EL_EDELSTEIN_BD:
-    case EL_EDELSTEIN_GELB:
-    case EL_EDELSTEIN_ROT:
-    case EL_EDELSTEIN_LILA:
-      RaiseScore(level.score[SC_EDELSTEIN]);
+    case EL_EMERALD:
+    case EL_BD_DIAMOND:
+    case EL_EMERALD_YELLOW:
+    case EL_EMERALD_RED:
+    case EL_EMERALD_PURPLE:
+    case EL_SP_INFOTRON:
+      RaiseScore(level.score[SC_EMERALD]);
+      break;
+    case EL_DIAMOND:
+      RaiseScore(level.score[SC_DIAMOND]);
       break;
-    case EL_DIAMANT:
-      RaiseScore(level.score[SC_DIAMANT]);
+    case EL_CRYSTAL:
+      RaiseScore(level.score[SC_CRYSTAL]);
+      break;
+    case EL_PEARL:
+      RaiseScore(level.score[SC_PEARL]);
       break;
-    case EL_KAEFER:
-    case EL_BUTTERFLY:
-      RaiseScore(level.score[SC_KAEFER]);
+    case EL_BUG:
+    case EL_BD_BUTTERFLY:
+    case EL_SP_ELECTRON:
+      RaiseScore(level.score[SC_BUG]);
       break;
-    case EL_FLIEGER:
-    case EL_FIREFLY:
-      RaiseScore(level.score[SC_FLIEGER]);
+    case EL_SPACESHIP:
+    case EL_BD_FIREFLY:
+    case EL_SP_SNIKSNAK:
+      RaiseScore(level.score[SC_SPACESHIP]);
       break;
-    case EL_MAMPFER:
-    case EL_MAMPFER2:
-      RaiseScore(level.score[SC_MAMPFER]);
+    case EL_YAMYAM:
+    case EL_DARK_YAMYAM:
+      RaiseScore(level.score[SC_YAMYAM]);
       break;
     case EL_ROBOT:
       RaiseScore(level.score[SC_ROBOT]);
@@ -6579,16 +7686,31 @@ void RaiseScoreElement(int element)
     case EL_PACMAN:
       RaiseScore(level.score[SC_PACMAN]);
       break;
-    case EL_KOKOSNUSS:
-      RaiseScore(level.score[SC_KOKOSNUSS]);
+    case EL_NUT:
+      RaiseScore(level.score[SC_NUT]);
+      break;
+    case EL_DYNAMITE:
+    case EL_SP_DISK_RED:
+    case EL_DYNABOMB_INCREASE_NUMBER:
+    case EL_DYNABOMB_INCREASE_SIZE:
+    case EL_DYNABOMB_INCREASE_POWER:
+      RaiseScore(level.score[SC_DYNAMITE]);
+      break;
+    case EL_SHIELD_NORMAL:
+    case EL_SHIELD_DEADLY:
+      RaiseScore(level.score[SC_SHIELD]);
       break;
-    case EL_DYNAMITE_INACTIVE:
-      RaiseScore(level.score[SC_DYNAMIT]);
+    case EL_EXTRA_TIME:
+      RaiseScore(level.score[SC_TIME_BONUS]);
       break;
-    case EL_SCHLUESSEL:
-      RaiseScore(level.score[SC_SCHLUESSEL]);
+    case EL_KEY_1:
+    case EL_KEY_2:
+    case EL_KEY_3:
+    case EL_KEY_4:
+      RaiseScore(level.score[SC_KEY]);
       break;
     default:
+      RaiseScore(element_info[element].score);
       break;
   }
 }
@@ -6607,7 +7729,7 @@ void RequestQuitGame(boolean ask_if_really_quit)
     else
 #endif
     {
-      game_status = MAINMENU;
+      game_status = GAME_MODE_MAIN;
       DrawMainMenu();
     }
   }
@@ -6680,7 +7802,7 @@ void CreateGameButtons()
 
   for (i=0; i<NUM_GAME_BUTTONS; i++)
   {
-    Bitmap *gd_bitmap = pix[PIX_DOOR];
+    Bitmap *gd_bitmap = graphic_info[IMG_GLOBAL_DOOR].bitmap;
     struct GadgetInfo *gi;
     int button_type;
     boolean checked;
@@ -6740,6 +7862,14 @@ void CreateGameButtons()
   }
 }
 
+void FreeGameButtons()
+{
+  int i;
+
+  for (i=0; i<NUM_GAME_BUTTONS; i++)
+    FreeGadget(game_gadget[i]);
+}
+
 static void MapGameButtons()
 {
   int i;
@@ -6760,7 +7890,7 @@ static void HandleGameButtons(struct GadgetInfo *gi)
 {
   int id = gi->custom_id;
 
-  if (game_status != PLAYING)
+  if (game_status != GAME_MODE_PLAYING)
     return;
 
   switch (id)
@@ -6807,6 +7937,8 @@ static void HandleGameButtons(struct GadgetInfo *gi)
       else if (audio.music_available)
       { 
        setup.sound = setup.sound_music = TRUE;
+
+       SetAudioMode(setup.sound);
        PlayMusic(level_nr);
       }
       break;
@@ -6815,14 +7947,20 @@ static void HandleGameButtons(struct GadgetInfo *gi)
       if (setup.sound_loops)
        setup.sound_loops = FALSE;
       else if (audio.loops_available)
+      {
        setup.sound = setup.sound_loops = TRUE;
+       SetAudioMode(setup.sound);
+      }
       break;
 
     case SOUND_CTRL_ID_SIMPLE:
       if (setup.sound_simple)
        setup.sound_simple = FALSE;
       else if (audio.sound_available)
+      {
        setup.sound = setup.sound_simple = TRUE;
+       SetAudioMode(setup.sound);
+      }
       break;
 
     default:
index 607e34e2bf97836b7d88d4a42db730b5141d861c..01209d95e53d733ace1fc96e2070d4a10b789f4b 100644 (file)
 #include "main.h"
 
 /* score for elements (also used by editor.c) */
-#define SC_EDELSTEIN           0
-#define SC_DIAMANT             1
-#define SC_KAEFER              2
-#define SC_FLIEGER             3
-#define SC_MAMPFER             4
+#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_KOKOSNUSS           7
-#define SC_DYNAMIT             8
-#define SC_SCHLUESSEL          9
-#define SC_ZEITBONUS           10
+#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
 
 void GetPlayerConfig(void);
 void DrawGameDoorValues(void);
@@ -37,6 +40,8 @@ void InitMovDir(int, int);
 void InitAmoebaNr(int, int);
 void GameWon(void);
 int NewHiScore(void);
+
+void InitPlayerGfxAnimation(struct PlayerInfo *, int, int);
 void InitMovingField(int, int, int);
 void Moving2Blocked(int, int, int *, int *);
 void Blocked2Moving(int, int, int *, int *);
@@ -91,11 +96,15 @@ void RemoveHero(struct PlayerInfo *);
 int DigField(struct PlayerInfo *, int, int, int, int, int);
 boolean SnapField(struct PlayerInfo *, int, int);
 boolean PlaceBomb(struct PlayerInfo *);
+
+void InitPlaySoundLevel();
+
 void RaiseScore(int);
 void RaiseScoreElement(int);
 void RequestQuitGame(boolean);
 
 void CreateGameButtons();
+void FreeGameButtons();
 void UnmapGameButtons();
 
 #endif
index 0e1fc339e647669f08750afa9b4a67888a66e916..79a67d1eb066eec2842660ddf6b26a633d2d62b2 100644 (file)
 #include "network.h"
 #include "netserv.h"
 #include "cartoons.h"
-#include "config.h"
 
-static char *image_filename[NUM_PICTURES] =
-{
-  "RocksScreen.pcx",
-  "RocksDoor.pcx",
-  "RocksHeroes.pcx",
-  "RocksToons.pcx",
-  "RocksSP.pcx",
-  "RocksDC.pcx",
-  "RocksMore.pcx",
-  "RocksFont.pcx",
-  "RocksFont2.pcx",
-  "RocksFont3.pcx"
-}; 
-
-static void InitSetup(void);
-static void InitPlayerInfo(void);
-static void InitLevelInfo(void);
-static void InitArtworkInfo(void);
-static void InitLevelArtworkInfo(void);
-static void InitNetworkServer(void);
-static void InitMixer(void);
-static void InitSound(void);
-static void InitGfx(void);
-static void InitGfxBackground(void);
-static void InitGadgets(void);
-static void InitElementProperties(void);
-static void Execute_Debug_Command(char *);
-
-void OpenAll(void)
-{
-  if (options.debug_command)
-  {
-    Execute_Debug_Command(options.debug_command);
-
-    exit(0);
-  }
-
-  if (options.serveronly)
-  {
-#if defined(PLATFORM_UNIX)
-    NetworkServer(options.server_port, options.serveronly);
-#else
-    Error(ERR_WARN, "networking only supported in Unix version");
-#endif
-    exit(0);   /* never reached */
-  }
-
-  InitProgramInfo(UNIX_USERDATA_DIRECTORY,
-                 PROGRAM_TITLE_STRING, getWindowTitleString(),
-                 ICON_TITLE_STRING, X11_ICON_FILENAME, X11_ICONMASK_FILENAME,
-                 MSDOS_POINTER_FILENAME,
-                 COOKIE_PREFIX, FILENAME_PREFIX, GAME_VERSION_ACTUAL);
-
-  InitSetup();
-  InitPlayerInfo();
-  InitArtworkInfo();           /* needed before loading gfx, sound & music */
-
-  InitCounter();
-  InitMixer();
-  InitJoysticks();
-  InitRND(NEW_RANDOMIZE);
-
-  InitVideoDisplay();
-  InitVideoBuffer(&backbuffer, &window, WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH,
-                 setup.fullscreen);
-
-  InitEventFilter(FilterMouseMotionEvents);
-
-  InitGfx();
-  InitElementProperties();     /* initializes IS_CHAR() for el2gfx() */
-
-  InitLevelInfo();
-  InitLevelArtworkInfo();
-  InitGadgets();               /* needs to know number of level series */
-  InitSound();                 /* needs to know current level directory */
-
-  InitGfxBackground();
-  InitToons();
-
-  DrawMainMenu();
-
-  InitNetworkServer();
-}
-
-void InitSetup()
-{
-  LoadSetup();                                 /* global setup info */
-}
-
-void InitPlayerInfo()
-{
-  int i;
-
-  /* choose default local player */
-  local_player = &stored_player[0];
-
-  for (i=0; i<MAX_PLAYERS; i++)
-    stored_player[i].connected = FALSE;
-
-  local_player->connected = TRUE;
-}
-
-void InitLevelInfo()
-{
-  LoadLevelInfo();                             /* global level info */
-  LoadLevelSetup_LastSeries();                 /* last played series info */
-  LoadLevelSetup_SeriesInfo();                 /* last played level info */
-}
-
-void InitArtworkInfo()
-{
-  LoadArtworkInfo();
-}
-
-void InitLevelArtworkInfo()
-{
-  LoadLevelArtworkInfo();
-}
-
-void InitNetworkServer()
-{
-#if defined(PLATFORM_UNIX)
-  int nr_wanted;
-#endif
-
-  if (!options.network)
-    return;
-
-#if defined(PLATFORM_UNIX)
-  nr_wanted = Request("Choose player", REQ_PLAYER | REQ_STAY_CLOSED);
+#include "conf_e2g.c"  /* include auto-generated data structure definitions */
+#include "conf_esg.c"  /* include auto-generated data structure definitions */
+#include "conf_e2s.c"  /* include auto-generated data structure definitions */
+#include "conf_fnt.c"  /* include auto-generated data structure definitions */
 
-  if (!ConnectToServer(options.server_host, options.server_port))
-    Error(ERR_EXIT, "cannot connect to network game server");
-
-  SendToServer_PlayerName(setup.player_name);
-  SendToServer_ProtocolVersion();
-
-  if (nr_wanted)
-    SendToServer_NrWanted(nr_wanted);
-#endif
-}
 
-static void InitMixer()
-{
-  OpenAudio();
-  InitSoundList(sound_effects, NUM_SOUND_EFFECTS);
+#define CONFIG_TOKEN_FONT_INITIAL              "font.initial"
 
-  StartMixer();
-}
 
-static void InitSound()
-{
-  /* load custom sounds and music */
-  InitReloadSounds(artwork.snd_current->name);
-  InitReloadMusic(artwork.mus_current->name);
+struct FontBitmapInfo font_initial[NUM_INITIAL_FONTS];
 
-  /* initialize sound effect lookup table for element actions */
-  InitGameSound();
-}
 
 static void InitTileClipmasks()
 {
+#if 0
 #if defined(TARGET_X11)
   XGCValues clip_gc_values;
   unsigned long clip_gc_valuemask;
 
 #if defined(TARGET_X11_NATIVE)
+
+#if 0
   GC copy_clipmask_gc;
 
   static struct
@@ -246,13 +100,15 @@ static void InitTileClipmasks()
     { GFX2_SHIELD_ACTIVE, 3 },
     { -1, 0 }
   };
+#endif
+
 #endif /* TARGET_X11_NATIVE */
 #endif /* TARGET_X11 */
 
   int i;
 
   /* initialize pixmap array for special X11 tile clipping to Pixmap 'None' */
-  for(i=0; i<NUM_TILES; i++)
+  for (i=0; i<NUM_TILES; i++)
     tile_clipmask[i] = None;
 
 #if defined(TARGET_X11)
@@ -263,10 +119,11 @@ static void InitTileClipmasks()
 
   clip_gc_values.graphics_exposures = False;
   clip_gc_valuemask = GCGraphicsExposures;
-  tile_clip_gc =
-    XCreateGC(display, window->drawable, clip_gc_valuemask, &clip_gc_values);
+  tile_clip_gc = XCreateGC(display, window->drawable,
+                          clip_gc_valuemask, &clip_gc_values);
 
-  for(i=0; i<NUM_BITMAPS; i++)
+#if 0
+  for (i=0; i<NUM_BITMAPS; i++)
   {
     if (pix[i]->clip_mask)
     {
@@ -277,31 +134,32 @@ static void InitTileClipmasks()
                                         clip_gc_valuemask, &clip_gc_values);
     }
   }
+#endif
 
 #if defined(TARGET_X11_NATIVE)
 
+#if 0
   /* create graphic context structures needed for clipping */
   clip_gc_values.graphics_exposures = False;
   clip_gc_valuemask = GCGraphicsExposures;
-  copy_clipmask_gc =
-    XCreateGC(display, pix[PIX_BACK]->clip_mask,
-             clip_gc_valuemask, &clip_gc_values);
+  copy_clipmask_gc = XCreateGC(display, pix[PIX_BACK]->clip_mask,
+                              clip_gc_valuemask, &clip_gc_values);
 
   /* create only those clipping Pixmaps we really need */
-  for(i=0; tile_needs_clipping[i].start>=0; i++)
+  for (i=0; tile_needs_clipping[i].start>=0; i++)
   {
     int j;
 
-    for(j=0; j<tile_needs_clipping[i].count; j++)
+    for (j=0; j<tile_needs_clipping[i].count; j++)
     {
       int tile = tile_needs_clipping[i].start + j;
       int graphic = tile;
       int src_x, src_y;
-      int pixmap_nr;
+      Bitmap *src_bitmap;
       Pixmap src_pixmap;
 
-      getGraphicSource(graphic, &pixmap_nr, &src_x, &src_y);
-      src_pixmap = pix[pixmap_nr]->clip_mask;
+      getGraphicSource(graphic, &src_bitmap, &src_x, &src_y);
+      src_pixmap = src_bitmap->clip_mask;
 
       tile_clipmask[tile] = XCreatePixmap(display, window->drawable,
                                          TILEX, TILEY, 1);
@@ -312,17 +170,20 @@ static void InitTileClipmasks()
   }
 
   XFreeGC(display, copy_clipmask_gc);
+#endif
 
 #endif /* TARGET_X11_NATIVE */
 #endif /* TARGET_X11 */
+#endif
 }
 
 void FreeTileClipmasks()
 {
+#if 0
 #if defined(TARGET_X11)
   int i;
 
-  for(i=0; i<NUM_TILES; i++)
+  for (i=0; i<NUM_TILES; i++)
   {
     if (tile_clipmask[i] != None)
     {
@@ -335,7 +196,8 @@ void FreeTileClipmasks()
     XFreeGC(display, tile_clip_gc);
   tile_clip_gc = None;
 
-  for(i=0; i<NUM_BITMAPS; i++)
+#if 0
+  for (i=0; i<NUM_BITMAPS; i++)
   {
     if (pix[i] != NULL && pix[i]->stored_clip_gc)
     {
@@ -343,307 +205,1210 @@ void FreeTileClipmasks()
       pix[i]->stored_clip_gc = None;
     }
   }
+#endif
+
 #endif /* TARGET_X11 */
+#endif
 }
 
-void InitGfx()
+void FreeGadgets()
+{
+  FreeLevelEditorGadgets();
+  FreeGameButtons();
+  FreeTapeButtons();
+  FreeToolButtons();
+  FreeScreenGadgets();
+}
+
+void InitGadgets()
+{
+  static boolean gadgets_initialized = FALSE;
+
+  if (gadgets_initialized)
+    FreeGadgets();
+
+  CreateLevelEditorGadgets();
+  CreateGameButtons();
+  CreateTapeButtons();
+  CreateToolButtons();
+  CreateScreenGadgets();
+
+  gadgets_initialized = TRUE;
+}
+
+void InitElementSmallImages()
 {
+  struct PropertyMapping *property_mapping = getImageListPropertyMapping();
+  int num_property_mappings = getImageListPropertyMappingSize();
   int i;
 
-  /* initialize some global variables */
-  global.frames_per_second = 0;
-  global.fps_slowdown = FALSE;
-  global.fps_slowdown_factor = 1;
+  /* initialize normal images from static configuration */
+  for (i=0; element_to_graphic[i].element > -1; i++)
+    CreateImageWithSmallImages(element_to_graphic[i].graphic);
 
-  /* initialize screen properties */
-  InitGfxFieldInfo(SX, SY, SXSIZE, SYSIZE,
-                  REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE);
-  InitGfxDoor1Info(DX, DY, DXSIZE, DYSIZE);
-  InitGfxDoor2Info(VX, VY, VXSIZE, VYSIZE);
-  InitGfxScrollbufferInfo(FXSIZE, FYSIZE);
+  /* initialize special images from static configuration */
+  for (i=0; element_to_special_graphic[i].element > -1; i++)
+    CreateImageWithSmallImages(element_to_special_graphic[i].graphic);
 
-  /* create additional image buffers for double-buffering */
-  pix[PIX_DB_DOOR] = CreateBitmap(3 * DXSIZE, DYSIZE + VYSIZE, DEFAULT_DEPTH);
-  pix[PIX_DB_FIELD] = CreateBitmap(FXSIZE, FYSIZE, DEFAULT_DEPTH);
+  /* initialize images from dynamic configuration */
+  for (i=0; i < num_property_mappings; i++)
+    if (property_mapping[i].artwork_index < MAX_NUM_ELEMENTS)
+      CreateImageWithSmallImages(property_mapping[i].artwork_index);
+}
 
-  pix[PIX_SMALLFONT] = LoadCustomImage(image_filename[PIX_SMALLFONT]);
+static int getFontBitmapID(int font_nr)
+{
+  int special = -1;
+
+  if (game_status >= GAME_MODE_MAIN && game_status <= GAME_MODE_PSEUDO_PREVIEW)
+    special = game_status;
+  else if (game_status == GAME_MODE_PSEUDO_TYPENAME)
+    special = GFX_SPECIAL_ARG_MAIN;
+  else if (game_status == GAME_MODE_PLAYING)
+    special = GFX_SPECIAL_ARG_DOOR;
+
+  if (special != -1)
+    return font_info[font_nr].special_bitmap_id[special];
+  else
+    return font_nr;
+}
 
-  InitFontInfo(NULL, NULL, pix[PIX_SMALLFONT]);
+void InitFontGraphicInfo()
+{
+  static struct FontBitmapInfo *font_bitmap_info = NULL;
+  struct PropertyMapping *property_mapping = getImageListPropertyMapping();
+  int num_property_mappings = getImageListPropertyMappingSize();
+  int num_font_bitmaps = NUM_FONTS;
+  int i, j;
 
-  DrawInitText(WINDOW_TITLE_STRING, 20, FC_YELLOW);
-  DrawInitText(WINDOW_SUBTITLE_STRING, 50, FC_RED);
+  if (graphic_info == NULL)            /* still at startup phase */
+  {
+    InitFontInfo(font_initial, NUM_INITIAL_FONTS, getFontBitmapID);
 
-  DrawInitText("Loading graphics:", 120, FC_GREEN);
+    return;
+  }
+
+  /* ---------- initialize font graphic definitions ---------- */
+
+  /* always start with reliable default values (normal font graphics) */
+  for (i=0; i < NUM_FONTS; i++)
+    font_info[i].graphic = FONT_INITIAL_1;
+
+  /* initialize normal font/graphic mapping from static configuration */
+  for (i=0; font_to_graphic[i].font_nr > -1; i++)
+  {
+    int font_nr = font_to_graphic[i].font_nr;
+    int special = font_to_graphic[i].special;
+    int graphic = font_to_graphic[i].graphic;
+
+    if (special != -1)
+      continue;
+
+    font_info[font_nr].graphic = graphic;
+  }
+
+  /* always start with reliable default values (special font graphics) */
+  for (i=0; i < NUM_FONTS; i++)
+  {
+    for (j=0; j < NUM_SPECIAL_GFX_ARGS; j++)
+    {
+      font_info[i].special_graphic[j] = font_info[i].graphic;
+      font_info[i].special_bitmap_id[j] = i;
+    }
+  }
 
-  for(i=0; i<NUM_PICTURES; i++)
+  /* initialize special font/graphic mapping from static configuration */
+  for (i=0; font_to_graphic[i].font_nr > -1; i++)
   {
-    if (i != PIX_SMALLFONT)
+    int font_nr = font_to_graphic[i].font_nr;
+    int special = font_to_graphic[i].special;
+    int graphic = font_to_graphic[i].graphic;
+
+    if (special >= 0 && special < NUM_SPECIAL_GFX_ARGS)
     {
-      DrawInitText(image_filename[i], 150, FC_YELLOW);
+      font_info[font_nr].special_graphic[special] = graphic;
+      font_info[font_nr].special_bitmap_id[special] = num_font_bitmaps;
+      num_font_bitmaps++;
+    }
+  }
 
-      pix[i] = LoadCustomImage(image_filename[i]);
+  /* initialize special element/graphic mapping from dynamic configuration */
+  for (i=0; i < num_property_mappings; i++)
+  {
+    int font_nr = property_mapping[i].base_index - MAX_NUM_ELEMENTS;
+    int special = property_mapping[i].ext3_index;
+    int graphic = property_mapping[i].artwork_index;
+
+    if (font_nr < 0)
+      continue;
+
+    if (special >= 0 && special < NUM_SPECIAL_GFX_ARGS)
+    {
+      font_info[font_nr].special_graphic[special] = graphic;
+      font_info[font_nr].special_bitmap_id[special] = num_font_bitmaps;
+      num_font_bitmaps++;
     }
   }
 
-  InitFontInfo(pix[PIX_BIGFONT], pix[PIX_MEDIUMFONT], pix[PIX_SMALLFONT]);
+  /* ---------- initialize font bitmap array ---------- */
 
-  InitTileClipmasks();
-}
+  if (font_bitmap_info != NULL)
+    FreeFontInfo(font_bitmap_info);
 
-void InitGfxBackground()
-{
-  int x, y;
+  font_bitmap_info =
+    checked_calloc(num_font_bitmaps * sizeof(struct FontBitmapInfo));
 
-  drawto = backbuffer;
-  fieldbuffer = pix[PIX_DB_FIELD];
-  SetDrawtoField(DRAW_BACKBUFFER);
+  /* ---------- initialize font bitmap definitions ---------- */
 
-  BlitBitmap(pix[PIX_BACK], backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
-  ClearRectangle(backbuffer, REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE);
-  ClearRectangle(pix[PIX_DB_DOOR], 0, 0, 3 * DXSIZE, DYSIZE + VYSIZE);
+  for (i=0; i < NUM_FONTS; i++)
+  {
+    if (i < NUM_INITIAL_FONTS)
+    {
+      font_bitmap_info[i] = font_initial[i];
+      continue;
+    }
 
-  for(x=0; x<MAX_BUF_XSIZE; x++)
-    for(y=0; y<MAX_BUF_YSIZE; y++)
-      redraw[x][y] = 0;
-  redraw_tiles = 0;
-  redraw_mask = REDRAW_ALL;
+    for (j=0; j < NUM_SPECIAL_GFX_ARGS; j++)
+    {
+      int font_bitmap_id = font_info[i].special_bitmap_id[j];
+      int graphic = font_info[i].special_graphic[j];
+
+      /* set 'graphic_info' for font entries, if uninitialized (guessed) */
+      if (graphic_info[graphic].anim_frames < MIN_NUM_CHARS_PER_FONT)
+      {
+       graphic_info[graphic].anim_frames = DEFAULT_NUM_CHARS_PER_FONT;
+       graphic_info[graphic].anim_frames_per_line= DEFAULT_NUM_CHARS_PER_LINE;
+      }
+
+      /* copy font relevant information from graphics information */
+      font_bitmap_info[font_bitmap_id].bitmap = graphic_info[graphic].bitmap;
+      font_bitmap_info[font_bitmap_id].src_x  = graphic_info[graphic].src_x;
+      font_bitmap_info[font_bitmap_id].src_y  = graphic_info[graphic].src_y;
+      font_bitmap_info[font_bitmap_id].width  = graphic_info[graphic].width;
+      font_bitmap_info[font_bitmap_id].height = graphic_info[graphic].height;
+      font_bitmap_info[font_bitmap_id].draw_x = graphic_info[graphic].draw_x;
+      font_bitmap_info[font_bitmap_id].draw_y = graphic_info[graphic].draw_y;
+
+      font_bitmap_info[font_bitmap_id].num_chars =
+       graphic_info[graphic].anim_frames;
+      font_bitmap_info[font_bitmap_id].num_chars_per_line =
+       graphic_info[graphic].anim_frames_per_line;
+    }
+  }
+
+  InitFontInfo(font_bitmap_info, num_font_bitmaps, getFontBitmapID);
 }
 
-void ReloadCustomArtwork()
+void InitElementGraphicInfo()
 {
-  static char *leveldir_current_filename = NULL;
-  static boolean last_override_level_graphics = FALSE;
-  static boolean last_override_level_sounds = FALSE;
-  static boolean last_override_level_music = FALSE;
-
-  if (leveldir_current_filename != leveldir_current->filename)
-  {
-    char *filename_old = leveldir_current_filename;
-    char *filename_new = leveldir_current->filename;
-
-    /* force reload of custom artwork after new level series was selected,
-       but reload only that part of the artwork that really has changed */
-    if (getTreeInfoFromFilename(artwork.gfx_first, filename_old) !=
-       getTreeInfoFromFilename(artwork.gfx_first, filename_new))
-      artwork.graphics_set_current_name = NULL;
-    if (getTreeInfoFromFilename(artwork.snd_first, filename_old) !=
-       getTreeInfoFromFilename(artwork.snd_first, filename_new))
-      artwork.sounds_set_current_name = NULL;
-    if (getTreeInfoFromFilename(artwork.mus_first, filename_new) !=
-       getTreeInfoFromFilename(artwork.mus_first, filename_new))
-      artwork.music_set_current_name = NULL;
-
-    leveldir_current_filename = leveldir_current->filename;
+  struct PropertyMapping *property_mapping = getImageListPropertyMapping();
+  int num_property_mappings = getImageListPropertyMappingSize();
+  int i, act, dir;
+
+  /* set values to -1 to identify later as "uninitialized" values */
+  for (i=0; i<MAX_NUM_ELEMENTS; i++)
+  {
+    for (act=0; act<NUM_ACTIONS; act++)
+    {
+      element_info[i].graphic[act] = -1;
+      element_info[i].crumbled[act] = -1;
+
+      for (dir=0; dir<NUM_DIRECTIONS; dir++)
+      {
+       element_info[i].direction_graphic[act][dir] = -1;
+       element_info[i].direction_crumbled[act][dir] = -1;
+      }
+    }
   }
 
-  if (artwork.graphics_set_current_name != artwork.gfx_current->name ||
-      last_override_level_graphics != setup.override_level_graphics)
+  /* initialize normal element/graphic mapping from static configuration */
+  for (i=0; element_to_graphic[i].element > -1; i++)
   {
-    int i;
+    int element      = element_to_graphic[i].element;
+    int action       = element_to_graphic[i].action;
+    int direction    = element_to_graphic[i].direction;
+    boolean crumbled = element_to_graphic[i].crumbled;
+    int graphic      = element_to_graphic[i].graphic;
 
-    ClearRectangle(window, 0, 0, WIN_XSIZE, WIN_YSIZE);
+    if (graphic_info[graphic].bitmap == NULL)
+      continue;
 
-    for(i=0; i<NUM_PICTURES; i++)
+    if ((action > -1 || direction > -1 || crumbled == TRUE) &&
+       el2img(element) != -1)
     {
-      DrawInitText(image_filename[i], 150, FC_YELLOW);
-      ReloadCustomImage(pix[i], image_filename[i]);
+      boolean base_redefined = getImageListEntry(el2img(element))->redefined;
+      boolean act_dir_redefined = getImageListEntry(graphic)->redefined;
+
+      /* if the base graphic ("emerald", for example) has been redefined,
+        but not the action graphic ("emerald.falling", for example), do not
+        use an existing (in this case considered obsolete) action graphic
+        anymore, but use the automatically determined default graphic */
+      if (base_redefined && !act_dir_redefined)
+       continue;
     }
 
-    FreeTileClipmasks();
-    InitTileClipmasks();
-    InitGfxBackground();
+    if (action < 0)
+      action = ACTION_DEFAULT;
 
-    /* force redraw of (open or closed) door graphics */
-    SetDoorState(DOOR_OPEN_ALL);
-    CloseDoor(DOOR_CLOSE_ALL | DOOR_NO_DELAY);
+    if (crumbled)
+    {
+      if (direction > -1)
+       element_info[element].direction_crumbled[action][direction] = graphic;
+      else
+       element_info[element].crumbled[action] = graphic;
+    }
+    else
+    {
+      if (direction > -1)
+       element_info[element].direction_graphic[action][direction] = graphic;
+      else
+       element_info[element].graphic[action] = graphic;
+    }
+  }
+
+  /* initialize normal element/graphic mapping from dynamic configuration */
+  for (i=0; i < num_property_mappings; i++)
+  {
+    int element   = property_mapping[i].base_index;
+    int action    = property_mapping[i].ext1_index;
+    int direction = property_mapping[i].ext2_index;
+    int special   = property_mapping[i].ext3_index;
+    int graphic   = property_mapping[i].artwork_index;
+    boolean crumbled = FALSE;
+
+    if (special == GFX_SPECIAL_ARG_CRUMBLED)
+    {
+      special = -1;
+      crumbled = TRUE;
+    }
 
-    artwork.graphics_set_current_name = artwork.gfx_current->name;
-    last_override_level_graphics = setup.override_level_graphics;
+    if (graphic_info[graphic].bitmap == NULL)
+      continue;
+
+    if (element >= MAX_NUM_ELEMENTS || special != -1)
+      continue;
+
+    if (action < 0)
+      action = ACTION_DEFAULT;
+
+    if (crumbled)
+    {
+      if (direction < 0)
+       for (dir=0; dir<NUM_DIRECTIONS; dir++)
+         element_info[element].direction_crumbled[action][dir] = -1;
+
+      if (direction > -1)
+       element_info[element].direction_crumbled[action][direction] = graphic;
+      else
+       element_info[element].crumbled[action] = graphic;
+    }
+    else
+    {
+      if (direction < 0)
+       for (dir=0; dir<NUM_DIRECTIONS; dir++)
+         element_info[element].direction_graphic[action][dir] = -1;
+
+      if (direction > -1)
+       element_info[element].direction_graphic[action][direction] = graphic;
+      else
+       element_info[element].graphic[action] = graphic;
+    }
   }
 
-  if (artwork.sounds_set_current_name != artwork.snd_current->name ||
-      last_override_level_sounds != setup.override_level_sounds)
+  /* now copy all graphics that are defined to be cloned from other graphics */
+  for (i=0; i<MAX_NUM_ELEMENTS; i++)
   {
-    InitReloadSounds(artwork.snd_current->name);
+    int graphic = element_info[i].graphic[ACTION_DEFAULT];
+    int crumbled_like, diggable_like;
+
+    if (graphic == -1)
+      continue;
 
-    artwork.sounds_set_current_name = artwork.snd_current->name;
-    last_override_level_sounds = setup.override_level_sounds;
+    crumbled_like = graphic_info[graphic].crumbled_like;
+    diggable_like = graphic_info[graphic].diggable_like;
+
+    if (crumbled_like != -1 && element_info[i].crumbled[ACTION_DEFAULT] == -1)
+    {
+      for (act=0; act<NUM_ACTIONS; act++)
+       element_info[i].crumbled[act] =
+         element_info[crumbled_like].crumbled[act];
+      for (act=0; act<NUM_ACTIONS; act++)
+       for (dir=0; dir<NUM_DIRECTIONS; dir++)
+         element_info[i].direction_crumbled[act][dir] =
+           element_info[crumbled_like].direction_crumbled[act][dir];
+    }
+
+    if (diggable_like != -1 && element_info[i].graphic[ACTION_DIGGING] == -1)
+    {
+      element_info[i].graphic[ACTION_DIGGING] =
+       element_info[diggable_like].graphic[ACTION_DIGGING];
+      for (dir=0; dir<NUM_DIRECTIONS; dir++)
+       element_info[i].direction_graphic[ACTION_DIGGING][dir] =
+         element_info[diggable_like].direction_graphic[ACTION_DIGGING][dir];
+    }
   }
 
-  if (artwork.music_set_current_name != artwork.mus_current->name ||
-      last_override_level_music != setup.override_level_music)
+  /* now set all '-1' values to element specific default values */
+  for (i=0; i<MAX_NUM_ELEMENTS; i++)
   {
-    InitReloadMusic(artwork.mus_current->name);
+    int default_graphic = element_info[i].graphic[ACTION_DEFAULT];
+    int default_crumbled = element_info[i].crumbled[ACTION_DEFAULT];
+    int default_direction_graphic[NUM_DIRECTIONS];
+    int default_direction_crumbled[NUM_DIRECTIONS];
+
+    if (default_graphic == -1)
+      default_graphic = IMG_CHAR_QUESTION;
+    if (default_crumbled == -1)
+      default_crumbled = IMG_EMPTY;
+
+    for (dir=0; dir<NUM_DIRECTIONS; dir++)
+    {
+      default_direction_graphic[dir] =
+       element_info[i].direction_graphic[ACTION_DEFAULT][dir];
+      default_direction_crumbled[dir] =
+       element_info[i].direction_crumbled[ACTION_DEFAULT][dir];
+
+      if (default_direction_graphic[dir] == -1)
+       default_direction_graphic[dir] = default_graphic;
+      if (default_direction_crumbled[dir] == -1)
+       default_direction_crumbled[dir] = default_crumbled;
+    }
+
+    for (act=0; act<NUM_ACTIONS; act++)
+    {
+      boolean act_remove = (act == ACTION_DIGGING ||
+                           act == ACTION_SNAPPING ||
+                           act == ACTION_COLLECTING);
+
+      /* generic default action graphic (defined by "[default]" directive) */
+      int default_action_graphic = element_info[EL_DEFAULT].graphic[act];
+      int default_action_crumbled = element_info[EL_DEFAULT].crumbled[act];
+
+      /* 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_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)
+       default_action_graphic = element_info[EL_SB_DEFAULT].graphic[act];
+
+      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_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)
+       default_action_crumbled = element_info[EL_SB_DEFAULT].crumbled[act];
+
+      if (default_action_graphic == -1)
+       default_action_graphic = default_graphic;
+      if (default_action_crumbled == -1)
+       default_action_crumbled = default_crumbled;
+
+      for (dir=0; dir<NUM_DIRECTIONS; dir++)
+      {
+       int default_action_direction_graphic = element_info[i].graphic[act];
+       int default_action_direction_crumbled = element_info[i].crumbled[act];
+
+       /* no graphic for current action -- use default direction graphic */
+       if (default_action_direction_graphic == -1)
+         default_action_direction_graphic =
+           (act_remove ? IMG_EMPTY : default_direction_graphic[dir]);
+       if (default_action_direction_crumbled == -1)
+         default_action_direction_crumbled =
+           (act_remove ? IMG_EMPTY : default_direction_crumbled[dir]);
+
+       if (element_info[i].direction_graphic[act][dir] == -1)
+         element_info[i].direction_graphic[act][dir] =
+           default_action_direction_graphic;
+       if (element_info[i].direction_crumbled[act][dir] == -1)
+         element_info[i].direction_crumbled[act][dir] =
+           default_action_direction_crumbled;
+      }
+
+      /* no graphic for this specific action -- use default action graphic */
+      if (element_info[i].graphic[act] == -1)
+       element_info[i].graphic[act] =
+         (act_remove ? IMG_EMPTY : default_action_graphic);
+      if (element_info[i].crumbled[act] == -1)
+       element_info[i].crumbled[act] =
+         (act_remove ? IMG_EMPTY : default_action_crumbled);
+    }
+  }
 
-    artwork.music_set_current_name = artwork.mus_current->name;
-    last_override_level_music = setup.override_level_music;
+#if 0
+#if DEBUG
+  if (options.verbose)
+  {
+    for (i=0; i<MAX_NUM_ELEMENTS; i++)
+      if (element_info[i].graphic[ACTION_DEFAULT] == IMG_CHAR_QUESTION &&
+         i != EL_CHAR_QUESTION)
+       Error(ERR_RETURN, "warning: no graphic for element '%s' (%d)",
+             element_info[i].token_name, i);
   }
+#endif
+#endif
 }
 
-void InitGadgets()
+void InitElementSpecialGraphicInfo()
 {
-  CreateLevelEditorGadgets();
-  CreateGameButtons();
-  CreateTapeButtons();
-  CreateToolButtons();
-  CreateScreenGadgets();
+  struct PropertyMapping *property_mapping = getImageListPropertyMapping();
+  int num_property_mappings = getImageListPropertyMappingSize();
+  int i, j;
+
+  /* always start with reliable default values */
+  for (i=0; i < MAX_NUM_ELEMENTS; i++)
+    for (j=0; j < NUM_SPECIAL_GFX_ARGS; j++)
+      element_info[i].special_graphic[j] =
+       element_info[i].graphic[ACTION_DEFAULT];
+
+  /* initialize special element/graphic mapping from static configuration */
+  for (i=0; element_to_special_graphic[i].element > -1; i++)
+  {
+    int element = element_to_special_graphic[i].element;
+    int special = element_to_special_graphic[i].special;
+    int graphic = element_to_special_graphic[i].graphic;
+    boolean base_redefined = getImageListEntry(el2img(element))->redefined;
+    boolean special_redefined = getImageListEntry(graphic)->redefined;
+
+    /* if the base graphic ("emerald", for example) has been redefined,
+       but not the special graphic ("emerald.EDITOR", for example), do not
+       use an existing (in this case considered obsolete) special graphic
+       anymore, but use the automatically created (down-scaled) graphic */
+    if (base_redefined && !special_redefined)
+      continue;
+
+    element_info[element].special_graphic[special] = graphic;
+  }
+
+  /* initialize special element/graphic mapping from dynamic configuration */
+  for (i=0; i < num_property_mappings; i++)
+  {
+    int element = property_mapping[i].base_index;
+    int special = property_mapping[i].ext3_index;
+    int graphic = property_mapping[i].artwork_index;
+
+    if (element >= MAX_NUM_ELEMENTS)
+      continue;
+
+    if (special >= 0 && special < NUM_SPECIAL_GFX_ARGS)
+      element_info[element].special_graphic[special] = graphic;
+  }
 }
 
-void InitElementProperties()
+static int get_element_from_token(char *token)
 {
-  int i,j;
+  int i;
 
-  static int ep_amoebalive[] =
-  {
-    EL_AMOEBE_NASS,
-    EL_AMOEBE_NORM,
-    EL_AMOEBE_VOLL,
-    EL_AMOEBE_BD
-  };
-  static int ep_amoebalive_num = SIZEOF_ARRAY_INT(ep_amoebalive);
+  for (i=0; i < MAX_NUM_ELEMENTS; i++)
+    if (strcmp(element_info[i].token_name, token) == 0)
+      return i;
 
-  static int ep_amoeboid[] =
-  {
-    EL_AMOEBE_TOT,
-    EL_AMOEBE_NASS,
-    EL_AMOEBE_NORM,
-    EL_AMOEBE_VOLL,
-    EL_AMOEBE_BD
-  };
-  static int ep_amoeboid_num = SIZEOF_ARRAY_INT(ep_amoeboid);
+  return -1;
+}
 
-  static int ep_schluessel[] =
-  {
-    EL_SCHLUESSEL1,
-    EL_SCHLUESSEL2,
-    EL_SCHLUESSEL3,
-    EL_SCHLUESSEL4,
-    EL_EM_KEY_1,
+static void set_graphic_parameters(int graphic, char **parameter_raw)
+{
+  Bitmap *src_bitmap = getBitmapFromImageID(graphic);
+  int parameter[NUM_GFX_ARGS];
+  int anim_frames_per_row = 1, anim_frames_per_col = 1;
+  int anim_frames_per_line = 1;
+  int i;
+
+  /* get integer values from string parameters */
+  for (i=0; i < NUM_GFX_ARGS; i++)
+  {
+    parameter[i] =
+      get_parameter_value(image_config_suffix[i].token, parameter_raw[i],
+                         image_config_suffix[i].type);
+
+    if (image_config_suffix[i].type == TYPE_TOKEN)
+      parameter[i] = get_element_from_token(parameter_raw[i]);
+  }
+
+  graphic_info[graphic].bitmap = src_bitmap;
+
+  /* start with reliable default values */
+  graphic_info[graphic].src_x = 0;
+  graphic_info[graphic].src_y = 0;
+  graphic_info[graphic].width = TILEX;
+  graphic_info[graphic].height = TILEY;
+  graphic_info[graphic].offset_x = 0;  /* one or both of these values ... */
+  graphic_info[graphic].offset_y = 0;  /* ... will be corrected later */
+  graphic_info[graphic].crumbled_like = -1;    /* do not use clone element */
+  graphic_info[graphic].diggable_like = -1;    /* do not use clone element */
+
+  /* optional x and y tile position of animation frame sequence */
+  if (parameter[GFX_ARG_XPOS] != ARG_UNDEFINED_VALUE)
+    graphic_info[graphic].src_x = parameter[GFX_ARG_XPOS] * TILEX;
+  if (parameter[GFX_ARG_YPOS] != ARG_UNDEFINED_VALUE)
+    graphic_info[graphic].src_y = parameter[GFX_ARG_YPOS] * TILEY;
+
+  /* optional x and y pixel position of animation frame sequence */
+  if (parameter[GFX_ARG_X] != ARG_UNDEFINED_VALUE)
+    graphic_info[graphic].src_x = parameter[GFX_ARG_X];
+  if (parameter[GFX_ARG_Y] != ARG_UNDEFINED_VALUE)
+    graphic_info[graphic].src_y = parameter[GFX_ARG_Y];
+
+  /* optional width and height of each animation frame */
+  if (parameter[GFX_ARG_WIDTH] != ARG_UNDEFINED_VALUE)
+    graphic_info[graphic].width = parameter[GFX_ARG_WIDTH];
+  if (parameter[GFX_ARG_HEIGHT] != ARG_UNDEFINED_VALUE)
+    graphic_info[graphic].height = parameter[GFX_ARG_HEIGHT];
+
+  if (src_bitmap)
+  {
+    anim_frames_per_row = src_bitmap->width  / graphic_info[graphic].width;
+    anim_frames_per_col = src_bitmap->height / graphic_info[graphic].height;
+  }
+
+  /* correct x or y offset dependent of vertical or horizontal frame order */
+  if (parameter[GFX_ARG_VERTICAL])     /* frames are ordered vertically */
+  {
+    graphic_info[graphic].offset_y =
+      (parameter[GFX_ARG_OFFSET] != ARG_UNDEFINED_VALUE ?
+       parameter[GFX_ARG_OFFSET] : graphic_info[graphic].height);
+    anim_frames_per_line = anim_frames_per_col;
+  }
+  else                                 /* frames are ordered horizontally */
+  {
+    graphic_info[graphic].offset_x =
+      (parameter[GFX_ARG_OFFSET] != ARG_UNDEFINED_VALUE ?
+       parameter[GFX_ARG_OFFSET] : graphic_info[graphic].width);
+    anim_frames_per_line = anim_frames_per_row;
+  }
+
+  /* optionally, the x and y offset of frames can be specified directly */
+  if (parameter[GFX_ARG_XOFFSET] != ARG_UNDEFINED_VALUE)
+    graphic_info[graphic].offset_x = parameter[GFX_ARG_XOFFSET];
+  if (parameter[GFX_ARG_YOFFSET] != ARG_UNDEFINED_VALUE)
+    graphic_info[graphic].offset_y = parameter[GFX_ARG_YOFFSET];
+
+  /* automatically determine correct number of frames, if not defined */
+  if (parameter[GFX_ARG_FRAMES] != ARG_UNDEFINED_VALUE)
+    graphic_info[graphic].anim_frames = parameter[GFX_ARG_FRAMES];
+  else if (parameter[GFX_ARG_XPOS] == 0 && !parameter[GFX_ARG_VERTICAL])
+    graphic_info[graphic].anim_frames =        anim_frames_per_row;
+  else if (parameter[GFX_ARG_YPOS] == 0 && parameter[GFX_ARG_VERTICAL])
+    graphic_info[graphic].anim_frames =        anim_frames_per_col;
+  else
+    graphic_info[graphic].anim_frames = 1;
+
+  graphic_info[graphic].anim_frames_per_line =
+    (parameter[GFX_ARG_FRAMES_PER_LINE] != ARG_UNDEFINED_VALUE ?
+     parameter[GFX_ARG_FRAMES_PER_LINE] : anim_frames_per_line);
+
+  graphic_info[graphic].anim_delay = parameter[GFX_ARG_DELAY];
+  if (graphic_info[graphic].anim_delay == 0)   /* delay must be at least 1 */
+    graphic_info[graphic].anim_delay = 1;
+
+  graphic_info[graphic].anim_mode = parameter[GFX_ARG_ANIM_MODE];
+  if (graphic_info[graphic].anim_frames == 1)
+    graphic_info[graphic].anim_mode = ANIM_NONE;
+
+  /* automatically determine correct start frame, if not defined */
+  if (parameter[GFX_ARG_START_FRAME] == ARG_UNDEFINED_VALUE)
+    graphic_info[graphic].anim_start_frame = 0;
+  else if (graphic_info[graphic].anim_mode & ANIM_REVERSE)
+    graphic_info[graphic].anim_start_frame =
+      graphic_info[graphic].anim_frames - parameter[GFX_ARG_START_FRAME] - 1;
+  else
+    graphic_info[graphic].anim_start_frame = parameter[GFX_ARG_START_FRAME];
+
+  /* animation synchronized with global frame counter, not move position */
+  graphic_info[graphic].anim_global_sync = parameter[GFX_ARG_GLOBAL_SYNC];
+
+  /* optional element for cloning crumble graphics */
+  if (parameter[GFX_ARG_CRUMBLED_LIKE] != ARG_UNDEFINED_VALUE)
+    graphic_info[graphic].crumbled_like = parameter[GFX_ARG_CRUMBLED_LIKE];
+
+  /* optional element for cloning digging graphics */
+  if (parameter[GFX_ARG_DIGGABLE_LIKE] != ARG_UNDEFINED_VALUE)
+    graphic_info[graphic].diggable_like = parameter[GFX_ARG_DIGGABLE_LIKE];
+
+  /* this is only used for toon animations */
+  graphic_info[graphic].step_offset = parameter[GFX_ARG_STEP_OFFSET];
+  graphic_info[graphic].step_delay  = parameter[GFX_ARG_STEP_DELAY];
+
+  /* this is only used for drawing font characters */
+  graphic_info[graphic].draw_x = parameter[GFX_ARG_DRAW_XOFFSET];
+  graphic_info[graphic].draw_y = parameter[GFX_ARG_DRAW_YOFFSET];
+}
+
+static void InitGraphicInfo()
+{
+  int fallback_graphic = IMG_CHAR_EXCLAM;
+  struct FileInfo *fallback_image = getImageListEntry(fallback_graphic);
+  Bitmap *fallback_bitmap = getBitmapFromImageID(fallback_graphic);
+  int num_images = getImageListSize();
+  int i;
+
+#if defined(TARGET_X11_NATIVE_PERFORMANCE_WORKAROUND)
+  static boolean clipmasks_initialized = FALSE;
+  Pixmap src_pixmap;
+  XGCValues clip_gc_values;
+  unsigned long clip_gc_valuemask;
+  GC copy_clipmask_gc = None;
+#endif
+
+  if (graphic_info != NULL)
+    free(graphic_info);
+
+  graphic_info = checked_calloc(num_images * sizeof(struct GraphicInfo));
+
+#if defined(TARGET_X11_NATIVE_PERFORMANCE_WORKAROUND)
+  if (clipmasks_initialized)
+  {
+    for (i=0; i<num_images; i++)
+    {
+      if (graphic_info[i].clip_mask)
+       XFreePixmap(display, graphic_info[i].clip_mask);
+      if (graphic_info[i].clip_gc)
+       XFreeGC(display, graphic_info[i].clip_gc);
+
+      graphic_info[i].clip_mask = None;
+      graphic_info[i].clip_gc = None;
+    }
+  }
+#endif
+
+  for (i=0; i<num_images; i++)
+  {
+    struct FileInfo *image = getImageListEntry(i);
+    Bitmap *src_bitmap;
+    int src_x, src_y;
+    int first_frame, last_frame;
+
+#if 0
+    printf("::: image: '%s'\n", image->token);
+#endif
+
+#if 0
+    printf("::: image # %d: '%s' ['%s']\n",
+          i, image->token,
+          getTokenFromImageID(i));
+#endif
+
+    set_graphic_parameters(i, image->parameter);
+
+    /* now check if no animation frames are outside of the loaded image */
+
+    if (graphic_info[i].bitmap == NULL)
+      continue;                /* skip check for optional images that are undefined */
+
+    first_frame = 0;
+    getGraphicSource(i, first_frame, &src_bitmap, &src_x, &src_y);
+    if (src_x < 0 || src_y < 0 ||
+       src_x + TILEX > src_bitmap->width ||
+       src_y + TILEY > src_bitmap->height)
+    {
+      Error(ERR_RETURN_LINE, "-");
+      Error(ERR_RETURN, "warning: error found in config file:");
+      Error(ERR_RETURN, "- config file: '%s'",
+           getImageConfigFilename());
+      Error(ERR_RETURN, "- config token: '%s'",
+           getTokenFromImageID(i));
+      Error(ERR_RETURN, "- image file: '%s'",
+           src_bitmap->source_filename);
+      Error(ERR_RETURN,
+           "error: first animation frame out of bounds (%d, %d)",
+           src_x, src_y);
+      Error(ERR_RETURN, "custom graphic rejected for this element/action");
+
+      if (i == fallback_graphic)
+       Error(ERR_EXIT, "fatal error: no fallback graphic available");
+
+      Error(ERR_RETURN, "fallback done to 'char_exclam' for this graphic");
+      Error(ERR_RETURN_LINE, "-");
+
+      set_graphic_parameters(i, fallback_image->default_parameter);
+      graphic_info[i].bitmap = fallback_bitmap;
+    }
+
+    last_frame = graphic_info[i].anim_frames - 1;
+    getGraphicSource(i, last_frame, &src_bitmap, &src_x, &src_y);
+    if (src_x < 0 || src_y < 0 ||
+       src_x + TILEX > src_bitmap->width ||
+       src_y + TILEY > src_bitmap->height)
+    {
+      Error(ERR_RETURN_LINE, "-");
+      Error(ERR_RETURN, "warning: error found in config file:");
+      Error(ERR_RETURN, "- config file: '%s'",
+           getImageConfigFilename());
+      Error(ERR_RETURN, "- config token: '%s'",
+           getTokenFromImageID(i));
+      Error(ERR_RETURN, "- image file: '%s'",
+           src_bitmap->source_filename);
+      Error(ERR_RETURN,
+           "error: last animation frame (%d) out of bounds (%d, %d)",
+           last_frame, src_x, src_y);
+      Error(ERR_RETURN, "custom graphic rejected for this element/action");
+
+      if (i == fallback_graphic)
+       Error(ERR_EXIT, "fatal error: no fallback graphic available");
+
+      Error(ERR_RETURN, "fallback done to 'char_exclam' for this graphic");
+      Error(ERR_RETURN_LINE, "-");
+
+      set_graphic_parameters(i, fallback_image->default_parameter);
+      graphic_info[i].bitmap = fallback_bitmap;
+    }
+
+#if defined(TARGET_X11_NATIVE_PERFORMANCE_WORKAROUND)
+    /* currently we need only a tile clip mask from the first frame */
+    getGraphicSource(i, first_frame, &src_bitmap, &src_x, &src_y);
+
+    if (copy_clipmask_gc == None)
+    {
+      clip_gc_values.graphics_exposures = False;
+      clip_gc_valuemask = GCGraphicsExposures;
+      copy_clipmask_gc = XCreateGC(display, src_bitmap->clip_mask,
+                                  clip_gc_valuemask, &clip_gc_values);
+    }
+
+    graphic_info[i].clip_mask =
+      XCreatePixmap(display, window->drawable, TILEX, TILEY, 1);
+
+    src_pixmap = src_bitmap->clip_mask;
+    XCopyArea(display, src_pixmap, graphic_info[i].clip_mask,
+             copy_clipmask_gc, src_x, src_y, TILEX, TILEY, 0, 0);
+
+    clip_gc_values.graphics_exposures = False;
+    clip_gc_values.clip_mask = graphic_info[i].clip_mask;
+    clip_gc_valuemask = GCGraphicsExposures | GCClipMask;
+
+    graphic_info[i].clip_gc =
+      XCreateGC(display, window->drawable, clip_gc_valuemask, &clip_gc_values);
+#endif
+  }
+
+#if defined(TARGET_X11_NATIVE_PERFORMANCE_WORKAROUND)
+  if (copy_clipmask_gc)
+    XFreeGC(display, copy_clipmask_gc);
+
+  clipmasks_initialized = TRUE;
+#endif
+}
+
+static void InitElementSoundInfo()
+{
+  struct PropertyMapping *property_mapping = getSoundListPropertyMapping();
+  int num_property_mappings = getSoundListPropertyMappingSize();
+  int i, j, act;
+
+  /* set values to -1 to identify later as "uninitialized" values */
+  for (i=0; i < MAX_NUM_ELEMENTS; i++)
+    for (act=0; act < NUM_ACTIONS; act++)
+      element_info[i].sound[act] = -1;
+
+  /* initialize element/sound mapping from static configuration */
+  for (i=0; element_to_sound[i].element > -1; i++)
+  {
+    int element      = element_to_sound[i].element;
+    int action       = element_to_sound[i].action;
+    int sound        = element_to_sound[i].sound;
+    boolean is_class = element_to_sound[i].is_class;
+
+    if (action < 0)
+      action = ACTION_DEFAULT;
+
+    if (!is_class)
+      element_info[element].sound[action] = sound;
+    else
+      for (j=0; j < MAX_NUM_ELEMENTS; j++)
+       if (strcmp(element_info[j].class_name,
+                  element_info[element].class_name) == 0)
+         element_info[j].sound[action] = sound;
+  }
+
+  /* initialize element class/sound mapping from dynamic configuration */
+  for (i=0; i < num_property_mappings; i++)
+  {
+    int element_class = property_mapping[i].base_index - MAX_NUM_ELEMENTS;
+    int action        = property_mapping[i].ext1_index;
+    int sound         = property_mapping[i].artwork_index;
+
+    if (element_class < 0 || element_class >= MAX_NUM_ELEMENTS)
+      continue;
+
+    if (action < 0)
+      action = ACTION_DEFAULT;
+
+    for (j=0; j < MAX_NUM_ELEMENTS; j++)
+      if (strcmp(element_info[j].class_name,
+                element_info[element_class].class_name) == 0)
+       element_info[j].sound[action] = sound;
+  }
+
+  /* initialize element/sound mapping from dynamic configuration */
+  for (i=0; i < num_property_mappings; i++)
+  {
+    int element = property_mapping[i].base_index;
+    int action  = property_mapping[i].ext1_index;
+    int sound   = property_mapping[i].artwork_index;
+
+    if (element >= MAX_NUM_ELEMENTS)
+      continue;
+
+    if (action < 0)
+      action = ACTION_DEFAULT;
+
+    element_info[element].sound[action] = sound;
+  }
+
+  /* now set all '-1' values to element specific default values */
+  for (i=0; i<MAX_NUM_ELEMENTS; i++)
+  {
+    for (act=0; act < NUM_ACTIONS; act++)
+    {
+      /* generic default action sound (defined by "[default]" directive) */
+      int default_action_sound = element_info[EL_DEFAULT].sound[act];
+
+      /* 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_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)
+       default_action_sound = element_info[EL_SB_DEFAULT].sound[act];
+
+      /* look for element specific default sound (independent from action) */
+      if (element_info[i].sound[ACTION_DEFAULT] != -1)
+       default_action_sound = element_info[i].sound[ACTION_DEFAULT];
+
+      /* no sound for this specific action -- use default action sound */
+      if (element_info[i].sound[act] == -1)
+       element_info[i].sound[act] = default_action_sound;
+    }
+  }
+}
+
+static void set_sound_parameters(int sound, char **parameter_raw)
+{
+  int parameter[NUM_SND_ARGS];
+  int i;
+
+  /* get integer values from string parameters */
+  for (i=0; i < NUM_SND_ARGS; i++)
+    parameter[i] =
+      get_parameter_value(sound_config_suffix[i].token, parameter_raw[i],
+                         sound_config_suffix[i].type);
+
+  /* explicit loop mode setting in configuration overrides default value */
+  if (parameter[SND_ARG_MODE_LOOP] != ARG_UNDEFINED_VALUE)
+    sound_info[sound].loop = parameter[SND_ARG_MODE_LOOP];
+}
+
+static void InitSoundInfo()
+{
+#if 0
+  struct PropertyMapping *property_mapping = getSoundListPropertyMapping();
+  int num_property_mappings = getSoundListPropertyMappingSize();
+#endif
+  int *sound_effect_properties;
+  int num_sounds = getSoundListSize();
+  int i, j;
+
+  if (sound_info != NULL)
+    free(sound_info);
+
+  sound_effect_properties = checked_calloc(num_sounds * sizeof(int));
+  sound_info = checked_calloc(num_sounds * sizeof(struct SoundInfo));
+
+  /* initialize sound effect for all elements to "no sound" */
+  for (i=0; i<MAX_NUM_ELEMENTS; i++)
+    for (j=0; j<NUM_ACTIONS; j++)
+      element_info[i].sound[j] = SND_UNDEFINED;
+
+  for (i=0; i<num_sounds; i++)
+  {
+    struct FileInfo *sound = getSoundListEntry(i);
+    int len_effect_text = strlen(sound->token);
+
+    sound_effect_properties[i] = ACTION_OTHER;
+    sound_info[i].loop = FALSE;
+
+#if 0
+    printf("::: sound %d: '%s'\n", i, sound->token);
+#endif
+
+    /* determine all loop sounds and identify certain sound classes */
+
+    for (j=0; element_action_info[j].suffix; j++)
+    {
+      int len_action_text = strlen(element_action_info[j].suffix);
+
+      if (len_action_text < len_effect_text &&
+         strcmp(&sound->token[len_effect_text - len_action_text],
+                element_action_info[j].suffix) == 0)
+      {
+       sound_effect_properties[i] = element_action_info[j].value;
+       sound_info[i].loop = element_action_info[j].is_loop_sound;
+
+       break;
+      }
+    }
+
+#if 0
+    if (strcmp(sound->token, "custom_42") == 0)
+      printf("::: '%s' -> %d\n", sound->token, sound_info[i].loop);
+#endif
+
+    /* associate elements and some selected sound actions */
+
+    for (j=0; j<MAX_NUM_ELEMENTS; j++)
+    {
+      if (element_info[j].class_name)
+      {
+       int len_class_text = strlen(element_info[j].class_name);
+
+       if (len_class_text + 1 < len_effect_text &&
+           strncmp(sound->token,
+                   element_info[j].class_name, len_class_text) == 0 &&
+           sound->token[len_class_text] == '.')
+       {
+         int sound_action_value = sound_effect_properties[i];
+
+         element_info[j].sound[sound_action_value] = i;
+       }
+      }
+    }
+
+    set_sound_parameters(i, sound->parameter);
+  }
+
+  free(sound_effect_properties);
+
+#if 0
+  /* !!! now handled in InitElementSoundInfo() !!! */
+  /* initialize element/sound mapping from dynamic configuration */
+  for (i=0; i < num_property_mappings; i++)
+  {
+    int element   = property_mapping[i].base_index;
+    int action    = property_mapping[i].ext1_index;
+    int sound     = property_mapping[i].artwork_index;
+
+    if (action < 0)
+      action = ACTION_DEFAULT;
+
+    printf("::: %d: %d, %d, %d ['%s']\n",
+          i, element, action, sound, element_info[element].token_name);
+
+    element_info[element].sound[action] = sound;
+  }
+#endif
+
+#if 0
+  /* TEST ONLY */
+  {
+    int element = EL_CUSTOM_11;
+    int j = 0;
+
+    while (element_action_info[j].suffix)
+    {
+      printf("element %d, sound action '%s'  == %d\n",
+            element, element_action_info[j].suffix,
+            element_info[element].sound[j]);
+      j++;
+    }
+  }
+
+  PlaySoundLevelElementAction(0,0, EL_CUSTOM_11, ACTION_PUSHING);
+#endif
+
+#if 0
+  /* TEST ONLY */
+  {
+    int element = EL_SAND;
+    int sound_action = ACTION_DIGGING;
+    int j = 0;
+
+    while (element_action_info[j].suffix)
+    {
+      if (element_action_info[j].value == sound_action)
+       printf("element %d, sound action '%s'  == %d\n",
+              element, element_action_info[j].suffix,
+              element_info[element].sound[sound_action]);
+      j++;
+    }
+  }
+#endif
+}
+
+static void ReinitializeGraphics()
+{
+  InitGraphicInfo();                   /* graphic properties mapping */
+  InitElementGraphicInfo();            /* element game graphic mapping */
+  InitElementSpecialGraphicInfo();     /* element special graphic mapping */
+
+  InitElementSmallImages();            /* create editor and preview images */
+  InitFontGraphicInfo();               /* initialize text drawing functions */
+
+  SetMainBackgroundImage(IMG_BACKGROUND);
+  SetDoorBackgroundImage(IMG_BACKGROUND_DOOR);
+
+  InitGadgets();
+  InitToons();
+}
+
+static void ReinitializeSounds()
+{
+  InitSoundInfo();             /* sound properties mapping */
+  InitElementSoundInfo();      /* element game sound mapping */
+
+  InitPlaySoundLevel();                /* internal game sound settings */
+}
+
+static void ReinitializeMusic()
+{
+  /* currently nothing to do */
+}
+
+void InitElementPropertiesStatic()
+{
+  static int ep_diggable[] =
+  {
+    EL_SAND,
+    EL_SP_BASE,
+    EL_SP_BUGGY_BASE,
+    EL_SP_BUGGY_BASE_ACTIVATING,
+    EL_TRAP,
+    EL_INVISIBLE_SAND,
+    EL_INVISIBLE_SAND_ACTIVE,
+
+    /* !!! currently not diggable, but handled by 'ep_dont_run_into' !!! */
+#if 0
+    EL_LANDMINE,
+    EL_TRAP_ACTIVE,
+    EL_SP_BUGGY_BASE_ACTIVE,
+#endif
+    -1
+  };
+
+  static int ep_collectible[] =
+  {
+    EL_BD_DIAMOND,
+    EL_EMERALD,
+    EL_DIAMOND,
+    EL_EMERALD_YELLOW,
+    EL_EMERALD_RED,
+    EL_EMERALD_PURPLE,
+    EL_KEY_1,
+    EL_KEY_2,
+    EL_KEY_3,
+    EL_KEY_4,
+    EL_EM_KEY_1,
     EL_EM_KEY_2,
     EL_EM_KEY_3,
-    EL_EM_KEY_4
+    EL_EM_KEY_4,
+    EL_DYNAMITE,
+    EL_DYNABOMB_INCREASE_NUMBER,
+    EL_DYNABOMB_INCREASE_SIZE,
+    EL_DYNABOMB_INCREASE_POWER,
+    EL_SP_INFOTRON,
+    EL_SP_DISK_RED,
+    EL_PEARL,
+    EL_CRYSTAL,
+    EL_KEY_WHITE,
+    EL_SHIELD_NORMAL,
+    EL_SHIELD_DEADLY,
+    EL_EXTRA_TIME,
+    EL_ENVELOPE,
+    EL_SPEED_PILL,
+    -1
   };
-  static int ep_schluessel_num = SIZEOF_ARRAY_INT(ep_schluessel);
-
-  static int ep_pforte[] =
-  {
-    EL_PFORTE1,
-    EL_PFORTE2,
-    EL_PFORTE3,
-    EL_PFORTE4,
-    EL_PFORTE1X,
-    EL_PFORTE2X,
-    EL_PFORTE3X,
-    EL_PFORTE4X,
-    EL_EM_GATE_1,
-    EL_EM_GATE_2,
-    EL_EM_GATE_3,
-    EL_EM_GATE_4,
-    EL_EM_GATE_1X,
-    EL_EM_GATE_2X,
-    EL_EM_GATE_3X,
-    EL_EM_GATE_4X,
-    EL_SWITCHGATE_OPEN,
-    EL_SWITCHGATE_OPENING,
-    EL_SWITCHGATE_CLOSED,
-    EL_SWITCHGATE_CLOSING,
-    EL_TIMEGATE_OPEN,
-    EL_TIMEGATE_OPENING,
-    EL_TIMEGATE_CLOSED,
-    EL_TIMEGATE_CLOSING,
-    EL_TUBE_CROSS,
-    EL_TUBE_VERTICAL,
-    EL_TUBE_HORIZONTAL,
-    EL_TUBE_VERT_LEFT,
-    EL_TUBE_VERT_RIGHT,
-    EL_TUBE_HORIZ_UP,
-    EL_TUBE_HORIZ_DOWN,
-    EL_TUBE_LEFT_UP,
-    EL_TUBE_LEFT_DOWN,
-    EL_TUBE_RIGHT_UP,
-    EL_TUBE_RIGHT_DOWN
+
+  static int ep_dont_run_into[] =
+  {
+    /* same elements as in 'ep_dont_touch' */
+    EL_BUG,
+    EL_SPACESHIP,
+    EL_BD_BUTTERFLY,
+    EL_BD_FIREFLY,
+
+    /* same elements as in 'ep_dont_collide_with' */
+    EL_YAMYAM,
+    EL_DARK_YAMYAM,
+    EL_ROBOT,
+    EL_PACMAN,
+    EL_SP_SNIKSNAK,
+    EL_SP_ELECTRON,
+
+    /* new elements */
+    EL_AMOEBA_DROP,
+    EL_ACID,
+
+    /* !!! maybe this should better be handled by 'ep_diggable' !!! */
+#if 1
+    EL_SP_BUGGY_BASE_ACTIVE,
+    EL_TRAP_ACTIVE,
+    EL_LANDMINE,
+#endif
+    -1
   };
-  static int ep_pforte_num = SIZEOF_ARRAY_INT(ep_pforte);
 
-  static int ep_solid[] =
+  static int ep_dont_collide_with[] =
   {
-    EL_BETON,
-    EL_MAUERWERK,
-    EL_MAUER_LEBT,
-    EL_MAUER_X,
-    EL_MAUER_Y,
-    EL_MAUER_XY,
-    EL_BD_WALL,
-    EL_FELSBODEN,
-    EL_AUSGANG_ZU,
-    EL_AUSGANG_ACT,
-    EL_AUSGANG_AUF,
-    EL_AMOEBE_TOT,
-    EL_AMOEBE_NASS,
-    EL_AMOEBE_NORM,
-    EL_AMOEBE_VOLL,
-    EL_AMOEBE_BD,
-    EL_MORAST_VOLL,
-    EL_MORAST_LEER,
-    EL_QUICKSAND_FILLING,
-    EL_QUICKSAND_EMPTYING,
-    EL_MAGIC_WALL_OFF,
-    EL_MAGIC_WALL_EMPTY,
-    EL_MAGIC_WALL_EMPTYING,
-    EL_MAGIC_WALL_FILLING,
-    EL_MAGIC_WALL_FULL,
-    EL_MAGIC_WALL_DEAD,
-    EL_MAGIC_WALL_BD_OFF,
-    EL_MAGIC_WALL_BD_EMPTY,
-    EL_MAGIC_WALL_BD_EMPTYING,
-    EL_MAGIC_WALL_BD_FULL,
-    EL_MAGIC_WALL_BD_FILLING,
-    EL_MAGIC_WALL_BD_DEAD,
-    EL_LIFE,
-    EL_LIFE_ASYNC,
-    EL_BADEWANNE1,
-    EL_BADEWANNE2,
-    EL_BADEWANNE3,
-    EL_BADEWANNE4,
-    EL_BADEWANNE5,
-    EL_SP_CHIP_SINGLE,
-    EL_SP_CHIP_LEFT,
-    EL_SP_CHIP_RIGHT,
-    EL_SP_CHIP_UPPER,
-    EL_SP_CHIP_LOWER,
-    EL_SP_HARD_GRAY,
-    EL_SP_HARD_GREEN,
-    EL_SP_HARD_BLUE,
-    EL_SP_HARD_RED,
-    EL_SP_HARD_YELLOW,
-    EL_SP_HARD_BASE1,
-    EL_SP_HARD_BASE2,
-    EL_SP_HARD_BASE3,
-    EL_SP_HARD_BASE4,
-    EL_SP_HARD_BASE5,
-    EL_SP_HARD_BASE6,
-    EL_SP_TERMINAL,
-    EL_SP_TERMINAL_ACTIVE,
-    EL_SP_EXIT,
-    EL_INVISIBLE_STEEL,
-    EL_BELT1_SWITCH_LEFT,
-    EL_BELT1_SWITCH_MIDDLE,
-    EL_BELT1_SWITCH_RIGHT,
-    EL_BELT2_SWITCH_LEFT,
-    EL_BELT2_SWITCH_MIDDLE,
-    EL_BELT2_SWITCH_RIGHT,
-    EL_BELT3_SWITCH_LEFT,
-    EL_BELT3_SWITCH_MIDDLE,
-    EL_BELT3_SWITCH_RIGHT,
-    EL_BELT4_SWITCH_LEFT,
-    EL_BELT4_SWITCH_MIDDLE,
-    EL_BELT4_SWITCH_RIGHT,
-    EL_SWITCHGATE_SWITCH_1,
-    EL_SWITCHGATE_SWITCH_2,
-    EL_LIGHT_SWITCH_OFF,
-    EL_LIGHT_SWITCH_ON,
-    EL_TIMEGATE_SWITCH_OFF,
-    EL_TIMEGATE_SWITCH_ON,
+    /* same elements as in 'ep_dont_touch' */
+    EL_BUG,
+    EL_SPACESHIP,
+    EL_BD_BUTTERFLY,
+    EL_BD_FIREFLY,
+
+    /* new elements */
+    EL_YAMYAM,
+    EL_DARK_YAMYAM,
+    EL_ROBOT,
+    EL_PACMAN,
+    EL_SP_SNIKSNAK,
+    EL_SP_ELECTRON,
+    -1
+  };
+
+  static int ep_dont_touch[] =
+  {
+    EL_BUG,
+    EL_SPACESHIP,
+    EL_BD_BUTTERFLY,
+    EL_BD_FIREFLY,
+    -1
+  };
+
+  static int ep_indestructible[] =
+  {
+    EL_STEELWALL,
+    EL_ACID,
+    EL_ACID_POOL_TOPLEFT,
+    EL_ACID_POOL_TOPRIGHT,
+    EL_ACID_POOL_BOTTOMLEFT,
+    EL_ACID_POOL_BOTTOM,
+    EL_ACID_POOL_BOTTOMRIGHT,
+    EL_SP_HARDWARE_GRAY,
+    EL_SP_HARDWARE_GREEN,
+    EL_SP_HARDWARE_BLUE,
+    EL_SP_HARDWARE_RED,
+    EL_SP_HARDWARE_YELLOW,
+    EL_SP_HARDWARE_BASE_1,
+    EL_SP_HARDWARE_BASE_2,
+    EL_SP_HARDWARE_BASE_3,
+    EL_SP_HARDWARE_BASE_4,
+    EL_SP_HARDWARE_BASE_5,
+    EL_SP_HARDWARE_BASE_6,
+    EL_INVISIBLE_STEELWALL,
+    EL_INVISIBLE_STEELWALL_ACTIVE,
+    EL_CONVEYOR_BELT_1_SWITCH_LEFT,
+    EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
+    EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
+    EL_CONVEYOR_BELT_2_SWITCH_LEFT,
+    EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
+    EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
+    EL_CONVEYOR_BELT_3_SWITCH_LEFT,
+    EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
+    EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
+    EL_CONVEYOR_BELT_4_SWITCH_LEFT,
+    EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
+    EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
+    EL_LIGHT_SWITCH,
+    EL_LIGHT_SWITCH_ACTIVE,
     EL_SIGN_EXCLAMATION,
     EL_SIGN_RADIOACTIVITY,
     EL_SIGN_STOP,
@@ -656,1078 +1421,2064 @@ void InitElementProperties()
     EL_SIGN_EXIT,
     EL_SIGN_YINYANG,
     EL_SIGN_OTHER,
-    EL_STEEL_SLANTED,
-    EL_EMC_STEEL_WALL_1,
-    EL_EMC_STEEL_WALL_2,
-    EL_EMC_STEEL_WALL_3,
-    EL_EMC_STEEL_WALL_4,
-    EL_EMC_WALL_1,
-    EL_EMC_WALL_2,
-    EL_EMC_WALL_3,
-    EL_EMC_WALL_4,
-    EL_EMC_WALL_5,
-    EL_EMC_WALL_6,
-    EL_EMC_WALL_7,
-    EL_EMC_WALL_8,
+    EL_STEELWALL_SLIPPERY,
+    EL_EMC_STEELWALL_1,
+    EL_EMC_STEELWALL_2,
+    EL_EMC_STEELWALL_3,
+    EL_EMC_STEELWALL_4,
     EL_CRYSTAL,
-    EL_WALL_PEARL,
-    EL_WALL_CRYSTAL,
-    EL_PFORTE1,
-    EL_PFORTE2,
-    EL_PFORTE3,
-    EL_PFORTE4,
-    EL_PFORTE1X,
-    EL_PFORTE2X,
-    EL_PFORTE3X,
-    EL_PFORTE4X,
+    EL_GATE_1,
+    EL_GATE_2,
+    EL_GATE_3,
+    EL_GATE_4,
+    EL_GATE_1_GRAY,
+    EL_GATE_2_GRAY,
+    EL_GATE_3_GRAY,
+    EL_GATE_4_GRAY,
     EL_EM_GATE_1,
     EL_EM_GATE_2,
     EL_EM_GATE_3,
     EL_EM_GATE_4,
-    EL_EM_GATE_1X,
-    EL_EM_GATE_2X,
-    EL_EM_GATE_3X,
-    EL_EM_GATE_4X,
+    EL_EM_GATE_1_GRAY,
+    EL_EM_GATE_2_GRAY,
+    EL_EM_GATE_3_GRAY,
+    EL_EM_GATE_4_GRAY,
     EL_SWITCHGATE_OPEN,
     EL_SWITCHGATE_OPENING,
     EL_SWITCHGATE_CLOSED,
     EL_SWITCHGATE_CLOSING,
+#if 0
+    EL_SWITCHGATE_SWITCH_UP,
+    EL_SWITCHGATE_SWITCH_DOWN,
+#endif
     EL_TIMEGATE_OPEN,
     EL_TIMEGATE_OPENING,
     EL_TIMEGATE_CLOSED,
     EL_TIMEGATE_CLOSING,
-    EL_TUBE_CROSS,
+#if 0
+    EL_TIMEGATE_SWITCH,
+    EL_TIMEGATE_SWITCH_ACTIVE,
+#endif
+    EL_TUBE_ANY,
     EL_TUBE_VERTICAL,
     EL_TUBE_HORIZONTAL,
-    EL_TUBE_VERT_LEFT,
-    EL_TUBE_VERT_RIGHT,
-    EL_TUBE_HORIZ_UP,
-    EL_TUBE_HORIZ_DOWN,
+    EL_TUBE_VERTICAL_LEFT,
+    EL_TUBE_VERTICAL_RIGHT,
+    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_TUBE_RIGHT_DOWN,
+    -1
   };
-  static int ep_solid_num = SIZEOF_ARRAY_INT(ep_solid);
-
-  static int ep_massive[] =
-  {
-    EL_BETON,
-    EL_SALZSAEURE,
-    EL_BADEWANNE1,
-    EL_BADEWANNE2,
-    EL_BADEWANNE3,
-    EL_BADEWANNE4,
-    EL_BADEWANNE5,
-    EL_SP_HARD_GRAY,
-    EL_SP_HARD_GREEN,
-    EL_SP_HARD_BLUE,
-    EL_SP_HARD_RED,
-    EL_SP_HARD_YELLOW,
-    EL_SP_HARD_BASE1,
-    EL_SP_HARD_BASE2,
-    EL_SP_HARD_BASE3,
-    EL_SP_HARD_BASE4,
-    EL_SP_HARD_BASE5,
-    EL_SP_HARD_BASE6,
-    EL_INVISIBLE_STEEL,
-    EL_BELT1_SWITCH_LEFT,
-    EL_BELT1_SWITCH_MIDDLE,
-    EL_BELT1_SWITCH_RIGHT,
-    EL_BELT2_SWITCH_LEFT,
-    EL_BELT2_SWITCH_MIDDLE,
-    EL_BELT2_SWITCH_RIGHT,
-    EL_BELT3_SWITCH_LEFT,
-    EL_BELT3_SWITCH_MIDDLE,
-    EL_BELT3_SWITCH_RIGHT,
-    EL_BELT4_SWITCH_LEFT,
-    EL_BELT4_SWITCH_MIDDLE,
-    EL_BELT4_SWITCH_RIGHT,
-    EL_LIGHT_SWITCH_OFF,
-    EL_LIGHT_SWITCH_ON,
-    EL_SIGN_EXCLAMATION,
-    EL_SIGN_RADIOACTIVITY,
-    EL_SIGN_STOP,
-    EL_SIGN_WHEELCHAIR,
-    EL_SIGN_PARKING,
-    EL_SIGN_ONEWAY,
-    EL_SIGN_HEART,
-    EL_SIGN_TRIANGLE,
-    EL_SIGN_ROUND,
-    EL_SIGN_EXIT,
-    EL_SIGN_YINYANG,
-    EL_SIGN_OTHER,
-    EL_STEEL_SLANTED,
-    EL_EMC_STEEL_WALL_1,
-    EL_EMC_STEEL_WALL_2,
-    EL_EMC_STEEL_WALL_3,
-    EL_EMC_STEEL_WALL_4,
-    EL_CRYSTAL,
-    EL_PFORTE1,
-    EL_PFORTE2,
-    EL_PFORTE3,
-    EL_PFORTE4,
-    EL_PFORTE1X,
-    EL_PFORTE2X,
-    EL_PFORTE3X,
-    EL_PFORTE4X,
-    EL_EM_GATE_1,
-    EL_EM_GATE_2,
-    EL_EM_GATE_3,
-    EL_EM_GATE_4,
-    EL_EM_GATE_1X,
-    EL_EM_GATE_2X,
-    EL_EM_GATE_3X,
-    EL_EM_GATE_4X,
-    EL_SWITCHGATE_OPEN,
-    EL_SWITCHGATE_OPENING,
-    EL_SWITCHGATE_CLOSED,
-    EL_SWITCHGATE_CLOSING,
-    EL_TIMEGATE_OPEN,
-    EL_TIMEGATE_OPENING,
-    EL_TIMEGATE_CLOSED,
-    EL_TIMEGATE_CLOSING,
-    EL_TUBE_CROSS,
-    EL_TUBE_VERTICAL,
-    EL_TUBE_HORIZONTAL,
-    EL_TUBE_VERT_LEFT,
-    EL_TUBE_VERT_RIGHT,
-    EL_TUBE_HORIZ_UP,
-    EL_TUBE_HORIZ_DOWN,
-    EL_TUBE_LEFT_UP,
-    EL_TUBE_LEFT_DOWN,
-    EL_TUBE_RIGHT_UP,
-    EL_TUBE_RIGHT_DOWN
-  };
-  static int ep_massive_num = SIZEOF_ARRAY_INT(ep_massive);
 
   static int ep_slippery[] =
   {
-    EL_FELSBODEN,
+    EL_WALL_SLIPPERY,
     EL_BD_WALL,
-    EL_FELSBROCKEN,
+    EL_ROCK,
     EL_BD_ROCK,
-    EL_EDELSTEIN,
-    EL_EDELSTEIN_BD,
-    EL_EDELSTEIN_GELB,
-    EL_EDELSTEIN_ROT,
-    EL_EDELSTEIN_LILA,
-    EL_DIAMANT,
-    EL_BOMBE,
-    EL_KOKOSNUSS,
-    EL_ABLENK_EIN,
-    EL_ABLENK_AUS,
-    EL_ZEIT_VOLL,
-    EL_ZEIT_LEER,
-    EL_BIRNE_EIN,
-    EL_BIRNE_AUS,
-    EL_BADEWANNE1,
-    EL_BADEWANNE2,
-    EL_SONDE,
+    EL_EMERALD,
+    EL_BD_DIAMOND,
+    EL_EMERALD_YELLOW,
+    EL_EMERALD_RED,
+    EL_EMERALD_PURPLE,
+    EL_DIAMOND,
+    EL_BOMB,
+    EL_NUT,
+    EL_ROBOT_WHEEL_ACTIVE,
+    EL_ROBOT_WHEEL,
+    EL_TIME_ORB_FULL,
+    EL_TIME_ORB_EMPTY,
+    EL_LAMP_ACTIVE,
+    EL_LAMP,
+    EL_ACID_POOL_TOPLEFT,
+    EL_ACID_POOL_TOPRIGHT,
+    EL_SATELLITE,
     EL_SP_ZONK,
     EL_SP_INFOTRON,
     EL_SP_CHIP_SINGLE,
     EL_SP_CHIP_LEFT,
     EL_SP_CHIP_RIGHT,
-    EL_SP_CHIP_UPPER,
-    EL_SP_CHIP_LOWER,
+    EL_SP_CHIP_TOP,
+    EL_SP_CHIP_BOTTOM,
     EL_SPEED_PILL,
-    EL_STEEL_SLANTED,
+    EL_STEELWALL_SLIPPERY,
     EL_PEARL,
-    EL_CRYSTAL
+    EL_CRYSTAL,
+    -1
+  };
+
+  static int ep_can_change[] =
+  {
+    -1
   };
-  static int ep_slippery_num = SIZEOF_ARRAY_INT(ep_slippery);
 
-  static int ep_enemy[] =
+  static int ep_can_move[] =
   {
-    EL_KAEFER,
-    EL_FLIEGER,
-    EL_BUTTERFLY,
-    EL_FIREFLY,
-    EL_MAMPFER,
-    EL_MAMPFER2,
+    EL_BUG,
+    EL_SPACESHIP,
+    EL_BD_BUTTERFLY,
+    EL_BD_FIREFLY,
+    EL_YAMYAM,
+    EL_DARK_YAMYAM,
     EL_ROBOT,
     EL_PACMAN,
+    EL_MOLE,
+    EL_PENGUIN,
+    EL_PIG,
+    EL_DRAGON,
+    EL_SATELLITE,
     EL_SP_SNIKSNAK,
-    EL_SP_ELECTRON
-  };
-  static int ep_enemy_num = SIZEOF_ARRAY_INT(ep_enemy);
-
-  static int ep_mauer[] =
-  {
-    EL_BETON,
-    EL_PFORTE1,
-    EL_PFORTE2,
-    EL_PFORTE3,
-    EL_PFORTE4,
-    EL_PFORTE1X,
-    EL_PFORTE2X,
-    EL_PFORTE3X,
-    EL_PFORTE4X,
-    EL_EM_GATE_1,
-    EL_EM_GATE_2,
-    EL_EM_GATE_3,
-    EL_EM_GATE_4,
-    EL_EM_GATE_1X,
-    EL_EM_GATE_2X,
-    EL_EM_GATE_3X,
-    EL_EM_GATE_4X,
-    EL_AUSGANG_ZU,
-    EL_AUSGANG_ACT,
-    EL_AUSGANG_AUF,
-    EL_MAUERWERK,
-    EL_FELSBODEN,
-    EL_MAUER_LEBT,
-    EL_MAUER_X,
-    EL_MAUER_Y,
-    EL_MAUER_XY,
-    EL_MAUERND,
-    EL_BD_WALL,
-    EL_SP_CHIP_SINGLE,
-    EL_SP_CHIP_LEFT,
-    EL_SP_CHIP_RIGHT,
-    EL_SP_CHIP_UPPER,
-    EL_SP_CHIP_LOWER,
-    EL_SP_HARD_GRAY,
-    EL_SP_HARD_GREEN,
-    EL_SP_HARD_BLUE,
-    EL_SP_HARD_RED,
-    EL_SP_HARD_YELLOW,
-    EL_SP_HARD_BASE1,
-    EL_SP_HARD_BASE2,
-    EL_SP_HARD_BASE3,
-    EL_SP_HARD_BASE4,
-    EL_SP_HARD_BASE5,
-    EL_SP_HARD_BASE6,
-    EL_SP_TERMINAL,
-    EL_SP_TERMINAL_ACTIVE,
-    EL_SP_EXIT,
-    EL_INVISIBLE_STEEL,
-    EL_STEEL_SLANTED,
-    EL_EMC_STEEL_WALL_1,
-    EL_EMC_STEEL_WALL_2,
-    EL_EMC_STEEL_WALL_3,
-    EL_EMC_STEEL_WALL_4,
-    EL_EMC_WALL_1,
-    EL_EMC_WALL_2,
-    EL_EMC_WALL_3,
-    EL_EMC_WALL_4,
-    EL_EMC_WALL_5,
-    EL_EMC_WALL_6,
-    EL_EMC_WALL_7,
-    EL_EMC_WALL_8
+    EL_SP_ELECTRON,
+    EL_BALLOON,
+    EL_SPRING,
+    -1
   };
-  static int ep_mauer_num = SIZEOF_ARRAY_INT(ep_mauer);
 
   static int ep_can_fall[] =
   {
-    EL_FELSBROCKEN,
+    EL_ROCK,
     EL_BD_ROCK,
-    EL_EDELSTEIN,
-    EL_EDELSTEIN_BD,
-    EL_EDELSTEIN_GELB,
-    EL_EDELSTEIN_ROT,
-    EL_EDELSTEIN_LILA,
-    EL_DIAMANT,
-    EL_BOMBE,
-    EL_KOKOSNUSS,
-    EL_TROPFEN,
-    EL_MORAST_VOLL,
+    EL_EMERALD,
+    EL_BD_DIAMOND,
+    EL_EMERALD_YELLOW,
+    EL_EMERALD_RED,
+    EL_EMERALD_PURPLE,
+    EL_DIAMOND,
+    EL_BOMB,
+    EL_NUT,
+    EL_AMOEBA_DROP,
+    EL_QUICKSAND_FULL,
     EL_MAGIC_WALL_FULL,
-    EL_MAGIC_WALL_BD_FULL,
-    EL_ZEIT_VOLL,
-    EL_ZEIT_LEER,
+    EL_BD_MAGIC_WALL_FULL,
+    EL_TIME_ORB_FULL,
+    EL_TIME_ORB_EMPTY,
     EL_SP_ZONK,
     EL_SP_INFOTRON,
     EL_SP_DISK_ORANGE,
     EL_PEARL,
     EL_CRYSTAL,
     EL_SPRING,
-    EL_DX_SUPABOMB
+    EL_DX_SUPABOMB,
+    -1
   };
-  static int ep_can_fall_num = SIZEOF_ARRAY_INT(ep_can_fall);
 
-  static int ep_can_smash[] =
+  static int ep_can_smash_player[] =
   {
-    EL_FELSBROCKEN,
+    EL_ROCK,
     EL_BD_ROCK,
-    EL_EDELSTEIN,
-    EL_EDELSTEIN_BD,
-    EL_EDELSTEIN_GELB,
-    EL_EDELSTEIN_ROT,
-    EL_EDELSTEIN_LILA,
-    EL_DIAMANT,
-    EL_SCHLUESSEL1,
-    EL_SCHLUESSEL2,
-    EL_SCHLUESSEL3,
-    EL_SCHLUESSEL4,
-    EL_EM_KEY_1,
-    EL_EM_KEY_2,
-    EL_EM_KEY_3,
-    EL_EM_KEY_4,
-    EL_BOMBE,
-    EL_KOKOSNUSS,
-    EL_TROPFEN,
-    EL_ZEIT_VOLL,
-    EL_ZEIT_LEER,
+    EL_EMERALD,
+    EL_BD_DIAMOND,
+    EL_EMERALD_YELLOW,
+    EL_EMERALD_RED,
+    EL_EMERALD_PURPLE,
+    EL_DIAMOND,
+    EL_BOMB,
+    EL_NUT,
+    EL_AMOEBA_DROP,
+    EL_TIME_ORB_FULL,
+    EL_TIME_ORB_EMPTY,
     EL_SP_ZONK,
     EL_SP_INFOTRON,
     EL_SP_DISK_ORANGE,
     EL_PEARL,
     EL_CRYSTAL,
     EL_SPRING,
-    EL_DX_SUPABOMB
+    EL_DX_SUPABOMB,
+    -1
   };
-  static int ep_can_smash_num = SIZEOF_ARRAY_INT(ep_can_smash);
 
-  static int ep_can_change[] =
+  static int ep_can_smash_enemies[] =
   {
-    EL_FELSBROCKEN,
+    EL_ROCK,
     EL_BD_ROCK,
-    EL_EDELSTEIN,
-    EL_EDELSTEIN_BD,
-    EL_EDELSTEIN_GELB,
-    EL_EDELSTEIN_ROT,
-    EL_EDELSTEIN_LILA,
-    EL_DIAMANT
+    EL_SP_ZONK,
+    -1
   };
-  static int ep_can_change_num = SIZEOF_ARRAY_INT(ep_can_change);
 
-  static int ep_can_move[] =
+  static int ep_can_smash_everything[] =
   {
-    EL_KAEFER,
-    EL_FLIEGER,
-    EL_BUTTERFLY,
-    EL_FIREFLY,
-    EL_MAMPFER,
-    EL_MAMPFER2,
-    EL_ROBOT,
-    EL_PACMAN,
+    EL_ROCK,
+    EL_BD_ROCK,
+    EL_SP_ZONK,
+    -1
+  };
+
+  static int ep_can_explode_by_fire[] =
+  {
+    /* same elements as in 'ep_can_explode_impact' */
+    EL_BOMB,
+    EL_SP_DISK_ORANGE,
+    EL_DX_SUPABOMB,
+
+    /* same elements as in 'ep_can_explode_smashed' */
+    EL_SATELLITE,
+    EL_PIG,
+    EL_DRAGON,
     EL_MOLE,
-    EL_PINGUIN,
-    EL_SCHWEIN,
-    EL_DRACHE,
-    EL_SONDE,
+
+    /* new elements */
+    EL_DYNAMITE_ACTIVE,
+    EL_DYNAMITE,
+    EL_DYNABOMB_PLAYER_1_ACTIVE,
+    EL_DYNABOMB_PLAYER_2_ACTIVE,
+    EL_DYNABOMB_PLAYER_3_ACTIVE,
+    EL_DYNABOMB_PLAYER_4_ACTIVE,
+    EL_DYNABOMB_INCREASE_NUMBER,
+    EL_DYNABOMB_INCREASE_SIZE,
+    EL_DYNABOMB_INCREASE_POWER,
+    EL_SP_DISK_RED_ACTIVE,
+    EL_BUG,
+    EL_PENGUIN,
+    EL_SP_DISK_RED,
+    EL_SP_DISK_YELLOW,
     EL_SP_SNIKSNAK,
     EL_SP_ELECTRON,
+    -1
+  };
+
+  static int ep_can_explode_smashed[] =
+  {
+    /* same elements as in 'ep_can_explode_impact' */
+    EL_BOMB,
+    EL_SP_DISK_ORANGE,
+    EL_DX_SUPABOMB,
+
+    /* new elements */
+    EL_SATELLITE,
+    EL_PIG,
+    EL_DRAGON,
+    EL_MOLE,
+    -1
+  };
+
+  static int ep_can_explode_impact[] =
+  {
+    EL_BOMB,
+    EL_SP_DISK_ORANGE,
+    EL_DX_SUPABOMB,
+    -1
+  };
+
+  static int ep_walkable_over[] =
+  {
+    EL_EMPTY_SPACE,
+    EL_SP_EMPTY_SPACE,
+    EL_SOKOBAN_FIELD_EMPTY,
+    EL_EXIT_OPEN,
+    EL_SP_EXIT_OPEN,
+    EL_GATE_1,
+    EL_GATE_2,
+    EL_GATE_3,
+    EL_GATE_4,
+    EL_GATE_1_GRAY,
+    EL_GATE_2_GRAY,
+    EL_GATE_3_GRAY,
+    EL_GATE_4_GRAY,
+    EL_PENGUIN,
+    EL_PIG,
+    EL_DRAGON,
+    -1
+  };
+
+  static int ep_walkable_inside[] =
+  {
+    EL_TUBE_ANY,
+    EL_TUBE_VERTICAL,
+    EL_TUBE_HORIZONTAL,
+    EL_TUBE_VERTICAL_LEFT,
+    EL_TUBE_VERTICAL_RIGHT,
+    EL_TUBE_HORIZONTAL_UP,
+    EL_TUBE_HORIZONTAL_DOWN,
+    EL_TUBE_LEFT_UP,
+    EL_TUBE_LEFT_DOWN,
+    EL_TUBE_RIGHT_UP,
+    EL_TUBE_RIGHT_DOWN,
+    -1
+  };
+
+  static int ep_walkable_under[] =
+  {
+    -1
+  };
+
+  static int ep_passable_over[] =
+  {
+    EL_EM_GATE_1,
+    EL_EM_GATE_2,
+    EL_EM_GATE_3,
+    EL_EM_GATE_4,
+    EL_EM_GATE_1_GRAY,
+    EL_EM_GATE_2_GRAY,
+    EL_EM_GATE_3_GRAY,
+    EL_EM_GATE_4_GRAY,
+    EL_SWITCHGATE_OPEN,
+    EL_TIMEGATE_OPEN,
+    -1
+  };
+
+  static int ep_passable_inside[] =
+  {
+    EL_SP_PORT_LEFT,
+    EL_SP_PORT_RIGHT,
+    EL_SP_PORT_UP,
+    EL_SP_PORT_DOWN,
+    EL_SP_PORT_HORIZONTAL,
+    EL_SP_PORT_VERTICAL,
+    EL_SP_PORT_ANY,
+    EL_SP_GRAVITY_PORT_LEFT,
+    EL_SP_GRAVITY_PORT_RIGHT,
+    EL_SP_GRAVITY_PORT_UP,
+    EL_SP_GRAVITY_PORT_DOWN,
+    -1
+  };
+
+  static int ep_passable_under[] =
+  {
+    -1
+  };
+
+  static int ep_pushable[] =
+  {
+    EL_ROCK,
+    EL_BOMB,
+    EL_DX_SUPABOMB,
+    EL_NUT,
+    EL_TIME_ORB_EMPTY,
+    EL_SP_ZONK,
+    EL_SP_DISK_ORANGE,
+    EL_SPRING,
+    EL_BD_ROCK,
+    EL_SOKOBAN_OBJECT,
+    EL_SOKOBAN_FIELD_FULL,
+    EL_SATELLITE,
+    EL_SP_DISK_YELLOW,
     EL_BALLOON,
-    EL_SPRING_MOVING
+    -1
+  };
+
+  static int ep_can_be_crumbled[] =
+  {
+    EL_SAND,
+    EL_LANDMINE,
+    EL_TRAP,
+    EL_TRAP_ACTIVE,
+    -1
+  };
+
+  static int ep_player[] =
+  {
+    EL_PLAYER_1,
+    EL_PLAYER_2,
+    EL_PLAYER_3,
+    EL_PLAYER_4,
+    -1
+  };
+
+  static int ep_can_pass_magic_wall[] =
+  {
+    EL_ROCK,
+    EL_BD_ROCK,
+    EL_EMERALD,
+    EL_BD_DIAMOND,
+    EL_EMERALD_YELLOW,
+    EL_EMERALD_RED,
+    EL_EMERALD_PURPLE,
+    EL_DIAMOND,
+    -1
+  };
+
+  static int ep_switchable[] =
+  {
+    EL_ROBOT_WHEEL,
+    EL_SP_TERMINAL,
+    EL_CONVEYOR_BELT_1_SWITCH_LEFT,
+    EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
+    EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
+    EL_CONVEYOR_BELT_2_SWITCH_LEFT,
+    EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
+    EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
+    EL_CONVEYOR_BELT_3_SWITCH_LEFT,
+    EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
+    EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
+    EL_CONVEYOR_BELT_4_SWITCH_LEFT,
+    EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
+    EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
+    EL_SWITCHGATE_SWITCH_UP,
+    EL_SWITCHGATE_SWITCH_DOWN,
+    EL_LIGHT_SWITCH,
+    EL_LIGHT_SWITCH_ACTIVE,
+    EL_TIMEGATE_SWITCH,
+    EL_BALLOON_SWITCH_LEFT,
+    EL_BALLOON_SWITCH_RIGHT,
+    EL_BALLOON_SWITCH_UP,
+    EL_BALLOON_SWITCH_DOWN,
+    EL_BALLOON_SWITCH_ANY,
+    EL_LAMP,
+    EL_TIME_ORB_FULL,
+    -1
+  };
+
+  static int ep_bd_element[] =
+  {
+    EL_EMPTY,
+    EL_SAND,
+    EL_WALL_SLIPPERY,
+    EL_BD_WALL,
+    EL_ROCK,
+    EL_BD_ROCK,
+    EL_BD_DIAMOND,
+    EL_BD_MAGIC_WALL,
+    EL_EXIT_CLOSED,
+    EL_EXIT_OPEN,
+    EL_STEELWALL,
+    EL_PLAYER_1,
+    EL_BD_FIREFLY,
+    EL_BD_FIREFLY_1,
+    EL_BD_FIREFLY_2,
+    EL_BD_FIREFLY_3,
+    EL_BD_FIREFLY_4,
+    EL_BD_BUTTERFLY,
+    EL_BD_BUTTERFLY_1,
+    EL_BD_BUTTERFLY_2,
+    EL_BD_BUTTERFLY_3,
+    EL_BD_BUTTERFLY_4,
+    EL_BD_AMOEBA,
+    EL_CHAR_QUESTION,
+    -1
+  };
+
+  static int ep_sp_element[] =
+  {
+    EL_SP_EMPTY,
+    EL_SP_ZONK,
+    EL_SP_BASE,
+    EL_SP_MURPHY,
+    EL_SP_INFOTRON,
+    EL_SP_CHIP_SINGLE,
+    EL_SP_HARDWARE_GRAY,
+    EL_SP_EXIT_CLOSED,
+    EL_SP_EXIT_OPEN,
+    EL_SP_DISK_ORANGE,
+    EL_SP_PORT_RIGHT,
+    EL_SP_PORT_DOWN,
+    EL_SP_PORT_LEFT,
+    EL_SP_PORT_UP,
+    EL_SP_GRAVITY_PORT_RIGHT,
+    EL_SP_GRAVITY_PORT_DOWN,
+    EL_SP_GRAVITY_PORT_LEFT,
+    EL_SP_GRAVITY_PORT_UP,
+    EL_SP_SNIKSNAK,
+    EL_SP_DISK_YELLOW,
+    EL_SP_TERMINAL,
+    EL_SP_DISK_RED,
+    EL_SP_PORT_VERTICAL,
+    EL_SP_PORT_HORIZONTAL,
+    EL_SP_PORT_ANY,
+    EL_SP_ELECTRON,
+    EL_SP_BUGGY_BASE,
+    EL_SP_CHIP_LEFT,
+    EL_SP_CHIP_RIGHT,
+    EL_SP_HARDWARE_BASE_1,
+    EL_SP_HARDWARE_GREEN,
+    EL_SP_HARDWARE_BLUE,
+    EL_SP_HARDWARE_RED,
+    EL_SP_HARDWARE_YELLOW,
+    EL_SP_HARDWARE_BASE_2,
+    EL_SP_HARDWARE_BASE_3,
+    EL_SP_HARDWARE_BASE_4,
+    EL_SP_HARDWARE_BASE_5,
+    EL_SP_HARDWARE_BASE_6,
+    EL_SP_CHIP_TOP,
+    EL_SP_CHIP_BOTTOM,
+    /* additional elements that appeared in newer Supaplex levels */
+    EL_INVISIBLE_WALL,
+    /* more than one murphy in a level results in an inactive clone */
+    EL_SP_MURPHY_CLONE,
+    /* runtime elements*/
+    EL_SP_DISK_RED_ACTIVE,
+    EL_SP_TERMINAL_ACTIVE,
+    EL_SP_BUGGY_BASE_ACTIVATING,
+    EL_SP_BUGGY_BASE_ACTIVE,
+    -1
+  };
+
+  static int ep_sb_element[] =
+  {
+    EL_EMPTY,
+    EL_STEELWALL,
+    EL_SOKOBAN_OBJECT,
+    EL_SOKOBAN_FIELD_EMPTY,
+    EL_SOKOBAN_FIELD_FULL,
+    EL_PLAYER_1,
+    EL_INVISIBLE_STEELWALL,
+    -1
+  };
+
+  static int ep_gem[] =
+  {
+    EL_BD_DIAMOND,
+    EL_EMERALD,
+    EL_EMERALD_YELLOW,
+    EL_EMERALD_RED,
+    EL_EMERALD_PURPLE,
+    EL_DIAMOND,
+    -1
+  };
+
+  static int ep_food_dark_yamyam[] =
+  {
+    EL_SAND,
+    EL_BUG,
+    EL_SPACESHIP,
+    EL_BD_BUTTERFLY,
+    EL_BD_FIREFLY,
+    EL_YAMYAM,
+    EL_ROBOT,
+    EL_PACMAN,
+    EL_AMOEBA_DROP,
+    EL_AMOEBA_DEAD,
+    EL_AMOEBA_WET,
+    EL_AMOEBA_DRY,
+    EL_AMOEBA_FULL,
+    EL_BD_AMOEBA,
+    EL_EMERALD,
+    EL_BD_DIAMOND,
+    EL_EMERALD_YELLOW,
+    EL_EMERALD_RED,
+    EL_EMERALD_PURPLE,
+    EL_DIAMOND,
+    EL_PEARL,
+    EL_CRYSTAL,
+    -1
+  };
+
+  static int ep_food_penguin[] =
+  {
+    EL_EMERALD,
+    EL_BD_DIAMOND,
+    EL_EMERALD_YELLOW,
+    EL_EMERALD_RED,
+    EL_EMERALD_PURPLE,
+    EL_DIAMOND,
+    EL_PEARL,
+    EL_CRYSTAL,
+    -1
+  };
+
+  static int ep_food_pig[] =
+  {
+    EL_EMERALD,
+    EL_BD_DIAMOND,
+    EL_EMERALD_YELLOW,
+    EL_EMERALD_RED,
+    EL_EMERALD_PURPLE,
+    EL_DIAMOND,
+    -1
+  };
+
+  static int ep_historic_wall[] =
+  {
+    EL_STEELWALL,
+    EL_GATE_1,
+    EL_GATE_2,
+    EL_GATE_3,
+    EL_GATE_4,
+    EL_GATE_1_GRAY,
+    EL_GATE_2_GRAY,
+    EL_GATE_3_GRAY,
+    EL_GATE_4_GRAY,
+    EL_EM_GATE_1,
+    EL_EM_GATE_2,
+    EL_EM_GATE_3,
+    EL_EM_GATE_4,
+    EL_EM_GATE_1_GRAY,
+    EL_EM_GATE_2_GRAY,
+    EL_EM_GATE_3_GRAY,
+    EL_EM_GATE_4_GRAY,
+    EL_EXIT_CLOSED,
+    EL_EXIT_OPENING,
+    EL_EXIT_OPEN,
+    EL_WALL,
+    EL_WALL_SLIPPERY,
+    EL_EXPANDABLE_WALL,
+    EL_EXPANDABLE_WALL_HORIZONTAL,
+    EL_EXPANDABLE_WALL_VERTICAL,
+    EL_EXPANDABLE_WALL_ANY,
+    EL_EXPANDABLE_WALL_GROWING,
+    EL_BD_WALL,
+    EL_SP_CHIP_SINGLE,
+    EL_SP_CHIP_LEFT,
+    EL_SP_CHIP_RIGHT,
+    EL_SP_CHIP_TOP,
+    EL_SP_CHIP_BOTTOM,
+    EL_SP_HARDWARE_GRAY,
+    EL_SP_HARDWARE_GREEN,
+    EL_SP_HARDWARE_BLUE,
+    EL_SP_HARDWARE_RED,
+    EL_SP_HARDWARE_YELLOW,
+    EL_SP_HARDWARE_BASE_1,
+    EL_SP_HARDWARE_BASE_2,
+    EL_SP_HARDWARE_BASE_3,
+    EL_SP_HARDWARE_BASE_4,
+    EL_SP_HARDWARE_BASE_5,
+    EL_SP_HARDWARE_BASE_6,
+    EL_SP_TERMINAL,
+    EL_SP_TERMINAL_ACTIVE,
+    EL_SP_EXIT_CLOSED,
+    EL_SP_EXIT_OPEN,
+    EL_INVISIBLE_STEELWALL,
+    EL_INVISIBLE_STEELWALL_ACTIVE,
+    EL_INVISIBLE_WALL,
+    EL_INVISIBLE_WALL_ACTIVE,
+    EL_STEELWALL_SLIPPERY,
+    EL_EMC_STEELWALL_1,
+    EL_EMC_STEELWALL_2,
+    EL_EMC_STEELWALL_3,
+    EL_EMC_STEELWALL_4,
+    EL_EMC_WALL_1,
+    EL_EMC_WALL_2,
+    EL_EMC_WALL_3,
+    EL_EMC_WALL_4,
+    EL_EMC_WALL_5,
+    EL_EMC_WALL_6,
+    EL_EMC_WALL_7,
+    EL_EMC_WALL_8,
+    -1
+  };
+
+  static int ep_historic_solid[] =
+  {
+    EL_WALL,
+    EL_EXPANDABLE_WALL,
+    EL_EXPANDABLE_WALL_HORIZONTAL,
+    EL_EXPANDABLE_WALL_VERTICAL,
+    EL_EXPANDABLE_WALL_ANY,
+    EL_BD_WALL,
+    EL_WALL_SLIPPERY,
+    EL_EXIT_CLOSED,
+    EL_EXIT_OPENING,
+    EL_EXIT_OPEN,
+    EL_AMOEBA_DEAD,
+    EL_AMOEBA_WET,
+    EL_AMOEBA_DRY,
+    EL_AMOEBA_FULL,
+    EL_BD_AMOEBA,
+    EL_QUICKSAND_EMPTY,
+    EL_QUICKSAND_FULL,
+    EL_QUICKSAND_FILLING,
+    EL_QUICKSAND_EMPTYING,
+    EL_MAGIC_WALL,
+    EL_MAGIC_WALL_ACTIVE,
+    EL_MAGIC_WALL_EMPTYING,
+    EL_MAGIC_WALL_FILLING,
+    EL_MAGIC_WALL_FULL,
+    EL_MAGIC_WALL_DEAD,
+    EL_BD_MAGIC_WALL,
+    EL_BD_MAGIC_WALL_ACTIVE,
+    EL_BD_MAGIC_WALL_EMPTYING,
+    EL_BD_MAGIC_WALL_FULL,
+    EL_BD_MAGIC_WALL_FILLING,
+    EL_BD_MAGIC_WALL_DEAD,
+    EL_GAME_OF_LIFE,
+    EL_BIOMAZE,
+    EL_SP_CHIP_SINGLE,
+    EL_SP_CHIP_LEFT,
+    EL_SP_CHIP_RIGHT,
+    EL_SP_CHIP_TOP,
+    EL_SP_CHIP_BOTTOM,
+    EL_SP_TERMINAL,
+    EL_SP_TERMINAL_ACTIVE,
+    EL_SP_EXIT_CLOSED,
+    EL_SP_EXIT_OPEN,
+    EL_INVISIBLE_WALL,
+    EL_INVISIBLE_WALL_ACTIVE,
+    EL_SWITCHGATE_SWITCH_UP,
+    EL_SWITCHGATE_SWITCH_DOWN,
+    EL_TIMEGATE_SWITCH,
+    EL_TIMEGATE_SWITCH_ACTIVE,
+    EL_EMC_WALL_1,
+    EL_EMC_WALL_2,
+    EL_EMC_WALL_3,
+    EL_EMC_WALL_4,
+    EL_EMC_WALL_5,
+    EL_EMC_WALL_6,
+    EL_EMC_WALL_7,
+    EL_EMC_WALL_8,
+    EL_WALL_PEARL,
+    EL_WALL_CRYSTAL,
+
+    /* the following elements are a direct copy of "indestructible" elements,
+       except "EL_ACID", which is "indestructible", but not "solid"! */
+#if 0
+    EL_ACID,
+#endif
+    EL_STEELWALL,
+    EL_ACID_POOL_TOPLEFT,
+    EL_ACID_POOL_TOPRIGHT,
+    EL_ACID_POOL_BOTTOMLEFT,
+    EL_ACID_POOL_BOTTOM,
+    EL_ACID_POOL_BOTTOMRIGHT,
+    EL_SP_HARDWARE_GRAY,
+    EL_SP_HARDWARE_GREEN,
+    EL_SP_HARDWARE_BLUE,
+    EL_SP_HARDWARE_RED,
+    EL_SP_HARDWARE_YELLOW,
+    EL_SP_HARDWARE_BASE_1,
+    EL_SP_HARDWARE_BASE_2,
+    EL_SP_HARDWARE_BASE_3,
+    EL_SP_HARDWARE_BASE_4,
+    EL_SP_HARDWARE_BASE_5,
+    EL_SP_HARDWARE_BASE_6,
+    EL_INVISIBLE_STEELWALL,
+    EL_INVISIBLE_STEELWALL_ACTIVE,
+    EL_CONVEYOR_BELT_1_SWITCH_LEFT,
+    EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
+    EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
+    EL_CONVEYOR_BELT_2_SWITCH_LEFT,
+    EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
+    EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
+    EL_CONVEYOR_BELT_3_SWITCH_LEFT,
+    EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
+    EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
+    EL_CONVEYOR_BELT_4_SWITCH_LEFT,
+    EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
+    EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
+    EL_LIGHT_SWITCH,
+    EL_LIGHT_SWITCH_ACTIVE,
+    EL_SIGN_EXCLAMATION,
+    EL_SIGN_RADIOACTIVITY,
+    EL_SIGN_STOP,
+    EL_SIGN_WHEELCHAIR,
+    EL_SIGN_PARKING,
+    EL_SIGN_ONEWAY,
+    EL_SIGN_HEART,
+    EL_SIGN_TRIANGLE,
+    EL_SIGN_ROUND,
+    EL_SIGN_EXIT,
+    EL_SIGN_YINYANG,
+    EL_SIGN_OTHER,
+    EL_STEELWALL_SLIPPERY,
+    EL_EMC_STEELWALL_1,
+    EL_EMC_STEELWALL_2,
+    EL_EMC_STEELWALL_3,
+    EL_EMC_STEELWALL_4,
+    EL_CRYSTAL,
+    EL_GATE_1,
+    EL_GATE_2,
+    EL_GATE_3,
+    EL_GATE_4,
+    EL_GATE_1_GRAY,
+    EL_GATE_2_GRAY,
+    EL_GATE_3_GRAY,
+    EL_GATE_4_GRAY,
+    EL_EM_GATE_1,
+    EL_EM_GATE_2,
+    EL_EM_GATE_3,
+    EL_EM_GATE_4,
+    EL_EM_GATE_1_GRAY,
+    EL_EM_GATE_2_GRAY,
+    EL_EM_GATE_3_GRAY,
+    EL_EM_GATE_4_GRAY,
+    EL_SWITCHGATE_OPEN,
+    EL_SWITCHGATE_OPENING,
+    EL_SWITCHGATE_CLOSED,
+    EL_SWITCHGATE_CLOSING,
+    EL_TIMEGATE_OPEN,
+    EL_TIMEGATE_OPENING,
+    EL_TIMEGATE_CLOSED,
+    EL_TIMEGATE_CLOSING,
+    EL_TUBE_ANY,
+    EL_TUBE_VERTICAL,
+    EL_TUBE_HORIZONTAL,
+    EL_TUBE_VERTICAL_LEFT,
+    EL_TUBE_VERTICAL_RIGHT,
+    EL_TUBE_HORIZONTAL_UP,
+    EL_TUBE_HORIZONTAL_DOWN,
+    EL_TUBE_LEFT_UP,
+    EL_TUBE_LEFT_DOWN,
+    EL_TUBE_RIGHT_UP,
+    EL_TUBE_RIGHT_DOWN,
+    -1
   };
-  static int ep_can_move_num = SIZEOF_ARRAY_INT(ep_can_move);
-
-  static int ep_could_move[] =
-  {
-    EL_KAEFER_RIGHT,
-    EL_KAEFER_UP,
-    EL_KAEFER_LEFT,
-    EL_KAEFER_DOWN,
-    EL_FLIEGER_RIGHT,
-    EL_FLIEGER_UP,
-    EL_FLIEGER_LEFT,
-    EL_FLIEGER_DOWN,
-    EL_BUTTERFLY_RIGHT,
-    EL_BUTTERFLY_UP,
-    EL_BUTTERFLY_LEFT,
-    EL_BUTTERFLY_DOWN,
-    EL_FIREFLY_RIGHT,
-    EL_FIREFLY_UP,
-    EL_FIREFLY_LEFT,
-    EL_FIREFLY_DOWN,
-    EL_PACMAN_RIGHT,
-    EL_PACMAN_UP,
-    EL_PACMAN_LEFT,
-    EL_PACMAN_DOWN
+
+  static int ep_classic_enemy[] =
+  {
+    EL_BUG,
+    EL_SPACESHIP,
+    EL_BD_BUTTERFLY,
+    EL_BD_FIREFLY,
+
+    EL_YAMYAM,
+    EL_DARK_YAMYAM,
+    EL_ROBOT,
+    EL_PACMAN,
+    EL_SP_SNIKSNAK,
+    EL_SP_ELECTRON,
+    -1
   };
-  static int ep_could_move_num = SIZEOF_ARRAY_INT(ep_could_move);
 
-  static int ep_dont_touch[] =
-  {
-    EL_KAEFER,
-    EL_FLIEGER,
-    EL_BUTTERFLY,
-    EL_FIREFLY
-  };
-  static int ep_dont_touch_num = SIZEOF_ARRAY_INT(ep_dont_touch);
+  static int ep_belt[] =
+  {
+    EL_CONVEYOR_BELT_1_LEFT,
+    EL_CONVEYOR_BELT_1_MIDDLE,
+    EL_CONVEYOR_BELT_1_RIGHT,
+    EL_CONVEYOR_BELT_2_LEFT,
+    EL_CONVEYOR_BELT_2_MIDDLE,
+    EL_CONVEYOR_BELT_2_RIGHT,
+    EL_CONVEYOR_BELT_3_LEFT,
+    EL_CONVEYOR_BELT_3_MIDDLE,
+    EL_CONVEYOR_BELT_3_RIGHT,
+    EL_CONVEYOR_BELT_4_LEFT,
+    EL_CONVEYOR_BELT_4_MIDDLE,
+    EL_CONVEYOR_BELT_4_RIGHT,
+    -1
+  };
+
+  static int ep_belt_active[] =
+  {
+    EL_CONVEYOR_BELT_1_LEFT_ACTIVE,
+    EL_CONVEYOR_BELT_1_MIDDLE_ACTIVE,
+    EL_CONVEYOR_BELT_1_RIGHT_ACTIVE,
+    EL_CONVEYOR_BELT_2_LEFT_ACTIVE,
+    EL_CONVEYOR_BELT_2_MIDDLE_ACTIVE,
+    EL_CONVEYOR_BELT_2_RIGHT_ACTIVE,
+    EL_CONVEYOR_BELT_3_LEFT_ACTIVE,
+    EL_CONVEYOR_BELT_3_MIDDLE_ACTIVE,
+    EL_CONVEYOR_BELT_3_RIGHT_ACTIVE,
+    EL_CONVEYOR_BELT_4_LEFT_ACTIVE,
+    EL_CONVEYOR_BELT_4_MIDDLE_ACTIVE,
+    EL_CONVEYOR_BELT_4_RIGHT_ACTIVE,
+    -1
+  };
+
+  static int ep_belt_switch[] =
+  {
+    EL_CONVEYOR_BELT_1_SWITCH_LEFT,
+    EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
+    EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
+    EL_CONVEYOR_BELT_2_SWITCH_LEFT,
+    EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
+    EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
+    EL_CONVEYOR_BELT_3_SWITCH_LEFT,
+    EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
+    EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
+    EL_CONVEYOR_BELT_4_SWITCH_LEFT,
+    EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
+    EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
+    -1
+  };
+
+  static int ep_tube[] =
+  {
+    EL_TUBE_LEFT_UP,
+    EL_TUBE_LEFT_DOWN,
+    EL_TUBE_RIGHT_UP,
+    EL_TUBE_RIGHT_DOWN,
+    EL_TUBE_HORIZONTAL,
+    EL_TUBE_HORIZONTAL_UP,
+    EL_TUBE_HORIZONTAL_DOWN,
+    EL_TUBE_VERTICAL,
+    EL_TUBE_VERTICAL_LEFT,
+    EL_TUBE_VERTICAL_RIGHT,
+    EL_TUBE_ANY,
+    -1
+  };
+
+  static int ep_keygate[] =
+  {
+    EL_GATE_1,
+    EL_GATE_2,
+    EL_GATE_3,
+    EL_GATE_4,
+    EL_GATE_1_GRAY,
+    EL_GATE_2_GRAY,
+    EL_GATE_3_GRAY,
+    EL_GATE_4_GRAY,
+    EL_EM_GATE_1,
+    EL_EM_GATE_2,
+    EL_EM_GATE_3,
+    EL_EM_GATE_4,
+    EL_EM_GATE_1_GRAY,
+    EL_EM_GATE_2_GRAY,
+    EL_EM_GATE_3_GRAY,
+    EL_EM_GATE_4_GRAY,
+    -1
+  };
+
+  static int ep_amoeboid[] =
+  {
+    EL_AMOEBA_DEAD,
+    EL_AMOEBA_WET,
+    EL_AMOEBA_DRY,
+    EL_AMOEBA_FULL,
+    EL_BD_AMOEBA,
+    -1
+  };
+
+  static int ep_amoebalive[] =
+  {
+    EL_AMOEBA_WET,
+    EL_AMOEBA_DRY,
+    EL_AMOEBA_FULL,
+    EL_BD_AMOEBA,
+    -1
+  };
+
+  static int ep_has_content[] =
+  {
+    EL_YAMYAM,
+    EL_AMOEBA_WET,
+    EL_AMOEBA_DRY,
+    EL_AMOEBA_FULL,
+    EL_BD_AMOEBA,
+    -1
+  };
+
+  static int ep_active_bomb[] =
+  {
+    EL_DYNAMITE_ACTIVE,
+    EL_DYNABOMB_PLAYER_1_ACTIVE,
+    EL_DYNABOMB_PLAYER_2_ACTIVE,
+    EL_DYNABOMB_PLAYER_3_ACTIVE,
+    EL_DYNABOMB_PLAYER_4_ACTIVE,
+    EL_SP_DISK_RED_ACTIVE,
+    -1
+  };
+
+  static int ep_inactive[] =
+  {
+    EL_EMPTY,
+    EL_SAND,
+    EL_WALL,
+    EL_BD_WALL,
+    EL_WALL_SLIPPERY,
+    EL_STEELWALL,
+    EL_AMOEBA_DEAD,
+    EL_QUICKSAND_EMPTY,
+    EL_STONEBLOCK,
+    EL_ROBOT_WHEEL,
+    EL_KEY_1,
+    EL_KEY_2,
+    EL_KEY_3,
+    EL_KEY_4,
+    EL_EM_KEY_1,
+    EL_EM_KEY_2,
+    EL_EM_KEY_3,
+    EL_EM_KEY_4,
+    EL_GATE_1,
+    EL_GATE_2,
+    EL_GATE_3,
+    EL_GATE_4,
+    EL_GATE_1_GRAY,
+    EL_GATE_2_GRAY,
+    EL_GATE_3_GRAY,
+    EL_GATE_4_GRAY,
+    EL_EM_GATE_1,
+    EL_EM_GATE_2,
+    EL_EM_GATE_3,
+    EL_EM_GATE_4,
+    EL_EM_GATE_1_GRAY,
+    EL_EM_GATE_2_GRAY,
+    EL_EM_GATE_3_GRAY,
+    EL_EM_GATE_4_GRAY,
+    EL_DYNAMITE,
+    EL_INVISIBLE_STEELWALL,
+    EL_INVISIBLE_WALL,
+    EL_INVISIBLE_SAND,
+    EL_LAMP,
+    EL_LAMP_ACTIVE,
+    EL_WALL_EMERALD,
+    EL_WALL_DIAMOND,
+    EL_WALL_BD_DIAMOND,
+    EL_WALL_EMERALD_YELLOW,
+    EL_DYNABOMB_INCREASE_NUMBER,
+    EL_DYNABOMB_INCREASE_SIZE,
+    EL_DYNABOMB_INCREASE_POWER,
+#if 0
+    EL_SOKOBAN_OBJECT,
+#endif
+    EL_SOKOBAN_FIELD_EMPTY,
+    EL_SOKOBAN_FIELD_FULL,
+    EL_WALL_EMERALD_RED,
+    EL_WALL_EMERALD_PURPLE,
+    EL_ACID_POOL_TOPLEFT,
+    EL_ACID_POOL_TOPRIGHT,
+    EL_ACID_POOL_BOTTOMLEFT,
+    EL_ACID_POOL_BOTTOM,
+    EL_ACID_POOL_BOTTOMRIGHT,
+    EL_MAGIC_WALL,
+    EL_MAGIC_WALL_DEAD,
+    EL_BD_MAGIC_WALL,
+    EL_BD_MAGIC_WALL_DEAD,
+    EL_AMOEBA_TO_DIAMOND,
+    EL_BLOCKED,
+    EL_SP_EMPTY,
+    EL_SP_BASE,
+    EL_SP_PORT_RIGHT,
+    EL_SP_PORT_DOWN,
+    EL_SP_PORT_LEFT,
+    EL_SP_PORT_UP,
+    EL_SP_GRAVITY_PORT_RIGHT,
+    EL_SP_GRAVITY_PORT_DOWN,
+    EL_SP_GRAVITY_PORT_LEFT,
+    EL_SP_GRAVITY_PORT_UP,
+    EL_SP_PORT_HORIZONTAL,
+    EL_SP_PORT_VERTICAL,
+    EL_SP_PORT_ANY,
+    EL_SP_DISK_RED,
+#if 0
+    EL_SP_DISK_YELLOW,
+#endif
+    EL_SP_CHIP_SINGLE,
+    EL_SP_CHIP_LEFT,
+    EL_SP_CHIP_RIGHT,
+    EL_SP_CHIP_TOP,
+    EL_SP_CHIP_BOTTOM,
+    EL_SP_HARDWARE_GRAY,
+    EL_SP_HARDWARE_GREEN,
+    EL_SP_HARDWARE_BLUE,
+    EL_SP_HARDWARE_RED,
+    EL_SP_HARDWARE_YELLOW,
+    EL_SP_HARDWARE_BASE_1,
+    EL_SP_HARDWARE_BASE_2,
+    EL_SP_HARDWARE_BASE_3,
+    EL_SP_HARDWARE_BASE_4,
+    EL_SP_HARDWARE_BASE_5,
+    EL_SP_HARDWARE_BASE_6,
+    EL_CONVEYOR_BELT_1_SWITCH_LEFT,
+    EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
+    EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
+    EL_CONVEYOR_BELT_2_SWITCH_LEFT,
+    EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
+    EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
+    EL_CONVEYOR_BELT_3_SWITCH_LEFT,
+    EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
+    EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
+    EL_CONVEYOR_BELT_4_SWITCH_LEFT,
+    EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
+    EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
+    EL_SIGN_EXCLAMATION,
+    EL_SIGN_RADIOACTIVITY,
+    EL_SIGN_STOP,
+    EL_SIGN_WHEELCHAIR,
+    EL_SIGN_PARKING,
+    EL_SIGN_ONEWAY,
+    EL_SIGN_HEART,
+    EL_SIGN_TRIANGLE,
+    EL_SIGN_ROUND,
+    EL_SIGN_EXIT,
+    EL_SIGN_YINYANG,
+    EL_SIGN_OTHER,
+    EL_STEELWALL_SLIPPERY,
+    EL_EMC_STEELWALL_1,
+    EL_EMC_STEELWALL_2,
+    EL_EMC_STEELWALL_3,
+    EL_EMC_STEELWALL_4,
+    EL_EMC_WALL_1,
+    EL_EMC_WALL_2,
+    EL_EMC_WALL_3,
+    EL_EMC_WALL_4,
+    EL_EMC_WALL_5,
+    EL_EMC_WALL_6,
+    EL_EMC_WALL_7,
+    EL_EMC_WALL_8,
+    -1
+  };
+
+  static struct
+  {
+    int *elements;
+    int property;
+  } element_properties[] =
+  {
+    { ep_diggable,             EP_DIGGABLE             },
+    { ep_collectible,          EP_COLLECTIBLE          },
+    { ep_dont_run_into,                EP_DONT_RUN_INTO        },
+    { ep_dont_collide_with,    EP_DONT_COLLIDE_WITH    },
+    { ep_dont_touch,           EP_DONT_TOUCH           },
+    { ep_indestructible,       EP_INDESTRUCTIBLE       },
+    { ep_slippery,             EP_SLIPPERY             },
+    { ep_can_change,           EP_CAN_CHANGE           },
+    { ep_can_move,             EP_CAN_MOVE             },
+    { ep_can_fall,             EP_CAN_FALL             },
+    { ep_can_smash_player,     EP_CAN_SMASH_PLAYER     },
+    { ep_can_smash_enemies,    EP_CAN_SMASH_ENEMIES    },
+    { ep_can_smash_everything, EP_CAN_SMASH_EVERYTHING },
+    { ep_can_explode_by_fire,  EP_CAN_EXPLODE_BY_FIRE  },
+    { ep_can_explode_smashed,  EP_CAN_EXPLODE_SMASHED  },
+    { ep_can_explode_impact,   EP_CAN_EXPLODE_IMPACT   },
+    { ep_walkable_over,                EP_WALKABLE_OVER        },
+    { ep_walkable_inside,      EP_WALKABLE_INSIDE      },
+    { ep_walkable_under,       EP_WALKABLE_UNDER       },
+    { ep_passable_over,                EP_PASSABLE_OVER        },
+    { ep_passable_inside,      EP_PASSABLE_INSIDE      },
+    { ep_passable_under,       EP_PASSABLE_UNDER       },
+    { ep_pushable,             EP_PUSHABLE             },
+
+    { ep_can_be_crumbled,      EP_CAN_BE_CRUMBLED      },
+
+    { ep_player,               EP_PLAYER               },
+    { ep_can_pass_magic_wall,  EP_CAN_PASS_MAGIC_WALL  },
+    { ep_switchable,           EP_SWITCHABLE           },
+    { ep_bd_element,           EP_BD_ELEMENT           },
+    { ep_sp_element,           EP_SP_ELEMENT           },
+    { ep_sb_element,           EP_SB_ELEMENT           },
+    { ep_gem,                  EP_GEM                  },
+    { ep_food_dark_yamyam,     EP_FOOD_DARK_YAMYAM     },
+    { ep_food_penguin,         EP_FOOD_PENGUIN         },
+    { ep_food_pig,             EP_FOOD_PIG             },
+    { ep_historic_wall,                EP_HISTORIC_WALL        },
+    { ep_historic_solid,       EP_HISTORIC_SOLID       },
+    { ep_classic_enemy,                EP_CLASSIC_ENEMY        },
+    { ep_belt,                 EP_BELT                 },
+    { ep_belt_active,          EP_BELT_ACTIVE          },
+    { ep_belt_switch,          EP_BELT_SWITCH          },
+    { ep_tube,                 EP_TUBE                 },
+    { ep_keygate,              EP_KEYGATE              },
+    { ep_amoeboid,             EP_AMOEBOID             },
+    { ep_amoebalive,           EP_AMOEBALIVE           },
+    { ep_has_content,          EP_HAS_CONTENT          },
+    { ep_active_bomb,          EP_ACTIVE_BOMB          },
+    { ep_inactive,             EP_INACTIVE             },
+
+    { NULL,                    -1                      }
+  };
+
+  static int copy_properties[][5] =
+  {
+    {
+      EL_BUG,
+      EL_BUG_LEFT,             EL_BUG_RIGHT,
+      EL_BUG_UP,               EL_BUG_DOWN
+    },
+    {
+      EL_SPACESHIP,
+      EL_SPACESHIP_LEFT,       EL_SPACESHIP_RIGHT,
+      EL_SPACESHIP_UP,         EL_SPACESHIP_DOWN
+    },
+    {
+      EL_BD_BUTTERFLY,
+      EL_BD_BUTTERFLY_LEFT,    EL_BD_BUTTERFLY_RIGHT,
+      EL_BD_BUTTERFLY_UP,      EL_BD_BUTTERFLY_DOWN
+    },
+    {
+      EL_BD_FIREFLY,
+      EL_BD_FIREFLY_LEFT,      EL_BD_FIREFLY_RIGHT,
+      EL_BD_FIREFLY_UP,                EL_BD_FIREFLY_DOWN
+    },
+    {
+      EL_PACMAN,
+      EL_PACMAN_LEFT,          EL_PACMAN_RIGHT,
+      EL_PACMAN_UP,            EL_PACMAN_DOWN
+    },
+    {
+      -1,
+      -1, -1, -1, -1
+    }
+  };
+
+  int i, j, k;
+
+  /* always start with reliable default values (element has no properties) */
+  for (i=0; i < MAX_NUM_ELEMENTS; i++)
+    for (j=0; j < NUM_ELEMENT_PROPERTIES; j++)
+      SET_PROPERTY(i, j, FALSE);
+
+  /* set all base element properties from above array definitions */
+  for (i=0; element_properties[i].elements != NULL; i++)
+    for (j=0; (element_properties[i].elements)[j] != -1; j++)
+      SET_PROPERTY((element_properties[i].elements)[j],
+                  element_properties[i].property, TRUE);
+
+  /* copy properties to some elements that are only stored in level file */
+  for (i=0; i < NUM_ELEMENT_PROPERTIES; i++)
+    for (j=0; copy_properties[j][0] != -1; j++)
+      if (HAS_PROPERTY(copy_properties[j][0], i))
+       for (k=1; k<=4; k++)
+         SET_PROPERTY(copy_properties[j][k], i, TRUE);
+}
+
+void InitElementPropertiesEngine(int engine_version)
+{
+#if 0
+  static int active_properties[] =
+  {
+    EP_AMOEBALIVE,
+    EP_AMOEBOID,
+    EP_PFORTE,
+    EP_DONT_COLLIDE_WITH,
+    EP_MAUER,
+    EP_CAN_FALL,
+    EP_CAN_SMASH,
+    EP_CAN_PASS_MAGIC_WALL,
+    EP_CAN_MOVE,
+    EP_DONT_TOUCH,
+    EP_DONT_RUN_INTO,
+    EP_GEM,
+    EP_CAN_EXPLODE_BY_FIRE,
+    EP_PUSHABLE,
+    EP_PLAYER,
+    EP_HAS_CONTENT,
+    EP_DIGGABLE,
+    EP_PASSABLE_INSIDE,
+    EP_OVER_PLAYER,
+    EP_ACTIVE_BOMB,
+
+    EP_BELT,
+    EP_BELT_ACTIVE,
+    EP_BELT_SWITCH,
+    EP_WALKABLE_UNDER,
+    EP_EM_SLIPPERY_WALL,
+    EP_CAN_BE_CRUMBLED,
+  };
+#endif
+
+  static int no_wall_properties[] =
+  {
+    EP_DIGGABLE,
+    EP_COLLECTIBLE,
+    EP_DONT_RUN_INTO,
+    EP_DONT_COLLIDE_WITH,
+    EP_CAN_MOVE,
+    EP_CAN_FALL,
+    EP_CAN_SMASH_PLAYER,
+    EP_CAN_SMASH_ENEMIES,
+    EP_CAN_SMASH_EVERYTHING,
+    EP_PUSHABLE,
+
+    EP_CAN_BE_CRUMBLED,
+
+    EP_PLAYER,
+    EP_GEM,
+    EP_FOOD_DARK_YAMYAM,
+    EP_FOOD_PENGUIN,
+    EP_BELT,
+    EP_BELT_ACTIVE,
+    EP_TUBE,
+    EP_AMOEBOID,
+    EP_AMOEBALIVE,
+    EP_ACTIVE_BOMB,
+
+    EP_ACCESSIBLE,
+    -1
+  };
+
+  int i, j;
+
+#if 0
+  InitElementPropertiesStatic();
+#endif
+
+  /* set all special, combined or engine dependent element properties */
+  for (i=0; i < MAX_NUM_ELEMENTS; i++)
+  {
+#if 0
+    for (j=EP_ACCESSIBLE_OVER; j < NUM_ELEMENT_PROPERTIES; j++)
+      SET_PROPERTY(i, j, FALSE);
+#endif
+
+    /* ---------- INACTIVE ------------------------------------------------- */
+    if (i >= EL_CHAR_START && i <= EL_CHAR_END)
+      SET_PROPERTY(i, EP_INACTIVE, TRUE);
+
+    /* ---------- WALKABLE, PASSABLE, ACCESSIBLE --------------------------- */
+    SET_PROPERTY(i, EP_WALKABLE, (IS_WALKABLE_OVER(i) ||
+                                 IS_WALKABLE_INSIDE(i) ||
+                                 IS_WALKABLE_UNDER(i)));
+
+    SET_PROPERTY(i, EP_PASSABLE, (IS_PASSABLE_OVER(i) ||
+                                 IS_PASSABLE_INSIDE(i) ||
+                                 IS_PASSABLE_UNDER(i)));
+
+    SET_PROPERTY(i, EP_ACCESSIBLE_OVER, (IS_WALKABLE_OVER(i) ||
+                                        IS_PASSABLE_OVER(i)));
+
+    SET_PROPERTY(i, EP_ACCESSIBLE_INSIDE, (IS_WALKABLE_INSIDE(i) ||
+                                          IS_PASSABLE_INSIDE(i)));
+
+    SET_PROPERTY(i, EP_ACCESSIBLE_UNDER, (IS_WALKABLE_UNDER(i) ||
+                                         IS_PASSABLE_UNDER(i)));
+
+    SET_PROPERTY(i, EP_ACCESSIBLE, (IS_WALKABLE(i) ||
+                                   IS_PASSABLE(i)));
+
+    /* ---------- SNAPPABLE ------------------------------------------------ */
+    SET_PROPERTY(i, EP_SNAPPABLE, (IS_DIGGABLE(i) ||
+                                  IS_COLLECTIBLE(i) ||
+                                  IS_SWITCHABLE(i) ||
+                                  i == EL_BD_ROCK));
+
+    /* ---------- WALL ----------------------------------------------------- */
+    SET_PROPERTY(i, EP_WALL, TRUE);    /* default: element is wall */
+
+    for (j=0; no_wall_properties[j] != -1; j++)
+      if (HAS_PROPERTY(i, no_wall_properties[j]) ||
+         i >= EL_FIRST_RUNTIME_UNREAL)
+       SET_PROPERTY(i, EP_WALL, FALSE);
+
+    if (IS_HISTORIC_WALL(i))
+      SET_PROPERTY(i, EP_WALL, TRUE);
+
+    /* ---------- SOLID_FOR_PUSHING ---------------------------------------- */
+    if (engine_version < VERSION_IDENT(2,2,0))
+      SET_PROPERTY(i, EP_SOLID_FOR_PUSHING, IS_HISTORIC_SOLID(i));
+    else
+      SET_PROPERTY(i, EP_SOLID_FOR_PUSHING, (!IS_WALKABLE(i) &&
+                                            !IS_DIGGABLE(i) &&
+                                            !IS_COLLECTIBLE(i)));
+
+    /* ---------- DRAGONFIRE_PROOF ----------------------------------------- */
+
+    if (IS_HISTORIC_SOLID(i) || i == EL_EXPLOSION)
+      SET_PROPERTY(i, EP_DRAGONFIRE_PROOF, TRUE);
+    else
+      SET_PROPERTY(i, EP_DRAGONFIRE_PROOF, (IS_CUSTOM_ELEMENT(i) &&
+                                           IS_INDESTRUCTIBLE(i)));
+
+    /* ---------- EXPLOSION_PROOF ------------------------------------------ */
+    if (i == EL_FLAMES)
+      SET_PROPERTY(i, EP_EXPLOSION_PROOF, TRUE);
+    else if (engine_version < VERSION_IDENT(2,2,0))
+      SET_PROPERTY(i, EP_EXPLOSION_PROOF, IS_INDESTRUCTIBLE(i));
+    else
+      SET_PROPERTY(i, EP_EXPLOSION_PROOF, (IS_INDESTRUCTIBLE(i) &&
+                                          !IS_WALKABLE_OVER(i) &&
+                                          !IS_WALKABLE_UNDER(i)));
+
+    if (IS_CUSTOM_ELEMENT(i))
+    {
+      /* ---------- DONT_COLLIDE_WITH / DONT_RUN_INTO ---------------------- */
+      if (DONT_TOUCH(i))
+       SET_PROPERTY(i, EP_DONT_COLLIDE_WITH, TRUE);
+      if (DONT_COLLIDE_WITH(i))
+       SET_PROPERTY(i, EP_DONT_RUN_INTO, TRUE);
+
+      /* ---------- CAN_SMASH_ENEMIES / CAN_SMASH_PLAYER ------------------- */
+      if (CAN_SMASH_EVERYTHING(i))
+       SET_PROPERTY(i, EP_CAN_SMASH_ENEMIES, TRUE);
+      if (CAN_SMASH_ENEMIES(i))
+       SET_PROPERTY(i, EP_CAN_SMASH_PLAYER, TRUE);
+    }
+
+    /* ---------- CAN_SMASH ------------------------------------------------ */
+    SET_PROPERTY(i, EP_CAN_SMASH, (CAN_SMASH_PLAYER(i) ||
+                                  CAN_SMASH_ENEMIES(i) ||
+                                  CAN_SMASH_EVERYTHING(i)));
+
+    /* ---------- CAN_EXPLODE ---------------------------------------------- */
+    SET_PROPERTY(i, EP_CAN_EXPLODE, (CAN_EXPLODE_BY_FIRE(i) ||
+                                    CAN_EXPLODE_SMASHED(i) ||
+                                    CAN_EXPLODE_IMPACT(i)));
+
+    /* ---------- CAN_BE_CRUMBLED ------------------------------------------ */
+    SET_PROPERTY(i, EP_CAN_BE_CRUMBLED,
+                element_info[i].crumbled[ACTION_DEFAULT] != IMG_EMPTY);
+
+#if 0
+    if (CAN_BE_CRUMBLED(i))
+      printf("::: '%s' can be crumbled [%d]\n",
+            element_info[i].token_name,
+            element_info[i].crumbled[ACTION_DEFAULT]);
+#endif
+  }
+
+#if 0
+  /* determine inactive elements (used for engine main loop optimization) */
+  for (i=0; i < MAX_NUM_ELEMENTS; i++)
+  {
+    boolean active = FALSE;
+
+    for (j=0; i < NUM_ELEMENT_PROPERTIES; j++)
+    {
+      if (HAS_PROPERTY(i, j))
+       active = TRUE;
+    }
+
+#if 0
+    if (!active)
+      SET_PROPERTY(i, EP_INACTIVE, TRUE);
+#endif
+  }
+#endif
+
+  /* dynamically adjust element properties according to game engine version */
+  {
+    static int ep_em_slippery_wall[] =
+    {
+      EL_STEELWALL,
+      EL_WALL,
+      EL_EXPANDABLE_WALL,
+      EL_EXPANDABLE_WALL_HORIZONTAL,
+      EL_EXPANDABLE_WALL_VERTICAL,
+      EL_EXPANDABLE_WALL_ANY,
+      -1
+    };
+
+    /* special EM style gems behaviour */
+    for (i=0; ep_em_slippery_wall[i] != -1; i++)
+      SET_PROPERTY(ep_em_slippery_wall[i], EP_EM_SLIPPERY_WALL,
+                  level.em_slippery_gems);
+
+    /* "EL_EXPANDABLE_WALL_GROWING" wasn't slippery for EM gems in 2.0.1 */
+    SET_PROPERTY(EL_EXPANDABLE_WALL_GROWING, EP_EM_SLIPPERY_WALL,
+                (level.em_slippery_gems &&
+                 engine_version > VERSION_IDENT(2,0,1)));
+  }
+
+#if 0
+  /* dynamically adjust element properties according to game engine version */
+#if 0
+  if (engine_version < RELEASE_IDENT(2,2,0,7))
+#endif
+  {
+    for (i=0; i < NUM_CUSTOM_ELEMENTS; i++)
+    {
+      int element = EL_CUSTOM_START + i;
+
+      element_info[element].push_delay_fixed = 2;
+      element_info[element].push_delay_random = 8;
+    }
+  }
+#endif
+}
+
+static void InitGlobal()
+{
+  global.autoplay_leveldir = NULL;
+
+  global.frames_per_second = 0;
+  global.fps_slowdown = FALSE;
+  global.fps_slowdown_factor = 1;
+}
+
+void Execute_Command(char *command)
+{
+  if (strcmp(command, "print graphicsinfo.conf") == 0)
+  {
+    int i;
+
+    printf("# You can configure additional/alternative image files here.\n");
+    printf("# (The images below are default and therefore commented out.)\n");
+    printf("\n");
+    printf("%s\n", getFormattedSetupEntry("name", "Classic Graphics"));
+    printf("\n");
+    printf("%s\n", getFormattedSetupEntry("sort_priority", "100"));
+    printf("\n");
+
+    for (i=0; image_config[i].token != NULL; i++)
+      printf("# %s\n",
+            getFormattedSetupEntry(image_config[i].token,
+                                   image_config[i].value));
+
+    exit(0);
+  }
+  else if (strcmp(command, "print soundsinfo.conf") == 0)
+  {
+    int i;
+
+    printf("# You can configure additional/alternative sound files here.\n");
+    printf("# (The sounds below are default and therefore commented out.)\n");
+    printf("\n");
+    printf("%s\n", getFormattedSetupEntry("name", "Classic Sounds"));
+    printf("\n");
+    printf("%s\n", getFormattedSetupEntry("sort_priority", "100"));
+    printf("\n");
+
+    for (i=0; sound_config[i].token != NULL; i++)
+      printf("# %s\n",
+            getFormattedSetupEntry(sound_config[i].token,
+                                   sound_config[i].value));
+
+    exit(0);
+  }
+  else if (strcmp(command, "print musicinfo.conf") == 0)
+  {
+    printf("# (Currently only \"name\" and \"sort_priority\" recognized.)\n");
+    printf("\n");
+    printf("%s\n", getFormattedSetupEntry("name", "Classic Music"));
+    printf("\n");
+    printf("%s\n", getFormattedSetupEntry("sort_priority", "100"));
+
+    exit(0);
+  }
+  else if (strncmp(command, "dump level ", 11) == 0)
+  {
+    char *filename = &command[11];
+
+    if (access(filename, F_OK) != 0)
+      Error(ERR_EXIT, "cannot open file '%s'", filename);
+
+    LoadLevelFromFilename(&level, filename);
+    DumpLevel(&level);
+
+    exit(0);
+  }
+  else if (strncmp(command, "dump tape ", 10) == 0)
+  {
+    char *filename = &command[10];
+
+    if (access(filename, F_OK) != 0)
+      Error(ERR_EXIT, "cannot open file '%s'", filename);
+
+    LoadTapeFromFilename(filename);
+    DumpTape(&tape);
+
+    exit(0);
+  }
+  else if (strncmp(command, "autoplay ", 9) == 0)
+  {
+    char *str_copy = getStringCopy(&command[9]);
+    char *str_ptr = strchr(str_copy, ' ');
+
+    global.autoplay_leveldir = str_copy;
+    global.autoplay_level_nr = -1;
+
+    if (str_ptr != NULL)
+    {
+      *str_ptr++ = '\0';                       /* terminate leveldir string */
+      global.autoplay_level_nr = atoi(str_ptr);        /* get level_nr value */
+    }
+  }
+  else
+  {
+    Error(ERR_EXIT_HELP, "unrecognized command '%s'", command);
+  }
+}
+
+static void InitSetup()
+{
+  LoadSetup();                                 /* global setup info */
+
+  /* set some options from setup file */
+
+  if (setup.options.verbose)
+    options.verbose = TRUE;
+}
+
+static void InitPlayerInfo()
+{
+  int i;
+
+  /* choose default local player */
+  local_player = &stored_player[0];
+
+  for (i=0; i<MAX_PLAYERS; i++)
+    stored_player[i].connected = FALSE;
+
+  local_player->connected = TRUE;
+}
+
+static void InitArtworkInfo()
+{
+  LoadArtworkInfo();
+}
+
+static char *get_string_in_brackets(char *string)
+{
+  char *string_in_brackets = checked_malloc(strlen(string) + 3);
+
+  sprintf(string_in_brackets, "[%s]", string);
+
+  return string_in_brackets;
+}
+
+#if 0
+static char *get_element_class_token(int element)
+{
+  char *element_class_name = element_info[element].class_name;
+  char *element_class_token = checked_malloc(strlen(element_class_name) + 3);
+
+  sprintf(element_class_token, "[%s]", element_class_name);
+
+  return element_class_token;
+}
+
+static char *get_action_class_token(int action)
+{
+  char *action_class_name = &element_action_info[action].suffix[1];
+  char *action_class_token = checked_malloc(strlen(action_class_name) + 3);
+
+  sprintf(action_class_token, "[%s]", action_class_name);
+
+  return action_class_token;
+}
+#endif
+
+static void InitArtworkConfig()
+{
+  static char *image_id_prefix[MAX_NUM_ELEMENTS + NUM_FONTS + 1];
+  static char *sound_id_prefix[2 * MAX_NUM_ELEMENTS + 1];
+  static char *action_id_suffix[NUM_ACTIONS + 1];
+  static char *direction_id_suffix[NUM_DIRECTIONS + 1];
+  static char *special_id_suffix[NUM_SPECIAL_GFX_ARGS + 1];
+  static char *dummy[1] = { NULL };
+  static char *ignore_generic_tokens[] =
+  {
+    "name",
+    "sort_priority",
+    NULL
+  };
+  static char **ignore_image_tokens, **ignore_sound_tokens;
+  int num_ignore_generic_tokens;
+  int num_ignore_image_tokens, num_ignore_sound_tokens;
+  int i;
+
+  /* dynamically determine list of generic tokens to be ignored */
+  num_ignore_generic_tokens = 0;
+  for (i=0; ignore_generic_tokens[i] != NULL; i++)
+    num_ignore_generic_tokens++;
+
+  /* dynamically determine list of image tokens to be ignored */
+  num_ignore_image_tokens = num_ignore_generic_tokens;
+  for (i=0; image_config_vars[i].token != NULL; i++)
+    num_ignore_image_tokens++;
+  ignore_image_tokens =
+    checked_malloc((num_ignore_image_tokens + 1) * sizeof(char *));
+  for (i=0; i < num_ignore_generic_tokens; i++)
+    ignore_image_tokens[i] = ignore_generic_tokens[i];
+  for (i=0; i < num_ignore_image_tokens - num_ignore_generic_tokens; i++)
+    ignore_image_tokens[num_ignore_generic_tokens + i] =
+      image_config_vars[i].token;
+  ignore_image_tokens[num_ignore_image_tokens] = NULL;
+
+  /* dynamically determine list of sound tokens to be ignored */
+  num_ignore_sound_tokens = num_ignore_generic_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];
+  ignore_sound_tokens[num_ignore_sound_tokens] = NULL;
+
+  for (i=0; i<MAX_NUM_ELEMENTS; i++)
+    image_id_prefix[i] = element_info[i].token_name;
+  for (i=0; i<NUM_FONTS; i++)
+    image_id_prefix[MAX_NUM_ELEMENTS + i] = font_info[i].token_name;
+  image_id_prefix[MAX_NUM_ELEMENTS + NUM_FONTS] = NULL;
+
+  for (i=0; i<MAX_NUM_ELEMENTS; i++)
+    sound_id_prefix[i] = element_info[i].token_name;
+  for (i=0; i<MAX_NUM_ELEMENTS; i++)
+    sound_id_prefix[MAX_NUM_ELEMENTS + i] =
+      get_string_in_brackets(element_info[i].class_name);
+  sound_id_prefix[2 * MAX_NUM_ELEMENTS] = NULL;
+
+  for (i=0; i<NUM_ACTIONS; i++)
+    action_id_suffix[i] = element_action_info[i].suffix;
+  action_id_suffix[NUM_ACTIONS] = NULL;
+
+  for (i=0; i<NUM_DIRECTIONS; i++)
+    direction_id_suffix[i] = element_direction_info[i].suffix;
+  direction_id_suffix[NUM_DIRECTIONS] = NULL;
+
+  for (i=0; i<NUM_SPECIAL_GFX_ARGS; i++)
+    special_id_suffix[i] = special_suffix_info[i].suffix;
+  special_id_suffix[NUM_SPECIAL_GFX_ARGS] = NULL;
+
+  InitImageList(image_config, NUM_IMAGE_FILES, image_config_suffix,
+               image_id_prefix, action_id_suffix, direction_id_suffix,
+               special_id_suffix, ignore_image_tokens);
+  InitSoundList(sound_config, NUM_SOUND_FILES, sound_config_suffix,
+               sound_id_prefix, action_id_suffix, dummy,
+               special_id_suffix, ignore_sound_tokens);
+}
+
+static void InitMixer()
+{
+  OpenAudio();
+  StartMixer();
+}
+
+void InitGfx()
+{
+  char *filename_font_initial = NULL;
+  Bitmap *bitmap_font_initial = NULL;
+  int i, j;
+
+  /* determine settings for initial font (for displaying startup messages) */
+  for (i=0; image_config[i].token != NULL; i++)
+  {
+    for (j=0; j < NUM_INITIAL_FONTS; j++)
+    {
+      char font_token[128];
+      int len_font_token;
+
+      sprintf(font_token, "%s_%d", CONFIG_TOKEN_FONT_INITIAL, j + 1);
+      len_font_token = strlen(font_token);
+
+      if (strcmp(image_config[i].token, font_token) == 0)
+       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)
+      {
+       if (strcmp(&image_config[i].token[len_font_token], ".x") == 0)
+         font_initial[j].src_x = atoi(image_config[i].value);
+       else if (strcmp(&image_config[i].token[len_font_token], ".y") == 0)
+         font_initial[j].src_y = atoi(image_config[i].value);
+       else if (strcmp(&image_config[i].token[len_font_token], ".width") == 0)
+         font_initial[j].width = atoi(image_config[i].value);
+       else if (strcmp(&image_config[i].token[len_font_token],".height") == 0)
+         font_initial[j].height = atoi(image_config[i].value);
+      }
+    }
+  }
+
+  for (j=0; j < NUM_INITIAL_FONTS; j++)
+  {
+    font_initial[j].num_chars = DEFAULT_NUM_CHARS_PER_FONT;
+    font_initial[j].num_chars_per_line = DEFAULT_NUM_CHARS_PER_LINE;
+  }
+
+  if (filename_font_initial == NULL)   /* should not happen */
+    Error(ERR_EXIT, "cannot get filename for '%s'", CONFIG_TOKEN_FONT_INITIAL);
+
+  /* create additional image buffers for double-buffering */
+  bitmap_db_field = CreateBitmap(FXSIZE, FYSIZE, DEFAULT_DEPTH);
+  bitmap_db_door  = CreateBitmap(3 * DXSIZE, DYSIZE + VYSIZE, DEFAULT_DEPTH);
+
+  /* initialize screen properties */
+  InitGfxFieldInfo(SX, SY, SXSIZE, SYSIZE,
+                  REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE,
+                  bitmap_db_field);
+  InitGfxDoor1Info(DX, DY, DXSIZE, DYSIZE);
+  InitGfxDoor2Info(VX, VY, VXSIZE, VYSIZE);
+  InitGfxScrollbufferInfo(FXSIZE, FYSIZE);
+
+  bitmap_font_initial = LoadCustomImage(filename_font_initial);
+
+  for (j=0; j < NUM_INITIAL_FONTS; j++)
+    font_initial[j].bitmap = bitmap_font_initial;
+
+  InitFontGraphicInfo();
+
+  DrawInitText(WINDOW_TITLE_STRING, 20, FC_YELLOW);
+  DrawInitText(WINDOW_SUBTITLE_STRING, 50, FC_RED);
+
+  DrawInitText("Loading graphics:", 120, FC_GREEN);
+
+  InitTileClipmasks();
+}
+
+void InitGfxBackground()
+{
+  int x, y;
+
+  drawto = backbuffer;
+  fieldbuffer = bitmap_db_field;
+  SetDrawtoField(DRAW_BACKBUFFER);
+
+  BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, backbuffer,
+            0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
+  ClearRectangle(backbuffer, REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE);
+  ClearRectangle(bitmap_db_door, 0, 0, 3 * DXSIZE, DYSIZE + VYSIZE);
+
+  for (x=0; x<MAX_BUF_XSIZE; x++)
+    for (y=0; y<MAX_BUF_YSIZE; y++)
+      redraw[x][y] = 0;
+  redraw_tiles = 0;
+  redraw_mask = REDRAW_ALL;
+}
+
+static void InitLevelInfo()
+{
+  LoadLevelInfo();                             /* global level info */
+  LoadLevelSetup_LastSeries();                 /* last played series info */
+  LoadLevelSetup_SeriesInfo();                 /* last played level info */
+}
+
+void InitLevelArtworkInfo()
+{
+  LoadLevelArtworkInfo();
+}
+
+static void InitImages()
+{
+  setLevelArtworkDir(artwork.gfx_first);
+
+#if 0
+  printf("::: InitImages for '%s' ['%s', '%s'] ['%s', '%s']\n",
+        leveldir_current->identifier,
+        artwork.gfx_current_identifier,
+        artwork.gfx_current->identifier,
+        leveldir_current->graphics_set,
+        leveldir_current->graphics_path);
+#endif
+
+  ReloadCustomImages();
+
+  LoadCustomElementDescriptions();
+  LoadSpecialMenuDesignSettings();
+
+  ReinitializeGraphics();
+}
+
+static void InitSound(char *identifier)
+{
+  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);
+  ReinitializeSounds();
+}
+
+static void InitMusic(char *identifier)
+{
+  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);
+  ReinitializeMusic();
+}
+
+void InitNetworkServer()
+{
+#if defined(PLATFORM_UNIX)
+  int nr_wanted;
+#endif
+
+  if (!options.network)
+    return;
 
-  static int ep_dont_go_to[] =
-  {
-    EL_KAEFER,
-    EL_FLIEGER,
-    EL_BUTTERFLY,
-    EL_FIREFLY,
-    EL_MAMPFER,
-    EL_MAMPFER2,
-    EL_ROBOT,
-    EL_PACMAN,
-    EL_TROPFEN,
-    EL_SALZSAEURE,
-    EL_SP_SNIKSNAK,
-    EL_SP_ELECTRON,
-    EL_SP_BUG_ACTIVE,
-    EL_TRAP_ACTIVE,
-    EL_LANDMINE
-  };
-  static int ep_dont_go_to_num = SIZEOF_ARRAY_INT(ep_dont_go_to);
+#if defined(PLATFORM_UNIX)
+  nr_wanted = Request("Choose player", REQ_PLAYER | REQ_STAY_CLOSED);
 
-  static int ep_mampf2[] =
-  {
-    EL_ERDREICH,
-    EL_KAEFER,
-    EL_FLIEGER,
-    EL_BUTTERFLY,
-    EL_FIREFLY,
-    EL_MAMPFER,
-    EL_ROBOT,
-    EL_PACMAN,
-    EL_TROPFEN,
-    EL_AMOEBE_TOT,
-    EL_AMOEBE_NASS,
-    EL_AMOEBE_NORM,
-    EL_AMOEBE_VOLL,
-    EL_AMOEBE_BD,
-    EL_EDELSTEIN,
-    EL_EDELSTEIN_BD,
-    EL_EDELSTEIN_GELB,
-    EL_EDELSTEIN_ROT,
-    EL_EDELSTEIN_LILA,
-    EL_DIAMANT,
-    EL_PEARL,
-    EL_CRYSTAL
-  };
-  static int ep_mampf2_num = SIZEOF_ARRAY_INT(ep_mampf2);
+  if (!ConnectToServer(options.server_host, options.server_port))
+    Error(ERR_EXIT, "cannot connect to network game server");
 
-  static int ep_bd_element[] =
-  {
-    EL_LEERRAUM,
-    EL_ERDREICH,
-    EL_FELSBODEN,
-    EL_BD_WALL,
-    EL_FELSBROCKEN,
-    EL_BD_ROCK,
-    EL_EDELSTEIN_BD,
-    EL_MAGIC_WALL_BD_OFF,
-    EL_AUSGANG_ZU,
-    EL_AUSGANG_AUF,
-    EL_BETON,
-    EL_SPIELFIGUR,
-    EL_FIREFLY,
-    EL_FIREFLY_1,
-    EL_FIREFLY_2,
-    EL_FIREFLY_3,
-    EL_FIREFLY_4,
-    EL_BUTTERFLY,
-    EL_BUTTERFLY_1,
-    EL_BUTTERFLY_2,
-    EL_BUTTERFLY_3,
-    EL_BUTTERFLY_4,
-    EL_AMOEBE_BD,
-    EL_CHAR_FRAGE
-  };
-  static int ep_bd_element_num = SIZEOF_ARRAY_INT(ep_bd_element);
+  SendToServer_PlayerName(setup.player_name);
+  SendToServer_ProtocolVersion();
 
-  static int ep_sb_element[] =
-  {
-    EL_LEERRAUM,
-    EL_BETON,
-    EL_SOKOBAN_OBJEKT,
-    EL_SOKOBAN_FELD_LEER,
-    EL_SOKOBAN_FELD_VOLL,
-    EL_SPIELFIGUR,
-    EL_INVISIBLE_STEEL
-  };
-  static int ep_sb_element_num = SIZEOF_ARRAY_INT(ep_sb_element);
+  if (nr_wanted)
+    SendToServer_NrWanted(nr_wanted);
+#endif
+}
 
-  static int ep_gem[] =
-  {
-    EL_EDELSTEIN,
-    EL_EDELSTEIN_BD,
-    EL_EDELSTEIN_GELB,
-    EL_EDELSTEIN_ROT,
-    EL_EDELSTEIN_LILA,
-    EL_DIAMANT
-  };
-  static int ep_gem_num = SIZEOF_ARRAY_INT(ep_gem);
+static char *getNewArtworkIdentifier(int type)
+{
+  static char *leveldir_current_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 initialized[3] = { FALSE, FALSE, FALSE };
+  TreeInfo *artwork_first_node = ARTWORK_FIRST_NODE(artwork, type);
+  boolean setup_override_artwork = SETUP_OVERRIDE_ARTWORK(setup, type);
+  char *setup_artwork_set = SETUP_ARTWORK_SET(setup, type);
+  char *leveldir_identifier = leveldir_current->identifier;
+  char *leveldir_artwork_set = LEVELDIR_ARTWORK_SET(leveldir_current, type);
+  boolean has_level_artwork_set = (leveldir_artwork_set != NULL);
+  char *artwork_current_identifier;
+  char *artwork_new_identifier = NULL; /* default: nothing has changed */
+
+  /* leveldir_current may be invalid (level group, parent link) */
+  if (!validLevelSeries(leveldir_current))
+    return NULL;
+
+
+  /* 1st step: determine artwork set to be activated in descending order:
+     --------------------------------------------------------------------
+     1. setup artwork (when configured to override everything else)
+     2. artwork set configured in "levelinfo.conf" of current level set
+        (artwork in level directory will have priority when loading later)
+     3. artwork in level directory (stored in artwork sub-directory)
+     4. setup artwork (currently configured in setup menu) */
+
+  if (setup_override_artwork)
+    artwork_current_identifier = setup_artwork_set;
+  else if (leveldir_artwork_set != NULL)
+    artwork_current_identifier = leveldir_artwork_set;
+  else if (getTreeInfoFromIdentifier(artwork_first_node, leveldir_identifier))
+    artwork_current_identifier = leveldir_identifier;
+  else
+    artwork_current_identifier = setup_artwork_set;
+
+
+  /* 2nd step: check if it is really needed to reload artwork set
+     ------------------------------------------------------------ */
+
+  /* ---------- reload if level set and also artwork set has changed ------- */
+  if (leveldir_current_identifier[type] != leveldir_identifier &&
+      (last_has_level_artwork_set[type] || has_level_artwork_set))
+    artwork_new_identifier = artwork_current_identifier;
+
+  leveldir_current_identifier[type] = leveldir_identifier;
+  last_has_level_artwork_set[type] = has_level_artwork_set;
+
+  /* ---------- reload if "override artwork" setting has changed ----------- */
+  if (last_override_level_artwork[type] != setup_override_artwork)
+    artwork_new_identifier = artwork_current_identifier;
+
+  last_override_level_artwork[type] = setup_override_artwork;
+
+  /* ---------- reload if current artwork identifier has changed ----------- */
+  if (strcmp(ARTWORK_CURRENT_IDENTIFIER(artwork, type),
+            artwork_current_identifier) != 0)
+    artwork_new_identifier = artwork_current_identifier;
+
+  *(&(ARTWORK_CURRENT_IDENTIFIER(artwork, type))) = artwork_current_identifier;
+
+  /* ---------- do not reload directly after starting ---------------------- */
+  if (!initialized[type])
+    artwork_new_identifier = NULL;
+
+  initialized[type] = TRUE;
+
+#if 0
+  printf("CHECKING OLD/NEW GFX:\n- OLD: %s\n- NEW: %s ['%s', '%s'] ['%s']\n",
+        artwork.gfx_current_identifier, artwork_current_identifier,
+        artwork.gfx_current->identifier, leveldir_current->graphics_set,
+        artwork_new_identifier);
+#endif
 
-  static int ep_inactive[] =
-  {
-    EL_LEERRAUM,
-    EL_ERDREICH,
-    EL_MAUERWERK,
-    EL_BD_WALL,
-    EL_FELSBODEN,
-    EL_SCHLUESSEL,
-    EL_BETON,
-    EL_AMOEBE_TOT,
-    EL_MORAST_LEER,
-    EL_BADEWANNE,
-    EL_ABLENK_AUS,
-    EL_SCHLUESSEL1,
-    EL_SCHLUESSEL2,
-    EL_SCHLUESSEL3,
-    EL_SCHLUESSEL4,
-    EL_EM_KEY_1,
-    EL_EM_KEY_2,
-    EL_EM_KEY_3,
-    EL_EM_KEY_4,
-    EL_PFORTE1,
-    EL_PFORTE2,
-    EL_PFORTE3,
-    EL_PFORTE4,
-    EL_PFORTE1X,
-    EL_PFORTE2X,
-    EL_PFORTE3X,
-    EL_PFORTE4X,
-    EL_EM_GATE_1,
-    EL_EM_GATE_2,
-    EL_EM_GATE_3,
-    EL_EM_GATE_4,
-    EL_EM_GATE_1X,
-    EL_EM_GATE_2X,
-    EL_EM_GATE_3X,
-    EL_EM_GATE_4X,
-    EL_DYNAMITE_INACTIVE,
-    EL_UNSICHTBAR,
-    EL_BIRNE_AUS,
-    EL_BIRNE_EIN,
-    EL_ERZ_EDEL,
-    EL_ERZ_DIAM,
-    EL_ERZ_EDEL_BD,
-    EL_ERZ_EDEL_GELB,
-    EL_DYNABOMB_NR,
-    EL_DYNABOMB_SZ,
-    EL_DYNABOMB_XL,
-    EL_SOKOBAN_OBJEKT,
-    EL_SOKOBAN_FELD_LEER,
-    EL_SOKOBAN_FELD_VOLL,
-    EL_ERZ_EDEL_ROT,
-    EL_ERZ_EDEL_LILA,
-    EL_BADEWANNE1,
-    EL_BADEWANNE2,
-    EL_BADEWANNE3,
-    EL_BADEWANNE4,
-    EL_BADEWANNE5,
-    EL_MAGIC_WALL_OFF,
-    EL_MAGIC_WALL_DEAD,
-    EL_MAGIC_WALL_BD_OFF,
-    EL_MAGIC_WALL_BD_DEAD,
-    EL_AMOEBA2DIAM,
-    EL_BLOCKED,
-    EL_SP_EMPTY,
-    EL_SP_BASE,
-    EL_SP_PORT1_RIGHT,
-    EL_SP_PORT1_DOWN,
-    EL_SP_PORT1_LEFT,
-    EL_SP_PORT1_UP,
-    EL_SP_PORT2_RIGHT,
-    EL_SP_PORT2_DOWN,
-    EL_SP_PORT2_LEFT,
-    EL_SP_PORT2_UP,
-    EL_SP_PORT_X,
-    EL_SP_PORT_Y,
-    EL_SP_PORT_XY,
-    EL_SP_DISK_RED,
-    EL_SP_DISK_YELLOW,
-    EL_SP_CHIP_SINGLE,
-    EL_SP_CHIP_LEFT,
-    EL_SP_CHIP_RIGHT,
-    EL_SP_CHIP_UPPER,
-    EL_SP_CHIP_LOWER,
-    EL_SP_HARD_GRAY,
-    EL_SP_HARD_GREEN,
-    EL_SP_HARD_BLUE,
-    EL_SP_HARD_RED,
-    EL_SP_HARD_YELLOW,
-    EL_SP_HARD_BASE1,
-    EL_SP_HARD_BASE2,
-    EL_SP_HARD_BASE3,
-    EL_SP_HARD_BASE4,
-    EL_SP_HARD_BASE5,
-    EL_SP_HARD_BASE6,
-    EL_SP_EXIT,
-    EL_INVISIBLE_STEEL,
-    EL_BELT1_SWITCH_LEFT,
-    EL_BELT1_SWITCH_MIDDLE,
-    EL_BELT1_SWITCH_RIGHT,
-    EL_BELT2_SWITCH_LEFT,
-    EL_BELT2_SWITCH_MIDDLE,
-    EL_BELT2_SWITCH_RIGHT,
-    EL_BELT3_SWITCH_LEFT,
-    EL_BELT3_SWITCH_MIDDLE,
-    EL_BELT3_SWITCH_RIGHT,
-    EL_BELT4_SWITCH_LEFT,
-    EL_BELT4_SWITCH_MIDDLE,
-    EL_BELT4_SWITCH_RIGHT,
-    EL_SIGN_EXCLAMATION,
-    EL_SIGN_RADIOACTIVITY,
-    EL_SIGN_STOP,
-    EL_SIGN_WHEELCHAIR,
-    EL_SIGN_PARKING,
-    EL_SIGN_ONEWAY,
-    EL_SIGN_HEART,
-    EL_SIGN_TRIANGLE,
-    EL_SIGN_ROUND,
-    EL_SIGN_EXIT,
-    EL_SIGN_YINYANG,
-    EL_SIGN_OTHER,
-    EL_STEEL_SLANTED,
-    EL_EMC_STEEL_WALL_1,
-    EL_EMC_STEEL_WALL_2,
-    EL_EMC_STEEL_WALL_3,
-    EL_EMC_STEEL_WALL_4,
-    EL_EMC_WALL_1,
-    EL_EMC_WALL_2,
-    EL_EMC_WALL_3,
-    EL_EMC_WALL_4,
-    EL_EMC_WALL_5,
-    EL_EMC_WALL_6,
-    EL_EMC_WALL_7,
-    EL_EMC_WALL_8
-  };
-  static int ep_inactive_num = SIZEOF_ARRAY_INT(ep_inactive);
+  return artwork_new_identifier;
+}
 
-  static int ep_explosive[] =
-  {
-    EL_BOMBE,
-    EL_DYNAMITE_ACTIVE,
-    EL_DYNAMITE_INACTIVE,
-    EL_DYNABOMB_ACTIVE_1,
-    EL_DYNABOMB_ACTIVE_2,
-    EL_DYNABOMB_ACTIVE_3,
-    EL_DYNABOMB_ACTIVE_4,
-    EL_DYNABOMB_NR,
-    EL_DYNABOMB_SZ,
-    EL_DYNABOMB_XL,
-    EL_KAEFER,
-    EL_MOLE,
-    EL_PINGUIN,
-    EL_SCHWEIN,
-    EL_DRACHE,
-    EL_SONDE,
-    EL_SP_DISK_RED,
-    EL_SP_DISK_ORANGE,
-    EL_SP_DISK_YELLOW,
-    EL_SP_SNIKSNAK,
-    EL_SP_ELECTRON,
-    EL_DX_SUPABOMB
-  };
-  static int ep_explosive_num = SIZEOF_ARRAY_INT(ep_explosive);
+void ReloadCustomArtwork()
+{
+  char *gfx_new_identifier = getNewArtworkIdentifier(ARTWORK_TYPE_GRAPHICS);
+  char *snd_new_identifier = getNewArtworkIdentifier(ARTWORK_TYPE_SOUNDS);
+  char *mus_new_identifier = getNewArtworkIdentifier(ARTWORK_TYPE_MUSIC);
+  boolean redraw_screen = FALSE;
 
-  static int ep_mampf3[] =
+  if (gfx_new_identifier != NULL)
   {
-    EL_EDELSTEIN,
-    EL_EDELSTEIN_BD,
-    EL_EDELSTEIN_GELB,
-    EL_EDELSTEIN_ROT,
-    EL_EDELSTEIN_LILA,
-    EL_DIAMANT,
-    EL_PEARL,
-    EL_CRYSTAL
-  };
-  static int ep_mampf3_num = SIZEOF_ARRAY_INT(ep_mampf3);
+#if 0
+    printf("RELOADING GRAPHICS '%s' -> '%s' ['%s']\n",
+          artwork.gfx_current_identifier,
+          gfx_new_identifier,
+          artwork.gfx_current->identifier);
+#endif
 
-  static int ep_pushable[] =
-  {
-    EL_FELSBROCKEN,
-    EL_BD_ROCK,
-    EL_BOMBE,
-    EL_KOKOSNUSS,
-    EL_ZEIT_LEER,
-    EL_SOKOBAN_FELD_VOLL,
-    EL_SOKOBAN_OBJEKT,
-    EL_SONDE,
-    EL_SP_ZONK,
-    EL_SP_DISK_ORANGE,
-    EL_SP_DISK_YELLOW,
-    EL_BALLOON,
-    EL_SPRING,
-    EL_DX_SUPABOMB
-  };
-  static int ep_pushable_num = SIZEOF_ARRAY_INT(ep_pushable);
+    ClearRectangle(window, 0, 0, WIN_XSIZE, WIN_YSIZE);
 
-  static int ep_player[] =
-  {
-    EL_SPIELFIGUR,
-    EL_SPIELER1,
-    EL_SPIELER2,
-    EL_SPIELER3,
-    EL_SPIELER4
-  };
-  static int ep_player_num = SIZEOF_ARRAY_INT(ep_player);
+    InitImages();
 
-  static int ep_has_content[] =
-  {
-    EL_MAMPFER,
-    EL_AMOEBE_NASS,
-    EL_AMOEBE_NORM,
-    EL_AMOEBE_VOLL,
-    EL_AMOEBE_BD
-  };
-  static int ep_has_content_num = SIZEOF_ARRAY_INT(ep_has_content);
+    FreeTileClipmasks();
+    InitTileClipmasks();
 
-  static int ep_eatable[] =
-  {
-    EL_ERDREICH,
-    EL_SP_BASE,
-    EL_SP_BUG,
-    EL_TRAP_INACTIVE,
-    EL_SAND_INVISIBLE
-  };
-  static int ep_eatable_num = SIZEOF_ARRAY_INT(ep_eatable);
+    redraw_screen = TRUE;
+  }
 
-  static int ep_sp_element[] =
+  if (snd_new_identifier != NULL)
   {
-    EL_SP_EMPTY,
-    EL_SP_ZONK,
-    EL_SP_BASE,
-    EL_SP_MURPHY,
-    EL_SP_INFOTRON,
-    EL_SP_CHIP_SINGLE,
-    EL_SP_HARD_GRAY,
-    EL_SP_EXIT,
-    EL_SP_DISK_ORANGE,
-    EL_SP_PORT1_RIGHT,
-    EL_SP_PORT1_DOWN,
-    EL_SP_PORT1_LEFT,
-    EL_SP_PORT1_UP,
-    EL_SP_PORT2_RIGHT,
-    EL_SP_PORT2_DOWN,
-    EL_SP_PORT2_LEFT,
-    EL_SP_PORT2_UP,
-    EL_SP_SNIKSNAK,
-    EL_SP_DISK_YELLOW,
-    EL_SP_TERMINAL,
-    EL_SP_DISK_RED,
-    EL_SP_PORT_Y,
-    EL_SP_PORT_X,
-    EL_SP_PORT_XY,
-    EL_SP_ELECTRON,
-    EL_SP_BUG,
-    EL_SP_CHIP_LEFT,
-    EL_SP_CHIP_RIGHT,
-    EL_SP_HARD_BASE1,
-    EL_SP_HARD_GREEN,
-    EL_SP_HARD_BLUE,
-    EL_SP_HARD_RED,
-    EL_SP_HARD_YELLOW,
-    EL_SP_HARD_BASE2,
-    EL_SP_HARD_BASE3,
-    EL_SP_HARD_BASE4,
-    EL_SP_HARD_BASE5,
-    EL_SP_HARD_BASE6,
-    EL_SP_CHIP_UPPER,
-    EL_SP_CHIP_LOWER,
-    /* additional elements that appeared in newer Supaplex levels */
-    EL_UNSICHTBAR,
-    /* more than one murphy in a level results in an inactive clone */
-    EL_SP_MURPHY_CLONE
-  };
-  static int ep_sp_element_num = SIZEOF_ARRAY_INT(ep_sp_element);
+    ClearRectangle(window, 0, 0, WIN_XSIZE, WIN_YSIZE);
 
-  static int ep_quick_gate[] =
-  {
-    EL_EM_GATE_1,
-    EL_EM_GATE_2,
-    EL_EM_GATE_3,
-    EL_EM_GATE_4,
-    EL_EM_GATE_1X,
-    EL_EM_GATE_2X,
-    EL_EM_GATE_3X,
-    EL_EM_GATE_4X,
-    EL_SP_PORT1_LEFT,
-    EL_SP_PORT2_LEFT,
-    EL_SP_PORT1_RIGHT,
-    EL_SP_PORT2_RIGHT,
-    EL_SP_PORT1_UP,
-    EL_SP_PORT2_UP,
-    EL_SP_PORT1_DOWN,
-    EL_SP_PORT2_DOWN,
-    EL_SP_PORT_X,
-    EL_SP_PORT_Y,
-    EL_SP_PORT_XY,
-    EL_SWITCHGATE_OPEN,
-    EL_TIMEGATE_OPEN
-  };
-  static int ep_quick_gate_num = SIZEOF_ARRAY_INT(ep_quick_gate);
-
-  static int ep_over_player[] =
-  {
-    EL_SP_PORT1_LEFT,
-    EL_SP_PORT2_LEFT,
-    EL_SP_PORT1_RIGHT,
-    EL_SP_PORT2_RIGHT,
-    EL_SP_PORT1_UP,
-    EL_SP_PORT2_UP,
-    EL_SP_PORT1_DOWN,
-    EL_SP_PORT2_DOWN,
-    EL_SP_PORT_X,
-    EL_SP_PORT_Y,
-    EL_SP_PORT_XY,
-    EL_TUBE_CROSS,
-    EL_TUBE_VERTICAL,
-    EL_TUBE_HORIZONTAL,
-    EL_TUBE_VERT_LEFT,
-    EL_TUBE_VERT_RIGHT,
-    EL_TUBE_HORIZ_UP,
-    EL_TUBE_HORIZ_DOWN,
-    EL_TUBE_LEFT_UP,
-    EL_TUBE_LEFT_DOWN,
-    EL_TUBE_RIGHT_UP,
-    EL_TUBE_RIGHT_DOWN
-  };
-  static int ep_over_player_num = SIZEOF_ARRAY_INT(ep_over_player);
+    InitSound(snd_new_identifier);
 
-  static int ep_active_bomb[] =
-  {
-    EL_DYNAMITE_ACTIVE,
-    EL_DYNABOMB_ACTIVE_1,
-    EL_DYNABOMB_ACTIVE_2,
-    EL_DYNABOMB_ACTIVE_3,
-    EL_DYNABOMB_ACTIVE_4
-  };
-  static int ep_active_bomb_num = SIZEOF_ARRAY_INT(ep_active_bomb);
+    redraw_screen = TRUE;
+  }
 
-  static int ep_belt[] =
+  if (mus_new_identifier != NULL)
   {
-    EL_BELT1_LEFT,
-    EL_BELT1_MIDDLE,
-    EL_BELT1_RIGHT,
-    EL_BELT2_LEFT,
-    EL_BELT2_MIDDLE,
-    EL_BELT2_RIGHT,
-    EL_BELT3_LEFT,
-    EL_BELT3_MIDDLE,
-    EL_BELT3_RIGHT,
-    EL_BELT4_LEFT,
-    EL_BELT4_MIDDLE,
-    EL_BELT4_RIGHT,
-  };
-  static int ep_belt_num = SIZEOF_ARRAY_INT(ep_belt);
+    ClearRectangle(window, 0, 0, WIN_XSIZE, WIN_YSIZE);
 
-  static int ep_belt_switch[] =
-  {
-    EL_BELT1_SWITCH_LEFT,
-    EL_BELT1_SWITCH_MIDDLE,
-    EL_BELT1_SWITCH_RIGHT,
-    EL_BELT2_SWITCH_LEFT,
-    EL_BELT2_SWITCH_MIDDLE,
-    EL_BELT2_SWITCH_RIGHT,
-    EL_BELT3_SWITCH_LEFT,
-    EL_BELT3_SWITCH_MIDDLE,
-    EL_BELT3_SWITCH_RIGHT,
-    EL_BELT4_SWITCH_LEFT,
-    EL_BELT4_SWITCH_MIDDLE,
-    EL_BELT4_SWITCH_RIGHT,
-  };
-  static int ep_belt_switch_num = SIZEOF_ARRAY_INT(ep_belt_switch);
+    InitMusic(mus_new_identifier);
 
-  static int ep_tube[] =
-  {
-    EL_TUBE_CROSS,
-    EL_TUBE_VERTICAL,
-    EL_TUBE_HORIZONTAL,
-    EL_TUBE_VERT_LEFT,
-    EL_TUBE_VERT_RIGHT,
-    EL_TUBE_HORIZ_UP,
-    EL_TUBE_HORIZ_DOWN,
-    EL_TUBE_LEFT_UP,
-    EL_TUBE_LEFT_DOWN,
-    EL_TUBE_RIGHT_UP,
-    EL_TUBE_RIGHT_DOWN
-  };
-  static int ep_tube_num = SIZEOF_ARRAY_INT(ep_tube);
-
-  static long ep1_bit[] =
-  {
-    EP_BIT_AMOEBALIVE,
-    EP_BIT_AMOEBOID,
-    EP_BIT_SCHLUESSEL,
-    EP_BIT_PFORTE,
-    EP_BIT_SOLID,
-    EP_BIT_MASSIVE,
-    EP_BIT_SLIPPERY,
-    EP_BIT_ENEMY,
-    EP_BIT_MAUER,
-    EP_BIT_CAN_FALL,
-    EP_BIT_CAN_SMASH,
-    EP_BIT_CAN_CHANGE,
-    EP_BIT_CAN_MOVE,
-    EP_BIT_COULD_MOVE,
-    EP_BIT_DONT_TOUCH,
-    EP_BIT_DONT_GO_TO,
-    EP_BIT_MAMPF2,
-    EP_BIT_BD_ELEMENT,
-    EP_BIT_SB_ELEMENT,
-    EP_BIT_GEM,
-    EP_BIT_INACTIVE,
-    EP_BIT_EXPLOSIVE,
-    EP_BIT_MAMPF3,
-    EP_BIT_PUSHABLE,
-    EP_BIT_PLAYER,
-    EP_BIT_HAS_CONTENT,
-    EP_BIT_EATABLE,
-    EP_BIT_SP_ELEMENT,
-    EP_BIT_QUICK_GATE,
-    EP_BIT_OVER_PLAYER,
-    EP_BIT_ACTIVE_BOMB
-  };
-  static long ep2_bit[] =
-  {
-    EP_BIT_BELT,
-    EP_BIT_BELT_SWITCH,
-    EP_BIT_TUBE
-  };
-  static int *ep1_array[] =
-  {
-    ep_amoebalive,
-    ep_amoeboid,
-    ep_schluessel,
-    ep_pforte,
-    ep_solid,
-    ep_massive,
-    ep_slippery,
-    ep_enemy,
-    ep_mauer,
-    ep_can_fall,
-    ep_can_smash,
-    ep_can_change,
-    ep_can_move,
-    ep_could_move,
-    ep_dont_touch,
-    ep_dont_go_to,
-    ep_mampf2,
-    ep_bd_element,
-    ep_sb_element,
-    ep_gem,
-    ep_inactive,
-    ep_explosive,
-    ep_mampf3,
-    ep_pushable,
-    ep_player,
-    ep_has_content,
-    ep_eatable,
-    ep_sp_element,
-    ep_quick_gate,
-    ep_over_player,
-    ep_active_bomb
-  };
-  static int *ep2_array[] =
-  {
-    ep_belt,
-    ep_belt_switch,
-    ep_tube
-  };
-  static int *ep1_num[] =
-  {
-    &ep_amoebalive_num,
-    &ep_amoeboid_num,
-    &ep_schluessel_num,
-    &ep_pforte_num,
-    &ep_solid_num,
-    &ep_massive_num,
-    &ep_slippery_num,
-    &ep_enemy_num,
-    &ep_mauer_num,
-    &ep_can_fall_num,
-    &ep_can_smash_num,
-    &ep_can_change_num,
-    &ep_can_move_num,
-    &ep_could_move_num,
-    &ep_dont_touch_num,
-    &ep_dont_go_to_num,
-    &ep_mampf2_num,
-    &ep_bd_element_num,
-    &ep_sb_element_num,
-    &ep_gem_num,
-    &ep_inactive_num,
-    &ep_explosive_num,
-    &ep_mampf3_num,
-    &ep_pushable_num,
-    &ep_player_num,
-    &ep_has_content_num,
-    &ep_eatable_num,
-    &ep_sp_element_num,
-    &ep_quick_gate_num,
-    &ep_over_player_num,
-    &ep_active_bomb_num
-  };
-  static int *ep2_num[] =
-  {
-    &ep_belt_num,
-    &ep_belt_switch_num,
-    &ep_tube_num
-  };
-  static int num_properties1 = SIZEOF_ARRAY(ep1_num, int *);
-  static int num_properties2 = SIZEOF_ARRAY(ep2_num, int *);
+    redraw_screen = TRUE;
+  }
 
-  for(i=0; i<MAX_ELEMENTS; i++)
+  if (redraw_screen)
   {
-    Elementeigenschaften1[i] = 0;
-    Elementeigenschaften2[i] = 0;
-  }
+    InitGfxBackground();
 
-  for(i=0; i<num_properties1; i++)
-    for(j=0; j<*(ep1_num[i]); j++)
-      Elementeigenschaften1[(ep1_array[i])[j]] |= ep1_bit[i];
-  for(i=0; i<num_properties2; i++)
-    for(j=0; j<*(ep2_num[i]); j++)
-      Elementeigenschaften2[(ep2_array[i])[j]] |= ep2_bit[i];
+    /* force redraw of (open or closed) door graphics */
+    SetDoorState(DOOR_OPEN_ALL);
+    CloseDoor(DOOR_CLOSE_ALL | DOOR_NO_DELAY);
+  }
+}
 
-  for(i=EL_CHAR_START; i<=EL_CHAR_END; i++)
-    Elementeigenschaften1[i] |= (EP_BIT_CHAR | EP_BIT_INACTIVE);
+void KeyboardAutoRepeatOffUnlessAutoplay()
+{
+  if (global.autoplay_leveldir == NULL)
+    KeyboardAutoRepeatOff();
 }
 
-void Execute_Debug_Command(char *command)
+
+/* ========================================================================= */
+/* OpenAll()                                                                 */
+/* ========================================================================= */
+
+void OpenAll()
 {
-  if (strcmp(command, "create graphicsinfo.conf") == 0)
+  InitGlobal();                /* initialize some global variables */
+
+  if (options.execute_command)
+    Execute_Command(options.execute_command);
+
+  if (options.serveronly)
   {
-    printf("# (Currently only \"name\" and \"sort_priority\" recognized.)\n");
-    printf("\n");
-    printf("%s\n", getFormattedSetupEntry("name", "Classic Graphics"));
-    printf("\n");
-    printf("%s\n", getFormattedSetupEntry("sort_priority", "100"));
+#if defined(PLATFORM_UNIX)
+    NetworkServer(options.server_port, options.serveronly);
+#else
+    Error(ERR_WARN, "networking only supported in Unix version");
+#endif
+    exit(0);   /* never reached */
   }
-  else if (strcmp(command, "create soundsinfo.conf") == 0)
-  {
-    int i;
 
-    printf("# You can configure additional/alternative sound effects here\n");
-    printf("# (The sounds below are default and therefore commented out.)\n");
-    printf("\n");
-    printf("%s\n", getFormattedSetupEntry("name", "Classic Sounds"));
-    printf("\n");
-    printf("%s\n", getFormattedSetupEntry("sort_priority", "100"));
-    printf("\n");
+  InitSetup();
 
-    for (i=0; i<NUM_SOUND_EFFECTS; i++)
-      printf("# %s\n",
-            getFormattedSetupEntry(sound_effects[i].text,
-                                   sound_effects[i].default_filename));
-  }
-  else if (strcmp(command, "create musicinfo.conf") == 0)
+  InitPlayerInfo();
+  InitArtworkInfo();           /* needed before loading gfx, sound & music */
+  InitArtworkConfig();         /* needed before forking sound child process */
+  InitMixer();
+
+  InitCounter();
+
+  InitRND(NEW_RANDOMIZE);
+  InitSimpleRND(NEW_RANDOMIZE);
+
+  InitJoysticks();
+
+  InitVideoDisplay();
+  InitVideoBuffer(&backbuffer, &window, WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH,
+                 setup.fullscreen);
+
+  InitEventFilter(FilterMouseMotionEvents);
+
+  InitElementPropertiesStatic();
+
+  InitGfx();
+
+  InitLevelInfo();
+  InitLevelArtworkInfo();
+
+  InitImages();                        /* needs to know current level directory */
+  InitSound(NULL);             /* needs to know current level directory */
+  InitMusic(NULL);             /* needs to know current level directory */
+
+  InitGfxBackground();
+
+  if (global.autoplay_leveldir)
   {
-    printf("# (Currently only \"name\" and \"sort_priority\" recognized.)\n");
-    printf("\n");
-    printf("%s\n", getFormattedSetupEntry("name", "Classic Music"));
-    printf("\n");
-    printf("%s\n", getFormattedSetupEntry("sort_priority", "100"));
+    AutoPlayTape();
+    return;
   }
+
+  game_status = GAME_MODE_MAIN;
+
+  DrawMainMenu();
+
+  InitNetworkServer();
 }
 
 void CloseAllAndExit(int exit_value)
 {
-  int i;
-
   StopSounds();
   FreeAllSounds();
   FreeAllMusic();
   CloseAudio();                /* called after freeing sounds (needed for SDL) */
 
+  FreeAllImages();
   FreeTileClipmasks();
-  for(i=0; i<NUM_BITMAPS; i++)
-    FreeBitmap(pix[i]);
 
   CloseVideoDisplay();
-  ClosePlatformDependantStuff();
+  ClosePlatformDependentStuff();
 
   exit(exit_value);
 }
index 9eb9fb628c79aa82c6c8ca780bdc4e6f4c9a89f6..67fc835d5d3f17545b6d99456f79a84e36c25eaf 100644 (file)
 
 #include "main.h"
 
+void InitElementPropertiesStatic(void);
+void InitElementPropertiesEngine(int);
+
+void ReloadCustomArtwork(void);
+
+void KeyboardAutoRepeatOffUnlessAutoplay();
+
 void OpenAll(void);
-void ReloadCustomArtwork();
 void CloseAllAndExit(int);
 
 #endif
index f9f306b6345144cd1b914e50c347a70348a99a51..2eb6dda4bc8d7bdb732a1e01a12037de22b5ca4c 100644 (file)
@@ -12,6 +12,7 @@ SRCS =        system.c        \
        pcx.c           \
        image.c         \
        random.c        \
+       hash.c          \
        setup.c         \
        misc.c          \
        msdos.c         \
@@ -27,6 +28,7 @@ OBJS =        system.o        \
        pcx.o           \
        image.o         \
        random.o        \
+       hash.o          \
        setup.o         \
        misc.o          \
        msdos.o         \
index 9d709f3aba55d9359ae99c636d5a60f483ad2ebc..d2af524ac4353ceb8505c59351ea8e9834ca17e0 100644 (file)
@@ -63,21 +63,45 @@ static int getNewGadgetID()
   return id;
 }
 
-static struct GadgetInfo *getGadgetInfoFromMousePosition(int mx, int my)
+#if 0
+void DUMP_GADGET_MAP_STATE()
 {
   struct GadgetInfo *gi = gadget_list_first_entry;
 
-  while (gi)
+  while (gi != NULL)
   {
-    if (gi->mapped &&
-       mx >= gi->x && mx < gi->x + gi->width &&
-       my >= gi->y && my < gi->y + gi->height)
-       break;
+    printf("-XXX-1-> '%s': %s\n",
+          gi->info_text, (gi->mapped ? "mapped" : "not mapped"));
 
     gi = gi->next;
   }
+}
+#endif
 
-  return gi;
+static struct GadgetInfo *getGadgetInfoFromMousePosition(int mx, int my)
+{
+  struct GadgetInfo *gi;
+
+  /* open selectboxes 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_SELECTBOX && gi->selectbox.open &&
+       mx >= gi->selectbox.x && mx < gi->selectbox.x + gi->selectbox.width &&
+       my >= gi->selectbox.y && my < gi->selectbox.y + gi->selectbox.height)
+      return gi;
+  }
+
+  /* check all other gadgets */
+  for (gi = gadget_list_first_entry; gi != NULL; gi = gi->next)
+  {
+    if (gi->mapped && gi->active &&
+       mx >= gi->x && mx < gi->x + gi->width &&
+       my >= gi->y && my < gi->y + gi->height)
+      return gi;
+  }
+
+  return NULL;
 }
 
 static void default_callback_info(void *ptr)
@@ -92,18 +116,20 @@ static void default_callback_action(void *ptr)
 
 static void DrawGadget(struct GadgetInfo *gi, boolean pressed, boolean direct)
 {
-  int state = (pressed ? 1 : 0);
-  struct GadgetDesign *gd = (gi->checked ?
-                            &gi->alt_design[state] :
+  int state = (pressed ? GD_BUTTON_PRESSED : GD_BUTTON_UNPRESSED);
+  struct GadgetDesign *gd = (!gi->active ? &gi->alt_design[state] :
+                            gi->checked ? &gi->alt_design[state] :
                             &gi->design[state]);
+  boolean redraw_selectbox = FALSE;
 
   switch (gi->type)
   {
     case GD_TYPE_NORMAL_BUTTON:
     case GD_TYPE_CHECK_BUTTON:
     case GD_TYPE_RADIO_BUTTON:
-      BlitBitmap(gd->bitmap, drawto,
-                gd->x, gd->y, gi->width, gi->height, gi->x, gi->y);
+      BlitBitmapOnBackground(gd->bitmap, drawto,
+                            gd->x, gd->y, gi->width, gi->height,
+                            gi->x, gi->y);
       if (gi->deco.design.bitmap)
        BlitBitmap(gi->deco.design.bitmap, drawto,
                   gi->deco.design.x, gi->deco.design.y,
@@ -112,46 +138,280 @@ static void DrawGadget(struct GadgetInfo *gi, boolean pressed, boolean direct)
                   gi->y + gi->deco.y + (pressed ? gi->deco.yshift : 0));
       break;
 
+    case GD_TYPE_TEXT_BUTTON:
+      {
+       int i;
+       int font_nr = (gi->active ? gi->font_active : gi->font);
+       int font_width = getFontWidth(font_nr);
+       int border_x = gi->border.xsize;
+       int border_y = gi->border.ysize;
+       int text_size = strlen(gi->textbutton.value);
+       int text_start = (gi->width - text_size * font_width) / 2;
+
+       /* 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->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);
+
+       /* right part of gadget */
+       BlitBitmapOnBackground(gd->bitmap, drawto,
+                              gd->x + gi->border.width - border_x, gd->y,
+                              border_x, gi->height,
+                              gi->x + gi->width - border_x, gi->y);
+
+       /* gadget text value */
+       DrawTextExt(drawto,
+                   gi->x + text_start + (pressed ? gi->deco.xshift : 0),
+                   gi->y + border_y   + (pressed ? gi->deco.yshift : 0),
+                   gi->textbutton.value, font_nr, BLIT_MASKED);
+      }
+      break;
+
     case GD_TYPE_TEXTINPUT_ALPHANUMERIC:
     case GD_TYPE_TEXTINPUT_NUMERIC:
       {
        int i;
        char cursor_letter;
-       char cursor_string[3];
+       char cursor_string[2];
        char text[MAX_GADGET_TEXTSIZE + 1];
-       int font_type = gi->text.font_type;
-       int font_width = getFontWidth(FS_SMALL, font_type);
-       int border = gi->border.size;
-       strcpy(text, gi->text.value);
-       strcat(text, " ");
+       int font_nr = (pressed ? gi->font_active : gi->font);
+       int font_width = getFontWidth(font_nr);
+       int border_x = gi->border.xsize;
+       int border_y = gi->border.ysize;
 
        /* left part of gadget */
-       BlitBitmap(gd->bitmap, drawto,
-                  gd->x, gd->y, border, gi->height, gi->x, gi->y);
+       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->text.size; i++)
-         BlitBitmap(gd->bitmap, drawto,
-                    gd->x + border, gd->y, font_width, gi->height,
-                    gi->x + border + i * font_width, gi->y);
+       for (i=0; i < gi->text.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);
 
        /* right part of gadget */
-       BlitBitmap(gd->bitmap, drawto,
-                  gd->x + gi->border.width - border, gd->y,
-                  border, gi->height, gi->x + gi->width - border, gi->y);
+       BlitBitmapOnBackground(gd->bitmap, drawto,
+                              gd->x + gi->border.width - border_x, gd->y,
+                              border_x, gi->height,
+                              gi->x + gi->width - border_x, gi->y);
+
+       /* set text value */
+       strcpy(text, gi->text.value);
+       strcat(text, " ");
 
        /* gadget text value */
-       DrawText(gi->x + border, gi->y + border, text, FS_SMALL, font_type);
+       DrawTextExt(drawto,
+                   gi->x + border_x, gi->y + border_y, text,
+                   font_nr, BLIT_MASKED);
 
        cursor_letter = gi->text.value[gi->text.cursor_position];
-       cursor_string[0] = '~';
-       cursor_string[1] = (cursor_letter != '\0' ? cursor_letter : ' ');
-       cursor_string[2] = '\0';
+       cursor_string[0] = (cursor_letter != '\0' ? cursor_letter : ' ');
+       cursor_string[1] = '\0';
 
        /* draw cursor, if active */
        if (pressed)
-         DrawText(gi->x + border + gi->text.cursor_position * font_width,
-                  gi->y + border, cursor_string, FS_SMALL, font_type);
+         DrawTextExt(drawto,
+                     gi->x + border_x + gi->text.cursor_position * font_width,
+                     gi->y + border_y, cursor_string,
+                     font_nr, BLIT_INVERSE);
+      }
+      break;
+
+    case GD_TYPE_SELECTBOX:
+      {
+       int i;
+       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);
+       int border_x = gi->border.xsize;
+       int border_y = gi->border.ysize;
+       int button = gi->border.xsize_selectbutton;
+       int width_inner = gi->border.width - button - 2 * border_x;
+       int box_width = gi->selectbox.width;
+       int box_height = gi->selectbox.height;
+
+       /* 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->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);
+
+       /* button part of gadget */
+       BlitBitmapOnBackground(gd->bitmap, drawto,
+                              gd->x + border_x + width_inner, gd->y,
+                              button, gi->height,
+                              gi->x + gi->width - border_x - button, gi->y);
+
+       /* right part of gadget */
+       BlitBitmapOnBackground(gd->bitmap, drawto,
+                              gd->x + gi->border.width - border_x, gd->y,
+                              border_x, gi->height,
+                              gi->x + gi->width - border_x, gi->y);
+
+       /* set text value */
+       strncpy(text, gi->selectbox.options[gi->selectbox.index].text,
+               gi->selectbox.size);
+       text[gi->selectbox.size] = '\0';
+
+       /* gadget text value */
+       DrawTextExt(drawto, gi->x + border_x, gi->y + border_y, text,
+                   font_nr, BLIT_MASKED);
+
+       if (pressed)
+       {
+         if (!gi->selectbox.open)
+         {
+           gi->selectbox.open = TRUE;
+           gi->selectbox.stay_open = FALSE;
+           gi->selectbox.current_index = gi->selectbox.index;
+
+           /* save background under selectbox */
+           BlitBitmap(drawto, gfx.field_save_buffer,
+                      gi->selectbox.x,     gi->selectbox.y,
+                      gi->selectbox.width, gi->selectbox.height,
+                      gi->selectbox.x,     gi->selectbox.y);
+         }
+
+         /* draw open selectbox */
+
+         /* top left part of gadget border */
+         BlitBitmapOnBackground(gd->bitmap, drawto, gd->x, gd->y,
+                                border_x, border_y,
+                                gi->selectbox.x, gi->selectbox.y);
+
+         /* top middle part of gadget border */
+         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,
+                                  gi->selectbox.y);
+
+         /* top button part of gadget border */
+         BlitBitmapOnBackground(gd->bitmap, drawto,
+                                gd->x + border_x + width_inner, gd->y,
+                                button, border_y,
+                                gi->selectbox.x + box_width -border_x -button,
+                                gi->selectbox.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->selectbox.x + box_width - border_x,
+                                gi->selectbox.y);
+
+         /* left and right part of gadget border for each row */
+         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);
+           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);
+         }
+
+         /* bottom left part of gadget border */
+         BlitBitmapOnBackground(gd->bitmap, drawto,
+                                gd->x, gd->y + gi->height - border_y,
+                                border_x, border_y,
+                                gi->selectbox.x,
+                                gi->selectbox.y + box_height - border_y);
+
+         /* bottom middle part of gadget border */
+         for (i=0; i < gi->selectbox.size; i++)
+           BlitBitmapOnBackground(gd->bitmap, drawto,
+                                  gd->x + border_x,
+                                  gd->y + gi->height - border_y,
+                                  font_width, border_y,
+                                  gi->selectbox.x + border_x + i * font_width,
+                                  gi->selectbox.y + box_height - border_y);
+
+         /* bottom button part of gadget border */
+         BlitBitmapOnBackground(gd->bitmap, drawto,
+                                gd->x + border_x + width_inner,
+                                gd->y + gi->height - border_y,
+                                button, border_y,
+                                gi->selectbox.x + box_width -border_x -button,
+                                gi->selectbox.y + box_height - border_y);
+
+         /* bottom right part of gadget border */
+         BlitBitmapOnBackground(gd->bitmap, drawto,
+                                gd->x + gi->border.width - border_x,
+                                gd->y + gi->height - border_y,
+                                border_x, border_y,
+                                gi->selectbox.x + box_width - border_x,
+                                gi->selectbox.y + box_height - border_y);
+
+         ClearRectangleOnBackground(drawto,
+                                    gi->selectbox.x + border_x,
+                                    gi->selectbox.y + border_y,
+                                    gi->selectbox.width - 2 * border_x,
+                                    gi->selectbox.height - 2 * border_y);
+
+         /* selectbox text values */
+         for (i=0; i < gi->selectbox.num_values; i++)
+         {
+           int mask_mode;
+
+           if (i == gi->selectbox.current_index)
+           {
+             FillRectangle(drawto,
+                           gi->selectbox.x + border_x,
+                           gi->selectbox.y + border_y + i * font_height,
+                           gi->selectbox.width - 2 * border_x, font_height,
+                           gi->selectbox.inverse_color);
+
+             strncpy(text, gi->selectbox.options[i].text, gi->selectbox.size);
+             text[1 + gi->selectbox.size] = '\0';
+
+             mask_mode = BLIT_INVERSE;
+           }
+           else
+           {
+             strncpy(text, gi->selectbox.options[i].text, gi->selectbox.size);
+             text[gi->selectbox.size] = '\0';
+
+             mask_mode = BLIT_MASKED;
+           }
+
+           DrawTextExt(drawto,
+                       gi->selectbox.x + border_x,
+                       gi->selectbox.y + border_y + i * font_height, text,
+                       font_nr, mask_mode);
+         }
+
+         redraw_selectbox = TRUE;
+       }
+       else if (gi->selectbox.open)
+       {
+         gi->selectbox.open = FALSE;
+
+         /* redraw closed selectbox */
+         DrawGadget(gi, FALSE, FALSE);
+
+         /* restore background under selectbox */
+         BlitBitmap(gfx.field_save_buffer, drawto,
+                    gi->selectbox.x,     gi->selectbox.y,
+                    gi->selectbox.width, gi->selectbox.height,
+                    gi->selectbox.x,     gi->selectbox.y);
+
+         redraw_selectbox = TRUE;
+       }
       }
       break;
 
@@ -161,40 +421,44 @@ static void DrawGadget(struct GadgetInfo *gi, boolean pressed, boolean direct)
        int xpos = gi->x;
        int ypos = gi->y + gi->scrollbar.position;
        int design_full = gi->width;
-       int design_body = design_full - 2 * gi->border.size;
+       int design_body = design_full - 2 * gi->border.ysize;
        int size_full = gi->scrollbar.size;
-       int size_body = size_full - 2 * gi->border.size;
+       int size_body = size_full - 2 * gi->border.ysize;
        int num_steps = size_body / design_body;
        int step_size_remain = size_body - num_steps * design_body;
 
        /* clear scrollbar area */
-       ClearRectangle(backbuffer, gi->x, gi->y, gi->width, gi->height);
+       ClearRectangleOnBackground(backbuffer, gi->x, gi->y,
+                                  gi->width, gi->height);
 
        /* upper part of gadget */
-       BlitBitmap(gd->bitmap, drawto,
-                  gd->x, gd->y,
-                  gi->width, gi->border.size,
-                  xpos, ypos);
+       BlitBitmapOnBackground(gd->bitmap, drawto,
+                              gd->x, gd->y,
+                              gi->width, gi->border.ysize,
+                              xpos, ypos);
 
        /* middle part of gadget */
        for (i=0; i<num_steps; i++)
-         BlitBitmap(gd->bitmap, drawto,
-                    gd->x, gd->y + gi->border.size,
-                    gi->width, design_body,
-                    xpos, ypos + gi->border.size + i * design_body);
+         BlitBitmapOnBackground(gd->bitmap, drawto,
+                                gd->x, gd->y + gi->border.ysize,
+                                gi->width, design_body,
+                                xpos,
+                                ypos + gi->border.ysize + i * design_body);
 
        /* remaining middle part of gadget */
        if (step_size_remain > 0)
-         BlitBitmap(gd->bitmap, drawto,
-                    gd->x,  gd->y + gi->border.size,
-                    gi->width, step_size_remain,
-                    xpos, ypos + gi->border.size + num_steps * design_body);
+         BlitBitmapOnBackground(gd->bitmap, drawto,
+                                gd->x,  gd->y + gi->border.ysize,
+                                gi->width, step_size_remain,
+                                xpos,
+                                ypos + gi->border.ysize
+                                + num_steps * design_body);
 
        /* lower part of gadget */
-       BlitBitmap(gd->bitmap, drawto,
-                  gd->x, gd->y + design_full - gi->border.size,
-                  gi->width, gi->border.size,
-                  xpos, ypos + size_full - gi->border.size);
+       BlitBitmapOnBackground(gd->bitmap, drawto,
+                              gd->x, gd->y + design_full - gi->border.ysize,
+                              gi->width, gi->border.ysize,
+                              xpos, ypos + size_full - gi->border.ysize);
       }
       break;
 
@@ -204,40 +468,44 @@ static void DrawGadget(struct GadgetInfo *gi, boolean pressed, boolean direct)
        int xpos = gi->x + gi->scrollbar.position;
        int ypos = gi->y;
        int design_full = gi->height;
-       int design_body = design_full - 2 * gi->border.size;
+       int design_body = design_full - 2 * gi->border.xsize;
        int size_full = gi->scrollbar.size;
-       int size_body = size_full - 2 * gi->border.size;
+       int size_body = size_full - 2 * gi->border.xsize;
        int num_steps = size_body / design_body;
        int step_size_remain = size_body - num_steps * design_body;
 
        /* clear scrollbar area */
-       ClearRectangle(backbuffer, gi->x, gi->y, gi->width, gi->height);
+       ClearRectangleOnBackground(backbuffer, gi->x, gi->y,
+                                  gi->width, gi->height);
 
        /* left part of gadget */
-       BlitBitmap(gd->bitmap, drawto,
-                  gd->x, gd->y,
-                  gi->border.size, gi->height,
-                  xpos, ypos);
+       BlitBitmapOnBackground(gd->bitmap, drawto,
+                              gd->x, gd->y,
+                              gi->border.xsize, gi->height,
+                              xpos, ypos);
 
        /* middle part of gadget */
        for (i=0; i<num_steps; i++)
-         BlitBitmap(gd->bitmap, drawto,
-                    gd->x + gi->border.size, gd->y,
-                    design_body, gi->height,
-                    xpos + gi->border.size + i * design_body, ypos);
+         BlitBitmapOnBackground(gd->bitmap, drawto,
+                                gd->x + gi->border.xsize, gd->y,
+                                design_body, gi->height,
+                                xpos + gi->border.xsize + i * design_body,
+                                ypos);
 
        /* remaining middle part of gadget */
        if (step_size_remain > 0)
-         BlitBitmap(gd->bitmap, drawto,
-                    gd->x + gi->border.size, gd->y,
-                    step_size_remain, gi->height,
-                    xpos + gi->border.size + num_steps * design_body, ypos);
+         BlitBitmapOnBackground(gd->bitmap, drawto,
+                                gd->x + gi->border.xsize, gd->y,
+                                step_size_remain, gi->height,
+                                xpos + gi->border.xsize
+                                + num_steps * design_body,
+                                ypos);
 
        /* right part of gadget */
-       BlitBitmap(gd->bitmap, drawto,
-                  gd->x + design_full - gi->border.size, gd->y,
-                  gi->border.size, gi->height,
-                  xpos + size_full - gi->border.size, ypos);
+       BlitBitmapOnBackground(gd->bitmap, drawto,
+                              gd->x + design_full - gi->border.xsize, gd->y,
+                              gi->border.xsize, gi->height,
+                              xpos + size_full - gi->border.xsize, ypos);
       }
       break;
 
@@ -246,8 +514,16 @@ static void DrawGadget(struct GadgetInfo *gi, boolean pressed, boolean direct)
   }
 
   if (direct)
+  {
     BlitBitmap(drawto, window,
               gi->x, gi->y, gi->width, gi->height, gi->x, gi->y);
+
+    if (gi->type == GD_TYPE_SELECTBOX && redraw_selectbox)
+      BlitBitmap(drawto, window,
+                gi->selectbox.x,     gi->selectbox.y,
+                gi->selectbox.width, gi->selectbox.height,
+                gi->selectbox.x,     gi->selectbox.y);
+  }
   else
     redraw_mask |= (gi->x < gfx.sx + gfx.sxsize ? REDRAW_FIELD :
                    gi->y < gfx.dy + gfx.dysize ? REDRAW_DOOR_1 :
@@ -273,8 +549,13 @@ static void HandleGadgetTags(struct GadgetInfo *gi, int first_tag, va_list ap)
       case GDI_INFO_TEXT:
        {
          int max_textsize = MAX_INFO_TEXTSIZE - 1;
+         char *text = va_arg(ap, char *);
+
+         if (text != NULL)
+           strncpy(gi->info_text, text, max_textsize);
+         else
+           max_textsize = 0;
 
-         strncpy(gi->info_text, va_arg(ap, char *), max_textsize);
          gi->info_text[max_textsize] = '\0';
        }
        break;
@@ -303,6 +584,12 @@ static void HandleGadgetTags(struct GadgetInfo *gi, int first_tag, va_list ap)
        gi->state = va_arg(ap, unsigned long);
        break;
 
+      case GDI_ACTIVE:
+       /* take care here: "boolean" is typedef'ed as "unsigned char",
+          which gets promoted to "int" */
+       gi->active = (boolean)va_arg(ap, int);
+       break;
+
       case GDI_CHECKED:
        /* take care here: "boolean" is typedef'ed as "unsigned char",
           which gets promoted to "int" */
@@ -347,6 +634,9 @@ static void HandleGadgetTags(struct GadgetInfo *gi, int first_tag, va_list ap)
          strncpy(gi->text.value, va_arg(ap, char *), max_textsize);
          gi->text.value[max_textsize] = '\0';
          gi->text.cursor_position = strlen(gi->text.value);
+
+         /* same tag also used for textbutton definition */
+         strcpy(gi->textbutton.value, gi->text.value);
        }
        break;
 
@@ -357,11 +647,30 @@ static void HandleGadgetTags(struct GadgetInfo *gi, int first_tag, va_list ap)
 
          gi->text.size = max_textsize;
          gi->text.value[max_textsize] = '\0';
+
+         /* same tag also used for textbutton and selectbox definition */
+         strcpy(gi->textbutton.value, gi->text.value);
+         gi->textbutton.size = gi->text.size;
+         gi->selectbox.size = gi->text.size;
        }
        break;
 
       case GDI_TEXT_FONT:
-       gi->text.font_type = va_arg(ap, int);
+       gi->font = va_arg(ap, int);
+       if (gi->font_active == 0)
+         gi->font_active = gi->font;
+       break;
+
+      case GDI_TEXT_FONT_ACTIVE:
+       gi->font_active = va_arg(ap, int);
+       break;
+
+      case GDI_SELECTBOX_OPTIONS:
+       gi->selectbox.options = va_arg(ap, struct ValueTextInfo *);
+       break;
+
+      case GDI_SELECTBOX_INDEX:
+       gi->selectbox.index = va_arg(ap, int);
        break;
 
       case GDI_DESIGN_UNPRESSED:
@@ -389,10 +698,15 @@ static void HandleGadgetTags(struct GadgetInfo *gi, int first_tag, va_list ap)
        break;
 
       case GDI_BORDER_SIZE:
-       gi->border.size = va_arg(ap, int);
+       gi->border.xsize = va_arg(ap, int);
+       gi->border.ysize = va_arg(ap, int);
        break;
 
-      case GDI_TEXTINPUT_DESIGN_WIDTH:
+      case GDI_BORDER_SIZE_SELECTBUTTON:
+       gi->border.xsize_selectbutton = va_arg(ap, int);
+       break;
+
+      case GDI_DESIGN_WIDTH:
        gi->border.width = va_arg(ap, int);
        break;
 
@@ -486,7 +800,7 @@ static void HandleGadgetTags(struct GadgetInfo *gi, int first_tag, va_list ap)
     tag = va_arg(ap, int);     /* read next tag */
   }
 
-  /* check if gadget complete */
+  /* check if gadget is complete */
   if (gi->type != GD_TYPE_DRAWING_AREA &&
       (!gi->design[GD_BUTTON_UNPRESSED].bitmap ||
        !gi->design[GD_BUTTON_PRESSED].bitmap))
@@ -496,11 +810,57 @@ static void HandleGadgetTags(struct GadgetInfo *gi, int first_tag, va_list ap)
 
   if (gi->type & GD_TYPE_TEXTINPUT)
   {
-    int font_width = getFontWidth(FS_SMALL, gi->text.font_type);
-    int font_height = getFontHeight(FS_SMALL, gi->text.font_type);
+    int font_nr = gi->font_active;
+    int font_width = getFontWidth(font_nr);
+    int font_height = getFontHeight(font_nr);
+    int border_xsize = gi->border.xsize;
+    int border_ysize = gi->border.ysize;
+
+    gi->width  = 2 * border_xsize + (gi->text.size + 1) * font_width;
+    gi->height = 2 * border_ysize + font_height;
+  }
 
-    gi->width = 2 * gi->border.size + (gi->text.size + 1) * font_width;
-    gi->height = 2 * gi->border.size + font_height;
+  if (gi->type & GD_TYPE_SELECTBOX)
+  {
+    int font_nr = gi->font_active;
+    int font_width = getFontWidth(font_nr);
+    int font_height = getFontHeight(font_nr);
+    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;
+    Bitmap *src_bitmap;
+    int src_x, src_y;
+
+    gi->width  = 2 * border_xsize + gi->text.size * font_width + button_size;
+    gi->height = 2 * border_ysize + font_height;
+
+    if (gi->selectbox.options == NULL)
+      Error(ERR_EXIT, "selectbox gadget incomplete (missing options array)");
+
+    gi->selectbox.num_values = 0;
+    while (gi->selectbox.options[gi->selectbox.num_values].text != NULL)
+      gi->selectbox.num_values++;
+
+    /* calculate values for open selectbox */
+    gi->selectbox.width = gi->width;
+    gi->selectbox.height =
+      2 * border_ysize + gi->selectbox.num_values * font_height;
+
+    gi->selectbox.x = gi->x;
+    gi->selectbox.y = gi->y + gi->height;
+    if (gi->selectbox.y + gi->selectbox.height > bottom_screen_border)
+      gi->selectbox.y = gi->y - gi->selectbox.height;
+    if (gi->selectbox.y < 0)
+      gi->selectbox.y = bottom_screen_border - gi->selectbox.height;
+
+    getFontCharSource(font_nr, FONT_ASCII_CURSOR, &src_bitmap, &src_x, &src_y);
+    src_x += font_width / 2;
+    src_y += font_height / 2;
+    gi->selectbox.inverse_color = GetPixel(src_bitmap, src_x, src_y);
+
+    /* always start with closed selectbox */
+    gi->selectbox.open = FALSE;
   }
 
   if (gi->type & GD_TYPE_TEXTINPUT_NUMERIC)
@@ -515,6 +875,18 @@ static void HandleGadgetTags(struct GadgetInfo *gi, int first_tag, va_list ap)
     sprintf(text->value, "%d", text->number_value);
   }
 
+  if (gi->type & GD_TYPE_TEXT_BUTTON)
+  {
+    int font_nr = gi->font_active;
+    int font_width = getFontWidth(font_nr);
+    int font_height = getFontHeight(font_nr);
+    int border_xsize = gi->border.xsize;
+    int border_ysize = gi->border.ysize;
+
+    gi->width  = 2 * border_xsize + gi->textbutton.size * font_width;
+    gi->height = 2 * border_ysize + font_height;
+  }
+
   if (gi->type & GD_TYPE_SCROLLBAR)
   {
     struct GadgetScrollbar *gs = &gi->scrollbar;
@@ -556,14 +928,15 @@ void RedrawGadget(struct GadgetInfo *gi)
 
 struct GadgetInfo *CreateGadget(int first_tag, ...)
 {
-  struct GadgetInfo *new_gadget = checked_malloc(sizeof(struct GadgetInfo));
+  struct GadgetInfo *new_gadget = checked_calloc(sizeof(struct GadgetInfo));
   va_list ap;
 
   /* always start with reliable default values */
-  memset(new_gadget, 0, sizeof(struct GadgetInfo));    /* zero all fields */
   new_gadget->id = getNewGadgetID();
   new_gadget->callback_info = default_callback_info;
   new_gadget->callback_action = default_callback_action;
+  new_gadget->active = TRUE;
+  new_gadget->next = NULL;
 
   va_start(ap, first_tag);
   HandleGadgetTags(new_gadget, first_tag, ap);
@@ -585,7 +958,7 @@ void FreeGadget(struct GadgetInfo *gi)
 {
   struct GadgetInfo *gi_previous = gadget_list_first_entry;
 
-  while (gi_previous && gi_previous->next != gi)
+  while (gi_previous != NULL && gi_previous->next != gi)
     gi_previous = gi_previous->next;
 
   if (gi == gadget_list_first_entry)
@@ -594,7 +967,9 @@ void FreeGadget(struct GadgetInfo *gi)
   if (gi == gadget_list_last_entry)
     gadget_list_last_entry = gi_previous;
 
-  gi_previous->next = gi->next;
+  if (gi_previous != NULL)
+    gi_previous->next = gi->next;
+
   free(gi);
 }
 
@@ -665,7 +1040,7 @@ static void MultiMapGadgets(int mode)
   static boolean map_state[MAX_NUM_GADGETS];
   int map_count = 0;
 
-  while (gi)
+  while (gi != NULL)
   {
     if ((mode & MULTIMAP_PLAYFIELD &&
         gi->x < gfx.sx + gfx.sxsize) ||
@@ -701,9 +1076,19 @@ void RemapAllGadgets()
   MultiMapGadgets(MULTIMAP_ALL | MULTIMAP_REMAP);
 }
 
+boolean anyTextInputGadgetActive()
+{
+  return (last_gi && (last_gi->type & GD_TYPE_TEXTINPUT) && last_gi->mapped);
+}
+
+boolean anySelectboxGadgetActive()
+{
+  return (last_gi && (last_gi->type & GD_TYPE_SELECTBOX) && last_gi->mapped);
+}
+
 boolean anyTextGadgetActive()
 {
-  return (last_gi && last_gi->type & GD_TYPE_TEXTINPUT && last_gi->mapped);
+  return (anyTextInputGadgetActive() || anySelectboxGadgetActive());
 }
 
 void ClickOnGadget(struct GadgetInfo *gi, int button)
@@ -737,6 +1122,8 @@ void HandleGadgets(int mx, int my, int button)
   boolean gadget_moving_off_borders;
   boolean gadget_released;
   boolean gadget_released_inside;
+  boolean gadget_released_inside_select_line;
+  boolean gadget_released_inside_select_area;
   boolean gadget_released_off_borders;
   boolean changed_position = FALSE;
 
@@ -744,6 +1131,13 @@ void HandleGadgets(int mx, int my, int button)
   if (gadget_list_first_entry == NULL)
     return;
 
+  /* simulated release of mouse button over last gadget */
+  if (mx == -1 && my == -1 && button == 0)
+  {
+    mx = last_mx;
+    my = last_my;
+  }
+
   /* check which gadget is under the mouse pointer */
   new_gi = getGadgetInfoFromMousePosition(mx, my);
 
@@ -758,23 +1152,25 @@ void HandleGadgets(int mx, int my, int button)
   last_my = my;
 
   /* special treatment for text and number input gadgets */
-  if (anyTextGadgetActive() && button != 0 && !motion_status)
+  if (anyTextInputGadgetActive() && button != 0 && !motion_status)
   {
     struct GadgetInfo *gi = last_gi;
 
     if (new_gi == last_gi)
     {
+      int old_cursor_position = gi->text.cursor_position;
+
       /* if mouse button pressed inside activated text gadget, set cursor */
       gi->text.cursor_position =
-       (mx - gi->x - gi->border.size) /
-       getFontWidth(FS_SMALL, gi->text.font_type);
+       (mx - gi->x - gi->border.xsize) / getFontWidth(gi->font);
 
       if (gi->text.cursor_position < 0)
        gi->text.cursor_position = 0;
       else if (gi->text.cursor_position > strlen(gi->text.value))
        gi->text.cursor_position = strlen(gi->text.value);
 
-      DrawGadget(gi, DG_PRESSED, DG_DIRECT);
+      if (gi->text.cursor_position != old_cursor_position)
+       DrawGadget(gi, DG_PRESSED, DG_DIRECT);
     }
     else
     {
@@ -791,6 +1187,42 @@ void HandleGadgets(int mx, int my, int button)
     }
   }
 
+  /* special treatment for selectbox gadgets */
+  if (anySelectboxGadgetActive() && button != 0 && !motion_status)
+  {
+    struct GadgetInfo *gi = last_gi;
+
+    if (new_gi == last_gi)
+    {
+      int old_index = gi->selectbox.current_index;
+
+      /* if mouse button pressed inside activated selectbox, select value */
+      if (my >= gi->selectbox.y && my < gi->selectbox.y + gi->selectbox.height)
+       gi->selectbox.current_index =
+         (my - gi->selectbox.y - gi->border.ysize) / getFontHeight(gi->font);
+
+      if (gi->selectbox.current_index < 0)
+       gi->selectbox.current_index = 0;
+      else if (gi->selectbox.current_index > gi->selectbox.num_values - 1)
+       gi->selectbox.current_index = gi->selectbox.num_values - 1;
+
+      if (gi->selectbox.current_index != old_index)
+       DrawGadget(gi, DG_PRESSED, DG_DIRECT);
+    }
+    else
+    {
+      /* if mouse button pressed outside selectbox gadget, deactivate it */
+      DrawGadget(gi, DG_UNPRESSED, DG_DIRECT);
+
+      gi->event.type = GD_EVENT_TEXT_LEAVING;
+
+      if (gi->event_mask & GD_EVENT_TEXT_LEAVING)
+       gi->callback_action(gi);
+
+      last_gi = NULL;
+    }
+  }
+
   gadget_pressed =
     (button != 0 && last_gi == NULL && new_gi != NULL && press_event);
   gadget_pressed_repeated =
@@ -804,6 +1236,24 @@ void HandleGadgets(int mx, int my, int button)
   gadget_moving_inside =      (gadget_moving && new_gi == last_gi);
   gadget_moving_off_borders = (gadget_moving && new_gi != last_gi);
 
+  /* when handling selectbox, set additional state values */
+  if (gadget_released_inside && (last_gi->type & GD_TYPE_SELECTBOX))
+  {
+    struct GadgetInfo *gi = last_gi;
+
+    gadget_released_inside_select_line =
+      (mx >= gi->x && mx < gi->x + gi->width &&
+       my >= gi->y && my < gi->y + gi->height);
+    gadget_released_inside_select_area =
+      (mx >= gi->selectbox.x && mx < gi->selectbox.x + gi->selectbox.width &&
+       my >= gi->selectbox.y && my < gi->selectbox.y + gi->selectbox.height);
+  }
+  else
+  {
+    gadget_released_inside_select_line = FALSE;
+    gadget_released_inside_select_area = FALSE;
+  }
+
   /* if new gadget pressed, store this gadget  */
   if (gadget_pressed)
     last_gi = new_gi;
@@ -817,14 +1267,21 @@ void HandleGadgets(int mx, int my, int button)
       (gi->type == GD_TYPE_SCROLLBAR_HORIZONTAL ? mx - gi->x : my - gi->y);
 
   /* if mouse button released, no gadget needs to be handled anymore */
-  if (button == 0 && last_gi && !(last_gi->type & GD_TYPE_TEXTINPUT))
-    last_gi = NULL;
+  if (gadget_released)
+  {
+    if ((last_gi->type & GD_TYPE_SELECTBOX) &&
+       (gadget_released_inside_select_line ||
+        gadget_released_off_borders))              /* selectbox stays open */
+      gi->selectbox.stay_open = TRUE;
+    else if (!(last_gi->type & GD_TYPE_TEXTINPUT))  /* text input stays open */
+      last_gi = NULL;
+  }
 
   /* modify event position values even if no gadget is pressed */
   if (button == 0 && !release_event)
     gi = new_gi;
 
-  if (gi)
+  if (gi != NULL)
   {
     int last_x = gi->event.x;
     int last_y = gi->event.y;
@@ -840,6 +1297,23 @@ void HandleGadgets(int mx, int my, int button)
       if (last_x != gi->event.x || last_y != gi->event.y)
        changed_position = TRUE;
     }
+    else if (gi->type & GD_TYPE_SELECTBOX)
+    {
+      int old_index = gi->selectbox.current_index;
+
+      /* if mouse moving inside activated selectbox, select value */
+      if (my >= gi->selectbox.y && my < gi->selectbox.y + gi->selectbox.height)
+       gi->selectbox.current_index =
+         (my - gi->selectbox.y - gi->border.ysize) / getFontHeight(gi->font);
+
+      if (gi->selectbox.current_index < 0)
+       gi->selectbox.current_index = 0;
+      else if (gi->selectbox.current_index > gi->selectbox.num_values - 1)
+       gi->selectbox.current_index = gi->selectbox.num_values - 1;
+
+      if (gi->selectbox.current_index != old_index)
+       DrawGadget(gi, DG_PRESSED, DG_DIRECT);
+    }
   }
 
   /* handle gadget popup info text */
@@ -989,8 +1463,24 @@ void HandleGadgets(int mx, int my, int button)
       else if (gadget_moving_off_borders && gi->state == GD_BUTTON_PRESSED)
        DrawGadget(gi, DG_UNPRESSED, DG_DIRECT);
     }
+    else if (gi->type & GD_TYPE_SELECTBOX)
+    {
+      int old_index = gi->selectbox.current_index;
 
-    if (gi->type & GD_TYPE_SCROLLBAR)
+      /* if mouse moving inside activated selectbox, select value */
+      if (my >= gi->selectbox.y && my < gi->selectbox.y + gi->selectbox.height)
+       gi->selectbox.current_index =
+         (my - gi->selectbox.y - gi->border.ysize) / getFontHeight(gi->font);
+
+      if (gi->selectbox.current_index < 0)
+       gi->selectbox.current_index = 0;
+      else if (gi->selectbox.current_index > gi->selectbox.num_values - 1)
+       gi->selectbox.current_index = gi->selectbox.num_values - 1;
+
+      if (gi->selectbox.current_index != old_index)
+       DrawGadget(gi, DG_PRESSED, DG_DIRECT);
+    }
+    else if (gi->type & GD_TYPE_SCROLLBAR)
     {
       struct GadgetScrollbar *gs = &gi->scrollbar;
       int old_item_position = gs->item_position;
@@ -1031,13 +1521,25 @@ void HandleGadgets(int mx, int my, int button)
 
   if (gadget_released_inside)
   {
-    if (!(gi->type & GD_TYPE_TEXTINPUT))
+    boolean deactivate_gadget = TRUE;
+
+    if (gi->type & GD_TYPE_SELECTBOX)
+    {
+      if (gadget_released_inside_select_line ||
+         gadget_released_off_borders)              /* selectbox stays open */
+       deactivate_gadget = FALSE;
+      else
+       gi->selectbox.index = gi->selectbox.current_index;
+    }
+
+    if (deactivate_gadget &&
+       !(gi->type & GD_TYPE_TEXTINPUT))            /* text input stays open */
       DrawGadget(gi, DG_UNPRESSED, DG_DIRECT);
 
     gi->state = GD_BUTTON_UNPRESSED;
     gi->event.type = GD_EVENT_RELEASED;
 
-    if (gi->event_mask & GD_EVENT_RELEASED)
+    if ((gi->event_mask & GD_EVENT_RELEASED) && deactivate_gadget)
       gi->callback_action(gi);
   }
 
@@ -1052,61 +1554,27 @@ void HandleGadgets(int mx, int my, int button)
        gi->event_mask & GD_EVENT_OFF_BORDERS)
       gi->callback_action(gi);
   }
+
+  /* handle gadgets unmapped/mapped between pressing and releasing */
+  if (release_event && !gadget_released && new_gi)
+    new_gi->state = GD_BUTTON_UNPRESSED;
 }
 
 void HandleGadgetsKeyInput(Key key)
 {
   struct GadgetInfo *gi = last_gi;
-  char text[MAX_GADGET_TEXTSIZE];
-  int text_length;
-  int cursor_pos;
-  char letter;
-  boolean legal_letter;
 
-  if (gi == NULL || !(gi->type & GD_TYPE_TEXTINPUT) || !gi->mapped)
+  if (gi == NULL || !gi->mapped ||
+      !((gi->type & GD_TYPE_TEXTINPUT) || (gi->type & GD_TYPE_SELECTBOX)))
     return;
 
-  text_length = strlen(gi->text.value);
-  cursor_pos = gi->text.cursor_position;
-  letter = getCharFromKey(key);
-  legal_letter = (gi->type == GD_TYPE_TEXTINPUT_NUMERIC ?
-                 letter >= '0' && letter <= '9' :
-                 letter != 0);
-
-  if (legal_letter && text_length < gi->text.size)
+  if (key == KSYM_Return)      /* valid for both text input and selectbox */
   {
-    strcpy(text, gi->text.value);
-    strcpy(&gi->text.value[cursor_pos + 1], &text[cursor_pos]);
-    gi->text.value[cursor_pos] = letter;
-    gi->text.cursor_position++;
-    DrawGadget(gi, DG_PRESSED, DG_DIRECT);
-  }
-  else if (key == KSYM_Left && cursor_pos > 0)
-  {
-    gi->text.cursor_position--;
-    DrawGadget(gi, DG_PRESSED, DG_DIRECT);
-  }
-  else if (key == KSYM_Right && cursor_pos < text_length)
-  {
-    gi->text.cursor_position++;
-    DrawGadget(gi, DG_PRESSED, DG_DIRECT);
-  }
-  else if (key == KSYM_BackSpace && cursor_pos > 0)
-  {
-    strcpy(text, gi->text.value);
-    strcpy(&gi->text.value[cursor_pos - 1], &text[cursor_pos]);
-    gi->text.cursor_position--;
-    DrawGadget(gi, DG_PRESSED, DG_DIRECT);
-  }
-  else if (key == KSYM_Delete && cursor_pos < text_length)
-  {
-    strcpy(text, gi->text.value);
-    strcpy(&gi->text.value[cursor_pos], &text[cursor_pos + 1]);
-    DrawGadget(gi, DG_PRESSED, DG_DIRECT);
-  }
-  else if (key == KSYM_Return)
-  {
-    CheckRangeOfNumericInputGadget(gi);
+    if (gi->type & GD_TYPE_TEXTINPUT)
+      CheckRangeOfNumericInputGadget(gi);
+    else if (gi->type & GD_TYPE_SELECTBOX)
+      gi->selectbox.index = gi->selectbox.current_index;
+
     DrawGadget(gi, DG_UNPRESSED, DG_DIRECT);
 
     gi->event.type = GD_EVENT_TEXT_RETURN;
@@ -1116,4 +1584,63 @@ void HandleGadgetsKeyInput(Key key)
 
     last_gi = NULL;
   }
+  else if (gi->type & GD_TYPE_TEXTINPUT)       /* only valid for text input */
+  {
+    char text[MAX_GADGET_TEXTSIZE];
+    int text_length = strlen(gi->text.value);
+    int cursor_pos = gi->text.cursor_position;
+    char letter = getCharFromKey(key);
+    boolean legal_letter = (gi->type == GD_TYPE_TEXTINPUT_NUMERIC ?
+                           letter >= '0' && letter <= '9' :
+                           letter != 0);
+
+    if (legal_letter && text_length < gi->text.size)
+    {
+      strcpy(text, gi->text.value);
+      strcpy(&gi->text.value[cursor_pos + 1], &text[cursor_pos]);
+      gi->text.value[cursor_pos] = letter;
+      gi->text.cursor_position++;
+
+      DrawGadget(gi, DG_PRESSED, DG_DIRECT);
+    }
+    else if (key == KSYM_Left && cursor_pos > 0)
+    {
+      gi->text.cursor_position--;
+      DrawGadget(gi, DG_PRESSED, DG_DIRECT);
+    }
+    else if (key == KSYM_Right && cursor_pos < text_length)
+    {
+      gi->text.cursor_position++;
+      DrawGadget(gi, DG_PRESSED, DG_DIRECT);
+    }
+    else if (key == KSYM_BackSpace && cursor_pos > 0)
+    {
+      strcpy(text, gi->text.value);
+      strcpy(&gi->text.value[cursor_pos - 1], &text[cursor_pos]);
+      gi->text.cursor_position--;
+      DrawGadget(gi, DG_PRESSED, DG_DIRECT);
+    }
+    else if (key == KSYM_Delete && cursor_pos < text_length)
+    {
+      strcpy(text, gi->text.value);
+      strcpy(&gi->text.value[cursor_pos], &text[cursor_pos + 1]);
+      DrawGadget(gi, DG_PRESSED, DG_DIRECT);
+    }
+  }
+  else if (gi->type & GD_TYPE_SELECTBOX)       /* only valid for selectbox */
+  {
+    int index = gi->selectbox.current_index;
+    int num_values = gi->selectbox.num_values;
+
+    if (key == KSYM_Up && index > 0)
+    {
+      gi->selectbox.current_index--;
+      DrawGadget(gi, DG_PRESSED, DG_DIRECT);
+    }
+    else if (key == KSYM_Down && index < num_values - 1)
+    {
+      gi->selectbox.current_index++;
+      DrawGadget(gi, DG_PRESSED, DG_DIRECT);
+    }
+  }
 }
index 783e454f0a23f58bbe8a7ef30e2574dafd528957..0bf8cc5a53ca322c81d5afb90d45a4e3ef71c7bd 100644 (file)
 
 /* gadget types */
 #define GD_TYPE_NORMAL_BUTTON          (1 << 0)
-#define GD_TYPE_CHECK_BUTTON           (1 << 1)
-#define GD_TYPE_RADIO_BUTTON           (1 << 2)
-#define GD_TYPE_DRAWING_AREA           (1 << 3)
-#define GD_TYPE_TEXTINPUT_ALPHANUMERIC (1 << 4)
-#define GD_TYPE_TEXTINPUT_NUMERIC      (1 << 5)
-#define GD_TYPE_SCROLLBAR_VERTICAL     (1 << 6)
-#define GD_TYPE_SCROLLBAR_HORIZONTAL   (1 << 7)
+#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_TEXTINPUT_ALPHANUMERIC (1 << 5)
+#define GD_TYPE_TEXTINPUT_NUMERIC      (1 << 6)
+#define GD_TYPE_SELECTBOX              (1 << 7)
+#define GD_TYPE_SCROLLBAR_VERTICAL     (1 << 8)
+#define GD_TYPE_SCROLLBAR_HORIZONTAL   (1 << 9)
 
 #define GD_TYPE_BUTTON                 (GD_TYPE_NORMAL_BUTTON | \
+                                        GD_TYPE_TEXT_BUTTON | \
                                         GD_TYPE_CHECK_BUTTON | \
                                         GD_TYPE_RADIO_BUTTON)
 #define GD_TYPE_SCROLLBAR              (GD_TYPE_SCROLLBAR_VERTICAL | \
 #define GDI_TEXT_VALUE                 14
 #define GDI_TEXT_SIZE                  15
 #define GDI_TEXT_FONT                  16
-#define GDI_DESIGN_UNPRESSED           17
-#define GDI_DESIGN_PRESSED             18
-#define GDI_ALT_DESIGN_UNPRESSED       19
-#define GDI_ALT_DESIGN_PRESSED         20
-#define GDI_BORDER_SIZE                        21
-#define GDI_TEXTINPUT_DESIGN_WIDTH     22
-#define GDI_DECORATION_DESIGN          23
-#define GDI_DECORATION_POSITION                24
-#define GDI_DECORATION_SIZE            25
-#define GDI_DECORATION_SHIFTING                26
-#define GDI_EVENT_MASK                 27
-#define GDI_EVENT                      28
-#define GDI_CALLBACK_INFO              29
-#define GDI_CALLBACK_ACTION            30
-#define GDI_AREA_SIZE                  31
-#define GDI_ITEM_SIZE                  32
-#define GDI_SCROLLBAR_ITEMS_MAX                33
-#define GDI_SCROLLBAR_ITEMS_VISIBLE    34
-#define GDI_SCROLLBAR_ITEM_POSITION    35
-#define GDI_INFO_TEXT                  36
+#define GDI_TEXT_FONT_ACTIVE           17
+#define GDI_SELECTBOX_OPTIONS          18
+#define GDI_SELECTBOX_INDEX            19
+#define GDI_DESIGN_UNPRESSED           20
+#define GDI_DESIGN_PRESSED             21
+#define GDI_ALT_DESIGN_UNPRESSED       22
+#define GDI_ALT_DESIGN_PRESSED         23
+#define GDI_BORDER_SIZE                        24
+#define GDI_BORDER_SIZE_SELECTBUTTON   25
+#define GDI_DESIGN_WIDTH               26
+#define GDI_DECORATION_DESIGN          27
+#define GDI_DECORATION_POSITION                28
+#define GDI_DECORATION_SIZE            29
+#define GDI_DECORATION_SHIFTING                30
+#define GDI_EVENT_MASK                 31
+#define GDI_EVENT                      32
+#define GDI_CALLBACK_INFO              33
+#define GDI_CALLBACK_ACTION            34
+#define GDI_AREA_SIZE                  35
+#define GDI_ITEM_SIZE                  36
+#define GDI_SCROLLBAR_ITEMS_MAX                37
+#define GDI_SCROLLBAR_ITEMS_VISIBLE    38
+#define GDI_SCROLLBAR_ITEM_POSITION    39
+#define GDI_INFO_TEXT                  40
+#define GDI_ACTIVE                     41
 
 typedef void (*gadget_function)(void *);
 
 struct GadgetBorder
 {
-  int size;                            /* size of gadget border */
-  int width;                           /* for text input gadgets */
+  int xsize, ysize;                    /* size of gadget border */
+  int xsize_selectbutton;              /* for selectbox gadgets */
+  int width;                           /* for selectbox/text input gadgets */
 };
 
 struct GadgetDesign
@@ -132,15 +141,38 @@ struct GadgetDrawingArea
   int item_xsize, item_ysize;          /* size of each item in drawing area */
 };
 
+struct GadgetTextButton
+{
+  char value[MAX_GADGET_TEXTSIZE];     /* text written on the button */
+  int size;                            /* maximal size of button text */
+};
+
 struct GadgetTextInput
 {
   char value[MAX_GADGET_TEXTSIZE];     /* text string in input field */
+  int cursor_position;                 /* actual text cursor position */
   int number_value;                    /* integer value, if numeric */
   int number_min;                      /* minimal allowed numeric value */
   int number_max;                      /* maximal allowed numeric value */
   int size;                            /* maximal size of input text */
-  int cursor_position;                 /* actual cursor position */
-  int font_type;                       /* font to use for text input */
+};
+
+struct GadgetSelectbox
+{
+  struct ValueTextInfo *options;       /* pointer to text/value array */
+  int index;                           /* index of actual text string */
+  int size;                            /* maximal size of text strings */
+
+  /* automatically determined values */
+  int x, y;                            /* open selectbox position */
+  int width, height;                   /* open selectbox size */
+  int num_values;                      /* number of text strings */
+  Pixel inverse_color;                 /* color for highlighting */
+
+  /* runtime values */
+  boolean open;                                /* opening state of selectbox */
+  boolean stay_open;                   /* open after button release */
+  int current_index;                   /* index of text while selecting */
 };
 
 struct GadgetScrollbar
@@ -168,7 +200,10 @@ struct GadgetInfo
   unsigned long state;                 /* state (pressed, released, ...) */
   boolean checked;                     /* check/radio button state */
   int radio_nr;                                /* number of radio button series */
-  boolean mapped;                      /* gadget is active */
+  boolean mapped;                      /* gadget is mapped on the screen */
+  boolean active;                      /* gadget is active */
+  int font;                            /* font to use when inactive */
+  int font_active;                     /* font to use when active */
   struct GadgetBorder border;          /* gadget border design */
   struct GadgetDesign design[2];       /* 0: normal; 1: pressed */
   struct GadgetDesign alt_design[2];   /* alternative design */
@@ -178,7 +213,9 @@ struct GadgetInfo
   gadget_function callback_info;       /* function for pop-up info text */
   gadget_function callback_action;     /* function for gadget action */
   struct GadgetDrawingArea drawing;    /* fields for drawing area gadget */
+  struct GadgetTextButton textbutton;  /* fields for text button gadget */
   struct GadgetTextInput text;         /* fields for text input gadget */
+  struct GadgetSelectbox selectbox;    /* fields for selectbox gadget */
   struct GadgetScrollbar scrollbar;    /* fields for scrollbar gadget */
   struct GadgetInfo *next;             /* next list entry */
 };
diff --git a/src/libgame/hash.c b/src/libgame/hash.c
new file mode 100644 (file)
index 0000000..805190b
--- /dev/null
@@ -0,0 +1,366 @@
+/***********************************************************
+* Artsoft Retro-Game Library                               *
+*----------------------------------------------------------*
+* (c) 1994-2003 Artsoft Entertainment                      *
+*               Holger Schemel                             *
+*               Detmolder Strasse 189                      *
+*               33604 Bielefeld                            *
+*               Germany                                    *
+*               e-mail: info@artsoft.org                   *
+*----------------------------------------------------------*
+* hash.c                                                   *
+***********************************************************/
+
+/*
+ * Copyright (C) 2002 Christopher Clark <firstname.lastname@cl.cam.ac.uk>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies of the Software and its documentation and acknowledgment shall be
+ * given in the documentation and software packages that this Software was
+ * used.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
+ * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ * */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+#include "hash.h"
+
+
+/*****************************************************************************/
+struct hashtable *
+create_hashtable(unsigned int minsize, float maxloadfactor,
+                 unsigned int (*hashf) (void*),
+                 int (*eqf) (void*,void*))
+{
+    struct hashtable *h;
+    unsigned int i, size = 1u;
+    /* Check requested hashtable isn't too large */
+    if (minsize > (1u << 31)) return NULL;
+    /* Enforce size as power of 2 */
+    while (size < minsize) size <<= 1;
+    h = (struct hashtable *)malloc(sizeof(struct hashtable));
+    if (NULL == h) return NULL; /*oom*/
+    h->table = (struct entry **)malloc(sizeof(struct entry*) * size);
+    if (NULL == h->table) { free(h); return NULL; } /*oom*/
+
+    for (i=0;i<size;i++) { h->table[i] = NULL; }
+    h->tablelength  = size;
+    h->entrycount   = 0;
+    h->hashfn       = hashf;
+    h->eqfn         = eqf;
+    h->loadlimit    = (unsigned int) ((float)size * maxloadfactor);
+    return h;
+}
+
+/*****************************************************************************/
+static unsigned int
+hash(struct hashtable *h, void *k)
+{
+    /* Aim to protect against poor hash functions by adding logic here
+     * - logic taken from java 1.4 hashtable source */
+    unsigned int i = h->hashfn(k);
+    i += ~(i << 9);
+    i ^=  ((i >> 14) | (i << 18)); /* >>> */
+    i +=  (i << 4);
+    i ^=  ((i >> 10) | (i << 22)); /* >>> */
+    return i;
+}
+/*****************************************************************************/
+static unsigned int
+indexFor(unsigned int tablelength, unsigned int hashvalue)
+{
+    /* Only works if tablelength == 2^N */
+    return (hashvalue & (tablelength - 1u));
+}
+
+/*****************************************************************************/
+static int
+hashtable_expand(struct hashtable *h)
+{
+    /* Double the size of the table to accomodate more entries */
+    struct entry **newtable;
+    struct entry *e;
+    struct entry **pE;
+    unsigned int newsize, i, index;
+    /* Check we're not hitting max capacity */
+    if (0 == (newsize = (h->tablelength << 1))) return 0;
+
+    newtable = (struct entry **)malloc(sizeof(struct entry*) * newsize);
+    if (NULL != newtable)
+    {
+        memset(newtable, 0, newsize * sizeof(struct entry *));
+        /* This algorithm is not 'stable'. ie. it reverses the list
+         * when it transfers entries between the tables */
+        for (i = 0; i < h->tablelength; i++) {
+            while (NULL != (e = h->table[i])) {
+                h->table[i] = e->next;
+                index = indexFor(newsize,e->h);
+                e->next = newtable[index];
+                newtable[index] = e;
+            }
+        }
+        free(h->table);
+        h->table = newtable;
+    }
+    /* Plan B: realloc instead */
+    else 
+    {
+        newtable = (struct entry **)
+                   realloc(h->table, newsize * sizeof(struct entry *));
+        if (NULL == newtable) return 0;
+        h->table = newtable;
+        for (i = h->tablelength; i < newsize; i++) {
+            newtable[i] = NULL;
+        }
+        for (i = 0; i < h->tablelength; i++) {
+            for (pE = &(newtable[i]), e = *pE; e != NULL; e = *pE) {
+                index = indexFor(newsize,e->h);
+                if (index == i)
+                {
+                    pE = &(e->next);
+                }
+                else
+                {
+                    *pE = e->next;
+                    e->next = newtable[index];
+                    newtable[index] = e;
+                }
+            }
+        }
+    }
+    h->tablelength = newsize;
+    h->loadlimit <<= 1;
+    return -1;
+}
+
+/*****************************************************************************/
+unsigned int
+hashtable_count(struct hashtable *h)
+{
+    return h->entrycount;
+}
+
+/*****************************************************************************/
+int
+hashtable_insert(struct hashtable *h, void *k, void *v)
+{
+    /* This method allows duplicate keys - but they shouldn't be used */
+    unsigned int index;
+    struct entry *e;
+    if (++(h->entrycount) > h->loadlimit)
+    {
+        /* Ignore the return value. If expand fails, we should
+         * still try cramming just this value into the existing table
+         * -- we may not have memory for a larger table, but one more
+         * element may be ok. Next time we insert, we'll try expanding again.*/
+        hashtable_expand(h);
+    }
+    e = (struct entry *)malloc(sizeof(struct entry));
+    if (NULL == e) { --(h->entrycount); return 0; } /*oom*/
+    e->h = hash(h,k);
+    index = indexFor(h->tablelength,e->h);
+    e->k = k;
+    e->v = v;
+    e->next = h->table[index];
+    h->table[index] = e;
+    return -1;
+}
+
+/*****************************************************************************/
+int
+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);
+    e = h->table[index];
+    while (NULL != e)
+    {
+        /* Check hash value to short circuit heavier comparison */
+        if ((hashvalue == e->h) && (h->eqfn(k, e->k)))
+       {
+           free(e->v);
+           e->v = v;
+           return -1;
+       }
+        e = e->next;
+    }
+    return 0;
+}
+
+/*****************************************************************************/
+void * /* returns value associated with key */
+hashtable_search(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 (NULL != e)
+    {
+        /* Check hash value to short circuit heavier comparison */
+        if ((hashvalue == e->h) && (h->eqfn(k, e->k))) return e->v;
+        e = e->next;
+    }
+    return NULL;
+}
+
+/*****************************************************************************/
+void * /* returns value associated with key */
+hashtable_remove(struct hashtable *h, void *k)
+{
+    /* TODO: consider compacting the table when the load factor drops enough,
+     *       or provide a 'compact' method. */
+
+    struct entry *e;
+    struct entry **pE;
+    void *v;
+
+    unsigned int index = indexFor(h->tablelength,hash(h,k));
+    pE = &(h->table[index]);
+    e = *pE;
+    while (NULL != e)
+    {
+        if (h->eqfn(k, e->k))
+        {
+            *pE = e->next;
+            h->entrycount--;
+            v = e->v;
+            free(e->k);
+            free(e);
+            return v;
+        }
+        pE = &(e->next);
+        e = e->next;
+    }
+    return NULL;
+}
+
+/*****************************************************************************/
+/* destroy */
+void
+hashtable_destroy(struct hashtable *h, int free_values)
+{
+    unsigned int i;
+    struct entry *e, *f;
+    struct entry **table = h->table;
+
+    for (i = 0; i < h->tablelength; i++)
+    {
+        e = table[i];
+        while (NULL != e)
+       {
+           f = e;
+           e = e->next;
+           free(f->k);
+           if (free_values)
+               free(f->v);
+           free(f);
+       }
+    }
+
+    free(h->table);
+    free(h);
+}
+
+
+/*****************************************************************************/
+/* hashtable_iterator    - iterator constructor */
+
+struct hashtable_itr *
+hashtable_iterator(struct hashtable *h)
+{
+    unsigned int i, tablelength;
+    struct hashtable_itr *itr = (struct hashtable_itr *)
+        malloc(sizeof(struct hashtable_itr));
+    if (NULL == itr) return NULL;
+    itr->h = h;
+    itr->e = NULL;
+    tablelength = h->tablelength;
+    itr->index = tablelength;
+    if (0 == h->entrycount) return itr;
+
+    for (i = 0; i < tablelength; i++)
+    {
+        if (NULL != h->table[i])
+        {
+            itr->e = h->table[i];
+            itr->index = i;
+            break;
+        }
+    }
+    return itr;
+}
+
+/*****************************************************************************/
+/* key - return the key of the (key,value) pair at the current position */
+
+void *
+hashtable_iterator_key(struct hashtable_itr *i)
+{
+    return i->e->k;
+}
+
+/*****************************************************************************/
+/* value - return the value of the (key,value) pair at the current position */
+
+void *
+hashtable_iterator_value(struct hashtable_itr *i)
+{
+    return i->e->v;
+}
+
+/*****************************************************************************/
+/* advance - advance the iterator to the next element
+ *           returns zero if advanced to end of table */
+
+int
+hashtable_iterator_advance(struct hashtable_itr *itr)
+{
+    unsigned int j,tablelength;
+    struct entry **table;
+    struct entry *next;
+    if (NULL == itr->e) return 0; /* stupidity check */
+
+    next = itr->e->next;
+    if (NULL != next)
+    {
+        itr->e = next;
+        return -1;
+    }
+    tablelength = itr->h->tablelength;
+    if (tablelength <= (j = ++(itr->index)))
+    {
+        itr->e = NULL;
+        return 0;
+    }
+    table = itr->h->table;
+    while (NULL == (next = table[j]))
+    {
+        if (++j >= tablelength)
+        {
+            itr->index = tablelength;
+            return 0;
+        }
+    }
+    itr->index = j;
+    itr->e = next;
+    return -1;
+}
diff --git a/src/libgame/hash.h b/src/libgame/hash.h
new file mode 100644 (file)
index 0000000..4be5cc8
--- /dev/null
@@ -0,0 +1,278 @@
+/***********************************************************
+* Artsoft Retro-Game Library                               *
+*----------------------------------------------------------*
+* (c) 1994-2003 Artsoft Entertainment                      *
+*               Holger Schemel                             *
+*               Detmolder Strasse 189                      *
+*               33604 Bielefeld                            *
+*               Germany                                    *
+*               e-mail: info@artsoft.org                   *
+*----------------------------------------------------------*
+* hash.h                                                   *
+***********************************************************/
+
+/*
+ * Copyright (C) 2002 Christopher Clark <firstname.lastname@cl.cam.ac.uk>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies of the Software and its documentation and acknowledgment shall be
+ * given in the documentation and software packages that this Software was
+ * used.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
+ * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ * */
+
+#ifndef HASH_H
+#define HASH_H
+
+
+/* Example of use:
+ *
+ *      struct hashtable  *h;
+ *      struct some_key   *k;
+ *      struct some_value *v;
+ *
+ *      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);
+ *      k = (struct some_key *)     malloc(sizeof(struct some_key));
+ *      v = (struct some_value *)   malloc(sizeof(struct some_value));
+ *
+ *      (initialise k and v to suitable values)
+ * 
+ *      if (! hashtable_insert(h,k,v) )
+ *      {     exit(-1);               }
+ *
+ *      if (NULL == (found = hashtable_search(h,k) ))
+ *      {    printf("not found!");                  }
+ *
+ *      if (NULL == (found = hashtable_remove(h,k) ))
+ *      {    printf("Not found\n");                 }
+ *
+ */
+
+/* Macros may be used to define type-safe(r) hashtable access functions, with
+ * methods specialized to take known key and value types as parameters.
+ * 
+ * Example:
+ *
+ * Insert this at the start of your file:
+ *
+ * DEFINE_HASHTABLE_INSERT(insert_some, struct some_key, struct some_value);
+ * DEFINE_HASHTABLE_SEARCH(search_some, struct some_key, struct some_value);
+ * DEFINE_HASHTABLE_REMOVE(remove_some, struct some_key, struct some_value);
+ *
+ * This defines the functions 'insert_some', 'search_some' and 'remove_some'.
+ * These operate just like hashtable_insert etc., with the same parameters,
+ * but their function signatures have 'struct some_key *' rather than
+ * 'void *', and hence can generate compile time errors if your program is
+ * supplying incorrect data as a key (and similarly for value).
+ *
+ * Note that the hash and key equality functions passed to create_hashtable
+ * still take 'void *' parameters instead of 'some key *'. This shouldn't be
+ * a difficult issue as they're only defined and passed once, and the other
+ * functions will ensure that only valid keys are supplied to them.
+ *
+ * The cost for this checking is increased code size and runtime overhead
+ * - if performance is important, it may be worth switching back to the
+ * unsafe methods once your program has been debugged with the safe methods.
+ * This just requires switching to some simple alternative defines - eg:
+ * #define insert_some hashtable_insert
+ *
+ */
+
+
+/*****************************************************************************/
+struct entry
+{
+    void *k, *v;
+    unsigned int h;
+    struct entry *next;
+};
+
+struct hashtable {
+    unsigned int tablelength;
+    struct entry **table;
+    unsigned int entrycount;
+    unsigned int loadlimit;
+    unsigned int (*hashfn) (void *k);
+    int (*eqfn) (void *k1, void *k2);
+};
+
+/*****************************************************************************/
+struct hashtable_itr
+{
+    struct hashtable *h;
+    struct entry *e;
+    unsigned int index;
+};
+
+
+/*****************************************************************************
+ * create_hashtable
+   
+ * @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
+ * @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*));
+
+/*****************************************************************************
+ * 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
+ * @return      non-zero for successful insertion
+ *
+ * This function will cause the table to expand if the insertion would take
+ * the ratio of entries to table size over the maximum load factor.
+ *
+ * This function does not check for repeated insertions with a duplicate key.
+ * The value returned when using a duplicate key is undefined -- when
+ * the hashtable changes size, the order of retrieval of duplicate key
+ * entries is reversed.
+ * If in doubt, remove before insert.
+ */
+
+int 
+hashtable_insert(struct hashtable *h, void *k, void *v);
+
+#define DEFINE_HASHTABLE_INSERT(fnname, keytype, valuetype) \
+int fnname (struct hashtable *h, keytype *k, valuetype *v) \
+{ \
+    return hashtable_insert(h,k,v); \
+}
+
+/*****************************************************************************
+ * hashtable_change
+   
+ * @name        hashtable_change
+ * @param   h   the hashtable to search
+ * @param   k   the key of the entry to change
+ * @param   v   the new value
+ * @return      non-zero for successful change
+ */
+
+int 
+hashtable_change(struct hashtable *h, void *k, void *v);
+
+#define DEFINE_HASHTABLE_CHANGE(fnname, keytype, valuetype) \
+int fnname (struct hashtable *h, keytype *k, valuetype *v) \
+{ \
+    return hashtable_change(h,k,v); \
+}
+
+/*****************************************************************************
+ * hashtable_search
+   
+ * @name        hashtable_search
+ * @param   h   the hashtable to search
+ * @param   k   the key to search for  - does not claim ownership
+ * @return      the value associated with the key, or NULL if none found
+ */
+
+void *
+hashtable_search(struct hashtable *h, void *k);
+
+#define DEFINE_HASHTABLE_SEARCH(fnname, keytype, valuetype) \
+valuetype * fnname (struct hashtable *h, keytype *k) \
+{ \
+    return (valuetype *) (hashtable_search(h,k)); \
+}
+
+/*****************************************************************************
+ * hashtable_remove
+   
+ * @name        hashtable_remove
+ * @param   h   the hashtable to remove the item from
+ * @param   k   the key to search for  - does not claim ownership
+ * @return      the value associated with the key, or NULL if none found
+ */
+
+void * /* returns value */
+hashtable_remove(struct hashtable *h, void *k);
+
+#define DEFINE_HASHTABLE_REMOVE(fnname, keytype, valuetype) \
+valuetype * fnname (struct hashtable *h, keytype *k) \
+{ \
+    return (valuetype *) (hashtable_remove(h,k)); \
+}
+
+
+/*****************************************************************************
+ * hashtable_count
+   
+ * @name        hashtable_count
+ * @return      the number of items stored in the hashtable
+ */
+unsigned int
+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_iterator
+ */
+
+struct hashtable_itr *
+hashtable_iterator(struct hashtable *h);
+
+/*****************************************************************************/
+/* hashtable_iterator_key
+ * - return the value of the (key,value) pair at the current position */
+
+extern inline void *
+hashtable_iterator_key(struct hashtable_itr *i)
+{
+    return i->e->k;
+}
+
+/*****************************************************************************/
+/* value - return the value of the (key,value) pair at the current position */
+
+extern inline void *
+hashtable_iterator_value(struct hashtable_itr *i)
+{
+    return i->e->v;
+}
+
+/*****************************************************************************/
+/* advance - advance the iterator to the next element
+ *           returns zero if advanced to end of table */
+
+int
+hashtable_iterator_advance(struct hashtable_itr *itr);
+
+#endif
index 8299ad2b400e1ec20907442d04f575582d9ac830..f06a126ec6171fbcdc74014af811cc39c79ca202 100644 (file)
 #include "image.h"
 #include "pcx.h"
 #include "misc.h"
+#include "setup.h"
 
 
+/* ========================================================================= */
+/* PLATFORM SPECIFIC IMAGE FUNCTIONS                                         */
+/* ========================================================================= */
+
 #if defined(TARGET_X11)
 
 /* for MS-DOS/Allegro, exclude all except newImage() and freeImage() */
@@ -33,8 +38,8 @@ Image *newImage(unsigned int width, unsigned int height, unsigned int depth)
   depth = 8;
 #endif
 
-  image = checked_malloc(sizeof(Image));
-  image->data = checked_malloc(width * height * bytes_per_pixel);
+  image = checked_calloc(sizeof(Image));
+  image->data = checked_calloc(width * height * bytes_per_pixel);
   image->width = width;
   image->height = height;
   image->depth = depth;
@@ -438,8 +443,8 @@ XImageInfo *Image_to_Pixmap(Display *display, int screen, Visual *visual,
   display_bits_per_pixel = bitsPerPixelAtDepth(display, screen, depth);
   display_bytes_per_pixel = (display_bits_per_pixel + 7) / 8;
 
-  ximage = XCreateImage(display, visual, depth, ZPixmap, 0,
-                       NULL, image->width, image->height,
+  ximage = XCreateImage(display, visual, depth, ZPixmap,
+                       0, NULL, image->width, image->height,
                        8, image->width * display_bytes_per_pixel);
   ximage->data =
     checked_malloc(image->width * image->height * display_bytes_per_pixel);
@@ -560,6 +565,66 @@ XImageInfo *Image_to_Pixmap(Display *display, int screen, Visual *visual,
   return ximageinfo;
 }
 
+/*
+  -----------------------------------------------------------------------------
+  ZoomPixmap
+
+  Important note: The scaling code currently only supports scaling down the
+  image by a power of 2 -- scaling up is currently not supported at all!
+  -----------------------------------------------------------------------------
+*/
+
+void ZoomPixmap(Display *display, GC gc, Pixmap src_pixmap, Pixmap dst_pixmap,
+               int src_width, int src_height,
+               int dst_width, int dst_height)
+{
+  XImage *src_ximage, *dst_ximage;
+  byte *src_ptr, *dst_ptr;
+  int bits_per_pixel;
+  int bytes_per_pixel;
+  int x, y, i;
+  int zoom_factor = src_width / dst_width;     /* currently very limited! */
+  int row_skip, col_skip;
+
+  /* adjust source image size to integer multiple of destination image size */
+  src_width  = dst_width  * zoom_factor;
+  src_height = dst_height * zoom_factor;
+
+  /* copy source pixmap to temporary image */
+  src_ximage = XGetImage(display, src_pixmap, 0, 0, src_width, src_height,
+                        AllPlanes, ZPixmap);
+
+  bits_per_pixel = src_ximage->bits_per_pixel;
+  bytes_per_pixel = (bits_per_pixel + 7) / 8;
+
+  dst_ximage = XCreateImage(display, visual, src_ximage->depth, ZPixmap,
+                           0, NULL, dst_width, dst_height,
+                           8, dst_width * bytes_per_pixel);
+  dst_ximage->data =
+    checked_malloc(dst_width * dst_height * bytes_per_pixel);
+  dst_ximage->byte_order = src_ximage->byte_order;
+
+  src_ptr = (byte *)src_ximage->data;
+  dst_ptr = (byte *)dst_ximage->data;
+
+  col_skip = (zoom_factor - 1) * bytes_per_pixel;
+  row_skip = col_skip * src_width;
+
+  /* scale image down by scaling factor 'zoom_factor' */
+  for (y=0; y < src_height; y += zoom_factor, src_ptr += row_skip)
+    for (x=0; x < src_width; x += zoom_factor, src_ptr += col_skip)
+      for (i=0; i < bytes_per_pixel; i++)
+       *dst_ptr++ = *src_ptr++;
+
+  /* copy scaled image to destination pixmap */
+  XPutImage(display, dst_pixmap, gc, dst_ximage, 0, 0, 0, 0,
+           dst_width, dst_height);
+
+  /* free temporary images */
+  XDestroyImage(src_ximage);
+  XDestroyImage(dst_ximage);
+}
+
 void freeXImage(Image *image, XImageInfo *ximageinfo)
 {
   if (ximageinfo->index != NULL && ximageinfo->no > 0)
@@ -635,3 +700,252 @@ int Read_PCX_to_Pixmap(Display *display, Window window, GC gc, char *filename,
 
 #endif /* PLATFORM_UNIX */
 #endif /* TARGET_X11 */
+
+
+/* ========================================================================= */
+/* PLATFORM INDEPENDENT IMAGE FUNCTIONS                                      */
+/* ========================================================================= */
+
+struct ImageInfo
+{
+  char *source_filename;
+  int num_references;
+
+  Bitmap *bitmap;
+  boolean contains_small_images;
+};
+typedef struct ImageInfo ImageInfo;
+
+static struct ArtworkListInfo *image_info = NULL;
+
+static void *Load_PCX(char *filename)
+{
+  ImageInfo *img_info;
+
+#if 0
+  printf("loading PCX file '%s'\n", filename);
+#endif
+
+  img_info = checked_calloc(sizeof(ImageInfo));
+
+  if ((img_info->bitmap = LoadImage(filename)) == NULL)
+  {
+    Error(ERR_WARN, "cannot read image file '%s': LoadImage() failed: %s",
+         filename, GetError());
+    free(img_info);
+    return NULL;
+  }
+
+  img_info->source_filename = getStringCopy(filename);
+
+  img_info->contains_small_images = FALSE;
+
+  return img_info;
+}
+
+static void FreeImage(void *ptr)
+{
+  ImageInfo *image = (ImageInfo *)ptr;
+
+  if (image == NULL)
+    return;
+
+  if (image->bitmap)
+    FreeBitmap(image->bitmap);
+
+  if (image->source_filename)
+    free(image->source_filename);
+
+  free(image);
+}
+
+int getImageListSize()
+{
+  return (image_info->num_file_list_entries +
+         image_info->num_dynamic_file_list_entries);
+}
+
+struct FileInfo *getImageListEntry(int pos)
+{
+  int num_list_entries = image_info->num_file_list_entries;
+  int list_pos = (pos < num_list_entries ? pos : pos - num_list_entries);
+
+  return (pos < num_list_entries ? &image_info->file_list[list_pos] :
+         &image_info->dynamic_file_list[list_pos]);
+}
+
+static ImageInfo *getImageInfoEntryFromImageID(int pos)
+{
+  int num_list_entries = image_info->num_file_list_entries;
+  int list_pos = (pos < num_list_entries ? pos : pos - num_list_entries);
+  ImageInfo **img_info =
+    (ImageInfo **)(pos < num_list_entries ? image_info->artwork_list :
+                  image_info->dynamic_artwork_list);
+
+  return img_info[list_pos];
+}
+
+Bitmap *getBitmapFromImageID(int pos)
+{
+#if 0
+  int num_list_entries = image_info->num_file_list_entries;
+  int list_pos = (pos < num_list_entries ? pos : pos - num_list_entries);
+  ImageInfo **img_info =
+    (ImageInfo **)(pos < num_list_entries ? image_info->artwork_list :
+                  image_info->dynamic_artwork_list);
+
+  return (img_info[list_pos] != NULL ? img_info[list_pos]->bitmap : NULL);
+#else
+  ImageInfo *img_info = getImageInfoEntryFromImageID(pos);
+
+  return (img_info != NULL ? img_info->bitmap : NULL);
+#endif
+}
+
+char *getTokenFromImageID(int graphic)
+{
+#if 0
+  /* !!! this does not work for dynamic artwork (crash!) !!! */
+  struct FileInfo *file_list = (struct FileInfo *)image_info->file_list;
+
+  return file_list[graphic].token;
+#else
+  struct FileInfo *file_list = getImageListEntry(graphic);
+
+  return (file_list != NULL ? file_list->token : NULL);
+#endif
+}
+
+int getImageIDFromToken(char *token)
+{
+  struct FileInfo *file_list = image_info->file_list;
+  int num_list_entries = image_info->num_file_list_entries;
+  int i;
+
+  for (i=0; i < num_list_entries; i++)
+    if (strcmp(file_list[i].token, token) == 0)
+      return i;
+
+  return -1;
+}
+
+char *getImageConfigFilename()
+{
+  return getCustomArtworkConfigFilename(image_info->type);
+}
+
+int getImageListPropertyMappingSize()
+{
+  return image_info->num_property_mapping_entries;
+}
+
+struct PropertyMapping *getImageListPropertyMapping()
+{
+  return image_info->property_mapping;
+}
+
+void InitImageList(struct ConfigInfo *config_list, int num_file_list_entries,
+                  struct ConfigInfo *config_suffix_list,
+                  char **base_prefixes, char **ext1_suffixes,
+                  char **ext2_suffixes, char **ext3_suffixes,
+                  char **ignore_tokens)
+{
+  int i;
+
+  image_info = checked_calloc(sizeof(struct ArtworkListInfo));
+  image_info->type = ARTWORK_TYPE_GRAPHICS;
+
+  /* ---------- initialize file list and suffix lists ---------- */
+
+  image_info->num_file_list_entries = num_file_list_entries;
+  image_info->num_dynamic_file_list_entries = 0;
+
+  image_info->file_list =
+    getFileListFromConfigList(config_list, config_suffix_list, ignore_tokens,
+                             num_file_list_entries);
+  image_info->dynamic_file_list = NULL;
+
+  image_info->num_suffix_list_entries = 0;
+  for (i=0; config_suffix_list[i].token != NULL; i++)
+    image_info->num_suffix_list_entries++;
+
+  image_info->suffix_list = config_suffix_list;
+
+  /* ---------- initialize base prefix and suffixes lists ---------- */
+
+  image_info->num_base_prefixes = 0;
+  for (i=0; base_prefixes[i] != NULL; i++)
+    image_info->num_base_prefixes++;
+
+  image_info->num_ext1_suffixes = 0;
+  for (i=0; ext1_suffixes[i] != NULL; i++)
+    image_info->num_ext1_suffixes++;
+
+  image_info->num_ext2_suffixes = 0;
+  for (i=0; ext2_suffixes[i] != NULL; i++)
+    image_info->num_ext2_suffixes++;
+
+  image_info->num_ext3_suffixes = 0;
+  for (i=0; ext3_suffixes[i] != NULL; i++)
+    image_info->num_ext3_suffixes++;
+
+  image_info->num_ignore_tokens = 0;
+  for (i=0; ignore_tokens[i] != NULL; i++)
+    image_info->num_ignore_tokens++;
+
+  image_info->base_prefixes = base_prefixes;
+  image_info->ext1_suffixes = ext1_suffixes;
+  image_info->ext2_suffixes = ext2_suffixes;
+  image_info->ext3_suffixes = ext3_suffixes;
+  image_info->ignore_tokens = ignore_tokens;
+
+  image_info->num_property_mapping_entries = 0;
+
+  image_info->property_mapping = NULL;
+
+  /* ---------- initialize artwork reference and content lists ---------- */
+
+  image_info->sizeof_artwork_list_entry = sizeof(ImageInfo *);
+
+  image_info->artwork_list =
+    checked_calloc(num_file_list_entries * sizeof(ImageInfo *));
+  image_info->dynamic_artwork_list = NULL;
+
+  image_info->content_list = NULL;
+
+  /* ---------- initialize artwork loading/freeing functions ---------- */
+
+  image_info->load_artwork = Load_PCX;
+  image_info->free_artwork = FreeImage;
+}
+
+void ReloadCustomImages()
+{
+#if 0
+  printf("DEBUG: reloading images '%s' ...\n", artwork.gfx_current_identifier);
+#endif
+
+  LoadArtworkConfig(image_info);
+  ReloadCustomArtworkList(image_info);
+}
+
+void CreateImageWithSmallImages(int pos)
+{
+  ImageInfo *img_info = getImageInfoEntryFromImageID(pos);
+
+  if (img_info == NULL || img_info->contains_small_images)
+    return;
+
+  CreateBitmapWithSmallBitmaps(img_info->bitmap);
+
+  img_info->contains_small_images = TRUE;
+
+#if 0
+  printf("CreateImageWithSmallImages: '%s' done\n", img_info->source_filename);
+#endif
+}
+
+void FreeAllImages()
+{
+  FreeCustomArtworkLists(image_info);
+}
index 6f473beeaf1c48b69b7b907dc2853c441affa216..e48e04cc83d43e5a12895f467bf5460d6b9edc16 100644 (file)
@@ -67,8 +67,27 @@ typedef struct
 Image *newImage(unsigned int, unsigned int, unsigned int);
 void freeImage(Image *);
 void freeXImage(Image *, XImageInfo *);
+
+void ZoomPixmap(Display *, GC, Pixmap, Pixmap, int, int, int, int);
+
 int Read_PCX_to_Pixmap(Display *, Window, GC, char *, Pixmap *, Pixmap *);
 
 #endif /* TARGET_X11 */
 
+int getImageListSize();
+struct FileInfo *getImageListEntry(int);
+Bitmap *getBitmapFromImageID(int);
+char *getTokenFromImageID(int);
+int getImageIDFromToken(char *);
+char *getImageConfigFilename();
+int getImageListPropertyMappingSize();
+struct PropertyMapping *getImageListPropertyMapping();
+void InitImageList(struct ConfigInfo *, int, struct ConfigInfo *,
+                  char **, char **, char **, char **, char **);
+
+void ReloadCustomImages();
+void CreateImageWithSmallImages(int);
+
+void FreeAllImages();
+
 #endif /* IMAGE_H */
index 06ac654162e43f38da9f24b483d8d9de64db2691..32efad6f840fdccaf7d3fb224c8563db3fdf5caa 100644 (file)
@@ -20,7 +20,7 @@
 
 
 /* ========================================================================= */
-/* platform dependant joystick functions                                     */
+/* platform dependent joystick functions                                     */
 /* ========================================================================= */
 
 #if defined(PLATFORM_UNIX) && !defined(TARGET_SDL)
@@ -97,7 +97,7 @@ boolean UnixReadJoystick(int fd, int *x, int *y, boolean *b1, boolean *b2)
 
 
 /* ========================================================================= */
-/* platform independant joystick functions                                   */
+/* platform independent joystick functions                                   */
 /* ========================================================================= */
 
 #define TRANSLATE_JOYSYMBOL_TO_JOYNAME 0
diff --git a/src/libgame/macosx.h b/src/libgame/macosx.h
new file mode 100644 (file)
index 0000000..7cccf57
--- /dev/null
@@ -0,0 +1,24 @@
+/***********************************************************
+* Artsoft Retro-Game Library                               *
+*----------------------------------------------------------*
+* (c) 1994-2003 Artsoft Entertainment                      *
+*               Holger Schemel                             *
+*               Detmolder Strasse 189                      *
+*               33604 Bielefeld                            *
+*               Germany                                    *
+*               e-mail: info@artsoft.org                   *
+*----------------------------------------------------------*
+* macosx.h                                                 *
+***********************************************************/
+
+#ifndef MACOSX_H
+#define MACOSX_H
+
+
+/* some symbols are already defined on Mac OS X */
+#define Delay Delay_internal
+#define DrawLine DrawLine_internal
+#define DrawText DrawText_internal
+#define GetPixel GetPixel_internal
+
+#endif /* MACOSX_H */
index 8bc69396cb464a0ad20b666dbced14501277c85e..f6cc110d4922e9e41be4fe8bae19fc1433919cab 100644 (file)
 #include "misc.h"
 #include "setup.h"
 #include "random.h"
+#include "text.h"
+#include "image.h"
 
 
+/* ------------------------------------------------------------------------- */
+/* some generic helper functions                                             */
+/* ------------------------------------------------------------------------- */
+
+void fprintf_line(FILE *stream, char *line_string, int line_length)
+{
+  int i;
+
+  for (i=0; i<line_length; i++)
+    fprintf(stream, "%s", line_string);
+
+  fprintf(stream, "\n");
+}
+
+void printf_line(char *line_string, int line_length)
+{
+  fprintf_line(stdout, line_string, line_length);
+}
+
+/* int2str() returns a number converted to a string;
+   the used memory is static, but will be overwritten by later calls,
+   so if you want to save the result, copy it to a private string buffer;
+   there can be 10 local calls of int2str() without buffering the result --
+   the 11th call will then destroy the result from the first call and so on.
+*/
+
+char *int2str(int number, int size)
+{
+  static char shift_array[10][40];
+  static int shift_counter = 0;
+  char *s = shift_array[shift_counter];
+
+  shift_counter = (shift_counter + 1) % 10;
+
+  if (size > 20)
+    size = 20;
+
+  if (size)
+  {
+    sprintf(s, "                    %09d", number);
+    return &s[strlen(s) - size];
+  }
+  else
+  {
+    sprintf(s, "%d", number);
+    return s;
+  }
+}
+
+
+/* ------------------------------------------------------------------------- */
+/* counter functions                                                         */
+/* ------------------------------------------------------------------------- */
+
 #if defined(PLATFORM_MSDOS)
 volatile unsigned long counter = 0;
 
@@ -160,8 +216,8 @@ boolean FrameReached(unsigned long *frame_counter_var,
 {
   unsigned long actual_frame_counter = FrameCounter;
 
-  if (actual_frame_counter < *frame_counter_var + frame_delay &&
-      actual_frame_counter >= *frame_counter_var)
+  if (actual_frame_counter >= *frame_counter_var &&
+      actual_frame_counter < *frame_counter_var + frame_delay)
     return FALSE;
 
   *frame_counter_var = actual_frame_counter;
@@ -174,8 +230,8 @@ boolean DelayReached(unsigned long *counter_var,
 {
   unsigned long actual_counter = Counter();
 
-  if (actual_counter < *counter_var + delay &&
-      actual_counter >= *counter_var)
+  if (actual_counter >= *counter_var &&
+      actual_counter < *counter_var + delay)
     return FALSE;
 
   *counter_var = actual_counter;
@@ -191,8 +247,8 @@ void WaitUntilDelayReached(unsigned long *counter_var, unsigned long delay)
   {
     actual_counter = Counter();
 
-    if (actual_counter < *counter_var + delay &&
-       actual_counter >= *counter_var)
+    if (actual_counter >= *counter_var &&
+       actual_counter < *counter_var + delay)
       sleep_milliseconds((*counter_var + delay - actual_counter) / 2);
     else
       break;
@@ -201,113 +257,131 @@ void WaitUntilDelayReached(unsigned long *counter_var, unsigned long delay)
   *counter_var = actual_counter;
 }
 
-/* int2str() returns a number converted to a string;
-   the used memory is static, but will be overwritten by later calls,
-   so if you want to save the result, copy it to a private string buffer;
-   there can be 10 local calls of int2str() without buffering the result --
-   the 11th call will then destroy the result from the first call and so on.
-*/
-
-char *int2str(int number, int size)
-{
-  static char shift_array[10][40];
-  static int shift_counter = 0;
-  char *s = shift_array[shift_counter];
 
-  shift_counter = (shift_counter + 1) % 10;
+/* ------------------------------------------------------------------------- */
+/* random generator functions                                                */
+/* ------------------------------------------------------------------------- */
 
-  if (size > 20)
-    size = 20;
+#if 0
+unsigned int SimpleRND(unsigned int max)
+{
+  return (random_linux_libc(RND_FREE) % max);
+}
 
-  if (size)
+unsigned int InitSimpleRND(long seed)
+{
+  if (seed == NEW_RANDOMIZE)
   {
-    sprintf(s, "                    %09d", number);
-    return &s[strlen(s) - size];
+    struct timeval current_time;
+
+    gettimeofday(&current_time, NULL);
+    seed = (long)current_time.tv_usec;
   }
-  else
+
+  srandom_linux_libc(RND_FREE, (unsigned int) seed);
+
+  return (unsigned int) seed;
+}
+
+unsigned int RND(unsigned int max)
+{
+  return (random_linux_libc(RND_GAME) % max);
+}
+
+unsigned int InitRND(long seed)
+{
+  if (seed == NEW_RANDOMIZE)
   {
-    sprintf(s, "%d", number);
-    return s;
+    struct timeval current_time;
+
+    gettimeofday(&current_time, NULL);
+    seed = (long)current_time.tv_usec;
   }
+
+  srandom_linux_libc(RND_GAME, (unsigned int) seed);
+
+  return (unsigned int) seed;
 }
+#endif
 
-unsigned int SimpleRND(unsigned int max)
+unsigned int init_random_number(int nr, long seed)
 {
+  if (seed == NEW_RANDOMIZE)
+  {
 #if defined(TARGET_SDL)
-  static unsigned long root = 654321;
-  unsigned long current_ms;
-
-  current_ms = SDL_GetTicks();
-  root = root * 4253261 + current_ms;
-  return (root % max);
+    seed = (long)SDL_GetTicks();
 #else
-  static unsigned long root = 654321;
-  struct timeval current_time;
+    struct timeval current_time;
 
-  gettimeofday(&current_time, NULL);
-  root = root * 4253261 + current_time.tv_sec + current_time.tv_usec;
-  return (root % max);
+    gettimeofday(&current_time, NULL);
+    seed = (long)current_time.tv_usec;
 #endif
-}
+  }
 
-#ifdef DEBUG
-static unsigned int last_RND_value = 0;
+  srandom_linux_libc(nr, (unsigned int) seed);
 
-unsigned int last_RND()
-{
-  return last_RND_value;
+  return (unsigned int) seed;
 }
-#endif
 
-unsigned int RND(unsigned int max)
+unsigned int get_random_number(int nr, unsigned int max)
 {
-#ifdef DEBUG
-  return (last_RND_value = random_linux_libc() % max);
-#else
-  return (random_linux_libc() % max);
-#endif
+  return (max > 0 ? random_linux_libc(nr) % max : 0);
 }
 
-unsigned int InitRND(long seed)
+
+/* ------------------------------------------------------------------------- */
+/* system info functions                                                     */
+/* ------------------------------------------------------------------------- */
+
+#if !defined(PLATFORM_MSDOS)
+static char *get_corrected_real_name(char *real_name)
 {
-#if defined(TARGET_SDL)
-  unsigned long current_ms;
+  char *real_name_new = checked_malloc(MAX_USERNAME_LEN + 1);
+  char *from_ptr = real_name;
+  char *to_ptr   = real_name_new;
 
-  if (seed == NEW_RANDOMIZE)
-  {
-    current_ms = SDL_GetTicks();
-    srandom_linux_libc((unsigned int) current_ms);
-    return (unsigned int) current_ms;
-  }
-  else
+  if (strchr(real_name, 'ß') == NULL)  /* name does not contain 'ß' */
   {
-    srandom_linux_libc((unsigned int) seed);
-    return (unsigned int) seed;
-  }
-#else
-  struct timeval current_time;
+    strncpy(real_name_new, real_name, MAX_USERNAME_LEN);
+    real_name_new[MAX_USERNAME_LEN] = '\0';
 
-  if (seed == NEW_RANDOMIZE)
-  {
-    gettimeofday(&current_time, NULL);
-    srandom_linux_libc((unsigned int) current_time.tv_usec);
-    return (unsigned int) current_time.tv_usec;
+    return real_name_new;
   }
-  else
+
+  /* the user's real name may contain a 'ß' character (german sharp s),
+     which has no equivalent in upper case letters (which our fonts use) */
+  while (*from_ptr && (long)(to_ptr - real_name_new) < MAX_USERNAME_LEN - 1)
   {
-    srandom_linux_libc((unsigned int) seed);
-    return (unsigned int) seed;
+    if (*from_ptr != 'ß')
+      *to_ptr++ = *from_ptr++;
+    else
+    {
+      from_ptr++;
+      *to_ptr++ = 's';
+      *to_ptr++ = 's';
+    }
   }
-#endif
+
+  *to_ptr = '\0';
+
+  return real_name_new;
 }
+#endif
 
 char *getLoginName()
 {
-#if defined(PLATFORM_WIN32)
-  return ANONYMOUS_NAME;
-#else
   static char *login_name = NULL;
 
+#if defined(PLATFORM_WIN32)
+  if (login_name == NULL)
+  {
+    unsigned long buffer_size = MAX_USERNAME_LEN + 1;
+    login_name = checked_malloc(buffer_size);
+
+    if (GetUserName(login_name, &buffer_size) == 0)
+      strcpy(login_name, ANONYMOUS_NAME);
+  }
+#else
   if (login_name == NULL)
   {
     struct passwd *pwd;
@@ -317,78 +391,87 @@ char *getLoginName()
     else
       login_name = getStringCopy(pwd->pw_name);
   }
+#endif
 
   return login_name;
-#endif
 }
 
 char *getRealName()
 {
-#if defined(PLATFORM_UNIX)
-  struct passwd *pwd;
+  static char *real_name = NULL;
 
-  if ((pwd = getpwuid(getuid())) == NULL || strlen(pwd->pw_gecos) == 0)
-    return ANONYMOUS_NAME;
-  else
+#if defined(PLATFORM_WIN32)
+  if (real_name == NULL)
   {
-    static char real_name[1024];
-    char *from_ptr = pwd->pw_gecos, *to_ptr = real_name;
-
-    if (strchr(pwd->pw_gecos, 'ß') == NULL)
-      return pwd->pw_gecos;
+    static char buffer[MAX_USERNAME_LEN + 1];
+    unsigned long buffer_size = MAX_USERNAME_LEN + 1;
 
-    /* the user's real name contains a 'ß' character (german sharp s),
-       which has no equivalent in upper case letters (which our fonts use) */
-    while (*from_ptr != '\0' && (long)(to_ptr - real_name) < 1024 - 2)
-    {
-      if (*from_ptr != 'ß')
-       *to_ptr++ = *from_ptr++;
-      else
-      {
-       from_ptr++;
-       *to_ptr++ = 's';
-       *to_ptr++ = 's';
-      }
-    }
-    *to_ptr = '\0';
+    if (GetUserName(buffer, &buffer_size) != 0)
+      real_name = get_corrected_real_name(buffer);
+    else
+      real_name = ANONYMOUS_NAME;
+  }
+#elif defined(PLATFORM_UNIX)
+  if (real_name == NULL)
+  {
+    struct passwd *pwd;
 
-    return real_name;
+    if ((pwd = getpwuid(getuid())) != NULL && strlen(pwd->pw_gecos) != 0)
+      real_name = get_corrected_real_name(pwd->pw_gecos);
+    else
+      real_name = ANONYMOUS_NAME;
   }
-#else /* !PLATFORM_UNIX */
-  return ANONYMOUS_NAME;
+#else
+  real_name = ANONYMOUS_NAME;
 #endif
+
+  return real_name;
 }
 
 char *getHomeDir()
 {
-#if defined(PLATFORM_UNIX)
-  static char *home_dir = NULL;
+  static char *dir = NULL;
+
+#if defined(PLATFORM_WIN32)
+  if (dir == NULL)
+  {
+    dir = checked_malloc(MAX_PATH + 1);
 
-  if (home_dir == NULL)
+    if (!SUCCEEDED(SHGetFolderPath(NULL, CSIDL_PERSONAL, NULL, 0, dir)))
+      strcpy(dir, ".");
+  }
+#elif defined(PLATFORM_UNIX)
+  if (dir == NULL)
   {
-    if ((home_dir = getenv("HOME")) == NULL)
+    if ((dir = getenv("HOME")) == NULL)
     {
       struct passwd *pwd;
 
-      if ((pwd = getpwuid(getuid())) == NULL)
-       home_dir = ".";
+      if ((pwd = getpwuid(getuid())) != NULL)
+       dir = getStringCopy(pwd->pw_dir);
       else
-       home_dir = getStringCopy(pwd->pw_dir);
+       dir = ".";
     }
   }
-
-  return home_dir;
 #else
-  return ".";
+  dir = ".";
 #endif
+
+  return dir;
 }
 
+
+/* ------------------------------------------------------------------------- */
+/* various string functions                                                  */
+/* ------------------------------------------------------------------------- */
+
 char *getPath2(char *path1, char *path2)
 {
   char *complete_path = checked_malloc(strlen(path1) + 1 +
                                       strlen(path2) + 1);
 
   sprintf(complete_path, "%s/%s", path1, path2);
+
   return complete_path;
 }
 
@@ -399,9 +482,19 @@ char *getPath3(char *path1, char *path2, char *path3)
                                       strlen(path3) + 1);
 
   sprintf(complete_path, "%s/%s/%s", path1, path2, path3);
+
   return complete_path;
 }
 
+char *getStringCat2(char *s1, char *s2)
+{
+  char *complete_string = checked_malloc(strlen(s1) + strlen(s2) + 1);
+
+  sprintf(complete_string, "%s%s", s1, s2);
+
+  return complete_string;
+}
+
 char *getStringCopy(char *s)
 {
   char *s_copy;
@@ -410,8 +503,8 @@ char *getStringCopy(char *s)
     return NULL;
 
   s_copy = checked_malloc(strlen(s) + 1);
-
   strcpy(s_copy, s);
+
   return s_copy;
 }
 
@@ -427,6 +520,48 @@ char *getStringToLower(char *s)
   return s_copy;
 }
 
+void setString(char **old_value, char *new_value)
+{
+  if (*old_value != NULL)
+    free(*old_value);
+
+  *old_value = getStringCopy(new_value);
+}
+
+
+/* ------------------------------------------------------------------------- */
+/* command line option handling functions                                    */
+/* ------------------------------------------------------------------------- */
+
+static void printUsage()
+{
+  printf("\n"
+        "Usage: %s [OPTION]... [HOSTNAME [PORT]]\n"
+        "\n"
+        "Options:\n"
+        "  -d, --display HOSTNAME[:SCREEN]  specify X server display\n"
+        "  -b, --basepath DIRECTORY         alternative base DIRECTORY\n"
+        "  -l, --level DIRECTORY            alternative level DIRECTORY\n"
+        "  -g, --graphics DIRECTORY         alternative graphics DIRECTORY\n"
+        "  -s, --sounds DIRECTORY           alternative sounds DIRECTORY\n"
+        "  -m, --music DIRECTORY            alternative music DIRECTORY\n"
+        "  -n, --network                    network multiplayer game\n"
+        "      --serveronly                 only start network server\n"
+        "  -v, --verbose                    verbose mode\n"
+        "      --debug                      display debugging information\n"
+        "  -e, --execute COMMAND            execute batch COMMAND:\n"
+        "\n"
+        "Valid commands for '--execute' option:\n"
+        "  \"print graphicsinfo.conf\"        print default graphics config\n"
+        "  \"print soundsinfo.conf\"          print default sounds config\n"
+        "  \"print musicinfo.conf\"           print default music config\n"
+        "  \"dump level FILE\"                dump level data from FILE\n"
+        "  \"dump tape FILE\"                 dump tape data from FILE\n"
+        "  \"autoplay LEVELDIR\"              play level tapes for LEVELDIR\n"
+        "\n",
+        program.command_basename);
+}
+
 void GetOptions(char *argv[])
 {
   char **options_left = &argv[1];
@@ -441,11 +576,17 @@ void GetOptions(char *argv[])
   options.graphics_directory = RO_BASE_PATH "/" GRAPHICS_DIRECTORY;
   options.sounds_directory = RO_BASE_PATH "/" SOUNDS_DIRECTORY;
   options.music_directory = RO_BASE_PATH "/" MUSIC_DIRECTORY;
+  options.docs_directory = RO_BASE_PATH "/" DOCS_DIRECTORY;
+  options.execute_command = NULL;
   options.serveronly = FALSE;
   options.network = FALSE;
   options.verbose = FALSE;
   options.debug = FALSE;
-  options.debug_command = NULL;
+
+#if !defined(PLATFORM_UNIX)
+  if (*options_left == NULL)   /* no options given -- enable verbose mode */
+    options.verbose = TRUE;
+#endif
 
   while (*options_left)
   {
@@ -483,22 +624,7 @@ void GetOptions(char *argv[])
       Error(ERR_EXIT_HELP, "unrecognized option '%s'", option);
     else if (strncmp(option, "-help", option_len) == 0)
     {
-      printf("Usage: %s [options] [<server host> [<server port>]]\n"
-            "Options:\n"
-            "  -d, --display <host>[:<scr>]  X server display\n"
-            "  -b, --basepath <directory>    alternative base directory\n"
-            "  -l, --level <directory>       alternative level directory\n"
-            "  -g, --graphics <directory>    alternative graphics directory\n"
-            "  -s, --sounds <directory>      alternative sounds directory\n"
-            "  -m, --music <directory>       alternative music directory\n"
-            "  -n, --network                 network multiplayer game\n"
-            "      --serveronly              only start network server\n"
-            "  -v, --verbose                 verbose mode\n"
-            "      --debug                   display debugging information\n",
-            program.command_basename);
-
-      if (options.debug)
-       printf("      --debug-command <command> execute special command\n");
+      printUsage();
 
       exit(0);
     }
@@ -578,12 +704,12 @@ void GetOptions(char *argv[])
     {
       options.debug = TRUE;
     }
-    else if (strncmp(option, "-debug-command", option_len) == 0)
+    else if (strncmp(option, "-execute", option_len) == 0)
     {
       if (option_arg == NULL)
        Error(ERR_EXIT_HELP, "option '%s' requires an argument", option_str);
 
-      options.debug_command = option_arg;
+      options.execute_command = option_arg;
       if (option_arg == next_option)
        options_left++;
     }
@@ -608,6 +734,11 @@ void GetOptions(char *argv[])
   }
 }
 
+
+/* ------------------------------------------------------------------------- */
+/* error handling functions                                                  */
+/* ------------------------------------------------------------------------- */
+
 /* used by SetError() and GetError() to store internal error messages */
 static char internal_error[1024];      /* this is bad */
 
@@ -627,6 +758,7 @@ char *GetError()
 
 void Error(int mode, char *format, ...)
 {
+  static boolean last_line_was_separator = FALSE;
   char *process_name = "";
   FILE *error = stderr;
   char *newline = "\n";
@@ -635,6 +767,18 @@ void Error(int mode, char *format, ...)
   if (mode & ERR_WARN && !options.verbose)
     return;
 
+  if (mode == ERR_RETURN_LINE)
+  {
+    if (!last_line_was_separator)
+      fprintf_line(error, format, 79);
+
+    last_line_was_separator = TRUE;
+
+    return;
+  }
+
+  last_line_was_separator = FALSE;
+
 #if defined(PLATFORM_MSDOS)
   newline = "\r\n";
 
@@ -688,6 +832,11 @@ void Error(int mode, char *format, ...)
   }
 }
 
+
+/* ------------------------------------------------------------------------- */
+/* memory allocation functions                                               */
+/* ------------------------------------------------------------------------- */
+
 void *checked_malloc(unsigned long size)
 {
   void *ptr;
@@ -722,6 +871,11 @@ void *checked_realloc(void *ptr, unsigned long size)
   return ptr;
 }
 
+
+/* ------------------------------------------------------------------------- */
+/* various helper functions                                                  */
+/* ------------------------------------------------------------------------- */
+
 inline void swap_numbers(int *i1, int *i2)
 {
   int help = *i1;
@@ -830,26 +984,28 @@ void putFileChunk(FILE *file, char *chunk_name, int chunk_size,
 
 int getFileVersion(FILE *file)
 {
-  int version_major, version_minor, version_patch;
+  int version_major, version_minor, version_patch, version_release;
 
-  version_major = fgetc(file);
-  version_minor = fgetc(file);
-  version_patch = fgetc(file);
-  fgetc(file);         /* not used */
+  version_major   = fgetc(file);
+  version_minor   = fgetc(file);
+  version_patch   = fgetc(file);
+  version_release = fgetc(file);
 
-  return VERSION_IDENT(version_major, version_minor, version_patch);
+  return RELEASE_IDENT(version_major, version_minor, version_patch,
+                      version_release);
 }
 
 void putFileVersion(FILE *file, int version)
 {
-  int version_major = VERSION_MAJOR(version);
-  int version_minor = VERSION_MINOR(version);
-  int version_patch = VERSION_PATCH(version);
-
-  fputc(version_major, file);
-  fputc(version_minor, file);
-  fputc(version_patch, file);
-  fputc(0, file);      /* not used */
+  int version_major   = VERSION_MAJOR(version);
+  int version_minor   = VERSION_MINOR(version);
+  int version_patch   = VERSION_PATCH(version);
+  int version_release = VERSION_RELEASE(version);
+
+  fputc(version_major,   file);
+  fputc(version_minor,   file);
+  fputc(version_patch,   file);
+  fputc(version_release, file);
 }
 
 void ReadUnusedBytesFromFile(FILE *file, unsigned long bytes)
@@ -1212,50 +1368,196 @@ char getCharFromKey(Key key)
 }
 
 
-/* ========================================================================= */
-/* functions for checking filenames                                          */
-/* ========================================================================= */
+/* ------------------------------------------------------------------------- */
+/* functions to translate string identifiers to integer or boolean value     */
+/* ------------------------------------------------------------------------- */
 
-boolean FileIsGraphic(char *filename)
+int get_integer_from_string(char *s)
 {
-  if (strlen(filename) > 4 &&
-      strcmp(&filename[strlen(filename) - 4], ".pcx") == 0)
-    return TRUE;
+  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" },
+  };
 
-  return FALSE;
+  int i, j;
+  char *s_lower = getStringToLower(s);
+  int result = -1;
+
+  for (i=0; i<13; i++)
+    for (j=0; j<3; j++)
+      if (strcmp(s_lower, number_text[i][j]) == 0)
+       result = i;
+
+  if (result == -1)
+    result = atoi(s);
+
+  free(s_lower);
+
+  return result;
 }
 
-boolean FileIsSound(char *basename)
+boolean get_boolean_from_string(char *s)
 {
-  if (strlen(basename) > 4 &&
-      strcmp(&basename[strlen(basename) - 4], ".wav") == 0)
-    return TRUE;
+  char *s_lower = getStringToLower(s);
+  boolean result = FALSE;
 
-  return FALSE;
+  if (strcmp(s_lower, "true") == 0 ||
+      strcmp(s_lower, "yes") == 0 ||
+      strcmp(s_lower, "on") == 0 ||
+      get_integer_from_string(s) == 1)
+    result = TRUE;
+
+  free(s_lower);
+
+  return result;
 }
 
-boolean FileIsMusic(char *basename)
+
+/* ------------------------------------------------------------------------- */
+/* functions for generic lists                                               */
+/* ------------------------------------------------------------------------- */
+
+ListNode *newListNode()
 {
-  /* "music" can be a WAV (loop) file or (if compiled with SDL) a MOD file */
+  return checked_calloc(sizeof(ListNode));
+}
 
-  if (FileIsSound(basename))
-    return TRUE;
+void addNodeToList(ListNode **node_first, char *key, void *content)
+{
+  ListNode *node_new = newListNode();
 
-#if defined(TARGET_SDL)
-  if (strlen(basename) > 4 &&
-      (strcmp(&basename[strlen(basename) - 4], ".mod") == 0 ||
-       strcmp(&basename[strlen(basename) - 4], ".MOD") == 0 ||
-       strncmp(basename, "mod.", 4) == 0 ||
-       strncmp(basename, "MOD.", 4) == 0))
-    return TRUE;
+#if 0
+  printf("LIST: adding node with key '%s'\n", key);
 #endif
 
-  return FALSE;
+  node_new->key = getStringCopy(key);
+  node_new->content = content;
+  node_new->next = *node_first;
+  *node_first = node_new;
 }
 
-boolean FileIsArtworkType(char *basename, int type)
+void deleteNodeFromList(ListNode **node_first, char *key,
+                       void (*destructor_function)(void *))
 {
-  if ((type == TREE_TYPE_GRAPHICS_DIR && FileIsGraphic(basename)) ||
+  if (node_first == NULL || *node_first == NULL)
+    return;
+
+#if 0
+  printf("[CHECKING LIST KEY '%s' == '%s']\n",
+        (*node_first)->key, key);
+#endif
+
+  if (strcmp((*node_first)->key, key) == 0)
+  {
+#if 0
+    printf("[DELETING LIST ENTRY]\n");
+#endif
+
+    free((*node_first)->key);
+    if (destructor_function)
+      destructor_function((*node_first)->content);
+    *node_first = (*node_first)->next;
+  }
+  else
+    deleteNodeFromList(&(*node_first)->next, key, destructor_function);
+}
+
+ListNode *getNodeFromKey(ListNode *node_first, char *key)
+{
+  if (node_first == NULL)
+    return NULL;
+
+  if (strcmp(node_first->key, key) == 0)
+    return node_first;
+  else
+    return getNodeFromKey(node_first->next, key);
+}
+
+int getNumNodes(ListNode *node_first)
+{
+  return (node_first ? 1 + getNumNodes(node_first->next) : 0);
+}
+
+void dumpList(ListNode *node_first)
+{
+  ListNode *node = node_first;
+
+  while (node)
+  {
+    printf("['%s' (%d)]\n", node->key,
+          ((struct ListNodeInfo *)node->content)->num_references);
+    node = node->next;
+  }
+
+  printf("[%d nodes]\n", getNumNodes(node_first));
+}
+
+
+/* ------------------------------------------------------------------------- */
+/* functions for checking files and filenames                                */
+/* ------------------------------------------------------------------------- */
+
+boolean fileExists(char *filename)
+{
+#if 0
+  printf("checking file '%s'\n", filename);
+#endif
+
+  return (access(filename, F_OK) == 0);
+}
+
+boolean FileIsGraphic(char *filename)
+{
+  if (strlen(filename) > 4 &&
+      strcmp(&filename[strlen(filename) - 4], ".pcx") == 0)
+    return TRUE;
+
+  return FALSE;
+}
+
+boolean FileIsSound(char *basename)
+{
+  if (strlen(basename) > 4 &&
+      strcmp(&basename[strlen(basename) - 4], ".wav") == 0)
+    return TRUE;
+
+  return FALSE;
+}
+
+boolean FileIsMusic(char *basename)
+{
+  /* "music" can be a WAV (loop) file or (if compiled with SDL) a MOD file */
+
+  if (FileIsSound(basename))
+    return TRUE;
+
+#if defined(TARGET_SDL)
+  if (strlen(basename) > 4 &&
+      (strcmp(&basename[strlen(basename) - 4], ".mod") == 0 ||
+       strcmp(&basename[strlen(basename) - 4], ".MOD") == 0 ||
+       strncmp(basename, "mod.", 4) == 0 ||
+       strncmp(basename, "MOD.", 4) == 0))
+    return TRUE;
+#endif
+
+  return FALSE;
+}
+
+boolean FileIsArtworkType(char *basename, int type)
+{
+  if ((type == TREE_TYPE_GRAPHICS_DIR && FileIsGraphic(basename)) ||
       (type == TREE_TYPE_SOUNDS_DIR && FileIsSound(basename)) ||
       (type == TREE_TYPE_MUSIC_DIR && FileIsMusic(basename)))
     return TRUE;
@@ -1263,11 +1565,978 @@ boolean FileIsArtworkType(char *basename, int type)
   return FALSE;
 }
 
+/* ------------------------------------------------------------------------- */
+/* functions for loading artwork configuration information                   */
+/* ------------------------------------------------------------------------- */
+
+/* This function checks if a string <s> of the format "string1, string2, ..."
+   exactly contains a string <s_contained>. */
+
+static boolean string_has_parameter(char *s, char *s_contained)
+{
+  char *substring;
+
+  if (s == NULL || s_contained == NULL)
+    return FALSE;
+
+  if (strlen(s_contained) > strlen(s))
+    return FALSE;
+
+  if (strncmp(s, s_contained, strlen(s_contained)) == 0)
+  {
+    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);
+  }
+
+  /* check if string contains another parameter string after a comma */
+  substring = strchr(s, ',');
+  if (substring == NULL)       /* string does not contain a comma */
+    return FALSE;
+
+  /* advance string pointer to next character after the comma */
+  substring++;
+
+  /* skip potential whitespaces after the comma */
+  while (*substring == ' ' || *substring == '\t')
+    substring++;
+
+  return string_has_parameter(substring, s_contained);
+}
+
+int get_parameter_value(char *token, char *value_raw, int type)
+{
+  char *value = getStringToLower(value_raw);
+  int result = 0;      /* probably a save default value */
+
+  if (strcmp(token, ".direction") == 0)
+  {
+    result = (strcmp(value, "left")  == 0 ? MV_LEFT :
+             strcmp(value, "right") == 0 ? MV_RIGHT :
+             strcmp(value, "up")    == 0 ? MV_UP :
+             strcmp(value, "down")  == 0 ? MV_DOWN : MV_NO_MOVING);
+  }
+  else if (strcmp(token, ".anim_mode") == 0)
+  {
+    result = (string_has_parameter(value, "loop")      ? ANIM_LOOP :
+             string_has_parameter(value, "linear")    ? ANIM_LINEAR :
+             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, "none")      ? ANIM_NONE :
+             ANIM_LOOP);
+
+    if (string_has_parameter(value, "reverse"))
+      result |= ANIM_REVERSE;
+  }
+  else         /* generic parameter of type integer or boolean */
+  {
+    result = (strcmp(value, ARG_UNDEFINED) == 0 ? ARG_UNDEFINED_VALUE :
+             type == TYPE_INTEGER ? get_integer_from_string(value) :
+             type == TYPE_BOOLEAN ? get_boolean_from_string(value) :
+             ARG_UNDEFINED_VALUE);
+  }
+
+  free(value);
+
+  return result;
+}
+
+static void FreeCustomArtworkList(struct ArtworkListInfo *,
+                                 struct ListNodeInfo ***, int *);
+
+struct FileInfo *getFileListFromConfigList(struct ConfigInfo *config_list,
+                                          struct ConfigInfo *suffix_list,
+                                          char **ignore_tokens,
+                                          int num_file_list_entries)
+{
+  struct FileInfo *file_list;
+  int num_file_list_entries_found = 0;
+  int num_suffix_list_entries = 0;
+  int list_pos;
+  int i, j;
+
+  file_list = checked_calloc(num_file_list_entries * sizeof(struct FileInfo));
+
+  for (i=0; suffix_list[i].token != NULL; i++)
+    num_suffix_list_entries++;
+
+  /* always start with reliable default values */
+  for (i=0; i<num_file_list_entries; i++)
+  {
+    file_list[i].token = NULL;
+
+    file_list[i].default_filename = NULL;
+    file_list[i].filename = NULL;
+
+    if (num_suffix_list_entries > 0)
+    {
+      int parameter_array_size = num_suffix_list_entries * sizeof(char *);
+
+      file_list[i].default_parameter = checked_calloc(parameter_array_size);
+      file_list[i].parameter = checked_calloc(parameter_array_size);
+
+      for (j=0; j<num_suffix_list_entries; j++)
+      {
+       setString(&file_list[i].default_parameter[j], suffix_list[j].value);
+       setString(&file_list[i].parameter[j], suffix_list[j].value);
+      }
+    }
+  }
+
+  list_pos = 0;
+  for (i=0; config_list[i].token != NULL; i++)
+  {
+    int len_config_token = strlen(config_list[i].token);
+    int len_config_value = strlen(config_list[i].value);
+    boolean is_file_entry = TRUE;
+
+    for (j=0; suffix_list[j].token != NULL; j++)
+    {
+      int len_suffix = strlen(suffix_list[j].token);
+
+      if (len_suffix < len_config_token &&
+         strcmp(&config_list[i].token[len_config_token - len_suffix],
+                suffix_list[j].token) == 0)
+      {
+       setString(&file_list[list_pos].default_parameter[j],
+                 config_list[i].value);
+
+       is_file_entry = FALSE;
+       break;
+      }
+    }
+
+    /* the following tokens are no file definitions, but other config tokens */
+    for (j=0; ignore_tokens[j] != NULL; j++)
+      if (strcmp(config_list[i].token, ignore_tokens[j]) == 0)
+       is_file_entry = FALSE;
+
+    if (is_file_entry)
+    {
+      if (i > 0)
+       list_pos++;
+
+      if (list_pos >= num_file_list_entries)
+       break;
+
+      /* simple sanity check if this is really a file definition */
+      if (strcmp(&config_list[i].value[len_config_value - 4], ".pcx") != 0 &&
+         strcmp(&config_list[i].value[len_config_value - 4], ".wav") != 0 &&
+         strcmp(config_list[i].value, UNDEFINED_FILENAME) != 0)
+      {
+       Error(ERR_RETURN, "Configuration directive '%s' -> '%s':",
+             config_list[i].token, config_list[i].value);
+       Error(ERR_EXIT, "This seems to be no valid definition -- please fix");
+      }
+
+      file_list[list_pos].token = config_list[i].token;
+      file_list[list_pos].default_filename = config_list[i].value;
+    }
+  }
+
+  num_file_list_entries_found = list_pos + 1;
+  if (num_file_list_entries_found != num_file_list_entries)
+  {
+    Error(ERR_RETURN_LINE, "-");
+    Error(ERR_RETURN, "inconsistant config list information:");
+    Error(ERR_RETURN, "- should be:   %d (according to 'src/conf_gfx.h')",
+         num_file_list_entries);
+    Error(ERR_RETURN, "- found to be: %d (according to 'src/conf_gfx.c')",
+         num_file_list_entries_found);
+    Error(ERR_EXIT,   "please fix");
+  }
+
+  return file_list;
+}
+
+static boolean token_suffix_match(char *token, char *suffix, int start_pos)
+{
+  int len_token = strlen(token);
+  int len_suffix = strlen(suffix);
+
+#if 0
+  if (IS_PARENT_PROCESS())
+    printf(":::::::::: check '%s' for '%s' ::::::::::\n", token, suffix);
+#endif
+
+  if (start_pos < 0)   /* compare suffix from end of string */
+    start_pos += len_token;
+
+  if (start_pos < 0 || start_pos + len_suffix > len_token)
+    return FALSE;
+
+  if (strncmp(&token[start_pos], suffix, len_suffix) != 0)
+    return FALSE;
+
+  if (token[start_pos + len_suffix] == '\0')
+    return TRUE;
+
+  if (token[start_pos + len_suffix] == '.')
+    return TRUE;
+
+  return FALSE;
+}
+
+#define KNOWN_TOKEN_VALUE      "[KNOWN_TOKEN]"
+
+static void read_token_parameters(SetupFileHash *setup_file_hash,
+                                 struct ConfigInfo *suffix_list,
+                                 struct FileInfo *file_list_entry)
+{
+  /* check for config token that is the base token without any suffixes */
+  char *filename = getHashEntry(setup_file_hash, file_list_entry->token);
+  char *known_token_value = KNOWN_TOKEN_VALUE;
+  int i;
+
+  if (filename != NULL)
+  {
+    setString(&file_list_entry->filename, filename);
+
+    /* when file definition found, set all parameters to default values */
+    for (i=0; suffix_list[i].token != NULL; i++)
+      setString(&file_list_entry->parameter[i], suffix_list[i].value);
+
+    file_list_entry->redefined = TRUE;
+
+    /* mark config file token as well known from default config */
+    setHashEntry(setup_file_hash, file_list_entry->token, known_token_value);
+  }
+#if 0
+  else
+  {
+    if (strcmp(file_list_entry->filename,
+              file_list_entry->default_filename) != 0)
+      printf("___ resetting '%s' to default\n", file_list_entry->token);
+
+    setString(&file_list_entry->filename, file_list_entry->default_filename);
+  }
+#endif
+
+  /* check for config tokens that can be build by base token and suffixes */
+  for (i=0; suffix_list[i].token != NULL; i++)
+  {
+    char *token = getStringCat2(file_list_entry->token, suffix_list[i].token);
+    char *value = getHashEntry(setup_file_hash, token);
+
+    if (value != NULL)
+    {
+      setString(&file_list_entry->parameter[i], value);
+
+      /* mark config file token as well known from default config */
+      setHashEntry(setup_file_hash, token, known_token_value);
+    }
+
+    free(token);
+  }
+}
+
+static void add_dynamic_file_list_entry(struct FileInfo **list,
+                                       int *num_list_entries,
+                                       SetupFileHash *extra_file_hash,
+                                       struct ConfigInfo *suffix_list,
+                                       int num_suffix_list_entries,
+                                       char *token)
+{
+  struct FileInfo *new_list_entry;
+  int parameter_array_size = num_suffix_list_entries * sizeof(char *);
+
+#if 0
+  if (IS_PARENT_PROCESS())
+    printf("===> found dynamic definition '%s'\n", token);
+#endif
+
+  (*num_list_entries)++;
+  *list = checked_realloc(*list, *num_list_entries * sizeof(struct FileInfo));
+  new_list_entry = &(*list)[*num_list_entries - 1];
+
+  new_list_entry->token = getStringCopy(token);
+  new_list_entry->filename = NULL;
+  new_list_entry->parameter = checked_calloc(parameter_array_size);
+
+  read_token_parameters(extra_file_hash, suffix_list, new_list_entry);
+}
+
+static void add_property_mapping(struct PropertyMapping **list,
+                                int *num_list_entries,
+                                int base_index, int ext1_index,
+                                int ext2_index, int ext3_index,
+                                int artwork_index)
+{
+  struct PropertyMapping *new_list_entry;
+
+  (*num_list_entries)++;
+  *list = checked_realloc(*list,
+                         *num_list_entries * sizeof(struct PropertyMapping));
+  new_list_entry = &(*list)[*num_list_entries - 1];
+
+  new_list_entry->base_index = base_index;
+  new_list_entry->ext1_index = ext1_index;
+  new_list_entry->ext2_index = ext2_index;
+  new_list_entry->ext3_index = ext3_index;
+
+  new_list_entry->artwork_index = artwork_index;
+}
+
+static void LoadArtworkConfigFromFilename(struct ArtworkListInfo *artwork_info,
+                                         char *filename)
+{
+  struct FileInfo *file_list = artwork_info->file_list;
+  struct ConfigInfo *suffix_list = artwork_info->suffix_list;
+  char **base_prefixes = artwork_info->base_prefixes;
+  char **ext1_suffixes = artwork_info->ext1_suffixes;
+  char **ext2_suffixes = artwork_info->ext2_suffixes;
+  char **ext3_suffixes = artwork_info->ext3_suffixes;
+  char **ignore_tokens = artwork_info->ignore_tokens;
+  int num_file_list_entries = artwork_info->num_file_list_entries;
+  int num_suffix_list_entries = artwork_info->num_suffix_list_entries;
+  int num_base_prefixes = artwork_info->num_base_prefixes;
+  int num_ext1_suffixes = artwork_info->num_ext1_suffixes;
+  int num_ext2_suffixes = artwork_info->num_ext2_suffixes;
+  int num_ext3_suffixes = artwork_info->num_ext3_suffixes;
+  int num_ignore_tokens = artwork_info->num_ignore_tokens;
+  SetupFileHash *setup_file_hash, *extra_file_hash;
+  char *known_token_value = KNOWN_TOKEN_VALUE;
+  int i, j, k, l;
+
+  if (filename == NULL)
+    return;
+
+#if 0
+  printf("::: LoadArtworkConfigFromFilename: '%s'\n", filename);
+#endif
+
+  if ((setup_file_hash = loadSetupFileHash(filename)) == NULL)
+    return;
+
+  /* read parameters for all known config file tokens */
+  for (i=0; i<num_file_list_entries; i++)
+    read_token_parameters(setup_file_hash, suffix_list, &file_list[i]);
+
+  /* set all tokens that can be ignored here to "known" keyword */
+  for (i=0; i < num_ignore_tokens; i++)
+    setHashEntry(setup_file_hash, ignore_tokens[i], known_token_value);
+
+  /* copy all unknown config file tokens to extra config list */
+  extra_file_hash = newSetupFileHash();
+  BEGIN_HASH_ITERATION(setup_file_hash, itr)
+  {
+    if (strcmp(HASH_ITERATION_VALUE(itr), known_token_value) != 0)
+      setHashEntry(extra_file_hash,
+                  HASH_ITERATION_TOKEN(itr), HASH_ITERATION_VALUE(itr));
+  }
+  END_HASH_ITERATION(setup_file_hash, itr)
+
+  /* at this point, we do not need the config file hash anymore -- free it */
+  freeSetupFileHash(setup_file_hash);
+
+  /* now try to determine valid, dynamically defined config tokens */
+
+  BEGIN_HASH_ITERATION(extra_file_hash, itr)
+  {
+    struct FileInfo **dynamic_file_list =
+      &artwork_info->dynamic_file_list;
+    int *num_dynamic_file_list_entries =
+      &artwork_info->num_dynamic_file_list_entries;
+    struct PropertyMapping **property_mapping =
+      &artwork_info->property_mapping;
+    int *num_property_mapping_entries =
+      &artwork_info->num_property_mapping_entries;
+    int current_summarized_file_list_entry =
+      artwork_info->num_file_list_entries +
+      artwork_info->num_dynamic_file_list_entries;
+    char *token = HASH_ITERATION_TOKEN(itr);
+    int len_token = strlen(token);
+    int start_pos;
+    boolean base_prefix_found = FALSE;
+    boolean parameter_suffix_found = FALSE;
+
+    /* skip all parameter definitions (handled by read_token_parameters()) */
+    for (i=0; i < num_suffix_list_entries && !parameter_suffix_found; i++)
+    {
+      int len_suffix = strlen(suffix_list[i].token);
+
+      if (token_suffix_match(token, suffix_list[i].token, -len_suffix))
+       parameter_suffix_found = TRUE;
+    }
+
+#if 0
+    if (IS_PARENT_PROCESS())
+    {
+      if (parameter_suffix_found)
+       printf("---> skipping token '%s' (parameter token)\n", token);
+      else
+       printf("---> examining token '%s': search prefix ...\n", token);
+    }
+#endif
+
+    if (parameter_suffix_found)
+      continue;
+
+    /* ---------- step 0: search for matching base prefix ---------- */
+
+    start_pos = 0;
+    for (i=0; i<num_base_prefixes && !base_prefix_found; i++)
+    {
+      char *base_prefix = base_prefixes[i];
+      int len_base_prefix = strlen(base_prefix);
+      boolean ext1_suffix_found = FALSE;
+      boolean ext2_suffix_found = FALSE;
+      boolean ext3_suffix_found = FALSE;
+      boolean exact_match = FALSE;
+      int base_index = -1;
+      int ext1_index = -1;
+      int ext2_index = -1;
+      int ext3_index = -1;
+
+      base_prefix_found = token_suffix_match(token, base_prefix, start_pos);
+
+      if (!base_prefix_found)
+       continue;
+
+      base_index = i;
+
+      if (start_pos + len_base_prefix == len_token)    /* exact match */
+      {
+       exact_match = TRUE;
+
+       add_dynamic_file_list_entry(dynamic_file_list,
+                                   num_dynamic_file_list_entries,
+                                   extra_file_hash,
+                                   suffix_list,
+                                   num_suffix_list_entries,
+                                   token);
+       add_property_mapping(property_mapping,
+                            num_property_mapping_entries,
+                            base_index, -1, -1, -1,
+                            current_summarized_file_list_entry);
+       continue;
+      }
+
+#if 0
+      if (IS_PARENT_PROCESS())
+       printf("---> examining token '%s': search 1st suffix ...\n", token);
+#endif
+
+      /* ---------- step 1: search for matching first suffix ---------- */
+
+      start_pos += len_base_prefix;
+      for (j=0; j<num_ext1_suffixes && !ext1_suffix_found; j++)
+      {
+       char *ext1_suffix = ext1_suffixes[j];
+       int len_ext1_suffix = strlen(ext1_suffix);
+
+       ext1_suffix_found = token_suffix_match(token, ext1_suffix, start_pos);
+
+       if (!ext1_suffix_found)
+         continue;
+
+       ext1_index = j;
 
-/* ========================================================================= */
+       if (start_pos + len_ext1_suffix == len_token)   /* exact match */
+       {
+         exact_match = TRUE;
+
+         add_dynamic_file_list_entry(dynamic_file_list,
+                                     num_dynamic_file_list_entries,
+                                     extra_file_hash,
+                                     suffix_list,
+                                     num_suffix_list_entries,
+                                     token);
+         add_property_mapping(property_mapping,
+                              num_property_mapping_entries,
+                              base_index, ext1_index, -1, -1,
+                              current_summarized_file_list_entry);
+         continue;
+       }
+
+       start_pos += len_ext1_suffix;
+      }
+
+      if (exact_match)
+       break;
+
+#if 0
+      if (IS_PARENT_PROCESS())
+       printf("---> examining token '%s': search 2nd suffix ...\n", token);
+#endif
+
+      /* ---------- step 2: search for matching second suffix ---------- */
+
+      for (k=0; k<num_ext2_suffixes && !ext2_suffix_found; k++)
+      {
+       char *ext2_suffix = ext2_suffixes[k];
+       int len_ext2_suffix = strlen(ext2_suffix);
+
+       ext2_suffix_found = token_suffix_match(token, ext2_suffix,start_pos);
+
+       if (!ext2_suffix_found)
+         continue;
+
+       ext2_index = k;
+
+       if (start_pos + len_ext2_suffix == len_token)   /* exact match */
+       {
+         exact_match = TRUE;
+
+         add_dynamic_file_list_entry(dynamic_file_list,
+                                     num_dynamic_file_list_entries,
+                                     extra_file_hash,
+                                     suffix_list,
+                                     num_suffix_list_entries,
+                                     token);
+         add_property_mapping(property_mapping,
+                              num_property_mapping_entries,
+                              base_index, ext1_index, ext2_index, -1,
+                              current_summarized_file_list_entry);
+         continue;
+       }
+
+       start_pos += len_ext2_suffix;
+      }
+
+      if (exact_match)
+       break;
+
+#if 0
+      if (IS_PARENT_PROCESS())
+       printf("---> examining token '%s': search 3rd suffix ...\n",token);
+#endif
+
+      /* ---------- step 3: search for matching third suffix ---------- */
+
+      for (l=0; l<num_ext3_suffixes && !ext3_suffix_found; l++)
+      {
+       char *ext3_suffix = ext3_suffixes[l];
+       int len_ext3_suffix = strlen(ext3_suffix);
+
+       ext3_suffix_found =token_suffix_match(token,ext3_suffix,start_pos);
+
+       if (!ext3_suffix_found)
+         continue;
+
+       ext3_index = l;
+
+       if (start_pos + len_ext3_suffix == len_token) /* exact match */
+       {
+         exact_match = TRUE;
+
+         add_dynamic_file_list_entry(dynamic_file_list,
+                                     num_dynamic_file_list_entries,
+                                     extra_file_hash,
+                                     suffix_list,
+                                     num_suffix_list_entries,
+                                     token);
+         add_property_mapping(property_mapping,
+                              num_property_mapping_entries,
+                              base_index, ext1_index, ext2_index, ext3_index,
+                              current_summarized_file_list_entry);
+         continue;
+       }
+      }
+    }
+  }
+  END_HASH_ITERATION(extra_file_hash, itr)
+
+  if (artwork_info->num_dynamic_file_list_entries > 0)
+  {
+    artwork_info->dynamic_artwork_list =
+      checked_calloc(artwork_info->num_dynamic_file_list_entries *
+                    artwork_info->sizeof_artwork_list_entry);
+  }
+
+  if (extra_file_hash != NULL && options.verbose && IS_PARENT_PROCESS())
+  {
+    SetupFileList *setup_file_list, *list;
+    boolean dynamic_tokens_found = FALSE;
+    boolean unknown_tokens_found = FALSE;
+
+    if ((setup_file_list = loadSetupFileList(filename)) == NULL)
+      Error(ERR_EXIT, "loadSetupFileHash works, but loadSetupFileList fails");
+
+    BEGIN_HASH_ITERATION(extra_file_hash, itr)
+    {
+      if (strcmp(HASH_ITERATION_VALUE(itr), known_token_value) == 0)
+       dynamic_tokens_found = TRUE;
+      else
+       unknown_tokens_found = TRUE;
+    }
+    END_HASH_ITERATION(extra_file_hash, itr)
+
+#if DEBUG
+    if (dynamic_tokens_found)
+    {
+      Error(ERR_RETURN_LINE, "-");
+      Error(ERR_RETURN, "dynamic token(s) found in config file:");
+      Error(ERR_RETURN, "- config file: '%s'", filename);
+
+      for (list = setup_file_list; list != NULL; list = list->next)
+      {
+       char *value = getHashEntry(extra_file_hash, list->token);
+
+       if (value != NULL && strcmp(value, known_token_value) == 0)
+         Error(ERR_RETURN, "- dynamic token: '%s'", list->token);
+      }
+
+      Error(ERR_RETURN_LINE, "-");
+    }
+#endif
+
+    if (unknown_tokens_found)
+    {
+      Error(ERR_RETURN_LINE, "-");
+      Error(ERR_RETURN, "warning: unknown token(s) found in config file:");
+      Error(ERR_RETURN, "- config file: '%s'", filename);
+
+      for (list = setup_file_list; list != NULL; list = list->next)
+      {
+       char *value = getHashEntry(extra_file_hash, list->token);
+
+       if (value != NULL && strcmp(value, known_token_value) != 0)
+         Error(ERR_RETURN, "- dynamic token: '%s'", list->token);
+      }
+
+      Error(ERR_RETURN_LINE, "-");
+    }
+
+    freeSetupFileList(setup_file_list);
+  }
+
+  freeSetupFileHash(extra_file_hash);
+
+#if 0
+  for (i=0; i<num_file_list_entries; i++)
+  {
+    printf("'%s' ", file_list[i].token);
+    if (file_list[i].filename)
+      printf("-> '%s'\n", file_list[i].filename);
+    else
+      printf("-> UNDEFINED [-> '%s']\n", file_list[i].default_filename);
+  }
+#endif
+}
+
+void LoadArtworkConfig(struct ArtworkListInfo *artwork_info)
+{
+  struct FileInfo *file_list = artwork_info->file_list;
+  int num_file_list_entries = artwork_info->num_file_list_entries;
+  int num_suffix_list_entries = artwork_info->num_suffix_list_entries;
+  char *filename_base = UNDEFINED_FILENAME, *filename_local;
+  int i, j;
+
+#if 0
+  printf("GOT CUSTOM ARTWORK CONFIG FILE '%s'\n", filename);
+#endif
+
+  /* always start with reliable default values */
+  for (i=0; i<num_file_list_entries; i++)
+  {
+    setString(&file_list[i].filename, file_list[i].default_filename);
+
+    for (j=0; j<num_suffix_list_entries; j++)
+      setString(&file_list[i].parameter[j], file_list[i].default_parameter[j]);
+
+    file_list[i].redefined = FALSE;
+  }
+
+  /* free previous dynamic artwork file array */
+  if (artwork_info->dynamic_file_list != NULL)
+  {
+    for (i=0; i<artwork_info->num_dynamic_file_list_entries; i++)
+    {
+      free(artwork_info->dynamic_file_list[i].token);
+      free(artwork_info->dynamic_file_list[i].filename);
+      free(artwork_info->dynamic_file_list[i].parameter);
+    }
+
+    free(artwork_info->dynamic_file_list);
+    artwork_info->dynamic_file_list = NULL;
+
+    FreeCustomArtworkList(artwork_info, &artwork_info->dynamic_artwork_list,
+                         &artwork_info->num_dynamic_file_list_entries);
+  }
+
+  /* free previous property mapping */
+  if (artwork_info->property_mapping != NULL)
+  {
+    free(artwork_info->property_mapping);
+
+    artwork_info->property_mapping = NULL;
+    artwork_info->num_property_mapping_entries = 0;
+  }
+
+  if (!SETUP_OVERRIDE_ARTWORK(setup, artwork_info->type))
+  {
+    /* first look for special artwork configured in level series config */
+    filename_base = getCustomArtworkLevelConfigFilename(artwork_info->type);
+
+    if (fileExists(filename_base))
+      LoadArtworkConfigFromFilename(artwork_info, filename_base);
+  }
+
+  filename_local = getCustomArtworkConfigFilename(artwork_info->type);
+
+  if (filename_local != NULL && strcmp(filename_base, filename_local) != 0)
+    LoadArtworkConfigFromFilename(artwork_info, filename_local);
+}
+
+static void deleteArtworkListEntry(struct ArtworkListInfo *artwork_info,
+                                  struct ListNodeInfo **listnode)
+{
+  if (*listnode)
+  {
+    char *filename = (*listnode)->source_filename;
+
+#if 0
+    printf("[decrementing reference counter of artwork '%s']\n", filename);
+#endif
+
+    if (--(*listnode)->num_references <= 0)
+    {
+#if 0
+      printf("[deleting artwork '%s']\n", filename);
+#endif
+
+      deleteNodeFromList(&artwork_info->content_list, filename,
+                        artwork_info->free_artwork);
+    }
+
+    *listnode = NULL;
+  }
+}
+
+static void replaceArtworkListEntry(struct ArtworkListInfo *artwork_info,
+                                   struct ListNodeInfo **listnode,
+                                   char *basename)
+{
+  char *init_text[] =
+  {
+    "Loading graphics:",
+    "Loading sounds:",
+    "Loading music:"
+  };
+
+  ListNode *node;
+  char *filename = getCustomArtworkFilename(basename, artwork_info->type);
+
+  if (filename == NULL)
+  {
+    int error_mode = ERR_WARN;
+
+#if 1
+    /* we can get away without sounds and music, but not without graphics */
+    if (*listnode == NULL && artwork_info->type == ARTWORK_TYPE_GRAPHICS)
+      error_mode = ERR_EXIT;
+#endif
+
+    Error(error_mode, "cannot find artwork file '%s'", basename);
+    return;
+  }
+
+  /* check if the old and the new artwork file are the same */
+  if (*listnode && strcmp((*listnode)->source_filename, filename) == 0)
+  {
+    /* The old and new artwork are the same (have the same filename and path).
+       This usually means that this artwork does not exist in this artwork set
+       and a fallback to the existing artwork is done. */
+
+#if 0
+    printf("[artwork '%s' already exists (same list entry)]\n", filename);
+#endif
+
+    return;
+  }
+
+  /* delete existing artwork file entry */
+  deleteArtworkListEntry(artwork_info, listnode);
+
+  /* check if the new artwork file already exists in the list of artworks */
+  if ((node = getNodeFromKey(artwork_info->content_list, filename)) != NULL)
+  {
+#if 0
+      printf("[artwork '%s' already exists (other list entry)]\n", filename);
+#endif
+
+      *listnode = (struct ListNodeInfo *)node->content;
+      (*listnode)->num_references++;
+
+      return;
+  }
+
+#if 0
+  printf("::: %s: '%s'\n", init_text[artwork_info->type], basename);
+#endif
+
+  DrawInitText(init_text[artwork_info->type], 120, FC_GREEN);
+  DrawInitText(basename, 150, FC_YELLOW);
+
+  if ((*listnode = artwork_info->load_artwork(filename)) != NULL)
+  {
+#if 0
+      printf("[adding new artwork '%s']\n", filename);
+#endif
+
+    (*listnode)->num_references = 1;
+    addNodeToList(&artwork_info->content_list, (*listnode)->source_filename,
+                 *listnode);
+  }
+  else
+  {
+    int error_mode = ERR_WARN;
+
+#if 1
+    /* we can get away without sounds and music, but not without graphics */
+    if (artwork_info->type == ARTWORK_TYPE_GRAPHICS)
+      error_mode = ERR_EXIT;
+#endif
+
+    Error(error_mode, "cannot load artwork file '%s'", basename);
+    return;
+  }
+}
+
+static void LoadCustomArtwork(struct ArtworkListInfo *artwork_info,
+                             struct ListNodeInfo **listnode,
+                             char *basename)
+{
+#if 0
+  printf("GOT CUSTOM ARTWORK FILE '%s'\n", filename);
+#endif
+
+  if (strcmp(basename, UNDEFINED_FILENAME) == 0)
+  {
+    deleteArtworkListEntry(artwork_info, listnode);
+    return;
+  }
+
+  replaceArtworkListEntry(artwork_info, listnode, basename);
+}
+
+static void LoadArtworkToList(struct ArtworkListInfo *artwork_info,
+                             struct ListNodeInfo **listnode,
+                             char *basename, int list_pos)
+{
+#if 0
+  if (artwork_info->artwork_list == NULL ||
+      list_pos >= artwork_info->num_file_list_entries)
+    return;
+#endif
+
+#if 0
+  printf("loading artwork '%s' ...  [%d]\n",
+        basename, getNumNodes(artwork_info->content_list));
+#endif
+
+#if 1
+  LoadCustomArtwork(artwork_info, listnode, basename);
+#else
+  LoadCustomArtwork(artwork_info, &artwork_info->artwork_list[list_pos],
+                   basename);
+#endif
+
+#if 0
+  printf("loading artwork '%s' done [%d]\n",
+        basename, getNumNodes(artwork_info->content_list));
+#endif
+}
+
+void ReloadCustomArtworkList(struct ArtworkListInfo *artwork_info)
+{
+  struct FileInfo *file_list = artwork_info->file_list;
+  struct FileInfo *dynamic_file_list = artwork_info->dynamic_file_list;
+  int num_file_list_entries = artwork_info->num_file_list_entries;
+  int num_dynamic_file_list_entries =
+    artwork_info->num_dynamic_file_list_entries;
+  int i;
+
+#if 0
+  printf("DEBUG: reloading %d static artwork files ...\n",
+        num_file_list_entries);
+#endif
+
+  for(i=0; i<num_file_list_entries; i++)
+  {
+#if 0
+    if (strcmp(file_list[i].token, "background") == 0)
+      printf("::: '%s' -> '%s'\n", file_list[i].token, file_list[i].filename);
+#endif
+
+    LoadArtworkToList(artwork_info, &artwork_info->artwork_list[i],
+                     file_list[i].filename, i);
+
+#if 0
+    if (artwork_info->artwork_list[i] == NULL &&
+       strcmp(file_list[i].default_filename, file_list[i].filename) != 0)
+    {
+      Error(ERR_WARN, "trying default artwork file '%s'",
+           file_list[i].default_filename);
+
+      LoadArtworkToList(artwork_info, &artwork_info->artwork_list[i],
+                       file_list[i].default_filename, i);
+    }
+#endif
+  }
+
+#if 0
+  printf("DEBUG: reloading %d dynamic artwork files ...\n",
+        num_dynamic_file_list_entries);
+#endif
+
+  for(i=0; i<num_dynamic_file_list_entries; i++)
+    LoadArtworkToList(artwork_info, &artwork_info->dynamic_artwork_list[i],
+                     dynamic_file_list[i].filename, i);
+
+#if 0
+  dumpList(artwork_info->content_list);
+#endif
+}
+
+static void FreeCustomArtworkList(struct ArtworkListInfo *artwork_info,
+                                 struct ListNodeInfo ***list,
+                                 int *num_list_entries)
+{
+  int i;
+
+  if (*list == NULL)
+    return;
+
+  for(i=0; i<*num_list_entries; i++)
+    deleteArtworkListEntry(artwork_info, &(*list)[i]);
+  free(*list);
+
+  *list = NULL;
+  *num_list_entries = 0;
+}
+
+void FreeCustomArtworkLists(struct ArtworkListInfo *artwork_info)
+{
+  if (artwork_info == NULL)
+    return;
+
+#if 0
+  printf("%s: FREEING ARTWORK ...\n",
+        IS_CHILD_PROCESS() ? "CHILD" : "PARENT");
+#endif
+
+  FreeCustomArtworkList(artwork_info, &artwork_info->artwork_list,
+                       &artwork_info->num_file_list_entries);
+
+  FreeCustomArtworkList(artwork_info, &artwork_info->dynamic_artwork_list,
+                       &artwork_info->num_dynamic_file_list_entries);
+
+#if 0
+  printf("%s: FREEING ARTWORK -- DONE\n",
+        IS_CHILD_PROCESS() ? "CHILD" : "PARENT");
+#endif
+}
+
+
+/* ------------------------------------------------------------------------- */
 /* functions only needed for non-Unix (non-command-line) systems             */
 /* (MS-DOS only; SDL/Windows creates files "stdout.txt" and "stderr.txt")    */
-/* ========================================================================= */
+/* ------------------------------------------------------------------------- */
 
 #if defined(PLATFORM_MSDOS)
 
@@ -1298,9 +2567,9 @@ void dumpErrorFile()
 #endif
 
 
-/* ========================================================================= */
+/* ------------------------------------------------------------------------- */
 /* the following is only for debugging purpose and normally not used         */
-/* ========================================================================= */
+/* ------------------------------------------------------------------------- */
 
 #define DEBUG_NUM_TIMESTAMPS   3
 
@@ -1319,3 +2588,20 @@ void debug_print_timestamp(int counter_nr, char *message)
 
   counter[counter_nr][1] = Counter();
 }
+
+void debug_print_parent_only(char *format, ...)
+{
+  if (!IS_PARENT_PROCESS())
+    return;
+
+  if (format)
+  {
+    va_list ap;
+
+    va_start(ap, format);
+    vprintf(format, ap);
+    va_end(ap);
+
+    printf("\n");
+  }
+}
index e7dd846f9ef6c517f350004ee79e59eea8bc8bce..7fd0a1a5b83e25c9df3860f1fbf6d7b72beed304 100644 (file)
 /* values for InitRND() */
 #define NEW_RANDOMIZE                  -1
 
+#define InitRND(seed)                  init_random_number(0, seed)
+#define InitSimpleRND(seed)            init_random_number(1, seed)
+#define RND(max)                       get_random_number(0, max)
+#define SimpleRND(max)                 get_random_number(1, max)
+
 /* values for Error() */
 #define ERR_RETURN                     0
-#define ERR_WARN                       (1 << 0)
-#define ERR_EXIT                       (1 << 1)
-#define ERR_HELP                       (1 << 2)
-#define ERR_SOUND_SERVER               (1 << 3)
-#define ERR_NETWORK_SERVER             (1 << 4)
-#define ERR_NETWORK_CLIENT             (1 << 5)
+#define ERR_RETURN_LINE                        (1 << 0)
+#define ERR_WARN                       (1 << 1)
+#define ERR_EXIT                       (1 << 2)
+#define ERR_HELP                       (1 << 3)
+#define ERR_SOUND_SERVER               (1 << 4)
+#define ERR_NETWORK_SERVER             (1 << 5)
+#define ERR_NETWORK_CLIENT             (1 << 6)
 #define ERR_FROM_SERVER                        (ERR_SOUND_SERVER | ERR_NETWORK_SERVER)
 #define ERR_EXIT_HELP                  (ERR_EXIT | ERR_HELP)
 #define ERR_EXIT_SOUND_SERVER          (ERR_EXIT | ERR_SOUND_SERVER)
 #define BYTE_ORDER_BIG_ENDIAN          0
 #define BYTE_ORDER_LITTLE_ENDIAN       1
 
+/* values for cursor bitmap creation */
+#define BIT_ORDER_MSB                  0
+#define BIT_ORDER_LSB                  1
+
 /* values for createDirectory() */
 #define PERMS_PRIVATE                  0
 #define PERMS_PUBLIC                   1
 
 /* values for general file handling stuff */
 #define MAX_FILENAME_LEN               256
-#define MAX_LINE_LEN                   1000
+#define MAX_LINE_LEN                   1024
+
+/* values for general username handling stuff */
+#define MAX_USERNAME_LEN               1024
+
+
+void fprintf_line(FILE *, char *, int);
+void printf_line(char *, int);
+char *int2str(int, int);
 
 void InitCounter(void);
 unsigned long Counter(void);
@@ -59,17 +77,27 @@ void Delay(unsigned long);
 boolean FrameReached(unsigned long *, unsigned long);
 boolean DelayReached(unsigned long *, unsigned long);
 void WaitUntilDelayReached(unsigned long *, unsigned long);
-char *int2str(int, int);
+
+#if 0
 unsigned int SimpleRND(unsigned int);
+unsigned int InitSimpleRND(long);
 unsigned int RND(unsigned int);
 unsigned int InitRND(long);
+#endif
+
+unsigned int init_random_number(int, long);
+unsigned int get_random_number(int, unsigned int);
+
 char *getLoginName(void);
 char *getRealName(void);
 char *getHomeDir(void);
+
 char *getPath2(char *, char *);
 char *getPath3(char *, char *, char*);
+char *getStringCat2(char *, char *);
 char *getStringCopy(char *);
 char *getStringToLower(char *);
+void setString(char **, char *);
 
 void GetOptions(char **);
 
@@ -80,6 +108,7 @@ void Error(int, char *, ...);
 void *checked_malloc(unsigned long);
 void *checked_calloc(unsigned long);
 void *checked_realloc(void *, unsigned long);
+
 inline void swap_numbers(int *, int *);
 inline void swap_number_pairs(int *, int *, int *, int *);
 
@@ -94,6 +123,8 @@ void putFileVersion(FILE *, int);
 void ReadUnusedBytesFromFile(FILE *, unsigned long);
 void WriteUnusedBytesToFile(FILE *, unsigned long);
 
+#define getFile8Bit(f)        fgetc(f)
+#define putFile8Bit(f,x)      fputc(x, f)
 #define getFile16BitBE(f)     getFile16BitInteger(f,BYTE_ORDER_BIG_ENDIAN)
 #define getFile16BitLE(f)     getFile16BitInteger(f,BYTE_ORDER_LITTLE_ENDIAN)
 #define putFile16BitBE(f,x)   putFile16BitInteger(f,x,BYTE_ORDER_BIG_ENDIAN)
@@ -113,11 +144,29 @@ Key getKeyFromKeyName(char *);
 Key getKeyFromX11KeyName(char *);
 char getCharFromKey(Key);
 
+int get_integer_from_string(char *);
+boolean get_boolean_from_string(char *);
+
+ListNode *newListNode(void);
+void addNodeToList(ListNode **, char *, void *);
+void deleteNodeFromList(ListNode **, char *, void (*function)(void *));
+ListNode *getNodeFromKey(ListNode *, char *);
+int getNumNodes(ListNode *);
+
+boolean fileExists(char *);
 boolean FileIsGraphic(char *);
 boolean FileIsSound(char *);
 boolean FileIsMusic(char *);
 boolean FileIsArtworkType(char *, int);
 
+int get_parameter_value(char *, char *, int);
+
+struct FileInfo *getFileListFromConfigList(struct ConfigInfo *,
+                                          struct ConfigInfo *, char **, int);
+void LoadArtworkConfig(struct ArtworkListInfo *);
+void ReloadCustomArtworkList(struct ArtworkListInfo *);
+void FreeCustomArtworkLists(struct ArtworkListInfo *);
+
 #if !defined(PLATFORM_UNIX)
 void initErrorFile();
 FILE *openErrorFile();
index 29cc036028c7981817f400fa1f6e40037a342974..ec19ef6389c7d639c99f9106ef17826ff53de950 100644 (file)
@@ -297,7 +297,7 @@ Display *XOpenDisplay(char *display_name)
   Screen *screen;
   Display *display;
   BITMAP *mouse_bitmap = NULL;
-  char *mouse_filename =getCustomImageFilename(program.msdos_pointer_filename);
+  char *mouse_filename = getCustomImageFilename(program.msdos_cursor_filename);
 
   if ((mouse_bitmap = Read_PCX_to_AllegroBitmap(mouse_filename)) == NULL)
     return NULL;
@@ -917,6 +917,14 @@ Pixel AllegroGetPixel(Drawable d, int x, int y)
   return getpixel((BITMAP *)d, x, y);
 }
 
+void AllegroZoomBitmap(Drawable src, Drawable dst,
+                      int src_width, int src_height,
+                      int dst_width, int dst_height)
+{
+  stretch_blit((BITMAP *)src, (BITMAP *)dst,
+              0, 0, src_width, src_height, 0, 0, dst_width, dst_height);
+}
+
 void MSDOSOpenAudio(void)
 {
   if (allegro_init_audio())
index 5ddb3eef42aea353ed8e7ab3eeafd492d01143f3..e976420e06f0931e9ee23c0df69753d1fbe36de6 100644 (file)
@@ -747,6 +747,8 @@ void XAutoRepeatOff(Display *);
 void AllegroDrawLine(Drawable, int, int, int, int, Pixel);
 Pixel AllegroGetPixel(Drawable, int, int);
 
+void AllegroZoomBitmap(Drawable, Drawable, int, int, int, int);
+
 void MSDOSOpenAudio(void);
 void MSDOSCloseAudio(void);
 
index 7f6d7f2da42ad9407a0a6fa7b4d779aaabf9ea92..47a11d462fec86888cdb14b7cd7e39c99a3708ab 100644 (file)
@@ -19,7 +19,7 @@
 #include "misc.h"
 
 
-#define PCX_DEBUG              FALSE
+#define PCX_DEBUG              0
 
 #define PCX_MAGIC              0x0a    /* first byte in a PCX image file    */
 #define PCX_SUPPORTED_VERSION  5       /* last acceptable version number    */
@@ -112,7 +112,7 @@ static boolean PCX_ReadBitmap(FILE *file, struct PCX_Header *pcx, Image *image)
   for (y = 0; y < height; y++)
   {
     /* decode a scan line into a temporary buffer first */
-    byte *dst_ptr = (pcx_depth == 8) ? bitmap_ptr : row_buffer;
+    byte *dst_ptr = (pcx_depth == 8 ? bitmap_ptr : row_buffer);
     byte value = 0, count = 0;
     int value_int;
     int i;
@@ -122,14 +122,23 @@ static boolean PCX_ReadBitmap(FILE *file, struct PCX_Header *pcx, Image *image)
       if (count == 0)
       {
        if ((value_int = fgetc(file)) == EOF)
+       {
+         free(row_buffer);
          return FALSE;
+       }
+
        value = (byte)value_int;
 
        if ((value & 0xc0) == 0xc0)     /* this is a repeat count byte */
        {
          count = value & 0x3f;         /* extract repeat count from byte */
+
          if ((value_int = fgetc(file)) == EOF)
+         {
+           free(row_buffer);
            return FALSE;
+         }
+
          value = (byte)value_int;
        }
        else
@@ -152,14 +161,17 @@ static boolean PCX_ReadBitmap(FILE *file, struct PCX_Header *pcx, Image *image)
       {
        int i, j, x = 0;
 
-       for(i = 0; i < pcx->bytes_per_line; i++)
+       for (i = 0; i < pcx->bytes_per_line; i++)
        {
          byte value = *src_ptr++;
 
-         for(j = 7; j >= 0; j--)
+         for (j = 7; j >= 0; j--)
          {
            byte bit = (value >> j) & 1;
 
+           if (i * 8 + j >= width)     /* skip padding bits */
+             continue;
+
            bitmap_ptr[x++] |= bit << plane;
          }
        }
@@ -170,12 +182,12 @@ static boolean PCX_ReadBitmap(FILE *file, struct PCX_Header *pcx, Image *image)
       byte *src_ptr = row_buffer;
       int plane;
 
-      for(plane = 0; plane < pcx->color_planes; plane++)
+      for (plane = 0; plane < pcx->color_planes; plane++)
       {
        int x;
 
        dst_ptr = bitmap_ptr + plane;
-       for(x = 0; x < width; x++)
+       for (x = 0; x < width; x++)
        {
          *dst_ptr = *src_ptr++;
          dst_ptr += pcx->color_planes;
@@ -186,6 +198,8 @@ static boolean PCX_ReadBitmap(FILE *file, struct PCX_Header *pcx, Image *image)
     bitmap_ptr += image->bytes_per_row;
   }
 
+  free(row_buffer);
+
   return TRUE;
 }
 
@@ -321,6 +335,7 @@ Image *Read_PCX_to_Image(char *filename)
 #if PCX_DEBUG
   if (options.verbose)
   {
+    printf("\n");
     printf("%s is a %dx%d PC Paintbrush image\n", filename, width, height);
     printf("depth: %d\n", depth);
     printf("bits_per_pixel: %d\n", pcx.bits_per_pixel);
@@ -360,7 +375,6 @@ Image *Read_PCX_to_Image(char *filename)
   if (pcx_depth == 8)
   {
     /* determine number of used colormap entries for 8-bit PCX images */
-    image->rgb.used = 0;
     for (i=0; i<PCX_MAXCOLORS; i++)
       if (image->rgb.color_used[i])
        image->rgb.used++;
@@ -368,7 +382,7 @@ Image *Read_PCX_to_Image(char *filename)
 
 #if PCX_DEBUG
   if (options.verbose)
-    printf("Read_PCX_to_Image: %d colors found\n", image->rgb.used);
+    printf("Read_PCX_to_Image: %d colors in colormap\n", image->rgb.used);
 #endif
 
   return image;
index 08626fcab08584cc38957324a2a5624e8fff9bbe..1bf4ce316f1021e05c602ef9953b0d092f99f109 100644 (file)
    position of the rear pointer is just
        (MAX_TYPES * (rptr - state)) + TYPE_3 == TYPE_3.  */
 
-static long int randtbl[DEG_3 + 1] =
+static long int randtbl_0[DEG_3 + 1] =
 {
   TYPE_3,
   -851904987, -43806228, -2029755270, 1390239686, -1912102820,
@@ -139,6 +139,17 @@ static long int randtbl[DEG_3 + 1] =
   -607508183, -205999574, -1696891592, 1492211999, -1528267240,
   -952028296, -189082757, 362343714, 1424981831, 2039449641,
 };
+static long int randtbl_1[DEG_3 + 1] =
+{
+  TYPE_3,
+  -851904987, -43806228, -2029755270, 1390239686, -1912102820,
+  -485608943, 1969813258, -1590463333, -1944053249, 455935928, 508023712,
+  -1714531963, 1800685987, -2015299881, 654595283, -1149023258,
+  -1470005550, -1143256056, -1325577603, -1568001885, 1275120390,
+  -607508183, -205999574, -1696891592, 1492211999, -1528267240,
+  -952028296, -189082757, 362343714, 1424981831, 2039449641,
+};
+
 
 /* FPTR and RPTR are two pointers into the state info, a front and a rear
    pointer.  These two pointers are always rand_sep places aparts, as they
@@ -150,8 +161,8 @@ static long int randtbl[DEG_3 + 1] =
    in the initialization of randtbl) because the state table pointer is set
    to point to randtbl[1] (as explained below).)  */
 
-static long int *fptr = &randtbl[SEP_3 + 1];
-static long int *rptr = &randtbl[1];
+static long int *fptr[2] = { &randtbl_0[SEP_3 + 1], &randtbl_1[SEP_3 + 1] };
+static long int *rptr[2] = { &randtbl_0[1],         &randtbl_1[1]         };
 
 
 
@@ -165,13 +176,17 @@ static long int *rptr = &randtbl[1];
    indexing every time to find the address of the last element to see if
    the front and rear pointers have wrapped.  */
 
-static long int *state = &randtbl[1];
+static long int *state[2] = { &randtbl_0[1], &randtbl_1[1] };
 
-static int rand_type = TYPE_3;
-static int rand_deg = DEG_3;
-static int rand_sep = SEP_3;
+static int rand_type[2] = { TYPE_3,    TYPE_3  };
+static int rand_deg[2]  = { DEG_3,     DEG_3   };
+static int rand_sep[2]  = { SEP_3,     SEP_3   };
 
-static long int *end_ptr = &randtbl[sizeof(randtbl) / sizeof(randtbl[0])];
+static long int *end_ptr[2] =
+{
+  &randtbl_0[sizeof(randtbl_0) / sizeof(randtbl_0[0])],
+  &randtbl_1[sizeof(randtbl_1) / sizeof(randtbl_1[0])]
+};
 
 /* Initialize the random number generator based on the given seed.  If the
    type is the trivial no-state-information type, just remember the seed.
@@ -182,18 +197,22 @@ static long int *end_ptr = &randtbl[sizeof(randtbl) / sizeof(randtbl[0])];
    introduced by the L.C.R.N.G.  Note that the initialization of randtbl[]
    for default usage relies on values produced by this routine.  */
 
-void srandom_linux_libc(unsigned int x)
+void srandom_linux_libc(int nr, unsigned int x)
 {
-  state[0] = x;
-  if (rand_type != TYPE_0)
+  state[nr][0] = x;
+
+  if (rand_type[nr] != TYPE_0)
   {
     register long int i;
-    for (i = 1; i < rand_deg; ++i)
-      state[i] = (1103515145 * state[i - 1]) + 12345;
-    fptr = &state[rand_sep];
-    rptr = &state[0];
-    for (i = 0; i < 10 * rand_deg; ++i)
-      (void) random_linux_libc();
+
+    for (i = 1; i < rand_deg[nr]; ++i)
+      state[nr][i] = (1103515145 * state[nr][i - 1]) + 12345;
+
+    fptr[nr] = &state[nr][rand_sep[nr]];
+    rptr[nr] = &state[nr][0];
+
+    for (i = 0; i < 10 * rand_deg[nr]; ++i)
+      random_linux_libc(nr);
   }
 }
 
@@ -208,31 +227,35 @@ void srandom_linux_libc(unsigned int x)
    rear pointers can't wrap on the same call by not testing the rear
    pointer if the front one has wrapped.  Returns a 31-bit random number.  */
 
-long int random_linux_libc()
+long int random_linux_libc(int nr)
 {
-  if (rand_type == TYPE_0)
+  if (rand_type[nr] == TYPE_0)
   {
-    state[0] = ((state[0] * 1103515245) + 12345) & LONG_MAX;
-    return state[0];
+    state[nr][0] = ((state[nr][0] * 1103515245) + 12345) & LONG_MAX;
+    return state[nr][0];
   }
   else
   {
     long int i;
-    *fptr += *rptr;
+
+    *fptr[nr] += *rptr[nr];
+
     /* Chucking least random bit.  */
-    i = (*fptr >> 1) & LONG_MAX;
-    ++fptr;
-    if (fptr >= end_ptr)
+    i = (*fptr[nr] >> 1) & LONG_MAX;
+    fptr[nr]++;
+
+    if (fptr[nr] >= end_ptr[nr])
     {
-      fptr = state;
-      ++rptr;
+      fptr[nr] = state[nr];
+      rptr[nr]++;
     }
     else
     {
-      ++rptr;
-      if (rptr >= end_ptr)
-       rptr = state;
+      rptr[nr]++;
+      if (rptr[nr] >= end_ptr[nr])
+       rptr[nr] = state[nr];
     }
+
     return i;
   }
 }
index 540bc6679c885cf910b8f0f7418ad2493b7fdfea..ed01196dee47358e80d7de178bc7b5f45cee0950 100644 (file)
@@ -14,7 +14,7 @@
 #ifndef RANDOM_H
 #define RANDOM_H
 
-void srandom_linux_libc(unsigned int);
-long int random_linux_libc(void);
+void srandom_linux_libc(int, unsigned int);
+long int random_linux_libc(int);
 
 #endif
index 212ce1b86c59493753cf8262050c547b9e3b1ae1..95ef6eef6e9d97dcf3f724c45a1febc7af3d2022 100644 (file)
@@ -26,9 +26,9 @@
 /* functions from SGE library */
 inline void sge_Line(SDL_Surface *, Sint16, Sint16, Sint16, Sint16, Uint32);
 
-#ifdef PLATFORM_WIN32
+/* #ifdef PLATFORM_WIN32 */
 #define FULLSCREEN_BUG
-#endif
+/* #endif */
 
 /* stuff needed to work around SDL/Windows fullscreen drawing bug */
 static int fullscreen_width;
@@ -40,6 +40,8 @@ static int video_yoffset;
 
 inline void SDLInitVideoDisplay(void)
 {
+  putenv("SDL_VIDEO_CENTERED=1");
+
   /* initialize SDL video */
   if (SDL_InitSubSystem(SDL_INIT_VIDEO) < 0)
     Error(ERR_EXIT, "SDL_InitSubSystem() failed: %s", SDL_GetError());
@@ -170,10 +172,38 @@ inline boolean SDLSetVideoMode(DrawBuffer **backbuffer, boolean fullscreen)
   return success;
 }
 
+inline void SDLCreateBitmapContent(Bitmap *new_bitmap,
+                                  int width, int height, int depth)
+{
+  SDL_Surface *surface_tmp, *surface_native;
+
+  if ((surface_tmp = SDL_CreateRGBSurface(SURFACE_FLAGS, width, height, depth,
+                                         0, 0, 0, 0))
+      == NULL)
+    Error(ERR_EXIT, "SDL_CreateRGBSurface() failed: %s", SDL_GetError());
+
+  if ((surface_native = SDL_DisplayFormat(surface_tmp)) == NULL)
+    Error(ERR_EXIT, "SDL_DisplayFormat() failed: %s", SDL_GetError());
+
+  SDL_FreeSurface(surface_tmp);
+
+  new_bitmap->surface = surface_native;
+}
+
+inline void SDLFreeBitmapPointers(Bitmap *bitmap)
+{
+  if (bitmap->surface)
+    SDL_FreeSurface(bitmap->surface);
+  if (bitmap->surface_masked)
+    SDL_FreeSurface(bitmap->surface_masked);
+  bitmap->surface = NULL;
+  bitmap->surface_masked = NULL;
+}
+
 inline 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 copy_mode)
+                       int dst_x, int dst_y, int mask_mode)
 {
   Bitmap *real_dst_bitmap = (dst_bitmap == window ? backbuffer : dst_bitmap);
   SDL_Rect src_rect, dst_rect;
@@ -205,7 +235,7 @@ inline void SDLCopyArea(Bitmap *src_bitmap, Bitmap *dst_bitmap,
   dst_rect.h = height;
 
   if (src_bitmap != backbuffer || dst_bitmap != window)
-    SDL_BlitSurface((copy_mode == SDLCOPYAREA_MASKED ?
+    SDL_BlitSurface((mask_mode == BLIT_MASKED ?
                     src_bitmap->surface_masked : src_bitmap->surface),
                    &src_rect, real_dst_bitmap->surface, &dst_rect);
 
@@ -214,13 +244,15 @@ inline void SDLCopyArea(Bitmap *src_bitmap, Bitmap *dst_bitmap,
 }
 
 inline void SDLFillRectangle(Bitmap *dst_bitmap, int x, int y,
-                            int width, int height, unsigned int color)
+                            int width, int height, Uint32 color)
 {
   Bitmap *real_dst_bitmap = (dst_bitmap == window ? backbuffer : dst_bitmap);
   SDL_Rect rect;
-  unsigned int color_r = (color >> 16) && 0xff;
-  unsigned int color_g = (color >>  8) && 0xff;
-  unsigned int color_b = (color >>  0) && 0xff;
+#if 0
+  unsigned int color_r = (color >> 16) & 0xff;
+  unsigned int color_g = (color >>  8) & 0xff;
+  unsigned int color_b = (color >>  0) & 0xff;
+#endif
 
 #ifdef FULLSCREEN_BUG
   if (dst_bitmap == backbuffer || dst_bitmap == window)
@@ -235,22 +267,28 @@ inline void SDLFillRectangle(Bitmap *dst_bitmap, int x, int y,
   rect.w = width;
   rect.h = height;
 
+#if 1
+  SDL_FillRect(real_dst_bitmap->surface, &rect, color);
+#else
   SDL_FillRect(real_dst_bitmap->surface, &rect,
               SDL_MapRGB(real_dst_bitmap->surface->format,
                          color_r, color_g, color_b));
+#endif
 
   if (dst_bitmap == window)
     SDL_UpdateRect(backbuffer->surface, x, y, width, height);
 }
 
 inline void SDLDrawSimpleLine(Bitmap *dst_bitmap, int from_x, int from_y,
-                             int to_x, int to_y, unsigned int color)
+                             int to_x, int to_y, Uint32 color)
 {
   SDL_Surface *surface = dst_bitmap->surface;
   SDL_Rect rect;
+#if 0
   unsigned int color_r = (color >> 16) & 0xff;
   unsigned int color_g = (color >>  8) & 0xff;
   unsigned int color_b = (color >>  0) & 0xff;
+#endif
 
   if (from_x > to_x)
     swap_numbers(&from_x, &to_x);
@@ -271,8 +309,12 @@ inline void SDLDrawSimpleLine(Bitmap *dst_bitmap, int from_x, int from_y,
   }
 #endif
 
+#if 1
+  SDL_FillRect(surface, &rect, color);
+#else
   SDL_FillRect(surface, &rect,
                SDL_MapRGB(surface->format, color_r, color_g, color_b));
+#endif
 }
 
 inline void SDLDrawLine(Bitmap *dst_bitmap, int from_x, int from_y,
@@ -321,12 +363,12 @@ inline void SDLDrawLines(SDL_Surface *surface, struct XY *points,
 }
 #endif
 
-inline Pixel SDLGetPixel(Bitmap *dst_bitmap, int x, int y)
+inline Pixel SDLGetPixel(Bitmap *src_bitmap, int x, int y)
 {
-  SDL_Surface *surface = dst_bitmap->surface;
+  SDL_Surface *surface = src_bitmap->surface;
 
 #ifdef FULLSCREEN_BUG
-  if (dst_bitmap == backbuffer || dst_bitmap == window)
+  if (src_bitmap == backbuffer || src_bitmap == window)
   {
     x += video_xoffset;
     y += video_yoffset;
@@ -377,7 +419,7 @@ inline Pixel SDLGetPixel(Bitmap *dst_bitmap, int x, int y)
 
 
 /* ========================================================================= */
-/* The following functions have been taken from the SGE library              */
+/* The following functions were taken from the SGE library                   */
 /* (SDL Graphics Extension Library) by Anders Lindström                      */
 /* http://www.etek.chalmers.se/~e8cal1/sge/index.html                        */
 /* ========================================================================= */
@@ -506,9 +548,9 @@ void sge_PutPixel(SDL_Surface *surface, Sint16 x, Sint16 y, Uint32 color)
 }
 
 void sge_PutPixelRGB(SDL_Surface *surface, Sint16 x, Sint16 y,
-                 Uint8 R, Uint8 G, Uint8 B)
+                 Uint8 r, Uint8 g, Uint8 b)
 {
-  sge_PutPixel(surface, x, y, SDL_MapRGB(surface->format, R, G, B));
+  sge_PutPixel(surface, x, y, SDL_MapRGB(surface->format, r, g, b));
 }
 
 Sint32 sge_CalcYPitch(SDL_Surface *dest, Sint16 y)
@@ -822,6 +864,367 @@ void sge_LineRGB(SDL_Surface *Surface, Sint16 x1, Sint16 y1, Sint16 x2,
   sge_Line(Surface, x1, y1, x2, y2, SDL_MapRGB(Surface->format, R, G, B));
 }
 
+inline void SDLPutPixel(Bitmap *dst_bitmap, int x, int y, Pixel pixel)
+{
+#ifdef FULLSCREEN_BUG
+  if (dst_bitmap == backbuffer || dst_bitmap == window)
+  {
+    x += video_xoffset;
+    y += video_yoffset;
+  }
+#endif
+
+  sge_PutPixel(dst_bitmap->surface, x, y, pixel);
+}
+
+
+/*
+  -----------------------------------------------------------------------------
+  quick (no, it's slow) and dirty hack to "invert" rectangle inside SDL surface
+  -----------------------------------------------------------------------------
+*/
+
+inline 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);
+    }
+  }
+}
+
+inline void SDLCopyInverseMasked(Bitmap *src_bitmap, Bitmap *dst_bitmap,
+                                int src_x, int src_y, int width, int height,
+                                int dst_x, int dst_y)
+{
+  int x, y;
+
+  for (y=0; y < height; y++)
+  {
+    for (x=0; x < width; x++)
+    {
+      Uint32 pixel = SDLGetPixel(src_bitmap, src_x + x, src_y + y);
+
+      if (pixel != BLACK_PIXEL)
+       SDLPutPixel(dst_bitmap, dst_x + x, dst_y + y, BLACK_PIXEL);
+    }
+  }
+}
+
+
+/* ========================================================================= */
+/* The following functions were taken from the SDL_gfx library version 2.0.3 */
+/* (Rotozoomer) by Andreas Schiffler                                         */
+/* http://www.ferzkopp.net/Software/SDL_gfx-2.0/index.html                   */
+/* ========================================================================= */
+
+/*
+  -----------------------------------------------------------------------------
+  32 bit zoomer
+
+  zoomes 32bit RGBA/ABGR 'src' surface to 'dst' surface.
+  -----------------------------------------------------------------------------
+*/
+
+typedef struct
+{
+  Uint8 r;
+  Uint8 g;
+  Uint8 b;
+  Uint8 a;
+} tColorRGBA;
+
+int zoomSurfaceRGBA(SDL_Surface *src, SDL_Surface *dst)
+{
+  int x, y, sx, sy, *sax, *say, *csax, *csay, csx, csy;
+  tColorRGBA *sp, *csp, *dp;
+  int sgap, dgap;
+
+  /* variable setup */
+  sx = (int) (65536.0 * (float) src->w / (float) dst->w);
+  sy = (int) (65536.0 * (float) src->h / (float) dst->h);
+
+  /* allocate memory for row increments */
+  sax = (int *)checked_malloc((dst->w + 1) * sizeof(Uint32));
+  say = (int *)checked_malloc((dst->h + 1) * sizeof(Uint32));
+
+  /* precalculate row increments */
+  csx = 0;
+  csax = sax;
+  for (x = 0; x <= dst->w; x++)
+  {
+    *csax = csx;
+    csax++;
+    csx &= 0xffff;
+    csx += sx;
+  }
+
+  csy = 0;
+  csay = say;
+  for (y = 0; y <= dst->h; y++)
+  {
+    *csay = csy;
+    csay++;
+    csy &= 0xffff;
+    csy += sy;
+  }
+
+  /* pointer setup */
+  sp = csp = (tColorRGBA *) src->pixels;
+  dp = (tColorRGBA *) dst->pixels;
+  sgap = src->pitch - src->w * 4;
+  dgap = dst->pitch - dst->w * 4;
+
+  csay = say;
+  for (y = 0; y < dst->h; y++)
+  {
+    sp = csp;
+    csax = sax;
+
+    for (x = 0; x < dst->w; x++)
+    {
+      /* draw */
+      *dp = *sp;
+
+      /* advance source pointers */
+      csax++;
+      sp += (*csax >> 16);
+
+      /* advance destination pointer */
+      dp++;
+    }
+
+    /* advance source pointer */
+    csay++;
+    csp = (tColorRGBA *) ((Uint8 *) csp + (*csay >> 16) * src->pitch);
+
+    /* advance destination pointers */
+    dp = (tColorRGBA *) ((Uint8 *) dp + dgap);
+  }
+
+  free(sax);
+  free(say);
+
+  return 0;
+}
+
+/*
+  -----------------------------------------------------------------------------
+  8 bit zoomer
+
+  zoomes 8 bit palette/Y 'src' surface to 'dst' surface
+  -----------------------------------------------------------------------------
+*/
+
+int zoomSurfaceY(SDL_Surface * src, SDL_Surface * dst)
+{
+  Uint32 x, y, sx, sy, *sax, *say, *csax, *csay, csx, csy;
+  Uint8 *sp, *dp, *csp;
+  int dgap;
+
+  /* variable setup */
+  sx = (Uint32) (65536.0 * (float) src->w / (float) dst->w);
+  sy = (Uint32) (65536.0 * (float) src->h / (float) dst->h);
+
+  /* allocate memory for row increments */
+  sax = (Uint32 *)checked_malloc(dst->w * sizeof(Uint32));
+  say = (Uint32 *)checked_malloc(dst->h * sizeof(Uint32));
+
+  /* precalculate row increments */
+  csx = 0;
+  csax = sax;
+  for (x = 0; x < dst->w; x++)
+  {
+    csx += sx;
+    *csax = (csx >> 16);
+    csx &= 0xffff;
+    csax++;
+  }
+
+  csy = 0;
+  csay = say;
+  for (y = 0; y < dst->h; y++)
+  {
+    csy += sy;
+    *csay = (csy >> 16);
+    csy &= 0xffff;
+    csay++;
+  }
+
+  csx = 0;
+  csax = sax;
+  for (x = 0; x < dst->w; x++)
+  {
+    csx += (*csax);
+    csax++;
+  }
+
+  csy = 0;
+  csay = say;
+  for (y = 0; y < dst->h; y++)
+  {
+    csy += (*csay);
+    csay++;
+  }
+
+  /* pointer setup */
+  sp = csp = (Uint8 *) src->pixels;
+  dp = (Uint8 *) dst->pixels;
+  dgap = dst->pitch - dst->w;
+
+  /* draw */
+  csay = say;
+  for (y = 0; y < dst->h; y++)
+  {
+    csax = sax;
+    sp = csp;
+    for (x = 0; x < dst->w; x++)
+    {
+      /* draw */
+      *dp = *sp;
+
+      /* advance source pointers */
+      sp += (*csax);
+      csax++;
+
+      /* advance destination pointer */
+      dp++;
+    }
+
+    /* advance source pointer (for row) */
+    csp += ((*csay) * src->pitch);
+    csay++;
+
+    /* advance destination pointers */
+    dp += dgap;
+  }
+
+  free(sax);
+  free(say);
+
+  return 0;
+}
+
+/*
+  -----------------------------------------------------------------------------
+  zoomSurface()
+
+  Zoomes a 32bit or 8bit 'src' surface to newly created 'dst' surface.
+  'zoomx' and 'zoomy' are scaling factors for width and height.
+  If 'smooth' is 1 then the destination 32bit surface is anti-aliased.
+  If the surface is not 8bit or 32bit RGBA/ABGR it will be converted
+  into a 32bit RGBA format on the fly.
+  -----------------------------------------------------------------------------
+*/
+
+SDL_Surface *zoomSurface(SDL_Surface *src, int dst_width, int dst_height)
+{
+  SDL_Surface *zoom_src = NULL;
+  SDL_Surface *zoom_dst = NULL;
+  boolean is_converted = FALSE;
+  boolean is_32bit;
+  int i;
+
+  if (src == NULL)
+    return NULL;
+
+  /* determine if source surface is 32 bit or 8 bit */
+  is_32bit = (src->format->BitsPerPixel == 32);
+
+  if (is_32bit || src->format->BitsPerPixel == 8)
+  {
+    /* use source surface 'as is' */
+    zoom_src = src;
+  }
+  else
+  {
+    /* new source surface is 32 bit with a defined RGB ordering */
+    zoom_src = SDL_CreateRGBSurface(SDL_SWSURFACE, src->w, src->h, 32,
+                                   0x000000ff, 0x0000ff00, 0x00ff0000, 0);
+    SDL_BlitSurface(src, NULL, zoom_src, NULL);
+    is_32bit = TRUE;
+    is_converted = TRUE;
+  }
+
+  /* allocate surface to completely contain the zoomed surface */
+  if (is_32bit)
+  {
+    /* target surface is 32 bit with source RGBA/ABGR ordering */
+    zoom_dst = SDL_CreateRGBSurface(SDL_SWSURFACE, dst_width, dst_height, 32,
+                                   zoom_src->format->Rmask,
+                                   zoom_src->format->Gmask,
+                                   zoom_src->format->Bmask, 0);
+  }
+  else
+  {
+    /* target surface is 8 bit */
+    zoom_dst = SDL_CreateRGBSurface(SDL_SWSURFACE, dst_width, dst_height, 8,
+                                   0, 0, 0, 0);
+  }
+
+  /* lock source surface */
+  SDL_LockSurface(zoom_src);
+
+  /* check which kind of surface we have */
+  if (is_32bit)
+  {
+    /* call the 32 bit transformation routine to do the zooming */
+    zoomSurfaceRGBA(zoom_src, zoom_dst);
+  }
+  else
+  {
+    /* copy palette */
+    for (i=0; i < zoom_src->format->palette->ncolors; i++)
+      zoom_dst->format->palette->colors[i] =
+       zoom_src->format->palette->colors[i];
+    zoom_dst->format->palette->ncolors = zoom_src->format->palette->ncolors;
+
+    /* call the 8 bit transformation routine to do the zooming */
+    zoomSurfaceY(zoom_src, zoom_dst);
+  }
+
+  /* unlock source surface */
+  SDL_UnlockSurface(zoom_src);
+
+  /* free temporary surface */
+  if (is_converted)
+    SDL_FreeSurface(zoom_src);
+
+  /* return destination surface */
+  return zoom_dst;
+}
+
+void SDLZoomBitmap(Bitmap *src_bitmap, Bitmap *dst_bitmap)
+{
+  SDL_Surface *sdl_surface_tmp;
+  int dst_width = dst_bitmap->width;
+  int dst_height = dst_bitmap->height;
+
+  /* throw away old destination surface */
+  SDL_FreeSurface(dst_bitmap->surface);
+
+  /* create zoomed temporary surface from source surface */
+  sdl_surface_tmp = zoomSurface(src_bitmap->surface, dst_width, dst_height);
+
+  /* create native format destination surface from zoomed temporary surface */
+  dst_bitmap->surface = SDL_DisplayFormat(sdl_surface_tmp);
+
+  /* free temporary surface */
+  SDL_FreeSurface(sdl_surface_tmp);
+}
+
+
+/* ========================================================================= */
+/* load image to bitmap                                                      */
+/* ========================================================================= */
+
 Bitmap *SDLLoadImage(char *filename)
 {
   Bitmap *new_bitmap = CreateBitmapStruct();
@@ -860,12 +1263,45 @@ Bitmap *SDLLoadImage(char *filename)
 }
 
 
+/* ------------------------------------------------------------------------- */
+/* custom cursor fuctions                                                    */
+/* ------------------------------------------------------------------------- */
+
+static SDL_Cursor *create_cursor(struct MouseCursorInfo *cursor_info)
+{
+  return SDL_CreateCursor(cursor_info->data, cursor_info->mask,
+                         cursor_info->width, cursor_info->height,
+                         cursor_info->hot_x, cursor_info->hot_y);
+}
+
+void SDLSetMouseCursor(struct MouseCursorInfo *cursor_info)
+{
+  static struct MouseCursorInfo *last_cursor_info = NULL;
+  static SDL_Cursor *cursor_default = NULL;
+  static SDL_Cursor *cursor_current = NULL;
+
+  if (cursor_default == NULL)
+    cursor_default = SDL_GetCursor();
+
+  if (cursor_info != NULL && cursor_info != last_cursor_info)
+  {
+    cursor_current = create_cursor(cursor_info);
+    last_cursor_info = cursor_info;
+  }
+
+  SDL_SetCursor(cursor_info ? cursor_current : cursor_default);
+}
+
+
 /* ========================================================================= */
 /* audio functions                                                           */
 /* ========================================================================= */
 
 inline void SDLOpenAudio(void)
 {
+  if (strcmp(setup.system.sdl_audiodriver, ARG_DEFAULT) != 0)
+    putenv(getStringCat2("SDL_AUDIODRIVER=", setup.system.sdl_audiodriver));
+
   if (SDL_InitSubSystem(SDL_INIT_AUDIO) < 0)
   {
     Error(ERR_WARN, "SDL_InitSubSystem() failed: %s", SDL_GetError());
@@ -874,7 +1310,7 @@ inline void SDLOpenAudio(void)
 
   if (Mix_OpenAudio(DEFAULT_AUDIO_SAMPLE_RATE, MIX_DEFAULT_FORMAT,
                    AUDIO_NUM_CHANNELS_STEREO,
-                   DEFAULT_AUDIO_FRAGMENT_SIZE) < 0)
+                   setup.system.audio_fragment_size) < 0)
   {
     Error(ERR_WARN, "Mix_OpenAudio() failed: %s", SDL_GetError());
     return;
@@ -926,14 +1362,14 @@ inline void SDLNextEvent(Event *event)
   }
   else if (event->type == EVENT_MOTIONNOTIFY)
   {
-    if (((ButtonEvent *)event)->x > video_xoffset)
-      ((ButtonEvent *)event)->x -= video_xoffset;
+    if (((MotionEvent *)event)->x > video_xoffset)
+      ((MotionEvent *)event)->x -= video_xoffset;
     else
-      ((ButtonEvent *)event)->x = 0;
-    if (((ButtonEvent *)event)->y > video_yoffset)
-      ((ButtonEvent *)event)->y -= video_yoffset;
+      ((MotionEvent *)event)->x = 0;
+    if (((MotionEvent *)event)->y > video_yoffset)
+      ((MotionEvent *)event)->y -= video_yoffset;
     else
-      ((ButtonEvent *)event)->y = 0;
+      ((MotionEvent *)event)->y = 0;
   }
 #endif
 }
index 64db7795c9df1094f8a18a5ff5e942b29d919a5f..8ad6308bc823dc1d368246615685852facd22689 100644 (file)
 
 #define SURFACE_FLAGS          (SDL_SWSURFACE)
 
-#define SDLCOPYAREA_OPAQUE     0
-#define SDLCOPYAREA_MASKED     1
-
 /* system dependent definitions */
 
 #define TARGET_STRING          "SDL"
 #define FULLSCREEN_STATUS      FULLSCREEN_AVAILABLE
 
+#define CURSOR_MAX_WIDTH       32
+#define CURSOR_MAX_HEIGHT      32
+
 
 /* SDL type definitions */
 
@@ -38,8 +38,10 @@ typedef struct SDLSurfaceInfo        Bitmap;
 typedef struct SDLSurfaceInfo  DrawBuffer;
 typedef struct SDLSurfaceInfo  DrawWindow;
 typedef Uint32                 Pixel;
+typedef SDL_Cursor            *Cursor;
 
 typedef SDLKey                 Key;
+typedef unsigned int           KeyMod;
 
 typedef SDL_Event              Event;
 typedef SDL_MouseButtonEvent   ButtonEvent;
@@ -69,6 +71,15 @@ struct SDLSurfaceInfo
   GC stored_clip_gc;
 };
 
+struct MouseCursorInfo
+{
+  int width, height;
+  int hot_x, hot_y;
+
+  char data[CURSOR_MAX_WIDTH * CURSOR_MAX_HEIGHT / 8];
+  char mask[CURSOR_MAX_WIDTH * CURSOR_MAX_HEIGHT / 8];
+};
+
 struct XY
 {
   short x, y;
@@ -79,6 +90,9 @@ struct XY
 
 #define None                   0L
 
+#define BLACK_PIXEL            0x000000
+#define WHITE_PIXEL            0xffffff
+
 #define EVENT_BUTTONPRESS      SDL_MOUSEBUTTONDOWN
 #define EVENT_BUTTONRELEASE    SDL_MOUSEBUTTONUP
 #define EVENT_MOTIONNOTIFY     SDL_MOUSEMOTION
@@ -318,20 +332,46 @@ struct XY
 #define KSYM_FKEY_LAST         KSYM_F15
 #define KSYM_NUM_FKEYS         (KSYM_FKEY_LAST - KSYM_FKEY_FIRST + 1)
 
+#define KMOD_None              None
+#define KMOD_Shift_L           KMOD_LSHIFT
+#define KMOD_Shift_R           KMOD_RSHIFT
+#define KMOD_Control_L         KMOD_LCTRL
+#define KMOD_Control_R         KMOD_RCTRL
+#define KMOD_Meta_L            KMOD_LMETA
+#define KMOD_Meta_R            KMOD_RMETA
+#define KMOD_Alt_L             KMOD_LALT
+#define KMOD_Alt_R             KMOD_RALT
+
+#define KMOD_Shift             (KMOD_Shift_L   | KMOD_Shift_R)
+#define KMOD_Control           (KMOD_Control_L | KMOD_Control_R)
+#define KMOD_Meta              (KMOD_Meta_L    | KMOD_Meta_R)
+#define KMOD_Alt               (KMOD_Alt_L     | KMOD_Alt_R)
+
 
 /* SDL function definitions */
 
 inline void SDLInitVideoDisplay(void);
 inline void SDLInitVideoBuffer(DrawBuffer **, DrawWindow **, boolean);
 inline boolean SDLSetVideoMode(DrawBuffer **, boolean);
+inline void SDLCreateBitmapContent(Bitmap *, int, int, int);
+inline void SDLFreeBitmapPointers(Bitmap *);
 inline void SDLCopyArea(Bitmap *, Bitmap *, int, int, int, int, int, int, int);
-inline void SDLFillRectangle(Bitmap *, int, int, int, int, unsigned int);
-inline void SDLDrawSimpleLine(Bitmap *, int, int, int, int, unsigned int);
+inline void SDLFillRectangle(Bitmap *, int, int, int, int, Uint32);
+inline void SDLDrawSimpleLine(Bitmap *, int, int, int, int, Uint32);
 inline void SDLDrawLine(Bitmap *, int, int, int, int, Uint32);
 inline Pixel SDLGetPixel(Bitmap *, int, int);
+inline void SDLPutPixel(Bitmap *, int, int, Pixel);
+
+inline void SDLInvertArea(Bitmap *, int, int, int, int, Uint32);
+inline void SDLCopyInverseMasked(Bitmap *, Bitmap *, int, int, int, int,
+                                int, int);
+
+void SDLZoomBitmap(Bitmap *, Bitmap *);
 
 Bitmap *SDLLoadImage(char *);
 
+void SDLSetMouseCursor(struct MouseCursorInfo *);
+
 inline void SDLOpenAudio(void);
 inline void SDLCloseAudio(void);
 
index c6450a664319e8b237c2b4bce0493aebc9d76cb3..a99c7a83fa80178fbcb3638091dbc8eea39d431a 100644 (file)
@@ -21,6 +21,7 @@
 #include "joystick.h"
 #include "text.h"
 #include "misc.h"
+#include "hash.h"
 
 /* file names and filename extensions */
 #if !defined(PLATFORM_MSDOS)
@@ -97,25 +98,25 @@ static char *levelclass_desc[NUM_LEVELCLASS_DESC] =
 
 #define MAX_COOKIE_LEN                 256
 
-#define ARTWORKINFO_FILENAME(type)     ((type) == TREE_TYPE_GRAPHICS_DIR ? \
-                                        GRAPHICSINFO_FILENAME :            \
-                                        (type) == TREE_TYPE_SOUNDS_DIR ?   \
-                                        SOUNDSINFO_FILENAME :              \
-                                        (type) == TREE_TYPE_MUSIC_DIR ?    \
+#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) == TREE_TYPE_GRAPHICS_DIR ? \
-                                        GRAPHICS_DIRECTORY :               \
-                                        (type) == TREE_TYPE_SOUNDS_DIR ?   \
-                                        SOUNDS_DIRECTORY :                 \
-                                        (type) == TREE_TYPE_MUSIC_DIR ?    \
+#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) == TREE_TYPE_GRAPHICS_DIR ? \
-                                        options.graphics_directory :       \
-                                        (type) == TREE_TYPE_SOUNDS_DIR ?   \
-                                        options.sounds_directory :         \
-                                        (type) == TREE_TYPE_MUSIC_DIR ?    \
+#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 : "")
 
 
@@ -170,7 +171,7 @@ static char *getTapeDir(char *level_subdir)
 static char *getScoreDir(char *level_subdir)
 {
   static char *score_dir = NULL;
-  char *data_dir = options.rw_base_directory;
+  char *data_dir = getCommonDataDir();
   char *score_subdir = SCORES_DIRECTORY;
 
   if (score_dir)
@@ -267,6 +268,23 @@ static char *getDefaultMusicDir(char *music_subdir)
   return music_dir;
 }
 
+static char *getDefaultArtworkSet(int type)
+{
+  return (type == TREE_TYPE_GRAPHICS_DIR ? GRAPHICS_SUBDIR :
+         type == TREE_TYPE_SOUNDS_DIR   ? SOUNDS_SUBDIR   :
+         type == TREE_TYPE_MUSIC_DIR    ? MUSIC_SUBDIR    : "");
+}
+
+static char *getDefaultArtworkDir(int type)
+{
+  return (type == TREE_TYPE_GRAPHICS_DIR ?
+         getDefaultGraphicsDir(GRAPHICS_SUBDIR) :
+         type == TREE_TYPE_SOUNDS_DIR ?
+         getDefaultSoundsDir(SOUNDS_SUBDIR) :
+         type == TREE_TYPE_MUSIC_DIR ?
+         getDefaultMusicDir(MUSIC_SUBDIR) : "");
+}
+
 static char *getUserGraphicsDir()
 {
   static char *usergraphics_dir = NULL;
@@ -297,6 +315,79 @@ static char *getUserMusicDir()
   return usermusic_dir;
 }
 
+static char *getSetupArtworkDir(TreeInfo *ti)
+{
+  static char *artwork_dir = NULL;
+
+  if (artwork_dir != NULL)
+    free(artwork_dir);
+
+  artwork_dir = getPath2(ti->basepath, ti->fullpath);
+
+  return artwork_dir;
+}
+
+void setLevelArtworkDir(TreeInfo *ti)
+{
+  char **artwork_path_ptr, **artwork_set_ptr;
+  TreeInfo *level_artwork;
+
+  if (ti == NULL || leveldir_current == NULL)
+    return;
+
+  artwork_path_ptr = &(LEVELDIR_ARTWORK_PATH(leveldir_current, ti->type));
+  artwork_set_ptr  = &(LEVELDIR_ARTWORK_SET( leveldir_current, ti->type));
+
+  if (*artwork_path_ptr != NULL)
+    free(*artwork_path_ptr);
+
+  if ((level_artwork = getTreeInfoFromIdentifier(ti, *artwork_set_ptr)))
+    *artwork_path_ptr = getStringCopy(getSetupArtworkDir(level_artwork));
+  else
+  {
+    /* No (or non-existing) artwork configured in "levelinfo.conf". This would
+       normally result in using the artwork configured in the setup menu. But
+       if an artwork subdirectory exists (which might contain custom artwork
+       or an artwork configuration file), this level artwork must be treated
+       as relative to the default "classic" artwork, not to the artwork that
+       is currently configured in the setup menu. */
+
+    char *dir = getPath2(getCurrentLevelDir(), ARTWORK_DIRECTORY(ti->type));
+
+    if (*artwork_set_ptr != NULL)
+      free(*artwork_set_ptr);
+
+    if (fileExists(dir))
+    {
+      *artwork_path_ptr = getStringCopy(getDefaultArtworkDir(ti->type));
+      *artwork_set_ptr = getStringCopy(getDefaultArtworkSet(ti->type));
+    }
+    else
+    {
+      *artwork_path_ptr = getStringCopy(UNDEFINED_FILENAME);
+      *artwork_set_ptr = NULL;
+    }
+
+    free(dir);
+  }
+}
+
+inline static char *getLevelArtworkSet(int type)
+{
+  if (leveldir_current == NULL)
+    return NULL;
+
+  return LEVELDIR_ARTWORK_SET(leveldir_current, type);
+}
+
+inline static char *getLevelArtworkDir(int type)
+{
+  if (leveldir_current == NULL)
+    return UNDEFINED_FILENAME;
+
+  return LEVELDIR_ARTWORK_PATH(leveldir_current, type);
+}
+
 char *getLevelFilename(int nr)
 {
   static char *filename = NULL;
@@ -305,7 +396,11 @@ char *getLevelFilename(int nr)
   if (filename != NULL)
     free(filename);
 
-  sprintf(basename, "%03d.%s", nr, LEVELFILE_EXTENSION);
+  if (nr < 0)
+    sprintf(basename, "template.%s", LEVELFILE_EXTENSION);
+  else
+    sprintf(basename, "%03d.%s", nr, LEVELFILE_EXTENSION);
+
   filename = getPath2(getCurrentLevelDir(), basename);
 
   return filename;
@@ -351,21 +446,9 @@ char *getSetupFilename()
   return filename;
 }
 
-static char *getSetupArtworkDir(TreeInfo *ti)
-{
-  static char *artwork_dir = NULL;
-
-  if (artwork_dir != NULL)
-    free(artwork_dir);
-
-  artwork_dir = getPath2(ti->basepath, ti->fullpath);
-
-  return artwork_dir;
-}
-
 static char *getCorrectedImageBasename(char *basename)
 {
-  char *result = basename;
+  char *basename_corrected = basename;
 
 #if defined(PLATFORM_MSDOS)
   if (program.filename_prefix != NULL)
@@ -373,25 +456,31 @@ static char *getCorrectedImageBasename(char *basename)
     int prefix_len = strlen(program.filename_prefix);
 
     if (strncmp(basename, program.filename_prefix, prefix_len) == 0)
-      result = &basename[prefix_len];
-  }
-#endif
+      basename_corrected = &basename[prefix_len];
 
-  return result;
-}
+    /* if corrected filename is still longer than standard MS-DOS filename
+       size (8 characters + 1 dot + 3 characters file extension), shorten
+       filename by writing file extension after 8th basename character */
+    if (strlen(basename_corrected) > 8+1+3)
+    {
+      static char *msdos_filename = NULL;
 
-static boolean fileExists(char *filename)
-{
-#if 0
-  printf("checking file '%s'\n", filename);
+      if (msdos_filename != NULL)
+       free(msdos_filename);
+
+      msdos_filename = getStringCopy(basename_corrected);
+      strncpy(&msdos_filename[8], &basename[strlen(basename) - 1+3], 1+3 + 1);
+    }
+  }
 #endif
 
-  return (access(filename, F_OK) == 0);
+  return basename_corrected;
 }
 
 char *getCustomImageFilename(char *basename)
 {
   static char *filename = NULL;
+  boolean skip_setup_artwork = FALSE;
 
   if (filename != NULL)
     free(filename);
@@ -404,19 +493,42 @@ char *getCustomImageFilename(char *basename)
     filename = getPath3(getCurrentLevelDir(), GRAPHICS_DIRECTORY, basename);
     if (fileExists(filename))
       return filename;
+
+    free(filename);
+
+    /* check if there is special artwork configured in level series config */
+    if (getLevelArtworkSet(ARTWORK_TYPE_GRAPHICS) != NULL)
+    {
+      /* 2nd try: look for special artwork configured in level series config */
+      filename = getPath2(getLevelArtworkDir(ARTWORK_TYPE_GRAPHICS), basename);
+      if (fileExists(filename))
+       return filename;
+
+      free(filename);
+
+      /* take missing artwork configured in level set config from default */
+      skip_setup_artwork = TRUE;
+    }
   }
 
-  /* 2nd try: look for special artwork in configured artwork directory */
-  filename = getPath2(getSetupArtworkDir(artwork.gfx_current), basename);
-  if (fileExists(filename))
-    return filename;
+  if (!skip_setup_artwork)
+  {
+    /* 3rd try: look for special artwork in configured artwork directory */
+    filename = getPath2(getSetupArtworkDir(artwork.gfx_current), basename);
+    if (fileExists(filename))
+      return filename;
+
+    free(filename);
+  }
 
-  /* 3rd try: look for default artwork in new default artwork directory */
+  /* 4th try: look for default artwork in new default artwork directory */
   filename = getPath2(getDefaultGraphicsDir(GRAPHICS_SUBDIR), basename);
   if (fileExists(filename))
     return filename;
 
-  /* 4th try: look for default artwork in old default artwork directory */
+  free(filename);
+
+  /* 5th try: look for default artwork in old default artwork directory */
   filename = getPath2(options.graphics_directory, basename);
   if (fileExists(filename))
     return filename;
@@ -427,6 +539,7 @@ char *getCustomImageFilename(char *basename)
 char *getCustomSoundFilename(char *basename)
 {
   static char *filename = NULL;
+  boolean skip_setup_artwork = FALSE;
 
   if (filename != NULL)
     free(filename);
@@ -437,19 +550,42 @@ char *getCustomSoundFilename(char *basename)
     filename = getPath3(getCurrentLevelDir(), SOUNDS_DIRECTORY, basename);
     if (fileExists(filename))
       return filename;
+
+    free(filename);
+
+    /* check if there is special artwork configured in level series config */
+    if (getLevelArtworkSet(ARTWORK_TYPE_SOUNDS) != NULL)
+    {
+      /* 2nd try: look for special artwork configured in level series config */
+      filename = getPath2(getLevelArtworkDir(TREE_TYPE_SOUNDS_DIR), basename);
+      if (fileExists(filename))
+       return filename;
+
+      free(filename);
+
+      /* take missing artwork configured in level set config from default */
+      skip_setup_artwork = TRUE;
+    }
   }
 
-  /* 2nd try: look for special artwork in configured artwork directory */
-  filename = getPath2(getSetupArtworkDir(artwork.snd_current), basename);
-  if (fileExists(filename))
-    return filename;
+  if (!skip_setup_artwork)
+  {
+    /* 3rd try: look for special artwork in configured artwork directory */
+    filename = getPath2(getSetupArtworkDir(artwork.snd_current), basename);
+    if (fileExists(filename))
+      return filename;
 
-  /* 3rd try: look for default artwork in new default artwork directory */
+    free(filename);
+  }
+
+  /* 4th try: look for default artwork in new default artwork directory */
   filename = getPath2(getDefaultSoundsDir(SOUNDS_SUBDIR), basename);
   if (fileExists(filename))
     return filename;
 
-  /* 4th try: look for default artwork in old default artwork directory */
+  free(filename);
+
+  /* 5th try: look for default artwork in old default artwork directory */
   filename = getPath2(options.sounds_directory, basename);
   if (fileExists(filename))
     return filename;
@@ -457,14 +593,37 @@ char *getCustomSoundFilename(char *basename)
   return NULL;         /* cannot find specified artwork file anywhere */
 }
 
-char *getCustomSoundConfigFilename()
+char *getCustomArtworkFilename(char *basename, int type)
+{
+  if (type == ARTWORK_TYPE_GRAPHICS)
+    return getCustomImageFilename(basename);
+  else if (type == ARTWORK_TYPE_SOUNDS)
+    return getCustomSoundFilename(basename);
+  else
+    return UNDEFINED_FILENAME;
+}
+
+char *getCustomArtworkConfigFilename(int type)
 {
-  return getCustomSoundFilename(SOUNDSINFO_FILENAME);
+  return getCustomArtworkFilename(ARTWORKINFO_FILENAME(type), type);
+}
+
+char *getCustomArtworkLevelConfigFilename(int type)
+{
+  static char *filename = NULL;
+
+  if (filename != NULL)
+    free(filename);
+
+  filename = getPath2(getLevelArtworkDir(type), ARTWORKINFO_FILENAME(type));
+
+  return filename;
 }
 
 char *getCustomMusicDirectory(void)
 {
   static char *directory = NULL;
+  boolean skip_setup_artwork = FALSE;
 
   if (directory != NULL)
     free(directory);
@@ -475,19 +634,42 @@ char *getCustomMusicDirectory(void)
     directory = getPath2(getCurrentLevelDir(), MUSIC_DIRECTORY);
     if (fileExists(directory))
       return directory;
+
+    free(directory);
+
+    /* check if there is special artwork configured in level series config */
+    if (getLevelArtworkSet(ARTWORK_TYPE_MUSIC) != NULL)
+    {
+      /* 2nd try: look for special artwork configured in level series config */
+      directory = getStringCopy(getLevelArtworkDir(TREE_TYPE_MUSIC_DIR));
+      if (fileExists(directory))
+       return directory;
+
+      free(directory);
+
+      /* take missing artwork configured in level set config from default */
+      skip_setup_artwork = TRUE;
+    }
   }
 
-  /* 2nd try: look for special artwork in configured artwork directory */
-  directory = getStringCopy(getSetupArtworkDir(artwork.mus_current));
-  if (fileExists(directory))
-    return directory;
+  if (!skip_setup_artwork)
+  {
+    /* 3rd try: look for special artwork in configured artwork directory */
+    directory = getStringCopy(getSetupArtworkDir(artwork.mus_current));
+    if (fileExists(directory))
+      return directory;
+
+    free(directory);
+  }
 
-  /* 3rd try: look for default artwork in new default artwork directory */
+  /* 4th try: look for default artwork in new default artwork directory */
   directory = getStringCopy(getDefaultMusicDir(MUSIC_SUBDIR));
   if (fileExists(directory))
     return directory;
 
-  /* 4th try: look for default artwork in old default artwork directory */
+  free(directory);
+
+  /* 5th try: look for default artwork in old default artwork directory */
   directory = getStringCopy(options.music_directory);
   if (fileExists(directory))
     return directory;
@@ -504,6 +686,7 @@ void InitTapeDirectory(char *level_subdir)
 
 void InitScoreDirectory(char *level_subdir)
 {
+  createDirectory(getCommonDataDir(), "common data", PERMS_PUBLIC);
   createDirectory(getScoreDir(NULL), "main score", PERMS_PUBLIC);
   createDirectory(getScoreDir(level_subdir), "level score", PERMS_PUBLIC);
 }
@@ -631,9 +814,9 @@ TreeInfo *getTreeInfoFromPos(TreeInfo *node, int pos)
   return node_default;
 }
 
-TreeInfo *getTreeInfoFromFilenameExt(TreeInfo *node, char *filename)
+TreeInfo *getTreeInfoFromIdentifier(TreeInfo *node, char *identifier)
 {
-  if (filename == NULL)
+  if (identifier == NULL)
     return NULL;
 
   while (node)
@@ -642,20 +825,14 @@ TreeInfo *getTreeInfoFromFilenameExt(TreeInfo *node, char *filename)
     {
       TreeInfo *node_group;
 
-      node_group = getTreeInfoFromFilenameExt(node->node_group, filename);
+      node_group = getTreeInfoFromIdentifier(node->node_group, identifier);
 
       if (node_group)
        return node_group;
     }
     else if (!node->parent_link)
     {
-      if (strcmp(filename, node->filename) == 0)
-       return node;
-
-      /* special case when looking for level series artwork:
-        node->name_short contains level series filename */
-      if (strcmp(node->filename, ".") == 0 &&
-         strcmp(filename, node->name_short) == 0)
+      if (strcmp(identifier, node->identifier) == 0)
        return node;
     }
 
@@ -665,11 +842,6 @@ TreeInfo *getTreeInfoFromFilenameExt(TreeInfo *node, char *filename)
   return NULL;
 }
 
-TreeInfo *getTreeInfoFromFilename(TreeInfo *ti, char *filename)
-{
-  return getTreeInfoFromFilenameExt(ti, filename);
-}
-
 void dumpTreeInfo(TreeInfo *node, int depth)
 {
   int i;
@@ -682,7 +854,7 @@ void dumpTreeInfo(TreeInfo *node, int depth)
       printf(" ");
 
     printf("filename == '%s' (%s) [%s] (%d)\n",
-          node->filename, node->name, node->name_short, node->sort_priority);
+          node->filename, node->name, node->identifier, node->sort_priority);
 
     if (node->node_group != NULL)
       dumpTreeInfo(node->node_group, depth + 1);
@@ -790,15 +962,33 @@ char *getUserDataDir(void)
 {
   static char *userdata_dir = NULL;
 
-  if (!userdata_dir)
+  if (userdata_dir == NULL)
+    userdata_dir = getPath2(getHomeDir(), program.userdata_directory);
+
+  return userdata_dir;
+}
+
+char *getCommonDataDir(void)
+{
+  static char *common_data_dir = NULL;
+
+#if defined(PLATFORM_WIN32)
+  if (common_data_dir == NULL)
   {
-    char *home_dir = getHomeDir();
-    char *data_dir = program.userdata_directory;
+    char *dir = checked_malloc(MAX_PATH + 1);
 
-    userdata_dir = getPath2(home_dir, data_dir);
+    if (SUCCEEDED(SHGetFolderPath(NULL, CSIDL_COMMON_DOCUMENTS, NULL, 0, dir))
+       && strcmp(dir, "") != 0)        /* empty for Windows 95/98 */
+      common_data_dir = getPath2(dir, program.userdata_directory);
+    else
+      common_data_dir = options.rw_base_directory;
   }
+#else
+  if (common_data_dir == NULL)
+    common_data_dir = options.rw_base_directory;
+#endif
 
-  return userdata_dir;
+  return common_data_dir;
 }
 
 char *getSetupDir()
@@ -915,158 +1105,206 @@ boolean checkCookieString(const char *cookie, const char *template)
 }
 
 /* ------------------------------------------------------------------------- */
-/* setup file list handling functions                                        */
+/* setup file list and hash handling functions                               */
 /* ------------------------------------------------------------------------- */
 
-int get_string_integer_value(char *s)
+char *getFormattedSetupEntry(char *token, char *value)
 {
-  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" },
-  };
+  int i;
+  static char entry[MAX_LINE_LEN];
+
+  /* start with the token and some spaces to format output line */
+  sprintf(entry, "%s:", token);
+  for (i=strlen(entry); i<TOKEN_VALUE_POSITION; i++)
+    strcat(entry, " ");
+
+  /* continue with the token's value */
+  strcat(entry, value);
 
-  int i, j;
-  char *s_lower = getStringToLower(s);
-  int result = -1;
+  return entry;
+}
 
-  for (i=0; i<13; i++)
-    for (j=0; j<3; j++)
-      if (strcmp(s_lower, number_text[i][j]) == 0)
-       result = i;
+SetupFileList *newSetupFileList(char *token, char *value)
+{
+  SetupFileList *new = checked_malloc(sizeof(SetupFileList));
 
-  if (result == -1)
-    result = atoi(s);
+  new->token = getStringCopy(token);
+  new->value = getStringCopy(value);
 
-  free(s_lower);
+  new->next = NULL;
 
-  return result;
+  return new;
 }
 
-boolean get_string_boolean_value(char *s)
+void freeSetupFileList(SetupFileList *list)
 {
-  char *s_lower = getStringToLower(s);
-  boolean result = FALSE;
+  if (list == NULL)
+    return;
 
-  if (strcmp(s_lower, "true") == 0 ||
-      strcmp(s_lower, "yes") == 0 ||
-      strcmp(s_lower, "on") == 0 ||
-      get_string_integer_value(s) == 1)
-    result = TRUE;
+  if (list->token)
+    free(list->token);
+  if (list->value)
+    free(list->value);
+  if (list->next)
+    freeSetupFileList(list->next);
+  free(list);
+}
 
-  free(s_lower);
+char *getListEntry(SetupFileList *list, char *token)
+{
+  if (list == NULL)
+    return NULL;
 
-  return result;
+  if (strcmp(list->token, token) == 0)
+    return list->value;
+  else
+    return getListEntry(list->next, token);
 }
 
-char *getFormattedSetupEntry(char *token, char *value)
+void setListEntry(SetupFileList *list, char *token, char *value)
 {
-  int i;
-  static char entry[MAX_LINE_LEN];
-
-  /* start with the token and some spaces to format output line */
-  sprintf(entry, "%s:", token);
-  for (i=strlen(entry); i<TOKEN_VALUE_POSITION; i++)
-    strcat(entry, " ");
+  if (list == NULL)
+    return;
 
-  /* continue with the token's value */
-  strcat(entry, value);
+  if (strcmp(list->token, token) == 0)
+  {
+    if (list->value)
+      free(list->value);
 
-  return entry;
+    list->value = getStringCopy(value);
+  }
+  else if (list->next == NULL)
+    list->next = newSetupFileList(token, value);
+  else
+    setListEntry(list->next, token, value);
 }
 
-void freeSetupFileList(struct SetupFileList *setup_file_list)
+#ifdef DEBUG
+static void printSetupFileList(SetupFileList *list)
 {
-  if (!setup_file_list)
+  if (!list)
     return;
 
-  if (setup_file_list->token)
-    free(setup_file_list->token);
-  if (setup_file_list->value)
-    free(setup_file_list->value);
-  if (setup_file_list->next)
-    freeSetupFileList(setup_file_list->next);
-  free(setup_file_list);
+  printf("token: '%s'\n", list->token);
+  printf("value: '%s'\n", list->value);
+
+  printSetupFileList(list->next);
 }
+#endif
+
+#ifdef DEBUG
+DEFINE_HASHTABLE_INSERT(insert_hash_entry, char, char);
+DEFINE_HASHTABLE_SEARCH(search_hash_entry, char, char);
+DEFINE_HASHTABLE_CHANGE(change_hash_entry, char, char);
+DEFINE_HASHTABLE_REMOVE(remove_hash_entry, char, char);
+#else
+#define insert_hash_entry hashtable_insert
+#define search_hash_entry hashtable_search
+#define change_hash_entry hashtable_change
+#define remove_hash_entry hashtable_remove
+#endif
 
-static struct SetupFileList *newSetupFileList(char *token, char *value)
+static unsigned int get_hash_from_key(void *key)
 {
-  struct SetupFileList *new = checked_malloc(sizeof(struct SetupFileList));
+  /*
+    djb2
 
-  new->token = checked_malloc(strlen(token) + 1);
-  strcpy(new->token, token);
+    This algorithm (k=33) was first reported by Dan Bernstein many years ago in
+    'comp.lang.c'. Another version of this algorithm (now favored by Bernstein)
+    uses XOR: hash(i) = hash(i - 1) * 33 ^ str[i]; the magic of number 33 (why
+    it works better than many other constants, prime or not) has never been
+    adequately explained.
 
-  new->value = checked_malloc(strlen(value) + 1);
-  strcpy(new->value, value);
+    If you just want to have a good hash function, and cannot wait, djb2
+    is one of the best string hash functions i know. It has excellent
+    distribution and speed on many different sets of keys and table sizes.
+    You are not likely to do better with one of the "well known" functions
+    such as PJW, K&R, etc.
 
-  new->next = NULL;
+    Ozan (oz) Yigit [http://www.cs.yorku.ca/~oz/hash.html]
+  */
 
-  return new;
+  char *str = (char *)key;
+  unsigned int hash = 5381;
+  int c;
+
+  while ((c = *str++))
+    hash = ((hash << 5) + hash) + c;   /* hash * 33 + c */
+
+  return hash;
 }
 
-char *getTokenValue(struct SetupFileList *setup_file_list, char *token)
+static int keys_are_equal(void *key1, void *key2)
 {
-  if (!setup_file_list)
-    return NULL;
+  return (strcmp((char *)key1, (char *)key2) == 0);
+}
 
-  if (strcmp(setup_file_list->token, token) == 0)
-    return setup_file_list->value;
-  else
-    return getTokenValue(setup_file_list->next, token);
+SetupFileHash *newSetupFileHash()
+{
+  SetupFileHash *new_hash =
+    create_hashtable(16, 0.75, get_hash_from_key, keys_are_equal);
+
+  return new_hash;
 }
 
-static void setTokenValue(struct SetupFileList *setup_file_list,
-                         char *token, char *value)
+void freeSetupFileHash(SetupFileHash *hash)
 {
-  if (!setup_file_list)
+  if (hash == NULL)
     return;
 
-  if (strcmp(setup_file_list->token, token) == 0)
-  {
-    free(setup_file_list->value);
-    setup_file_list->value = checked_malloc(strlen(value) + 1);
-    strcpy(setup_file_list->value, value);
-  }
-  else if (setup_file_list->next == NULL)
-    setup_file_list->next = newSetupFileList(token, value);
-  else
-    setTokenValue(setup_file_list->next, token, value);
+  hashtable_destroy(hash, 1);  /* 1 == also free values stored in hash */
 }
 
-#ifdef DEBUG
-static void printSetupFileList(struct SetupFileList *setup_file_list)
+char *getHashEntry(SetupFileHash *hash, char *token)
+{
+  if (hash == NULL)
+    return NULL;
+
+  return search_hash_entry(hash, token);
+}
+
+void setHashEntry(SetupFileHash *hash, char *token, char *value)
 {
-  if (!setup_file_list)
+  char *value_copy;
+
+  if (hash == NULL)
     return;
 
-  printf("token: '%s'\n", setup_file_list->token);
-  printf("value: '%s'\n", setup_file_list->value);
+  value_copy = getStringCopy(value);
 
-  printSetupFileList(setup_file_list->next);
+  /* change value; if it does not exist, insert it as new */
+  if (!change_hash_entry(hash, token, value_copy))
+    if (!insert_hash_entry(hash, getStringCopy(token), value_copy))
+      Error(ERR_EXIT, "cannot insert into hash -- aborting");
+}
+
+#if 0
+#ifdef DEBUG
+static void printSetupFileHash(SetupFileHash *hash)
+{
+  BEGIN_HASH_ITERATION(hash, itr)
+  {
+    printf("token: '%s'\n", HASH_ITERATION_TOKEN(itr));
+    printf("value: '%s'\n", HASH_ITERATION_VALUE(itr));
+  }
+  END_HASH_ITERATION(hash, itr)
 }
 #endif
+#endif
 
-struct SetupFileList *loadSetupFileList(char *filename)
+static void *loadSetupFileData(char *filename, boolean use_hash)
 {
   int line_len;
   char line[MAX_LINE_LEN];
   char *token, *value, *line_ptr;
-  struct SetupFileList *setup_file_list = newSetupFileList("", "");
-  struct SetupFileList *first_valid_list_entry;
-
+  void *setup_file_data;
   FILE *file;
 
+  if (use_hash)
+    setup_file_data = newSetupFileHash();
+  else
+    setup_file_data = newSetupFileList("", "");
+
   if (!(file = fopen(filename, MODE_READ)))
   {
     Error(ERR_WARN, "cannot open configuration file '%s'", filename);
@@ -1126,47 +1364,57 @@ struct SetupFileList *loadSetupFileList(char *filename)
        break;
 
     if (*token && *value)
-      setTokenValue(setup_file_list, token, value);
+    {
+      if (use_hash)
+       setHashEntry((SetupFileHash *)setup_file_data, token, value);
+      else
+       setListEntry((SetupFileList *)setup_file_data, token, value);
+    }
   }
 
   fclose(file);
 
-  first_valid_list_entry = setup_file_list->next;
+  if (use_hash)
+  {
+    if (hashtable_count((SetupFileHash *)setup_file_data) == 0)
+      Error(ERR_WARN, "configuration file '%s' is empty", filename);
+  }
+  else
+  {
+    SetupFileList *setup_file_list = (SetupFileList *)setup_file_data;
+    SetupFileList *first_valid_list_entry = setup_file_list->next;
 
-  /* free empty list header */
-  setup_file_list->next = NULL;
-  freeSetupFileList(setup_file_list);
+    /* free empty list header */
+    setup_file_list->next = NULL;
+    freeSetupFileList(setup_file_list);
+    setup_file_data = first_valid_list_entry;
 
-  if (first_valid_list_entry == NULL)
-    Error(ERR_WARN, "configuration file '%s' is empty", filename);
+    if (first_valid_list_entry == NULL)
+      Error(ERR_WARN, "configuration file '%s' is empty", filename);
+  }
 
-  return first_valid_list_entry;
+  return setup_file_data;
 }
 
-void checkSetupFileListIdentifier(struct SetupFileList *setup_file_list,
-                                 char *identifier)
+SetupFileList *loadSetupFileList(char *filename)
 {
-  if (!setup_file_list)
-    return;
+  return (SetupFileList *)loadSetupFileData(filename, FALSE);
+}
 
-  if (strcmp(setup_file_list->token, TOKEN_STR_FILE_IDENTIFIER) == 0)
-  {
-    if (!checkCookieString(setup_file_list->value, identifier))
-    {
-      Error(ERR_WARN, "configuration file has wrong file identifier");
-      return;
-    }
-    else
-      return;
-  }
+SetupFileHash *loadSetupFileHash(char *filename)
+{
+  return (SetupFileHash *)loadSetupFileData(filename, TRUE);
+}
 
-  if (setup_file_list->next)
-    checkSetupFileListIdentifier(setup_file_list->next, identifier);
-  else
-  {
+void checkSetupFileHashIdentifier(SetupFileHash *setup_file_hash,
+                                 char *identifier)
+{
+  char *value = getHashEntry(setup_file_hash, TOKEN_STR_FILE_IDENTIFIER);
+
+  if (value == NULL)
     Error(ERR_WARN, "configuration file has no file identifier");
-    return;
-  }
+  else if (!checkCookieString(value, identifier))
+    Error(ERR_WARN, "configuration file has wrong file identifier");
 }
 
 
@@ -1179,8 +1427,8 @@ void checkSetupFileListIdentifier(struct SetupFileList *setup_file_list,
 #define TOKEN_STR_HANDICAP_LEVEL       "handicap_level"
 
 /* level directory info */
-#define LEVELINFO_TOKEN_NAME           0
-#define LEVELINFO_TOKEN_NAME_SHORT     1
+#define LEVELINFO_TOKEN_IDENTIFIER     0
+#define LEVELINFO_TOKEN_NAME           1
 #define LEVELINFO_TOKEN_NAME_SORTING   2
 #define LEVELINFO_TOKEN_AUTHOR         3
 #define LEVELINFO_TOKEN_IMPORTED_FROM  4
@@ -1189,16 +1437,19 @@ void checkSetupFileListIdentifier(struct SetupFileList *setup_file_list,
 #define LEVELINFO_TOKEN_SORT_PRIORITY  7
 #define LEVELINFO_TOKEN_LEVEL_GROUP    8
 #define LEVELINFO_TOKEN_READONLY       9
+#define LEVELINFO_TOKEN_GRAPHICS_SET   10
+#define LEVELINFO_TOKEN_SOUNDS_SET     11
+#define LEVELINFO_TOKEN_MUSIC_SET      12
 
-#define NUM_LEVELINFO_TOKENS           10
+#define NUM_LEVELINFO_TOKENS           13
 
 static LevelDirTree ldi;
 
 static struct TokenInfo levelinfo_tokens[] =
 {
   /* level directory info */
+  { TYPE_STRING,  &ldi.identifier,     "identifier"    },
   { TYPE_STRING,  &ldi.name,           "name"          },
-  { TYPE_STRING,  &ldi.name_short,     "name_short"    },
   { TYPE_STRING,  &ldi.name_sorting,   "name_sorting"  },
   { TYPE_STRING,  &ldi.author,         "author"        },
   { TYPE_STRING,  &ldi.imported_from,  "imported_from" },
@@ -1206,7 +1457,10 @@ static struct TokenInfo levelinfo_tokens[] =
   { TYPE_INTEGER, &ldi.first_level,    "first_level"   },
   { TYPE_INTEGER, &ldi.sort_priority,  "sort_priority" },
   { TYPE_BOOLEAN, &ldi.level_group,    "level_group"   },
-  { TYPE_BOOLEAN, &ldi.readonly,       "readonly"      }
+  { TYPE_BOOLEAN, &ldi.readonly,       "readonly"      },
+  { TYPE_STRING,  &ldi.graphics_set,   "graphics_set"  },
+  { TYPE_STRING,  &ldi.sounds_set,     "sounds_set"    },
+  { TYPE_STRING,  &ldi.music_set,      "music_set"     }
 };
 
 static void setTreeInfoToDefaults(TreeInfo *ldi, int type)
@@ -1229,8 +1483,8 @@ static void setTreeInfoToDefaults(TreeInfo *ldi, int type)
   ldi->filename = NULL;
   ldi->fullpath = NULL;
   ldi->basepath = NULL;
+  ldi->identifier = NULL;
   ldi->name = getStringCopy(ANONYMOUS_NAME);
-  ldi->name_short = NULL;
   ldi->name_sorting = NULL;
   ldi->author = getStringCopy(ANONYMOUS_NAME);
 
@@ -1243,6 +1497,14 @@ static void setTreeInfoToDefaults(TreeInfo *ldi, int type)
   if (ldi->type == TREE_TYPE_LEVEL_DIR)
   {
     ldi->imported_from = NULL;
+
+    ldi->graphics_set = NULL;
+    ldi->sounds_set = NULL;
+    ldi->music_set = NULL;
+    ldi->graphics_path = getStringCopy(UNDEFINED_FILENAME);
+    ldi->sounds_path = getStringCopy(UNDEFINED_FILENAME);
+    ldi->music_path = getStringCopy(UNDEFINED_FILENAME);
+
     ldi->levels = 0;
     ldi->first_level = 0;
     ldi->last_level = 0;
@@ -1258,10 +1520,60 @@ static void setTreeInfoToDefaultsFromParent(TreeInfo *ldi, TreeInfo *parent)
   {
     Error(ERR_WARN, "setTreeInfoToDefaultsFromParent(): parent == NULL");
 
-    setTreeInfoToDefaults(ldi, TREE_TYPE_GENERIC);
+    setTreeInfoToDefaults(ldi, TREE_TYPE_UNDEFINED);
+
     return;
   }
 
+#if 1
+  /* copy all values from the parent structure */
+
+  ldi->type = parent->type;
+
+  ldi->node_top = parent->node_top;
+  ldi->node_parent = parent;
+  ldi->node_group = NULL;
+  ldi->next = NULL;
+
+  ldi->cl_first = -1;
+  ldi->cl_cursor = -1;
+
+  ldi->filename = NULL;
+  ldi->fullpath = NULL;
+  ldi->basepath = NULL;
+  ldi->identifier = NULL;
+  ldi->name = getStringCopy(ANONYMOUS_NAME);
+  ldi->name_sorting = NULL;
+  ldi->author = getStringCopy(parent->author);
+
+  ldi->sort_priority = parent->sort_priority;
+  ldi->parent_link = FALSE;
+  ldi->user_defined = parent->user_defined;
+  ldi->color = parent->color;
+  ldi->class_desc = getStringCopy(parent->class_desc);
+
+  if (ldi->type == TREE_TYPE_LEVEL_DIR)
+  {
+    ldi->imported_from = getStringCopy(parent->imported_from);
+
+    ldi->graphics_set = NULL;
+    ldi->sounds_set = NULL;
+    ldi->music_set = NULL;
+    ldi->graphics_path = getStringCopy(UNDEFINED_FILENAME);
+    ldi->sounds_path = getStringCopy(UNDEFINED_FILENAME);
+    ldi->music_path = getStringCopy(UNDEFINED_FILENAME);
+
+    ldi->levels = 0;
+    ldi->first_level = 0;
+    ldi->last_level = 0;
+    ldi->level_group = FALSE;
+    ldi->handicap_level = 0;
+    ldi->readonly = TRUE;
+  }
+
+
+#else
+
   /* first copy all values from the parent structure ... */
   *ldi = *parent;
 
@@ -1275,11 +1587,20 @@ static void setTreeInfoToDefaultsFromParent(TreeInfo *ldi, TreeInfo *parent)
   ldi->filename = NULL;
   ldi->fullpath = NULL;
   ldi->basepath = NULL;
+  ldi->identifier = NULL;
   ldi->name = getStringCopy(ANONYMOUS_NAME);
-  ldi->name_short = NULL;
   ldi->name_sorting = NULL;
   ldi->author = getStringCopy(parent->author);
+
   ldi->imported_from = getStringCopy(parent->imported_from);
+  ldi->class_desc = getStringCopy(parent->class_desc);
+
+  ldi->graphics_set = NULL;
+  ldi->sounds_set = NULL;
+  ldi->music_set = NULL;
+  ldi->graphics_path = NULL;
+  ldi->sounds_path = NULL;
+  ldi->music_path = NULL;
 
   ldi->level_group = FALSE;
   ldi->parent_link = FALSE;
@@ -1288,6 +1609,8 @@ static void setTreeInfoToDefaultsFromParent(TreeInfo *ldi, TreeInfo *parent)
   ldi->node_parent = parent;
   ldi->node_group = NULL;
   ldi->next = NULL;
+
+#endif
 }
 
 void setSetupInfo(struct TokenInfo *token_info,
@@ -1304,7 +1627,7 @@ void setSetupInfo(struct TokenInfo *token_info,
   {
     case TYPE_BOOLEAN:
     case TYPE_SWITCH:
-      *(boolean *)setup_value = get_string_boolean_value(token_value);
+      *(boolean *)setup_value = get_boolean_from_string(token_value);
       break;
 
     case TYPE_KEY:
@@ -1316,7 +1639,7 @@ void setSetupInfo(struct TokenInfo *token_info,
       break;
 
     case TYPE_INTEGER:
-      *(int *)setup_value = get_string_integer_value(token_value);
+      *(int *)setup_value = get_integer_from_string(token_value);
       break;
 
     case TYPE_STRING:
@@ -1381,8 +1704,8 @@ static void createParentTreeInfoNode(TreeInfo *node_parent)
   ti_new->node_parent = node_parent;
   ti_new->parent_link = TRUE;
 
+  ti_new->identifier = getStringCopy(node_parent->identifier);
   ti_new->name = ".. (parent directory)";
-  ti_new->name_short = getStringCopy(ti_new->name);
   ti_new->name_sorting = getStringCopy(ti_new->name);
 
   ti_new->filename = "..";
@@ -1404,11 +1727,11 @@ static boolean LoadLevelInfoFromLevelConf(TreeInfo **node_first,
 {
   char *directory_path = getPath2(level_directory, directory_name);
   char *filename = getPath2(directory_path, LEVELINFO_FILENAME);
-  struct SetupFileList *setup_file_list = loadSetupFileList(filename);
+  SetupFileHash *setup_file_hash = loadSetupFileHash(filename);
   LevelDirTree *leveldir_new = NULL;
   int i;
 
-  if (setup_file_list == NULL)
+  if (setup_file_hash == NULL)
   {
     Error(ERR_WARN, "ignoring level directory '%s'", directory_path);
 
@@ -1427,13 +1750,13 @@ static boolean LoadLevelInfoFromLevelConf(TreeInfo **node_first,
 
   leveldir_new->filename = getStringCopy(directory_name);
 
-  checkSetupFileListIdentifier(setup_file_list, getCookie("LEVELINFO"));
+  checkSetupFileHashIdentifier(setup_file_hash, getCookie("LEVELINFO"));
 
   /* set all structure fields according to the token/value pairs */
   ldi = *leveldir_new;
   for (i=0; i<NUM_LEVELINFO_TOKENS; i++)
     setSetupInfo(levelinfo_tokens, i,
-                getTokenValue(setup_file_list, levelinfo_tokens[i].text));
+                getHashEntry(setup_file_hash, levelinfo_tokens[i].text));
   *leveldir_new = ldi;
 
   if (strcmp(leveldir_new->name, ANONYMOUS_NAME) == 0)
@@ -1444,8 +1767,8 @@ static boolean LoadLevelInfoFromLevelConf(TreeInfo **node_first,
 
   DrawInitText(leveldir_new->name, 150, FC_YELLOW);
 
-  if (leveldir_new->name_short == NULL)
-    leveldir_new->name_short = getStringCopy(leveldir_new->name);
+  if (leveldir_new->identifier == NULL)
+    leveldir_new->identifier = getStringCopy(leveldir_new->filename);
 
   if (leveldir_new->name_sorting == NULL)
     leveldir_new->name_sorting = getStringCopy(leveldir_new->name);
@@ -1480,7 +1803,7 @@ static boolean LoadLevelInfoFromLevelConf(TreeInfo **node_first,
 
   pushTreeInfo(node_first, leveldir_new);
 
-  freeSetupFileList(setup_file_list);
+  freeSetupFileHash(setup_file_hash);
 
   if (leveldir_new->level_group)
   {
@@ -1589,14 +1912,14 @@ static boolean LoadArtworkInfoFromArtworkConf(TreeInfo **node_first,
 {
   char *directory_path = getPath2(base_directory, directory_name);
   char *filename = getPath2(directory_path, ARTWORKINFO_FILENAME(type));
-  struct SetupFileList *setup_file_list = NULL;
+  SetupFileHash *setup_file_hash = NULL;
   TreeInfo *artwork_new = NULL;
   int i;
 
   if (access(filename, F_OK) == 0)             /* file exists */
-    setup_file_list = loadSetupFileList(filename);
+    setup_file_hash = loadSetupFileHash(filename);
 
-  if (setup_file_list == NULL) /* no config file -- look for artwork files */
+  if (setup_file_hash == NULL) /* no config file -- look for artwork files */
   {
     DIR *dir;
     struct dirent *dir_entry;
@@ -1639,17 +1962,17 @@ static boolean LoadArtworkInfoFromArtworkConf(TreeInfo **node_first,
 
   artwork_new->filename = getStringCopy(directory_name);
 
-  if (setup_file_list) /* (before defining ".color" and ".class_desc") */
+  if (setup_file_hash) /* (before defining ".color" and ".class_desc") */
   {
 #if 0
-    checkSetupFileListIdentifier(setup_file_list, getCookie("..."));
+    checkSetupFileHashIdentifier(setup_file_hash, getCookie("..."));
 #endif
 
     /* set all structure fields according to the token/value pairs */
     ldi = *artwork_new;
     for (i=0; i<NUM_LEVELINFO_TOKENS; i++)
       setSetupInfo(levelinfo_tokens, i,
-                  getTokenValue(setup_file_list, levelinfo_tokens[i].text));
+                  getHashEntry(setup_file_hash, levelinfo_tokens[i].text));
     *artwork_new = ldi;
 
     if (strcmp(artwork_new->name, ANONYMOUS_NAME) == 0)
@@ -1662,8 +1985,8 @@ static boolean LoadArtworkInfoFromArtworkConf(TreeInfo **node_first,
     DrawInitText(artwork_new->name, 150, FC_YELLOW);
 #endif
 
-    if (artwork_new->name_short == NULL)
-      artwork_new->name_short = getStringCopy(artwork_new->name);
+    if (artwork_new->identifier == NULL)
+      artwork_new->identifier = getStringCopy(artwork_new->filename);
 
     if (artwork_new->name_sorting == NULL)
       artwork_new->name_sorting = getStringCopy(artwork_new->name);
@@ -1683,11 +2006,11 @@ static boolean LoadArtworkInfoFromArtworkConf(TreeInfo **node_first,
   artwork_new->user_defined =
     (artwork_new->basepath == OPTIONS_ARTWORK_DIRECTORY(type) ? FALSE : TRUE);
 
-  /* (may use ".sort_priority" from "setup_file_list" above) */
+  /* (may use ".sort_priority" from "setup_file_hash" above) */
   artwork_new->color = ARTWORKCOLOR(artwork_new);
   artwork_new->class_desc = getLevelClassDescription(artwork_new);
 
-  if (setup_file_list == NULL) /* (after determining ".user_defined") */
+  if (setup_file_hash == NULL) /* (after determining ".user_defined") */
   {
     if (artwork_new->name != NULL)
       free(artwork_new->name);
@@ -1696,22 +2019,25 @@ static boolean LoadArtworkInfoFromArtworkConf(TreeInfo **node_first,
     {
       if (artwork_new->user_defined)
       {
-       artwork_new->name = getStringCopy("private");
+       artwork_new->identifier = getStringCopy("private");
        artwork_new->sort_priority = ARTWORKCLASS_USER;
       }
       else
       {
-       artwork_new->name = getStringCopy("classic");
+       artwork_new->identifier = getStringCopy("classic");
        artwork_new->sort_priority = ARTWORKCLASS_CLASSICS;
       }
 
+      /* set to new values after changing ".sort_priority" */
       artwork_new->color = ARTWORKCOLOR(artwork_new);
       artwork_new->class_desc = getLevelClassDescription(artwork_new);
     }
     else
-      artwork_new->name = getStringCopy(artwork_new->filename);
+    {
+      artwork_new->identifier = getStringCopy(artwork_new->filename);
+    }
 
-    artwork_new->name_short = getStringCopy(artwork_new->name);
+    artwork_new->name = getStringCopy(artwork_new->identifier);
     artwork_new->name_sorting = getStringCopy(artwork_new->name);
   }
 
@@ -1719,7 +2045,7 @@ static boolean LoadArtworkInfoFromArtworkConf(TreeInfo **node_first,
 
   pushTreeInfo(node_first, artwork_new);
 
-  freeSetupFileList(setup_file_list);
+  freeSetupFileHash(setup_file_hash);
 
   free(directory_path);
   free(filename);
@@ -1790,16 +2116,16 @@ static TreeInfo *getDummyArtworkInfo(int type)
 
   setTreeInfoToDefaults(artwork_new, type);
 
-  artwork_new->filename = getStringCopy(NOT_AVAILABLE);
-  artwork_new->fullpath = getStringCopy(NOT_AVAILABLE);
-  artwork_new->basepath = getStringCopy(NOT_AVAILABLE);
+  artwork_new->filename = getStringCopy(UNDEFINED_FILENAME);
+  artwork_new->fullpath = getStringCopy(UNDEFINED_FILENAME);
+  artwork_new->basepath = getStringCopy(UNDEFINED_FILENAME);
 
   if (artwork_new->name != NULL)
     free(artwork_new->name);
 
-  artwork_new->name         = getStringCopy(NOT_AVAILABLE);
-  artwork_new->name_short   = getStringCopy(NOT_AVAILABLE);
-  artwork_new->name_sorting = getStringCopy(NOT_AVAILABLE);
+  artwork_new->identifier   = getStringCopy(UNDEFINED_FILENAME);
+  artwork_new->name         = getStringCopy(UNDEFINED_FILENAME);
+  artwork_new->name_sorting = getStringCopy(UNDEFINED_FILENAME);
 
   return artwork_new;
 }
@@ -1838,28 +2164,37 @@ void LoadArtworkInfo()
 
   /* before sorting, the first entries will be from the user directory */
   artwork.gfx_current =
-    getTreeInfoFromFilename(artwork.gfx_first, setup.graphics_set);
+    getTreeInfoFromIdentifier(artwork.gfx_first, setup.graphics_set);
+  if (artwork.gfx_current == NULL)
+    artwork.gfx_current =
+      getTreeInfoFromIdentifier(artwork.gfx_first, GRAPHICS_SUBDIR);
   if (artwork.gfx_current == NULL)
     artwork.gfx_current = getFirstValidTreeInfoEntry(artwork.gfx_first);
 
   artwork.snd_current =
-    getTreeInfoFromFilename(artwork.snd_first, setup.sounds_set);
+    getTreeInfoFromIdentifier(artwork.snd_first, setup.sounds_set);
+  if (artwork.snd_current == NULL)
+    artwork.snd_current =
+      getTreeInfoFromIdentifier(artwork.snd_first, SOUNDS_SUBDIR);
   if (artwork.snd_current == NULL)
     artwork.snd_current = getFirstValidTreeInfoEntry(artwork.snd_first);
 
   artwork.mus_current =
-    getTreeInfoFromFilename(artwork.mus_first, setup.music_set);
+    getTreeInfoFromIdentifier(artwork.mus_first, setup.music_set);
+  if (artwork.mus_current == NULL)
+    artwork.mus_current =
+      getTreeInfoFromIdentifier(artwork.mus_first, MUSIC_SUBDIR);
   if (artwork.mus_current == NULL)
     artwork.mus_current = getFirstValidTreeInfoEntry(artwork.mus_first);
 
-  artwork.graphics_set_current_name = artwork.gfx_current->name;
-  artwork.sounds_set_current_name = artwork.snd_current->name;
-  artwork.music_set_current_name = artwork.mus_current->name;
+  artwork.gfx_current_identifier = artwork.gfx_current->identifier;
+  artwork.snd_current_identifier = artwork.snd_current->identifier;
+  artwork.mus_current_identifier = artwork.mus_current->identifier;
 
 #if 0
-  printf("graphics set == %s\n\n", artwork.graphics_set_current_name);
-  printf("sounds set == %s\n\n", artwork.sounds_set_current_name);
-  printf("music set == %s\n\n", artwork.music_set_current_name);
+  printf("graphics set == %s\n\n", artwork.gfx_current_identifier);
+  printf("sounds set == %s\n\n", artwork.snd_current_identifier);
+  printf("music set == %s\n\n", artwork.mus_current_identifier);
 #endif
 
   sortTreeInfo(&artwork.gfx_first, compareTreeInfoEntries);
@@ -1898,13 +2233,13 @@ void LoadArtworkInfoFromLevelInfo(ArtworkDirTree **artwork_node,
 
       if (topnode_last != *artwork_node)
       {
+       free((*artwork_node)->identifier);
        free((*artwork_node)->name);
        free((*artwork_node)->name_sorting);
-       free((*artwork_node)->name_short);
 
+       (*artwork_node)->identifier   = getStringCopy(level_node->filename);
        (*artwork_node)->name         = getStringCopy(level_node->name);
        (*artwork_node)->name_sorting = getStringCopy(level_node->name);
-       (*artwork_node)->name_short   = getStringCopy(level_node->filename);
 
        (*artwork_node)->sort_priority = level_node->sort_priority;
        (*artwork_node)->color = LEVELCOLOR((*artwork_node));
@@ -1928,6 +2263,40 @@ void LoadLevelArtworkInfo()
   LoadArtworkInfoFromLevelInfo(&artwork.snd_first, leveldir_first);
   LoadArtworkInfoFromLevelInfo(&artwork.mus_first, leveldir_first);
 
+  /* needed for reloading level artwork not known at ealier stage */
+  if (strcmp(artwork.gfx_current_identifier, setup.graphics_set) != 0)
+  {
+    artwork.gfx_current =
+      getTreeInfoFromIdentifier(artwork.gfx_first, setup.graphics_set);
+    if (artwork.gfx_current == NULL)
+      artwork.gfx_current =
+       getTreeInfoFromIdentifier(artwork.gfx_first, GRAPHICS_SUBDIR);
+    if (artwork.gfx_current == NULL)
+      artwork.gfx_current = getFirstValidTreeInfoEntry(artwork.gfx_first);
+  }
+
+  if (strcmp(artwork.snd_current_identifier, setup.sounds_set) != 0)
+  {
+    artwork.snd_current =
+      getTreeInfoFromIdentifier(artwork.snd_first, setup.sounds_set);
+    if (artwork.snd_current == NULL)
+      artwork.snd_current =
+       getTreeInfoFromIdentifier(artwork.snd_first, SOUNDS_SUBDIR);
+    if (artwork.snd_current == NULL)
+      artwork.snd_current = getFirstValidTreeInfoEntry(artwork.snd_first);
+  }
+
+  if (strcmp(artwork.mus_current_identifier, setup.music_set) != 0)
+  {
+    artwork.mus_current =
+      getTreeInfoFromIdentifier(artwork.mus_first, setup.music_set);
+    if (artwork.mus_current == NULL)
+      artwork.mus_current =
+       getTreeInfoFromIdentifier(artwork.mus_first, MUSIC_SUBDIR);
+    if (artwork.mus_current == NULL)
+      artwork.mus_current = getFirstValidTreeInfoEntry(artwork.mus_first);
+  }
+
   sortTreeInfo(&artwork.gfx_first, compareTreeInfoEntries);
   sortTreeInfo(&artwork.snd_first, compareTreeInfoEntries);
   sortTreeInfo(&artwork.mus_first, compareTreeInfoEntries);
@@ -1957,18 +2326,34 @@ static void SaveUserLevelInfo()
   /* always start with reliable default values */
   setTreeInfoToDefaults(&ldi, TREE_TYPE_LEVEL_DIR);
 
+#if 0
+  /* !!! FIX ME !!! */
+  setString(&ldi.name, getLoginName());
+  setString(&ldi.author, getRealName());
+  ldi.levels = 100;
+  ldi.first_level = 1;
+  ldi.sort_priority = LEVELCLASS_USER_START;
+  ldi.readonly = FALSE;
+  setString(&ldi.graphics_set, GRAPHICS_SUBDIR);
+  setString(&ldi.sounds_set, SOUNDS_SUBDIR);
+  setString(&ldi.music_set, MUSIC_SUBDIR);
+#else
   ldi.name = getStringCopy(getLoginName());
   ldi.author = getStringCopy(getRealName());
   ldi.levels = 100;
   ldi.first_level = 1;
   ldi.sort_priority = LEVELCLASS_USER_START;
   ldi.readonly = FALSE;
+  ldi.graphics_set = getStringCopy(GRAPHICS_SUBDIR);
+  ldi.sounds_set = getStringCopy(SOUNDS_SUBDIR);
+  ldi.music_set = getStringCopy(MUSIC_SUBDIR);
+#endif
 
   fprintf(file, "%s\n\n", getFormattedSetupEntry(TOKEN_STR_FILE_IDENTIFIER,
                                                 getCookie("LEVELINFO")));
 
   for (i=0; i<NUM_LEVELINFO_TOKENS; i++)
-    if (i != LEVELINFO_TOKEN_NAME_SHORT &&
+    if (i != LEVELINFO_TOKEN_IDENTIFIER &&
        i != LEVELINFO_TOKEN_NAME_SORTING &&
        i != LEVELINFO_TOKEN_IMPORTED_FROM)
       fprintf(file, "%s\n", getSetupLine(levelinfo_tokens, "", i));
@@ -2065,7 +2450,7 @@ char *getSetupLine(struct TokenInfo *token_info, char *prefix, int token_nr)
 void LoadLevelSetup_LastSeries()
 {
   char *filename;
-  struct SetupFileList *level_setup_list = NULL;
+  SetupFileHash *level_setup_hash = NULL;
 
   /* always start with reliable default values */
   leveldir_current = getFirstValidTreeInfoEntry(leveldir_first);
@@ -2076,19 +2461,19 @@ void LoadLevelSetup_LastSeries()
 
   filename = getPath2(getSetupDir(), LEVELSETUP_FILENAME);
 
-  if ((level_setup_list = loadSetupFileList(filename)))
+  if ((level_setup_hash = loadSetupFileHash(filename)))
   {
     char *last_level_series =
-      getTokenValue(level_setup_list, TOKEN_STR_LAST_LEVEL_SERIES);
+      getHashEntry(level_setup_hash, TOKEN_STR_LAST_LEVEL_SERIES);
 
-    leveldir_current = getTreeInfoFromFilename(leveldir_first,
-                                              last_level_series);
+    leveldir_current = getTreeInfoFromIdentifier(leveldir_first,
+                                                last_level_series);
     if (leveldir_current == NULL)
       leveldir_current = getFirstValidTreeInfoEntry(leveldir_first);
 
-    checkSetupFileListIdentifier(level_setup_list, getCookie("LEVELSETUP"));
+    checkSetupFileHashIdentifier(level_setup_hash, getCookie("LEVELSETUP"));
 
-    freeSetupFileList(level_setup_list);
+    freeSetupFileHash(level_setup_hash);
   }
   else
     Error(ERR_WARN, "using default setup values");
@@ -2161,6 +2546,7 @@ static void checkSeriesInfo()
 
       levelnum_value = atoi(levelnum_str);
 
+#if 0
       if (levelnum_value < leveldir_current->first_level)
       {
        Error(ERR_WARN, "additional level %d found", levelnum_value);
@@ -2171,6 +2557,7 @@ static void checkSeriesInfo()
        Error(ERR_WARN, "additional level %d found", levelnum_value);
        leveldir_current->last_level = levelnum_value;
       }
+#endif
     }
   }
 
@@ -2180,7 +2567,7 @@ static void checkSeriesInfo()
 void LoadLevelSetup_SeriesInfo()
 {
   char *filename;
-  struct SetupFileList *level_setup_list = NULL;
+  SetupFileHash *level_setup_hash = NULL;
   char *level_subdir = leveldir_current->filename;
 
   /* always start with reliable default values */
@@ -2196,11 +2583,11 @@ void LoadLevelSetup_SeriesInfo()
 
   filename = getPath2(getLevelSetupDir(level_subdir), LEVELSETUP_FILENAME);
 
-  if ((level_setup_list = loadSetupFileList(filename)))
+  if ((level_setup_hash = loadSetupFileHash(filename)))
   {
     char *token_value;
 
-    token_value = getTokenValue(level_setup_list, TOKEN_STR_LAST_PLAYED_LEVEL);
+    token_value = getHashEntry(level_setup_hash, TOKEN_STR_LAST_PLAYED_LEVEL);
 
     if (token_value)
     {
@@ -2212,7 +2599,7 @@ void LoadLevelSetup_SeriesInfo()
        level_nr = leveldir_current->last_level;
     }
 
-    token_value = getTokenValue(level_setup_list, TOKEN_STR_HANDICAP_LEVEL);
+    token_value = getHashEntry(level_setup_hash, TOKEN_STR_HANDICAP_LEVEL);
 
     if (token_value)
     {
@@ -2229,9 +2616,9 @@ void LoadLevelSetup_SeriesInfo()
       leveldir_current->handicap_level = level_nr;
     }
 
-    checkSetupFileListIdentifier(level_setup_list, getCookie("LEVELSETUP"));
+    checkSetupFileHashIdentifier(level_setup_hash, getCookie("LEVELSETUP"));
 
-    freeSetupFileList(level_setup_list);
+    freeSetupFileHash(level_setup_hash);
   }
   else
     Error(ERR_WARN, "using default setup values");
index f299f3d9ab5e514e3f3bef215b855f9b79eb6eec..30952c650e9b963aa26b0d658003d56599d79af9 100644 (file)
@@ -15,6 +15,7 @@
 #define SETUP_H
 
 #include "system.h"
+#include "hash.h"
 
 
 /* values for setup file handling */
 #define TYPE_KEY_X11                   (1 << 4)
 #define TYPE_INTEGER                   (1 << 5)
 #define TYPE_STRING                    (1 << 6)
+#define TYPE_TOKEN                     (1 << 7)
 
 #define TYPE_BOOLEAN_STYLE             (TYPE_BOOLEAN | \
                                         TYPE_SWITCH  | \
                                         TYPE_YES_NO)
 
 /* additional values for setup screen */
-#define TYPE_ENTER_MENU                        (1 << 7)
-#define TYPE_LEAVE_MENU                        (1 << 8)
-#define TYPE_EMPTY                     (1 << 9)
-#define TYPE_KEYTEXT                   (1 << 10)
-
-#define TYPE_GHOSTED                   (1 << 11)
-#define TYPE_QUERY                     (1 << 12)
-
-#define TYPE_VALUE                     (TYPE_BOOLEAN_STYLE | \
-                                        TYPE_KEY | \
-                                        TYPE_KEY_X11 | \
-                                        TYPE_INTEGER | \
+#define TYPE_ENTER_MENU                        (1 << 8)
+#define TYPE_LEAVE_MENU                        (1 << 9)
+#define TYPE_EMPTY                     (1 << 10)
+#define TYPE_KEYTEXT                   (1 << 11)
+
+#define TYPE_GHOSTED                   (1 << 12)
+#define TYPE_QUERY                     (1 << 13)
+
+#define TYPE_VALUE                     (TYPE_BOOLEAN_STYLE     | \
+                                        TYPE_KEY               | \
+                                        TYPE_KEY_X11           | \
+                                        TYPE_INTEGER           | \
+                                        TYPE_STRING            | \
+                                        TYPE_TOKEN)
+
+#define TYPE_SKIP_ENTRY                        (TYPE_EMPTY             | \
+                                        TYPE_KEY               | \
                                         TYPE_STRING)
 
-#define TYPE_SKIP_ENTRY                        (TYPE_EMPTY | \
-                                        TYPE_KEY | \
-                                        TYPE_STRING)
-
-#define TYPE_ENTER_OR_LEAVE_MENU       (TYPE_ENTER_MENU | \
+#define TYPE_ENTER_OR_LEAVE_MENU       (TYPE_ENTER_MENU        | \
                                         TYPE_LEAVE_MENU)
 
 /* cookie token for file identifier and version number */
 #define TOKEN_STR_FILE_IDENTIFIER      "file_identifier"
 
-/* structures for setup file handling */
-struct SetupFileList
-{
-  char *token;
-  char *value;
-  struct SetupFileList *next;
-};
-
 struct TokenInfo
 {
   int type;
@@ -70,6 +65,25 @@ struct TokenInfo
   char *text;
 };
 
+/* some definitions for list and hash handling */
+typedef struct SetupFileList SetupFileList;
+typedef struct hashtable SetupFileHash;
+
+#define BEGIN_HASH_ITERATION(hash, itr)                                \
+  if (hash != NULL && hashtable_count(hash) > 0)               \
+  {                                                            \
+    struct hashtable_itr *itr = hashtable_iterator(hash);      \
+    do {                                                       \
+
+#define HASH_ITERATION_TOKEN(itr)      ((char *)hashtable_iterator_key(itr))
+#define HASH_ITERATION_VALUE(itr)      ((char *)hashtable_iterator_value(itr))
+
+#define END_HASH_ITERATION(hash, itr)                          \
+    } while (hashtable_iterator_advance(itr));                 \
+    free(itr);                                                 \
+  }                                                            \
+
+
 /* sort priorities of level series (also used as level series classes) */
 #define LEVELCLASS_TUTORIAL_START      10
 #define LEVELCLASS_TUTORIAL_END                99
@@ -171,6 +185,7 @@ struct TokenInfo
                         ARTWORKCLASS_UNDEFINED)
 
 
+void setLevelArtworkDir(TreeInfo *);
 char *getLevelFilename(int);
 char *getTapeFilename(int);
 char *getScoreFilename(int);
@@ -178,7 +193,9 @@ char *getSetupFilename(void);
 char *getImageFilename(char *);
 char *getCustomImageFilename(char *);
 char *getCustomSoundFilename(char *);
-char *getCustomSoundConfigFilename(void);
+char *getCustomArtworkFilename(char *, int);
+char *getCustomArtworkConfigFilename(int);
+char *getCustomArtworkLevelConfigFilename(int);
 char *getCustomMusicDirectory(void);
 
 void InitTapeDirectory(char *);
@@ -195,12 +212,13 @@ TreeInfo *getTreeInfoFirstGroupEntry(TreeInfo *);
 int numTreeInfoInGroup(TreeInfo *);
 int posTreeInfo(TreeInfo *);
 TreeInfo *getTreeInfoFromPos(TreeInfo *, int);
-TreeInfo *getTreeInfoFromFilename(TreeInfo *, char *);
+TreeInfo *getTreeInfoFromIdentifier(TreeInfo *, char *);
 void dumpTreeInfo(TreeInfo *, int);
 void sortTreeInfo(TreeInfo **,
                  int (*compare_function)(const void *, const void *));
 
 char *getUserDataDir(void);
+char *getCommonDataDir(void);
 char *getSetupDir(void);
 void createDirectory(char *, char *, int);
 void InitUserDataDirectory(void);
@@ -211,10 +229,19 @@ int getFileVersionFromCookieString(const char *);
 boolean checkCookieString(const char *, const char *);
 
 char *getFormattedSetupEntry(char *, char *);
+
+struct SetupFileList *newSetupFileList(char *, char *);
 void freeSetupFileList(struct SetupFileList *);
-char *getTokenValue(struct SetupFileList *, char *);
-struct SetupFileList *loadSetupFileList(char *);
-void checkSetupFileListIdentifier(struct SetupFileList *, char *);
+char *getListEntry(struct SetupFileList *, char *);
+void setListEntry(struct SetupFileList *, char *, char *);
+SetupFileList *loadSetupFileList(char *);
+
+SetupFileHash *newSetupFileHash();
+void freeSetupFileHash(SetupFileHash *);
+char *getHashEntry(SetupFileHash *, char *);
+void setHashEntry(SetupFileHash *, char *, char *);
+SetupFileHash *loadSetupFileHash(char *);
+void checkSetupFileHashIdentifier(SetupFileHash *, char *);
 void setSetupInfo(struct TokenInfo *, int, char *);
 char *getSetupValue(int, void *);
 char *getSetupLine(struct TokenInfo *, char *, int);
index 6f48576667caf33254d8960e3338e51b9a55cf9c..0299521267dd802ccd5024467a15590fb286ed22 100644 (file)
 #define SOUND_FADING_VOLUME_THRESHOLD  (SOUND_FADING_VOLUME_STEP * 2)
 #endif
 
-#if !defined(PLATFORM_HPUX)
-#define SND_BLOCKSIZE                  4096
-#else
-#define SND_BLOCKSIZE                  32768
-#endif
-
 #define SND_TYPE_NONE                  0
 #define SND_TYPE_WAV                   1
 
@@ -124,6 +118,7 @@ struct SampleInfo
   int format;
   void *data_ptr;              /* pointer to first sample (8 or 16 bit) */
   long data_len;               /* number of samples, NOT number of bytes */
+  int num_channels;            /* mono: 1 channel, stereo: 2 channels */
 };
 typedef struct SampleInfo SoundInfo;
 typedef struct SampleInfo MusicInfo;
@@ -145,6 +140,7 @@ struct SoundControl
   int format;
   void *data_ptr;              /* pointer to first sample (8 or 16 bit) */
   long data_len;               /* number of samples, NOT number of bytes */
+  int num_channels;            /* mono: 1 channel, stereo: 2 channels */
 
 #if defined(TARGET_ALLEGRO)
   int voice;
@@ -152,26 +148,15 @@ struct SoundControl
 };
 typedef struct SoundControl SoundControl;
 
-struct ListNode
-{
-  char *key;
-  void *content;
-  struct ListNode *next;
-};
-typedef struct ListNode ListNode;
-
-static ListNode *newListNode(void);
-static void addNodeToList(ListNode **, char *, void *);
-static void deleteNodeFromList(ListNode **, char *, void (*function)(void *));
-static ListNode *getNodeFromKey(ListNode *, char *);
-static int getNumNodes(ListNode *);
-
-
-static struct SoundEffectInfo *sound_effect;
-static ListNode *SoundFileList = NULL;
+static struct ArtworkListInfo *sound_info = NULL;
+#if 0
 static SoundInfo **Sound = NULL;
+#endif
 static MusicInfo **Music = NULL;
-static int num_sounds = 0, num_music = 0;
+#if 0
+static int num_sounds = 0;
+#endif
+static int num_music = 0;
 static int stereo_volume[SOUND_MAX_LEFT2RIGHT + 1];
 
 
@@ -195,6 +180,8 @@ static void ReloadCustomSounds();
 static void ReloadCustomMusic();
 static void FreeSound(void *);
 
+static SoundInfo *getSoundInfoEntryFromSoundID(int);
+
 
 /* ------------------------------------------------------------------------- */
 /* functions for native (non-SDL) Unix audio/mixer support                   */
@@ -273,7 +260,15 @@ static boolean ForkAudioProcess(void)
     return FALSE;
   }
 
-  if (IS_CHILD_PROCESS(audio.mixer_pid))
+  if (audio.mixer_pid == 0)            /* we are the child process */
+    audio.mixer_pid = getpid();
+
+#if 0
+  printf("PID: %d [%s]\n", getpid(),(IS_CHILD_PROCESS() ? "child" : "parent"));
+  Delay(10000 * 0);
+#endif
+
+  if (IS_CHILD_PROCESS())
     Mixer_Main();                      /* this function never returns */
   else
     close(audio.mixer_pipe[0]);                /* no reading from pipe needed */
@@ -304,7 +299,7 @@ void UnixCloseAudio(void)
   if (audio.device_fd)
     close(audio.device_fd);
 
-  if (IS_PARENT_PROCESS(audio.mixer_pid))
+  if (IS_PARENT_PROCESS() && HAS_CHILD_PROCESS())
     kill(audio.mixer_pid, SIGTERM);
 }
 
@@ -471,7 +466,7 @@ static void InitAudioDevice(struct AudioFormatInfo *afmt)
 
 static void SendSoundControlToMixerProcess(SoundControl *snd_ctrl)
 {
-  if (IS_CHILD_PROCESS(audio.mixer_pid))
+  if (IS_CHILD_PROCESS())
     return;
 
   if (write(audio.mixer_pipe[1], snd_ctrl, sizeof(SoundControl)) < 0)
@@ -484,7 +479,7 @@ static void SendSoundControlToMixerProcess(SoundControl *snd_ctrl)
 
 static void ReadSoundControlFromMainProcess(SoundControl *snd_ctrl)
 {
-  if (IS_PARENT_PROCESS(audio.mixer_pid))
+  if (IS_PARENT_PROCESS())
     return;
 
   if (read(audio.mixer_pipe[0], snd_ctrl, sizeof(SoundControl))
@@ -492,19 +487,21 @@ static void ReadSoundControlFromMainProcess(SoundControl *snd_ctrl)
     Error(ERR_EXIT_SOUND_SERVER, "broken pipe -- no sounds");
 }
 
-static void WriteReloadInfoToPipe(char *set_name, int type)
+static void WriteReloadInfoToPipe(char *set_identifier, int type)
 {
   SoundControl snd_ctrl;
   TreeInfo *ti = (type == SND_CTRL_RELOAD_SOUNDS ? artwork.snd_current :
                  artwork.mus_current);
   unsigned long str_size1 = strlen(leveldir_current->fullpath) + 1;
-  unsigned long str_size2 = strlen(ti->basepath) + 1;
-  unsigned long str_size3 = strlen(ti->fullpath) + 1;
+  unsigned long str_size2 = strlen(leveldir_current->sounds_path) + 1;
+  unsigned long str_size3 = strlen(leveldir_current->music_path) + 1;
+  unsigned long str_size4 = strlen(ti->basepath) + 1;
+  unsigned long str_size5 = strlen(ti->fullpath) + 1;
   boolean override_level_artwork = (type == SND_CTRL_RELOAD_SOUNDS ?
                                    setup.override_level_sounds :
                                    setup.override_level_music);
 
-  if (IS_CHILD_PROCESS(audio.mixer_pid))
+  if (IS_CHILD_PROCESS())
     return;
 
   if (leveldir_current == NULL)                /* should never happen */
@@ -512,11 +509,11 @@ static void WriteReloadInfoToPipe(char *set_name, int type)
 
   snd_ctrl.active = FALSE;
   snd_ctrl.state = type;
-  snd_ctrl.data_len = strlen(set_name) + 1;
+  snd_ctrl.data_len = strlen(set_identifier) + 1;
 
   if (write(audio.mixer_pipe[1], &snd_ctrl,
            sizeof(snd_ctrl)) < 0 ||
-      write(audio.mixer_pipe[1], set_name,
+      write(audio.mixer_pipe[1], set_identifier,
            snd_ctrl.data_len) < 0 ||
       write(audio.mixer_pipe[1], &override_level_artwork,
            sizeof(boolean)) < 0 ||
@@ -530,12 +527,20 @@ static void WriteReloadInfoToPipe(char *set_name, int type)
            sizeof(unsigned long)) < 0 ||
       write(audio.mixer_pipe[1], &str_size3,
            sizeof(unsigned long)) < 0 ||
+      write(audio.mixer_pipe[1], &str_size4,
+           sizeof(unsigned long)) < 0 ||
+      write(audio.mixer_pipe[1], &str_size5,
+           sizeof(unsigned long)) < 0 ||
       write(audio.mixer_pipe[1], leveldir_current->fullpath,
            str_size1) < 0 ||
-      write(audio.mixer_pipe[1], ti->basepath,
+      write(audio.mixer_pipe[1], leveldir_current->sounds_path,
            str_size2) < 0 ||
+      write(audio.mixer_pipe[1], leveldir_current->music_path,
+           str_size3) < 0 ||
+      write(audio.mixer_pipe[1], ti->basepath,
+           str_size4) < 0 ||
       write(audio.mixer_pipe[1], ti->fullpath,
-           str_size3) < 0)
+           str_size5) < 0)
   {
     Error(ERR_WARN, "cannot pipe to child process -- no sounds");
     audio.sound_available = audio.sound_enabled = FALSE;
@@ -548,29 +553,34 @@ static void ReadReloadInfoFromPipe(SoundControl *snd_ctrl)
   TreeInfo **ti_ptr = ((snd_ctrl->state & SND_CTRL_RELOAD_SOUNDS) ?
                       &artwork.snd_current : &artwork.mus_current);
   TreeInfo *ti = *ti_ptr;
-  unsigned long str_size1, str_size2, str_size3;
-  static char *set_name = NULL;
+  unsigned long str_size1, str_size2, str_size3, str_size4, str_size5;
+  static char *set_identifier = NULL;
   boolean *override_level_artwork = (snd_ctrl->state & SND_CTRL_RELOAD_SOUNDS ?
                                     &setup.override_level_sounds :
                                     &setup.override_level_music);
 
-  if (set_name)
-    free(set_name);
+  if (set_identifier)
+    free(set_identifier);
 
-  set_name = checked_malloc(snd_ctrl->data_len);
+  set_identifier = checked_malloc(snd_ctrl->data_len);
 
   if (leveldir_current == NULL)
     leveldir_current = checked_calloc(sizeof(TreeInfo));
+
   if (ti == NULL)
     ti = *ti_ptr = checked_calloc(sizeof(TreeInfo));
   if (leveldir_current->fullpath != NULL)
     free(leveldir_current->fullpath);
+  if (leveldir_current->sounds_path != NULL)
+    free(leveldir_current->sounds_path);
+  if (leveldir_current->music_path != NULL)
+    free(leveldir_current->music_path);
   if (ti->basepath != NULL)
     free(ti->basepath);
   if (ti->fullpath != NULL)
     free(ti->fullpath);
 
-  if (read(audio.mixer_pipe[0], set_name,
+  if (read(audio.mixer_pipe[0], set_identifier,
           snd_ctrl->data_len) != snd_ctrl->data_len ||
       read(audio.mixer_pipe[0], override_level_artwork,
           sizeof(boolean)) != sizeof(boolean) ||
@@ -583,25 +593,35 @@ static void ReadReloadInfoFromPipe(SoundControl *snd_ctrl)
       read(audio.mixer_pipe[0], &str_size2,
           sizeof(unsigned long)) != sizeof(unsigned long) ||
       read(audio.mixer_pipe[0], &str_size3,
+          sizeof(unsigned long)) != sizeof(unsigned long) ||
+      read(audio.mixer_pipe[0], &str_size4,
+          sizeof(unsigned long)) != sizeof(unsigned long) ||
+      read(audio.mixer_pipe[0], &str_size5,
           sizeof(unsigned long)) != sizeof(unsigned long))
     Error(ERR_EXIT_SOUND_SERVER, "broken pipe -- no sounds");
 
   leveldir_current->fullpath = checked_calloc(str_size1);
-  ti->basepath = checked_calloc(str_size2);
-  ti->fullpath = checked_calloc(str_size3);
+  leveldir_current->sounds_path = checked_calloc(str_size2);
+  leveldir_current->music_path = checked_calloc(str_size3);
+  ti->basepath = checked_calloc(str_size4);
+  ti->fullpath = checked_calloc(str_size5);
 
   if (read(audio.mixer_pipe[0], leveldir_current->fullpath,
           str_size1) != str_size1 ||
-      read(audio.mixer_pipe[0], ti->basepath,
+      read(audio.mixer_pipe[0], leveldir_current->sounds_path,
           str_size2) != str_size2 ||
+      read(audio.mixer_pipe[0], leveldir_current->music_path,
+          str_size3) != str_size3 ||
+      read(audio.mixer_pipe[0], ti->basepath,
+          str_size4) != str_size4 ||
       read(audio.mixer_pipe[0], ti->fullpath,
-          str_size3) != str_size3)
+          str_size5) != str_size5)
     Error(ERR_EXIT_SOUND_SERVER, "broken pipe -- no sounds");
 
   if (snd_ctrl->state & SND_CTRL_RELOAD_SOUNDS)
-    artwork.sounds_set_current_name = set_name;
+    artwork.snd_current_identifier = set_identifier;
   else
-    artwork.music_set_current_name = set_name;
+    artwork.mus_current_identifier = set_identifier;
 }
 
 #endif /* AUDIO_UNIX_NATIVE */
@@ -803,6 +823,7 @@ static void Mixer_InsertSound(SoundControl snd_ctrl)
 {
   SoundInfo *snd_info;
   int i, k;
+  int num_sounds = getSoundListSize();
 
 #if 0
   printf("NEW SOUND %d ARRIVED [%d] [%d ACTIVE CHANNELS]\n",
@@ -819,15 +840,22 @@ static void Mixer_InsertSound(SoundControl snd_ctrl)
   else if (snd_ctrl.nr >= num_sounds)
     return;
 
+#if 0
   snd_info = (IS_MUSIC(snd_ctrl) ? Music[snd_ctrl.nr] : Sound[snd_ctrl.nr]);
+#else
+  snd_info = (IS_MUSIC(snd_ctrl) ? Music[snd_ctrl.nr] :
+             getSoundInfoEntryFromSoundID(snd_ctrl.nr));
+#endif
+
   if (snd_info == NULL)
     return;
 
   /* copy sound sample and format information */
-  snd_ctrl.type     = snd_info->type;
-  snd_ctrl.format   = snd_info->format;
-  snd_ctrl.data_ptr = snd_info->data_ptr;
-  snd_ctrl.data_len = snd_info->data_len;
+  snd_ctrl.type         = snd_info->type;
+  snd_ctrl.format       = snd_info->format;
+  snd_ctrl.data_ptr     = snd_info->data_ptr;
+  snd_ctrl.data_len     = snd_info->data_len;
+  snd_ctrl.num_channels = snd_info->num_channels;
 
   /* play music samples on a dedicated music channel */
   if (IS_MUSIC(snd_ctrl))
@@ -941,11 +969,16 @@ static void Mixer_InsertSound(SoundControl snd_ctrl)
     unsigned long playing_current = Counter();
     int longest = 0, longest_nr = audio.first_sound_channel;
 
+#if 0
+#if DEBUG
+    /* print some debugging information about audio channel usage */
     for (i=audio.first_sound_channel; i<audio.num_channels; i++)
     {
       Error(ERR_RETURN, "Mixer_InsertSound: %d [%d]: %ld (%ld)",
            i, mixer[i].active, mixer[i].data_len, (long)mixer[i].data_ptr);
     }
+#endif
+#endif
 
     for (i=audio.first_sound_channel; i<audio.num_channels; i++)
     {
@@ -995,7 +1028,7 @@ static void HandleSoundRequest(SoundControl snd_ctrl)
   int i;
 
 #if defined(AUDIO_UNIX_NATIVE)
-  if (IS_PARENT_PROCESS(audio.mixer_pid))
+  if (IS_PARENT_PROCESS())
   {
     SendSoundControlToMixerProcess(&snd_ctrl);
     return;
@@ -1095,33 +1128,54 @@ void StartMixer(void)
 
 static void CopySampleToMixingBuffer(SoundControl *snd_ctrl,
                                     int sample_pos, int sample_size,
-                                    short *buffer_ptr)
+                                    short *buffer_base_ptr, int buffer_pos,
+                                    int num_output_channels)
 {
-  void *sample_ptr = snd_ctrl->data_ptr;
-  int i;
+  short *buffer_ptr = buffer_base_ptr + num_output_channels * buffer_pos;
+  int num_channels = snd_ctrl->num_channels;
+  int stepsize = num_channels;
+  int output_stepsize = num_output_channels;
+  int i, j;
 
   if (snd_ctrl->format == AUDIO_FORMAT_U8)
-    for (i=0; i<sample_size; i++)
-      *buffer_ptr++ =
-       ((short)(((byte *)sample_ptr)[sample_pos + i] ^ 0x80)) << 8;
+  {
+    byte *sample_ptr = (byte *)snd_ctrl->data_ptr + num_channels * sample_pos;
+
+    for (i=0; i<num_output_channels; i++)
+    {
+      int offset = (snd_ctrl->num_channels == 1 ? 0 : i);
+
+      for (j=0; j<sample_size; j++)
+       buffer_ptr[output_stepsize * j + i] =
+         ((short)(sample_ptr[stepsize * j + offset] ^ 0x80)) << 8;
+    }
+  }
   else /* AUDIO_FORMAT_S16 */
-    for (i=0; i<sample_size; i++)
-      *buffer_ptr++ =
-       ((short *)sample_ptr)[sample_pos + i];
+  {
+    short *sample_ptr= (short *)snd_ctrl->data_ptr + num_channels * sample_pos;
+
+    for (i=0; i<num_output_channels; i++)
+    {
+      int offset = (snd_ctrl->num_channels == 1 ? 0 : i);
+
+      for (j=0; j<sample_size; j++)
+       buffer_ptr[output_stepsize * j + i] =
+         sample_ptr[stepsize * j + offset];
+    }
+  }
 }
 
 #if defined(AUDIO_STREAMING_DSP)
 static void Mixer_Main_DSP()
 {
-  static short premix_first_buffer[SND_BLOCKSIZE];
-  static short premix_left_buffer[SND_BLOCKSIZE];
-  static short premix_right_buffer[SND_BLOCKSIZE];
-  static long premix_last_buffer[SND_BLOCKSIZE];
-  static byte playing_buffer[SND_BLOCKSIZE];
+  static short premix_first_buffer[DEFAULT_AUDIO_FRAGMENT_SIZE];
+  static long premix_last_buffer[DEFAULT_AUDIO_FRAGMENT_SIZE];
+  static byte playing_buffer[DEFAULT_AUDIO_FRAGMENT_SIZE];
   boolean stereo;
   int fragment_size;
   int sample_bytes;
   int max_sample_size;
+  int num_output_channels;
   int i, j;
 
   if (!mixer_active_channels)
@@ -1138,11 +1192,12 @@ static void Mixer_Main_DSP()
   stereo = afmt.stereo;
   fragment_size = afmt.fragment_size;
   sample_bytes = (afmt.format & AUDIO_FORMAT_U8 ? 1 : 2);
-  max_sample_size = fragment_size / ((stereo ? 2 : 1) * sample_bytes);
+  num_output_channels = (stereo ? 2 : 1);
+  max_sample_size = fragment_size / (num_output_channels * sample_bytes);
 
   /* first clear the last premixing buffer */
   memset(premix_last_buffer, 0,
-        max_sample_size * (stereo ? 2 : 1) * sizeof(long));
+        max_sample_size * num_output_channels * sizeof(long));
 
   for(i=0; i<audio.num_channels; i++)
   {
@@ -1169,7 +1224,7 @@ static void Mixer_Main_DSP()
 
     /* copy original sample to first mixing buffer */
     CopySampleToMixingBuffer(&mixer[i], sample_pos, sample_size,
-                            premix_first_buffer);
+                            premix_first_buffer, 0, num_output_channels);
 
     /* are we about to restart a looping sound? */
     if (IS_LOOP(mixer[i]) && sample_size < max_sample_size)
@@ -1179,14 +1234,9 @@ static void Mixer_Main_DSP()
        int restarted_sample_size =
          MIN(max_sample_size - sample_size, sample_len);
 
-       if (mixer[i].format == AUDIO_FORMAT_U8)
-         for (j=0; j<restarted_sample_size; j++)
-           premix_first_buffer[sample_size + j] =
-             ((short)(((byte *)sample_ptr)[j] ^ 0x80)) << 8;
-       else
-         for (j=0; j<restarted_sample_size; j++)
-           premix_first_buffer[sample_size + j] =
-             ((short *)sample_ptr)[j];
+       CopySampleToMixingBuffer(&mixer[i], 0, restarted_sample_size,
+                                premix_first_buffer, sample_size,
+                                num_output_channels);
 
        mixer[i].playing_pos = restarted_sample_size;
        sample_size += restarted_sample_size;
@@ -1200,11 +1250,11 @@ static void Mixer_Main_DSP()
 
     /* adjust volume of actual sound sample */
     if (mixer[i].volume != SOUND_MAX_VOLUME)
-      for(j=0; j<sample_size; j++)
+      for(j=0; j<sample_size * num_output_channels; j++)
        premix_first_buffer[j] =
          mixer[i].volume * (long)premix_first_buffer[j] / SOUND_MAX_VOLUME;
 
-    /* fill the last mixing buffer with stereo or mono sound */
+    /* adjust left and right channel volume due to stereo sound position */
     if (stereo)
     {
       int left_volume  = SOUND_VOLUME_LEFT(mixer[i].stereo_position);
@@ -1212,20 +1262,16 @@ static void Mixer_Main_DSP()
 
       for(j=0; j<sample_size; j++)
       {
-       premix_left_buffer[j] =
-         left_volume  * premix_first_buffer[j] / SOUND_MAX_LEFT2RIGHT;
-       premix_right_buffer[j] =
-         right_volume * premix_first_buffer[j] / SOUND_MAX_LEFT2RIGHT;
-
-       premix_last_buffer[2 * j + 0] += premix_left_buffer[j];
-       premix_last_buffer[2 * j + 1] += premix_right_buffer[j];
+       premix_first_buffer[2 * j + 0] =
+         left_volume  * premix_first_buffer[2 * j + 0] / SOUND_MAX_LEFT2RIGHT;
+       premix_first_buffer[2 * j + 1] =
+         right_volume * premix_first_buffer[2 * j + 1] / SOUND_MAX_LEFT2RIGHT;
       }
     }
-    else
-    {
-      for(j=0; j<sample_size; j++)
-       premix_last_buffer[j] += premix_first_buffer[j];
-    }
+
+    /* fill the last mixing buffer with stereo or mono sound */
+    for(j=0; j<sample_size * num_output_channels; j++)
+      premix_last_buffer[j] += premix_first_buffer[j];
 
     /* delete completed sound entries from the mixer */
     if (mixer[i].playing_pos >= mixer[i].data_len)
@@ -1240,7 +1286,7 @@ static void Mixer_Main_DSP()
   }
 
   /* prepare final playing buffer according to system audio format */
-  for(i=0; i<max_sample_size * (stereo ? 2 : 1); i++)
+  for(i=0; i<max_sample_size * num_output_channels; i++)
   {
     /* cut off at 17 bit value */
     if (premix_last_buffer[i] < -65535)
@@ -1278,9 +1324,10 @@ static void Mixer_Main_DSP()
 
 static int Mixer_Main_SimpleAudio(SoundControl snd_ctrl)
 {
-  static short premix_first_buffer[SND_BLOCKSIZE];
-  static byte playing_buffer[SND_BLOCKSIZE];
-  int max_sample_size = SND_BLOCKSIZE;
+  static short premix_first_buffer[DEFAULT_AUDIO_FRAGMENT_SIZE];
+  static byte playing_buffer[DEFAULT_AUDIO_FRAGMENT_SIZE];
+  int max_sample_size = DEFAULT_AUDIO_FRAGMENT_SIZE;
+  int num_output_channels = 1;
   void *sample_ptr;
   int sample_len;
   int sample_pos;
@@ -1298,7 +1345,7 @@ static int Mixer_Main_SimpleAudio(SoundControl snd_ctrl)
 
   /* copy original sample to first mixing buffer */
   CopySampleToMixingBuffer(&mixer[i], sample_pos, sample_size,
-                          premix_first_buffer);
+                          premix_first_buffer, 0, num_output_channels);
 
   /* adjust volume of actual sound sample */
   if (mixer[i].volume != SOUND_MAX_VOLUME)
@@ -1519,7 +1566,7 @@ static int ulaw_to_linear(unsigned char ulawbyte)
 #define CHUNK_ID_LEN            4       /* IFF style chunk id length */
 #define WAV_HEADER_SIZE                16      /* size of WAV file header */
 
-static SoundInfo *Load_WAV(char *filename)
+static void *Load_WAV(char *filename)
 {
   SoundInfo *snd_info;
 #if defined(AUDIO_UNIX_NATIVE)
@@ -1530,6 +1577,7 @@ static SoundInfo *Load_WAV(char *filename)
 #endif
   char chunk_name[CHUNK_ID_LEN + 1];
   int chunk_size;
+  int data_byte_len;
   FILE *file;
 #endif
 
@@ -1624,7 +1672,8 @@ static SoundInfo *Load_WAV(char *filename)
        return NULL;
       }
 
-      if (header.num_channels != 1)
+      if (header.num_channels != 1 &&
+         header.num_channels != 2)
       {
        Error(ERR_WARN, "sound file '%s': number of %d channels not supported",
              filename, header.num_channels);
@@ -1633,7 +1682,8 @@ static SoundInfo *Load_WAV(char *filename)
        return NULL;
       }
 
-      if (header.bits_per_sample != 8 && header.bits_per_sample != 16)
+      if (header.bits_per_sample != 8 &&
+         header.bits_per_sample != 16)
       {
        Error(ERR_WARN, "sound file '%s': %d bits per sample not supported",
              filename, header.bits_per_sample);
@@ -1659,7 +1709,9 @@ static SoundInfo *Load_WAV(char *filename)
     }
     else if (strcmp(chunk_name, "data") == 0)
     {
-      snd_info->data_len = chunk_size;
+      data_byte_len = chunk_size;
+
+      snd_info->data_len = data_byte_len;
       snd_info->data_ptr = checked_malloc(snd_info->data_len);
 
       /* read sound data */
@@ -1673,8 +1725,8 @@ static SoundInfo *Load_WAV(char *filename)
        return NULL;
       }
 
-      /* check for odd number of sample bytes (data chunk is word aligned) */
-      if ((chunk_size % 2) == 1)
+      /* check for odd number of data bytes (data chunk is word aligned) */
+      if ((data_byte_len % 2) == 1)
        ReadUnusedBytesFromFile(file, 1);
     }
     else       /* unknown chunk -- ignore */
@@ -1698,6 +1750,29 @@ static SoundInfo *Load_WAV(char *filename)
     snd_info->data_len /= 2;           /* correct number of samples */
   }
 
+  snd_info->num_channels = header.num_channels;
+  if (header.num_channels == 2)
+    snd_info->data_len /= 2;           /* correct number of samples */
+
+#if 0
+  if (header.num_channels == 1)                /* convert mono sound to stereo */
+  {
+    void *buffer_ptr = checked_malloc(data_byte_len * 2);
+    void *sample_ptr = snd_info->data_ptr;
+    int sample_size = snd_info->data_len;
+    int i;
+
+    if (snd_ctrl->format == AUDIO_FORMAT_U8)
+      for (i=0; i<sample_size; i++)
+       *buffer_ptr++ =
+         ((short)(((byte *)sample_ptr)[i] ^ 0x80)) << 8;
+    else       /* AUDIO_FORMAT_S16 */
+      for (i=0; i<sample_size; i++)
+       *buffer_ptr++ =
+         ((short *)sample_ptr)[i];
+  }
+#endif
+
 #endif /* AUDIO_UNIX_NATIVE */
 
   snd_info->type = SND_TYPE_WAV;
@@ -1706,117 +1781,119 @@ static SoundInfo *Load_WAV(char *filename)
   return snd_info;
 }
 
-static void deleteSoundEntry(SoundInfo **snd_info)
+int getSoundListSize()
 {
-  if (*snd_info)
-  {
-    char *filename = (*snd_info)->source_filename;
+  return (sound_info->num_file_list_entries +
+         sound_info->num_dynamic_file_list_entries);
+}
 
-#if 0
-    printf("[decrementing reference counter of sound '%s']\n", filename);
-#endif
+struct FileInfo *getSoundListEntry(int pos)
+{
+  int num_list_entries = sound_info->num_file_list_entries;
+  int list_pos = (pos < num_list_entries ? pos : pos - num_list_entries);
 
-    if (--(*snd_info)->num_references <= 0)
-    {
-#if 0
-      printf("[deleting sound '%s']\n", filename);
-#endif
+  return (pos < num_list_entries ? &sound_info->file_list[list_pos] :
+         &sound_info->dynamic_file_list[list_pos]);
+}
 
-      /*
-      FreeSound(*snd_info);
-      */
-      deleteNodeFromList(&SoundFileList, filename, FreeSound);
-    }
+static SoundInfo *getSoundInfoEntryFromSoundID(int pos)
+{
+  int num_list_entries = sound_info->num_file_list_entries;
+  int list_pos = (pos < num_list_entries ? pos : pos - num_list_entries);
+  SoundInfo **snd_info =
+    (SoundInfo **)(pos < num_list_entries ? sound_info->artwork_list :
+                  sound_info->dynamic_artwork_list);
 
-    *snd_info = NULL;
-  }
+  return snd_info[list_pos];
 }
 
-static void replaceSoundEntry(SoundInfo **snd_info, char *filename)
+int getSoundListPropertyMappingSize()
 {
-  ListNode *node;
+  return sound_info->num_property_mapping_entries;
+}
 
-  /* check if the old and the new sound file are the same */
-  if (*snd_info && strcmp((*snd_info)->source_filename, filename) == 0)
-  {
-    /* The old and new sound are the same (have the same filename and path).
-       This usually means that this sound does not exist in this sound set
-       and a fallback to the existing sound is done. */
+struct PropertyMapping *getSoundListPropertyMapping()
+{
+  return sound_info->property_mapping;
+}
 
-#if 0
-    printf("[sound '%s' already exists (same list entry)]\n", filename);
-#endif
+void InitSoundList(struct ConfigInfo *config_list, int num_file_list_entries,
+                  struct ConfigInfo *config_suffix_list,
+                  char **base_prefixes, char **ext1_suffixes,
+                  char **ext2_suffixes, char **ext3_suffixes,
+                  char **ignore_tokens)
+{
+  int i;
 
-    return;
-  }
+  sound_info = checked_calloc(sizeof(struct ArtworkListInfo));
+  sound_info->type = ARTWORK_TYPE_SOUNDS;
 
-  /* delete existing sound file entry */
-  deleteSoundEntry(snd_info);
+  /* ---------- initialize file list and suffix lists ---------- */
 
-  /* check if the new sound file already exists in the list of sounds */
-  if ((node = getNodeFromKey(SoundFileList, filename)) != NULL)
-  {
-#if 0
-      printf("[sound '%s' already exists (other list entry)]\n", filename);
-#endif
+  sound_info->num_file_list_entries = num_file_list_entries;
+  sound_info->num_dynamic_file_list_entries = 0;
 
-      *snd_info = (SoundInfo *)node->content;
-      (*snd_info)->num_references++;
-  }
-  else if ((*snd_info = Load_WAV(filename)) != NULL)   /* load new sound */
-  {
-    (*snd_info)->num_references = 1;
-    addNodeToList(&SoundFileList, (*snd_info)->source_filename, *snd_info);
-  }
-}
+  sound_info->file_list =
+    getFileListFromConfigList(config_list, config_suffix_list, ignore_tokens,
+                             num_file_list_entries);
+  sound_info->dynamic_file_list = NULL;
 
-static void LoadCustomSound(SoundInfo **snd_info, char *basename)
-{
-  char *filename = getCustomSoundFilename(basename);
+  sound_info->num_suffix_list_entries = 0;
+  for (i=0; config_suffix_list[i].token != NULL; i++)
+    sound_info->num_suffix_list_entries++;
 
-#if 0
-  printf("GOT CUSTOM SOUND FILE '%s'\n", filename);
-#endif
+  sound_info->suffix_list = config_suffix_list;
 
-  if (strcmp(basename, SND_FILE_UNDEFINED) == 0)
-  {
-    deleteSoundEntry(snd_info);
-    return;
-  }
+  /* ---------- initialize base prefix and suffixes lists ---------- */
 
-  if (filename == NULL)
-  {
-    Error(ERR_WARN, "cannot find sound file '%s'", basename);
-    return;
-  }
+  sound_info->num_base_prefixes = 0;
+  for (i=0; base_prefixes[i] != NULL; i++)
+    sound_info->num_base_prefixes++;
 
-  replaceSoundEntry(snd_info, filename);
-}
+  sound_info->num_ext1_suffixes = 0;
+  for (i=0; ext1_suffixes[i] != NULL; i++)
+    sound_info->num_ext1_suffixes++;
 
-void InitSoundList(struct SoundEffectInfo *sounds_list, int num_list_entries)
-{
-  if (Sound == NULL)
-    Sound = checked_calloc(num_list_entries * sizeof(SoundInfo *));
+  sound_info->num_ext2_suffixes = 0;
+  for (i=0; ext2_suffixes[i] != NULL; i++)
+    sound_info->num_ext2_suffixes++;
 
-  sound_effect = sounds_list;
-  num_sounds = num_list_entries;
-}
+  sound_info->num_ext3_suffixes = 0;
+  for (i=0; ext3_suffixes[i] != NULL; i++)
+    sound_info->num_ext3_suffixes++;
 
-void LoadSoundToList(char *basename, int list_pos)
-{
-  if (Sound == NULL || list_pos >= num_sounds)
-    return;
+  sound_info->num_ignore_tokens = 0;
+  for (i=0; ignore_tokens[i] != NULL; i++)
+    sound_info->num_ignore_tokens++;
 
-#if 0
-  printf("loading sound '%s' ...  [%d]\n",
-        basename, getNumNodes(SoundFileList));
-#endif
+  sound_info->base_prefixes = base_prefixes;
+  sound_info->ext1_suffixes = ext1_suffixes;
+  sound_info->ext2_suffixes = ext2_suffixes;
+  sound_info->ext3_suffixes = ext3_suffixes;
+  sound_info->ignore_tokens = ignore_tokens;
+
+  sound_info->num_property_mapping_entries = 0;
+
+  sound_info->property_mapping = NULL;
+
+  /* ---------- initialize artwork reference and content lists ---------- */
+
+  sound_info->sizeof_artwork_list_entry = sizeof(SoundInfo *);
 
-  LoadCustomSound(&Sound[list_pos], basename);
+  sound_info->artwork_list =
+    checked_calloc(num_file_list_entries * sizeof(SoundInfo *));
+  sound_info->dynamic_artwork_list = NULL;
+
+  sound_info->content_list = NULL;
+
+  /* ---------- initialize artwork loading/freeing functions ---------- */
+
+  sound_info->load_artwork = Load_WAV;
+  sound_info->free_artwork = FreeSound;
 
 #if 0
-  printf("loading sound '%s' done [%d]\n",
-        basename, getNumNodes(SoundFileList));
+  num_sounds = sound_info->num_file_list_entries;
+  Sound = (SoundInfo **)sound_info->artwork_list;
 #endif
 }
 
@@ -1861,7 +1938,9 @@ void LoadCustomMusic(void)
       strcmp(last_music_directory, music_directory) == 0)
     return;    /* old and new music directory are the same */
 
-  last_music_directory = music_directory;
+  if (last_music_directory != NULL)
+    free(last_music_directory);
+  last_music_directory = getStringCopy(music_directory);
 
   FreeAllMusic();
 
@@ -1881,6 +1960,10 @@ void LoadCustomMusic(void)
     char *filename = getPath2(music_directory, basename);
     MusicInfo *mus_info = NULL;
 
+#if 0
+    printf("DEBUG: loading music '%s' ...\n", basename);
+#endif
+
     if (draw_init_text)
       DrawInitText(basename, 150, FC_YELLOW);
 
@@ -1895,7 +1978,7 @@ void LoadCustomMusic(void)
     {
       num_music++;
       Music = checked_realloc(Music, num_music * sizeof(MusicInfo *));
-      Music[num_music -1] = mus_info;
+      Music[num_music - 1] = mus_info;
     }
   }
 
@@ -2016,192 +2099,49 @@ void StopSoundExt(int nr, int state)
   HandleSoundRequest(snd_ctrl);
 }
 
-ListNode *newListNode()
-{
-  return checked_calloc(sizeof(ListNode));
-}
-
-void addNodeToList(ListNode **node_first, char *key, void *content)
-{
-  ListNode *node_new = newListNode();
-
-#if 0
-  printf("LIST: adding node with key '%s'\n", key);
-#endif
-
-  node_new->key = getStringCopy(key);
-  node_new->content = content;
-  node_new->next = *node_first;
-  *node_first = node_new;
-}
-
-void deleteNodeFromList(ListNode **node_first, char *key,
-                       void (*destructor_function)(void *))
-{
-  if (node_first == NULL || *node_first == NULL)
-    return;
-
-#if 0
-  printf("[CHECKING LIST KEY '%s' == '%s']\n",
-        (*node_first)->key, key);
-#endif
-
-  if (strcmp((*node_first)->key, key) == 0)
-  {
-#if 0
-    printf("[DELETING LIST ENTRY]\n");
-#endif
-
-    free((*node_first)->key);
-    if (destructor_function)
-      destructor_function((*node_first)->content);
-    *node_first = (*node_first)->next;
-  }
-  else
-    deleteNodeFromList(&(*node_first)->next, key, destructor_function);
-}
-
-ListNode *getNodeFromKey(ListNode *node_first, char *key)
-{
-  if (node_first == NULL)
-    return NULL;
-
-  if (strcmp(node_first->key, key) == 0)
-    return node_first;
-  else
-    return getNodeFromKey(node_first->next, key);
-}
-
-int getNumNodes(ListNode *node_first)
-{
-  return (node_first ? 1 + getNumNodes(node_first->next) : 0);
-}
-
-void dumpList(ListNode *node_first)
-{
-  ListNode *node = node_first;
-
-  while (node)
-  {
-    printf("['%s' (%d)]\n", node->key,
-          ((SoundInfo *)node->content)->num_references);
-    node = node->next;
-  }
-
-  printf("[%d nodes]\n", getNumNodes(node_first));
-}
-
-static void LoadSoundsInfo()
-{
-  char *filename = getCustomSoundConfigFilename();
-  struct SetupFileList *setup_file_list;
-  int i;
-
-#if 0
-  printf("GOT CUSTOM SOUND CONFIG FILE '%s'\n", filename);
-#endif
-
-  /* always start with reliable default values */
-  for (i=0; i<num_sounds; i++)
-    sound_effect[i].filename = NULL;
-
-  if (filename == NULL)
-    return;
-
-  if ((setup_file_list = loadSetupFileList(filename)))
-  {
-    for (i=0; i<num_sounds; i++)
-      sound_effect[i].filename =
-       getStringCopy(getTokenValue(setup_file_list, sound_effect[i].text));
-
-    freeSetupFileList(setup_file_list);
-
-#if 0
-    for (i=0; i<num_sounds; i++)
-    {
-      printf("'%s' ", sound_effect[i].text);
-      if (sound_effect[i].filename)
-       printf("-> '%s'\n", sound_effect[i].filename);
-      else
-       printf("-> UNDEFINED [-> '%s']\n", sound_effect[i].default_filename);
-    }
-#endif
-  }
-}
-
 static void ReloadCustomSounds()
 {
-  static boolean draw_init_text = TRUE;                /* only draw at startup */
-  int i;
-
 #if 0
-  printf("DEBUG: reloading sounds '%s' ...\n",artwork.sounds_set_current_name);
+  printf("DEBUG: reloading sounds '%s' ...\n", artwork.snd_current_identifier);
 #endif
 
-  LoadSoundsInfo();
-
-  if (draw_init_text)
-    DrawInitText("Loading sounds:", 120, FC_GREEN);
+  LoadArtworkConfig(sound_info);
+  ReloadCustomArtworkList(sound_info);
 
 #if 0
-  printf("DEBUG: reloading %d sounds ...\n", num_sounds);
-#endif
-
-  for(i=0; i<num_sounds; i++)
-  {
-    if (draw_init_text)
-      DrawInitText(sound_effect[i].text, 150, FC_YELLOW);
-
-    if (sound_effect[i].filename)
-      LoadSoundToList(sound_effect[i].filename, i);
-    else
-      LoadSoundToList(sound_effect[i].default_filename, i);
-  }
-
-  draw_init_text = FALSE;
-
-  /*
-  printf("list size == %d\n", getNumNodes(SoundFileList));
-  */
-
-#if 0
-  dumpList(SoundFileList);
+  num_sounds = getSoundListSize();
 #endif
 }
 
 static void ReloadCustomMusic()
 {
 #if 0
-  printf("DEBUG: reloading music '%s' ...\n", artwork.music_set_current_name);
-#endif
-
-#if 0
-  /* this is done directly in LoadCustomMusic() now */
-  FreeAllMusic();
+  printf("DEBUG: reloading music '%s' ...\n", artwork.mus_current_identifier);
 #endif
 
   LoadCustomMusic();
 }
 
-void InitReloadSounds(char *set_name)
+void InitReloadCustomSounds(char *set_identifier)
 {
   if (!audio.sound_available)
     return;
 
 #if defined(AUDIO_UNIX_NATIVE)
-  WriteReloadInfoToPipe(set_name, SND_CTRL_RELOAD_SOUNDS);
+  LoadArtworkConfig(sound_info);       /* also load config on sound client */
+  WriteReloadInfoToPipe(set_identifier, SND_CTRL_RELOAD_SOUNDS);
 #else
   ReloadCustomSounds();
 #endif
 }
 
-void InitReloadMusic(char *set_name)
+void InitReloadCustomMusic(char *set_identifier)
 {
   if (!audio.music_available)
     return;
 
 #if defined(AUDIO_UNIX_NATIVE)
-  WriteReloadInfoToPipe(set_name, SND_CTRL_RELOAD_MUSIC);
+  WriteReloadInfoToPipe(set_identifier, SND_CTRL_RELOAD_MUSIC);
 #else
   ReloadCustomMusic();
 #endif
@@ -2255,31 +2195,7 @@ void FreeMusic(MusicInfo *music)
 
 void FreeAllSounds()
 {
-  int i;
-
-  if (Sound == NULL)
-    return;
-
-#if 0
-  printf("%s: FREEING SOUNDS ...\n",
-        IS_CHILD_PROCESS(audio.mixer_pid) ? "CHILD" : "PARENT");
-#endif
-
-  for(i=0; i<num_sounds; i++)
-    deleteSoundEntry(&Sound[i]);
-  /*
-    FreeSound(Sound[i]);
-  */
-
-#if 0
-  printf("%s: FREEING SOUNDS -- DONE\n",
-        IS_CHILD_PROCESS(audio.mixer_pid) ? "CHILD" : "PARENT");
-#endif
-
-  free(Sound);
-
-  Sound = NULL;
-  num_sounds = 0;
+  FreeCustomArtworkLists(sound_info);
 }
 
 void FreeAllMusic()
index ec5a2a8b8c2a0a13d7382cb4a7e5a6dd73dfe72f..3b5270b9ae13f043d27be5c096134659302e4d33 100644 (file)
@@ -14,7 +14,7 @@
 #ifndef SOUND_H
 #define SOUND_H
 
-#include "platform.h"
+#include "system.h"
 
 
 #if defined(PLATFORM_UNIX) && !defined(TARGET_SDL)
@@ -37,6 +37,7 @@
 #define AUDIO_FRAGMENT_SIZE_1024       1024
 #define AUDIO_FRAGMENT_SIZE_2048       2048
 #define AUDIO_FRAGMENT_SIZE_4096       4096
+#define AUDIO_FRAGMENT_SIZE_32768      32768
 
 #define AUDIO_NUM_CHANNELS_MONO                1
 #define AUDIO_NUM_CHANNELS_STEREO      2
 #define DEFAULT_AUDIO_SAMPLE_RATE      AUDIO_SAMPLE_RATE_22050
 #endif
 
-#if defined(PLATFORM_WIN32)
-#define DEFAULT_AUDIO_FRAGMENT_SIZE    AUDIO_FRAGMENT_SIZE_2048
+#if defined(PLATFORM_HPUX)
+#define DEFAULT_AUDIO_FRAGMENT_SIZE    AUDIO_FRAGMENT_SIZE_32768
+#elif defined(PLATFORM_WIN32)
+#define DEFAULT_AUDIO_FRAGMENT_SIZE    AUDIO_FRAGMENT_SIZE_1024
 #else
 #define DEFAULT_AUDIO_FRAGMENT_SIZE    AUDIO_FRAGMENT_SIZE_512
 #endif
 #define SOUND_MAX_LEFT2RIGHT           255
 #define SOUND_MIDDLE                   (SOUND_MAX_LEFT2RIGHT / 2)
 
-/* value for undefined sound effect filename */
-#define SND_FILE_UNDEFINED             "NONE"
-
-
-struct SoundEffectInfo
-{
-  char *text;
-  char *default_filename;
-
-  char *filename;
-};
-
 
 /* general sound functions */
 void UnixOpenAudio(void);
@@ -148,9 +139,15 @@ void StopMusic(void);
 void StopSound(int);
 void StopSounds(void);
 void StopSoundExt(int, int);
-void InitSoundList(struct SoundEffectInfo *, int);
-void InitReloadSounds(char *);
-void InitReloadMusic(char *);
+
+int getSoundListSize();
+struct FileInfo *getSoundListEntry(int);
+int getSoundListPropertyMappingSize();
+struct PropertyMapping *getSoundListPropertyMapping();
+void InitSoundList(struct ConfigInfo *, int, struct ConfigInfo *,
+                  char **, char **, char **, char **, char **);
+void InitReloadCustomSounds(char *);
+void InitReloadCustomMusic(char *);
 void FreeAllSounds(void);
 void FreeAllMusic(void);
 
index 5c0b4fbe9aeb81e1602c6bf6bed9efa6ced49d6f..96adfcfebc88f2a50b5dd10670c805136593e617 100644 (file)
@@ -66,10 +66,31 @@ int                 FrameCounter = 0;
 /* init/close functions                                                      */
 /* ========================================================================= */
 
-void InitCommandName(char *argv0)
+void InitProgramInfo(char *argv0,
+                    char *userdata_directory, char *program_title,
+                    char *window_title, char *icon_title,
+                    char *x11_icon_filename, char *x11_iconmask_filename,
+                    char *msdos_cursor_filename,
+                    char *cookie_prefix, char *filename_prefix,
+                    int program_version)
 {
   program.command_basename =
     (strrchr(argv0, '/') ? strrchr(argv0, '/') + 1 : argv0);
+
+  program.userdata_directory = userdata_directory;
+  program.program_title = program_title;
+  program.window_title = window_title;
+  program.icon_title = icon_title;
+  program.x11_icon_filename = x11_icon_filename;
+  program.x11_iconmask_filename = x11_iconmask_filename;
+  program.msdos_cursor_filename = msdos_cursor_filename;
+
+  program.cookie_prefix = cookie_prefix;
+  program.filename_prefix = filename_prefix;
+
+  program.version_major = VERSION_MAJOR(program_version);
+  program.version_minor = VERSION_MINOR(program_version);
+  program.version_patch = VERSION_PATCH(program_version);
 }
 
 void InitExitFunction(void (*exit_function)(int))
@@ -86,17 +107,10 @@ void InitExitFunction(void (*exit_function)(int))
 #endif
 }
 
-void InitPlatformDependantStuff(void)
+void InitPlatformDependentStuff(void)
 {
 #if defined(PLATFORM_MSDOS)
   _fmode = O_BINARY;
-#endif
-
-#if !defined(PLATFORM_UNIX)
-  program.userdata_directory = "userdata";
-#endif
-
-#if defined(PLATFORM_MSDOS)
   initErrorFile();
 #endif
 
@@ -106,44 +120,17 @@ void InitPlatformDependantStuff(void)
 #endif
 }
 
-void ClosePlatformDependantStuff(void)
+void ClosePlatformDependentStuff(void)
 {
 #if defined(PLATFORM_MSDOS)
   dumpErrorFile();
 #endif
 }
 
-void InitProgramInfo(char *unix_userdata_directory, char *program_title,
-                    char *window_title, char *icon_title,
-                    char *x11_icon_filename, char *x11_iconmask_filename,
-                    char *msdos_pointer_filename,
-                    char *cookie_prefix, char *filename_prefix,
-                    int program_version)
-{
-#if defined(PLATFORM_UNIX)
-  program.userdata_directory = unix_userdata_directory;
-#else
-  program.userdata_directory = "userdata";
-#endif
-
-  program.program_title = program_title;
-  program.window_title = window_title;
-  program.icon_title = icon_title;
-  program.x11_icon_filename = x11_icon_filename;
-  program.x11_iconmask_filename = x11_iconmask_filename;
-  program.msdos_pointer_filename = msdos_pointer_filename;
-
-  program.cookie_prefix = cookie_prefix;
-  program.filename_prefix = filename_prefix;
-
-  program.version_major = VERSION_MAJOR(program_version);
-  program.version_minor = VERSION_MINOR(program_version);
-  program.version_patch = VERSION_PATCH(program_version);
-}
-
 void InitGfxFieldInfo(int sx, int sy, int sxsize, int sysize,
                      int real_sx, int real_sy,
-                     int full_sxsize, int full_sysize)
+                     int full_sxsize, int full_sysize,
+                     Bitmap *field_save_buffer)
 {
   gfx.sx = sx;
   gfx.sy = sy;
@@ -154,7 +141,13 @@ void InitGfxFieldInfo(int sx, int sy, int sxsize, int sysize,
   gfx.full_sxsize = full_sxsize;
   gfx.full_sysize = full_sysize;
 
+  gfx.field_save_buffer = field_save_buffer;
+
+  gfx.background_bitmap = NULL;
+  gfx.background_bitmap_mask = REDRAW_NONE;
+
   SetDrawDeactivationMask(REDRAW_NONE);                /* do not deactivate drawing */
+  SetDrawBackgroundMask(REDRAW_NONE);          /* deactivate masked drawing */
 }
 
 void InitGfxDoor1Info(int dx, int dy, int dxsize, int dysize)
@@ -185,6 +178,90 @@ void SetDrawDeactivationMask(int draw_deactivation_mask)
   gfx.draw_deactivation_mask = draw_deactivation_mask;
 }
 
+void SetDrawBackgroundMask(int draw_background_mask)
+{
+  gfx.draw_background_mask = draw_background_mask;
+}
+
+static void DrawBitmapFromTile(Bitmap *bitmap, Bitmap *tile,
+                              int dest_x, int dest_y, int width, int height)
+{
+  int bitmap_xsize = width;
+  int bitmap_ysize = height;
+  int tile_xsize = tile->width;
+  int tile_ysize = tile->height;
+  int tile_xsteps = (bitmap_xsize + tile_xsize - 1) / tile_xsize;
+  int tile_ysteps = (bitmap_ysize + tile_ysize - 1) / tile_ysize;
+  int x, y;
+
+  for (y=0; y < tile_ysteps; y++)
+  {
+    for (x=0; x < tile_xsteps; x++)
+    {
+      int draw_x = dest_x + x * tile_xsize;
+      int draw_y = dest_y + y * tile_ysize;
+      int draw_xsize = MIN(tile_xsize, bitmap_xsize - x * tile_xsize);
+      int draw_ysize = MIN(tile_ysize, bitmap_ysize - y * tile_ysize);
+
+      BlitBitmap(tile, bitmap, 0, 0, draw_xsize, draw_ysize, draw_x, draw_y);
+    }
+  }
+}
+
+void SetBackgroundBitmap(Bitmap *background_bitmap_tile, int mask)
+{
+  static Bitmap *main_bitmap_tile = NULL;
+  static Bitmap *door_bitmap_tile = NULL;
+
+  if (mask == REDRAW_FIELD)
+  {
+    if (background_bitmap_tile == main_bitmap_tile)
+      return;          /* main background tile has not changed */
+
+    main_bitmap_tile = background_bitmap_tile;
+  }
+  else if (mask == REDRAW_DOOR_1)
+  {
+    if (background_bitmap_tile == door_bitmap_tile)
+      return;  /* main background tile has not changed */
+
+    door_bitmap_tile = background_bitmap_tile;
+  }
+  else         /* should not happen */
+    return;
+
+  if (background_bitmap_tile)
+    gfx.background_bitmap_mask |= mask;
+  else
+    gfx.background_bitmap_mask &= ~mask;
+
+  if (gfx.background_bitmap == NULL)
+    gfx.background_bitmap = CreateBitmap(video.width, video.height,
+                                        DEFAULT_DEPTH);
+
+  if (background_bitmap_tile == NULL)  /* empty background requested */
+    return;
+
+  if (mask == REDRAW_FIELD)
+    DrawBitmapFromTile(gfx.background_bitmap, background_bitmap_tile,
+                      gfx.real_sx, gfx.real_sy,
+                      gfx.full_sxsize, gfx.full_sysize);
+  else
+    DrawBitmapFromTile(gfx.background_bitmap, background_bitmap_tile,
+                      gfx.dx, gfx.dy,
+                      gfx.dxsize, gfx.dysize);
+}
+
+void SetMainBackgroundBitmap(Bitmap *background_bitmap_tile)
+{
+  SetBackgroundBitmap(background_bitmap_tile, REDRAW_FIELD);
+}
+
+void SetDoorBackgroundBitmap(Bitmap *background_bitmap_tile)
+{
+  SetBackgroundBitmap(background_bitmap_tile, REDRAW_DOOR_1);
+}
+
 
 /* ========================================================================= */
 /* video functions                                                           */
@@ -195,6 +272,29 @@ inline static int GetRealDepth(int depth)
   return (depth == DEFAULT_DEPTH ? video.default_depth : depth);
 }
 
+inline static void sysFillRectangle(Bitmap *bitmap, int x, int y,
+                              int width, int height, Pixel color)
+{
+#if defined(TARGET_SDL)
+  SDLFillRectangle(bitmap, x, y, width, height, color);
+#else
+  X11FillRectangle(bitmap, x, y, width, height, color);
+#endif
+}
+
+inline static void sysCopyArea(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)
+{
+#if defined(TARGET_SDL)
+  SDLCopyArea(src_bitmap, dst_bitmap, src_x, src_y, width, height,
+             dst_x, dst_y, mask_mode);
+#else
+  X11CopyArea(src_bitmap, dst_bitmap, src_x, src_y, width, height,
+             dst_x, dst_y, mask_mode);
+#endif
+}
+
 inline void InitVideoDisplay(void)
 {
 #if defined(TARGET_SDL)
@@ -211,7 +311,6 @@ inline void CloseVideoDisplay(void)
 #if defined(TARGET_SDL)
   SDL_QuitSubSystem(SDL_INIT_VIDEO);
 #else
-
   if (display)
     XCloseDisplay(display);
 #endif
@@ -227,7 +326,7 @@ inline void InitVideoBuffer(DrawBuffer **backbuffer, DrawWindow **window,
   video.fullscreen_available = FULLSCREEN_STATUS;
   video.fullscreen_enabled = FALSE;
 
-#ifdef TARGET_SDL
+#if defined(TARGET_SDL)
   SDLInitVideoBuffer(backbuffer, window, fullscreen);
 #else
   X11InitVideoBuffer(backbuffer, window);
@@ -236,7 +335,7 @@ inline void InitVideoBuffer(DrawBuffer **backbuffer, DrawWindow **window,
 
 inline Bitmap *CreateBitmapStruct(void)
 {
-#ifdef TARGET_SDL
+#if defined(TARGET_SDL)
   return checked_calloc(sizeof(struct SDLSurfaceInfo));
 #else
   return checked_calloc(sizeof(struct X11DrawableInfo));
@@ -248,39 +347,15 @@ inline Bitmap *CreateBitmap(int width, int height, int depth)
   Bitmap *new_bitmap = CreateBitmapStruct();
   int real_depth = GetRealDepth(depth);
 
-#ifdef TARGET_SDL
-  SDL_Surface *surface_tmp, *surface_native;
-
-  if ((surface_tmp = SDL_CreateRGBSurface(SURFACE_FLAGS, width, height,
-                                         real_depth, 0, 0, 0, 0))
-      == NULL)
-    Error(ERR_EXIT, "SDL_CreateRGBSurface() failed: %s", SDL_GetError());
-
-  if ((surface_native = SDL_DisplayFormat(surface_tmp)) == NULL)
-    Error(ERR_EXIT, "SDL_DisplayFormat() failed: %s", SDL_GetError());
-
-  SDL_FreeSurface(surface_tmp);
-
-  new_bitmap->surface = surface_native;
+#if defined(TARGET_SDL)
+  SDLCreateBitmapContent(new_bitmap, width, height, real_depth);
 #else
-  Pixmap pixmap;
-
-  if ((pixmap = XCreatePixmap(display, window->drawable,
-                             width, height, real_depth))
-      == None)
-    Error(ERR_EXIT, "cannot create pixmap");
-
-  new_bitmap->drawable = pixmap;
-
-  if (window == NULL)
-    Error(ERR_EXIT, "Window GC needed for Bitmap -- create Window first");
-
-  new_bitmap->gc = window->gc;
-
-  new_bitmap->line_gc[0] = window->line_gc[0];
-  new_bitmap->line_gc[1] = window->line_gc[1];
+  X11CreateBitmapContent(new_bitmap, width, height, real_depth);
 #endif
 
+  new_bitmap->width = width;
+  new_bitmap->height = height;
+
   return new_bitmap;
 }
 
@@ -289,29 +364,10 @@ inline static void FreeBitmapPointers(Bitmap *bitmap)
   if (bitmap == NULL)
     return;
 
-#ifdef TARGET_SDL
-  if (bitmap->surface)
-    SDL_FreeSurface(bitmap->surface);
-  if (bitmap->surface_masked)
-    SDL_FreeSurface(bitmap->surface_masked);
-  bitmap->surface = NULL;
-  bitmap->surface_masked = NULL;
+#if defined(TARGET_SDL)
+  SDLFreeBitmapPointers(bitmap);
 #else
-  /* The X11 version seems to have a memory leak here -- although
-     "XFreePixmap()" is called, the correspondig memory seems not
-     to be freed (according to "ps"). The SDL version apparently
-     does not have this problem. */
-
-  if (bitmap->drawable)
-    XFreePixmap(display, bitmap->drawable);
-  if (bitmap->clip_mask)
-    XFreePixmap(display, bitmap->clip_mask);
-  if (bitmap->stored_clip_gc)
-    XFreeGC(display, bitmap->stored_clip_gc);
-  /* the other GCs are only pointers to GCs used elsewhere */
-  bitmap->drawable = None;
-  bitmap->clip_mask = None;
-  bitmap->stored_clip_gc = None;
+  X11FreeBitmapPointers(bitmap);
 #endif
 
   if (bitmap->source_filename)
@@ -342,7 +398,7 @@ inline void FreeBitmap(Bitmap *bitmap)
 
 inline void CloseWindow(DrawWindow *window)
 {
-#ifdef TARGET_X11
+#if defined(TARGET_X11)
   if (window->drawable)
   {
     XUnmapWindow(display, window->drawable);
@@ -353,55 +409,70 @@ inline void CloseWindow(DrawWindow *window)
 #endif
 }
 
-inline boolean DrawingDeactivated(int x, int y, int width, int height)
+static inline boolean CheckDrawingArea(int x, int y, int width, int height,
+                                      int draw_mask)
 {
-  if (gfx.draw_deactivation_mask != REDRAW_NONE)
-  {
-    if ((gfx.draw_deactivation_mask & REDRAW_FIELD) &&
-       x < gfx.sx + gfx.sxsize)
-      return TRUE;
-    else if ((gfx.draw_deactivation_mask & REDRAW_DOORS) &&
-            x > gfx.dx)
-    {
-      if ((gfx.draw_deactivation_mask & REDRAW_DOOR_1) &&
-         y < gfx.dy + gfx.dysize)
-       return TRUE;
-      else if ((gfx.draw_deactivation_mask & REDRAW_DOOR_2) &&
-              y > gfx.vy)
-       return TRUE;
-    }
-  }
+  if (draw_mask == REDRAW_NONE)
+    return FALSE;
+
+  if (draw_mask & REDRAW_ALL)
+    return TRUE;
+
+  if ((draw_mask & REDRAW_FIELD) && x < gfx.real_sx + gfx.full_sxsize)
+    return TRUE;
+
+  if ((draw_mask & REDRAW_DOOR_1) && x >= gfx.dx && y < gfx.dy + gfx.dysize)
+    return TRUE;
+
+  if ((draw_mask & REDRAW_DOOR_2) && x >= gfx.dx && y >= gfx.vy)
+    return TRUE;
 
   return FALSE;
 }
 
+inline boolean DrawingDeactivated(int x, int y, int width, int height)
+{
+  return CheckDrawingArea(x, y, width, height, gfx.draw_deactivation_mask);
+}
+
+inline boolean DrawingOnBackground(int x, int y)
+{
+  return ((gfx.draw_background_mask & gfx.background_bitmap_mask) &&
+         CheckDrawingArea(x, y, 1, 1, gfx.draw_background_mask));
+}
+
 inline void BlitBitmap(Bitmap *src_bitmap, Bitmap *dst_bitmap,
-                      int src_x, int src_y,
-                      int width, int height,
+                      int src_x, int src_y, int width, int height,
                       int dst_x, int dst_y)
 {
   if (DrawingDeactivated(dst_x, dst_y, width, height))
     return;
 
-#ifdef TARGET_SDL
-  SDLCopyArea(src_bitmap, dst_bitmap,
-             src_x, src_y, width, height, dst_x, dst_y, SDLCOPYAREA_OPAQUE);
-#else
-  XCopyArea(display, src_bitmap->drawable, dst_bitmap->drawable,
-           dst_bitmap->gc, src_x, src_y, width, height, dst_x, dst_y);
-#endif
+  sysCopyArea(src_bitmap, dst_bitmap, src_x, src_y, width, height,
+             dst_x, dst_y, BLIT_OPAQUE);
 }
 
-inline void ClearRectangle(Bitmap *bitmap, int x, int y, int width, int height)
+inline void FillRectangle(Bitmap *bitmap, int x, int y, int width, int height,
+                         Pixel color)
 {
   if (DrawingDeactivated(x, y, width, height))
     return;
 
-#ifdef TARGET_SDL
-  SDLFillRectangle(bitmap, x, y, width, height, 0x000000);
-#else
-  XFillRectangle(display, bitmap->drawable, bitmap->gc, x, y, width, height);
-#endif
+  sysFillRectangle(bitmap, x, y, width, height, color);
+}
+
+inline void ClearRectangle(Bitmap *bitmap, int x, int y, int width, int height)
+{
+  FillRectangle(bitmap, x, y, width, height, BLACK_PIXEL);
+}
+
+inline void ClearRectangleOnBackground(Bitmap *bitmap, int x, int y,
+                                      int width, int height)
+{
+  if (DrawingOnBackground(x, y))
+    BlitBitmap(gfx.background_bitmap, bitmap, x, y, width, height, x, y);
+  else
+    ClearRectangle(bitmap, x, y, width, height);
 }
 
 #if 0
@@ -412,7 +483,7 @@ static GC last_clip_gc = 0; /* needed for XCopyArea() through clip mask */
 
 inline void SetClipMask(Bitmap *bitmap, GC clip_gc, Pixmap clip_pixmap)
 {
-#ifdef TARGET_X11
+#if defined(TARGET_X11)
   if (clip_gc)
   {
     bitmap->clip_gc = clip_gc;
@@ -426,7 +497,7 @@ inline void SetClipMask(Bitmap *bitmap, GC clip_gc, Pixmap clip_pixmap)
 
 inline void SetClipOrigin(Bitmap *bitmap, GC clip_gc, int clip_x, int clip_y)
 {
-#ifdef TARGET_X11
+#if defined(TARGET_X11)
   if (clip_gc)
   {
     bitmap->clip_gc = clip_gc;
@@ -446,24 +517,39 @@ inline void BlitBitmapMasked(Bitmap *src_bitmap, Bitmap *dst_bitmap,
   if (DrawingDeactivated(dst_x, dst_y, width, height))
     return;
 
-#ifdef TARGET_SDL
-  SDLCopyArea(src_bitmap, dst_bitmap,
-             src_x, src_y, width, height, dst_x, dst_y, SDLCOPYAREA_MASKED);
-#else
-  XCopyArea(display, src_bitmap->drawable, dst_bitmap->drawable,
-           src_bitmap->clip_gc, src_x, src_y, width, height, dst_x, dst_y);
-#endif
+  sysCopyArea(src_bitmap, dst_bitmap, src_x, src_y, width, height,
+             dst_x, dst_y, BLIT_MASKED);
+}
+
+inline void BlitBitmapOnBackground(Bitmap *src_bitmap, Bitmap *dst_bitmap,
+                                  int src_x, int src_y,
+                                  int width, int height,
+                                  int dst_x, int dst_y)
+{
+  if (DrawingOnBackground(dst_x, dst_y))
+  {
+    /* draw background */
+    BlitBitmap(gfx.background_bitmap, dst_bitmap, dst_x, dst_y, width, height,
+              dst_x, dst_y);
+
+    /* draw foreground */
+    SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc,
+                 dst_x - src_x, dst_y - src_y);
+    BlitBitmapMasked(src_bitmap, dst_bitmap, src_x, src_y, width, height,
+                    dst_x, dst_y);
+  }
+  else
+    BlitBitmap(src_bitmap, dst_bitmap, src_x, src_y, width, height,
+              dst_x, dst_y);
 }
 
 inline void DrawSimpleWhiteLine(Bitmap *bitmap, int from_x, int from_y,
                                int to_x, int to_y)
 {
-#ifdef TARGET_SDL
-  SDLDrawSimpleLine(bitmap, from_x, from_y, to_x, to_y, 0xffffff);
+#if defined(TARGET_SDL)
+  SDLDrawSimpleLine(bitmap, from_x, from_y, to_x, to_y, WHITE_PIXEL);
 #else
-  XSetForeground(display, bitmap->gc, WhitePixel(display, screen));
-  XDrawLine(display, bitmap->drawable, bitmap->gc, from_x, from_y, to_x, to_y);
-  XSetForeground(display, bitmap->gc, BlackPixel(display, screen));
+  X11DrawSimpleLine(bitmap, from_x, from_y, to_x, to_y, WHITE_PIXEL);
 #endif
 }
 
@@ -516,53 +602,34 @@ inline void DrawLines(Bitmap *bitmap, struct XY *points, int num_points,
   XSetForeground(display, bitmap->line_gc[1], pixel);
   XDrawLines(display, bitmap->drawable, bitmap->line_gc[1],
             (XPoint *)points, num_points, CoordModeOrigin);
-  /*
-  XSetForeground(display, gc, BlackPixel(display, screen));
-  */
 #endif
 }
 
 inline Pixel GetPixel(Bitmap *bitmap, int x, int y)
 {
+  if (x < 0 || x >= bitmap->width ||
+      y < 0 || y >= bitmap->height)
+    return BLACK_PIXEL;
+
 #if defined(TARGET_SDL)
   return SDLGetPixel(bitmap, x, y);
 #elif defined(TARGET_ALLEGRO)
   return AllegroGetPixel(bitmap->drawable, x, y);
 #else
-  unsigned long pixel_value;
-  XImage *pixel_image;
-
-  pixel_image = XGetImage(display, bitmap->drawable, x, y, 1, 1,
-                         AllPlanes, ZPixmap);
-  pixel_value = XGetPixel(pixel_image, 0, 0);
-
-  XDestroyImage(pixel_image);
-
-  return pixel_value;
+  return X11GetPixel(bitmap, x, y);
 #endif
 }
 
 inline Pixel GetPixelFromRGB(Bitmap *bitmap, unsigned int color_r,
                             unsigned int color_g, unsigned int color_b)
 {
-  Pixel pixel;
-
 #if defined(TARGET_SDL)
-  pixel = SDL_MapRGB(bitmap->surface->format, color_r, color_g, color_b);
+  return SDL_MapRGB(bitmap->surface->format, color_r, color_g, color_b);
 #elif defined(TARGET_ALLEGRO)
-  pixel = AllegroAllocColorCell(color_r << 8, color_g << 8, color_b << 8);
-#elif defined(TARGET_X11_NATIVE)
-  XColor xcolor;
-
-  xcolor.flags = DoRed | DoGreen | DoBlue;
-  xcolor.red = (color_r << 8);
-  xcolor.green = (color_g << 8);
-  xcolor.blue = (color_b << 8);
-  XAllocColor(display, cmap, &xcolor);
-  pixel = xcolor.pixel;
+  return AllegroAllocColorCell(color_r << 8, color_g << 8, color_b << 8);
+#else
+  return X11GetPixelFromRGB(color_r, color_g, color_b);
 #endif
-
-  return pixel;
 }
 
 inline Pixel GetPixelFromRGBcompact(Bitmap *bitmap, unsigned int color)
@@ -592,7 +659,7 @@ inline void SyncDisplay(void)
 
 inline void KeyboardAutoRepeatOn(void)
 {
-#ifdef TARGET_SDL
+#if defined(TARGET_SDL)
   SDL_EnableKeyRepeat(SDL_DEFAULT_REPEAT_DELAY / 2,
                      SDL_DEFAULT_REPEAT_INTERVAL / 2);
   SDL_EnableUNICODE(1);
@@ -604,7 +671,7 @@ inline void KeyboardAutoRepeatOn(void)
 
 inline void KeyboardAutoRepeatOff(void)
 {
-#ifdef TARGET_SDL
+#if defined(TARGET_SDL)
   SDL_EnableKeyRepeat(0, SDL_DEFAULT_REPEAT_INTERVAL);
   SDL_EnableUNICODE(0);
 #else
@@ -615,7 +682,7 @@ inline void KeyboardAutoRepeatOff(void)
 
 inline boolean PointerInWindow(DrawWindow *window)
 {
-#ifdef TARGET_SDL
+#if defined(TARGET_SDL)
   return TRUE;
 #else
   Window root, child;
@@ -632,7 +699,7 @@ inline boolean PointerInWindow(DrawWindow *window)
 
 inline boolean SetVideoMode(boolean fullscreen)
 {
-#ifdef TARGET_SDL
+#if defined(TARGET_SDL)
   return SDLSetVideoMode(&backbuffer, fullscreen);
 #else
   boolean success = TRUE;
@@ -653,7 +720,7 @@ inline boolean SetVideoMode(boolean fullscreen)
 
 inline boolean ChangeVideoModeIfNeeded(boolean fullscreen)
 {
-#ifdef TARGET_SDL
+#if defined(TARGET_SDL)
   if ((fullscreen && !video.fullscreen_enabled && video.fullscreen_available)||
       (!fullscreen && video.fullscreen_enabled))
     fullscreen = SetVideoMode(fullscreen);
@@ -721,7 +788,8 @@ void ReloadCustomImage(Bitmap *bitmap, char *basename)
   if (bitmap->width != new_bitmap->width ||
       bitmap->height != new_bitmap->height)
   {
-    Error(ERR_WARN, "ReloadCustomImage: new image has wrong dimensions");
+    Error(ERR_WARN, "ReloadCustomImage: new image '%s' has wrong dimensions",
+         filename);
     FreeBitmap(new_bitmap);
     return;
   }
@@ -730,6 +798,169 @@ void ReloadCustomImage(Bitmap *bitmap, char *basename)
   free(new_bitmap);
 }
 
+Bitmap *ZoomBitmap(Bitmap *src_bitmap, int zoom_width, int zoom_height)
+{
+  Bitmap *dst_bitmap = CreateBitmap(zoom_width, zoom_height, DEFAULT_DEPTH);
+
+#if defined(TARGET_SDL)
+  SDLZoomBitmap(src_bitmap, dst_bitmap);
+#else
+  X11ZoomBitmap(src_bitmap, dst_bitmap);
+#endif
+
+  return dst_bitmap;
+}
+
+void CreateBitmapWithSmallBitmaps(Bitmap *src_bitmap)
+{
+  Bitmap *tmp_bitmap, *tmp_bitmap_2, *tmp_bitmap_8;
+  int src_width, src_height;
+  int tmp_width, tmp_height;
+
+  src_width  = src_bitmap->width;
+  src_height = src_bitmap->height;
+
+  tmp_width  = src_width;
+  tmp_height = src_height + (src_height + 1) / 2;     /* prevent odd height */
+
+  tmp_bitmap = CreateBitmap(tmp_width, tmp_height, DEFAULT_DEPTH);
+
+  tmp_bitmap_2 = ZoomBitmap(src_bitmap, src_width / 2, src_height / 2);
+  tmp_bitmap_8 = ZoomBitmap(src_bitmap, src_width / 8, src_height / 8);
+
+  BlitBitmap(src_bitmap, tmp_bitmap, 0, 0, src_width, src_height, 0, 0);
+  BlitBitmap(tmp_bitmap_2, tmp_bitmap, 0, 0, src_width / 2, src_height / 2,
+            0, src_height);
+  BlitBitmap(tmp_bitmap_8, tmp_bitmap, 0, 0, src_width / 8, src_height / 8,
+            3 * src_width / 4, src_height);
+
+  FreeBitmap(tmp_bitmap_2);
+  FreeBitmap(tmp_bitmap_8);
+
+#if defined(TARGET_SDL)
+  /* !!! what about the old src_bitmap->surface ??? FIX ME !!! */
+  src_bitmap->surface = tmp_bitmap->surface;
+  tmp_bitmap->surface = NULL;
+#else
+  /* !!! see above !!! */
+  src_bitmap->drawable = tmp_bitmap->drawable;
+  tmp_bitmap->drawable = None;
+#endif
+
+  src_bitmap->height = tmp_bitmap->height;
+
+  FreeBitmap(tmp_bitmap);
+}
+
+
+/* ------------------------------------------------------------------------- */
+/* mouse pointer functions                                                   */
+/* ------------------------------------------------------------------------- */
+
+#if !defined(PLATFORM_MSDOS)
+/* XPM */
+static const char *cursor_image_playfield[] =
+{
+  /* width height num_colors chars_per_pixel */
+  "    16    16        3            1",
+
+  /* colors */
+  "X c #000000",
+  ". c #ffffff",
+  "  c None",
+
+  /* pixels */
+  " X              ",
+  "X.X             ",
+  " X              ",
+  "                ",
+  "                ",
+  "                ",
+  "                ",
+  "                ",
+  "                ",
+  "                ",
+  "                ",
+  "                ",
+  "                ",
+  "                ",
+  "                ",
+  "                ",
+
+  /* hot spot */
+  "1,1"
+};
+
+#if defined(TARGET_SDL)
+static const int cursor_bit_order = BIT_ORDER_MSB;
+#elif defined(TARGET_X11_NATIVE)
+static const int cursor_bit_order = BIT_ORDER_LSB;
+#endif
+
+static struct MouseCursorInfo *get_cursor_from_image(const char **image)
+{
+  struct MouseCursorInfo *cursor;
+  boolean bit_order_msb = (cursor_bit_order == BIT_ORDER_MSB);
+  int header_lines = 4;
+  int x, y, i;
+
+  cursor = checked_calloc(sizeof(struct MouseCursorInfo));
+
+  sscanf(image[0], " %d %d ", &cursor->width, &cursor->height);
+
+  i = -1;
+  for (y=0; y < cursor->width; y++)
+  {
+    for (x=0; x < cursor->height; x++)
+    {
+      int bit_nr = x % 8;
+      int bit_mask = 0x01 << (bit_order_msb ? 7 - bit_nr : bit_nr );
+
+      if (bit_nr == 0)
+      {
+        i++;
+        cursor->data[i] = cursor->mask[i] = 0;
+      }
+
+      switch (image[header_lines + y][x])
+      {
+        case 'X':
+         cursor->data[i] |= bit_mask;
+         cursor->mask[i] |= bit_mask;
+         break;
+
+        case '.':
+         cursor->mask[i] |= bit_mask;
+         break;
+
+        case ' ':
+         break;
+      }
+    }
+  }
+
+  sscanf(image[header_lines + y], "%d,%d", &cursor->hot_x, &cursor->hot_y);
+
+  return cursor;
+}
+#endif /* !PLATFORM_MSDOS */
+
+void SetMouseCursor(int mode)
+{
+#if !defined(PLATFORM_MSDOS)
+  static struct MouseCursorInfo *cursor_playfield = NULL;
+
+  if (cursor_playfield == NULL)
+    cursor_playfield = get_cursor_from_image(cursor_image_playfield);
+
+#if defined(TARGET_SDL)
+  SDLSetMouseCursor(mode == CURSOR_PLAYFIELD ? cursor_playfield : NULL);
+#elif defined(TARGET_X11_NATIVE)
+  X11SetMouseCursor(mode == CURSOR_PLAYFIELD ? cursor_playfield : NULL);
+#endif
+#endif
+}
+
 
 /* ========================================================================= */
 /* audio functions                                                           */
@@ -746,7 +977,7 @@ inline void OpenAudio(void)
   audio.sound_deactivated = FALSE;
 
   audio.mixer_pipe[0] = audio.mixer_pipe[1] = 0;
-  audio.mixer_pid = -1;
+  audio.mixer_pid = 0;
   audio.device_name = NULL;
   audio.device_fd = -1;
 
@@ -791,7 +1022,7 @@ inline void SetAudioMode(boolean enabled)
 
 inline void InitEventFilter(EventFilter filter_function)
 {
-#ifdef TARGET_SDL
+#if defined(TARGET_SDL)
   /* set event filter to filter out certain events */
   SDL_SetEventFilter(filter_function);
 #endif
@@ -799,7 +1030,7 @@ inline void InitEventFilter(EventFilter filter_function)
 
 inline boolean PendingEvent(void)
 {
-#ifdef TARGET_SDL
+#if defined(TARGET_SDL)
   return (SDL_PollEvent(NULL) ? TRUE : FALSE);
 #else
   return (XPending(display) ? TRUE : FALSE);
@@ -808,7 +1039,7 @@ inline boolean PendingEvent(void)
 
 inline void NextEvent(Event *event)
 {
-#ifdef TARGET_SDL
+#if defined(TARGET_SDL)
   SDLNextEvent(event);
 #else
   XNextEvent(display, event);
@@ -817,7 +1048,7 @@ inline void NextEvent(Event *event)
 
 inline Key GetEventKey(KeyEvent *event, boolean with_modifiers)
 {
-#ifdef TARGET_SDL
+#if defined(TARGET_SDL)
 #if 0
   printf("unicode == '%d', sym == '%d', mod == '0x%04x'\n",
         (int)event->keysym.unicode,
@@ -845,6 +1076,64 @@ inline Key GetEventKey(KeyEvent *event, boolean with_modifiers)
 #endif
 }
 
+inline KeyMod HandleKeyModState(Key key, int key_status)
+{
+  static KeyMod current_modifiers = KMOD_None;
+
+#if !defined(TARGET_SDL)
+  if (key != KSYM_UNDEFINED)   /* new key => check for modifier key change */
+  {
+    KeyMod new_modifier = KMOD_None;
+
+    switch(key)
+    {
+      case KSYM_Shift_L:
+       new_modifier = KMOD_Shift_L;
+       break;
+      case KSYM_Shift_R:
+       new_modifier = KMOD_Shift_R;
+       break;
+      case KSYM_Control_L:
+       new_modifier = KMOD_Control_L;
+       break;
+      case KSYM_Control_R:
+       new_modifier = KMOD_Control_R;
+       break;
+      case KSYM_Meta_L:
+       new_modifier = KMOD_Meta_L;
+       break;
+      case KSYM_Meta_R:
+       new_modifier = KMOD_Meta_R;
+       break;
+      case KSYM_Alt_L:
+       new_modifier = KMOD_Alt_L;
+       break;
+      case KSYM_Alt_R:
+       new_modifier = KMOD_Alt_R;
+       break;
+      default:
+       break;
+    }
+
+    if (key_status == KEY_PRESSED)
+      current_modifiers |= new_modifier;
+    else
+      current_modifiers &= ~new_modifier;
+  }
+#endif
+
+  return current_modifiers;
+}
+
+inline KeyMod GetKeyModState()
+{
+#if defined(TARGET_SDL)
+  return (KeyMod)SDL_GetModState();
+#else
+  return HandleKeyModState(KSYM_UNDEFINED, 0);
+#endif
+}
+
 inline boolean CheckCloseWindowEvent(ClientMessageEvent *event)
 {
   if (event->type != EVENT_CLIENTMESSAGE)
@@ -870,7 +1159,7 @@ inline void InitJoysticks()
 {
   int i;
 
-#ifdef NO_JOYSTICK
+#if defined(NO_JOYSTICK)
   return;      /* joysticks generally deactivated by compile-time directive */
 #endif
 
index 743a8b9bfd013d47940fce121c5fe20edd431f97..eaa71dc010602c207ad6e8186fff62930cf451ac 100644 (file)
 #include "platform.h"
 #include "types.h"
 
-#if defined(PLATFORM_MSDOS)
+
+#if defined(PLATFORM_MACOSX)
+#include "macosx.h"
+#elif defined(PLATFORM_WIN32)
+#include "windows.h"
+#elif defined(PLATFORM_MSDOS)
 #include "msdos.h"
 #endif
 
 #include "x11.h"
 #endif
 
-#if defined(PLATFORM_MACOSX)
-/* some symbols are already defined on Mac OS X */
-#define Delay Delay_internal
-#define DrawLine DrawLine_internal
-#define DrawText DrawText_internal
-#define GetPixel GetPixel_internal
-#endif
-
 
 /* the additional 'b' is needed for Win32 to open files in binary mode */
 #define MODE_READ              "rb"
 
 #define DEFAULT_DEPTH          0
 
+#define BLIT_OPAQUE            0
+#define BLIT_MASKED            1
+#define BLIT_INVERSE           2
+#define BLIT_ON_BACKGROUND     3
+
 #define FULLSCREEN_NOT_AVAILABLE FALSE
 #define FULLSCREEN_AVAILABLE    TRUE
 
 #define DEFAULT_KEY_LOAD_GAME  KSYM_F2
 #define DEFAULT_KEY_TOGGLE_PAUSE KSYM_space
 
-/* values for move directions and special "button" keys */
-#define MV_NO_MOVING           0
-#define MV_LEFT                        (1 << 0)
-#define MV_RIGHT               (1 << 1)
-#define MV_UP                  (1 << 2)
-#define MV_DOWN                        (1 << 3)
-#define KEY_BUTTON_1           (1 << 4)
-#define KEY_BUTTON_2           (1 << 5)
-#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)
+/* values for key_status */
+#define KEY_NOT_PRESSED                FALSE
+#define KEY_RELEASED           FALSE
+#define KEY_PRESSED            TRUE
 
 /* values for button status */
 #define MB_NOT_PRESSED         FALSE
 #define MB_MIDDLEBUTTON                2
 #define MB_RIGHTBUTTON         3
 
+
+/* values for move directions */
+#define MV_BIT_LEFT            0
+#define MV_BIT_RIGHT           1
+#define MV_BIT_UP              2
+#define MV_BIT_DOWN            3
+
+#define NUM_DIRECTIONS         4
+
+/* values for special "button" bitmasks */
+#define BUTTON_1               4
+#define BUTTON_2               5
+
+/* values for move direction and special "button" key bitmasks */
+#define MV_NO_MOVING           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 KEY_BUTTON_1           (1 << BUTTON_1)
+#define KEY_BUTTON_2           (1 << 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 MV_DIR_BIT(x)          ((x) == MV_LEFT  ? MV_BIT_LEFT  :       \
+                                (x) == MV_RIGHT ? MV_BIT_RIGHT :       \
+                                (x) == MV_UP    ? MV_BIT_UP    : MV_BIT_DOWN)
+
+
+/* values for animation mode (frame order and direction) */
+#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_REVERSE           (1 << 5)
+
+
 /* values for redraw_mask */
 #define REDRAW_NONE            (0)
 #define REDRAW_ALL             (1 << 0)
 #define REDRAW_FPS             (1 << 11)
 #define REDRAWTILES_THRESHOLD  (SCR_FIELDX * SCR_FIELDY / 2)
 
+
+/* values for mouse cursor */
+#define CURSOR_DEFAULT         0
+#define CURSOR_PLAYFIELD       1
+
+
 /* maximum number of parallel players supported by libgame functions */
 #define MAX_PLAYERS            4
 
 /* default name for unknown player names */
 #define ANONYMOUS_NAME         "anonymous"
 
+/* default name for new levels */
+#define NAMELESS_LEVEL_NAME    "nameless level"
+
 /* default text for non-existant artwork */
 #define NOT_AVAILABLE          "(not available)"
 
-/* default name for new levels */
-#define NAMELESS_LEVEL_NAME    "nameless level"
+/* default value for undefined filename */
+#define UNDEFINED_FILENAME     "[NONE]"
+
+/* default value for undefined parameter */
+#define ARG_DEFAULT            "[DEFAULT]"
+
+/* default values for undefined configuration file parameters */
+#define ARG_UNDEFINED          "-1000000"
+#define ARG_UNDEFINED_VALUE    (atoi(ARG_UNDEFINED))
 
 /* definitions for game sub-directories */
 #ifndef RO_GAME_DIR
 #define LEVELS_DIRECTORY       "levels"
 #define TAPES_DIRECTORY                "tapes"
 #define SCORES_DIRECTORY       "scores"
+#define DOCS_DIRECTORY         "docs"
 
 #if !defined(PLATFORM_MSDOS)
 #define GRAPHICS_SUBDIR                "gfx_classic"
 #define MUSIC_SUBDIR           "mus_orig"
 #endif
 
+
 /* areas in bitmap PIX_DOOR */
 /* meaning in PIX_DB_DOOR: (3 PAGEs)
    PAGEX1: 1. buffer for DOOR_1
 #define DOOR_GFX_PAGEY1                (0)
 #define DOOR_GFX_PAGEY2                (gfx.dysize)
 
-/* functions for version handling */
-#define VERSION_IDENT(x,y,z)   ((x) * 10000 + (y) * 100 + (z))
-#define VERSION_MAJOR(x)       ((x) / 10000)
-#define VERSION_MINOR(x)       (((x) % 10000) / 100)
-#define VERSION_PATCH(x)       ((x) % 100)
 
-/* functions for parent/child process identification */
-#define IS_PARENT_PROCESS(pid) ((pid) > 0)
-#define IS_CHILD_PROCESS(pid)  ((pid) == 0)
+/* macros for version handling */
+#define VERSION_IDENT(x,y,z)   ((x) * 1000000 + (y) * 10000 + (z) * 100)
+#define RELEASE_IDENT(x,y,z,r) (VERSION_IDENT(x,y,z) + (r))
+#define VERSION_MAJOR(x)       ((x) / 1000000)
+#define VERSION_MINOR(x)       (((x) % 1000000) / 10000)
+#define VERSION_PATCH(x)       (((x) % 10000) / 100)
+#define VERSION_RELEASE(x)     ((x) % 100)
+
+
+/* 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)
+#else
+#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 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 NUM_TREE_TYPES         4
+
+
+/* values for artwork handling */
+#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(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 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_IDENTIFIER(artwork, type)                      \
+                               ((type) == ARTWORK_TYPE_GRAPHICS ?      \
+                                (artwork).gfx_current_identifier :     \
+                                (type) == ARTWORK_TYPE_SOUNDS ?        \
+                                (artwork).snd_current_identifier :     \
+                                (artwork).mus_current_identifier)
 
 
 /* type definitions */
@@ -210,7 +337,7 @@ struct ProgramInfo
 
   char *x11_icon_filename;
   char *x11_iconmask_filename;
-  char *msdos_pointer_filename;
+  char *msdos_cursor_filename;
 
   char *cookie_prefix;
   char *filename_prefix;       /* prefix to cut off from DOS filenames */
@@ -227,17 +354,20 @@ struct OptionInfo
   char *display_name;
   char *server_host;
   int server_port;
+
   char *ro_base_directory;
   char *rw_base_directory;
   char *level_directory;
   char *graphics_directory;
   char *sounds_directory;
   char *music_directory;
+  char *docs_directory;
+  char *execute_command;
+
   boolean serveronly;
   boolean network;
   boolean verbose;
   boolean debug;
-  char *debug_command;
 };
 
 struct VideoSystemInfo
@@ -267,6 +397,20 @@ struct AudioSystemInfo
   int first_sound_channel;
 };
 
+struct FontBitmapInfo
+{
+  Bitmap *bitmap;
+  int src_x, src_y;            /* start position of animation frames */
+  int width, height;           /* width/height of each animation frame */
+  int draw_x, draw_y;          /* offset for drawing font characters */
+  int num_chars;
+  int num_chars_per_line;
+
+#if defined(TARGET_X11_NATIVE_PERFORMANCE_WORKAROUND)
+  Pixmap *clip_mask;           /* single-char-only clip mask array for X11 */
+#endif
+};
+
 struct GfxInfo
 {
   int sx, sy;
@@ -281,7 +425,19 @@ struct GfxInfo
   int vx, vy;
   int vxsize, vysize;
 
-  boolean draw_deactivation_mask;
+  int draw_deactivation_mask;
+  int draw_background_mask;
+
+  Bitmap *field_save_buffer;
+
+  Bitmap *background_bitmap;
+  int background_bitmap_mask;
+
+  int num_fonts;
+  struct FontBitmapInfo *font_bitmap_info;
+  int (*select_font_function)(int);
+
+  int anim_random_frame;
 };
 
 struct JoystickInfo
@@ -317,6 +473,19 @@ struct SetupInputInfo
   struct SetupKeyboardInfo key;
 };
 
+struct SetupEditorInfo
+{
+  boolean el_boulderdash;
+  boolean el_emerald_mine;
+  boolean el_more;
+  boolean el_sokoban;
+  boolean el_supaplex;
+  boolean el_diamond_caves;
+  boolean el_dx_boulderdash;
+  boolean el_chars;
+  boolean el_custom;
+};
+
 struct SetupShortcutInfo
 {
   Key save_game;
@@ -324,6 +493,12 @@ struct SetupShortcutInfo
   Key toggle_pause;
 };
 
+struct SetupSystemInfo
+{
+  char *sdl_audiodriver;
+  int audio_fragment_size;
+};
+
 struct SetupInfo
 {
   char *player_name;
@@ -353,16 +528,13 @@ struct SetupInfo
   boolean override_level_sounds;
   boolean override_level_music;
 
+  struct SetupEditorInfo editor;
   struct SetupShortcutInfo shortcut;
   struct SetupInputInfo input[MAX_PLAYERS];
+  struct SetupSystemInfo system;
+  struct OptionInfo options;
 };
 
-#define TREE_TYPE_GENERIC              0
-#define TREE_TYPE_LEVEL_DIR            1
-#define TREE_TYPE_GRAPHICS_DIR         2
-#define TREE_TYPE_SOUNDS_DIR           3
-#define TREE_TYPE_MUSIC_DIR            4
-
 struct TreeInfo
 {
   struct TreeInfo **node_top;          /* topmost node in tree */
@@ -377,22 +549,32 @@ struct TreeInfo
 
   /* fields for "type == TREE_TYPE_LEVEL_DIR" */
 
-  char *filename;      /* level series single directory name */
-  char *fullpath;      /* complete path relative to level directory */
-  char *basepath;      /* absolute base path of level directory */
-  char *name;          /* level series name, as displayed on main screen */
-  char *name_short;    /* optional short name for level selection screen */
-  char *name_sorting;  /* optional sorting name for correct level sorting */
-  char *author;                /* level series author name levels without author */
-  char *imported_from; /* optional comment for imported level series */
+  char *filename;      /* 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 *imported_from; /* optional comment for imported levels or artwork */
+
+  char *graphics_set;  /* optional custom graphics set (level tree only) */
+  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) */
+
   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 level_group; /* directory contains more level series directories */
   boolean parent_link; /* entry links back to parent directory */
   boolean user_defined;        /* user defined levels are stored in home directory */
   boolean readonly;    /* readonly levels can not be changed with editor */
+
   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 */
@@ -414,9 +596,102 @@ struct ArtworkInfo
   MusicDirTree *mus_first;
   MusicDirTree *mus_current;
 
-  char *graphics_set_current_name;
-  char *sounds_set_current_name;
-  char *music_set_current_name;
+  char *gfx_current_identifier;
+  char *snd_current_identifier;
+  char *mus_current_identifier;
+};
+
+struct ValueTextInfo
+{
+  int value;
+  char *text;
+};
+
+struct ConfigInfo
+{
+  char *token;
+  char *value;
+  int type;
+};
+
+struct TokenIntPtrInfo
+{
+  char *token;
+  int *value;
+};
+
+struct FileInfo
+{
+  char *token;
+
+  char *default_filename;
+  char *filename;
+
+  char **default_parameter;                    /* array of file parameters */
+  char **parameter;                            /* array of file parameters */
+
+  boolean redefined;
+};
+
+struct SetupFileList
+{
+  char *token;
+  char *value;
+
+  struct SetupFileList *next;
+};
+
+struct ListNodeInfo
+{
+  char *source_filename;                       /* primary key for node list */
+  int num_references;
+};
+
+struct PropertyMapping
+{
+  int base_index;
+  int ext1_index;
+  int ext2_index;
+  int ext3_index;
+
+  int artwork_index;
+};
+
+struct ArtworkListInfo
+{
+  int type;                                    /* type of artwork */
+
+  int num_file_list_entries;
+  int num_dynamic_file_list_entries;
+  struct FileInfo *file_list;                  /* static artwork file array */
+  struct FileInfo *dynamic_file_list;          /* dynamic artwrk file array */
+
+  int num_suffix_list_entries;
+  struct ConfigInfo *suffix_list;              /* parameter suffixes array */
+
+  int num_base_prefixes;
+  int num_ext1_suffixes;
+  int num_ext2_suffixes;
+  int num_ext3_suffixes;
+  char **base_prefixes;                                /* base token prefixes array */
+  char **ext1_suffixes;                                /* property suffixes array 1 */
+  char **ext2_suffixes;                                /* property suffixes array 2 */
+  char **ext3_suffixes;                                /* property suffixes array 3 */
+
+  int num_ignore_tokens;
+  char **ignore_tokens;                                /* file tokens to be ignored */
+
+  int num_property_mapping_entries;
+  struct PropertyMapping *property_mapping;    /* mapping token -> artwork */
+
+  int sizeof_artwork_list_entry;
+
+  struct ListNodeInfo **artwork_list;          /* static artwork node array */
+  struct ListNodeInfo **dynamic_artwork_list;  /* dynamic artwrk node array */
+  struct ListNode *content_list;               /* dynamic artwork node list */
+
+  void *(*load_artwork)(char *);               /* constructor function */
+  void (*free_artwork)(void *);                        /* destructor function */
 };
 
 
@@ -429,6 +704,7 @@ extern struct OptionInfo    options;
 extern struct VideoSystemInfo  video;
 extern struct AudioSystemInfo  audio;
 extern struct GfxInfo          gfx;
+extern struct AnimInfo         anim;
 extern struct ArtworkInfo      artwork;
 extern struct JoystickInfo     joystick;
 extern struct SetupInfo                setup;
@@ -457,19 +733,21 @@ extern int                        FrameCounter;
 
 /* function definitions */
 
-void InitCommandName(char *);
-void InitExitFunction(void (*exit_function)(int));
-void InitPlatformDependantStuff(void);
-void ClosePlatformDependantStuff(void);
-
 void InitProgramInfo(char *, char *, char *, char *, char *, char *, char *,
-                    char *, char *, int);
+                    char *, char *, char *, int);
+
+void InitExitFunction(void (*exit_function)(int));
+void InitPlatformDependentStuff(void);
+void ClosePlatformDependentStuff(void);
 
-void InitGfxFieldInfo(int, int, int, int, int, int, int, int);
+void InitGfxFieldInfo(int, int, int, int, int, int, int, int, Bitmap *);
 void InitGfxDoor1Info(int, int, int, int);
 void InitGfxDoor2Info(int, int, int, int);
 void InitGfxScrollbufferInfo(int, int);
-void SetDrawDeactivationMask(int );
+void SetDrawDeactivationMask(int);
+void SetDrawBackgroundMask(int);
+void SetMainBackgroundBitmap(Bitmap *);
+void SetDoorBackgroundBitmap(Bitmap *);
 
 inline void InitVideoDisplay(void);
 inline void CloseVideoDisplay(void);
@@ -478,10 +756,15 @@ inline Bitmap *CreateBitmapStruct(void);
 inline Bitmap *CreateBitmap(int, int, int);
 inline void FreeBitmap(Bitmap *);
 inline void BlitBitmap(Bitmap *, Bitmap *, int, int, int, int, int, int);
+inline void FillRectangle(Bitmap *, int, int, int, int, Pixel);
 inline void ClearRectangle(Bitmap *, int, int, int, int);
+inline void ClearRectangleOnBackground(Bitmap *, int, int, int, int);
 inline void SetClipMask(Bitmap *, GC, Pixmap);
 inline void SetClipOrigin(Bitmap *, GC, int, int);
 inline void BlitBitmapMasked(Bitmap *, Bitmap *, int, int, int, int, int, int);
+inline boolean DrawingOnBackground(int, int);
+inline void BlitBitmapOnBackground(Bitmap *, Bitmap *, int, int, int, int, int,
+                                  int);
 inline void DrawSimpleWhiteLine(Bitmap *, int, int, int, int);
 inline void DrawLines(Bitmap *, struct XY *, int, Pixel);
 inline Pixel GetPixel(Bitmap *, int, int);
@@ -500,6 +783,11 @@ Bitmap *LoadImage(char *);
 Bitmap *LoadCustomImage(char *);
 void ReloadCustomImage(Bitmap *, char *);
 
+Bitmap *ZoomBitmap(Bitmap *, int, int);
+void CreateBitmapWithSmallBitmaps(Bitmap *);
+
+void SetMouseCursor(int);
+
 inline void OpenAudio(void);
 inline void CloseAudio(void);
 inline void SetAudioMode(boolean);
@@ -508,6 +796,8 @@ inline void InitEventFilter(EventFilter);
 inline boolean PendingEvent(void);
 inline void NextEvent(Event *event);
 inline Key GetEventKey(KeyEvent *, boolean);
+inline KeyMod HandleKeyModState(Key, int);
+inline KeyMod GetKeyModState();
 inline boolean CheckCloseWindowEvent(ClientMessageEvent *);
 
 inline void InitJoysticks();
index 16381e494438e8872531972fb045c6eb1a884a76..5558fc1c2b8efb471a4f994dfdc050fead8b6118 100644 (file)
 #include <stdarg.h>
 
 #include "text.h"
+#include "misc.h"
 
 
 /* ========================================================================= */
-/* exported variables                                                        */
+/* font functions                                                            */
 /* ========================================================================= */
 
-struct FontInfo                font;
+#if defined(TARGET_X11_NATIVE_PERFORMANCE_WORKAROUND)
+static GC      font_clip_gc = None;
+
+static void InitFontClipmasks()
+{
+  XGCValues clip_gc_values;
+  unsigned long clip_gc_valuemask;
+  GC copy_clipmask_gc;
+  int i, j;
+
+  /* This stuff is needed because X11 (XSetClipOrigin(), to be precise) is
+     often very slow when preparing a masked XCopyArea() for big Pixmaps.
+     To prevent this, create small (tile-sized) mask Pixmaps which will then
+     be set much faster with XSetClipOrigin() and speed things up a lot. */
+
+  clip_gc_values.graphics_exposures = False;
+  clip_gc_valuemask = GCGraphicsExposures;
+  font_clip_gc = XCreateGC(display, window->drawable,
+                          clip_gc_valuemask, &clip_gc_values);
+
+  /* create graphic context structures needed for clipping */
+  clip_gc_values.graphics_exposures = False;
+  clip_gc_valuemask = GCGraphicsExposures;
+  copy_clipmask_gc = XCreateGC(display,
+                              gfx.font_bitmap_info[0].bitmap->clip_mask,
+                              clip_gc_valuemask, &clip_gc_values);
+
+  /* create only those clipping Pixmaps we really need */
+  for (i=0; i < gfx.num_fonts; i++)
+  {
+    if (gfx.font_bitmap_info[i].bitmap == NULL)
+      continue;
 
+    gfx.font_bitmap_info[i].clip_mask =
+      checked_calloc(gfx.font_bitmap_info[i].num_chars * sizeof(Pixmap));
 
-/* ========================================================================= */
-/* font functions                                                            */
-/* ========================================================================= */
+    for (j=0; j < gfx.font_bitmap_info[i].num_chars; j++)
+    {
+      Bitmap *src_bitmap = gfx.font_bitmap_info[i].bitmap;
+      Pixmap src_pixmap = src_bitmap->clip_mask;
+      int xpos = j % gfx.font_bitmap_info[i].num_chars_per_line;
+      int ypos = j / gfx.font_bitmap_info[i].num_chars_per_line;
+      int width  = gfx.font_bitmap_info[i].width;
+      int height = gfx.font_bitmap_info[i].height;
+      int src_x = gfx.font_bitmap_info[i].src_x + xpos * width;
+      int src_y = gfx.font_bitmap_info[i].src_y + ypos * height;
+
+      gfx.font_bitmap_info[i].clip_mask[j] =
+       XCreatePixmap(display, window->drawable, width, height, 1);
+
+      XCopyArea(display, src_pixmap, gfx.font_bitmap_info[i].clip_mask[j],
+               copy_clipmask_gc, src_x, src_y, width, height, 0, 0);
+    }
+  }
+
+  XFreeGC(display, copy_clipmask_gc);
+}
+
+static void FreeFontClipmasks()
+{
+  int i, j;
+
+  if (gfx.num_fonts == 0 || gfx.font_bitmap_info[0].bitmap == NULL)
+    return;
+
+  for (i=0; i < gfx.num_fonts; i++)
+  {
+    if (gfx.font_bitmap_info[i].clip_mask)
+    {
+      for (j=0; j < gfx.font_bitmap_info[i].num_chars; j++)
+       XFreePixmap(display, gfx.font_bitmap_info[i].clip_mask[j]);
+      free(gfx.font_bitmap_info[i].clip_mask);
+    }
+
+    gfx.font_bitmap_info[i].clip_mask = NULL;
+    gfx.font_bitmap_info[i].num_chars = 0;
+  }
+
+  if (font_clip_gc)
+    XFreeGC(display, font_clip_gc);
+  font_clip_gc = None;
+}
+#endif /* TARGET_X11_NATIVE_PERFORMANCE_WORKAROUND */
+
+void InitFontInfo(struct FontBitmapInfo *font_bitmap_info, int num_fonts,
+                 int (*select_font_function)(int))
+{
+  gfx.num_fonts = num_fonts;
+  gfx.font_bitmap_info = font_bitmap_info;
+  gfx.select_font_function = select_font_function;
+
+#if defined(TARGET_X11_NATIVE_PERFORMANCE_WORKAROUND)
+  InitFontClipmasks();
+#endif
+}
+
+void FreeFontInfo(struct FontBitmapInfo *font_bitmap_info)
+{
+  if (font_bitmap_info == NULL)
+    return;
 
-void InitFontInfo(Bitmap *bitmap_big, Bitmap *bitmap_medium,
-                 Bitmap *bitmap_small)
+#if defined(TARGET_X11_NATIVE_PERFORMANCE_WORKAROUND)
+  FreeFontClipmasks();
+#endif
+
+  free(font_bitmap_info);
+}
+
+int getFontWidth(int font_nr)
 {
-  font.bitmap_big = bitmap_big;
-  font.bitmap_medium = bitmap_medium;
-  font.bitmap_small = bitmap_small;
+  int font_bitmap_id = gfx.select_font_function(font_nr);
+
+  return gfx.font_bitmap_info[font_bitmap_id].width;
 }
 
-int getFontWidth(int font_size, int font_type)
+int getFontHeight(int font_nr)
 {
-  return (font_size == FS_BIG ? FONT1_XSIZE :
-         font_size == FS_MEDIUM ? FONT6_XSIZE :
-         font_type == FC_SPECIAL1 ? FONT3_XSIZE :
-         font_type == FC_SPECIAL2 ? FONT4_XSIZE :
-         font_type == FC_SPECIAL3 ? FONT5_XSIZE :
-         FONT2_XSIZE);
+  int font_bitmap_id = gfx.select_font_function(font_nr);
+
+  return gfx.font_bitmap_info[font_bitmap_id].height;
 }
 
-int getFontHeight(int font_size, int font_type)
+static char getFontCharPosition(int font_nr, char c)
 {
-  return (font_size == FS_BIG ? FONT1_YSIZE :
-         font_size == FS_MEDIUM ? FONT6_YSIZE :
-         font_type == FC_SPECIAL1 ? FONT3_YSIZE :
-         font_type == FC_SPECIAL2 ? FONT4_YSIZE :
-         font_type == FC_SPECIAL3 ? FONT5_YSIZE :
-         FONT2_YSIZE);
+  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 = c - 32;
+
+  /* map some special characters to their ascii values in default font */
+  if (default_font)
+    font_pos = MAP_FONT_ASCII(c) - 32;
+
+  /* this allows dynamic special characters together with special font */
+  if (font_pos < 0 || font_pos >= font->num_chars)
+    font_pos = 0;
+
+  return font_pos;
 }
 
-void DrawInitText(char *text, int ypos, int color)
+void getFontCharSource(int font_nr, char c, Bitmap **bitmap, int *x, int *y)
 {
-  if (window && font.bitmap_small)
+  int font_bitmap_id = gfx.select_font_function(font_nr);
+  struct FontBitmapInfo *font = &gfx.font_bitmap_info[font_bitmap_id];
+  int font_pos = getFontCharPosition(font_nr, c);
+
+  *bitmap = font->bitmap;
+  *x = font->src_x + (font_pos % font->num_chars_per_line) * font->width;
+  *y = font->src_y + (font_pos / font->num_chars_per_line) * font->height;
+}
+
+void DrawInitText(char *text, int ypos, int font_nr)
+{
+  if (window &&
+      gfx.num_fonts > 0 &&
+      gfx.font_bitmap_info[font_nr].bitmap != NULL)
   {
-    ClearRectangle(window, 0, ypos, video.width, FONT2_YSIZE);
-    DrawTextExt(window, (video.width - strlen(text) * FONT2_XSIZE)/2,
-               ypos, text, FS_SMALL, color);
+    int text_width = strlen(text) * getFontWidth(font_nr);
+
+    ClearRectangle(window, 0, ypos, video.width, getFontHeight(font_nr));
+    DrawTextExt(window, (video.width - text_width) / 2, ypos, text, font_nr,
+               BLIT_OPAQUE);
     FlushDisplay();
   }
 }
 
-void DrawTextFCentered(int y, int font_type, char *format, ...)
+void DrawTextFCentered(int y, int font_nr, char *format, ...)
 {
   char buffer[MAX_OUTPUT_LINESIZE + 1];
-  int font_width = getFontWidth(FS_SMALL, font_type);
   va_list ap;
 
   va_start(ap, format);
   vsprintf(buffer, format, ap);
   va_end(ap);
 
-  DrawText(gfx.sx + (gfx.sxsize - strlen(buffer) * font_width) / 2,
-          gfx.sy + y, buffer, FS_SMALL, font_type);
+  if (strlen(buffer) > MAX_OUTPUT_LINESIZE)
+    Error(ERR_EXIT, "string too long in DrawTextFCentered() -- aborting");
+
+  DrawText(gfx.sx + (gfx.sxsize - strlen(buffer) * getFontWidth(font_nr)) / 2,
+          gfx.sy + y, buffer, font_nr);
 }
 
-void DrawTextF(int x, int y, int font_type, char *format, ...)
+void DrawTextF(int x, int y, int font_nr, char *format, ...)
 {
   char buffer[MAX_OUTPUT_LINESIZE + 1];
   va_list ap;
@@ -90,12 +213,20 @@ void DrawTextF(int x, int y, int font_type, char *format, ...)
   vsprintf(buffer, format, ap);
   va_end(ap);
 
-  DrawText(gfx.sx + x, gfx.sy + y, buffer, FS_SMALL, font_type);
+  if (strlen(buffer) > MAX_OUTPUT_LINESIZE)
+    Error(ERR_EXIT, "string too long in DrawTextF() -- aborting");
+
+  DrawText(gfx.sx + x, gfx.sy + y, buffer, font_nr);
 }
 
-void DrawText(int x, int y, char *text, int font_size, int font_type)
+void DrawText(int x, int y, char *text, int font_nr)
 {
-  DrawTextExt(drawto, x, y, text, font_size, font_type);
+  int mask_mode = BLIT_OPAQUE;
+
+  if (DrawingOnBackground(x, y))
+    mask_mode = BLIT_ON_BACKGROUND;
+
+  DrawTextExt(drawto, x, y, text, font_nr, mask_mode);
 
   if (x < gfx.dx)
     redraw_mask |= REDRAW_FIELD;
@@ -103,84 +234,88 @@ void DrawText(int x, int y, char *text, int font_size, int font_type)
     redraw_mask |= REDRAW_DOOR_1;
 }
 
-void DrawTextExt(DrawBuffer *bitmap, int x, int y,
-                char *text, int font_size, int font_type)
+void DrawTextExt(DrawBuffer *dst_bitmap, int dst_x, int dst_y, char *text,
+                int font_nr, int mask_mode)
 {
-  Bitmap *font_bitmap;
-  int font_width, font_height, font_start;
-  boolean print_inverse = FALSE;
-
-  if (font_size != FS_SMALL && font_size != FS_BIG && font_size != FS_MEDIUM)
-    font_size = FS_SMALL;
-  if (font_type < FC_RED || font_type > FC_SPECIAL3)
-    font_type = FC_RED;
-
-  font_width = getFontWidth(font_size, font_type);
-  font_height = getFontHeight(font_size, font_type);
-
-  font_bitmap = (font_size == FS_BIG ? font.bitmap_big :
-                font_size == FS_MEDIUM ? font.bitmap_medium :
-                font.bitmap_small);
-  font_start = (font_type * (font_size == FS_BIG ? FONT1_YSIZE :
-                            font_size == FS_MEDIUM ? FONT6_YSIZE :
-                            FONT2_YSIZE) *
-               FONT_LINES_PER_FONT);
-
-  if (font_type == FC_SPECIAL3)
-    font_start += (FONT4_YSIZE - FONT2_YSIZE) * FONT_LINES_PER_FONT;
-
-  while (*text)
+  int font_bitmap_id = gfx.select_font_function(font_nr);
+  struct FontBitmapInfo *font = &gfx.font_bitmap_info[font_bitmap_id];
+  int font_width = getFontWidth(font_nr);
+  int font_height = getFontHeight(font_nr);
+  Bitmap *src_bitmap;
+  int src_x, src_y;
+  char *text_ptr = text;
+
+  if (font->bitmap == NULL)
+    return;
+
+  /* add offset for drawing font characters */
+  dst_x += font->draw_x;
+  dst_y += font->draw_y;
+
+  while (*text_ptr)
   {
-    char c = *text++;
+    char c = *text_ptr++;
 
-    if (c == '~' && font_size == FS_SMALL)
-    {
-      print_inverse = TRUE;
-      continue;
-    }
+    getFontCharSource(font_nr, c, &src_bitmap, &src_x, &src_y);
 
-    if (c >= 'a' && c <= 'z')
-      c = 'A' + (c - 'a');
-    else if (c == 'ä' || c == 'Ä')
-      c = 91;
-    else if (c == 'ö' || c == 'Ö')
-      c = 92;
-    else if (c == 'ü' || c == 'Ãœ')
-      c = 93;
-    else if (c == '[' || c == ']')     /* map to normal braces */
-      c = (c == '[' ? '(' : ')');
-    else if (c == '\\')                        /* bad luck ... */
-      c = '/';
-
-    if ((c >= 32 && c <= 95) || c == '°' || c == '´')
+    if (mask_mode == BLIT_INVERSE)     /* special mode for text gadgets */
     {
-      int src_x = ((c - 32) % FONT_CHARS_PER_LINE) * font_width;
-      int src_y = ((c - 32) / FONT_CHARS_PER_LINE) * font_height + font_start;
-      int dest_x = x, dest_y = y;
+      /* first step: draw solid colored rectangle (use "cursor" character) */
+      if (strlen(text) == 1)   /* only one char inverted => draw cursor */
+      {
+       Bitmap *cursor_bitmap;
+       int cursor_x, cursor_y;
 
-      if (c == '°' || c == '´')                /* map '°' and 'TM' signs */
+       getFontCharSource(font_nr, FONT_ASCII_CURSOR, &cursor_bitmap,
+                         &cursor_x, &cursor_y);
+
+       BlitBitmap(cursor_bitmap, dst_bitmap, cursor_x, cursor_y,
+                  font_width, font_height, dst_x, dst_y);
+      }
+
+#if defined(TARGET_SDL)
+      /* second step: draw masked inverted character */
+      SDLCopyInverseMasked(src_bitmap, dst_bitmap, src_x, src_y,
+                          font_width, font_height, dst_x, dst_y);
+#else
+      /* second step: draw masked black rectangle (use "space" character) */
+      SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc,
+                   dst_x - src_x, dst_y - src_y);
+      BlitBitmapMasked(src_bitmap, dst_bitmap, 0, 0,
+                      font_width, font_height, dst_x, dst_y);
+#endif
+    }
+    else if (mask_mode == BLIT_MASKED || mask_mode == BLIT_ON_BACKGROUND)
+    {
+      if (mask_mode == BLIT_ON_BACKGROUND)
       {
-       src_x = FONT_CHARS_PER_LINE * font_width;
-       src_y = (c == '°' ? 1 : 2) * font_height + font_start;
+       /* clear font character background */
+       ClearRectangleOnBackground(dst_bitmap, dst_x, dst_y,
+                                  font_width, font_height);
       }
 
-      if (print_inverse)
+#if defined(TARGET_X11_NATIVE_PERFORMANCE_WORKAROUND)
+      /* use special font tile clipmasks */
       {
-       BlitBitmap(font_bitmap, bitmap,
-                  FONT_CHARS_PER_LINE * font_width,
-                  3 * font_height + font_start,
-                  font_width, font_height, x, y);
-
-       SetClipOrigin(font_bitmap, font_bitmap->stored_clip_gc,
-                     dest_x - src_x, dest_y - src_y);
-       BlitBitmapMasked(font_bitmap, bitmap,
-                        0, 0, font_width, font_height, dest_x, dest_y);
+       int font_pos = getFontCharPosition(font_nr, c);
+
+       SetClipMask(src_bitmap, font_clip_gc, font->clip_mask[font_pos]);
+       SetClipOrigin(src_bitmap, font_clip_gc, dst_x, dst_y);
       }
-      else
-       BlitBitmap(font_bitmap, bitmap,
-                  src_x, src_y, font_width, font_height, dest_x, dest_y);
+#else
+      SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc,
+                   dst_x - src_x, dst_y - src_y);
+#endif
+
+      BlitBitmapMasked(src_bitmap, dst_bitmap, src_x, src_y,
+                      font_width, font_height, dst_x, dst_y);
+    }
+    else       /* normal, non-masked font blitting */
+    {
+      BlitBitmap(src_bitmap, dst_bitmap, src_x, src_y,
+                font_width, font_height, dst_x, dst_y);
     }
 
-    x += font_width;
+    dst_x += font_width;
   }
 }
index f459e3fd9f392366c2fd37f176b51deb22568693..5d701fa714e4cf4073a8eb3f104324d70f8ce86a 100644 (file)
 #include "system.h"
 
 
-/* font types */
-#define FS_SMALL               0
-#define FS_BIG                 1
-#define FS_MEDIUM              2
+/* default fonts */
+#define FONT_INITIAL_1         0
+#define FONT_INITIAL_2         1
+#define FONT_INITIAL_3         2
+#define FONT_INITIAL_4         3
 
 /* font colors */
-#define FC_RED                 0
-#define FC_BLUE                        1
-#define FC_GREEN               2
-#define FC_YELLOW              3
-#define FC_SPECIAL1            4
-#define FC_SPECIAL2            5
-#define FC_SPECIAL3            6
+#define FC_RED                 FONT_INITIAL_1
+#define FC_BLUE                        FONT_INITIAL_2
+#define FC_GREEN               FONT_INITIAL_3
+#define FC_YELLOW              FONT_INITIAL_4
 
-/* font graphics definitions */
-#define FONT1_XSIZE            32
-#define FONT1_YSIZE            32
-#define FONT2_XSIZE            14
-#define FONT2_YSIZE            14
-#define FONT3_XSIZE            11
-#define FONT3_YSIZE            14
-#define FONT4_XSIZE            16
-#define FONT4_YSIZE            16
-#define FONT5_XSIZE            10
-#define FONT5_YSIZE            14
-#define FONT6_XSIZE            16
-#define FONT6_YSIZE            32
+/* text output definitions */
+#define MAX_OUTPUT_LINESIZE    1024
 
-#define FONT_CHARS_PER_LINE    16
-#define FONT_LINES_PER_FONT    4
+/* special character mapping for default fonts */
+#define FONT_ASCII_CURSOR      ((char)160)
+#define MAP_FONT_ASCII(c)      ((c) >= 'a' && (c) <= 'z' ? 'A' + (c) - 'a' : \
+                                (c) == '©'               ? 96  :             \
+                                (c) == 'ä' || (c) == 'Ä' ? 97  :             \
+                                (c) == 'ö' || (c) == 'Ö' ? 98  :             \
+                                (c) == 'ü' || (c) == 'Ãœ' ? 99  :             \
+                                (c) == '°'               ? 100 :             \
+                                (c) == '®'               ? 101 :             \
+                                (c) == FONT_ASCII_CURSOR ? 102 :             \
+                                (c))
+
+/* 64 regular ordered ASCII characters, 6 special characters, 1 cursor char. */
+#define MIN_NUM_CHARS_PER_FONT                 64
+#define DEFAULT_NUM_CHARS_PER_FONT             (MIN_NUM_CHARS_PER_FONT + 6 +1)
+#define DEFAULT_NUM_CHARS_PER_LINE             16
 
-/* text output definitions */
-#define MAX_OUTPUT_LINESIZE    256
 
 /* font structure definitions */
 
-struct FontInfo
-{
-  Bitmap *bitmap_big;
-  Bitmap *bitmap_medium;
-  Bitmap *bitmap_small;
-};
+void InitFontInfo(struct FontBitmapInfo *, int, int (*function)(int));
+void FreeFontInfo(struct FontBitmapInfo *);
 
+int getFontWidth(int);
+int getFontHeight(int);
+void getFontCharSource(int, char, Bitmap **, int *, int *);
 
-void InitFontInfo(Bitmap *, Bitmap *, Bitmap *);
-int getFontWidth(int, int);
-int getFontHeight(int, int);
 void DrawInitText(char *, int, int);
 void DrawTextF(int, int, int, char *, ...);
 void DrawTextFCentered(int, int, char *, ...);
-void DrawText(int, int, char *, int, int);
+void DrawText(int, int, char *, int);
 void DrawTextExt(DrawBuffer *, int, int, char *, int, int);
 
 #endif /* TEXT_H */
index 2546975b5b5f978e509b068043eb3c21909d0ecf..01229f019b0b7285fe295fdc135bce184504246a 100644 (file)
 
 static struct ToonScreenInfo screen_info;
 
-void InitToonScreen(Bitmap **toon_bitmap_array,
-                   Bitmap *save_buffer,
+
+/* ========================================================================= */
+/* generic animation frame calculation                                       */
+/* ========================================================================= */
+
+int getAnimationFrame(int num_frames, int delay, int mode, int start_frame,
+                     int sync_frame)
+{
+  int frame = 0;
+
+  sync_frame += start_frame * delay;
+
+  if (mode & ANIM_LOOP)                        /* looping animation */
+  {
+    frame = (sync_frame % (delay * num_frames)) / delay;
+  }
+  else if (mode & ANIM_LINEAR)         /* linear (non-looping) animation */
+  {
+    frame = sync_frame / delay;
+
+    if (frame > num_frames - 1)
+      frame = num_frames - 1;
+  }
+  else if (mode & ANIM_PINGPONG)       /* oscillate (border frames once) */
+  {
+    int max_anim_frames = 2 * num_frames - 2;
+
+    frame = (sync_frame % (delay * max_anim_frames)) / delay;
+    frame = (frame < num_frames ? frame : max_anim_frames - frame);
+  }
+  else if (mode & ANIM_PINGPONG2)      /* oscillate (border frames twice) */
+  {
+    int max_anim_frames = 2 * num_frames;
+
+    frame = (sync_frame % (delay * max_anim_frames)) / delay;
+    frame = (frame < num_frames ? frame : max_anim_frames - frame - 1);
+  }
+  else if (mode & ANIM_RANDOM)         /* play frames in random order */
+  {
+    /* note: expect different frames for the same delay cycle! */
+
+    if (gfx.anim_random_frame < 0)
+      frame = SimpleRND(num_frames);
+    else
+      frame = gfx.anim_random_frame % num_frames;
+  }
+
+  if (mode & ANIM_REVERSE)             /* use reverse animation direction */
+    frame = num_frames - frame - 1;
+
+  return frame;
+}
+
+
+/* ========================================================================= */
+/* toon animation functions                                                  */
+/* ========================================================================= */
+
+static int get_toon_direction(char *direction_raw)
+{
+  static char *direction = NULL;
+
+  /* !!! MEMORY LEAK HERE! FIX IT! !!! */
+  setString(&direction, getStringToLower(direction_raw));
+
+  return (strcmp(direction, "left")  == 0 ? MV_LEFT :
+         strcmp(direction, "right") == 0 ? MV_RIGHT :
+         strcmp(direction, "up")    == 0 ? MV_UP :
+         strcmp(direction, "down")  == 0 ? MV_DOWN : MV_NO_MOVING);
+}
+
+void InitToonScreen(Bitmap *save_buffer,
                    void (*update_function)(void),
                    void (*prepare_backbuffer_function)(void),
                    boolean (*redraw_needed_function)(void),
                    struct ToonInfo *toons, int num_toons,
                    int startx, int starty,
-                   int width, int height)
+                   int width, int height,
+                   int frame_delay_value)
 {
-  screen_info.toon_bitmap_array = toon_bitmap_array;
   screen_info.save_buffer = save_buffer;
   screen_info.update_function = update_function;
   screen_info.prepare_backbuffer_function = prepare_backbuffer_function;
@@ -43,6 +113,7 @@ void InitToonScreen(Bitmap **toon_bitmap_array,
   screen_info.starty = starty;
   screen_info.width = width;
   screen_info.height = height;
+  screen_info.frame_delay_value = frame_delay_value;
 }
 
 void DrawAnim(Bitmap *toon_bitmap, GC toon_clip_gc,
@@ -81,9 +152,10 @@ void DrawAnim(Bitmap *toon_bitmap, GC toon_clip_gc,
 
 boolean AnimateToon(int toon_nr, boolean restart)
 {
+  static unsigned long animation_frame_counter = 0;
   static int pos_x = 0, pos_y = 0;
   static int delta_x = 0, delta_y = 0;
-  static int frame = 0, frame_step = 1;
+  static int frame = 0;
   static boolean horiz_move, vert_move;
   static unsigned long anim_delay = 0;
   static unsigned long anim_delay_value = 0;
@@ -92,69 +164,79 @@ boolean AnimateToon(int toon_nr, boolean restart)
   static int cut_x,cut_y;
   static int src_x, src_y;
   static int dest_x, dest_y;
-
   struct ToonInfo *anim = &screen_info.toons[toon_nr];
-  int bitmap_nr = screen_info.toons[toon_nr].bitmap_nr;
-  Bitmap *anim_bitmap = screen_info.toon_bitmap_array[bitmap_nr];
+  Bitmap *anim_bitmap = screen_info.toons[toon_nr].bitmap;
   GC anim_clip_gc = anim_bitmap->stored_clip_gc;
+  int direction = get_toon_direction(anim->direction);
 
   if (restart)
   {
-    horiz_move = (anim->direction & (ANIMDIR_LEFT | ANIMDIR_RIGHT));
-    vert_move = (anim->direction & (ANIMDIR_UP | ANIMDIR_DOWN));
-    anim_delay_value = 1000/anim->frames_per_second;
-    frame = 0;
+    horiz_move = (direction & (MV_LEFT | MV_RIGHT));
+    vert_move = (direction & (MV_UP | MV_DOWN));
+    anim_delay_value = anim->step_delay * screen_info.frame_delay_value;
+
+    frame = getAnimationFrame(anim->anim_frames, anim->anim_delay,
+                             anim->anim_mode, anim->anim_start_frame,
+                             animation_frame_counter++);
 
     if (horiz_move)
     {
-      if (anim->position == ANIMPOS_UP)
+      int pos_bottom = screen_info.height - anim->height;
+
+      if (strcmp(anim->position, "top") == 0)
        pos_y = 0;
-      else if (anim->position == ANIMPOS_DOWN)
-       pos_y = screen_info.height - anim->height;
-      else if (anim->position == ANIMPOS_UPPER)
-       pos_y = SimpleRND((screen_info.height - anim->height) / 2);
+      else if (strcmp(anim->position, "bottom") == 0)
+       pos_y = pos_bottom;
+      else if (strcmp(anim->position, "upper")  == 0)
+       pos_y = SimpleRND(pos_bottom / 2);
+      else if (strcmp(anim->position, "lower")  == 0)
+       pos_y = pos_bottom / 2 + SimpleRND(pos_bottom / 2);
       else
-       pos_y = SimpleRND(screen_info.height - anim->height);
+       pos_y = SimpleRND(pos_bottom);
 
-      if (anim->direction == ANIMDIR_RIGHT)
+      if (direction == MV_RIGHT)
       {
-       delta_x = anim->stepsize;
+       delta_x = anim->step_offset;
        pos_x = -anim->width + delta_x;
       }
       else
       {
-       delta_x = -anim->stepsize;
+       delta_x = -anim->step_offset;
        pos_x = screen_info.width + delta_x;
       }
+
       delta_y = 0;
     }
     else
     {
-      if (anim->position == ANIMPOS_LEFT)
+      int pos_right = screen_info.width - anim->width;
+
+      if (strcmp(anim->position, "left") == 0)
        pos_x = 0;
-      else if (anim->position == ANIMPOS_RIGHT)
-       pos_x = screen_info.width - anim->width;
+      else if (strcmp(anim->position, "right")  == 0)
+       pos_x = pos_right;
       else
-       pos_x = SimpleRND(screen_info.width - anim->width);
+       pos_x = SimpleRND(pos_right);
 
-      if (anim->direction == ANIMDIR_DOWN)
+      if (direction == MV_DOWN)
       {
-       delta_y = anim->stepsize;
+       delta_y = anim->step_offset;
        pos_y = -anim->height + delta_y;
       }
       else
       {
-       delta_y = -anim->stepsize;
+       delta_y = -anim->step_offset;
        pos_y = screen_info.width + delta_y;
       }
+
       delta_x = 0;
     }
   }
 
-  if (pos_x <= -anim->width        - anim->stepsize ||
-      pos_x >=  screen_info.width  + anim->stepsize ||
-      pos_y <= -anim->height       - anim->stepsize ||
-      pos_y >=  screen_info.height + anim->stepsize)
+  if (pos_x <= -anim->width        - anim->step_offset ||
+      pos_x >=  screen_info.width  + anim->step_offset ||
+      pos_y <= -anim->height       - anim->step_offset ||
+      pos_y >=  screen_info.height + anim->step_offset)
     return TRUE;
 
   if (!DelayReached(&anim_delay, anim_delay_value))
@@ -179,8 +261,8 @@ boolean AnimateToon(int toon_nr, boolean restart)
   else if (pos_y > screen_info.height)
     pos_y = screen_info.height;
 
-  pad_x = (horiz_move ? anim->stepsize : 0);
-  pad_y = (vert_move  ? anim->stepsize : 0);
+  pad_x = (horiz_move ? anim->step_offset : 0);
+  pad_y = (vert_move  ? anim->step_offset : 0);
   src_x = anim->src_x + frame * anim->width;
   src_y = anim->src_y;
   dest_x = pos_x;
@@ -189,7 +271,7 @@ boolean AnimateToon(int toon_nr, boolean restart)
   width  = anim->width;
   height = anim->height;
 
-  if (pos_x<0)
+  if (pos_x < 0)
   {
     dest_x = 0;
     width += pos_x;
@@ -198,7 +280,7 @@ boolean AnimateToon(int toon_nr, boolean restart)
   else if (pos_x > screen_info.width - anim->width)
     width -= (pos_x - (screen_info.width - anim->width));
 
-  if (pos_y<0)
+  if (pos_y < 0)
   {
     dest_y = 0;
     height += pos_y;
@@ -216,18 +298,10 @@ boolean AnimateToon(int toon_nr, boolean restart)
 
   pos_x += delta_x;
   pos_y += delta_y;
-  frame += frame_step;
 
-  if (frame<0 || frame>=anim->frames)
-  {
-    if (anim->pingpong)
-    {
-      frame_step *= -1;
-      frame = (frame<0 ? 1 : anim->frames-2);
-    }
-    else
-      frame = (frame<0 ? anim->frames-1 : 0);
-  }
+  frame = getAnimationFrame(anim->anim_frames, anim->anim_delay,
+                           anim->anim_mode, anim->anim_start_frame,
+                           animation_frame_counter++);
 
   return FALSE;
 }
@@ -244,6 +318,10 @@ void HandleAnimation(int mode)
   if (!setup.toons)
     return;
 
+  /* this may happen after reloading graphics and redefining "num_toons" */
+  if (toon_nr >= screen_info.num_toons)
+    anim_restart = TRUE;
+
   switch(mode)
   {
     case ANIM_START:
@@ -286,7 +364,7 @@ void HandleAnimation(int mode)
     toon_nr = SimpleRND(screen_info.num_toons);
   }
 
-  anim_restart = reset_delay = AnimateToon(toon_nr,anim_restart);
+  anim_restart = reset_delay = AnimateToon(toon_nr, anim_restart);
 }
 
 void InitAnimation()
index f090b4d293922ca3b55e254293f13b8a24ab6940..313458372e363252b52ed40af19317fc3125c83b 100644 (file)
 #include "system.h"
 
 
-/* values for toon animation */
-#define ANIMDIR_LEFT   1
-#define ANIMDIR_RIGHT  2
-#define ANIMDIR_UP     4
-#define ANIMDIR_DOWN   8
-
-#define ANIMPOS_ANY    0
-#define ANIMPOS_LEFT   1
-#define ANIMPOS_RIGHT  2
-#define ANIMPOS_UP     4
-#define ANIMPOS_DOWN   8
-#define ANIMPOS_UPPER  16
-
-
 struct ToonScreenInfo
 {
-  Bitmap **toon_bitmap_array;
   Bitmap *save_buffer;
   void (*update_function)(void);
   void (*prepare_backbuffer_function)(void);
@@ -44,23 +29,53 @@ struct ToonScreenInfo
 
   int startx, starty;
   int width, height;
+
+  int frame_delay_value;
 };
 
 struct ToonInfo
 {
-  int bitmap_nr;
+#if 0
+  int graphic;
   int width, height;
   int src_x, src_y;
-  int frames;
-  int frames_per_second;
-  int stepsize;
-  boolean pingpong;
+  int anim_frames;
+  int step_delay;
+  int step_offset;
+  int anim_mode;
   int direction;
   int position;
+
+  int anim_delay;
+  int anim_start_frame;
+  Bitmap *bitmap;      /* dynamically initialized */
+
+  char *direction_str;
+  char *position_str;
+
+#else
+
+  Bitmap *bitmap;
+  int src_x, src_y;
+  int width, height;
+  int anim_frames;
+  int anim_start_frame;
+  int anim_delay;
+  int anim_mode;
+  int step_offset;
+  int step_delay;
+  char *direction;
+  char *position;
+#endif
 };
 
 
-void InitToonScreen();
+int getAnimationFrame(int, int, int, int, int);
+
+void InitToonScreen(Bitmap *, void (*update_function)(void),
+                   void (*prepare_backbuffer_function)(void),
+                   boolean (*redraw_needed_function)(void),
+                   struct ToonInfo *, int, int, int, int, int, int);
 void InitAnimation(void);
 void StopAnimation(void);
 void DoAnimation(void);
index 2ee05af0c7e961cbe16555889488fb1f7d708712..c8ab0efc85fac9471049ab5a6a15714fdd3e145c 100644 (file)
 #include <sys/types.h>
 
 typedef unsigned char boolean;
+
+#if !defined(PLATFORM_WIN32)
 typedef unsigned char byte;
+#endif
 
 #ifndef FALSE
 #define FALSE          0
@@ -46,4 +49,13 @@ typedef unsigned char byte;
 #define SIZEOF_ARRAY(array, type)      (sizeof(array) / sizeof(type))
 #define SIZEOF_ARRAY_INT(array)                SIZEOF_ARRAY(array, int)
 
+
+struct ListNode
+{
+  char *key;
+  void *content;
+  struct ListNode *next;
+};
+typedef struct ListNode ListNode;
+
 #endif /* TYPES_H */
diff --git a/src/libgame/windows.h b/src/libgame/windows.h
new file mode 100644 (file)
index 0000000..d96d4b7
--- /dev/null
@@ -0,0 +1,41 @@
+/***********************************************************
+* Artsoft Retro-Game Library                               *
+*----------------------------------------------------------*
+* (c) 1994-2003 Artsoft Entertainment                      *
+*               Holger Schemel                             *
+*               Detmolder Strasse 189                      *
+*               33604 Bielefeld                            *
+*               Germany                                    *
+*               e-mail: info@artsoft.org                   *
+*----------------------------------------------------------*
+* windows.h                                                *
+***********************************************************/
+
+#ifndef WINDOWS_H
+#define WINDOWS_H
+
+#include <shlobj.h>
+
+
+/* some symbols are already defined on Windows */
+#define CreateBitmap CreateBitmap_internal
+#define GetPixel GetPixel_internal
+#define CloseWindow CloseWindow_internal
+#define FloodFill FloodFill_internal
+
+#ifdef LoadImage
+#undef LoadImage
+#define LoadImage LoadImage_internal
+#endif
+
+#ifdef PlaySound
+#undef PlaySound
+#define PlaySound PlaySound_internal
+#endif
+
+#ifdef DrawText
+#undef DrawText
+#define DrawText DrawText_internal
+#endif
+
+#endif /* WINDOWS_H */
index 4ef1bd16f258cbb3c6eb3cb206cdf98bdd870410..d7acc801be5ae6ced5087e396fa48f35ccce3bfb 100644 (file)
@@ -198,8 +198,9 @@ static DrawWindow *X11InitWindow()
   /* Select event types wanted */
   window_event_mask =
     ExposureMask | StructureNotifyMask | FocusChangeMask |
-    ButtonPressMask | ButtonReleaseMask | PointerMotionMask |
-    PointerMotionHintMask | KeyPressMask | KeyReleaseMask;
+    ButtonPressMask | ButtonReleaseMask |
+    PointerMotionMask | PointerMotionHintMask |
+    KeyPressMask | KeyReleaseMask;
 
   XSelectInput(display, new_window->drawable, window_event_mask);
 #endif
@@ -232,6 +233,20 @@ static DrawWindow *X11InitWindow()
   return new_window;
 }
 
+void X11ZoomBitmap(Bitmap *src_bitmap, Bitmap *dst_bitmap)
+{
+#if defined(TARGET_ALLEGRO)
+  AllegroZoomBitmap(src_bitmap->drawable, dst_bitmap->drawable,
+                   src_bitmap->width, src_bitmap->height,
+                   dst_bitmap->width, dst_bitmap->height);
+#else
+  ZoomPixmap(display, src_bitmap->gc,
+            src_bitmap->drawable, dst_bitmap->drawable,
+            src_bitmap->width, src_bitmap->height,
+            dst_bitmap->width, dst_bitmap->height);
+#endif
+}
+
 static void SetImageDimensions(Bitmap *bitmap)
 {
 #if defined(TARGET_ALLEGRO)
@@ -254,6 +269,8 @@ Bitmap *X11LoadImage(char *filename)
   Bitmap *new_bitmap = CreateBitmapStruct();
   char *error = "Read_PCX_to_Pixmap(): %s '%s'";
   int pcx_err;
+  XGCValues clip_gc_values;
+  unsigned long clip_gc_valuemask;
 
   pcx_err = Read_PCX_to_Pixmap(display, window->drawable, window->gc, filename,
                               &new_bitmap->drawable, &new_bitmap->clip_mask);
@@ -296,6 +313,12 @@ Bitmap *X11LoadImage(char *filename)
     return NULL;
   }
 
+  clip_gc_values.graphics_exposures = False;
+  clip_gc_values.clip_mask = new_bitmap->clip_mask;
+  clip_gc_valuemask = GCGraphicsExposures | GCClipMask;
+  new_bitmap->stored_clip_gc = XCreateGC(display, window->drawable,
+                                        clip_gc_valuemask, &clip_gc_values);
+
   /* set GraphicContext inheritated from Window */
   new_bitmap->gc = window->gc;
 
@@ -305,4 +328,149 @@ Bitmap *X11LoadImage(char *filename)
   return new_bitmap;
 }
 
+inline void X11CreateBitmapContent(Bitmap *new_bitmap,
+                                  int width, int height, int depth)
+{
+  Pixmap pixmap;
+
+  if ((pixmap = XCreatePixmap(display, window->drawable, width, height, depth))
+      == None)
+    Error(ERR_EXIT, "cannot create pixmap");
+
+  new_bitmap->drawable = pixmap;
+
+  if (window == NULL)
+    Error(ERR_EXIT, "Window GC needed for Bitmap -- create Window first");
+
+  new_bitmap->gc = window->gc;
+
+  new_bitmap->line_gc[0] = window->line_gc[0];
+  new_bitmap->line_gc[1] = window->line_gc[1];
+}
+
+inline void X11FreeBitmapPointers(Bitmap *bitmap)
+{
+  /* The X11 version seems to have a memory leak here -- although
+     "XFreePixmap()" is called, the corresponding memory seems not
+     to be freed (according to "ps"). The SDL version apparently
+     does not have this problem. */
+
+  if (bitmap->drawable)
+    XFreePixmap(display, bitmap->drawable);
+  if (bitmap->clip_mask)
+    XFreePixmap(display, bitmap->clip_mask);
+  if (bitmap->stored_clip_gc)
+    XFreeGC(display, bitmap->stored_clip_gc);
+  /* the other GCs are only pointers to GCs used elsewhere */
+  bitmap->drawable = None;
+  bitmap->clip_mask = None;
+  bitmap->stored_clip_gc = None;
+}
+
+inline void X11CopyArea(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)
+{
+  XCopyArea(display, src_bitmap->drawable, dst_bitmap->drawable,
+           (mask_mode == BLIT_MASKED ? src_bitmap->clip_gc : dst_bitmap->gc),
+           src_x, src_y, width, height, dst_x, dst_y);
+}
+
+inline void X11FillRectangle(Bitmap *bitmap, int x, int y,
+                            int width, int height, Pixel color)
+{
+  XSetForeground(display, bitmap->gc, color);
+  XFillRectangle(display, bitmap->drawable, bitmap->gc, x, y, width, height);
+}
+
+inline void X11DrawSimpleLine(Bitmap *bitmap, int from_x, int from_y,
+                             int to_x, int to_y, Pixel color)
+{
+  XSetForeground(display, bitmap->gc, color);
+  XDrawLine(display, bitmap->drawable, bitmap->gc, from_x, from_y, to_x, to_y);
+}
+
+inline Pixel X11GetPixel(Bitmap *bitmap, int x, int y)
+{
+  XImage *pixel_image;
+  Pixel pixel_value;
+
+  pixel_image = XGetImage(display, bitmap->drawable, x, y, 1, 1,
+                         AllPlanes, ZPixmap);
+  pixel_value = XGetPixel(pixel_image, 0, 0);
+
+  XDestroyImage(pixel_image);
+
+  return pixel_value;
+}
+
+#if defined(TARGET_X11_NATIVE)
+inline Pixel X11GetPixelFromRGB(unsigned int color_r, unsigned int color_g,
+                               unsigned int color_b)
+{
+  XColor xcolor;
+  Pixel pixel;
+
+  xcolor.flags = DoRed | DoGreen | DoBlue;
+  xcolor.red = (color_r << 8);
+  xcolor.green = (color_g << 8);
+  xcolor.blue = (color_b << 8);
+
+  XAllocColor(display, cmap, &xcolor);
+  pixel = xcolor.pixel;
+
+  return pixel;
+}
+#endif /* TARGET_X11_NATIVE */
+
+
+/* ------------------------------------------------------------------------- */
+/* mouse pointer functions                                                   */
+/* ------------------------------------------------------------------------- */
+
+#if defined(TARGET_X11_NATIVE)
+
+static Cursor create_cursor(struct MouseCursorInfo *cursor_info)
+{
+  Pixmap pixmap_data, pixmap_mask;
+  XColor color_fg, color_bg;
+  Cursor cursor;
+
+  /* shape and mask are single plane pixmaps */
+  pixmap_data =
+    XCreatePixmapFromBitmapData(display, window->drawable, cursor_info->data,
+                               cursor_info->width, cursor_info->height,
+                               1, 0, 1);
+  pixmap_mask =
+    XCreatePixmapFromBitmapData(display, window->drawable, cursor_info->mask,
+                               cursor_info->width, cursor_info->height,
+                               1, 0, 1);
+
+  XParseColor(display, cmap, "black", &color_fg);
+  XParseColor(display, cmap, "white", &color_bg);
+
+  cursor = XCreatePixmapCursor(display, pixmap_data, pixmap_mask,
+                              &color_fg, &color_bg,
+                              cursor_info->hot_x, cursor_info->hot_y);
+
+  return cursor;
+}
+
+void X11SetMouseCursor(struct MouseCursorInfo *cursor_info)
+{
+  static struct MouseCursorInfo *last_cursor_info = NULL;
+  static Cursor cursor_default = None;
+  static Cursor cursor_current = None;
+
+  if (cursor_info != NULL && cursor_info != last_cursor_info)
+  {
+    cursor_current = create_cursor(cursor_info);
+    last_cursor_info = cursor_info;
+  }
+
+  XDefineCursor(display, window->drawable,
+               cursor_info ? cursor_current : cursor_default);
+}
+#endif /* TARGET_X11_NATIVE */
+
 #endif /* TARGET_X11 */
index c42f25cc54fe4d896277a192c5348b01351e2d2f..99dc4c9cf6cdb0f4f909a5ab64f67cd6a492bd00 100644 (file)
 #define TARGET_STRING          "X11"
 #endif
 
+#if defined(PLATFORM_UNIX)
+/* This triggers some stuff that is needed because X11 (XSetClipOrigin(),
+   to be precise) is often very slow when preparing a masked XCopyArea()
+   for big Pixmaps.
+   To prevent this, small (tile-sized) mask Pixmaps are created which will
+   then be set much faster with XSetClipOrigin() and speed things up a lot. */
+#define TARGET_X11_NATIVE_PERFORMANCE_WORKAROUND
+#endif
+
 #define FULLSCREEN_STATUS      FULLSCREEN_NOT_AVAILABLE
 
+#define CURSOR_MAX_WIDTH       32
+#define CURSOR_MAX_HEIGHT      32
+
 
 /* X11 type definitions */
 
 typedef struct X11DrawableInfo Bitmap;
 typedef struct X11DrawableInfo DrawWindow;
 typedef struct X11DrawableInfo DrawBuffer;
-/* "Pixel" is already defined in X11/Intrinsic.h */
+/* "Pixel" is already defined */
+/* "Cursor" is already defined */
 
 typedef KeySym                 Key;
+typedef unsigned int           KeyMod;
 
 typedef XEvent                 Event;
 typedef XButtonEvent           ButtonEvent;
@@ -70,6 +84,15 @@ struct X11DrawableInfo
   GC clip_gc;          /* can be 'stored_clip_gc' or one-tile-only clip GC  */
 };
 
+struct MouseCursorInfo
+{
+  int width, height;
+  int hot_x, hot_y;
+
+  char data[CURSOR_MAX_WIDTH * CURSOR_MAX_HEIGHT / 8];
+  char mask[CURSOR_MAX_WIDTH * CURSOR_MAX_HEIGHT / 8];
+};
+
 struct XY
 {
   short x, y;
@@ -78,6 +101,9 @@ struct XY
 
 /* X11 symbol definitions */
 
+#define BLACK_PIXEL            BlackPixel(display, screen)
+#define WHITE_PIXEL            WhitePixel(display, screen)
+
 #define EVENT_BUTTONPRESS      ButtonPress
 #define EVENT_BUTTONRELEASE    ButtonRelease
 #define EVENT_MOTIONNOTIFY     MotionNotify
@@ -290,11 +316,40 @@ struct XY
 #define KSYM_FKEY_LAST         KSYM_F24
 #define KSYM_NUM_FKEYS         (KSYM_FKEY_LAST - KSYM_FKEY_FIRST + 1)
 
+#define KMOD_None              None
+#define KMOD_Shift_L           0x0001
+#define KMOD_Shift_R           0x0002
+#define KMOD_Control_L         0x0040
+#define KMOD_Control_R         0x0080
+#define KMOD_Meta_L            0x0400
+#define KMOD_Meta_R            0x0800
+#define KMOD_Alt_L             0x0100
+#define KMOD_Alt_R             0x0200
+
+#define KMOD_Shift             (KMOD_Shift_L   | KMOD_Shift_R)
+#define KMOD_Control           (KMOD_Control_L | KMOD_Control_R)
+#define KMOD_Meta              (KMOD_Meta_L    | KMOD_Meta_R)
+#define KMOD_Alt               (KMOD_Alt_L     | KMOD_Alt_R)
+
 
 /* X11 function definitions */
 
 inline void X11InitVideoDisplay(void);
 inline void X11InitVideoBuffer(DrawBuffer **, DrawWindow **);
+
+void X11ZoomBitmap(Bitmap *, Bitmap *);
 Bitmap *X11LoadImage(char *);
 
+inline void X11CreateBitmapContent(Bitmap *, int, int, int);
+inline void X11FreeBitmapPointers(Bitmap *);
+inline void X11CopyArea(Bitmap *, Bitmap *, int, int, int, int, int, int, int);
+inline void X11FillRectangle(Bitmap *, int, int, int, int, Pixel);
+inline void X11DrawSimpleLine(Bitmap *, int, int, int, int, Pixel);
+inline Pixel X11GetPixel(Bitmap *, int, int);
+inline Pixel X11GetPixelFromRGB(unsigned int, unsigned int, unsigned int);
+
+#if defined(TARGET_X11_NATIVE)
+void X11SetMouseCursor(struct MouseCursorInfo *);
+#endif
+
 #endif /* X11_H */
index 2a0d656655036ea0cbab99364b0d171b9245674f..ba7ab867873f6620715e4bf35ebbdc3812b11520 100644 (file)
 #include "init.h"
 #include "game.h"
 #include "events.h"
+#include "config.h"
 
-GC             tile_clip_gc;
-Bitmap        *pix[NUM_BITMAPS];
-Pixmap         tile_clipmask[NUM_TILES];
-DrawBuffer     *fieldbuffer;
-DrawBuffer     *drawto_field;
-
-int            game_status = MAINMENU;
-boolean                level_editor_test_game = FALSE;
-boolean                network_playing = FALSE;
-
-int            key_joystick_mapping = 0;
-
-boolean                redraw[MAX_BUF_XSIZE][MAX_BUF_YSIZE];
-int            redraw_x1 = 0, redraw_y1 = 0;
-
-short          Feld[MAX_LEV_FIELDX][MAX_LEV_FIELDY];
-short          Ur[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          Store[MAX_LEV_FIELDX][MAX_LEV_FIELDY];
-short          Store2[MAX_LEV_FIELDX][MAX_LEV_FIELDY];
-short          StorePlayer[MAX_LEV_FIELDX][MAX_LEV_FIELDY];
-short          Frame[MAX_LEV_FIELDX][MAX_LEV_FIELDY];
-boolean                Stop[MAX_LEV_FIELDX][MAX_LEV_FIELDY];
-short          JustStopped[MAX_LEV_FIELDX][MAX_LEV_FIELDY];
-short          AmoebaNr[MAX_LEV_FIELDX][MAX_LEV_FIELDY];
-short          AmoebaCnt[MAX_NUM_AMOEBA], AmoebaCnt2[MAX_NUM_AMOEBA];
-short          ExplodeField[MAX_LEV_FIELDX][MAX_LEV_FIELDY];
-unsigned long  Elementeigenschaften1[MAX_ELEMENTS];
-unsigned long  Elementeigenschaften2[MAX_ELEMENTS];
-
-int            lev_fieldx,lev_fieldy, scroll_x,scroll_y;
-
-int            FX = SX, FY = SY, ScrollStepSize;
-int            ScreenMovDir = MV_NO_MOVING, ScreenMovPos = 0;
-int            ScreenGfxPos = 0;
-int            BorderElement = EL_BETON;
-int            GameFrameDelay = GAME_FRAME_DELAY;
-int            FfwdFrameDelay = FFWD_FRAME_DELAY;
-int            BX1 = 0, BY1 = 0, BX2 = SCR_FIELDX-1, BY2 = SCR_FIELDY-1;
-int            SBX_Left, SBX_Right;
-int            SBY_Upper, SBY_Lower;
-int            ZX,ZY, ExitX,ExitY;
-int            AllPlayersGone;
-
-int            TimeFrames, TimePlayed, TimeLeft;
-
-boolean                network_player_action_received = FALSE;
-
-struct LevelInfo       level;
+#if 0
+GC                     tile_clip_gc;
+Bitmap                *pix[NUM_BITMAPS];
+#endif
+Bitmap                *bitmap_db_field, *bitmap_db_door;
+#if 0
+Pixmap                 tile_clipmask[NUM_TILES];
+#endif
+DrawBuffer            *fieldbuffer;
+DrawBuffer            *drawto_field;
+
+int                    game_status = -1;
+boolean                        level_editor_test_game = FALSE;
+boolean                        network_playing = FALSE;
+
+int                    key_joystick_mapping = 0;
+
+boolean                        redraw[MAX_BUF_XSIZE][MAX_BUF_YSIZE];
+int                    redraw_x1 = 0, redraw_y1 = 0;
+
+short                  Feld[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                  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];
+boolean                        Changing[MAX_LEV_FIELDX][MAX_LEV_FIELDY];
+short                  JustStopped[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                  ExplodePhase[MAX_LEV_FIELDX][MAX_LEV_FIELDY];
+short                  ExplodeField[MAX_LEV_FIELDX][MAX_LEV_FIELDY];
+
+unsigned long          Properties[MAX_NUM_ELEMENTS][NUM_EP_BITFIELDS];
+
+int                    GfxFrame[MAX_LEV_FIELDX][MAX_LEV_FIELDY];
+int                    GfxAction[MAX_LEV_FIELDX][MAX_LEV_FIELDY];
+int                    GfxRandom[MAX_LEV_FIELDX][MAX_LEV_FIELDY];
+int                    GfxElement[MAX_LEV_FIELDX][MAX_LEV_FIELDY];
+
+int                    lev_fieldx, lev_fieldy;
+int                    scroll_x, scroll_y;
+
+int                    FX = SX, FY = SY;
+int                    ScrollStepSize;
+int                    ScreenMovDir = MV_NO_MOVING, ScreenMovPos = 0;
+int                    ScreenGfxPos = 0;
+int                    BorderElement = EL_STEELWALL;
+int                    GameFrameDelay = GAME_FRAME_DELAY;
+int                    FfwdFrameDelay = FFWD_FRAME_DELAY;
+int                    BX1 = 0, BY1 = 0;
+int                    BX2 = SCR_FIELDX - 1, BY2 = SCR_FIELDY - 1;
+int                    SBX_Left, SBX_Right;
+int                    SBY_Upper, SBY_Lower;
+int                    ZX, ZY;
+int                    ExitX, ExitY;
+int                    AllPlayersGone;
+
+int                    TimeFrames, TimePlayed, TimeLeft;
+
+boolean                        network_player_action_received = FALSE;
+
+struct LevelInfo       level, level_template;
 struct PlayerInfo      stored_player[MAX_PLAYERS], *local_player = NULL;
 struct HiScore         highscore[MAX_SCORE_ENTRIES];
 struct TapeInfo                tape;
 struct SetupInfo       setup;
 struct GameInfo                game;
 struct GlobalInfo      global;
+struct MenuInfo                menu;
+struct DoorInfo                door;
+struct GraphicInfo     *graphic_info = NULL;
+struct SoundInfo       *sound_info = NULL;
+
+
+/* ------------------------------------------------------------------------- */
+/* element definitions                                                       */
+/* ------------------------------------------------------------------------- */
+
+struct ElementInfo element_info[MAX_NUM_ELEMENTS + 1] =
+{
+  /* keyword to start parser: "ELEMENT_INFO_START" <-- do not change! */
+
+  /* ----------------------------------------------------------------------- */
+  /* "real" level file elements                                              */
+  /* ----------------------------------------------------------------------- */
+
+  {
+    "empty_space",
+    "empty_space",
+    "empty space"
+  },
+  {
+    "sand",
+    "sand",
+    "sand"
+  },
+  {
+    "wall",
+    "wall",
+    "normal wall"
+  },
+  {
+    "wall_slippery",
+    "wall",
+    "slippery wall"
+  },
+  {
+    "rock",
+    "rock",
+    "rock"
+  },
+  {
+    "key_obsolete",
+    "key",
+    "key"
+  },
+  {
+    "emerald",
+    "emerald",
+    "emerald"
+  },
+  {
+    "exit_closed",
+    "exit",
+    "closed exit"
+  },
+  {
+    "player_obsolete",
+    "player",
+    "player"
+  },
+  {
+    "bug",
+    "bug",
+    "bug"
+  },
+  {
+    "spaceship",
+    "spaceship",
+    "spaceship"
+  },
+  {
+    "yamyam",
+    "yamyam",
+    "yam yam"
+  },
+  {
+    "robot",
+    "robot",
+    "robot"
+  },
+  {
+    "steelwall",
+    "wall",
+    "steel wall"
+  },
+  {
+    "diamond",
+    "diamond",
+    "diamond"
+  },
+  {
+    "amoeba_dead",
+    "amoeba",
+    "dead amoeba"
+  },
+  {
+    "quicksand_empty",
+    "quicksand",
+    "empty quicksand"
+  },
+  {
+    "quicksand_full",
+    "quicksand",
+    "quicksand with rock"
+  },
+  {
+    "amoeba_drop",
+    "amoeba",
+    "amoeba drop"
+  },
+  {
+    "bomb",
+    "bomb",
+    "bomb"
+  },
+  {
+    "magic_wall",
+    "magic_wall",
+    "magic wall"
+  },
+  {
+    "speed_pill",
+    "speed_pill",
+    "speed pill"
+  },
+  {
+    "acid",
+    "acid",
+    "acid"
+  },
+  {
+    "amoeba_wet",
+    "amoeba",
+    "dropping amoeba"
+  },
+  {
+    "amoeba_dry",
+    "amoeba",
+    "normal amoeba"
+  },
+  {
+    "nut",
+    "nut",
+    "nut with emerald"
+  },
+  {
+    "game_of_life",
+    "game_of_life",
+    "Conway's wall of life"
+  },
+  {
+    "biomaze",
+    "biomaze",
+    "biomaze"
+  },
+  {
+    "dynamite_active",
+    "dynamite",
+    "burning dynamite"
+  },
+  {
+    "stoneblock",
+    "wall",
+    "wall"
+  },
+  {
+    "robot_wheel",
+    "robot_wheel",
+    "magic wheel"
+  },
+  {
+    "robot_wheel_active",
+    "robot_wheel",
+    "magic wheel (running)"
+  },
+  {
+    "key_1",
+    "key",
+    "red key"
+  },
+  {
+    "key_2",
+    "key",
+    "yellow key"
+  },
+  {
+    "key_3",
+    "key",
+    "green key"
+  },
+  {
+    "key_4",
+    "key",
+    "blue key"
+  },
+  {
+    "gate_1",
+    "gate",
+    "red door"
+  },
+  {
+    "gate_2",
+    "gate",
+    "yellow door"
+  },
+  {
+    "gate_3",
+    "gate",
+    "green door"
+  },
+  {
+    "gate_4",
+    "gate",
+    "blue door"
+  },
+  {
+    "gate_1_gray",
+    "gate",
+    "gray door (opened by red key)"
+  },
+  {
+    "gate_2_gray",
+    "gate",
+    "gray door (opened by yellow key)"},
+  {
+    "gate_3_gray",
+    "gate",
+    "gray door (opened by green key)"},
+  {
+    "gate_4_gray",
+    "gate",
+    "gray door (opened by blue key)"},
+  {
+    "dynamite",
+    "dynamite",
+    "dynamite"
+  },
+  {
+    "pacman",
+    "pacman",
+    "pac man"
+  },
+  {
+    "invisible_wall",
+    "wall",
+    "invisible normal wall"
+  },
+  {
+    "lamp",
+    "lamp",
+    "lamp (off)"
+  },
+  {
+    "lamp_active",
+    "lamp",
+    "lamp (on)"
+  },
+  {
+    "wall_emerald",
+    "wall",
+    "wall with emerald"
+  },
+  {
+    "wall_diamond",
+    "wall",
+    "wall with diamond"
+  },
+  {
+    "amoeba_full",
+    "amoeba",
+    "amoeba with content"
+  },
+  {
+    "bd_amoeba",
+    "bd_amoeba",
+    "amoeba (BD style)"
+  },
+  {
+    "time_orb_full",
+    "time_orb_full",
+    "time orb (full)"
+  },
+  {
+    "time_orb_empty",
+    "time_orb_empty",
+    "time orb (empty)"
+  },
+  {
+    "expandable_wall",
+    "wall",
+    "growing wall"
+  },
+  {
+    "bd_diamond",
+    "bd_diamond",
+    "diamond (BD style)"
+  },
+  {
+    "emerald_yellow",
+    "emerald",
+    "yellow emerald"
+  },
+  {
+    "wall_bd_diamond",
+    "wall",
+    "wall with BD style diamond"
+  },
+  {
+    "wall_emerald_yellow",
+    "wall",
+    "wall with yellow emerald"
+  },
+  {
+    "dark_yamyam",
+    "dark_yamyam",
+    "dark yam yam"
+  },
+  {
+    "bd_magic_wall",
+    "bd_magic_wall",
+    "magic wall (BD style)"
+  },
+  {
+    "invisible_steelwall",
+    "wall",
+    "invisible steel wall"
+  },
+  {
+    "unused_63",
+    "unused",
+    "(not used)"
+  },
+  {
+    "dynabomb_increase_number",
+    "dynabomb",
+    "increases number of bombs"
+  },
+  {
+    "dynabomb_increase_size",
+    "dynabomb",
+    "increases explosion size"
+  },
+  {
+    "dynabomb_increase_power",
+    "dynabomb",
+    "increases power of explosion"
+  },
+  {
+    "sokoban_object",
+    "sokoban",
+    "sokoban object"
+  },
+  {
+    "sokoban_field_empty",
+    "sokoban",
+    "sokoban empty field"
+  },
+  {
+    "sokoban_field_full",
+    "sokoban",
+    "sokoban field with object"
+  },
+  {
+    "bd_butterfly_right",
+    "bd_butterfly",
+    "butterfly (starts moving right)"},
+  {
+    "bd_butterfly_up",
+    "bd_butterfly",
+    "butterfly (starts moving up)"
+  },
+  {
+    "bd_butterfly_left",
+    "bd_butterfly",
+    "butterfly (starts moving left)"},
+  {
+    "bd_butterfly_down",
+    "bd_butterfly",
+    "butterfly (starts moving down)"},
+  {
+    "bd_firefly_right",
+    "bd_firefly",
+    "firefly (starts moving right)"
+  },
+  {
+    "bd_firefly_up",
+    "bd_firefly",
+    "firefly (starts moving up)"
+  },
+  {
+    "bd_firefly_left",
+    "bd_firefly",
+    "firefly (starts moving left)"
+  },
+  {
+    "bd_firefly_down",
+    "bd_firefly",
+    "firefly (starts moving down)"
+  },
+  {
+    "bd_butterfly",
+    "bd_butterfly",
+    "butterfly"
+  },
+  {
+    "bd_firefly",
+    "bd_firefly",
+    "firefly"
+  },
+  {
+    "player_1",
+    "player",
+    "yellow player"
+  },
+  {
+    "player_2",
+    "player",
+    "red player"
+  },
+  {
+    "player_3",
+    "player",
+    "green player"
+  },
+  {
+    "player_4",
+    "player",
+    "blue player"
+  },
+  {
+    "bug_right",
+    "bug",
+    "bug (starts moving right)"
+  },
+  {
+    "bug_up",
+    "bug",
+    "bug (starts moving up)"
+  },
+  {
+    "bug_left",
+    "bug",
+    "bug (starts moving left)"
+  },
+  {
+    "bug_down",
+    "bug",
+    "bug (starts moving down)"
+  },
+  {
+    "spaceship_right",
+    "spaceship",
+    "spaceship (starts moving right)"},
+  {
+    "spaceship_up",
+    "spaceship",
+    "spaceship (starts moving up)"
+  },
+  {
+    "spaceship_left",
+    "spaceship",
+    "spaceship (starts moving left)"},
+  {
+    "spaceship_down",
+    "spaceship",
+    "spaceship (starts moving down)"},
+  {
+    "pacman_right",
+    "pacman",
+    "pac man (starts moving right)"
+  },
+  {
+    "pacman_up",
+    "pacman",
+    "pac man (starts moving up)"
+  },
+  {
+    "pacman_left",
+    "pacman",
+    "pac man (starts moving left)"
+  },
+  {
+    "pacman_down",
+    "pacman",
+    "pac man (starts moving down)"
+  },
+  {
+    "emerald_red",
+    "emerald",
+    "red emerald"
+  },
+  {
+    "emerald_purple",
+    "emerald",
+    "purple emerald"
+  },
+  {
+    "wall_emerald_red",
+    "wall",
+    "wall with red emerald"
+  },
+  {
+    "wall_emerald_purple",
+    "wall",
+    "wall with purple emerald"
+  },
+  {
+    "acid_pool_topleft",
+    "wall",
+    "acid pool (top left)"
+  },
+  {
+    "acid_pool_topright",
+    "wall",
+    "acid pool (top right)"
+  },
+  {
+    "acid_pool_bottomleft",
+    "wall",
+    "acid pool (bottom left)"
+  },
+  {
+    "acid_pool_bottom",
+    "wall",
+    "acid pool (bottom)"
+  },
+  {
+    "acid_pool_bottomright",
+    "wall",
+    "acid pool (bottom right)"
+  },
+  {
+    "bd_wall",
+    "wall",
+    "normal wall (BD style)"
+  },
+  {
+    "bd_rock",
+    "bd_rock",
+    "rock (BD style)"
+  },
+  {
+    "exit_open",
+    "exit",
+    "open exit"
+  },
+  {
+    "black_orb",
+    "black_orb",
+    "bomb"
+  },
+  {
+    "amoeba_to_diamond",
+    "amoeba",
+    "amoeba"
+  },
+  {
+    "mole",
+    "mole",
+    "mole"
+  },
+  {
+    "penguin",
+    "penguin",
+    "penguin"
+  },
+  {
+    "satellite",
+    "satellite",
+    "satellite"
+  },
+  {
+    "arrow_left",
+    "arrow",
+    "arrow left"
+  },
+  {
+    "arrow_right",
+    "arrow",
+    "arrow right"
+  },
+  {
+    "arrow_up",
+    "arrow",
+    "arrow up"
+  },
+  {
+    "arrow_down",
+    "arrow",
+    "arrow down"
+  },
+  {
+    "pig",
+    "pig",
+    "pig"
+  },
+  {
+    "dragon",
+    "dragon",
+    "fire breathing dragon"
+  },
+  {
+    "em_key_1_file",
+    "key",
+    "red key (EM style)"
+  },
+  {
+    "char_space",
+    "char",
+    "letter ' '"
+  },
+  {
+    "char_exclam",
+    "char",
+    "letter '!'"
+  },
+  {
+    "char_quotedbl",
+    "char",
+    "letter '\"'"
+  },
+  {
+    "char_numbersign",
+    "char",
+    "letter '#'"
+  },
+  {
+    "char_dollar",
+    "char",
+    "letter '$'"
+  },
+  {
+    "char_procent",
+    "char",
+    "letter '%'"
+  },
+  {
+    "char_ampersand",
+    "char",
+    "letter '&'"
+  },
+  {
+    "char_apostrophe",
+    "char",
+    "letter '''"
+  },
+  {
+    "char_parenleft",
+    "char",
+    "letter '('"
+  },
+  {
+    "char_parenright",
+    "char",
+    "letter ')'"
+  },
+  {
+    "char_asterisk",
+    "char",
+    "letter '*'"
+  },
+  {
+    "char_plus",
+    "char",
+    "letter '+'"
+  },
+  {
+    "char_comma",
+    "char",
+    "letter ','"
+  },
+  {
+    "char_minus",
+    "char",
+    "letter '-'"
+  },
+  {
+    "char_period",
+    "char",
+    "letter '.'"
+  },
+  {
+    "char_slash",
+    "char",
+    "letter '/'"
+  },
+  {
+    "char_0",
+    "char",
+    "letter '0'"
+  },
+  {
+    "char_1",
+    "char",
+    "letter '1'"
+  },
+  {
+    "char_2",
+    "char",
+    "letter '2'"
+  },
+  {
+    "char_3",
+    "char",
+    "letter '3'"
+  },
+  {
+    "char_4",
+    "char",
+    "letter '4'"
+  },
+  {
+    "char_5",
+    "char",
+    "letter '5'"
+  },
+  {
+    "char_6",
+    "char",
+    "letter '6'"
+  },
+  {
+    "char_7",
+    "char",
+    "letter '7'"
+  },
+  {
+    "char_8",
+    "char",
+    "letter '8'"
+  },
+  {
+    "char_9",
+    "char",
+    "letter '9'"
+  },
+  {
+    "char_colon",
+    "char",
+    "letter ':'"
+  },
+  {
+    "char_semicolon",
+    "char",
+    "letter ';'"
+  },
+  {
+    "char_less",
+    "char",
+    "letter '<'"
+  },
+  {
+    "char_equal",
+    "char",
+    "letter '='"
+  },
+  {
+    "char_greater",
+    "char",
+    "letter '>'"
+  },
+  {
+    "char_question",
+    "char",
+    "letter '?'"
+  },
+  {
+    "char_at",
+    "char",
+    "letter '@'"
+  },
+  {
+    "char_a",
+    "char",
+    "letter 'A'"
+  },
+  {
+    "char_b",
+    "char",
+    "letter 'B'"
+  },
+  {
+    "char_c",
+    "char",
+    "letter 'C'"
+  },
+  {
+    "char_d",
+    "char",
+    "letter 'D'"
+  },
+  {
+    "char_e",
+    "char",
+    "letter 'E'"
+  },
+  {
+    "char_f",
+    "char",
+    "letter 'F'"
+  },
+  {
+    "char_g",
+    "char",
+    "letter 'G'"
+  },
+  {
+    "char_h",
+    "char",
+    "letter 'H'"
+  },
+  {
+    "char_i",
+    "char",
+    "letter 'I'"
+  },
+  {
+    "char_j",
+    "char",
+    "letter 'J'"
+  },
+  {
+    "char_k",
+    "char",
+    "letter 'K'"
+  },
+  {
+    "char_l",
+    "char",
+    "letter 'L'"
+  },
+  {
+    "char_m",
+    "char",
+    "letter 'M'"
+  },
+  {
+    "char_n",
+    "char",
+    "letter 'N'"
+  },
+  {
+    "char_o",
+    "char",
+    "letter 'O'"
+  },
+  {
+    "char_p",
+    "char",
+    "letter 'P'"
+  },
+  {
+    "char_q",
+    "char",
+    "letter 'Q'"
+  },
+  {
+    "char_r",
+    "char",
+    "letter 'R'"
+  },
+  {
+    "char_s",
+    "char",
+    "letter 'S'"
+  },
+  {
+    "char_t",
+    "char",
+    "letter 'T'"
+  },
+  {
+    "char_u",
+    "char",
+    "letter 'U'"
+  },
+  {
+    "char_v",
+    "char",
+    "letter 'V'"
+  },
+  {
+    "char_w",
+    "char",
+    "letter 'W'"
+  },
+  {
+    "char_x",
+    "char",
+    "letter 'X'"
+  },
+  {
+    "char_y",
+    "char",
+    "letter 'Y'"
+  },
+  {
+    "char_z",
+    "char",
+    "letter 'Z'"
+  },
+  {
+    "char_bracketleft",
+    "char",
+    "letter '['"
+  },
+  {
+    "char_backslash",
+    "char",
+    "letter '\\'"
+  },
+  {
+    "char_bracketright",
+    "char",
+    "letter ']'"
+  },
+  {
+    "char_asciicircum",
+    "char",
+    "letter '^'"
+  },
+  {
+    "char_underscore",
+    "char",
+    "letter '_'"
+  },
+  {
+    "char_copyright",
+    "char",
+    "letter '©'"
+  },
+  {
+    "char_aumlaut",
+    "char",
+    "letter 'Ä'"
+  },
+  {
+    "char_oumlaut",
+    "char",
+    "letter 'Ö'"
+  },
+  {
+    "char_uumlaut",
+    "char",
+    "letter 'Ãœ'"
+  },
+  {
+    "char_degree",
+    "char",
+    "letter '°'"
+  },
+  {
+    "char_trademark",
+    "char",
+    "letter '®'"
+  },
+  {
+    "char_cursor",
+    "char",
+    "letter ' '"
+  },
+  {
+    "char_unused",
+    "char",
+    "letter ''"
+  },
+  {
+    "char_unused",
+    "char",
+    "letter ''"
+  },
+  {
+    "char_unused",
+    "char",
+    "letter ''"
+  },
+  {
+    "char_unused",
+    "char",
+    "letter ''"
+  },
+  {
+    "char_unused",
+    "char",
+    "letter ''"
+  },
+  {
+    "char_unused",
+    "char",
+    "letter ''"
+  },
+  {
+    "char_unused",
+    "char",
+    "letter ''"
+  },
+  {
+    "char_unused",
+    "char",
+    "letter ''"
+  },
+  {
+    "char_unused",
+    "char",
+    "letter ''"
+  },
+  {
+    "expandable_wall_horizontal",
+    "wall",
+    "growing wall (horizontal)"
+  },
+  {
+    "expandable_wall_vertical",
+    "wall",
+    "growing wall (vertical)"
+  },
+  {
+    "expandable_wall_any",
+    "wall",
+    "growing wall (any direction)"
+  },
+  {
+    "em_gate_1",
+    "gate",
+    "red door (EM style)"
+  },
+  {
+    "em_gate_2",
+    "gate",
+    "yellow door (EM style)"
+  },
+  {
+    "em_gate_3",
+    "gate",
+    "green door (EM style)"
+  },
+  {
+    "em_gate_4",
+    "gate",
+    "blue door (EM style)"
+  },
+  {
+    "em_key_2_file",
+    "key",
+    "yellow key (EM style)"
+  },
+  {
+    "em_key_3_file",
+    "key",
+    "green key (EM style)"
+  },
+  {
+    "em_key_4_file",
+    "key",
+    "blue key (EM style)"
+  },
+  {
+    "sp_empty_space",
+    "empty_space",
+    "empty space"
+  },
+  {
+    "sp_zonk",
+    "sp_zonk",
+    "zonk"
+  },
+  {
+    "sp_base",
+    "sp_base",
+    "base"
+  },
+  {
+    "sp_murphy",
+    "player",
+    "murphy"
+  },
+  {
+    "sp_infotron",
+    "sp_infotron",
+    "infotron"
+  },
+  {
+    "sp_chip_single",
+    "wall",
+    "chip (single)"
+  },
+  {
+    "sp_hardware_gray",
+    "wall",
+    "hardware"
+  },
+  {
+    "sp_exit_closed",
+    "sp_exit",
+    "exit"
+  },
+  {
+    "sp_disk_orange",
+    "sp_disk_orange",
+    "orange disk"
+  },
+  {
+    "sp_port_right",
+    "sp_port",
+    "port (leading right)"
+  },
+  {
+    "sp_port_down",
+    "sp_port",
+    "port (leading down)"
+  },
+  {
+    "sp_port_left",
+    "sp_port",
+    "port (leading left)"
+  },
+  {
+    "sp_port_up",
+    "sp_port",
+    "port (leading up)"
+  },
+  {
+    "sp_gravity_port_right",
+    "sp_port",
+    "gravity port (leading right)"
+  },
+  {
+    "sp_gravity_port_down",
+    "sp_port",
+    "gravity port (leading down)"
+  },
+  {
+    "sp_gravity_port_left",
+    "sp_port",
+    "gravity port (leading left)"
+  },
+  {
+    "sp_gravity_port_up",
+    "sp_port",
+    "gravity port (leading up)"
+  },
+  {
+    "sp_sniksnak",
+    "sp_sniksnak",
+    "snik snak"
+  },
+  {
+    "sp_disk_yellow",
+    "sp_disk_yellow",
+    "yellow disk"
+  },
+  {
+    "sp_terminal",
+    "sp_terminal",
+    "terminal"
+  },
+  {
+    "sp_disk_red",
+    "dynamite",
+    "red disk"
+  },
+  {
+    "sp_port_vertical",
+    "sp_port",
+    "port (vertical)"
+  },
+  {
+    "sp_port_horizontal",
+    "sp_port",
+    "port (horizontal)"
+  },
+  {
+    "sp_port_any",
+    "sp_port",
+    "port (any direction)"
+  },
+  {
+    "sp_electron",
+    "sp_electron",
+    "electron"
+  },
+  {
+    "sp_buggy_base",
+    "sp_buggy_base",
+    "buggy base"
+  },
+  {
+    "sp_chip_left",
+    "wall",
+    "chip (left half)"
+  },
+  {
+    "sp_chip_right",
+    "wall",
+    "chip (right half)"
+  },
+  {
+    "sp_hardware_base_1",
+    "wall",
+    "hardware"
+  },
+  {
+    "sp_hardware_green",
+    "wall",
+    "hardware"
+  },
+  {
+    "sp_hardware_blue",
+    "wall",
+    "hardware"
+  },
+  {
+    "sp_hardware_red",
+    "wall",
+    "hardware"
+  },
+  {
+    "sp_hardware_yellow",
+    "wall",
+    "hardware"
+  },
+  {
+    "sp_hardware_base_2",
+    "wall",
+    "hardware"
+  },
+  {
+    "sp_hardware_base_3",
+    "wall",
+    "hardware"
+  },
+  {
+    "sp_hardware_base_4",
+    "wall",
+    "hardware"
+  },
+  {
+    "sp_hardware_base_5",
+    "wall",
+    "hardware"
+  },
+  {
+    "sp_hardware_base_6",
+    "wall",
+    "hardware"
+  },
+  {
+    "sp_chip_top",
+    "wall",
+    "chip (upper half)"
+  },
+  {
+    "sp_chip_bottom",
+    "wall",
+    "chip (lower half)"
+  },
+  {
+    "em_gate_1_gray",
+    "gate",
+    "gray door (EM style, red key)"
+  },
+  {
+    "em_gate_2_gray",
+    "gate",
+    "gray door (EM style, yellow key)"
+  },
+  {
+    "em_gate_3_gray",
+    "gate",
+    "gray door (EM style, green key)"
+  },
+  {
+    "em_gate_4_gray",
+    "gate",
+    "gray door (EM style, blue key)"
+  },
+  {
+    "unused_254",
+    "unused",
+    "(not used)"
+  },
+  {
+    "unused_255",
+    "unused",
+    "(not used)"
+  },
+  {
+    "pearl",
+    "pearl",
+    "pearl"
+  },
+  {
+    "crystal",
+    "crystal",
+    "crystal"
+  },
+  {
+    "wall_pearl",
+    "wall",
+    "wall with pearl"
+  },
+  {
+    "wall_crystal",
+    "wall",
+    "wall with crystal"
+  },
+  {
+    "door_white",
+    "gate",
+    "white door"
+  },
+  {
+    "door_white_gray",
+    "gate",
+    "gray door (opened by white key)"
+  },
+  {
+    "key_white",
+    "key",
+    "white key"
+  },
+  {
+    "shield_normal",
+    "shield_normal",
+    "shield (normal)"
+  },
+  {
+    "extra_time",
+    "extra_time",
+    "extra time"
+  },
+  {
+    "switchgate_open",
+    "switchgate",
+    "switch gate (open)"
+  },
+  {
+    "switchgate_closed",
+    "switchgate",
+    "switch gate (closed)"
+  },
+  {
+    "switchgate_switch_up",
+    "switchgate_switch",
+    "switch for switch gate"
+  },
+  {
+    "switchgate_switch_down",
+    "switchgate_switch",
+    "switch for switch gate"
+  },
+  {
+    "unused_269",
+    "unused",
+    "-"
+  },
+  {
+    "unused_270",
+    "unused",
+    "-"
+  },
+  {
+    "conveyor_belt_1_left",
+    "conveyor_belt",
+    "red conveyor belt (left)"
+  },
+  {
+    "conveyor_belt_1_middle",
+    "conveyor_belt",
+    "red conveyor belt (middle)"
+  },
+  {
+    "conveyor_belt_1_right",
+    "conveyor_belt",
+    "red conveyor belt (right)"
+  },
+  {
+    "conveyor_belt_1_switch_left",
+    "conveyor_belt_switch",
+    "switch for red conveyor belt (left)"
+  },
+  {
+    "conveyor_belt_1_switch_middle",
+    "conveyor_belt_switch",
+    "switch for red conveyor belt (middle)"
+  },
+  {
+    "conveyor_belt_1_switch_right",
+    "conveyor_belt_switch",
+    "switch for red conveyor belt (right)"
+  },
+  {
+    "conveyor_belt_2_left",
+    "conveyor_belt",
+    "yellow conveyor belt (left)"
+  },
+  {
+    "conveyor_belt_2_middle",
+    "conveyor_belt",
+    "yellow conveyor belt (middle)"
+  },
+  {
+    "conveyor_belt_2_right",
+    "conveyor_belt",
+    "yellow conveyor belt (right)"
+  },
+  {
+    "conveyor_belt_2_switch_left",
+    "conveyor_belt_switch",
+    "switch for yellow conveyor belt (left)"
+  },
+  {
+    "conveyor_belt_2_switch_middle",
+    "conveyor_belt_switch",
+    "switch for yellow conveyor belt (middle)"
+  },
+  {
+    "conveyor_belt_2_switch_right",
+    "conveyor_belt_switch",
+    "switch for yellow conveyor belt (right)"
+  },
+  {
+    "conveyor_belt_3_left",
+    "conveyor_belt",
+    "green conveyor belt (left)"
+  },
+  {
+    "conveyor_belt_3_middle",
+    "conveyor_belt",
+    "green conveyor belt (middle)"
+  },
+  {
+    "conveyor_belt_3_right",
+    "conveyor_belt",
+    "green conveyor belt (right)"
+  },
+  {
+    "conveyor_belt_3_switch_left",
+    "conveyor_belt_switch",
+    "switch for green conveyor belt (left)"
+  },
+  {
+    "conveyor_belt_3_switch_middle",
+    "conveyor_belt_switch",
+    "switch for green conveyor belt (middle)"
+  },
+  {
+    "conveyor_belt_3_switch_right",
+    "conveyor_belt_switch",
+    "switch for green conveyor belt (right)"
+  },
+  {
+    "conveyor_belt_4_left",
+    "conveyor_belt",
+    "blue conveyor belt (left)"
+  },
+  {
+    "conveyor_belt_4_middle",
+    "conveyor_belt",
+    "blue conveyor belt (middle)"
+  },
+  {
+    "conveyor_belt_4_right",
+    "conveyor_belt",
+    "blue conveyor belt (right)"
+  },
+  {
+    "conveyor_belt_4_switch_left",
+    "conveyor_belt_switch",
+    "switch for blue conveyor belt (left)"
+  },
+  {
+    "conveyor_belt_4_switch_middle",
+    "conveyor_belt_switch",
+    "switch for blue conveyor belt (middle)"
+  },
+  {
+    "conveyor_belt_4_switch_right",
+    "conveyor_belt_switch",
+    "switch for blue conveyor belt (right)"
+  },
+  {
+    "landmine",
+    "sand",
+    "land mine"
+  },
+  {
+    "envelope",
+    "envelope",
+    "mail envelope"
+  },
+  {
+    "light_switch",
+    "light_switch",
+    "light switch (off)"
+  },
+  {
+    "light_switch_active",
+    "light_switch",
+    "light switch (on)"
+  },
+  {
+    "sign_exclamation",
+    "wall",
+    "sign (exclamation)"
+  },
+  {
+    "sign_radioactivity",
+    "wall",
+    "sign (radio activity)"
+  },
+  {
+    "sign_stop",
+    "wall",
+    "sign (stop)"
+  },
+  {
+    "sign_wheelchair",
+    "wall",
+    "sign (wheel chair)"
+  },
+  {
+    "sign_parking",
+    "wall",
+    "sign (parking)"
+  },
+  {
+    "sign_oneway",
+    "wall",
+    "sign (one way)"
+  },
+  {
+    "sign_heart",
+    "wall",
+    "sign (heart)"
+  },
+  {
+    "sign_triangle",
+    "wall",
+    "sign (triangle)"
+  },
+  {
+    "sign_round",
+    "wall",
+    "sign (round)"
+  },
+  {
+    "sign_exit",
+    "wall",
+    "sign (exit)"
+  },
+  {
+    "sign_yinyang",
+    "wall",
+    "sign (yin yang)"
+  },
+  {
+    "sign_other",
+    "wall",
+    "sign (other)"
+  },
+  {
+    "mole_left",
+    "mole",
+    "mole (starts moving left)"
+  },
+  {
+    "mole_right",
+    "mole",
+    "mole (starts moving right)"
+  },
+  {
+    "mole_up",
+    "mole",
+    "mole (starts moving up)"
+  },
+  {
+    "mole_down",
+    "mole",
+    "mole (starts moving down)"
+  },
+  {
+    "steelwall_slippery",
+    "wall",
+    "slippery steel wall"
+  },
+  {
+    "invisible_sand",
+    "sand",
+    "invisible sand"
+  },
+  {
+    "dx_unknown_15",
+    "unknown",
+    "dx unknown element 15"
+  },
+  {
+    "dx_unknown_42",
+    "unknown",
+    "dx unknown element 42"
+  },
+  {
+    "unused_319",
+    "unused",
+    "(not used)"
+  },
+  {
+    "unused_320",
+    "unused",
+    "(not used)"
+  },
+  {
+    "shield_deadly",
+    "shield_deadly",
+    "shield (deadly, kills enemies)"
+  },
+  {
+    "timegate_open",
+    "timegate",
+    "time gate (open)"
+  },
+  {
+    "timegate_closed",
+    "timegate",
+    "time gate (closed)"
+  },
+  {
+    "timegate_switch_active",
+    "timegate_switch",
+    "switch for time gate"
+  },
+  {
+    "timegate_switch",
+    "timegate_switch",
+    "switch for time gate"
+  },
+  {
+    "balloon",
+    "balloon",
+    "balloon"
+  },
+  {
+    "balloon_switch_left",
+    "balloon_switch",
+    "send balloon to the left"
+  },
+  {
+    "balloon_switch_right",
+    "balloon_switch",
+    "send balloon to the right"
+  },
+  {
+    "balloon_switch_up",
+    "balloon_switch",
+    "send balloon up"
+  },
+  {
+    "balloon_switch_down",
+    "balloon_switch",
+    "send balloon down"
+  },
+  {
+    "balloon_switch_any",
+    "balloon_switch",
+    "send balloon in any direction"
+  },
+  {
+    "emc_steelwall_1",
+    "wall",
+    "steel wall"
+  },
+  {
+    "emc_steelwall_2",
+    "wall",
+    "steel wall"
+  },
+  {
+    "emc_steelwall_3",
+    "wall",
+    "steel wall"
+  },
+  {
+    "emc_steelwall_4",
+    "wall",
+    "steel wall"
+  },
+  {
+    "emc_wall_1",
+    "wall",
+    "normal wall"
+  },
+  {
+    "emc_wall_2",
+    "wall",
+    "normal wall"
+  },
+  {
+    "emc_wall_3",
+    "wall",
+    "normal wall"
+  },
+  {
+    "emc_wall_4",
+    "wall",
+    "normal wall"
+  },
+  {
+    "emc_wall_5",
+    "wall",
+    "normal wall"
+  },
+  {
+    "emc_wall_6",
+    "wall",
+    "normal wall"
+  },
+  {
+    "emc_wall_7",
+    "wall",
+    "normal wall"
+  },
+  {
+    "emc_wall_8",
+    "wall",
+    "normal wall"
+  },
+  {
+    "tube_any",
+    "tube",
+    "tube (any direction)"
+  },
+  {
+    "tube_vertical",
+    "tube",
+    "tube (vertical)"
+  },
+  {
+    "tube_horizontal",
+    "tube",
+    "tube (horizontal)"
+  },
+  {
+    "tube_vertical_left",
+    "tube",
+    "tube (vertical & left)"
+  },
+  {
+    "tube_vertical_right",
+    "tube",
+    "tube (vertical & right)"
+  },
+  {
+    "tube_horizontal_up",
+    "tube",
+    "tube (horizontal & up)"
+  },
+  {
+    "tube_horizontal_down",
+    "tube",
+    "tube (horizontal & down)"
+  },
+  {
+    "tube_left_up",
+    "tube",
+    "tube (left & up)"
+  },
+  {
+    "tube_left_down",
+    "tube",
+    "tube (left & down)"
+  },
+  {
+    "tube_right_up",
+    "tube",
+    "tube (right & up)"
+  },
+  {
+    "tube_right_down",
+    "tube",
+    "tube (right & down)"
+  },
+  {
+    "spring",
+    "spring",
+    "spring"
+  },
+  {
+    "trap",
+    "trap",
+    "trap"
+  },
+  {
+    "dx_supabomb",
+    "bomb",
+    "stable bomb (DX style)"
+  },
+  {
+    "unused_358",
+    "unused",
+    "-"
+  },
+  {
+    "unused_359",
+    "unused",
+    "-"
+  },
+  {
+    "custom_1",
+    "custom",
+    "custom element 1"
+  },
+  {
+    "custom_2",
+    "custom",
+    "custom element 2"
+  },
+  {
+    "custom_3",
+    "custom",
+    "custom element 3"
+  },
+  {
+    "custom_4",
+    "custom",
+    "custom element 4"
+  },
+  {
+    "custom_5",
+    "custom",
+    "custom element 5"
+  },
+  {
+    "custom_6",
+    "custom",
+    "custom element 6"
+  },
+  {
+    "custom_7",
+    "custom",
+    "custom element 7"
+  },
+  {
+    "custom_8",
+    "custom",
+    "custom element 8"
+  },
+  {
+    "custom_9",
+    "custom",
+    "custom element 9"
+  },
+  {
+    "custom_10",
+    "custom",
+    "custom element 10"
+  },
+  {
+    "custom_11",
+    "custom",
+    "custom element 11"
+  },
+  {
+    "custom_12",
+    "custom",
+    "custom element 12"
+  },
+  {
+    "custom_13",
+    "custom",
+    "custom element 13"
+  },
+  {
+    "custom_14",
+    "custom",
+    "custom element 14"
+  },
+  {
+    "custom_15",
+    "custom",
+    "custom element 15"
+  },
+  {
+    "custom_16",
+    "custom",
+    "custom element 16"
+  },
+  {
+    "custom_17",
+    "custom",
+    "custom element 17"
+  },
+  {
+    "custom_18",
+    "custom",
+    "custom element 18"
+  },
+  {
+    "custom_19",
+    "custom",
+    "custom element 19"
+  },
+  {
+    "custom_20",
+    "custom",
+    "custom element 20"
+  },
+  {
+    "custom_21",
+    "custom",
+    "custom element 21"
+  },
+  {
+    "custom_22",
+    "custom",
+    "custom element 22"
+  },
+  {
+    "custom_23",
+    "custom",
+    "custom element 23"
+  },
+  {
+    "custom_24",
+    "custom",
+    "custom element 24"
+  },
+  {
+    "custom_25",
+    "custom",
+    "custom element 25"
+  },
+  {
+    "custom_26",
+    "custom",
+    "custom element 26"
+  },
+  {
+    "custom_27",
+    "custom",
+    "custom element 27"
+  },
+  {
+    "custom_28",
+    "custom",
+    "custom element 28"
+  },
+  {
+    "custom_29",
+    "custom",
+    "custom element 29"
+  },
+  {
+    "custom_30",
+    "custom",
+    "custom element 30"
+  },
+  {
+    "custom_31",
+    "custom",
+    "custom element 31"
+  },
+  {
+    "custom_32",
+    "custom",
+    "custom element 32"
+  },
+  {
+    "custom_33",
+    "custom",
+    "custom element 33"
+  },
+  {
+    "custom_34",
+    "custom",
+    "custom element 34"
+  },
+  {
+    "custom_35",
+    "custom",
+    "custom element 35"
+  },
+  {
+    "custom_36",
+    "custom",
+    "custom element 36"
+  },
+  {
+    "custom_37",
+    "custom",
+    "custom element 37"
+  },
+  {
+    "custom_38",
+    "custom",
+    "custom element 38"
+  },
+  {
+    "custom_39",
+    "custom",
+    "custom element 39"
+  },
+  {
+    "custom_40",
+    "custom",
+    "custom element 40"
+  },
+  {
+    "custom_41",
+    "custom",
+    "custom element 41"
+  },
+  {
+    "custom_42",
+    "custom",
+    "custom element 42"
+  },
+  {
+    "custom_43",
+    "custom",
+    "custom element 43"
+  },
+  {
+    "custom_44",
+    "custom",
+    "custom element 44"
+  },
+  {
+    "custom_45",
+    "custom",
+    "custom element 45"
+  },
+  {
+    "custom_46",
+    "custom",
+    "custom element 46"
+  },
+  {
+    "custom_47",
+    "custom",
+    "custom element 47"
+  },
+  {
+    "custom_48",
+    "custom",
+    "custom element 48"
+  },
+  {
+    "custom_49",
+    "custom",
+    "custom element 49"
+  },
+  {
+    "custom_50",
+    "custom",
+    "custom element 50"
+  },
+  {
+    "custom_51",
+    "custom",
+    "custom element 51"
+  },
+  {
+    "custom_52",
+    "custom",
+    "custom element 52"
+  },
+  {
+    "custom_53",
+    "custom",
+    "custom element 53"
+  },
+  {
+    "custom_54",
+    "custom",
+    "custom element 54"
+  },
+  {
+    "custom_55",
+    "custom",
+    "custom element 55"
+  },
+  {
+    "custom_56",
+    "custom",
+    "custom element 56"
+  },
+  {
+    "custom_57",
+    "custom",
+    "custom element 57"
+  },
+  {
+    "custom_58",
+    "custom",
+    "custom element 58"
+  },
+  {
+    "custom_59",
+    "custom",
+    "custom element 59"
+  },
+  {
+    "custom_60",
+    "custom",
+    "custom element 60"
+  },
+  {
+    "custom_61",
+    "custom",
+    "custom element 61"
+  },
+  {
+    "custom_62",
+    "custom",
+    "custom element 62"
+  },
+  {
+    "custom_63",
+    "custom",
+    "custom element 63"
+  },
+  {
+    "custom_64",
+    "custom",
+    "custom element 64"
+  },
+  {
+    "custom_65",
+    "custom",
+    "custom element 65"
+  },
+  {
+    "custom_66",
+    "custom",
+    "custom element 66"
+  },
+  {
+    "custom_67",
+    "custom",
+    "custom element 67"
+  },
+  {
+    "custom_68",
+    "custom",
+    "custom element 68"
+  },
+  {
+    "custom_69",
+    "custom",
+    "custom element 69"
+  },
+  {
+    "custom_70",
+    "custom",
+    "custom element 70"
+  },
+  {
+    "custom_71",
+    "custom",
+    "custom element 71"
+  },
+  {
+    "custom_72",
+    "custom",
+    "custom element 72"
+  },
+  {
+    "custom_73",
+    "custom",
+    "custom element 73"
+  },
+  {
+    "custom_74",
+    "custom",
+    "custom element 74"
+  },
+  {
+    "custom_75",
+    "custom",
+    "custom element 75"
+  },
+  {
+    "custom_76",
+    "custom",
+    "custom element 76"
+  },
+  {
+    "custom_77",
+    "custom",
+    "custom element 77"
+  },
+  {
+    "custom_78",
+    "custom",
+    "custom element 78"
+  },
+  {
+    "custom_79",
+    "custom",
+    "custom element 79"
+  },
+  {
+    "custom_80",
+    "custom",
+    "custom element 80"
+  },
+  {
+    "custom_81",
+    "custom",
+    "custom element 81"
+  },
+  {
+    "custom_82",
+    "custom",
+    "custom element 82"
+  },
+  {
+    "custom_83",
+    "custom",
+    "custom element 83"
+  },
+  {
+    "custom_84",
+    "custom",
+    "custom element 84"
+  },
+  {
+    "custom_85",
+    "custom",
+    "custom element 85"
+  },
+  {
+    "custom_86",
+    "custom",
+    "custom element 86"
+  },
+  {
+    "custom_87",
+    "custom",
+    "custom element 87"
+  },
+  {
+    "custom_88",
+    "custom",
+    "custom element 88"
+  },
+  {
+    "custom_89",
+    "custom",
+    "custom element 89"
+  },
+  {
+    "custom_90",
+    "custom",
+    "custom element 90"
+  },
+  {
+    "custom_91",
+    "custom",
+    "custom element 91"
+  },
+  {
+    "custom_92",
+    "custom",
+    "custom element 92"
+  },
+  {
+    "custom_93",
+    "custom",
+    "custom element 93"
+  },
+  {
+    "custom_94",
+    "custom",
+    "custom element 94"
+  },
+  {
+    "custom_95",
+    "custom",
+    "custom element 95"
+  },
+  {
+    "custom_96",
+    "custom",
+    "custom element 96"
+  },
+  {
+    "custom_97",
+    "custom",
+    "custom element 97"
+  },
+  {
+    "custom_98",
+    "custom",
+    "custom element 98"
+  },
+  {
+    "custom_99",
+    "custom",
+    "custom element 99"
+  },
+  {
+    "custom_100",
+    "custom",
+    "custom element 100"
+  },
+  {
+    "custom_101",
+    "custom",
+    "custom element 101"
+  },
+  {
+    "custom_102",
+    "custom",
+    "custom element 102"
+  },
+  {
+    "custom_103",
+    "custom",
+    "custom element 103"
+  },
+  {
+    "custom_104",
+    "custom",
+    "custom element 104"
+  },
+  {
+    "custom_105",
+    "custom",
+    "custom element 105"
+  },
+  {
+    "custom_106",
+    "custom",
+    "custom element 106"
+  },
+  {
+    "custom_107",
+    "custom",
+    "custom element 107"
+  },
+  {
+    "custom_108",
+    "custom",
+    "custom element 108"
+  },
+  {
+    "custom_109",
+    "custom",
+    "custom element 109"
+  },
+  {
+    "custom_110",
+    "custom",
+    "custom element 110"
+  },
+  {
+    "custom_111",
+    "custom",
+    "custom element 111"
+  },
+  {
+    "custom_112",
+    "custom",
+    "custom element 112"
+  },
+  {
+    "custom_113",
+    "custom",
+    "custom element 113"
+  },
+  {
+    "custom_114",
+    "custom",
+    "custom element 114"
+  },
+  {
+    "custom_115",
+    "custom",
+    "custom element 115"
+  },
+  {
+    "custom_116",
+    "custom",
+    "custom element 116"
+  },
+  {
+    "custom_117",
+    "custom",
+    "custom element 117"
+  },
+  {
+    "custom_118",
+    "custom",
+    "custom element 118"
+  },
+  {
+    "custom_119",
+    "custom",
+    "custom element 119"
+  },
+  {
+    "custom_120",
+    "custom",
+    "custom element 120"
+  },
+  {
+    "custom_121",
+    "custom",
+    "custom element 121"
+  },
+  {
+    "custom_122",
+    "custom",
+    "custom element 122"
+  },
+  {
+    "custom_123",
+    "custom",
+    "custom element 123"
+  },
+  {
+    "custom_124",
+    "custom",
+    "custom element 124"
+  },
+  {
+    "custom_125",
+    "custom",
+    "custom element 125"
+  },
+  {
+    "custom_126",
+    "custom",
+    "custom element 126"
+  },
+  {
+    "custom_127",
+    "custom",
+    "custom element 127"
+  },
+  {
+    "custom_128",
+    "custom",
+    "custom element 128"
+  },
+
+  /* ----------------------------------------------------------------------- */
+  /* "real" (and therefore drawable) runtime elements                        */
+  /* ----------------------------------------------------------------------- */
+
+  {
+    "em_key_1",
+    "key",
+    "-"
+    },
+  {
+    "em_key_2",
+    "key",
+    "-"
+    },
+  {
+    "em_key_3",
+    "key",
+    "-"
+  },
+  {
+    "em_key_4",
+    "key",
+    "-"
+  },
+  {
+    "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",
+    "wall",
+    "-"
+  },
+  {
+    "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",
+    "-"
+  },
+  {
+    "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",
+    "-"
+  },
+  {
+    "magic_wall_active",
+    "magic_wall",
+    "-"
+  },
+  {
+    "bd_magic_wall_active",
+    "magic_wall",
+    "-"
+  },
+  {
+    "magic_wall_full",
+    "magic_wall",
+    "-"
+  },
+  {
+    "bd_magic_wall_full",
+    "magic_wall",
+    "-"
+  },
+  {
+    "magic_wall_emptying",
+    "magic_wall",
+    "-"
+  },
+  {
+    "bd_magic_wall_emptying",
+    "magic_wall",
+    "-"
+  },
+  {
+    "magic_wall_dead",
+    "magic_wall",
+    "-"
+  },
+  {
+    "bd_magic_wall_dead",
+    "magic_wall",
+    "-"
+  },
+
+  /* ----------------------------------------------------------------------- */
+  /* "unreal" (and therefore not drawable) runtime elements                  */
+  /* ----------------------------------------------------------------------- */
+
+  {
+    "blocked",
+    "-",
+    "-"
+  },
+  {
+    "explosion",
+    "-",
+    "-"
+  },
+  {
+    "nut_breaking",
+    "-",
+    "-"
+  },
+  {
+    "diamond_breaking",
+    "-",
+    "-"
+  },
+  {
+    "acid_splash_left",
+    "-",
+    "-"
+  },
+  {
+    "acid_splash_right",
+    "-",
+    "-"
+  },
+  {
+    "amoeba_growing",
+    "-",
+    "-"
+  },
+  {
+    "amoeba_shrinking",
+    "-",
+    "-"
+  },
+  {
+    "expandable_wall_growing",
+    "-",
+    "-"
+  },
+  {
+    "flames",
+    "-",
+    "-"
+  },
+  {
+    "player_is_leaving",
+    "-",
+    "-"
+  },
+  {
+    "quicksand_filling",
+    "quicksand",
+    "-"
+  },
+  {
+    "magic_wall_filling",
+    "-",
+    "-"
+  },
+  {
+    "bd_magic_wall_filling",
+    "-",
+    "-"
+  },
+
+  /* ----------------------------------------------------------------------- */
+  /* dummy elements (never used as game elements, only used as graphics)     */
+  /* ----------------------------------------------------------------------- */
 
-/* filenames of sound effects */
-char *sound_name[NUM_SOUNDS] =
+  {
+    "steelwall_topleft",
+    "-",
+    "-"
+  },
+  {
+    "steelwall_topright",
+    "-",
+    "-"
+  },
+  {
+    "steelwall_bottomleft",
+    "-",
+    "-"
+  },
+  {
+    "steelwall_bottomright",
+    "-",
+    "-"
+  },
+  {
+    "steelwall_horizontal",
+    "-",
+    "-"
+  },
+  {
+    "steelwall_vertical",
+    "-",
+    "-"
+  },
+  {
+    "invisible_steelwall_topleft",
+    "-",
+    "-"
+  },
+  {
+    "invisible_steelwall_topright",
+    "-",
+    "-"
+  },
+  {
+    "invisible_steelwall_bottomleft",
+    "-",
+    "-"
+  },
+  {
+    "invisible_steelwall_bottomright",
+    "-",
+    "-"
+  },
+  {
+    "invisible_steelwall_horizontal",
+    "-",
+    "-"
+  },
+  {
+    "invisible_steelwall_vertical",
+    "-",
+    "-"
+  },
+  {
+    "dynabomb",
+    "-",
+    "-"
+  },
+  {
+    "dynabomb_active",
+    "-",
+    "-"
+  },
+  {
+    "dynabomb_player_1",
+    "-",
+    "-"
+  },
+  {
+    "dynabomb_player_2",
+    "-",
+    "-"
+  },
+  {
+    "dynabomb_player_3",
+    "-",
+    "-"
+  },
+  {
+    "dynabomb_player_4",
+    "-",
+    "-"
+  },
+  {
+    "shield_normal_active",
+    "-",
+    "-"
+  },
+  {
+    "shield_deadly_active",
+    "-",
+    "-"
+  },
+  {
+    "[default]",
+    "default",
+    "-"
+  },
+  {
+    "[bd_default]",
+    "bd_default",
+    "-"
+  },
+  {
+    "[sp_default]",
+    "sp_default",
+    "-"
+  },
+  {
+    "[sb_default]",
+    "sb_default",
+    "-"
+  },
+
+  /* keyword to stop parser: "ELEMENT_INFO_END" <-- do not change! */
+
+  {
+    NULL,
+    NULL,
+    NULL
+  }
+};
+
+
+/* ------------------------------------------------------------------------- */
+/* element action and direction definitions                                  */
+/* ------------------------------------------------------------------------- */
+
+struct ElementActionInfo element_action_info[NUM_ACTIONS + 1 + 1] =
 {
-  "amoebe.wav",
-  "antigrav.wav",
-  "autsch.wav",
-  "blurb.wav",
-  "bong.wav",
-  "buing.wav",
-  "deng.wav",
-  "fuel.wav",
-  "gong.wav",
-  "halloffame.wav",
-  "holz.wav",
-  "hui.wav",
-  "kabumm.wav",
-  "kink.wav",
-  "klapper.wav",
-  "kling.wav",
-  "klopf.wav",
-  "klumpf.wav",
-  "knack.wav",
-  "knurk.wav",
-  "krach.wav",
-  "lachen.wav",
-  "laser.wav",
-  "miep.wav",
-  "njam.wav",
-  "oeffnen.wav",
-  "pling.wav",
-  "pong.wav",
-  "pusch.wav",
-  "quiek.wav",
-  "quirk.wav",
-  "rhythmloop.wav",
-  "roaaar.wav",
-  "roehr.wav",
-  "rumms.wav",
-  "schlopp.wav",
-  "schlurf.wav",
-  "schrff.wav",
-  "schwirr.wav",
-  "sirr.wav",
-  "slurp.wav",
-  "sproing.wav",
-  "warnton.wav",
-  "whoosh.wav",
-  "zisch.wav",
-  "base.wav",
-  "infotron.wav",
-  "zonkdown.wav",
-  "zonkpush.wav",
-  "bug.wav",
-  "boom.wav",
-  "booom.wav",
-  "exit.wav",
-  "empty.wav",
-  "gate.wav"
+  { ".[DEFAULT]",      ACTION_DEFAULT,         TRUE    },
+  { ".waiting",                ACTION_WAITING,         TRUE    },
+  { ".falling",                ACTION_FALLING,         TRUE    },
+  { ".moving",         ACTION_MOVING,          TRUE    },
+  { ".digging",                ACTION_DIGGING,         FALSE   },
+  { ".snapping",       ACTION_SNAPPING,        FALSE   },
+  { ".collecting",     ACTION_COLLECTING,      FALSE   },
+  { ".dropping",       ACTION_DROPPING,        FALSE   },
+  { ".pushing",                ACTION_PUSHING,         FALSE   },
+  { ".walking",                ACTION_WALKING,         FALSE   },
+  { ".passing",                ACTION_PASSING,         FALSE   },
+  { ".impact",         ACTION_IMPACT,          FALSE   },
+  { ".breaking",       ACTION_BREAKING,        FALSE   },
+  { ".activating",     ACTION_ACTIVATING,      FALSE   },
+  { ".deactivating",   ACTION_DEACTIVATING,    FALSE   },
+  { ".opening",                ACTION_OPENING,         FALSE   },
+  { ".closing",                ACTION_CLOSING,         FALSE   },
+  { ".attacking",      ACTION_ATTACKING,       TRUE    },
+  { ".growing",                ACTION_GROWING,         TRUE    },
+  { ".shrinking",      ACTION_SHRINKING,       FALSE   },
+  { ".active",         ACTION_ACTIVE,          TRUE    },
+  { ".filling",                ACTION_FILLING,         FALSE   },
+  { ".emptying",       ACTION_EMPTYING,        FALSE   },
+  { ".changing",       ACTION_CHANGING,        FALSE   },
+  { ".exploding",      ACTION_EXPLODING,       FALSE   },
+  { ".dying",          ACTION_DYING,           FALSE   },
+  { ".other",          ACTION_OTHER,           FALSE   },
+
+  /* empty suffix always matches -- check as last entry in InitSoundInfo() */
+  { "",                        ACTION_DEFAULT,         TRUE    },
+
+  { NULL,              0,                      0       }
 };
 
-struct SoundEffectInfo sound_effects[] =
+struct ElementDirectionInfo element_direction_info[NUM_DIRECTIONS + 1] =
 {
-  /* sounds for Boulder Dash style elements and actions */
-  { "bd_empty_space.digging",          "empty.wav"             },
-  { "bd_sand.digging",                 "schlurf.wav"           },
-  { "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.changing",          "quirk.wav"             },
-  { "bd_magic_wall.running",           "miep.wav"              },
-  { "bd_amoeba.waiting",               SND_FILE_UNDEFINED      },
-  { "bd_amoeba.creating",              "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_exit.entering",                        "buing.wav"             },
-
-  /* sounds for Supaplex style elements and actions */
-  { "sp_empty_space.digging",          "empty.wav"             },
-  { "sp_base.digging",                 "base.wav"              },
-  { "sp_buggy_base.digging",           "base.wav"              },
-  { "sp_buggy_base.activating",                "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.entering",                        "exit.wav"              },
-  { "sp_element.exploding",            "booom.wav"             },
-  { "sp_sniksnak.moving",              SND_FILE_UNDEFINED      },
-  { "sp_sniksnak.waiting",             SND_FILE_UNDEFINED      },
-  { "sp_electron.moving",              SND_FILE_UNDEFINED      },
-  { "sp_electron.waiting",             SND_FILE_UNDEFINED      },
-  { "sp_terminal.activating",          SND_FILE_UNDEFINED      },
-
-  /* sounds for Sokoban style elements and actions */
-  { "sokoban_object.pushing",          "pusch.wav"             },
-  { "sokoban_field.filling",           "deng.wav"              },
-  { "sokoban_field.clearing",          SND_FILE_UNDEFINED      },
-  { "sokoban_game.solving",            "buing.wav"             },
-
-  /* sounds for Emerald Mine style elements and actions */
-  { "empty_space.digging",             "empty.wav"             },
-  { "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.cracking",                    "knack.wav"             },
-  { "nut.impact",                      "klumpf.wav"            },
-  { "dynamite.collecting",             "pong.wav"              },
-  { "dynamite.placing",                        "deng.wav"              },
-  { "dynamite.burning",                        "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",                   SND_FILE_UNDEFINED      },
-  { "yamyam.waiting",                  "njam.wav"              },
-  { "yamyam.eating_diamond",           SND_FILE_UNDEFINED      },
-  { "robot.stepping",                  "schlurf.wav"           },
-  { "robot.waiting",                   SND_FILE_UNDEFINED      },
-  { "robot_wheel.activating",          "deng.wav"              },
-  { "robot_wheel.running",             "miep.wav"              },
-  { "magic_wall.activating",           "quirk.wav"             },
-  { "magic_wall.changing",             "quirk.wav"             },
-  { "magic_wall.running",              "miep.wav"              },
-  { "amoeba.waiting",                  SND_FILE_UNDEFINED      },
-  { "amoeba.creating",                 "amoebe.wav"            },
-  { "amoeba.dropping",                 SND_FILE_UNDEFINED      },
-  { "acid.splashing",                  "blurb.wav"             },
-  { "quicksand.filling",               SND_FILE_UNDEFINED      },
-  { "quicksand.slipping_through",      SND_FILE_UNDEFINED      },
-  { "quicksand.emptying",              SND_FILE_UNDEFINED      },
-  { "exit.opening",                    "oeffnen.wav"           },
-  { "exit.entering",                   "buing.wav"             },
-
-  /* sounds for Emerald Mine Club style elements and actions */
-  { "balloon.moving",                  SND_FILE_UNDEFINED      },
-  { "balloon.waiting",                 SND_FILE_UNDEFINED      },
-  { "balloon.pushing",                 "schlurf.wav"           },
-  { "balloon_switch.activating",       SND_FILE_UNDEFINED      },
-  { "spring.moving",                   SND_FILE_UNDEFINED      },
-  { "spring.pushing",                  "pusch.wav"             },
-  { "spring.impact",                   "klopf.wav"             },
-  { "wall.growing",                    SND_FILE_UNDEFINED      },
-
-  /* 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"              },
-  { "sand_invisible.digging",          "schlurf.wav"           },
-  { "shield_passive.collecting",       "pong.wav"              },
-  { "shield_passive.activated",                SND_FILE_UNDEFINED      },
-  { "shield_active.collecting",                "pong.wav"              },
-  { "shield_active.activated",         SND_FILE_UNDEFINED      },
-  { "extra_time.collecting",           "gong.wav"              },
-  { "mole.moving",                     SND_FILE_UNDEFINED      },
-  { "mole.waiting",                    SND_FILE_UNDEFINED      },
-  { "mole.eating_amoeba",              "blurb.wav"             },
-  { "switchgate_switch.activating",    SND_FILE_UNDEFINED      },
-  { "switchgate.opening",              "oeffnen.wav"           },
-  { "switchgate.closing",              "oeffnen.wav"           },
-  { "switchgate.passing",              "gate.wav"              },
-  { "timegate_wheel.activating",       "deng.wav"              },
-  { "timegate_wheel.running",          "miep.wav"              },
-  { "timegate.opening",                        "oeffnen.wav"           },
-  { "timegate.closing",                        "oeffnen.wav"           },
-  { "timegate.passing",                        "gate.wav"              },
-  { "conveyor_belt_switch.activating", SND_FILE_UNDEFINED      },
-  { "conveyor_belt.running",           SND_FILE_UNDEFINED      },
-  { "light_switch.activating",         SND_FILE_UNDEFINED      },
-  { "light_switch.deactivating",       SND_FILE_UNDEFINED      },
-
-  /* sounds for DX Boulderdash style elements and actions */
-  { "dx_bomb.pushing",                 "pusch.wav"             },
-  { "trap_inactive.digging",           "schlurf.wav"           },
-  { "trap.activating",                 SND_FILE_UNDEFINED      },
-  { "tube.passing",                    SND_FILE_UNDEFINED      },
-
-  /* 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_nr.collecting",          "pong.wav"              },
-  { "dynabomb_sz.collecting",          "pong.wav"              },
-  { "dynabomb_xl.collecting",          "pong.wav"              },
-  { "dynabomb.placing",                        "deng.wav"              },
-  { "dynabomb.burning",                        "zisch.wav"             },
-  { "satellite.moving",                        SND_FILE_UNDEFINED      },
-  { "satellite.waiting",               SND_FILE_UNDEFINED      },
-  { "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"              },
-  { "gameoflife.waiting",              SND_FILE_UNDEFINED      },
-  { "gameoflife.creating",             "amoebe.wav"            },
-  { "biomaze.waiting",                 SND_FILE_UNDEFINED      },
-  { "biomaze.creating",                        "amoebe.wav"            },
-  { "pacman.moving",                   SND_FILE_UNDEFINED      },
-  { "pacman.waiting",                  SND_FILE_UNDEFINED      },
-  { "pacman.eating_amoeba",            SND_FILE_UNDEFINED      },
-  { "dark_yamyam.moving",              SND_FILE_UNDEFINED      },
-  { "dark_yamyam.waiting",             "njam.wav"              },
-  { "dark_yamyam.eating_any",          SND_FILE_UNDEFINED      },
-  { "penguin.moving",                  SND_FILE_UNDEFINED      },
-  { "penguin.waiting",                 SND_FILE_UNDEFINED      },
-  { "penguin.entering_exit",           "buing.wav"             },
-  { "pig.moving",                      SND_FILE_UNDEFINED      },
-  { "pig.waiting",                     SND_FILE_UNDEFINED      },
-  { "pig.eating_gem",                  SND_FILE_UNDEFINED      },
-  { "dragon.moving",                   SND_FILE_UNDEFINED      },
-  { "dragon.waiting",                  SND_FILE_UNDEFINED      },
-  { "dragon.attacking",                        SND_FILE_UNDEFINED      },
-
-  /* sounds for generic elements and actions */
-  { "player.dying",                    "autsch.wav"            },
-  { "element.exploding",               "roaaar.wav"            },
-
-  /* sounds for other game actions */
-  { "game.starting",                   SND_FILE_UNDEFINED      },
-  { "game.running_out_of_time",                "gong.wav"              },
-  { "game.leveltime_bonus",            "sirr.wav"              },
-  { "game.losing",                     "lachen.wav"            },
-  { "game.winning",                    SND_FILE_UNDEFINED      },
-
-  /* sounds for other non-game actions */
-  { "menu.door_opening",               "oeffnen.wav"           },
-  { "menu.door_closing",               "oeffnen.wav"           },
-  { "menu.hall_of_fame",               "halloffame.wav"        },
-  { "menu.info_screen",                        "rhythmloop.wav"        },
+  { ".left",           MV_BIT_LEFT                     },
+  { ".right",          MV_BIT_RIGHT                    },
+  { ".up",             MV_BIT_UP                       },
+  { ".down",           MV_BIT_DOWN                     },
 
-#if 0
-  { "[not used]",                      "antigrav.wav"          },
-  { "[not used]",                      "bong.wav"              },
-  { "[not used]",                      "fuel.wav"              },
-  { "[not used]",                      "holz.wav"              },
-  { "[not used]",                      "hui.wav"               },
-  { "[not used]",                      "kabumm.wav"            },
-  { "[not used]",                      "kink.wav"              },
-  { "[not used]",                      "kling.wav"             },
-  { "[not used]",                      "krach.wav"             },
-  { "[not used]",                      "laser.wav"             },
-  { "[not used]",                      "quiek.wav"             },
-  { "[not used]",                      "rumms.wav"             },
-  { "[not used]",                      "schlopp.wav"           },
-  { "[not used]",                      "schrff.wav"            },
-  { "[not used]",                      "schwirr.wav"           },
-  { "[not used]",                      "slurp.wav"             },
-  { "[not used]",                      "sproing.wav"           },
-  { "[not used]",                      "warnton.wav"           },
-  { "[not used]",                      "whoosh.wav"            },
-  { "[not used]",                      "boom.wav"              },
-#endif
+  { NULL,              0                               }
+};
+
+struct SpecialSuffixInfo special_suffix_info[NUM_SPECIAL_GFX_ARGS + 1] =
+{
+  { ".MAIN",           GAME_MODE_MAIN,                 },
+  { ".LEVELS",         GAME_MODE_LEVELS                },
+  { ".SCORES",         GAME_MODE_SCORES,               },
+  { ".EDITOR",         GAME_MODE_EDITOR,               },
+  { ".INFO",           GAME_MODE_INFO,                 },
+  { ".SETUP",          GAME_MODE_SETUP,                },
+  { ".DOOR",           GAME_MODE_PSEUDO_DOOR,          },
+  { ".PREVIEW",                GAME_MODE_PSEUDO_PREVIEW,       },
+  { ".CRUMBLED",       GAME_MODE_PSEUDO_CRUMBLED,      },
+
+  { NULL,              0,                              }
 };
 
-struct ElementInfo element_info[] =
+struct TokenIntPtrInfo image_config_vars[] =
 {
-  { "empty_space",             "empty space"                   },      /* 0 */
-  { "sand",                    "sand"                          },
-  { "wall",                    "normal wall"                   },
-  { "wall",                    "round wall"                    },
-  { "rock",                    "rock"                          },
-  { "key",                     "key"                           },
-  { "emerald",                 "emerald"                       },
-  { "exit",                    "closed exit"                   },
-  { "player",                  "player"                        },
-  { "bug",                     "bug"                           },
-  { "spaceship",               "spaceship"                     },     /* 10 */
-  { "yamyam",                  "yam yam"                       },
-  { "robot",                   "robot"                         },
-  { "wall",                    "steel wall"                    },
-  { "diamond",                 "diamond"                       },
-  { "amoeba",                  "dead amoeba"                   },
-  { "quicksand",               "empty quicksand"               },
-  { "quicksand",               "quicksand with rock"           },
-  { "amoeba",                  "amoeba drop"                   },
-  { "bomb",                    "bomb"                          },
-  { "magic_wall",              "magic wall"                    },     /* 20 */
-  { "speed_pill",              "speed pill"                    },
-  { "acid",                    "acid pool"                     },
-  { "amoeba",                  "dropping amoeba"               },
-  { "amoeba",                  "normal amoeba"                 },
-  { "nut",                     "nut with emerald"              },
-  { "gameoflife",              "Conway's wall of life"         },
-  { "biomaze",                 "biomaze"                       },
-  { "dynamite",                        "burning dynamite"              },
-  { NULL,                      "unknown"                       },
-  { "robot_wheel",             "magic wheel"                   },     /* 30 */
-  { "robot_wheel",             "magic wheel (running)"         },
-  { "key",                     "red key"                       },
-  { "key",                     "yellow key"                    },
-  { "key",                     "green key"                     },
-  { "key",                     "blue key"                      },
-  { "gate",                    "red door"                      },
-  { "gate",                    "yellow door"                   },
-  { "gate",                    "green door"                    },
-  { "gate",                    "blue door"                     },
-  { "gate",                    "gray door (opened by red key)" },     /* 40 */
-  { "gate",                    "gray door (opened by yellow key)"},
-  { "gate",                    "gray door (opened by green key)"},
-  { "gate",                    "gray door (opened by blue key)"},
-  { "dynamite",                        "dynamite"                      },
-  { "pacman",                  "pac man"                       },
-  { "wall",                    "invisible normal wall"         },
-  { "lamp",                    "lamp (off)"                    },
-  { "lamp",                    "lamp (on)"                     },
-  { "wall",                    "wall with emerald"             },
-  { "wall",                    "wall with diamond"             },     /* 50 */
-  { "amoeba",                  "amoeba with content"           },
-  { "bd_amoeba",               "amoeba (BD style)"             },
-  { "time_orb_full",           "time orb (full)"               },
-  { "time_orb_empty",          "time orb (empty)"              },
-  { "wall",                    "growing wall"                  },
-  { "bd_diamond",              "diamond (BD style)"            },
-  { "emerald",                 "yellow emerald"                },
-  { "wall",                    "wall with BD style diamond"    },
-  { "wall",                    "wall with yellow emerald"      },
-  { "dark_yamyam",             "dark yam yam"                  },     /* 60 */
-  { "bd_magic_wall",           "magic wall (BD style)"         },
-  { "wall",                    "invisible steel wall"          },
-  { NULL,                      "-"                             },
-  { "dynabomb_nr",             "increases number of bombs"     },
-  { "dynabomb_sz",             "increases explosion size"      },
-  { "dynabomb_xl",             "increases power of explosion"  },
-  { "sokoban_object",          "sokoban object"                },
-  { "sokoban_field",           "sokoban empty field"           },
-  { "sokoban_field",           "sokoban field with object"     },
-  { "bd_butterfly",            "butterfly (starts moving right)"},    /* 70 */
-  { "bd_butterfly",            "butterfly (starts moving up)"  },
-  { "bd_butterfly",            "butterfly (starts moving left)"},
-  { "bd_butterfly",            "butterfly (starts moving down)"},
-  { "bd_firefly",              "firefly (starts moving right)" },
-  { "bd_firefly",              "firefly (starts moving up)"    },
-  { "bd_firefly",              "firefly (starts moving left)"  },
-  { "bd_firefly",              "firefly (starts moving down)"  },
-  { "bd_butterfly",            "butterfly"                     },
-  { "bd_firefly",              "firefly"                       },
-  { "player",                  "yellow player"                 },     /* 80 */
-  { "player",                  "red player"                    },
-  { "player",                  "green player"                  },
-  { "player",                  "blue player"                   },
-  { "bug",                     "bug (starts moving right)"     },
-  { "bug",                     "bug (starts moving up)"        },
-  { "bug",                     "bug (starts moving left)"      },
-  { "bug",                     "bug (starts moving down)"      },
-  { "spaceship",               "spaceship (starts moving right)"},
-  { "spaceship",               "spaceship (starts moving up)"  },
-  { "spaceship",               "spaceship (starts moving left)"},     /* 90 */
-  { "spaceship",               "spaceship (starts moving down)"},
-  { "pacman",                  "pac man (starts moving right)" },
-  { "pacman",                  "pac man (starts moving up)"    },
-  { "pacman",                  "pac man (starts moving left)"  },
-  { "pacman",                  "pac man (starts moving down)"  },
-  { "emerald",                 "red emerald"                   },
-  { "emerald",                 "purple emerald"                },
-  { "wall",                    "wall with red emerald"         },
-  { "wall",                    "wall with purple emerald"      },
-  { NULL,                      "unknown"                       },    /* 100 */
-  { NULL,                      "unknown"                       },
-  { NULL,                      "unknown"                       },
-  { NULL,                      "unknown"                       },
-  { NULL,                      "unknown"                       },
-  { NULL,                      "normal wall (BD style)"        },
-  { "bd_rock",                 "rock (BD style)"               },
-  { "exit",                    "open exit"                     },
-  { NULL,                      "black orb bomb"                },
-  { "amoeba",                  "amoeba"                        },
-  { "mole",                    "mole"                          },    /* 110 */
-  { "penguin",                 "penguin"                       },
-  { "satellite",               "satellite"                     },
-  { NULL,                      "arrow left"                    },
-  { NULL,                      "arrow right"                   },
-  { NULL,                      "arrow up"                      },
-  { NULL,                      "arrow down"                    },
-  { "pig",                     "pig"                           },
-  { "dragon",                  "fire breathing dragon"         },
-  { "key",                     "red key (EM style)"            },
-  { NULL,                      "letter ' '"                    },    /* 120 */
-  { NULL,                      "letter '!'"                    },
-  { NULL,                      "letter '\"'"                   },
-  { NULL,                      "letter '#'"                    },
-  { NULL,                      "letter '$'"                    },
-  { NULL,                      "letter '%'"                    },
-  { NULL,                      "letter '&'"                    },
-  { NULL,                      "letter '''"                    },
-  { NULL,                      "letter '('"                    },
-  { NULL,                      "letter ')'"                    },
-  { NULL,                      "letter '*'"                    },    /* 130 */
-  { NULL,                      "letter '+'"                    },
-  { NULL,                      "letter ','"                    },
-  { NULL,                      "letter '-'"                    },
-  { NULL,                      "letter '.'"                    },
-  { NULL,                      "letter '/'"                    },
-  { NULL,                      "letter '0'"                    },
-  { NULL,                      "letter '1'"                    },
-  { NULL,                      "letter '2'"                    },
-  { NULL,                      "letter '3'"                    },
-  { NULL,                      "letter '4'"                    },    /* 140 */
-  { NULL,                      "letter '5'"                    },
-  { NULL,                      "letter '6'"                    },
-  { NULL,                      "letter '7'"                    },
-  { NULL,                      "letter '8'"                    },
-  { NULL,                      "letter '9'"                    },
-  { NULL,                      "letter ':'"                    },
-  { NULL,                      "letter ';'"                    },
-  { NULL,                      "letter '<'"                    },
-  { NULL,                      "letter '='"                    },
-  { NULL,                      "letter '>'"                    },    /* 150 */
-  { NULL,                      "letter '?'"                    },
-  { NULL,                      "letter '@'"                    },
-  { NULL,                      "letter 'A'"                    },
-  { NULL,                      "letter 'B'"                    },
-  { NULL,                      "letter 'C'"                    },
-  { NULL,                      "letter 'D'"                    },
-  { NULL,                      "letter 'E'"                    },
-  { NULL,                      "letter 'F'"                    },
-  { NULL,                      "letter 'G'"                    },
-  { NULL,                      "letter 'H'"                    },    /* 160 */
-  { NULL,                      "letter 'I'"                    },
-  { NULL,                      "letter 'J'"                    },
-  { NULL,                      "letter 'K'"                    },
-  { NULL,                      "letter 'L'"                    },
-  { NULL,                      "letter 'M'"                    },
-  { NULL,                      "letter 'N'"                    },
-  { NULL,                      "letter 'O'"                    },
-  { NULL,                      "letter 'P'"                    },
-  { NULL,                      "letter 'Q'"                    },
-  { NULL,                      "letter 'R'"                    },    /* 170 */
-  { NULL,                      "letter 'S'"                    },
-  { NULL,                      "letter 'T'"                    },
-  { NULL,                      "letter 'U'"                    },
-  { NULL,                      "letter 'V'"                    },
-  { NULL,                      "letter 'W'"                    },
-  { NULL,                      "letter 'X'"                    },
-  { NULL,                      "letter 'Y'"                    },
-  { NULL,                      "letter 'Z'"                    },
-  { NULL,                      "letter 'Ä'"                    },
-  { NULL,                      "letter 'Ö'"                    },    /* 180 */
-  { NULL,                      "letter 'Ãœ'"                    },
-  { NULL,                      "letter '^'"                    },
-  { NULL,                      "letter ''"                     },
-  { NULL,                      "letter ''"                     },
-  { NULL,                      "letter ''"                     },
-  { NULL,                      "letter ''"                     },
-  { NULL,                      "letter ''"                     },
-  { NULL,                      "letter ''"                     },
-  { NULL,                      "letter ''"                     },
-  { NULL,                      "letter ''"                     },    /* 190 */
-  { NULL,                      "letter ''"                     },
-  { NULL,                      "letter ''"                     },
-  { NULL,                      "letter ''"                     },
-  { NULL,                      "letter ''"                     },
-  { NULL,                      "letter ''"                     },
-  { NULL,                      "letter ''"                     },
-  { NULL,                      "letter ''"                     },
-  { NULL,                      "letter ''"                     },
-  { NULL,                      "letter ''"                     },
-  { "wall",                    "growing wall (horizontal)"     },    /* 200 */
-  { "wall",                    "growing wall (vertical)"       },
-  { "wall",                    "growing wall (all directions)" },
-  { "gate",                    "red door (EM style)"           },
-  { "gate",                    "yellow door (EM style)"        },
-  { "gate",                    "green door (EM style)"         },
-  { "gate",                    "blue door (EM style)"          },
-  { "key",                     "yellow key (EM style)"         },
-  { "key",                     "green key (EM style)"          },
-  { "key",                     "blue key (EM style)"           },
-  { "empty_space",             "empty space"                   },    /* 210 */
-  { "sp_zonk",                 "zonk"                          },
-  { "sp_base",                 "base"                          },
-  { "player",                  "murphy"                        },
-  { "sp_infotron",             "infotron"                      },
-  { "wall",                    "chip (single)"                 },
-  { "wall",                    "hardware"                      },
-  { "sp_exit",                 "exit"                          },
-  { "sp_disk_orange",          "orange disk"                   },
-  { "sp_port",                 "port (leading right)"          },
-  { "sp_port",                 "port (leading down)"           },    /* 220 */
-  { "sp_port",                 "port (leading left)"           },
-  { "sp_port",                 "port (leading up)"             },
-  { "sp_port",                 "port (leading right)"          },
-  { "sp_port",                 "port (leading down)"           },
-  { "sp_port",                 "port (leading left)"           },
-  { "sp_port",                 "port (leading up)"             },
-  { "sp_sniksnak",             "snik snak"                     },
-  { "sp_disk_yellow",          "yellow disk"                   },
-  { "sp_terminal",             "terminal"                      },
-  { "sp_disk_red",             "red disk"                      },    /* 230 */
-  { "sp_port",                 "port (vertical)"               },
-  { "sp_port",                 "port (horizontal)"             },
-  { "sp_port",                 "port (all directions)"         },
-  { "sp_electron",             "electron"                      },
-  { "sp_buggy_base",           "buggy base"                    },
-  { "wall",                    "chip (left half)"              },
-  { "wall",                    "chip (right half)"             },
-  { "wall",                    "hardware"                      },
-  { "wall",                    "hardware"                      },
-  { "wall",                    "hardware"                      },    /* 240 */
-  { "wall",                    "hardware"                      },
-  { "wall",                    "hardware"                      },
-  { "wall",                    "hardware"                      },
-  { "wall",                    "hardware"                      },
-  { "wall",                    "hardware"                      },
-  { "wall",                    "hardware"                      },
-  { "wall",                    "hardware"                      },
-  { "wall",                    "chip (upper half)"             },
-  { "wall",                    "chip (lower half)"             },
-  { "gate",                    "gray door (EM style, red key)" },    /* 250 */
-  { "gate",                    "gray door (EM style, yellow key)"},
-  { "gate",                    "gray door (EM style, green key)"},
-  { "gate",                    "gray door (EM style, blue key)"},
-  { NULL,                      "unknown"                       },
-  { NULL,                      "unknown"                       },
-
-  /* 256 */
-
-  { "pearl",                   "pearl"                         },  /* (256) */
-  { "crystal",                 "crystal"                       },
-  { "wall",                    "wall with pearl"               },
-  { "wall",                    "wall with crystal"             },
-  { "gate",                    "white door"                    },    /* 260 */
-  { "gate",                    "gray door (opened by white key)"},
-  { "key",                     "white key"                     },
-  { "shield_passive",          "shield (passive)"              },
-  { "extra_time",              "extra time"                    },
-  { "switchgate",              "switch gate (open)"            },
-  { "switchgate",              "switch gate (closed)"          },
-  { "switchgate_switch",       "switch for switch gate"        },
-  { "switchgate_switch",       "switch for switch gate"        },
-  { NULL,                      "-"                             },
-  { NULL,                      "-"                             },    /* 270 */
-  { "conveyor_belt",           "red conveyor belt (left)"      },
-  { "conveyor_belt",           "red conveyor belt (middle)"    },
-  { "conveyor_belt",           "red conveyor belt (right)"     },
-  { "conveyor_belt_switch",    "switch for red conveyor belt (left)"},
-  { "conveyor_belt_switch",    "switch for red conveyor belt (middle)"},
-  { "conveyor_belt_switch",    "switch for red conveyor belt (right)"},
-  { "conveyor_belt",           "yellow conveyor belt (left)"   },
-  { "conveyor_belt",           "yellow conveyor belt (middle)" },
-  { "conveyor_belt",           "yellow conveyor belt (right)"  },
-  { "conveyor_belt_switch",    "switch for yellow conveyor belt (left)"},
-  { "conveyor_belt_switch",    "switch for yellow conveyor belt (middle)"},
-  { "conveyor_belt_switch",    "switch for yellow conveyor belt (right)"},
-  { "conveyor_belt",           "green conveyor belt (left)"    },
-  { "conveyor_belt",           "green conveyor belt (middle)"  },
-  { "conveyor_belt",           "green conveyor belt (right)"   },
-  { "conveyor_belt_switch",    "switch for green conveyor belt (left)"},
-  { "conveyor_belt_switch",    "switch for green conveyor belt (middle)"},
-  { "conveyor_belt_switch",    "switch for green conveyor belt (right)"},
-  { "conveyor_belt",           "blue conveyor belt (left)"     },
-  { "conveyor_belt",           "blue conveyor belt (middle)"   },
-  { "conveyor_belt",           "blue conveyor belt (right)"    },
-  { "conveyor_belt_switch",    "switch for blue conveyor belt (left)"},
-  { "conveyor_belt_switch",    "switch for blue conveyor belt (middle)"},
-  { "conveyor_belt_switch",    "switch for blue conveyor belt (right)"},
-  { "sand",                    "land mine"                     },
-  { "envelope",                        "mail envelope"                 },
-  { "light_switch",            "light switch (off)"            },
-  { "light_switch",            "light switch (on)"             },
-  { "wall",                    "sign (exclamation)"            },
-  { "wall",                    "sign (radio activity)"         },    /* 300 */
-  { "wall",                    "sign (stop)"                   },
-  { "wall",                    "sign (wheel chair)"            },
-  { "wall",                    "sign (parking)"                },
-  { "wall",                    "sign (one way)"                },
-  { "wall",                    "sign (heart)"                  },
-  { "wall",                    "sign (triangle)"               },
-  { "wall",                    "sign (round)"                  },
-  { "wall",                    "sign (exit)"                   },
-  { "wall",                    "sign (yin yang)"               },
-  { "wall",                    "sign (other)"                  },    /* 310 */
-  { "mole",                    "mole (starts moving left)"     },
-  { "mole",                    "mole (starts moving right)"    },
-  { "mole",                    "mole (starts moving up)"       },
-  { "mole",                    "mole (starts moving down)"     },
-  { "wall",                    "steel wall (slanted)"          },
-  { "sand",                    "invisible sand"                },
-  { NULL,                      "dx unknown 15"                 },
-  { NULL,                      "dx unknown 42"                 },
-  { NULL,                      "-"                             },
-  { NULL,                      "-"                             },    /* 320 */
-  { "shield_active",           "shield (active, kills enemies)"},
-  { "timegate",                        "time gate (open)"              },
-  { "timegate",                        "time gate (closed)"            },
-  { "timegate_wheel",          "switch for time gate"          },
-  { "timegate_wheel",          "switch for time gate"          },
-  { "balloon",                 "balloon"                       },
-  { "wall",                    "send balloon to the left"      },
-  { "wall",                    "send balloon to the right"     },
-  { "balloon_switch",          "send balloon up"               },
-  { "balloon_switch",          "send balloon down"             },    /* 330 */
-  { "balloon_switch",          "send balloon in any direction" },
-  { "wall",                    "steel wall"                    },
-  { "wall",                    "steel wall"                    },
-  { "wall",                    "steel wall"                    },
-  { "wall",                    "steel wall"                    },
-  { "wall",                    "normal wall"                   },
-  { "wall",                    "normal wall"                   },
-  { "wall",                    "normal wall"                   },
-  { "wall",                    "normal wall"                   },
-  { "wall",                    "normal wall"                   },    /* 340 */
-  { "wall",                    "normal wall"                   },
-  { "wall",                    "normal wall"                   },
-  { "wall",                    "normal wall"                   },
-  { "tube",                    "tube (all directions)"         },
-  { "tube",                    "tube (vertical)"               },
-  { "tube",                    "tube (horizontal)"             },
-  { "tube",                    "tube (vertical & left)"        },
-  { "tube",                    "tube (vertical & right)"       },
-  { "tube",                    "tube (horizontal & up)"        },
-  { "tube",                    "tube (horizontal & down)"      },    /* 350 */
-  { "tube",                    "tube (left & up)"              },
-  { "tube",                    "tube (left & down)"            },
-  { "tube",                    "tube (right & up)"             },
-  { "tube",                    "tube (right & down)"           },
-  { "spring",                  "spring"                        },
-  { "trap",                    "trap"                          },
-  { "dx_bomb",                 "stable bomb (DX style)"        },
-  { NULL,                      "-"                             }
-
-  /*
-  "-------------------------------",
-  */
+  { "global.num_toons",                &global.num_toons                          },
+
+  { "menu.draw_xoffset",       &menu.draw_xoffset_default                 },
+  { "menu.draw_yoffset",       &menu.draw_yoffset_default                 },
+  { "menu.draw_xoffset.MAIN",  &menu.draw_xoffset[GFX_SPECIAL_ARG_MAIN]   },
+  { "menu.draw_yoffset.MAIN",  &menu.draw_yoffset[GFX_SPECIAL_ARG_MAIN]   },
+  { "menu.draw_xoffset.LEVELS",        &menu.draw_xoffset[GFX_SPECIAL_ARG_LEVELS] },
+  { "menu.draw_yoffset.LEVELS",        &menu.draw_yoffset[GFX_SPECIAL_ARG_LEVELS] },
+  { "menu.draw_xoffset.SCORES",        &menu.draw_xoffset[GFX_SPECIAL_ARG_SCORES] },
+  { "menu.draw_yoffset.SCORES",        &menu.draw_yoffset[GFX_SPECIAL_ARG_SCORES] },
+  { "menu.draw_xoffset.EDITOR",        &menu.draw_xoffset[GFX_SPECIAL_ARG_EDITOR] },
+  { "menu.draw_yoffset.EDITOR",        &menu.draw_yoffset[GFX_SPECIAL_ARG_EDITOR] },
+  { "menu.draw_xoffset.INFO",  &menu.draw_xoffset[GFX_SPECIAL_ARG_INFO]   },
+  { "menu.draw_yoffset.INFO",  &menu.draw_yoffset[GFX_SPECIAL_ARG_INFO]   },
+  { "menu.draw_xoffset.SETUP", &menu.draw_xoffset[GFX_SPECIAL_ARG_SETUP]  },
+  { "menu.draw_yoffset.SETUP", &menu.draw_yoffset[GFX_SPECIAL_ARG_SETUP]  },
+
+  { "menu.scrollbar_xoffset",  &menu.scrollbar_xoffset                    },
+
+  { "menu.list_size",          &menu.list_size_default                    },
+  { "menu.list_size.LEVELS",   &menu.list_size[GFX_SPECIAL_ARG_LEVELS]    },
+  { "menu.list_size.SCORES",   &menu.list_size[GFX_SPECIAL_ARG_SCORES]    },
+  { "menu.list_size.INFO",     &menu.list_size[GFX_SPECIAL_ARG_INFO]      },
+
+  { "door.step_offset",                &door.step_offset                          },
+  { "door.step_delay",         &door.step_delay                           },
+
+  { NULL,                      NULL,                                      }
+};
+
+
+/* ------------------------------------------------------------------------- */
+/* font definitions                                                          */
+/* ------------------------------------------------------------------------- */
+
+/* Important: When one entry is a prefix of another entry, the longer entry
+   must come first, because the dynamic configuration does prefix matching! */
+
+struct FontInfo font_info[NUM_FONTS + 1] =
+{
+  { "font.initial_1"           },
+  { "font.initial_2"           },
+  { "font.initial_3"           },
+  { "font.initial_4"           },
+  { "font.title_1"             },
+  { "font.title_2"             },
+  { "font.menu_1"              },
+  { "font.menu_2"              },
+  { "font.text_1.active"       },
+  { "font.text_2.active"       },
+  { "font.text_3.active"       },
+  { "font.text_4.active"       },
+  { "font.text_1"              },
+  { "font.text_2"              },
+  { "font.text_3"              },
+  { "font.text_4"              },
+  { "font.input_1.active"      },
+  { "font.input_2.active"      },
+  { "font.input_1"             },
+  { "font.input_2"             },
+  { "font.option_off"          },
+  { "font.option_on"           },
+  { "font.value_1"             },
+  { "font.value_2"             },
+  { "font.value_old"           },
+  { "font.level_number"                },
+  { "font.tape_recorder"       },
+  { "font.game_info"           },
 };
 
 
@@ -730,9 +3133,14 @@ struct ElementInfo element_info[] =
 
 int main(int argc, char *argv[])
 {
-  InitCommandName(argv[0]);
+  InitProgramInfo(argv[0], USERDATA_DIRECTORY,
+                 PROGRAM_TITLE_STRING, getWindowTitleString(),
+                 ICON_TITLE_STRING, X11_ICON_FILENAME, X11_ICONMASK_FILENAME,
+                 MSDOS_POINTER_FILENAME,
+                 COOKIE_PREFIX, FILENAME_PREFIX, GAME_VERSION_ACTUAL);
+
   InitExitFunction(CloseAllAndExit);
-  InitPlatformDependantStuff();
+  InitPlatformDependentStuff();
 
   GetOptions(argv);
   OpenAll();
index 71cfcdf9402604d4342fa48810b122a28fd8fcdc..03e983782a83ec62ff9425804ffbd1e422c9e8a8 100644 (file)
 
 #include "libgame/libgame.h"
 
-#define WIN_XSIZE      672
-#define WIN_YSIZE      560
-
-#define SCR_FIELDX     17
-#define SCR_FIELDY     17
-#define MAX_BUF_XSIZE  (SCR_FIELDX + 2)
-#define MAX_BUF_YSIZE  (SCR_FIELDY + 2)
-#define MIN_LEV_FIELDX 3
-#define MIN_LEV_FIELDY 3
-#define STD_LEV_FIELDX 64
-#define STD_LEV_FIELDY 32
-#define MAX_LEV_FIELDX 128
-#define MAX_LEV_FIELDY 128
-
-#define SCREENX(a)     ((a) - scroll_x)
-#define SCREENY(a)     ((a) - scroll_y)
-#define LEVELX(a)      ((a) + scroll_x)
-#define LEVELY(a)      ((a) + scroll_y)
+#include "conf_gfx.h"  /* include auto-generated data structure definitions */
+#include "conf_snd.h"  /* include auto-generated data structure definitions */
+
+#define IMG_UNDEFINED          (-1)
+#define IMG_EMPTY              IMG_EMPTY_SPACE
+#define IMG_SP_EMPTY           IMG_SP_EMPTY_SPACE
+#define IMG_EXPLOSION          IMG_DEFAULT_EXPLODING
+#define IMG_CHAR_START         IMG_CHAR_SPACE
+#define IMG_CUSTOM_START       IMG_CUSTOM_1
+
+#define SND_UNDEFINED          (-1)
+
+#define WIN_XSIZE              672
+#define WIN_YSIZE              560
+
+#define SCR_FIELDX             17
+#define SCR_FIELDY             17
+#define MAX_BUF_XSIZE          (SCR_FIELDX + 2)
+#define MAX_BUF_YSIZE          (SCR_FIELDY + 2)
+#define MIN_LEV_FIELDX         3
+#define MIN_LEV_FIELDY         3
+#define STD_LEV_FIELDX         64
+#define STD_LEV_FIELDY         32
+#define MAX_LEV_FIELDX         128
+#define MAX_LEV_FIELDY         128
+
+#define SCREENX(a)             ((a) - scroll_x)
+#define SCREENY(a)             ((a) - scroll_y)
+#define LEVELX(a)              ((a) + scroll_x)
+#define LEVELY(a)              ((a) + scroll_y)
 #define IN_VIS_FIELD(x,y) ((x)>=0 && (x)<SCR_FIELDX && (y)>=0 &&(y)<SCR_FIELDY)
 #define IN_SCR_FIELD(x,y) ((x)>=BX1 && (x)<=BX2 && (y)>=BY1 &&(y)<=BY2)
 #define IN_LEV_FIELD(x,y) ((x)>=0 && (x)<lev_fieldx && (y)>=0 &&(y)<lev_fieldy)
 
-/* values for 'Elementeigenschaften1' */
-#define EP_BIT_AMOEBALIVE      (1 << 0)
-#define EP_BIT_AMOEBOID                (1 << 1)
-#define EP_BIT_SCHLUESSEL      (1 << 2)
-#define EP_BIT_PFORTE          (1 << 3)
-#define EP_BIT_SOLID           (1 << 4)
-#define EP_BIT_MASSIVE         (1 << 5)
-#define EP_BIT_SLIPPERY                (1 << 6)
-#define EP_BIT_ENEMY           (1 << 7)
-#define EP_BIT_MAUER           (1 << 8)
-#define EP_BIT_CAN_FALL                (1 << 9)
-#define EP_BIT_CAN_SMASH       (1 << 10)
-#define EP_BIT_CAN_CHANGE      (1 << 11)
-#define EP_BIT_CAN_MOVE                (1 << 12)
-#define EP_BIT_COULD_MOVE      (1 << 13)
-#define EP_BIT_DONT_TOUCH      (1 << 14)
-#define EP_BIT_DONT_GO_TO      (1 << 15)
-#define EP_BIT_MAMPF2          (1 << 16)
-#define EP_BIT_CHAR            (1 << 17)
-#define EP_BIT_BD_ELEMENT      (1 << 18)
-#define EP_BIT_SB_ELEMENT      (1 << 19)
-#define EP_BIT_GEM             (1 << 20)
-#define EP_BIT_INACTIVE                (1 << 21)
-#define EP_BIT_EXPLOSIVE       (1 << 22)
-#define EP_BIT_MAMPF3          (1 << 23)
-#define EP_BIT_PUSHABLE                (1 << 24)
-#define EP_BIT_PLAYER          (1 << 25)
-#define EP_BIT_HAS_CONTENT     (1 << 26)
-#define EP_BIT_EATABLE         (1 << 27)
-#define EP_BIT_SP_ELEMENT      (1 << 28)
-#define EP_BIT_QUICK_GATE      (1 << 29)
-#define EP_BIT_OVER_PLAYER     (1 << 30)
-#define EP_BIT_ACTIVE_BOMB     (1 << 31)
-
-/* values for 'Elementeigenschaften2' */
-#define EP_BIT_BELT            (1 << 0)
-#define EP_BIT_BELT_SWITCH     (1 << 1)
-#define EP_BIT_TUBE            (1 << 2)
-#define EP_BIT_EM_SLIPPERY_WALL        (1 << 3)
-
-#define IS_AMOEBALIVE(e)       (Elementeigenschaften1[e] & EP_BIT_AMOEBALIVE)
-#define IS_AMOEBOID(e)         (Elementeigenschaften1[e] & EP_BIT_AMOEBOID)
-#define IS_SCHLUESSEL(e)       (Elementeigenschaften1[e] & EP_BIT_SCHLUESSEL)
-#define IS_PFORTE(e)           (Elementeigenschaften1[e] & EP_BIT_PFORTE)
-#define IS_SOLID(e)            (Elementeigenschaften1[e] & EP_BIT_SOLID)
-#define IS_MASSIVE(e)          (Elementeigenschaften1[e] & EP_BIT_MASSIVE)
-#define IS_SLIPPERY(e)         (Elementeigenschaften1[e] & EP_BIT_SLIPPERY)
-#define IS_ENEMY(e)            (Elementeigenschaften1[e] & EP_BIT_ENEMY)
-#define IS_MAUER(e)            (Elementeigenschaften1[e] & EP_BIT_MAUER)
-#define CAN_FALL(e)            (Elementeigenschaften1[e] & EP_BIT_CAN_FALL)
-#define CAN_SMASH(e)           (Elementeigenschaften1[e] & EP_BIT_CAN_SMASH)
-#define CAN_CHANGE(e)          (Elementeigenschaften1[e] & EP_BIT_CAN_CHANGE)
-#define CAN_MOVE(e)            (Elementeigenschaften1[e] & EP_BIT_CAN_MOVE)
-#define COULD_MOVE(e)          (Elementeigenschaften1[e] & EP_BIT_COULD_MOVE)
-#define DONT_TOUCH(e)          (Elementeigenschaften1[e] & EP_BIT_DONT_TOUCH)
-#define DONT_GO_TO(e)          (Elementeigenschaften1[e] & EP_BIT_DONT_GO_TO)
-#define IS_MAMPF2(e)           (Elementeigenschaften1[e] & EP_BIT_MAMPF2)
-#define IS_CHAR(e)             (Elementeigenschaften1[e] & EP_BIT_CHAR)
-#define IS_BD_ELEMENT(e)       (Elementeigenschaften1[e] & EP_BIT_BD_ELEMENT)
-#define IS_SB_ELEMENT(e)       (Elementeigenschaften1[e] & EP_BIT_SB_ELEMENT)
-#define IS_GEM(e)              (Elementeigenschaften1[e] & EP_BIT_GEM)
-#define IS_INACTIVE(e)         (Elementeigenschaften1[e] & EP_BIT_INACTIVE)
-#define IS_EXPLOSIVE(e)                (Elementeigenschaften1[e] & EP_BIT_EXPLOSIVE)
-#define IS_MAMPF3(e)           (Elementeigenschaften1[e] & EP_BIT_MAMPF3)
-#define IS_PUSHABLE(e)         (Elementeigenschaften1[e] & EP_BIT_PUSHABLE)
-#define ELEM_IS_PLAYER(e)      (Elementeigenschaften1[e] & EP_BIT_PLAYER)
-#define HAS_CONTENT(e)         (Elementeigenschaften1[e] & EP_BIT_HAS_CONTENT)
-#define IS_EATABLE(e)          (Elementeigenschaften1[e] & EP_BIT_EATABLE)
-#define IS_SP_ELEMENT(e)       (Elementeigenschaften1[e] & EP_BIT_SP_ELEMENT)
-#define IS_QUICK_GATE(e)       (Elementeigenschaften1[e] & EP_BIT_QUICK_GATE)
-#define IS_OVER_PLAYER(e)      (Elementeigenschaften1[e] & EP_BIT_OVER_PLAYER)
-#define IS_ACTIVE_BOMB(e)      (Elementeigenschaften1[e] & EP_BIT_ACTIVE_BOMB)
-#define IS_BELT(e)             (Elementeigenschaften2[e] & EP_BIT_BELT)
-#define IS_BELT_SWITCH(e)      (Elementeigenschaften2[e] & EP_BIT_BELT_SWITCH)
-#define IS_TUBE(e)             (Elementeigenschaften2[e] & EP_BIT_TUBE)
-#define IS_EM_SLIPPERY_WALL(e) (Elementeigenschaften2[e] & EP_BIT_EM_SLIPPERY_WALL)
+/* values for configurable properties (custom elem's only, else pre-defined) */
+#define EP_DIGGABLE            0
+#define EP_COLLECTIBLE         1
+#define EP_DONT_RUN_INTO       2
+#define EP_DONT_COLLIDE_WITH   3
+#define EP_DONT_TOUCH          4
+#define EP_INDESTRUCTIBLE      5
+#define EP_SLIPPERY            6
+#define EP_CAN_CHANGE          7
+#define EP_CAN_MOVE            8
+#define EP_CAN_FALL            9
+#define EP_CAN_SMASH_PLAYER    10
+#define EP_CAN_SMASH_ENEMIES   11
+#define EP_CAN_SMASH_EVERYTHING        12
+#define EP_CAN_EXPLODE_BY_FIRE 13
+#define EP_CAN_EXPLODE_SMASHED 14
+#define EP_CAN_EXPLODE_IMPACT  15
+#define EP_WALKABLE_OVER       16
+#define EP_WALKABLE_INSIDE     17
+#define EP_WALKABLE_UNDER      18
+#define EP_PASSABLE_OVER       19
+#define EP_PASSABLE_INSIDE     20
+#define EP_PASSABLE_UNDER      21
+#define EP_UNUSED_22           22
+#define EP_UNUSED_23           23
+#define EP_PUSHABLE            24
+
+/* values for special configurable properties (depending on level settings) */
+#define EP_EM_SLIPPERY_WALL    32
+
+/* values for special graphics properties (no effect on game engine) */
+#define EP_CAN_BE_CRUMBLED     33
+
+/* values for pre-defined properties */
+#define EP_PLAYER              34
+#define EP_CAN_PASS_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_KEYGATE             51
+#define EP_AMOEBOID            52
+#define EP_AMOEBALIVE          53
+#define EP_HAS_CONTENT         54
+#define EP_ACTIVE_BOMB         55
+#define EP_INACTIVE            56
+
+/* values for derived properties (determined from properties above) */
+#define EP_ACCESSIBLE_OVER     57
+#define EP_ACCESSIBLE_INSIDE   58
+#define EP_ACCESSIBLE_UNDER    59
+#define EP_WALKABLE            60
+#define EP_PASSABLE            61
+#define EP_ACCESSIBLE          62
+#define EP_SNAPPABLE           63
+#define EP_WALL                        64
+#define EP_SOLID_FOR_PUSHING   65
+#define EP_DRAGONFIRE_PROOF    66
+#define EP_EXPLOSION_PROOF     67
+#define EP_CAN_SMASH           68
+#define EP_CAN_EXPLODE         69
+
+/* values for internal purpose only (level editor) */
+#define EP_EXPLODE_RESULT      70
+#define EP_WALK_TO_OBJECT      71
+#define EP_DEADLY              72
+
+#define NUM_ELEMENT_PROPERTIES 73
+
+#define NUM_EP_BITFIELDS       ((NUM_ELEMENT_PROPERTIES + 31) / 32)
+#define EP_BITFIELD_BASE       0
+
+#define EP_BITMASK_DEFAULT     0
+
+#define PROPERTY_BIT(p)                (1 << ((p) % 32))
+#define PROPERTY_VAR(e,p)      (Properties[e][(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 */
+#define CE_DELAY               0
+#define CE_TOUCHED_BY_PLAYER   1
+#define CE_PRESSED_BY_PLAYER   2
+#define CE_PUSHED_BY_PLAYER    3
+#define CE_COLLISION           4
+#define CE_IMPACT              5
+#define CE_SMASHED             6
+#define CE_OTHER_IS_TOUCHING   7
+#define CE_OTHER_IS_CHANGING   8
+#define CE_OTHER_IS_EXPLODING  9
+#define CE_OTHER_GETS_TOUCHED  10
+#define CE_OTHER_GETS_PRESSED  11
+#define CE_OTHER_GETS_PUSHED   12
+#define CE_OTHER_GETS_COLLECTED        13
+
+/* values for internal purpose only (level editor) */
+#define CE_BY_PLAYER           14
+#define CE_BY_COLLISION                15
+#define CE_BY_OTHER            16
+
+#define NUM_CHANGE_EVENTS      17
+
+#define CE_BITMASK_DEFAULT     0
+
+#define CH_EVENT_BIT(c)                (1 << (c))
+#define CH_EVENT_VAR(e)                (element_info[e].change.events)
+
+#define HAS_CHANGE_EVENT(e,c)  (IS_CUSTOM_ELEMENT(e) &&                  \
+                                (CH_EVENT_VAR(e) & CH_EVENT_BIT(c)) != 0)
+#define SET_CHANGE_EVENT(e,c,v)        (IS_CUSTOM_ELEMENT(e) ?                   \
+                                ((v) ?                                   \
+                                 (CH_EVENT_VAR(e) |=  CH_EVENT_BIT(c)) : \
+                                 (CH_EVENT_VAR(e) &= ~CH_EVENT_BIT(c))) : 0)
+
+/* values for change power for custom elements */
+#define CP_NON_DESTRUCTIVE     0
+#define CP_HALF_DESTRUCTIVE    1
+#define CP_FULL_DESTRUCTIVE    2
+
+/* values for special move patterns (bits 0-3: basic move directions) */
+#define MV_BIT_TOWARDS_PLAYER  4
+#define MV_BIT_AWAY_FROM_PLAYER        5
+#define MV_BIT_ALONG_LEFT_SIDE 6
+#define MV_BIT_ALONG_RIGHT_SIDE        7
+#define MV_BIT_TURNING_LEFT    8
+#define MV_BIT_TURNING_RIGHT   9
+
+/* values for special move patterns for custom elements */
+#define MV_HORIZONTAL          (MV_LEFT | MV_RIGHT)
+#define MV_VERTICAL            (MV_UP | MV_DOWN)
+#define MV_ALL_DIRECTIONS      (MV_HORIZONTAL | MV_VERTICAL)
+#define MV_ANY_DIRECTION       (MV_ALL_DIRECTIONS)
+#define MV_TOWARDS_PLAYER      (1 << MV_BIT_TOWARDS_PLAYER)
+#define MV_AWAY_FROM_PLAYER    (1 << MV_BIT_AWAY_FROM_PLAYER)
+#define MV_ALONG_LEFT_SIDE     (1 << MV_BIT_ALONG_LEFT_SIDE)
+#define MV_ALONG_RIGHT_SIDE    (1 << MV_BIT_ALONG_RIGHT_SIDE)
+#define MV_TURNING_LEFT                (1 << MV_BIT_TURNING_LEFT)
+#define MV_TURNING_RIGHT       (1 << MV_BIT_TURNING_RIGHT)
+
+/* values for slippery property for custom elements */
+#define SLIPPERY_ANY_RANDOM    0
+#define SLIPPERY_ANY_LEFT_RIGHT        1
+#define SLIPPERY_ANY_RIGHT_LEFT        2
+#define SLIPPERY_ONLY_LEFT     3
+#define SLIPPERY_ONLY_RIGHT    4
+
+/* macros for configurable properties */
+#define IS_DIGGABLE(e)         HAS_PROPERTY(e, EP_DIGGABLE)
+#define IS_COLLECTIBLE(e)      HAS_PROPERTY(e, EP_COLLECTIBLE)
+#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 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_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_PUSHABLE(e)         HAS_PROPERTY(e, EP_PUSHABLE)
+
+/* macros for special configurable properties */
+#define IS_EM_SLIPPERY_WALL(e) HAS_PROPERTY(e, EP_EM_SLIPPERY_WALL)
+
+/* macros for special graphics properties */
+#define CAN_BE_CRUMBLED(e)     HAS_PROPERTY(GFX_ELEMENT(e),EP_CAN_BE_CRUMBLED)
+
+/* macros for pre-defined properties */
+#define ELEM_IS_PLAYER(e)      HAS_PROPERTY(e, EP_PLAYER)
+#define CAN_PASS_MAGIC_WALL(e) HAS_PROPERTY(e, EP_CAN_PASS_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_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_CONTENT(e)         HAS_PROPERTY(e, EP_HAS_CONTENT)
+#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_SNAPPABLE(e)                HAS_PROPERTY(e, EP_SNAPPABLE)
+#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_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 CAN_EXPLODE(e)         HAS_PROPERTY(e, EP_CAN_EXPLODE)
+
+/* special macros used in game engine */
+#define IS_CUSTOM_ELEMENT(e)   ((e) >= EL_CUSTOM_START &&              \
+                                (e) <= EL_CUSTOM_END)
+
+#define GFX_ELEMENT(e)         (element_info[e].use_gfx_element ?      \
+                                element_info[e].gfx_element : e)
 
 #define IS_PLAYER(x,y)         (ELEM_IS_PLAYER(StorePlayer[x][y]))
 
-#define IS_FREE(x,y)           (Feld[x][y] == EL_LEERRAUM && !IS_PLAYER(x,y))
-#define IS_FREE_OR_PLAYER(x,y) (Feld[x][y] == EL_LEERRAUM)
+#define IS_FREE(x,y)           (Feld[x][y] == EL_EMPTY && !IS_PLAYER(x,y))
+#define IS_FREE_OR_PLAYER(x,y) (Feld[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)                (Feld[x][y] == EL_BLOCKED)
 
-#define EL_CHANGED(e)          ((e) == EL_FELSBROCKEN    ? EL_EDELSTEIN :  \
-                                (e) == EL_BD_ROCK        ? EL_EDELSTEIN_BD : \
-                                (e) == EL_EDELSTEIN      ? EL_DIAMANT :    \
-                                (e) == EL_EDELSTEIN_GELB ? EL_DIAMANT :    \
-                                (e) == EL_EDELSTEIN_ROT  ? EL_DIAMANT :    \
-                                (e) == EL_EDELSTEIN_LILA ? EL_DIAMANT :    \
-                                EL_FELSBROCKEN)
-#define EL_CHANGED2(e)         ((e) == EL_FELSBROCKEN ? EL_EDELSTEIN_BD :  \
-                                (e) == EL_BD_ROCK     ? EL_EDELSTEIN_BD : \
+#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_CHANGED2(e)         ((e) == EL_ROCK           ? EL_BD_DIAMOND : \
+                                (e) == EL_BD_ROCK        ? EL_BD_DIAMOND : \
                                 EL_BD_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_SPIELER1])
-#define SHIELD_ON(p)           ((p)->shield_passive_time_left > 0)
-#define PROTECTED_FIELD(x,y)   (IS_TUBE(Feld[x][y]))
+#define PLAYERINFO(x,y)                (&stored_player[StorePlayer[x][y]-EL_PLAYER_1])
+#define SHIELD_ON(p)           ((p)->shield_normal_time_left > 0)
+#define PROTECTED_FIELD(x,y)   (IS_ACCESSIBLE_INSIDE(Feld[x][y]) &&    \
+                                IS_INDESTRUCTIBLE(Feld[x][y]))
 #define PLAYER_PROTECTED(x,y)  (SHIELD_ON(PLAYERINFO(x, y)) ||         \
                                 PROTECTED_FIELD(x, y))
 
-/* Bitmaps with graphic file */
-#define PIX_BACK               0
-#define PIX_DOOR               1
-#define PIX_HEROES             2
-#define PIX_TOONS              3
-#define PIX_SP                 4
-#define PIX_DC                 5
-#define PIX_MORE               6
-#define        PIX_BIGFONT             7
-#define PIX_SMALLFONT          8
-#define PIX_MEDIUMFONT         9
-/* Bitmaps without graphic file */
-#define PIX_DB_DOOR            10
-#define PIX_DB_FIELD           11
-
-#define NUM_PICTURES           10
-#define NUM_BITMAPS            12
+#define PLAYER_NR_GFX(g,i)     ((g) + i * (IMG_PLAYER_2 - IMG_PLAYER_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 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)
+
 
 /* boundaries of arrays etc. */
 #define MAX_LEVEL_NAME_LEN     32
 #define MAX_LEVEL_AUTHOR_LEN   32
+#define MAX_ELEMENT_NAME_LEN   32
 #define MAX_TAPELEN            (1000 * 50)     /* max. time * framerate */
 #define MAX_SCORE_ENTRIES      100
-#define MAX_ELEMENTS           700             /* 500 static + 200 runtime */
 #define MAX_NUM_AMOEBA         100
 
 /* values for elements with content */
 #define MICROLEVEL_SCROLL_DELAY        50      /* delay for scrolling micro level */
 #define MICROLEVEL_LABEL_DELAY 250     /* delay for micro level label */
 
+/* often used screen positions */
+#define SX                     8
+#define SY                     8
+#define REAL_SX                        (SX - 2)
+#define REAL_SY                        (SY - 2)
+#define DX                     566
+#define DY                     60
+#define VX                     DX
+#define VY                     400
+#define EX                     DX
+#define EY                     (VY - 44)
+#define TILEX                  32
+#define TILEY                  32
+#define MINI_TILEX             (TILEX / 2)
+#define MINI_TILEY             (TILEY / 2)
+#define MICRO_TILEX            (TILEX / 8)
+#define MICRO_TILEY            (TILEY / 8)
+#define MIDPOSX                        (SCR_FIELDX / 2)
+#define MIDPOSY                        (SCR_FIELDY / 2)
+#define SXSIZE                 (SCR_FIELDX * TILEX)
+#define SYSIZE                 (SCR_FIELDY * TILEY)
+#define FXSIZE                 ((SCR_FIELDX + 2) * TILEX)
+#define FYSIZE                 ((SCR_FIELDY + 2) * TILEY)
+#define DXSIZE                 100
+#define DYSIZE                 280
+#define VXSIZE                 DXSIZE
+#define VYSIZE                 100
+#define EXSIZE                 DXSIZE
+#define EYSIZE                 (VYSIZE + 44)
+#define FULL_SXSIZE            (2 + SXSIZE + 2)
+#define FULL_SYSIZE            (2 + SYSIZE + 2)
+#define MICROLEV_XSIZE         ((STD_LEV_FIELDX + 2) * MICRO_TILEX)
+#define MICROLEV_YSIZE         ((STD_LEV_FIELDY + 2) * MICRO_TILEY)
+#define MICROLEV_XPOS          (SX + (SXSIZE - MICROLEV_XSIZE) / 2)
+#define MICROLEV_YPOS          (SX + 12 * TILEY - MICRO_TILEY)
+#define MICROLABEL_YPOS                (MICROLEV_YPOS + MICROLEV_YSIZE + 7)
+
+
+/* "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; mapped to EL_KEY_1 */
+#define EL_EMERALD                     6
+#define EL_EXIT_CLOSED                 7
+#define EL_PLAYER_OBSOLETE             8 /* obsolete; mapped to 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_UNUSED_63                   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               119
+
+#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                       207
+#define EL_EM_KEY_3_FILE                       208
+#define EL_EM_KEY_4_FILE                       209
+
+#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_UNUSED_254                  254
+#define EL_UNUSED_255                  255
+
+#define EL_PEARL                       256
+#define EL_CRYSTAL                     257
+#define EL_WALL_PEARL                  258
+#define EL_WALL_CRYSTAL                        259
+#define EL_DOOR_WHITE                  260
+#define EL_DOOR_WHITE_GRAY             261
+#define EL_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                    296
+#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_ONEWAY                 304
+#define EL_SIGN_HEART                  305
+#define EL_SIGN_TRIANGLE               306
+#define EL_SIGN_ROUND                  307
+#define EL_SIGN_EXIT                   308
+#define EL_SIGN_YINYANG                        309
+#define EL_SIGN_OTHER                  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_CUSTOM_START                        360
+
+#include "conf_cus.h"  /* include auto-generated data structure definitions */
+
+#define EL_CUSTOM_END                  (EL_CUSTOM_START + 127)
+
+#define NUM_CUSTOM_ELEMENTS            128
+#define NUM_FILE_ELEMENTS              488
+
+
+/* "real" (and therefore drawable) runtime elements */
+#define EL_FIRST_RUNTIME_REAL          NUM_FILE_ELEMENTS
+
+#define EL_EM_KEY_1                    (EL_FIRST_RUNTIME_REAL + 0)
+#define EL_EM_KEY_2                    (EL_FIRST_RUNTIME_REAL + 1)
+#define EL_EM_KEY_3                    (EL_FIRST_RUNTIME_REAL + 2)
+#define EL_EM_KEY_4                    (EL_FIRST_RUNTIME_REAL + 3)
+#define EL_DYNABOMB_PLAYER_1_ACTIVE    (EL_FIRST_RUNTIME_REAL + 4)
+#define EL_DYNABOMB_PLAYER_2_ACTIVE    (EL_FIRST_RUNTIME_REAL + 5)
+#define EL_DYNABOMB_PLAYER_3_ACTIVE    (EL_FIRST_RUNTIME_REAL + 6)
+#define EL_DYNABOMB_PLAYER_4_ACTIVE    (EL_FIRST_RUNTIME_REAL + 7)
+#define EL_SP_DISK_RED_ACTIVE          (EL_FIRST_RUNTIME_REAL + 8)
+#define EL_SWITCHGATE_OPENING          (EL_FIRST_RUNTIME_REAL + 9)
+#define EL_SWITCHGATE_CLOSING          (EL_FIRST_RUNTIME_REAL + 10)
+#define EL_TIMEGATE_OPENING            (EL_FIRST_RUNTIME_REAL + 11)
+#define EL_TIMEGATE_CLOSING            (EL_FIRST_RUNTIME_REAL + 12)
+#define EL_PEARL_BREAKING              (EL_FIRST_RUNTIME_REAL + 13)
+#define EL_TRAP_ACTIVE                 (EL_FIRST_RUNTIME_REAL + 14)
+#define EL_INVISIBLE_STEELWALL_ACTIVE  (EL_FIRST_RUNTIME_REAL + 15)
+#define EL_INVISIBLE_WALL_ACTIVE       (EL_FIRST_RUNTIME_REAL + 16)
+#define EL_INVISIBLE_SAND_ACTIVE       (EL_FIRST_RUNTIME_REAL + 17)
+#define EL_CONVEYOR_BELT_1_LEFT_ACTIVE  (EL_FIRST_RUNTIME_REAL + 18)
+#define EL_CONVEYOR_BELT_1_MIDDLE_ACTIVE (EL_FIRST_RUNTIME_REAL + 19)
+#define EL_CONVEYOR_BELT_1_RIGHT_ACTIVE         (EL_FIRST_RUNTIME_REAL + 20)
+#define EL_CONVEYOR_BELT_2_LEFT_ACTIVE  (EL_FIRST_RUNTIME_REAL + 21)
+#define EL_CONVEYOR_BELT_2_MIDDLE_ACTIVE (EL_FIRST_RUNTIME_REAL + 22)
+#define EL_CONVEYOR_BELT_2_RIGHT_ACTIVE         (EL_FIRST_RUNTIME_REAL + 23)
+#define EL_CONVEYOR_BELT_3_LEFT_ACTIVE  (EL_FIRST_RUNTIME_REAL + 24)
+#define EL_CONVEYOR_BELT_3_MIDDLE_ACTIVE (EL_FIRST_RUNTIME_REAL + 25)
+#define EL_CONVEYOR_BELT_3_RIGHT_ACTIVE         (EL_FIRST_RUNTIME_REAL + 26)
+#define EL_CONVEYOR_BELT_4_LEFT_ACTIVE  (EL_FIRST_RUNTIME_REAL + 27)
+#define EL_CONVEYOR_BELT_4_MIDDLE_ACTIVE (EL_FIRST_RUNTIME_REAL + 28)
+#define EL_CONVEYOR_BELT_4_RIGHT_ACTIVE         (EL_FIRST_RUNTIME_REAL + 29)
+#define EL_EXIT_OPENING                        (EL_FIRST_RUNTIME_REAL + 30)
+#define EL_SP_EXIT_OPEN                        (EL_FIRST_RUNTIME_REAL + 31)
+#define EL_SP_TERMINAL_ACTIVE          (EL_FIRST_RUNTIME_REAL + 32)
+#define EL_SP_BUGGY_BASE_ACTIVATING    (EL_FIRST_RUNTIME_REAL + 33)
+#define EL_SP_BUGGY_BASE_ACTIVE                (EL_FIRST_RUNTIME_REAL + 34)
+#define EL_SP_MURPHY_CLONE             (EL_FIRST_RUNTIME_REAL + 35)
+#define EL_AMOEBA_DROPPING             (EL_FIRST_RUNTIME_REAL + 36)
+#define EL_QUICKSAND_EMPTYING          (EL_FIRST_RUNTIME_REAL + 37)
+#define EL_MAGIC_WALL_ACTIVE           (EL_FIRST_RUNTIME_REAL + 38)
+#define EL_BD_MAGIC_WALL_ACTIVE                (EL_FIRST_RUNTIME_REAL + 39)
+#define EL_MAGIC_WALL_FULL             (EL_FIRST_RUNTIME_REAL + 40)
+#define EL_BD_MAGIC_WALL_FULL          (EL_FIRST_RUNTIME_REAL + 41)
+#define EL_MAGIC_WALL_EMPTYING         (EL_FIRST_RUNTIME_REAL + 42)
+#define EL_BD_MAGIC_WALL_EMPTYING      (EL_FIRST_RUNTIME_REAL + 43)
+#define EL_MAGIC_WALL_DEAD             (EL_FIRST_RUNTIME_REAL + 44)
+#define EL_BD_MAGIC_WALL_DEAD          (EL_FIRST_RUNTIME_REAL + 45)
+
+/* "unreal" (and therefore not drawable) runtime elements */
+#define EL_FIRST_RUNTIME_UNREAL                (EL_FIRST_RUNTIME_REAL + 46)
+
+#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_FLAMES                      (EL_FIRST_RUNTIME_UNREAL + 9)
+#define EL_PLAYER_IS_LEAVING           (EL_FIRST_RUNTIME_UNREAL + 10)
+#define EL_QUICKSAND_FILLING           (EL_FIRST_RUNTIME_UNREAL + 11)
+#define EL_MAGIC_WALL_FILLING          (EL_FIRST_RUNTIME_UNREAL + 12)
+#define EL_BD_MAGIC_WALL_FILLING       (EL_FIRST_RUNTIME_UNREAL + 13)
+
+/* dummy elements (never used as game elements, only used as graphics) */
+#define EL_FIRST_DUMMY                 (EL_FIRST_RUNTIME_UNREAL + 14)
+
+#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_DEFAULT                             (EL_FIRST_DUMMY + 20)
+#define EL_BD_DEFAULT                          (EL_FIRST_DUMMY + 21)
+#define EL_SP_DEFAULT                          (EL_FIRST_DUMMY + 22)
+#define EL_SB_DEFAULT                          (EL_FIRST_DUMMY + 23)
+
+#define MAX_NUM_ELEMENTS                       (EL_FIRST_DUMMY + 24)
+
+
+/* values for graphics/sounds action types */
+#define ACTION_DEFAULT                         0
+#define ACTION_WAITING                         1
+#define ACTION_FALLING                         2
+#define ACTION_MOVING                          3
+#define ACTION_DIGGING                         4
+#define ACTION_SNAPPING                                5
+#define ACTION_COLLECTING                      6
+#define ACTION_DROPPING                                7
+#define ACTION_PUSHING                         8
+#define ACTION_WALKING                         9
+#define ACTION_PASSING                         10
+#define ACTION_IMPACT                          11
+#define ACTION_BREAKING                                12
+#define ACTION_ACTIVATING                      13
+#define ACTION_DEACTIVATING                    14
+#define ACTION_OPENING                         15
+#define ACTION_CLOSING                         16
+#define ACTION_ATTACKING                       17
+#define ACTION_GROWING                         18
+#define ACTION_SHRINKING                       19
+#define ACTION_ACTIVE                          20
+#define ACTION_FILLING                         21
+#define ACTION_EMPTYING                                22
+#define ACTION_CHANGING                                23
+#define ACTION_EXPLODING                       24
+#define ACTION_DYING                           25
+#define ACTION_OTHER                           26
+
+#define NUM_ACTIONS                            27
+
+/* values for special image configuration suffixes (must match game mode) */
+#define GFX_SPECIAL_ARG_MAIN                   0
+#define GFX_SPECIAL_ARG_LEVELS                 1
+#define GFX_SPECIAL_ARG_SCORES                 2
+#define GFX_SPECIAL_ARG_EDITOR                 3
+#define GFX_SPECIAL_ARG_INFO                   4
+#define GFX_SPECIAL_ARG_SETUP                  5
+#define GFX_SPECIAL_ARG_DOOR                   6
+#define GFX_SPECIAL_ARG_PREVIEW                        7
+#define GFX_SPECIAL_ARG_CRUMBLED               8
+
+#define NUM_SPECIAL_GFX_ARGS                   9
+
+
+/* values for image configuration suffixes */
+#define GFX_ARG_X                              0
+#define GFX_ARG_Y                              1
+#define GFX_ARG_XPOS                           2
+#define GFX_ARG_YPOS                           3
+#define GFX_ARG_WIDTH                          4
+#define GFX_ARG_HEIGHT                         5
+#define GFX_ARG_OFFSET                         6
+#define GFX_ARG_VERTICAL                       7
+#define GFX_ARG_XOFFSET                                8
+#define GFX_ARG_YOFFSET                                9
+#define GFX_ARG_FRAMES                         10
+#define GFX_ARG_FRAMES_PER_LINE                        11
+#define GFX_ARG_START_FRAME                    12
+#define GFX_ARG_DELAY                          13
+#define GFX_ARG_ANIM_MODE                      14
+#define GFX_ARG_GLOBAL_SYNC                    15
+#define GFX_ARG_CRUMBLED_LIKE                  16
+#define GFX_ARG_DIGGABLE_LIKE                  17
+#define GFX_ARG_STEP_OFFSET                    18
+#define GFX_ARG_STEP_DELAY                     19
+#define GFX_ARG_DIRECTION                      20
+#define GFX_ARG_POSITION                       21
+#define GFX_ARG_DRAW_XOFFSET                   22
+#define GFX_ARG_DRAW_YOFFSET                   23
+#define GFX_ARG_NAME                           24
+
+#define NUM_GFX_ARGS                           25
+
+
+/* values for sound configuration suffixes */
+#define SND_ARG_MODE_LOOP                      0
+
+#define NUM_SND_ARGS                           1
+
+
+/* values for font configuration */
+
+#define FONT_INITIAL_1                         0
+#define FONT_INITIAL_2                         1
+#define FONT_INITIAL_3                         2
+#define FONT_INITIAL_4                         3
+#define FONT_TITLE_1                           4
+#define FONT_TITLE_2                           5
+#define FONT_MENU_1                            6
+#define FONT_MENU_2                            7
+#define FONT_TEXT_1_ACTIVE                     8
+#define FONT_TEXT_2_ACTIVE                     9
+#define FONT_TEXT_3_ACTIVE                     10
+#define FONT_TEXT_4_ACTIVE                     11
+#define FONT_TEXT_1                            12
+#define FONT_TEXT_2                            13
+#define FONT_TEXT_3                            14
+#define FONT_TEXT_4                            15
+#define FONT_INPUT_1_ACTIVE                    16
+#define FONT_INPUT_2_ACTIVE                    17
+#define FONT_INPUT_1                           18
+#define FONT_INPUT_2                           19
+#define FONT_OPTION_OFF                                20
+#define FONT_OPTION_ON                         21
+#define FONT_VALUE_1                           22
+#define FONT_VALUE_2                           23
+#define FONT_VALUE_OLD                         24
+#define FONT_LEVEL_NUMBER                      25
+#define FONT_TAPE_RECORDER                     26
+#define FONT_GAME_INFO                         27
+
+#define NUM_FONTS                              28
+#define NUM_INITIAL_FONTS                      4
+
+/* values for game_status (must match special image configuration suffixes) */
+#define GAME_MODE_MAIN                         0
+#define GAME_MODE_LEVELS                       1
+#define GAME_MODE_SCORES                       2
+#define GAME_MODE_EDITOR                       3
+#define GAME_MODE_INFO                         4
+#define GAME_MODE_SETUP                                5
+#define GAME_MODE_PSEUDO_DOOR                  6
+#define GAME_MODE_PSEUDO_PREVIEW               7
+#define GAME_MODE_PSEUDO_CRUMBLED              8
+
+/* there are no special config file suffixes for these modes */
+#define GAME_MODE_PLAYING                      9
+#define GAME_MODE_PSEUDO_TYPENAME              10
+#define GAME_MODE_QUIT                         11
+
+#define PROGRAM_VERSION_MAJOR  3
+#define PROGRAM_VERSION_MINOR  0
+#define PROGRAM_VERSION_PATCH  0
+#define PROGRAM_VERSION_RELEASE        0
+#define PROGRAM_VERSION_STRING "3.0.0"
+
+#define PROGRAM_TITLE_STRING   "Rocks'n'Diamonds"
+#define PROGRAM_AUTHOR_STRING  "Holger Schemel"
+#define PROGRAM_RIGHTS_STRING  "Copyright Â©1995-2003 by"
+#define PROGRAM_DOS_PORT_STRING        "DOS port done 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 COOKIE_PREFIX          "ROCKSNDIAMONDS"
+#define FILENAME_PREFIX                "Rocks"
+
+#if defined(PLATFORM_UNIX)
+#define USERDATA_DIRECTORY     ".rocksndiamonds"
+#elif defined(PLATFORM_WIN32)
+#define USERDATA_DIRECTORY     PROGRAM_TITLE_STRING
+#else
+#define USERDATA_DIRECTORY     "userdata"
+#endif
+
+#define X11_ICON_FILENAME      "rocks_icon.xbm"
+#define X11_ICONMASK_FILENAME  "rocks_iconmask.xbm"
+#define MSDOS_POINTER_FILENAME "mouse.pcx"
+
+/* file version numbers for resource files (levels, tapes, score, setup, etc.)
+** currently supported/known file version numbers:
+**     1.0 (old)
+**     1.2 (still in use)
+**     1.4 (still in use)
+**     2.0 (actual)
+*/
+#define FILE_VERSION_1_0       VERSION_IDENT(1,0,0)
+#define FILE_VERSION_1_2       VERSION_IDENT(1,2,0)
+#define FILE_VERSION_1_4       VERSION_IDENT(1,4,0)
+#define FILE_VERSION_2_0       VERSION_IDENT(2,0,0)
+
+/* file version does not change for every program version, but is changed
+   when new features are introduced that are incompatible with older file
+   versions, so that they can be treated accordingly */
+#define FILE_VERSION_ACTUAL    FILE_VERSION_2_0
+
+#define GAME_VERSION_1_0       FILE_VERSION_1_0
+#define GAME_VERSION_1_2       FILE_VERSION_1_2
+#define GAME_VERSION_1_4       FILE_VERSION_1_4
+#define GAME_VERSION_2_0       FILE_VERSION_2_0
+
+#define GAME_VERSION_ACTUAL    RELEASE_IDENT(PROGRAM_VERSION_MAJOR, \
+                                             PROGRAM_VERSION_MINOR, \
+                                             PROGRAM_VERSION_PATCH, \
+                                             PROGRAM_VERSION_RELEASE)
+
+/* values for game_emulation */
+#define EMU_NONE               0
+#define EMU_BOULDERDASH                1
+#define EMU_SOKOBAN            2
+#define EMU_SUPAPLEX           3
+
 struct HiScore
 {
   char Name[MAX_PLAYER_NAME_LEN + 1];
@@ -218,8 +1053,13 @@ struct PlayerInfo
                                   through doors); overrides other actions */
 
   int jx,jy, last_jx,last_jy;
-  int MovDir, MovPos, GfxPos;
-  int Frame;
+  int MovDir, MovPos, GfxDir, GfxPos;
+  int Frame, StepFrame;
+
+  int GfxAction;
+
+  boolean use_murphy_graphic;
+  boolean use_disk_red_graphic;
 
   boolean Pushing;
   boolean Switching;
@@ -227,7 +1067,10 @@ struct PlayerInfo
   boolean snapped;
 
   int last_move_dir;
-  int is_moving;
+  boolean is_moving;
+  boolean is_waiting;
+  boolean is_digging;
+  boolean is_collecting;
 
   unsigned long move_delay;
   int move_delay_value;
@@ -235,8 +1078,6 @@ struct PlayerInfo
   unsigned long push_delay;
   unsigned long push_delay_value;
 
-  int frame_reset_delay;
-
   unsigned long actual_frame_counter;
 
   int score;
@@ -247,8 +1088,8 @@ struct PlayerInfo
   int key[4];
   int dynamite;
   int dynabomb_count, dynabomb_size, dynabombs_left, dynabomb_xl;
-  int shield_passive_time_left;
-  int shield_active_time_left;
+  int shield_normal_time_left;
+  int shield_deadly_time_left;
 };
 
 struct LevelInfo
@@ -267,8 +1108,8 @@ struct LevelInfo
   char name[MAX_LEVEL_NAME_LEN + 1];
   char author[MAX_LEVEL_AUTHOR_LEN + 1];
   int score[LEVEL_SCORE_ELEMENTS];
-  int yam_content[MAX_ELEMENT_CONTENTS][3][3];
-  int num_yam_contents;
+  int yamyam_content[MAX_ELEMENT_CONTENTS][3][3];
+  int num_yamyam_contents;
   int amoeba_speed;
   int amoeba_content;
   int time_magic_wall;
@@ -278,6 +1119,12 @@ struct LevelInfo
   boolean double_speed;
   boolean gravity;
   boolean em_slippery_gems;    /* EM style "gems slip from wall" behaviour */
+
+  short field[MAX_LEV_FIELDX][MAX_LEV_FIELDY];
+
+  boolean use_custom_template; /* use custom properties from template file */
+
+  boolean no_level_file;
 };
 
 struct TapeInfo
@@ -286,6 +1133,7 @@ struct TapeInfo
   int game_version;    /* game release version the tape was created with */
   int engine_version;  /* game engine version the tape was recorded with */
 
+  char *level_identifier;
   int level_nr;
   unsigned long random_seed;
   unsigned long date;
@@ -297,6 +1145,8 @@ struct TapeInfo
   boolean recording, playing, pausing;
   boolean fast_forward;
   boolean index_search;
+  boolean auto_play;
+  boolean auto_play_level_solved;
   boolean quick_resume;
   boolean single_step;
   boolean changed;
@@ -319,7 +1169,7 @@ struct GameInfo
   int initial_move_delay_value;
 
   /* variable within running game */
-  int yam_content_nr;
+  int yamyam_content_nr;
   boolean magic_wall_active;
   int magic_wall_time_left;
   int light_time_left;
@@ -333,1359 +1183,276 @@ struct GameInfo
 
 struct GlobalInfo
 {
+  char *autoplay_leveldir;
+  int autoplay_level_nr;
+
+  int num_toons;
+
   float frames_per_second;
   boolean fps_slowdown;
   int fps_slowdown_factor;
 };
 
-struct ElementInfo
+struct MenuInfo
 {
-  char *sound_class_name;
-  char *editor_description;
+  int draw_xoffset_default;
+  int draw_yoffset_default;
+  int draw_xoffset[NUM_SPECIAL_GFX_ARGS];
+  int draw_yoffset[NUM_SPECIAL_GFX_ARGS];
+
+  int scrollbar_xoffset;
+
+  int list_size_default;
+  int list_size[NUM_SPECIAL_GFX_ARGS];
 };
 
-extern GC              tile_clip_gc;
-extern Bitmap         *pix[];
-extern Pixmap          tile_clipmask[];
-extern DrawBuffer      *fieldbuffer;
-extern DrawBuffer      *drawto_field;
-
-extern int             game_status;
-extern boolean         level_editor_test_game;
-extern boolean         network_playing;
-
-extern int             key_joystick_mapping;
-
-extern boolean         redraw[MAX_BUF_XSIZE][MAX_BUF_YSIZE];
-extern int             redraw_x1, redraw_y1;
-
-extern short           Feld[MAX_LEV_FIELDX][MAX_LEV_FIELDY];
-extern short           Ur[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           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           Frame[MAX_LEV_FIELDX][MAX_LEV_FIELDY];
-extern boolean         Stop[MAX_LEV_FIELDX][MAX_LEV_FIELDY];
-extern short           JustStopped[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           ExplodeField[MAX_LEV_FIELDX][MAX_LEV_FIELDY];
-extern unsigned long   Elementeigenschaften1[MAX_ELEMENTS];
-extern unsigned long   Elementeigenschaften2[MAX_ELEMENTS];
-
-extern int             lev_fieldx,lev_fieldy, scroll_x,scroll_y;
-
-extern int             FX,FY, ScrollStepSize;
-extern int             ScreenMovDir, ScreenMovPos, ScreenGfxPos;
-extern int             BorderElement;
-extern int             GameFrameDelay;
-extern int             FfwdFrameDelay;
-extern int             BX1,BY1, BX2,BY2;
-extern int             SBX_Left, SBX_Right;
-extern int             SBY_Upper, SBY_Lower;
-extern int             ZX,ZY, ExitX,ExitY;
-extern int             AllPlayersGone;
-
-extern int             TimeFrames, TimePlayed, TimeLeft;
-extern boolean         SiebAktiv;
-extern int             SiebCount;
-
-extern boolean         network_player_action_received;
-
-extern struct LevelInfo                level;
-extern struct PlayerInfo       stored_player[], *local_player;
-extern struct HiScore          highscore[];
-extern struct TapeInfo         tape;
-extern struct GameInfo         game;
-extern struct GlobalInfo       global;
-extern struct ElementInfo      element_info[];
-extern struct SoundEffectInfo  sound_effects[];
+struct DoorInfo
+{
+  int step_offset;
+  int step_delay;
+};
 
-/* often used screen positions */
-#define SX                     8
-#define SY                     8
-#define REAL_SX                        (SX - 2)
-#define REAL_SY                        (SY - 2)
-#define DX                     566
-#define DY                     60
-#define VX                     DX
-#define VY                     400
-#define EX                     DX
-#define EY                     (VY - 44)
-#define TILEX                  32
-#define TILEY                  32
-#define MINI_TILEX             (TILEX / 2)
-#define MINI_TILEY             (TILEY / 2)
-#define MICRO_TILEX            (TILEX / 8)
-#define MICRO_TILEY            (TILEY / 8)
-#define MIDPOSX                        (SCR_FIELDX / 2)
-#define MIDPOSY                        (SCR_FIELDY / 2)
-#define SXSIZE                 (SCR_FIELDX * TILEX)
-#define SYSIZE                 (SCR_FIELDY * TILEY)
-#define FXSIZE                 ((SCR_FIELDX + 2) * TILEX)
-#define FYSIZE                 ((SCR_FIELDY + 2) * TILEY)
-#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_XSIZE         ((STD_LEV_FIELDX + 2) * MICRO_TILEX)
-#define MICROLEV_YSIZE         ((STD_LEV_FIELDY + 2) * MICRO_TILEY)
-#define MICROLEV_XPOS          (SX + (SXSIZE - MICROLEV_XSIZE) / 2)
-#define MICROLEV_YPOS          (SX + 12 * TILEY - MICRO_TILEY)
-#define MICROLABEL_YPOS                (MICROLEV_YPOS + MICROLEV_YSIZE + 7)
+struct ElementChangeInfo
+{
+  unsigned long events;                /* bitfield for change events */
 
-#define GFX_STARTX             SX
-#define GFX_STARTY             SY
-#define MINI_GFX_STARTX                SX
-#define MINI_GFX_STARTY                424
-#define MICRO_GFX_STARTX       SX
-#define MICRO_GFX_STARTY       536
-#define GFX_PER_LINE           16
-#define MINI_GFX_PER_LINE      32
-#define MICRO_GFX_PER_LINE     128
-
-#define HEROES_PER_LINE                16
-
-#define MINI_SP_STARTX         0
-#define MINI_SP_STARTY         352
-#define MICRO_SP_STARTX                0
-#define MICRO_SP_STARTY                448
-#define SP_PER_LINE            16
-#define MINI_SP_PER_LINE       16
-#define MICRO_SP_PER_LINE      64
-
-#define MINI_DC_STARTX         256
-#define MINI_DC_STARTY         256
-#define MICRO_DC_STARTX                384
-#define MICRO_DC_STARTY                384
-#define DC_PER_LINE            16
-#define MINI_DC_PER_LINE       16
-#define MICRO_DC_PER_LINE      16
-
-#define MINI_MORE_STARTX       256
-#define MINI_MORE_STARTY       256
-#define MICRO_MORE_STARTX      384
-#define MICRO_MORE_STARTY      384
-#define MORE_PER_LINE          16
-#define MINI_MORE_PER_LINE     16
-#define MICRO_MORE_PER_LINE    16
-
-/* game elements:
-**       0 - 499: real elements, stored in level file
-**      500 - 699: flag elements, only used at runtime
-*/
-/* "real" level elements */
-#define EL_LEERRAUM            0
-#define        EL_ERDREICH             1
-#define        EL_MAUERWERK            2
-#define        EL_FELSBODEN            3
-#define        EL_FELSBROCKEN          4
-#define        EL_SCHLUESSEL           5
-#define        EL_EDELSTEIN            6
-#define        EL_AUSGANG_ZU           7
-#define        EL_SPIELFIGUR           8
-#define EL_KAEFER              9
-#define EL_FLIEGER             10
-#define EL_MAMPFER             11
-#define EL_ROBOT               12
-#define EL_BETON               13
-#define EL_DIAMANT             14
-#define EL_AMOEBE_TOT          15
-#define EL_MORAST_LEER         16
-#define EL_MORAST_VOLL         17
-#define EL_TROPFEN             18
-#define EL_BOMBE               19
-#define EL_MAGIC_WALL_OFF      20
-#define EL_SPEED_PILL          21
-#define EL_SALZSAEURE          22
-#define EL_AMOEBE_NASS         23
-#define EL_AMOEBE_NORM         24
-#define EL_KOKOSNUSS           25
-#define EL_LIFE                        26
-#define EL_LIFE_ASYNC          27
-#define EL_DYNAMITE_ACTIVE     28
-#define EL_BADEWANNE           29
-#define EL_ABLENK_AUS          30
-#define EL_ABLENK_EIN          31
-#define EL_SCHLUESSEL1         32
-#define EL_SCHLUESSEL2         33
-#define EL_SCHLUESSEL3         34
-#define EL_SCHLUESSEL4         35
-#define EL_PFORTE1             36
-#define EL_PFORTE2             37
-#define EL_PFORTE3             38
-#define EL_PFORTE4             39
-#define EL_PFORTE1X            40
-#define EL_PFORTE2X            41
-#define EL_PFORTE3X            42
-#define EL_PFORTE4X            43
-#define EL_DYNAMITE_INACTIVE   44
-#define EL_PACMAN              45
-#define EL_UNSICHTBAR          46
-#define EL_BIRNE_AUS           47
-#define EL_BIRNE_EIN           48
-#define EL_ERZ_EDEL            49
-#define EL_ERZ_DIAM            50
-#define EL_AMOEBE_VOLL         51
-#define EL_AMOEBE_BD           52
-#define EL_ZEIT_VOLL           53
-#define EL_ZEIT_LEER           54
-#define EL_MAUER_LEBT          55
-#define EL_EDELSTEIN_BD                56
-#define EL_EDELSTEIN_GELB      57
-#define EL_ERZ_EDEL_BD         58
-#define EL_ERZ_EDEL_GELB       59
-#define EL_MAMPFER2            60
-#define EL_MAGIC_WALL_BD_OFF   61
-#define EL_INVISIBLE_STEEL     62
-
-#define EL_UNUSED_63           63
-
-#define EL_DYNABOMB_NR         64
-#define EL_DYNABOMB_SZ         65
-#define EL_DYNABOMB_XL         66
-#define EL_SOKOBAN_OBJEKT      67
-#define EL_SOKOBAN_FELD_LEER   68
-#define EL_SOKOBAN_FELD_VOLL   69
-#define EL_BUTTERFLY_RIGHT     70
-#define EL_BUTTERFLY_UP                71
-#define EL_BUTTERFLY_LEFT      72
-#define EL_BUTTERFLY_DOWN      73
-#define EL_FIREFLY_RIGHT       74
-#define EL_FIREFLY_UP          75
-#define EL_FIREFLY_LEFT                76
-#define EL_FIREFLY_DOWN                77
-#define EL_BUTTERFLY_1         EL_BUTTERFLY_DOWN
-#define EL_BUTTERFLY_2         EL_BUTTERFLY_LEFT
-#define EL_BUTTERFLY_3         EL_BUTTERFLY_UP
-#define EL_BUTTERFLY_4         EL_BUTTERFLY_RIGHT
-#define EL_FIREFLY_1           EL_FIREFLY_LEFT
-#define EL_FIREFLY_2           EL_FIREFLY_DOWN
-#define EL_FIREFLY_3           EL_FIREFLY_RIGHT
-#define EL_FIREFLY_4           EL_FIREFLY_UP
-#define EL_BUTTERFLY           78
-#define EL_FIREFLY             79
-#define EL_SPIELER1            80
-#define EL_SPIELER2            81
-#define EL_SPIELER3            82
-#define EL_SPIELER4            83
-#define EL_KAEFER_RIGHT                84
-#define EL_KAEFER_UP           85
-#define EL_KAEFER_LEFT         86
-#define EL_KAEFER_DOWN         87
-#define EL_FLIEGER_RIGHT       88
-#define EL_FLIEGER_UP          89
-#define EL_FLIEGER_LEFT                90
-#define EL_FLIEGER_DOWN                91
-#define EL_PACMAN_RIGHT                92
-#define EL_PACMAN_UP           93
-#define EL_PACMAN_LEFT         94
-#define EL_PACMAN_DOWN         95
-#define EL_EDELSTEIN_ROT       96
-#define EL_EDELSTEIN_LILA      97
-#define EL_ERZ_EDEL_ROT                98
-#define EL_ERZ_EDEL_LILA       99
-#define EL_BADEWANNE1          100
-#define EL_BADEWANNE2          101
-#define EL_BADEWANNE3          102
-#define EL_BADEWANNE4          103
-#define EL_BADEWANNE5          104
-#define EL_BD_WALL             105
-#define EL_BD_ROCK             106
-#define EL_AUSGANG_AUF         107
-#define EL_BLACK_ORB           108
-#define EL_AMOEBA2DIAM         109
-#define EL_MOLE                        110
-#define EL_PINGUIN             111
-#define EL_SONDE               112
-#define EL_PFEIL_LEFT          113
-#define EL_PFEIL_RIGHT         114
-#define EL_PFEIL_UP            115
-#define EL_PFEIL_DOWN          116
-#define EL_SCHWEIN             117
-#define EL_DRACHE              118
-
-#define EL_EM_KEY_1_FILE       119
-
-#define EL_CHAR_START          120
-#define EL_CHAR_ASCII0         (EL_CHAR_START-32)
-#define EL_CHAR_AUSRUF         (EL_CHAR_ASCII0+33)
-#define EL_CHAR_ZOLL           (EL_CHAR_ASCII0+34)
-#define EL_CHAR_RAUTE          (EL_CHAR_ASCII0+35)
-#define EL_CHAR_DOLLAR         (EL_CHAR_ASCII0+36)
-#define EL_CHAR_PROZ           (EL_CHAR_ASCII0+37)
-#define EL_CHAR_AMPERSAND      (EL_CHAR_ASCII0+38)
-#define EL_CHAR_APOSTR         (EL_CHAR_ASCII0+39)
-#define EL_CHAR_KLAMM1         (EL_CHAR_ASCII0+40)
-#define EL_CHAR_KLAMM2         (EL_CHAR_ASCII0+41)
-#define EL_CHAR_MULT           (EL_CHAR_ASCII0+42)
-#define EL_CHAR_PLUS           (EL_CHAR_ASCII0+43)
-#define EL_CHAR_KOMMA          (EL_CHAR_ASCII0+44)
-#define EL_CHAR_MINUS          (EL_CHAR_ASCII0+45)
-#define EL_CHAR_PUNKT          (EL_CHAR_ASCII0+46)
-#define EL_CHAR_SLASH          (EL_CHAR_ASCII0+47)
-#define EL_CHAR_0              (EL_CHAR_ASCII0+48)
-#define EL_CHAR_9              (EL_CHAR_ASCII0+57)
-#define EL_CHAR_DOPPEL         (EL_CHAR_ASCII0+58)
-#define EL_CHAR_SEMIKL         (EL_CHAR_ASCII0+59)
-#define EL_CHAR_LT             (EL_CHAR_ASCII0+60)
-#define EL_CHAR_GLEICH         (EL_CHAR_ASCII0+61)
-#define EL_CHAR_GT             (EL_CHAR_ASCII0+62)
-#define EL_CHAR_FRAGE          (EL_CHAR_ASCII0+63)
-#define EL_CHAR_AT             (EL_CHAR_ASCII0+64)
-#define EL_CHAR_A              (EL_CHAR_ASCII0+65)
-#define EL_CHAR_Z              (EL_CHAR_ASCII0+90)
-#define EL_CHAR_AE             (EL_CHAR_ASCII0+91)
-#define EL_CHAR_OE             (EL_CHAR_ASCII0+92)
-#define EL_CHAR_UE             (EL_CHAR_ASCII0+93)
-#define EL_CHAR_COPY           (EL_CHAR_ASCII0+94)
-#define EL_CHAR_END            (EL_CHAR_START+79)
-
-#define EL_CHAR(x)             ((x) == 'Ä' ? EL_CHAR_AE : \
-                                (x) == 'Ö' ? EL_CHAR_OE : \
-                                (x) == 'Ãœ' ? EL_CHAR_UE : \
-                                EL_CHAR_A + (x) - 'A')
-
-#define EL_MAUER_X             200
-#define EL_MAUER_Y             201
-#define EL_MAUER_XY            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       207
-#define EL_EM_KEY_3_FILE       208
-#define EL_EM_KEY_4_FILE       209
-
-#define EL_SP_START            210
-#define EL_SP_EMPTY            (EL_SP_START + 0)
-#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_HARD_GRAY                (EL_SP_START + 6)
-#define EL_SP_EXIT             (EL_SP_START + 7)
-#define EL_SP_DISK_ORANGE      (EL_SP_START + 8)
-#define EL_SP_PORT1_RIGHT      (EL_SP_START + 9)
-#define EL_SP_PORT1_DOWN       (EL_SP_START + 10)
-#define EL_SP_PORT1_LEFT       (EL_SP_START + 11)
-#define EL_SP_PORT1_UP         (EL_SP_START + 12)
-#define EL_SP_PORT2_RIGHT      (EL_SP_START + 13)
-#define EL_SP_PORT2_DOWN       (EL_SP_START + 14)
-#define EL_SP_PORT2_LEFT       (EL_SP_START + 15)
-#define EL_SP_PORT2_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_Y           (EL_SP_START + 21)
-#define EL_SP_PORT_X           (EL_SP_START + 22)
-#define EL_SP_PORT_XY          (EL_SP_START + 23)
-#define EL_SP_ELECTRON         (EL_SP_START + 24)
-#define EL_SP_BUG              (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_HARD_BASE1       (EL_SP_START + 28)
-#define EL_SP_HARD_GREEN       (EL_SP_START + 29)
-#define EL_SP_HARD_BLUE                (EL_SP_START + 30)
-#define EL_SP_HARD_RED         (EL_SP_START + 31)
-#define EL_SP_HARD_YELLOW      (EL_SP_START + 32)
-#define EL_SP_HARD_BASE2       (EL_SP_START + 33)
-#define EL_SP_HARD_BASE3       (EL_SP_START + 34)
-#define EL_SP_HARD_BASE4       (EL_SP_START + 35)
-#define EL_SP_HARD_BASE5       (EL_SP_START + 36)
-#define EL_SP_HARD_BASE6       (EL_SP_START + 37)
-#define EL_SP_CHIP_UPPER       (EL_SP_START + 38)
-#define EL_SP_CHIP_LOWER       (EL_SP_START + 39)
-#define EL_SP_END              (EL_SP_START + 39)
-
-#define EL_EM_GATE_1X          250
-#define EL_EM_GATE_2X          251
-#define EL_EM_GATE_3X          252
-#define EL_EM_GATE_4X          253
-
-#define EL_UNUSED_254          254
-#define EL_UNUSED_255          255
-
-#define EL_PEARL               256
-#define EL_CRYSTAL             257
-#define EL_WALL_PEARL          258
-#define EL_WALL_CRYSTAL                259
-#define EL_DOOR_WHITE          260
-#define EL_DOOR_WHITE_GRAY     261
-#define EL_KEY_WHITE           262
-#define EL_SHIELD_PASSIVE      263
-#define EL_EXTRA_TIME          264
-#define EL_SWITCHGATE_OPEN     265
-#define EL_SWITCHGATE_CLOSED   266
-#define EL_SWITCHGATE_SWITCH_1 267
-#define EL_SWITCHGATE_SWITCH_2 268
-
-#define EL_UNUSED_269          269
-#define EL_UNUSED_270          270
-
-#define EL_BELT1_LEFT          271
-#define EL_BELT1_MIDDLE                272
-#define EL_BELT1_RIGHT         273
-#define EL_BELT1_SWITCH_LEFT   274
-#define EL_BELT1_SWITCH_MIDDLE 275
-#define EL_BELT1_SWITCH_RIGHT  276
-#define EL_BELT2_LEFT          277
-#define EL_BELT2_MIDDLE                278
-#define EL_BELT2_RIGHT         279
-#define EL_BELT2_SWITCH_LEFT   280
-#define EL_BELT2_SWITCH_MIDDLE 281
-#define EL_BELT2_SWITCH_RIGHT  282
-#define EL_BELT3_LEFT          283
-#define EL_BELT3_MIDDLE                284
-#define EL_BELT3_RIGHT         285
-#define EL_BELT3_SWITCH_LEFT   286
-#define EL_BELT3_SWITCH_MIDDLE 287
-#define EL_BELT3_SWITCH_RIGHT  288
-#define EL_BELT4_LEFT          289
-#define EL_BELT4_MIDDLE                290
-#define EL_BELT4_RIGHT         291
-#define EL_BELT4_SWITCH_LEFT   292
-#define EL_BELT4_SWITCH_MIDDLE 293
-#define EL_BELT4_SWITCH_RIGHT  294
-#define EL_LANDMINE            295
-#define EL_ENVELOPE            296
-#define EL_LIGHT_SWITCH_OFF    297
-#define EL_LIGHT_SWITCH_ON     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_ONEWAY         304
-#define EL_SIGN_HEART          305
-#define EL_SIGN_TRIANGLE       306
-#define EL_SIGN_ROUND          307
-#define EL_SIGN_EXIT           308
-#define EL_SIGN_YINYANG                309
-#define EL_SIGN_OTHER          310
-#define EL_MOLE_LEFT           311
-#define EL_MOLE_RIGHT          312
-#define EL_MOLE_UP             313
-#define EL_MOLE_DOWN           314
-#define EL_STEEL_SLANTED       315
-#define EL_SAND_INVISIBLE      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_ACTIVE       321
-#define EL_TIMEGATE_OPEN       322
-#define EL_TIMEGATE_CLOSED     323
-#define EL_TIMEGATE_SWITCH_ON  324
-#define EL_TIMEGATE_SWITCH_OFF 325
-
-#define EL_BALLOON             326
-#define EL_BALLOON_SEND_LEFT   327
-#define EL_BALLOON_SEND_RIGHT  328
-#define EL_BALLOON_SEND_UP     329
-#define EL_BALLOON_SEND_DOWN   330
-#define EL_BALLOON_SEND_ANY    331
-
-#define EL_EMC_STEEL_WALL_1    332
-#define EL_EMC_STEEL_WALL_2    333
-#define EL_EMC_STEEL_WALL_3    334
-#define EL_EMC_STEEL_WALL_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_CROSS          344
-#define EL_TUBE_VERTICAL       345
-#define EL_TUBE_HORIZONTAL     346
-#define EL_TUBE_VERT_LEFT      347
-#define EL_TUBE_VERT_RIGHT     348
-#define EL_TUBE_HORIZ_UP       349
-#define EL_TUBE_HORIZ_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_INACTIVE       356
-#define EL_DX_SUPABOMB         357
-
-#define NUM_LEVEL_ELEMENTS     358
+  short 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) */
 
-/* "real" (and therefore drawable) runtime elements */
-#define EL_FIRST_RUNTIME_EL    500
-
-#define EL_MAGIC_WALL_EMPTY    500
-#define EL_MAGIC_WALL_BD_EMPTY 501
-#define EL_MAGIC_WALL_FULL     502
-#define EL_MAGIC_WALL_BD_FULL  503
-#define EL_MAGIC_WALL_DEAD     504
-#define EL_MAGIC_WALL_BD_DEAD  505
-#define EL_AUSGANG_ACT         506
-#define EL_SP_TERMINAL_ACTIVE  507
-#define EL_SP_BUG_ACTIVE       508
-#define EL_EM_KEY_1            509
-#define EL_EM_KEY_2            510
-#define EL_EM_KEY_3            511
-#define EL_EM_KEY_4            512
-#define EL_DYNABOMB_ACTIVE_1   513
-#define EL_DYNABOMB_ACTIVE_2   514
-#define EL_DYNABOMB_ACTIVE_3   515
-#define EL_DYNABOMB_ACTIVE_4   516
-#define EL_SWITCHGATE_OPENING  517
-#define EL_SWITCHGATE_CLOSING  518
-#define EL_TIMEGATE_OPENING    519
-#define EL_TIMEGATE_CLOSING    520
-#define EL_PEARL_BREAKING      521
-#define EL_TRAP_ACTIVE         522
-#define EL_SPRING_MOVING       523
-#define EL_SP_MURPHY_CLONE     524
-#define EL_QUICKSAND_EMPTYING  525
-#define EL_MAGIC_WALL_EMPTYING 526
-#define EL_MAGIC_WALL_BD_EMPTYING 527
-#define EL_AMOEBA_DRIPPING     528
+  short trigger_element;       /* custom element triggering change */
 
-/* "unreal" (and therefore not drawable) runtime elements */
-#define EL_BLOCKED             600
-#define EL_EXPLODING           601
-#define EL_CRACKINGNUT         602
-#define EL_BLURB_LEFT          603
-#define EL_BLURB_RIGHT         604
-#define EL_AMOEBING            605
-#define EL_DEAMOEBING          606
-#define EL_MAUERND             607
-#define EL_BURNING             608
-#define EL_PLAYER_IS_LEAVING   609
-#define EL_QUICKSAND_FILLING   610
-#define EL_MAGIC_WALL_FILLING  611
-#define EL_MAGIC_WALL_BD_FILLING 612
-
-/* game graphics:
-**       0 -  255: graphics from "RocksScreen"
-**     256 -  511: graphics from "RocksFont"
-**     512 -  767: graphics from "RocksHeroes"
-**     768 - 1023: graphics from "RocksSP"
-**     1024 - 1279: graphics from "RocksDC"
-**     1280 - 1535: graphics from "RocksMore"
-*/
+  int content[3][3];           /* new elements after extended change */
+  boolean use_content;         /* use extended change content */
+  boolean only_complete;       /* only use complete content */
+  boolean use_random_change;   /* use random value for setting content */
+  int random;                  /* random value for setting content */
+  int power;                   /* power of extended change */
 
-#define GFX_START_ROCKSSCREEN  0
-#define GFX_END_ROCKSSCREEN    255
-#define GFX_START_ROCKSFONT    256
-#define GFX_END_ROCKSFONT      511
-#define GFX_START_ROCKSHEROES  512
-#define GFX_END_ROCKSHEROES    767
-#define GFX_START_ROCKSSP      768
-#define GFX_END_ROCKSSP                1023
-#define GFX_START_ROCKSDC      1024
-#define GFX_END_ROCKSDC                1279
-#define GFX_START_ROCKSMORE    1280
-#define GFX_END_ROCKSMORE      1535
-
-#define NUM_TILES              1536
-
-/* graphics from "RocksScreen" */
-/* Zeile 0 (0) */
-#define GFX_LEERRAUM           (-1)
-#define        GFX_ERDREICH            0
-#define GFX_ERDENRAND          1
-#define GFX_MORAST_LEER                2
-#define GFX_MORAST_VOLL                3
-#define GFX_BETON              4
-#define        GFX_MAUERWERK           5
-#define        GFX_FELSBODEN           6
-#define        GFX_EDELSTEIN           8
-#define GFX_DIAMANT            10
-#define        GFX_FELSBROCKEN         12
-/* Zeile 1 (16) */
-#define GFX_BADEWANNE1         16
-#define GFX_SALZSAEURE         17
-#define GFX_BADEWANNE2         18
-
-/*
-#define GFX_UNSICHTBAR         19
-*/
+  boolean explode;             /* explode instead of change */
 
-#define GFX_SCHLUESSEL1                20
-#define GFX_SCHLUESSEL2                21
-#define GFX_SCHLUESSEL3                22
-#define GFX_SCHLUESSEL4                23
-#define GFX_LIFE               24
-#define GFX_LIFE_ASYNC         25
-#define GFX_BADEWANNE          26
-#define GFX_BOMBE              27
-#define GFX_KOKOSNUSS          28
-#define GFX_CRACKINGNUT                29
-/* Zeile 2 (32) */
-#define GFX_BADEWANNE3         32
-#define GFX_BADEWANNE4         33
-#define GFX_BADEWANNE5         34
-#define        GFX_SMILEY              35
-#define GFX_PFORTE1            36
-#define GFX_PFORTE2            37
-#define GFX_PFORTE3            38
-#define GFX_PFORTE4            39
-#define GFX_PFORTE1X           40
-#define GFX_PFORTE2X           41
-#define GFX_PFORTE3X           42
-#define GFX_PFORTE4X           43
-/* Zeile 3 (48) */
-#define GFX_DYNAMIT_AUS                48
-#define GFX_DYNAMIT            49
-#define GFX_FLIEGER            56
-#define GFX_FLIEGER_RIGHT      56
-#define GFX_FLIEGER_UP         57
-#define GFX_FLIEGER_LEFT       58
-#define GFX_FLIEGER_DOWN       59
-/* Zeile 4 (64) */
-#define GFX_EXPLOSION          64
-#define GFX_KAEFER             72
-#define GFX_KAEFER_RIGHT       72
-#define GFX_KAEFER_UP          73
-#define GFX_KAEFER_LEFT                74
-#define GFX_KAEFER_DOWN                75
-/* Zeile 5 (80) */
-#define GFX_MAMPFER            80
-#define GFX_ROBOT              84
-#define GFX_PACMAN             88
-#define GFX_PACMAN_RIGHT       88
-#define GFX_PACMAN_UP          89
-#define GFX_PACMAN_LEFT                90
-#define GFX_PACMAN_DOWN                91
-/* Zeile 6 (96) */
-#define GFX_ABLENK             96
-#define GFX_ABLENK_EIN         GFX_ABLENK
-#define GFX_ABLENK_AUS         GFX_ABLENK
-#define GFX_AMOEBE_NASS                100
-#define GFX_TROPFEN            101
-#define GFX_AMOEBING           GFX_TROPFEN
-#define GFX_AMOEBE_LEBT                104
-#define GFX_AMOEBE_NORM                GFX_AMOEBE_LEBT
-#define GFX_AMOEBE_TOT         108
-#define GFX_AMOEBA2DIAM                GFX_AMOEBE_TOT
-/* Zeile 7 (112) */
-#define GFX_BIRNE_AUS          112
-#define GFX_BIRNE_EIN          113
-#define GFX_ZEIT_VOLL          114
-#define GFX_ZEIT_LEER          115
-#define GFX_SPIELER1           116
-#define GFX_SPIELER2           117
-#define GFX_SPIELER3           118
-#define GFX_SPIELER4           119
-#define GFX_AMOEBE_VOLL                120
-#define GFX_AMOEBE_BD          GFX_AMOEBE_VOLL
-#define GFX_SOKOBAN_OBJEKT     121
-#define GFX_SOKOBAN_FELD_LEER  122
-#define GFX_SOKOBAN_FELD_VOLL  123
-#define GFX_GEBLUBBER          124
-/* Zeile 8 (128) */
-#define GFX_MAGIC_WALL_OFF     128
-#define GFX_MAGIC_WALL_EMPTY   GFX_MAGIC_WALL_OFF
-#define GFX_MAGIC_WALL_FULL    GFX_MAGIC_WALL_OFF
-#define GFX_MAGIC_WALL_DEAD    GFX_MAGIC_WALL_OFF
-#define GFX_ERZ_EDEL           132
-#define GFX_ERZ_DIAM           133
-#define GFX_ERZ_EDEL_ROT       134
-#define GFX_ERZ_EDEL_LILA      135
-#define GFX_ERZ_EDEL_GELB      136
-#define GFX_ERZ_EDEL_BD                137
-#define GFX_EDELSTEIN_GELB     138
-#define GFX_KUGEL_ROT          140
-#define GFX_KUGEL_BLAU         141
-#define GFX_KUGEL_GELB         142
-#define GFX_KUGEL_GRAU         143
-/* Zeile 9 (144) */
-#define GFX_PINGUIN            144
-#define GFX_MOLE               145
-#define GFX_SCHWEIN            146
-#define GFX_DRACHE             147
-#define GFX_MAUER_XY           148
-#define GFX_MAUER_X            149
-#define GFX_MAUER_Y            150
-#define GFX_EDELSTEIN_ROT      152
-#define GFX_EDELSTEIN_LILA     154
-#define GFX_DYNABOMB_XL                156
-#define GFX_BLACK_ORB          157
-#define GFX_SPEED_PILL         158
-#define GFX_SONDE              159
-/* Zeile 10 (160) */
-#define GFX_EDELSTEIN_BD       163
-#define GFX_MAUER_RIGHT                165
-#define GFX_MAUER_R1           GFX_MAUER_RIGHT
-#define GFX_MAUER_R            167
-#define GFX_MAUER_LEFT         168
-#define GFX_MAUER_L1           GFX_MAUER_LEFT
-#define GFX_MAUER_L            170
-#define GFX_MAUER_LEBT         171
-#define GFX_MAGIC_WALL_BD_OFF  172
-#define GFX_MAGIC_WALL_BD_EMPTY        GFX_MAGIC_WALL_BD_OFF
-#define GFX_MAGIC_WALL_BD_FULL GFX_MAGIC_WALL_BD_OFF
-#define GFX_MAGIC_WALL_BD_DEAD GFX_MAGIC_WALL_BD_OFF
-/* Zeile 11 (176) */
-#define        GFX_AUSGANG_ZU          176
-#define        GFX_AUSGANG_ACT         177
-#define        GFX_AUSGANG_AUF         180
-#define GFX_MAMPFER2           184
-#define GFX_DYNABOMB           188
-#define GFX_DYNABOMB_NR                188
-#define GFX_DYNABOMB_SZ                191
-/* Zeile 12 (192) */
-#define GFX_PFEIL_LEFT         192
-#define GFX_PFEIL_RIGHT                193
-#define GFX_PFEIL_UP           194
-#define GFX_PFEIL_DOWN         195
-#define GFX_BUTTERFLY          196
-#define GFX_FIREFLY            198
-#define GFX_BUTTERFLY_RIGHT    200
-#define GFX_BUTTERFLY_UP       201
-#define GFX_BUTTERFLY_LEFT     202
-#define GFX_BUTTERFLY_DOWN     203
-#define GFX_FIREFLY_RIGHT      204
-#define GFX_FIREFLY_UP         205
-#define GFX_FIREFLY_LEFT       206
-#define GFX_FIREFLY_DOWN       207
-
-/* only available as size MINI_TILE */
-#define GFX_VSTEEL_UPPER_LEFT  208
-#define GFX_VSTEEL_UPPER_RIGHT 209
-#define GFX_VSTEEL_LOWER_LEFT  210
-#define GFX_VSTEEL_LOWER_RIGHT 211
-#define GFX_VSTEEL_HORIZONTAL  212
-#define GFX_VSTEEL_VERTICAL    213
-#define GFX_ISTEEL_UPPER_LEFT  214
-#define GFX_ISTEEL_UPPER_RIGHT 215
-#define GFX_ISTEEL_LOWER_LEFT  216
-#define GFX_ISTEEL_LOWER_RIGHT 217
-#define GFX_ISTEEL_HORIZONTAL  218
-#define GFX_ISTEEL_VERTICAL    219
-
-/* elements with graphics borrowed from other elements */
-#define GFX_SCHLUESSEL         GFX_SCHLUESSEL1
-#define GFX_SPIELFIGUR         GFX_SPIELER1
-
-/* graphics from "RocksHeroes" */
-#define GFX_SPIELER1_DOWN      (GFX_START_ROCKSHEROES + 0*HEROES_PER_LINE + 0)
-#define GFX_SPIELER1_UP                (GFX_START_ROCKSHEROES + 0*HEROES_PER_LINE + 4)
-#define GFX_SPIELER1_LEFT      (GFX_START_ROCKSHEROES + 1*HEROES_PER_LINE + 0)
-#define GFX_SPIELER1_RIGHT     (GFX_START_ROCKSHEROES + 1*HEROES_PER_LINE + 4)
-#define GFX_SPIELER1_PUSH_RIGHT        (GFX_START_ROCKSHEROES + 2*HEROES_PER_LINE + 0)
-#define GFX_SPIELER1_PUSH_LEFT (GFX_START_ROCKSHEROES + 2*HEROES_PER_LINE + 4)
-#define GFX_SPIELER2_DOWN      (GFX_START_ROCKSHEROES + 3*HEROES_PER_LINE + 0)
-#define GFX_SPIELER2_UP                (GFX_START_ROCKSHEROES + 3*HEROES_PER_LINE + 4)
-#define GFX_SPIELER2_LEFT      (GFX_START_ROCKSHEROES + 4*HEROES_PER_LINE + 0)
-#define GFX_SPIELER2_RIGHT     (GFX_START_ROCKSHEROES + 4*HEROES_PER_LINE + 4)
-#define GFX_SPIELER2_PUSH_RIGHT        (GFX_START_ROCKSHEROES + 5*HEROES_PER_LINE + 0)
-#define GFX_SPIELER2_PUSH_LEFT (GFX_START_ROCKSHEROES + 5*HEROES_PER_LINE + 4)
-#define GFX_SPIELER3_DOWN      (GFX_START_ROCKSHEROES + 6*HEROES_PER_LINE + 0)
-#define GFX_SPIELER3_UP                (GFX_START_ROCKSHEROES + 6*HEROES_PER_LINE + 4)
-#define GFX_SPIELER3_LEFT      (GFX_START_ROCKSHEROES + 7*HEROES_PER_LINE + 0)
-#define GFX_SPIELER3_RIGHT     (GFX_START_ROCKSHEROES + 7*HEROES_PER_LINE + 4)
-#define GFX_SPIELER3_PUSH_RIGHT        (GFX_START_ROCKSHEROES + 8*HEROES_PER_LINE + 0)
-#define GFX_SPIELER3_PUSH_LEFT (GFX_START_ROCKSHEROES + 8*HEROES_PER_LINE + 4)
-#define GFX_SPIELER4_DOWN      (GFX_START_ROCKSHEROES + 9*HEROES_PER_LINE + 0)
-#define GFX_SPIELER4_UP                (GFX_START_ROCKSHEROES + 9*HEROES_PER_LINE + 4)
-#define GFX_SPIELER4_LEFT      (GFX_START_ROCKSHEROES +10*HEROES_PER_LINE + 0)
-#define GFX_SPIELER4_RIGHT     (GFX_START_ROCKSHEROES +10*HEROES_PER_LINE + 4)
-#define GFX_SPIELER4_PUSH_RIGHT        (GFX_START_ROCKSHEROES +11*HEROES_PER_LINE + 0)
-#define GFX_SPIELER4_PUSH_LEFT (GFX_START_ROCKSHEROES +11*HEROES_PER_LINE + 4)
-#define GFX_MAUER_DOWN         (GFX_START_ROCKSHEROES +12*HEROES_PER_LINE + 0)
-#define GFX_MAUER_UP           (GFX_START_ROCKSHEROES +12*HEROES_PER_LINE + 3)
-#define GFX2_SHIELD_PASSIVE    (GFX_START_ROCKSHEROES +13*HEROES_PER_LINE + 1)
-#define GFX2_SHIELD_ACTIVE     (GFX_START_ROCKSHEROES +13*HEROES_PER_LINE + 5)
-
-#define GFX_SONDE_START                (GFX_START_ROCKSHEROES + 9*HEROES_PER_LINE + 8)
-#define GFX_SCHWEIN_DOWN       (GFX_START_ROCKSHEROES + 0*HEROES_PER_LINE + 8)
-#define GFX_SCHWEIN_UP         (GFX_START_ROCKSHEROES + 0*HEROES_PER_LINE +12)
-#define GFX_SCHWEIN_LEFT       (GFX_START_ROCKSHEROES + 1*HEROES_PER_LINE + 8)
-#define GFX_SCHWEIN_RIGHT      (GFX_START_ROCKSHEROES + 1*HEROES_PER_LINE +12)
-#define GFX_DRACHE_DOWN                (GFX_START_ROCKSHEROES + 2*HEROES_PER_LINE + 8)
-#define GFX_DRACHE_UP          (GFX_START_ROCKSHEROES + 2*HEROES_PER_LINE +12)
-#define GFX_DRACHE_LEFT                (GFX_START_ROCKSHEROES + 3*HEROES_PER_LINE + 8)
-#define GFX_DRACHE_RIGHT       (GFX_START_ROCKSHEROES + 3*HEROES_PER_LINE +12)
-/*
-#define GFX_MOLE_DOWN          (GFX_START_ROCKSHEROES + 4*HEROES_PER_LINE + 8)
-#define GFX_MOLE_UP            (GFX_START_ROCKSHEROES + 4*HEROES_PER_LINE +12)
-#define GFX_MOLE_LEFT          (GFX_START_ROCKSHEROES + 5*HEROES_PER_LINE + 8)
-#define GFX_MOLE_RIGHT         (GFX_START_ROCKSHEROES + 5*HEROES_PER_LINE +12)
-*/
-#define GFX_PINGUIN_DOWN       (GFX_START_ROCKSHEROES + 6*HEROES_PER_LINE + 8)
-#define GFX_PINGUIN_UP         (GFX_START_ROCKSHEROES + 6*HEROES_PER_LINE +12)
-#define GFX_PINGUIN_LEFT       (GFX_START_ROCKSHEROES + 7*HEROES_PER_LINE + 8)
-#define GFX_PINGUIN_RIGHT      (GFX_START_ROCKSHEROES + 7*HEROES_PER_LINE +12)
-#define GFX_BLURB_LEFT         (GFX_START_ROCKSHEROES +10*HEROES_PER_LINE + 8)
-#define GFX_BLURB_RIGHT                (GFX_START_ROCKSHEROES +10*HEROES_PER_LINE +12)
-#define GFX_FUNKELN_BLAU       (GFX_START_ROCKSHEROES +11*HEROES_PER_LINE + 9)
-#define GFX_FUNKELN_WEISS      (GFX_START_ROCKSHEROES +11*HEROES_PER_LINE +13)
-#define GFX_FLAMMEN_LEFT       (GFX_START_ROCKSHEROES +12*HEROES_PER_LINE + 8)
-#define GFX_FLAMMEN_RIGHT      (GFX_START_ROCKSHEROES +13*HEROES_PER_LINE + 8)
-#define GFX_FLAMMEN_UP         (GFX_START_ROCKSHEROES +14*HEROES_PER_LINE + 8)
-#define GFX_FLAMMEN_DOWN       (GFX_START_ROCKSHEROES +15*HEROES_PER_LINE + 8)
-
-/* graphics from "RocksSP" */
-#define GFX_SP_EMPTY           (GFX_START_ROCKSSP +  0 * SP_PER_LINE +  0)
-/*
-#define GFX_SP_ZONK            (GFX_START_ROCKSSP +  0 * SP_PER_LINE +  1)
-*/
-#define GFX_SP_BASE            (GFX_START_ROCKSSP +  0 * SP_PER_LINE +  2)
-#define GFX_SP_MURPHY          (GFX_START_ROCKSSP +  0 * SP_PER_LINE +  3)
-#define GFX_SP_INFOTRON                (GFX_START_ROCKSSP +  0 * SP_PER_LINE +  4)
-#define GFX_SP_CHIP_SINGLE     (GFX_START_ROCKSSP +  0 * SP_PER_LINE +  5)
-#define GFX_SP_HARD_GRAY       (GFX_START_ROCKSSP +  0 * SP_PER_LINE +  6)
-#define GFX_SP_EXIT            (GFX_START_ROCKSSP +  0 * SP_PER_LINE +  7)
-#define GFX_SP_DISK_ORANGE     (GFX_START_ROCKSSP +  1 * SP_PER_LINE +  0)
-#define GFX_SP_PORT1_RIGHT     (GFX_START_ROCKSSP +  1 * SP_PER_LINE +  1)
-#define GFX_SP_PORT1_DOWN      (GFX_START_ROCKSSP +  1 * SP_PER_LINE +  2)
-#define GFX_SP_PORT1_LEFT      (GFX_START_ROCKSSP +  1 * SP_PER_LINE +  3)
-#define GFX_SP_PORT1_UP                (GFX_START_ROCKSSP +  1 * SP_PER_LINE +  4)
-#define GFX_SP_PORT2_RIGHT     (GFX_START_ROCKSSP +  1 * SP_PER_LINE +  5)
-#define GFX_SP_PORT2_DOWN      (GFX_START_ROCKSSP +  1 * SP_PER_LINE +  6)
-#define GFX_SP_PORT2_LEFT      (GFX_START_ROCKSSP +  1 * SP_PER_LINE +  7)
-#define GFX_SP_PORT2_UP                (GFX_START_ROCKSSP +  2 * SP_PER_LINE +  0)
-#define GFX_SP_SNIKSNAK                (GFX_START_ROCKSSP +  2 * SP_PER_LINE +  1)
-#define GFX_SP_DISK_YELLOW     (GFX_START_ROCKSSP +  2 * SP_PER_LINE +  2)
-#define GFX_SP_TERMINAL                (GFX_START_ROCKSSP +  2 * SP_PER_LINE +  3)
-#define GFX_SP_DISK_RED                (GFX_START_ROCKSSP +  2 * SP_PER_LINE +  4)
-#define GFX_SP_PORT_Y          (GFX_START_ROCKSSP +  2 * SP_PER_LINE +  5)
-#define GFX_SP_PORT_X          (GFX_START_ROCKSSP +  2 * SP_PER_LINE +  6)
-#define GFX_SP_PORT_XY         (GFX_START_ROCKSSP +  2 * SP_PER_LINE +  7)
-#define GFX_SP_ELECTRON                (GFX_START_ROCKSSP +  3 * SP_PER_LINE +  0)
-#define GFX_SP_BUG             (GFX_START_ROCKSSP +  3 * SP_PER_LINE +  1)
-#define GFX_SP_CHIP_LEFT       (GFX_START_ROCKSSP +  3 * SP_PER_LINE +  2)
-#define GFX_SP_CHIP_RIGHT      (GFX_START_ROCKSSP +  3 * SP_PER_LINE +  3)
-#define GFX_SP_HARD_BASE1      (GFX_START_ROCKSSP +  3 * SP_PER_LINE +  4)
-#define GFX_SP_HARD_GREEN      (GFX_START_ROCKSSP +  3 * SP_PER_LINE +  5)
-#define GFX_SP_HARD_BLUE       (GFX_START_ROCKSSP +  3 * SP_PER_LINE +  6)
-#define GFX_SP_HARD_RED                (GFX_START_ROCKSSP +  3 * SP_PER_LINE +  7)
-#define GFX_SP_HARD_YELLOW     (GFX_START_ROCKSSP +  4 * SP_PER_LINE +  0)
-#define GFX_SP_HARD_BASE2      (GFX_START_ROCKSSP +  4 * SP_PER_LINE +  1)
-#define GFX_SP_HARD_BASE3      (GFX_START_ROCKSSP +  4 * SP_PER_LINE +  2)
-#define GFX_SP_HARD_BASE4      (GFX_START_ROCKSSP +  4 * SP_PER_LINE +  3)
-#define GFX_SP_HARD_BASE5      (GFX_START_ROCKSSP +  4 * SP_PER_LINE +  4)
-#define GFX_SP_HARD_BASE6      (GFX_START_ROCKSSP +  4 * SP_PER_LINE +  5)
-#define GFX_SP_CHIP_UPPER      (GFX_START_ROCKSSP +  4 * SP_PER_LINE +  6)
-#define GFX_SP_CHIP_LOWER      (GFX_START_ROCKSSP +  4 * SP_PER_LINE +  7)
-
-#define GFX_INVISIBLE_STEEL_ON (GFX_START_ROCKSSP +  5 * SP_PER_LINE +  1)
-#define GFX_SAND_INVISIBLE_ON  (GFX_START_ROCKSSP +  5 * SP_PER_LINE +  2)
-#define GFX_INVISIBLE_STEEL    (GFX_START_ROCKSSP +  5 * SP_PER_LINE +  3)
-#define GFX_UNSICHTBAR_ON      (GFX_START_ROCKSSP +  5 * SP_PER_LINE +  5)
-#define GFX_SAND_INVISIBLE     (GFX_START_ROCKSSP +  5 * SP_PER_LINE +  6)
-#define GFX_UNSICHTBAR         (GFX_START_ROCKSSP +  5 * SP_PER_LINE +  7)
-
-#define GFX_SP_ZONK            (GFX_START_ROCKSSP +  6 * SP_PER_LINE +  0)
-
-#define GFX_EM_KEY_1           (GFX_START_ROCKSSP +  6 * SP_PER_LINE +  4)
-#define GFX_EM_KEY_2           (GFX_START_ROCKSSP +  6 * SP_PER_LINE +  5)
-#define GFX_EM_KEY_3           (GFX_START_ROCKSSP +  6 * SP_PER_LINE +  6)
-#define GFX_EM_KEY_4           (GFX_START_ROCKSSP +  6 * SP_PER_LINE +  7)
-#define GFX_EM_GATE_1          (GFX_START_ROCKSSP +  7 * SP_PER_LINE +  0)
-#define GFX_EM_GATE_2          (GFX_START_ROCKSSP +  7 * SP_PER_LINE +  1)
-#define GFX_EM_GATE_3          (GFX_START_ROCKSSP +  7 * SP_PER_LINE +  2)
-#define GFX_EM_GATE_4          (GFX_START_ROCKSSP +  7 * SP_PER_LINE +  3)
-#define GFX_EM_GATE_1X         (GFX_START_ROCKSSP +  7 * SP_PER_LINE +  4)
-#define GFX_EM_GATE_2X         (GFX_START_ROCKSSP +  7 * SP_PER_LINE +  5)
-#define GFX_EM_GATE_3X         (GFX_START_ROCKSSP +  7 * SP_PER_LINE +  6)
-#define GFX_EM_GATE_4X         (GFX_START_ROCKSSP +  7 * SP_PER_LINE +  7)
-
-#define GFX_MURPHY_GO_LEFT     (GFX_START_ROCKSSP +  0 * SP_PER_LINE +  8)
-#define GFX_MURPHY_ANY_LEFT    (GFX_START_ROCKSSP +  0 * SP_PER_LINE +  9)
-#define GFX_MURPHY_GO_RIGHT    (GFX_START_ROCKSSP +  0 * SP_PER_LINE + 11)
-#define GFX_MURPHY_ANY_RIGHT   (GFX_START_ROCKSSP +  0 * SP_PER_LINE + 12)
-#define GFX_MURPHY_SNAP_UP     (GFX_START_ROCKSSP +  0 * SP_PER_LINE + 14)
-#define GFX_MURPHY_SNAP_DOWN   (GFX_START_ROCKSSP +  0 * SP_PER_LINE + 15)
-#define GFX_MURPHY_SNAP_RIGHT  (GFX_START_ROCKSSP +  1 * SP_PER_LINE +  8)
-#define GFX_MURPHY_SNAP_LEFT   (GFX_START_ROCKSSP +  1 * SP_PER_LINE +  9)
-#define GFX_MURPHY_PUSH_RIGHT  (GFX_START_ROCKSSP +  1 * SP_PER_LINE + 10)
-#define GFX_MURPHY_PUSH_LEFT   (GFX_START_ROCKSSP +  1 * SP_PER_LINE + 11)
-
-#define GFX_SP_BUG_WARNING     (GFX_START_ROCKSSP +  2 * SP_PER_LINE + 15)
-#define GFX_SP_EXPLODE_EMPTY   (GFX_START_ROCKSSP +  3 * SP_PER_LINE +  8)
-#define GFX_SP_EXPLODE_INFOTRON        (GFX_START_ROCKSSP +  4 * SP_PER_LINE +  8)
-#define GFX_SP_BUG_ACTIVE      (GFX_START_ROCKSSP +  6 * SP_PER_LINE +  8)
-#define GFX_SP_SNIKSNAK_LEFT   (GFX_START_ROCKSSP +  8 * SP_PER_LINE +  8)
-#define GFX_SP_SNIKSNAK_RIGHT  (GFX_START_ROCKSSP +  8 * SP_PER_LINE + 12)
-#define GFX_SP_SNIKSNAK_UP     (GFX_START_ROCKSSP +  9 * SP_PER_LINE +  8)
-#define GFX_SP_SNIKSNAK_DOWN   (GFX_START_ROCKSSP +  9 * SP_PER_LINE + 12)
-
-#define GFX2_SP_ELECTRON       (GFX_START_ROCKSSP + 10 * SP_PER_LINE +  8)
-#define GFX2_SP_TERMINAL       (GFX_START_ROCKSSP + 11 * SP_PER_LINE +  8)
-#define GFX2_SP_TERMINAL_ACTIVE        (GFX_START_ROCKSSP + 12 * SP_PER_LINE +  8)
-
-#define GFX_SP_MURPHY_CLONE    (GFX_START_ROCKSSP +  0 * SP_PER_LINE +  3)
-
-/* graphics from "RocksDC" */
-#define GFX_BELT1_MIDDLE       (GFX_START_ROCKSDC +  0 * DC_PER_LINE +  0)
-#define GFX_BELT1_LEFT         (GFX_START_ROCKSDC +  1 * DC_PER_LINE +  0)
-#define GFX_BELT1_RIGHT                (GFX_START_ROCKSDC +  2 * DC_PER_LINE +  0)
-#define GFX_BELT2_MIDDLE       (GFX_START_ROCKSDC +  3 * DC_PER_LINE +  0)
-#define GFX_BELT2_LEFT         (GFX_START_ROCKSDC +  4 * DC_PER_LINE +  0)
-#define GFX_BELT2_RIGHT                (GFX_START_ROCKSDC +  5 * DC_PER_LINE +  0)
-#define GFX_BELT3_MIDDLE       (GFX_START_ROCKSDC +  6 * DC_PER_LINE +  0)
-#define GFX_BELT3_LEFT         (GFX_START_ROCKSDC +  7 * DC_PER_LINE +  0)
-#define GFX_BELT3_RIGHT                (GFX_START_ROCKSDC +  8 * DC_PER_LINE +  0)
-#define GFX_BELT4_MIDDLE       (GFX_START_ROCKSDC +  9 * DC_PER_LINE +  0)
-#define GFX_BELT4_LEFT         (GFX_START_ROCKSDC + 10 * DC_PER_LINE +  0)
-#define GFX_BELT4_RIGHT                (GFX_START_ROCKSDC + 11 * DC_PER_LINE +  0)
-#define GFX_BELT1_SWITCH_LEFT  (GFX_START_ROCKSDC + 12 * DC_PER_LINE +  0)
-#define GFX_BELT2_SWITCH_LEFT  (GFX_START_ROCKSDC + 12 * DC_PER_LINE +  1)
-#define GFX_BELT3_SWITCH_LEFT  (GFX_START_ROCKSDC + 12 * DC_PER_LINE +  2)
-#define GFX_BELT4_SWITCH_LEFT  (GFX_START_ROCKSDC + 12 * DC_PER_LINE +  3)
-#define GFX_BELT1_SWITCH_MIDDLE        (GFX_START_ROCKSDC + 13 * DC_PER_LINE +  0)
-#define GFX_BELT2_SWITCH_MIDDLE        (GFX_START_ROCKSDC + 13 * DC_PER_LINE +  1)
-#define GFX_BELT3_SWITCH_MIDDLE        (GFX_START_ROCKSDC + 13 * DC_PER_LINE +  2)
-#define GFX_BELT4_SWITCH_MIDDLE        (GFX_START_ROCKSDC + 13 * DC_PER_LINE +  3)
-#define GFX_BELT1_SWITCH_RIGHT (GFX_START_ROCKSDC + 14 * DC_PER_LINE +  0)
-#define GFX_BELT2_SWITCH_RIGHT (GFX_START_ROCKSDC + 14 * DC_PER_LINE +  1)
-#define GFX_BELT3_SWITCH_RIGHT (GFX_START_ROCKSDC + 14 * DC_PER_LINE +  2)
-#define GFX_BELT4_SWITCH_RIGHT (GFX_START_ROCKSDC + 14 * DC_PER_LINE +  3)
-
-#define GFX_SWITCHGATE_SWITCH_1        (GFX_START_ROCKSDC + 12 * DC_PER_LINE +  4)
-#define GFX_SWITCHGATE_SWITCH_2        (GFX_START_ROCKSDC + 12 * DC_PER_LINE +  5)
-#define GFX_LIGHT_SWITCH_OFF   (GFX_START_ROCKSDC + 12 * DC_PER_LINE +  6)
-#define GFX_LIGHT_SWITCH_ON    (GFX_START_ROCKSDC + 12 * DC_PER_LINE +  7)
-#define GFX_TIMEGATE_SWITCH    (GFX_START_ROCKSDC + 15 * DC_PER_LINE +  0)
-
-#define GFX_ENVELOPE           (GFX_START_ROCKSDC + 14 * DC_PER_LINE +  4)
-#define GFX_SIGN_EXCLAMATION   (GFX_START_ROCKSDC + 14 * DC_PER_LINE +  5)
-#define GFX_SIGN_STOP          (GFX_START_ROCKSDC + 14 * DC_PER_LINE +  6)
-#define GFX_LANDMINE           (GFX_START_ROCKSDC + 14 * DC_PER_LINE +  7)
-#define GFX_STEEL_SLANTED      (GFX_START_ROCKSDC + 15 * DC_PER_LINE +  5)
-
-#define GFX_EXTRA_TIME         (GFX_START_ROCKSDC +  0 * DC_PER_LINE +  8)
-#define GFX_SHIELD_ACTIVE      (GFX_START_ROCKSDC +  1 * DC_PER_LINE +  8)
-#define GFX_SHIELD_PASSIVE     (GFX_START_ROCKSDC +  2 * DC_PER_LINE +  8)
-#define GFX_MOLE_DOWN          (GFX_START_ROCKSDC +  3 * DC_PER_LINE +  8)
-#define GFX_MOLE_UP            (GFX_START_ROCKSDC +  3 * DC_PER_LINE + 12)
-#define GFX_MOLE_LEFT          (GFX_START_ROCKSDC +  4 * DC_PER_LINE +  8)
-#define GFX_MOLE_RIGHT         (GFX_START_ROCKSDC +  4 * DC_PER_LINE + 12)
-#define GFX_SWITCHGATE_CLOSED  (GFX_START_ROCKSDC +  5 * DC_PER_LINE +  8)
-#define GFX_SWITCHGATE_OPEN    (GFX_START_ROCKSDC +  5 * DC_PER_LINE + 12)
-#define GFX_TIMEGATE_CLOSED    (GFX_START_ROCKSDC +  6 * DC_PER_LINE +  8)
-#define GFX_TIMEGATE_OPEN      (GFX_START_ROCKSDC +  6 * DC_PER_LINE + 12)
-#define GFX_BALLOON_SEND_LEFT  (GFX_START_ROCKSDC +  7 * DC_PER_LINE +  8)
-#define GFX_BALLOON_SEND_RIGHT (GFX_START_ROCKSDC +  7 * DC_PER_LINE +  9)
-#define GFX_BALLOON_SEND_UP    (GFX_START_ROCKSDC +  7 * DC_PER_LINE + 10)
-#define GFX_BALLOON_SEND_DOWN  (GFX_START_ROCKSDC +  7 * DC_PER_LINE + 11)
-#define GFX_BALLOON            (GFX_START_ROCKSDC +  7 * DC_PER_LINE + 12)
-#define GFX_BALLOON_SEND_ANY   (GFX_START_ROCKSDC +  0 * DC_PER_LINE + 15)
-
-#define GFX_EMC_STEEL_WALL_1   (GFX_START_ROCKSDC +  0 * DC_PER_LINE + 14)
-#define GFX_EMC_STEEL_WALL_2   (GFX_START_ROCKSDC +  0 * DC_PER_LINE + 14)
-#define GFX_EMC_STEEL_WALL_3   (GFX_START_ROCKSDC +  0 * DC_PER_LINE + 14)
-#define GFX_EMC_STEEL_WALL_4   (GFX_START_ROCKSDC +  0 * DC_PER_LINE + 14)
-#define GFX_EMC_WALL_1         (GFX_START_ROCKSDC +  6 * DC_PER_LINE + 13)
-#define GFX_EMC_WALL_2         (GFX_START_ROCKSDC +  6 * DC_PER_LINE + 14)
-#define GFX_EMC_WALL_3         (GFX_START_ROCKSDC +  6 * DC_PER_LINE + 15)
-#define GFX_EMC_WALL_4         (GFX_START_ROCKSDC +  1 * DC_PER_LINE + 14)
-#define GFX_EMC_WALL_5         (GFX_START_ROCKSDC +  1 * DC_PER_LINE + 15)
-#define GFX_EMC_WALL_6         (GFX_START_ROCKSDC +  2 * DC_PER_LINE + 14)
-#define GFX_EMC_WALL_7         (GFX_START_ROCKSDC +  2 * DC_PER_LINE + 15)
-#define GFX_EMC_WALL_8         (GFX_START_ROCKSDC +  1 * DC_PER_LINE + 14)
-
-/* graphics from "RocksMore" */
-#define GFX_ARROW_BLUE_LEFT    (GFX_START_ROCKSMORE +  0 * MORE_PER_LINE +  0)
-#define GFX_ARROW_BLUE_RIGHT   (GFX_START_ROCKSMORE +  0 * MORE_PER_LINE +  1)
-#define GFX_ARROW_BLUE_UP      (GFX_START_ROCKSMORE +  0 * MORE_PER_LINE +  2)
-#define GFX_ARROW_BLUE_DOWN    (GFX_START_ROCKSMORE +  0 * MORE_PER_LINE +  3)
-#define GFX_ARROW_RED_LEFT     (GFX_START_ROCKSMORE +  1 * MORE_PER_LINE +  0)
-#define GFX_ARROW_RED_RIGHT    (GFX_START_ROCKSMORE +  1 * MORE_PER_LINE +  1)
-#define GFX_ARROW_RED_UP       (GFX_START_ROCKSMORE +  1 * MORE_PER_LINE +  2)
-#define GFX_ARROW_RED_DOWN     (GFX_START_ROCKSMORE +  1 * MORE_PER_LINE +  3)
-#define GFX_SCROLLBAR_BLUE     (GFX_START_ROCKSMORE +  2 * MORE_PER_LINE +  0)
-#define GFX_SCROLLBAR_RED      (GFX_START_ROCKSMORE +  2 * MORE_PER_LINE +  1)
-#define GFX_PEARL              (GFX_START_ROCKSMORE +  3 * MORE_PER_LINE +  0)
-#define GFX_CRYSTAL            (GFX_START_ROCKSMORE +  3 * MORE_PER_LINE +  1)
-#define GFX_WALL_PEARL         (GFX_START_ROCKSMORE +  3 * MORE_PER_LINE +  2)
-#define GFX_WALL_CRYSTAL       (GFX_START_ROCKSMORE +  3 * MORE_PER_LINE +  3)
-#define GFX_PEARL_BREAKING     (GFX_START_ROCKSMORE +  4 * MORE_PER_LINE +  0)
-#define GFX_SPRING             (GFX_START_ROCKSMORE +  5 * MORE_PER_LINE +  0)
-#define GFX_TUBE_RIGHT_DOWN    (GFX_START_ROCKSMORE +  5 * MORE_PER_LINE +  1)
-#define GFX_TUBE_HORIZ_DOWN    (GFX_START_ROCKSMORE +  5 * MORE_PER_LINE +  2)
-#define GFX_TUBE_LEFT_DOWN     (GFX_START_ROCKSMORE +  5 * MORE_PER_LINE +  3)
-#define GFX_TUBE_HORIZONTAL    (GFX_START_ROCKSMORE +  6 * MORE_PER_LINE +  0)
-#define GFX_TUBE_VERT_RIGHT    (GFX_START_ROCKSMORE +  6 * MORE_PER_LINE +  1)
-#define GFX_TUBE_CROSS         (GFX_START_ROCKSMORE +  6 * MORE_PER_LINE +  2)
-#define GFX_TUBE_VERT_LEFT     (GFX_START_ROCKSMORE +  6 * MORE_PER_LINE +  3)
-#define GFX_TUBE_VERTICAL      (GFX_START_ROCKSMORE +  7 * MORE_PER_LINE +  0)
-#define GFX_TUBE_RIGHT_UP      (GFX_START_ROCKSMORE +  7 * MORE_PER_LINE +  1)
-#define GFX_TUBE_HORIZ_UP      (GFX_START_ROCKSMORE +  7 * MORE_PER_LINE +  2)
-#define GFX_TUBE_LEFT_UP       (GFX_START_ROCKSMORE +  7 * MORE_PER_LINE +  3)
-
-#define GFX_TRAP_INACTIVE      (GFX_START_ROCKSMORE +  0 * MORE_PER_LINE +  4)
-#define GFX_TRAP_ACTIVE                (GFX_START_ROCKSMORE +  0 * MORE_PER_LINE +  7)
-#define GFX_BD_WALL            (GFX_START_ROCKSMORE +  1 * MORE_PER_LINE +  4)
-#define GFX_BD_ROCK            (GFX_START_ROCKSMORE +  2 * MORE_PER_LINE +  4)
-#define GFX_DX_SUPABOMB                (GFX_START_ROCKSMORE +  1 * MORE_PER_LINE +  7)
-
-/* graphics from "RocksFont" */
-#define GFX_CHAR_START         (GFX_START_ROCKSFONT)
-#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)
-
-/* new elements which still have no graphic */
-#define GFX_DOOR_WHITE         GFX_CHAR_FRAGE
-#define GFX_DOOR_WHITE_GRAY    GFX_CHAR_FRAGE
-#define GFX_KEY_WHITE          GFX_CHAR_FRAGE
-#define GFX_SIGN_RADIOACTIVITY GFX_CHAR_FRAGE
-#define GFX_SIGN_WHEELCHAIR    GFX_CHAR_FRAGE
-#define GFX_SIGN_PARKING       GFX_CHAR_FRAGE
-#define GFX_SIGN_ONEWAY                GFX_CHAR_FRAGE
-#define GFX_SIGN_HEART         GFX_CHAR_FRAGE
-#define GFX_SIGN_TRIANGLE      GFX_CHAR_FRAGE
-#define GFX_SIGN_ROUND         GFX_CHAR_FRAGE
-#define GFX_SIGN_EXIT          GFX_CHAR_FRAGE
-#define GFX_SIGN_YINYANG       GFX_CHAR_FRAGE
-#define GFX_SIGN_OTHER         GFX_CHAR_FRAGE
-#define GFX_DX_UNKNOWN_15      GFX_CHAR_FRAGE
-#define GFX_DX_UNKNOWN_42      GFX_CHAR_FRAGE
-
-
-/* the names of the sounds */
-#define SND_AMOEBE             0
-#define SND_ANTIGRAV           1
-#define SND_AUTSCH             2
-#define SND_BLURB              3
-#define SND_BONG               4
-#define SND_BUING              5
-#define SND_DENG               6
-#define SND_FUEL               7
-#define SND_GONG               8
-#define SND_HALLOFFAME         9
-#define SND_HOLZ               10
-#define SND_HUI                        11
-#define SND_KABUMM             12
-#define SND_KINK               13
-#define SND_KLAPPER            14
-#define SND_KLING              15
-#define SND_KLOPF              16
-#define SND_KLUMPF             17
-#define SND_KNACK              18
-#define SND_KNURK              19
-#define SND_KRACH              20
-#define SND_LACHEN             21
-#define SND_LASER              22
-#define SND_MIEP               23
-#define SND_NJAM               24
-#define SND_OEFFNEN            25
-#define SND_PLING              26
-#define SND_PONG               27
-#define SND_PUSCH              28
-#define SND_QUIEK              29
-#define SND_QUIRK              30
-#define SND_RHYTHMLOOP         31
-#define SND_ROAAAR             32
-#define SND_ROEHR              33
-#define SND_RUMMS              34
-#define SND_SCHLOPP            35
-#define SND_SCHLURF            36
-#define SND_SCHRFF             37
-#define SND_SCHWIRR            38
-#define SND_SIRR               39
-#define SND_SLURP              40
-#define SND_SPROING            41
-#define SND_WARNTON            42
-#define SND_WHOOSH             43
-#define SND_ZISCH              44
-#define SND_SP_BASE            45
-#define SND_SP_INFOTRON                46
-#define SND_SP_ZONKDOWN                47
-#define SND_SP_ZONKPUSH                48
-#define SND_SP_BUG             49
-#define SND_SP_BOOM            50
-#define SND_SP_BOOOM           51
-#define SND_SP_EXIT            52
-#define SND_EMPTY              53
-#define SND_GATE               54
-
-#define NUM_SOUNDS             55
-
-
-/* values for sound effects */
-#define SND_BD_EMPTY_SPACE_DIGGING             0
-#define SND_BD_SAND_DIGGING                    1
-#define SND_BD_DIAMOND_COLLECTING              2
-#define SND_BD_DIAMOND_IMPACT                  3
-#define SND_BD_ROCK_PUSHING                    4
-#define SND_BD_ROCK_IMPACT                     5
-#define SND_BD_MAGIC_WALL_ACTIVATING           6
-#define SND_BD_MAGIC_WALL_CHANGING             7
-#define SND_BD_MAGIC_WALL_RUNNING              8
-#define SND_BD_AMOEBA_WAITING                  9
-#define SND_BD_AMOEBA_CREATING                 10
-#define SND_BD_AMOEBA_TURNING_TO_GEM           11
-#define SND_BD_AMOEBA_TURNING_TO_ROCK          12
-#define SND_BD_BUTTERFLY_MOVING                        13
-#define SND_BD_BUTTERFLY_WAITING               14
-#define SND_BD_FIREFLY_MOVING                  15
-#define SND_BD_FIREFLY_WAITING                 16
-#define SND_BD_EXIT_ENTERING                   17
-#define SND_SP_EMPTY_SPACE_DIGGING             18
-#define SND_SP_BASE_DIGGING                    19
-#define SND_SP_BUGGY_BASE_DIGGING              20
-#define SND_SP_BUGGY_BASE_ACTIVATING           21
-#define SND_SP_INFOTRON_COLLECTING             22
-#define SND_SP_INFOTRON_IMPACT                 23
-#define SND_SP_ZONK_PUSHING                    24
-#define SND_SP_ZONK_IMPACT                     25
-#define SND_SP_DISK_RED_COLLECTING             26
-#define SND_SP_DISK_ORANGE_PUSHING             27
-#define SND_SP_DISK_YELLOW_PUSHING             28
-#define SND_SP_PORT_PASSING                    29
-#define SND_SP_EXIT_ENTERING                   30
-#define SND_SP_ELEMENT_EXPLODING               31
-#define SND_SP_SNIKSNAK_MOVING                 32
-#define SND_SP_SNIKSNAK_WAITING                        33
-#define SND_SP_ELECTRON_MOVING                 34
-#define SND_SP_ELECTRON_WAITING                        35
-#define SND_SP_TERMINAL_ACTIVATING             36
-#define SND_SOKOBAN_OBJECT_PUSHING             37
-#define SND_SOKOBAN_FIELD_FILLING              38
-#define SND_SOKOBAN_FIELD_CLEARING             39
-#define SND_SOKOBAN_GAME_SOLVING               40
-#define SND_EMPTY_SPACE_DIGGING                        41
-#define SND_SAND_DIGGING                       42
-#define SND_EMERALD_COLLECTING                 43
-#define SND_EMERALD_IMPACT                     44
-#define SND_DIAMOND_COLLECTING                 45
-#define SND_DIAMOND_IMPACT                     46
-#define SND_DIAMOND_BREAKING                   47
-#define SND_ROCK_PUSHING                       48
-#define SND_ROCK_IMPACT                                49
-#define SND_BOMB_PUSHING                       50
-#define SND_NUT_PUSHING                                51
-#define SND_NUT_CRACKING                       52
-#define SND_NUT_IMPACT                         53
-#define SND_DYNAMITE_COLLECTING                        54
-#define SND_DYNAMITE_PLACING                   55
-#define SND_DYNAMITE_BURNING                   56
-#define SND_KEY_COLLECTING                     57
-#define SND_GATE_PASSING                       58
-#define SND_BUG_MOVING                         59
-#define SND_BUG_WAITING                                60
-#define SND_SPACESHIP_MOVING                   61
-#define SND_SPACESHIP_WAITING                  62
-#define SND_YAMYAM_MOVING                      63
-#define SND_YAMYAM_WAITING                     64
-#define SND_YAMYAM_EATING_DIAMOND              65
-#define SND_ROBOT_STEPPING                     66
-#define SND_ROBOT_WAITING                      67
-#define SND_ROBOT_WHEEL_ACTIVATING             68
-#define SND_ROBOT_WHEEL_RUNNING                        69
-#define SND_MAGIC_WALL_ACTIVATING              70
-#define SND_MAGIC_WALL_CHANGING                        71
-#define SND_MAGIC_WALL_RUNNING                 72
-#define SND_AMOEBA_WAITING                     73
-#define SND_AMOEBA_CREATING                    74
-#define SND_AMOEBA_DROPPING                    75
-#define SND_ACID_SPLASHING                     76
-#define SND_QUICKSAND_FILLING                  77
-#define SND_QUICKSAND_SLIPPING_THROUGH         78
-#define SND_QUICKSAND_EMPTYING                 79
-#define SND_EXIT_OPENING                       80
-#define SND_EXIT_ENTERING                      81
-#define SND_BALLOON_MOVING                     82
-#define SND_BALLOON_WAITING                    83
-#define SND_BALLOON_PUSHING                    84
-#define SND_BALLOON_SWITCH_ACTIVATING          85
-#define SND_SPRING_MOVING                      86
-#define SND_SPRING_PUSHING                     87
-#define SND_SPRING_IMPACT                      88
-#define SND_WALL_GROWING                       89
-#define SND_PEARL_COLLECTING                   90
-#define SND_PEARL_BREAKING                     91
-#define SND_PEARL_IMPACT                       92
-#define SND_CRYSTAL_COLLECTING                 93
-#define SND_CRYSTAL_IMPACT                     94
-#define SND_ENVELOPE_COLLECTING                        95
-#define SND_SAND_INVISIBLE_DIGGING             96
-#define SND_SHIELD_PASSIVE_COLLECTING          97
-#define SND_SHIELD_PASSIVE_ACTIVATED           98
-#define SND_SHIELD_ACTIVE_COLLECTING           99
-#define SND_SHIELD_ACTIVE_ACTIVATED            100
-#define SND_EXTRA_TIME_COLLECTING              101
-#define SND_MOLE_MOVING                                102
-#define SND_MOLE_WAITING                       103
-#define SND_MOLE_EATING_AMOEBA                 104
-#define SND_SWITCHGATE_SWITCH_ACTIVATING       105
-#define SND_SWITCHGATE_OPENING                 106
-#define SND_SWITCHGATE_CLOSING                 107
-#define SND_SWITCHGATE_PASSING                 108
-#define SND_TIMEGATE_WHEEL_ACTIVATING          109
-#define SND_TIMEGATE_WHEEL_RUNNING             110
-#define SND_TIMEGATE_OPENING                   111
-#define SND_TIMEGATE_CLOSING                   112
-#define SND_TIMEGATE_PASSING                   113
-#define SND_CONVEYOR_BELT_SWITCH_ACTIVATING    114
-#define SND_CONVEYOR_BELT_RUNNING              115
-#define SND_LIGHT_SWITCH_ACTIVATING            116
-#define SND_LIGHT_SWITCH_DEACTIVATING          117
-#define SND_DX_BOMB_PUSHING                    118
-#define SND_TRAP_INACTIVE_DIGGING              119
-#define SND_TRAP_ACTIVATING                    120
-#define SND_TUBE_PASSING                       121
-#define SND_AMOEBA_TURNING_TO_GEM              122
-#define SND_AMOEBA_TURNING_TO_ROCK             123
-#define SND_SPEED_PILL_COLLECTING              124
-#define SND_DYNABOMB_NR_COLLECTING             125
-#define SND_DYNABOMB_SZ_COLLECTING             126
-#define SND_DYNABOMB_XL_COLLECTING             127
-#define SND_DYNABOMB_PLACING                   128
-#define SND_DYNABOMB_BURNING                   129
-#define SND_SATELLITE_MOVING                   130
-#define SND_SATELLITE_WAITING                  131
-#define SND_SATELLITE_PUSHING                  132
-#define SND_LAMP_ACTIVATING                    133
-#define SND_LAMP_DEACTIVATING                  134
-#define SND_TIME_ORB_FULL_COLLECTING           135
-#define SND_TIME_ORB_FULL_IMPACT               136
-#define SND_TIME_ORB_EMPTY_PUSHING             137
-#define SND_TIME_ORB_EMPTY_IMPACT              138
-#define SND_GAMEOFLIFE_WAITING                 139
-#define SND_GAMEOFLIFE_CREATING                        140
-#define SND_BIOMAZE_WAITING                    141
-#define SND_BIOMAZE_CREATING                   142
-#define SND_PACMAN_MOVING                      143
-#define SND_PACMAN_WAITING                     144
-#define SND_PACMAN_EATING_AMOEBA               145
-#define SND_DARK_YAMYAM_MOVING                 146
-#define SND_DARK_YAMYAM_WAITING                        147
-#define SND_DARK_YAMYAM_EATING_ANY             148
-#define SND_PENGUIN_MOVING                     149
-#define SND_PENGUIN_WAITING                    150
-#define SND_PENGUIN_ENTERING_EXIT              151
-#define SND_PIG_MOVING                         152
-#define SND_PIG_WAITING                                153
-#define SND_PIG_EATING_GEM                     154
-#define SND_DRAGON_MOVING                      155
-#define SND_DRAGON_WAITING                     156
-#define SND_DRAGON_ATTACKING                   157
-#define SND_PLAYER_DYING                       158
-#define SND_ELEMENT_EXPLODING                  159
-#define SND_GAME_STARTING                      160
-#define SND_GAME_RUNNING_OUT_OF_TIME           161
-#define SND_GAME_LEVELTIME_BONUS               162
-#define SND_GAME_LOSING                                163
-#define SND_GAME_WINNING                       164
-#define SND_MENU_DOOR_OPENING                  165
-#define SND_MENU_DOOR_CLOSING                  166
-#define SND_MENU_HALL_OF_FAME                  167
-#define SND_MENU_INFO_SCREEN                   168
-
-#define NUM_SOUND_EFFECTS                      169
-
-
-/* values for game_status */
-#define EXITGAME               0
-#define MAINMENU               1
-#define PLAYING                        2
-#define LEVELED                        3
-#define HELPSCREEN             4
-#define CHOOSELEVEL            5
-#define TYPENAME               6
-#define HALLOFFAME             7
-#define SETUP                  8
-
-#define PROGRAM_VERSION_MAJOR  2
-#define PROGRAM_VERSION_MINOR  1
-#define PROGRAM_VERSION_PATCH  1
-#define PROGRAM_VERSION_STRING "2.1.1"
+  /* functions that are called before, while and after the change of an
+     element -- currently only used for non-custom elements */
+  void (*pre_change_function)(int x, int y);
+  void (*change_function)(int x, int y);
+  void (*post_change_function)(int x, int y);
+};
 
-#define PROGRAM_TITLE_STRING   "Rocks'n'Diamonds"
-#define PROGRAM_AUTHOR_STRING  "Holger Schemel"
-#define PROGRAM_RIGHTS_STRING  "Copyright ^1995-2002 by"
-#define PROGRAM_DOS_PORT_STRING        "DOS port done 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        ".rocksndiamonds"
-#define COOKIE_PREFIX          "ROCKSNDIAMONDS"
-#define FILENAME_PREFIX                "Rocks"
+struct ElementInfo
+{
+  /* ---------- token and description strings ---------- */
 
-#define X11_ICON_FILENAME      "rocks_icon.xbm"
-#define X11_ICONMASK_FILENAME  "rocks_iconmask.xbm"
-#define MSDOS_POINTER_FILENAME "mouse.pcx"
+  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 elements */
 
-/* file version numbers for resource files (levels, tapes, score, setup, etc.)
-** currently supported/known file version numbers:
-**     1.0 (old)
-**     1.2 (still in use)
-**     1.4 (still in use)
-**     2.0 (actual)
-*/
-#define FILE_VERSION_1_0       VERSION_IDENT(1,0,0)
-#define FILE_VERSION_1_2       VERSION_IDENT(1,2,0)
-#define FILE_VERSION_1_4       VERSION_IDENT(1,4,0)
-#define FILE_VERSION_2_0       VERSION_IDENT(2,0,0)
+  /* ---------- graphic and sound definitions ---------- */
 
-/* file version does not change for every program version, but is changed
-   when new features are introduced that are incompatible with older file
-   versions, so that they can be treated accordingly */
-#define FILE_VERSION_ACTUAL    FILE_VERSION_2_0
+  int graphic[NUM_ACTIONS];    /* default graphics for several actions */
+  int direction_graphic[NUM_ACTIONS][NUM_DIRECTIONS];
+                               /* special graphics for left/right/up/down */
 
-#define GAME_VERSION_1_0       FILE_VERSION_1_0
-#define GAME_VERSION_1_2       FILE_VERSION_1_2
-#define GAME_VERSION_1_4       FILE_VERSION_1_4
-#define GAME_VERSION_2_0       FILE_VERSION_2_0
+  int crumbled[NUM_ACTIONS];   /* crumbled graphics for several actions */
+  int direction_crumbled[NUM_ACTIONS][NUM_DIRECTIONS];
+                               /* crumbled graphics for left/right/up/down */
 
-#define GAME_VERSION_ACTUAL    VERSION_IDENT(PROGRAM_VERSION_MAJOR, \
-                                             PROGRAM_VERSION_MINOR, \
-                                             PROGRAM_VERSION_PATCH)
+  int special_graphic[NUM_SPECIAL_GFX_ARGS];
+                               /* special graphics for certain screens */
 
-/* for DrawGraphicAnimation() [tools.c] and AnimateToon() [cartoons.c] */
-#define ANIM_NORMAL            0
-#define ANIM_OSCILLATE         1
-#define ANIM_REVERSE           2
+  int sound[NUM_ACTIONS];      /* default sounds for several actions */
 
-/* values for game_emulation */
-#define EMU_NONE               0
-#define EMU_BOULDERDASH                1
-#define EMU_SOKOBAN            2
-#define EMU_SUPAPLEX           3
+  /* ---------- special element property values ---------- */
+
+  boolean use_gfx_element;     /* use custom graphic element */
+  short gfx_element;           /* optional custom graphic element */
+
+  int score;                   /* score value for collecting */
+  int gem_count;               /* gem count value for collecting */
+
+  int push_delay_fixed;                /* constant frame delay for pushing */
+  int push_delay_random;       /* additional random frame delay for pushing */
+  int move_delay_fixed;                /* constant frame delay for moving */
+  int move_delay_random;       /* additional random frame delay for 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 slippery_type;           /* how/where other elements slip away */
+
+  int content[3][3];           /* new elements after explosion */
+
+  struct ElementChangeInfo change;
+
+  /* ---------- internal values used in level editor ---------- */
+
+  int access_type;             /* walkable or passable */
+  int access_layer;            /* accessible over/inside/under */
+  int walk_to_action;          /* diggable/collectible/pushable */
+  int smash_targets;           /* can smash player/enemies/everything */
+  int deadliness;              /* deadly when running/colliding/touching */
+  int consistency;             /* indestructible/can explode */
+  int change_player_action;    /* touched/pressed/pushed by player */
+  int change_collide_action;   /* collision/impact/smashed */
+  int change_other_action;     /* various change actions */
+
+  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 */
+};
+
+struct FontInfo
+{
+  char *token_name;            /* font token used in config files */
+
+  int graphic;                 /* default graphic for this font */
+  int special_graphic[NUM_SPECIAL_GFX_ARGS];
+                               /* special graphics for certain screens */
+  int special_bitmap_id[NUM_SPECIAL_GFX_ARGS];
+                               /* internal bitmap ID for special graphics */
+};
+
+struct GraphicInfo
+{
+  Bitmap *bitmap;
+  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 anim_frames;
+  int anim_frames_per_line;
+  int anim_start_frame;
+  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 step_offset;             /* optional step offset of toon animations */
+  int step_delay;              /* optional step delay of toon animations */
+
+  int draw_x, draw_y;          /* optional offset for drawing fonts chars */
+
+#if defined(TARGET_X11_NATIVE_PERFORMANCE_WORKAROUND)
+  Pixmap clip_mask;            /* single-graphic-only clip mask for X11 */
+  GC clip_gc;                  /* single-graphic-only clip gc for X11 */
+#endif
+};
+
+struct SoundInfo
+{
+  boolean loop;
+};
+
+struct ElementActionInfo
+{
+  char *suffix;
+  int value;
+  boolean is_loop_sound;
+};
+
+struct ElementDirectionInfo
+{
+  char *suffix;
+  int value;
+};
+
+struct SpecialSuffixInfo
+{
+  char *suffix;
+  int value;
+};
+
+
+#if 0
+extern GC                      tile_clip_gc;
+extern Bitmap                 *pix[];
+#endif
+extern Bitmap                 *bitmap_db_field, *bitmap_db_door;
+extern Pixmap                  tile_clipmask[];
+extern DrawBuffer            *fieldbuffer;
+extern DrawBuffer            *drawto_field;
+
+extern int                     game_status;
+extern boolean                 level_editor_test_game;
+extern boolean                 network_playing;
+
+extern int                     key_joystick_mapping;
+
+extern boolean                 redraw[MAX_BUF_XSIZE][MAX_BUF_YSIZE];
+extern int                     redraw_x1, redraw_y1;
+
+extern short                   Feld[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                   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 boolean                 Changing[MAX_LEV_FIELDX][MAX_LEV_FIELDY];
+extern short                   JustStopped[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                   ExplodePhase[MAX_LEV_FIELDX][MAX_LEV_FIELDY];
+extern short                   ExplodeField[MAX_LEV_FIELDX][MAX_LEV_FIELDY];
+
+extern unsigned long           Properties[MAX_NUM_ELEMENTS][NUM_EP_BITFIELDS];
+
+extern int                     GfxFrame[MAX_LEV_FIELDX][MAX_LEV_FIELDY];
+extern int                     GfxAction[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                     lev_fieldx, lev_fieldy;
+extern int                     scroll_x, scroll_y;
+
+extern int                     FX, FY;
+extern int                     ScrollStepSize;
+extern int                     ScreenMovDir, ScreenMovPos, ScreenGfxPos;
+extern int                     BorderElement;
+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                     ZX, ZY;
+extern int                     ExitX, ExitY;
+extern int                     AllPlayersGone;
+
+extern int                     TimeFrames, TimePlayed, TimeLeft;
+extern boolean                 SiebAktiv;
+extern int                     SiebCount;
+
+extern boolean                 network_player_action_received;
+
+extern int                     graphics_action_mapping[];
+
+extern struct LevelInfo                level, level_template;
+extern struct PlayerInfo       stored_player[], *local_player;
+extern struct HiScore          highscore[];
+extern struct TapeInfo         tape;
+extern struct GameInfo         game;
+extern struct GlobalInfo       global;
+extern struct MenuInfo         menu;
+extern struct DoorInfo         door;
+extern struct ElementInfo      element_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 GraphicInfo      *graphic_info;
+extern struct SoundInfo               *sound_info;
+extern struct ConfigInfo       image_config[], sound_config[];
+extern struct ConfigInfo       image_config_suffix[], sound_config_suffix[];
 
 #endif /* MAIN_H */
index 21a48572d08af642fc09fbb42cd94630971fa0b6..58c32a6e06d13391bb8d70d2dc8fcfffea75a48e 100644 (file)
@@ -478,7 +478,7 @@ void NetworkServer(int port, int serveronly)
   if (is_daemon)
   {
     /* become a daemon, breaking all ties with the controlling terminal */
-    options.verbose = 0;
+    options.verbose = FALSE;
     for (i=0; i<255; i++)
     {
       if (i != lfd)
index 2b0ac6c205ecf7a9cafe378e1c95f733405b4ee0..a2928592b4a23fae7d379a47dbf68cf779e41e0f 100644 (file)
@@ -238,9 +238,9 @@ void SendToServer_StartPlaying()
   buffer[8] = (unsigned char)((new_random_seed >>  8) & 0xff);
   buffer[9] = (unsigned char)((new_random_seed >>  0) & 0xff);
 
-  strcpy((char *)&buffer[10], leveldir_current->filename);
+  strcpy((char *)&buffer[10], leveldir_current->identifier);
 
-  SendBufferToServer(10 + strlen(leveldir_current->filename) + 1);
+  SendBufferToServer(10 + strlen(leveldir_current->identifier) + 1);
 }
 
 void SendToServer_PausePlaying()
@@ -417,27 +417,28 @@ static void Handle_OP_START_PLAYING()
   int new_level_nr;
   int dummy;                           /* !!! HAS NO MEANING ANYMORE !!! */
   unsigned long new_random_seed;
-  char *new_leveldir_filename;
+  char *new_leveldir_identifier;
 
   new_level_nr = (buffer[2] << 8) + buffer[3];
   dummy = (buffer[4] << 8) + buffer[5];
   new_random_seed =
     (buffer[6] << 24) | (buffer[7] << 16) | (buffer[8] << 8) | (buffer[9]);
-  new_leveldir_filename = (char *)&buffer[10];
+  new_leveldir_identifier = (char *)&buffer[10];
 
-  new_leveldir = getTreeInfoFromFilename(leveldir_first,new_leveldir_filename);
+  new_leveldir = getTreeInfoFromIdentifier(leveldir_first,
+                                          new_leveldir_identifier);
   if (new_leveldir == NULL)
   {
-    Error(ERR_WARN, "no such level directory: '%s'", new_leveldir_filename);
+    Error(ERR_WARN, "no such level identifier: '%s'", new_leveldir_identifier);
 
     new_leveldir = leveldir_first;
-    Error(ERR_WARN, "using default level directory: '%s'", new_leveldir->name);
+    Error(ERR_WARN, "using default level set: '%s'", new_leveldir->identifier);
   }
 
   printf("OP_START_PLAYING: %d\n", buffer[0]);
   Error(ERR_NETWORK_CLIENT,
-       "client %d starts game [level %d from leveldir '%s']\n",
-       buffer[0], new_level_nr, new_leveldir->name);
+       "client %d starts game [level %d from level identifier '%s']\n",
+       buffer[0], new_level_nr, new_leveldir->identifier);
 
   leveldir_current = new_leveldir;
   level_nr = new_level_nr;
@@ -454,7 +455,7 @@ static void Handle_OP_START_PLAYING()
 
   InitRND(new_random_seed);
 
-  game_status = PLAYING;
+  game_status = GAME_MODE_PLAYING;
   InitGame();
 }
 
@@ -481,7 +482,7 @@ static void Handle_OP_STOP_PLAYING()
   printf("OP_STOP_PLAYING: %d\n", buffer[0]);
   Error(ERR_NETWORK_CLIENT, "client %d stops game", buffer[0]);
 
-  game_status = MAINMENU;
+  game_status = GAME_MODE_MAIN;
   DrawMainMenu();
 }
 
index ac88cbbedf89372adb10fff53e13f7a9a158695c..d0b5313d735b27fcf89b67157aa58f3c38974e1f 100644 (file)
 /* screens in the setup menu */
 #define SETUP_MODE_MAIN                        0
 #define SETUP_MODE_GAME                        1
-#define SETUP_MODE_INPUT               2
-#define SETUP_MODE_SHORTCUT            3
-#define SETUP_MODE_GRAPHICS            4
-#define SETUP_MODE_SOUND               5
-#define SETUP_MODE_ARTWORK             6
-#define SETUP_MODE_CHOOSE_GRAPHICS     7
-#define SETUP_MODE_CHOOSE_SOUNDS       8
-#define SETUP_MODE_CHOOSE_MUSIC                9
-
-#define MAX_SETUP_MODES                        10
+#define SETUP_MODE_EDITOR              2
+#define SETUP_MODE_INPUT               3
+#define SETUP_MODE_SHORTCUT            4
+#define SETUP_MODE_GRAPHICS            5
+#define SETUP_MODE_SOUND               6
+#define SETUP_MODE_ARTWORK             7
+#define SETUP_MODE_CHOOSE_GRAPHICS     8
+#define SETUP_MODE_CHOOSE_SOUNDS       9
+#define SETUP_MODE_CHOOSE_MUSIC                10
+
+#define MAX_SETUP_MODES                        11
 
 /* for input setup functions */
 #define SETUPINPUT_SCREEN_POS_START    0
@@ -70,39 +71,97 @@ static void HandleChooseTree(int, int, int, int, int, TreeInfo **);
 static struct GadgetInfo *screen_gadget[NUM_SCREEN_GADGETS];
 static int setup_mode = SETUP_MODE_MAIN;
 
-static void drawCursorExt(int pos, int color, int graphic)
+#define mSX (SX + (game_status >= GAME_MODE_MAIN &&    \
+                  game_status <= GAME_MODE_SETUP ?     \
+                  menu.draw_xoffset[game_status] : menu.draw_xoffset_default))
+#define mSY (SY + (game_status >= GAME_MODE_MAIN &&    \
+                  game_status <= GAME_MODE_SETUP ?     \
+                  menu.draw_yoffset[game_status] : menu.draw_yoffset_default))
+
+#define NUM_MENU_ENTRIES_ON_SCREEN (menu.list_size[game_status] > 2 ?  \
+                                   menu.list_size[game_status] :       \
+                                   MAX_MENU_ENTRIES_ON_SCREEN)
+
+#if defined(TARGET_X11_NATIVE_PERFORMANCE_WORKAROUND)
+#define NUM_SCROLLBAR_BITMAPS          2
+static Bitmap *scrollbar_bitmap[NUM_SCROLLBAR_BITMAPS];
+#endif
+
+
+static void drawCursorExt(int xpos, int ypos, int color, int graphic)
 {
   static int cursor_array[SCR_FIELDY];
 
-  if (graphic)
-    cursor_array[pos] = graphic;
-
-  graphic = cursor_array[pos];
+  if (xpos == 0)
+  {
+    if (graphic != 0)
+      cursor_array[ypos] = graphic;
+    else
+      graphic = cursor_array[ypos];
+  }
 
   if (color == FC_RED)
-    graphic = (graphic == GFX_ARROW_BLUE_LEFT  ? GFX_ARROW_RED_LEFT  :
-              graphic == GFX_ARROW_BLUE_RIGHT ? GFX_ARROW_RED_RIGHT :
-              GFX_KUGEL_ROT);
+    graphic = (graphic == IMG_MENU_BUTTON_LEFT  ? IMG_MENU_BUTTON_LEFT_ACTIVE :
+              graphic == IMG_MENU_BUTTON_RIGHT ? IMG_MENU_BUTTON_RIGHT_ACTIVE:
+              IMG_MENU_BUTTON_ACTIVE);
+
+  ypos += MENU_SCREEN_START_YPOS;
 
-  DrawGraphic(0, MENU_SCREEN_START_YPOS + pos, graphic);
+  DrawBackground(mSX + xpos * TILEX, mSY + ypos * TILEY, TILEX, TILEY);
+  DrawGraphicThruMaskExt(drawto, mSX + xpos * TILEX, mSY + ypos * TILEY,
+                        graphic, 0);
 }
 
-static void initCursor(int pos, int graphic)
+static void initCursor(int ypos, int graphic)
 {
-  drawCursorExt(pos, FC_BLUE, graphic);
+  drawCursorExt(0, ypos, FC_BLUE, graphic);
 }
 
-static void drawCursor(int pos, int color)
+static void drawCursor(int ypos, int color)
 {
-  drawCursorExt(pos, color, 0);
+  drawCursorExt(0, ypos, color, 0);
+}
+
+static void drawCursorXY(int xpos, int ypos, int graphic)
+{
+  drawCursorExt(xpos, ypos, -1, graphic);
+}
+
+static void drawChooseTreeCursor(int ypos, int color)
+{
+  int last_game_status = game_status;  /* save current game status */
+
+  /* force LEVELS draw offset on artwork setup screen */
+  game_status = GAME_MODE_LEVELS;
+
+  drawCursorExt(0, ypos, color, 0);
+
+  game_status = last_game_status;      /* restore current game status */
+}
+
+static void PlaySound_Menu_Start(int sound)
+{
+  if (sound_info[sound].loop)
+    PlaySoundLoop(sound);
+  else
+    PlaySound(sound);
+}
+
+static void PlaySound_Menu_Continue(int sound)
+{
+  if (sound_info[sound].loop)
+    PlaySoundLoop(sound);
 }
 
 void DrawHeadline()
 {
-  int x = SX + (SXSIZE - strlen(PROGRAM_TITLE_STRING) * FONT1_XSIZE) / 2;
+  int font1_width = getFontWidth(FONT_TITLE_1);
+  int font2_width = getFontWidth(FONT_TITLE_2);
+  int x1 = SX + (SXSIZE - strlen(PROGRAM_TITLE_STRING)   * font1_width) / 2;
+  int x2 = SX + (SXSIZE - strlen(WINDOW_SUBTITLE_STRING) * font2_width) / 2;
 
-  DrawText(x, SY + 8, PROGRAM_TITLE_STRING, FS_BIG, FC_YELLOW);
-  DrawTextFCentered(46, FC_RED, WINDOW_SUBTITLE_STRING);
+  DrawText(x1, SY + 8,  PROGRAM_TITLE_STRING,   FONT_TITLE_1);
+  DrawText(x2, SY + 46, WINDOW_SUBTITLE_STRING, FONT_TITLE_2);
 }
 
 static void ToggleFullscreenIfNeeded()
@@ -110,7 +169,7 @@ static void ToggleFullscreenIfNeeded()
   if (setup.fullscreen != video.fullscreen_enabled)
   {
     /* save old door content */
-    BlitBitmap(backbuffer, pix[PIX_DB_DOOR],
+    BlitBitmap(backbuffer, bitmap_db_door,
               DX, DY, DXSIZE, DYSIZE, DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
 
     /* toggle fullscreen */
@@ -118,10 +177,11 @@ static void ToggleFullscreenIfNeeded()
     setup.fullscreen = video.fullscreen_enabled;
 
     /* redraw background to newly created backbuffer */
-    BlitBitmap(pix[PIX_BACK], backbuffer, 0,0, WIN_XSIZE,WIN_YSIZE, 0,0);
+    BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, backbuffer,
+              0,0, WIN_XSIZE,WIN_YSIZE, 0,0);
 
     /* restore old door content */
-    BlitBitmap(pix[PIX_DB_DOOR], backbuffer,
+    BlitBitmap(bitmap_db_door, backbuffer,
               DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE, DX, DY);
 
     redraw_mask = REDRAW_ALL;
@@ -131,20 +191,27 @@ static void ToggleFullscreenIfNeeded()
 void DrawMainMenu()
 {
   static LevelDirTree *leveldir_last_valid = NULL;
-  int i;
   char *name_text = (!options.network && setup.team_mode ? "Team:" : "Name:");
+  int font_width = getFontWidth(FONT_MENU_1);
+  int name_width = font_width * strlen("Name:");
+  int level_width = font_width * strlen("Level:");
+  int i;
 
   UnmapAllGadgets();
   FadeSounds();
+
   KeyboardAutoRepeatOn();
   ActivateJoystick();
+
   SetDrawDeactivationMask(REDRAW_NONE);
+  SetDrawBackgroundMask(REDRAW_FIELD);
+
   audio.sound_deactivated = FALSE;
 
   /* needed if last screen was the playing screen, invoked from level editor */
   if (level_editor_test_game)
   {
-    game_status = LEVELED;
+    game_status = GAME_MODE_EDITOR;
     DrawLevelEd();
     return;
   }
@@ -155,6 +222,13 @@ void DrawMainMenu()
   /* needed if last screen was the setup screen and fullscreen state changed */
   ToggleFullscreenIfNeeded();
 
+  /* leveldir_current may be invalid (level group, parent link) */
+  if (!validLevelSeries(leveldir_current))
+    leveldir_current = getFirstValidTreeInfoEntry(leveldir_last_valid);
+
+  /* store valid level series information */
+  leveldir_last_valid = leveldir_current;
+
   /* needed if last screen (level choice) changed graphics, sounds or music */
   ReloadCustomArtwork();
 
@@ -165,13 +239,6 @@ void DrawMainMenu()
   /* map gadgets for main menu screen */
   MapTapeButtons();
 
-  /* leveldir_current may be invalid (level group, parent link) */
-  if (!validLevelSeries(leveldir_current))
-    leveldir_current = getFirstValidTreeInfoEntry(leveldir_last_valid);
-
-  /* store valid level series information */
-  leveldir_last_valid = leveldir_current;
-
   /* 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;
@@ -179,49 +246,44 @@ void DrawMainMenu()
   GetPlayerConfig();
   LoadLevel(level_nr);
 
+  SetMainBackgroundImage(IMG_BACKGROUND_MAIN);
   ClearWindow();
+
   DrawHeadline();
-  DrawText(SX + 32,    SY + 2*32, name_text, FS_BIG, FC_GREEN);
-  DrawText(SX + 6*32,  SY + 2*32, setup.player_name, FS_BIG, FC_RED);
-  DrawText(SX + 32,    SY + 3*32, "Level:", FS_BIG, FC_GREEN);
-  DrawText(SX + 11*32, SY + 3*32, int2str(level_nr,3), FS_BIG,
-          (leveldir_current->readonly ? FC_RED : FC_YELLOW));
-  DrawText(SX + 32,    SY + 4*32, "Hall Of Fame", FS_BIG, FC_GREEN);
-  DrawText(SX + 32,    SY + 5*32, "Level Creator", FS_BIG, FC_GREEN);
-  DrawText(SY + 32,    SY + 6*32, "Info Screen", FS_BIG, FC_GREEN);
-  DrawText(SX + 32,    SY + 7*32, "Start Game", FS_BIG, FC_GREEN);
-  DrawText(SX + 32,    SY + 8*32, "Setup", FS_BIG, FC_GREEN);
-  DrawText(SX + 32,    SY + 9*32, "Quit", FS_BIG, FC_GREEN);
+
+  DrawText(mSX + 32, mSY + 2*32, name_text, FONT_MENU_1);
+  DrawText(mSX + 32, mSY + 3*32, "Level:", FONT_MENU_1);
+  DrawText(mSX + 32, mSY + 4*32, "Hall Of Fame", FONT_MENU_1);
+  DrawText(mSX + 32, mSY + 5*32, "Level Creator", FONT_MENU_1);
+  DrawText(mSX + 32, mSY + 6*32, "Info Screen", FONT_MENU_1);
+  DrawText(mSX + 32, mSY + 7*32, "Start Game", FONT_MENU_1);
+  DrawText(mSX + 32, mSY + 8*32, "Setup", FONT_MENU_1);
+  DrawText(mSX + 32, mSY + 9*32, "Quit", FONT_MENU_1);
+
+  DrawText(mSX + 32 + name_width, mSY + 2*32, setup.player_name, FONT_INPUT_1);
+  DrawText(mSX + level_width + 5 * 32, mSY + 3*32, int2str(level_nr,3),
+          FONT_VALUE_1);
 
   DrawMicroLevel(MICROLEV_XPOS, MICROLEV_YPOS, TRUE);
 
-  DrawTextF(7*32 + 6, 3*32 + 9, FC_RED, "%d-%d",
-           leveldir_current->first_level,
-           leveldir_current->last_level);
+  DrawTextF(mSX + 32 + level_width - 2, mSY + 3*32 + 1, FONT_TEXT_3, "%d-%d",
+           leveldir_current->first_level, leveldir_current->last_level);
 
   if (leveldir_current->readonly)
   {
-    DrawTextF(15*32 + 6, 3*32 + 9 - 7, FC_RED, "READ");
-    DrawTextF(15*32 + 6, 3*32 + 9 + 7, FC_RED, "ONLY");
+    DrawTextF(mSX + level_width + 9 * 32 - 2,
+             mSY + 3 * 32 + 1 - 7, FONT_TEXT_3, "READ");
+    DrawTextF(mSX + level_width + 9 * 32 - 2,
+             mSY + 3 * 32 + 1 + 7, FONT_TEXT_3, "ONLY");
   }
 
   for(i=0; i<8; i++)
-    initCursor(i, (i == 1 || i == 6 ? GFX_ARROW_BLUE_RIGHT : GFX_KUGEL_BLAU));
-
-  DrawGraphic(10, 3, GFX_ARROW_BLUE_LEFT);
-  DrawGraphic(14, 3, GFX_ARROW_BLUE_RIGHT);
-
-  DrawText(SX + 56, SY + 326, "A Game by Artsoft Entertainment",
-          FS_SMALL, FC_RED);
+    initCursor(i, (i == 1 || i == 6 ? IMG_MENU_BUTTON_RIGHT :IMG_MENU_BUTTON));
 
-  if (leveldir_current->name)
-  {
-    int len = strlen(leveldir_current->name);
-    int lxpos = SX + (SXSIZE - len * FONT4_XSIZE) / 2;
-    int lypos = SY + 352;
+  drawCursorXY(level_width/32 + 4, 1, IMG_MENU_BUTTON_LEFT);
+  drawCursorXY(level_width/32 + 8, 1, IMG_MENU_BUTTON_RIGHT);
 
-    DrawText(lxpos, lypos, leveldir_current->name, FS_SMALL, FC_SPECIAL2);
-  }
+  DrawText(SX + 56, SY + 326, "A Game by Artsoft Entertainment", FONT_TITLE_2);
 
   FadeToFront();
   InitAnimation();
@@ -252,10 +314,10 @@ static void gotoTopLevelDir()
       int num_page_entries;
       int cl_first, cl_cursor;
 
-      if (num_leveldirs <= MAX_MENU_ENTRIES_ON_SCREEN)
+      if (num_leveldirs <= NUM_MENU_ENTRIES_ON_SCREEN)
        num_page_entries = num_leveldirs;
       else
-       num_page_entries = MAX_MENU_ENTRIES_ON_SCREEN - 1;
+       num_page_entries = NUM_MENU_ENTRIES_ON_SCREEN;
 
       cl_first = MAX(0, leveldir_pos - num_page_entries + 1);
       cl_cursor = leveldir_pos - cl_first;
@@ -282,8 +344,8 @@ void HandleMainMenu(int mx, int my, int dx, int dy, int button)
 
   if (mx || my)                /* mouse input */
   {
-    x = (mx - SX) / 32;
-    y = (my - SY) / 32 - MENU_SCREEN_START_YPOS;
+    x = (mx - mSX) / 32;
+    y = (my - mSY) / 32 - MENU_SCREEN_START_YPOS;
   }
   else if (dx || dy)   /* keyboard input */
   {
@@ -300,7 +362,6 @@ void HandleMainMenu(int mx, int my, int dx, int dy, int button)
     static unsigned long level_delay = 0;
     int step = (button == 1 ? 1 : button == 2 ? 5 : 10);
     int new_level_nr, old_level_nr = level_nr;
-    int font_color = (leveldir_current->readonly ? FC_RED : FC_YELLOW);
 
     new_level_nr = level_nr + (x == 10 ? -step : +step);
     if (new_level_nr < leveldir_current->first_level)
@@ -317,10 +378,7 @@ void HandleMainMenu(int mx, int my, int dx, int dy, int button)
 
     level_nr = new_level_nr;
 
-    DrawTextExt(drawto, SX + 11 * 32, SY + 3 * 32,
-               int2str(level_nr, 3), FS_BIG, font_color);
-    DrawTextExt(window, SX + 11 * 32, SY + 3 * 32,
-               int2str(level_nr, 3), FS_BIG, font_color);
+    DrawText(mSX + 11 * 32, mSY + 3 * 32, int2str(level_nr, 3), FONT_VALUE_1);
 
     LoadLevel(level_nr);
     DrawMicroLevel(MICROLEV_XPOS, MICROLEV_YPOS, TRUE);
@@ -349,14 +407,14 @@ void HandleMainMenu(int mx, int my, int dx, int dy, int button)
     {
       if (y == 0)
       {
-       game_status = TYPENAME;
+       game_status = GAME_MODE_PSEUDO_TYPENAME;
        HandleTypeName(strlen(setup.player_name), 0);
       }
       else if (y == 1)
       {
        if (leveldir_first)
        {
-         game_status = CHOOSELEVEL;
+         game_status = GAME_MODE_LEVELS;
          SaveLevelSetup_LastSeries();
          SaveLevelSetup_SeriesInfo();
 
@@ -367,7 +425,7 @@ void HandleMainMenu(int mx, int my, int dx, int dy, int button)
       }
       else if (y == 2)
       {
-       game_status = HALLOFFAME;
+       game_status = GAME_MODE_SCORES;
        DrawHallOfFame(-1);
       }
       else if (y == 3)
@@ -375,12 +433,12 @@ void HandleMainMenu(int mx, int my, int dx, int dy, int button)
        if (leveldir_current->readonly &&
            strcmp(setup.player_name, "Artsoft") != 0)
          Request("This level is read only !", REQ_CONFIRM);
-       game_status = LEVELED;
+       game_status = GAME_MODE_EDITOR;
        DrawLevelEd();
       }
       else if (y == 4)
       {
-       game_status = HELPSCREEN;
+       game_status = GAME_MODE_INFO;
        DrawHelpScreen();
       }
       else if (y == 5)
@@ -394,14 +452,14 @@ void HandleMainMenu(int mx, int my, int dx, int dy, int button)
        else
 #endif
        {
-         game_status = PLAYING;
+         game_status = GAME_MODE_PLAYING;
          StopAnimation();
          InitGame();
        }
       }
       else if (y == 6)
       {
-       game_status = SETUP;
+       game_status = GAME_MODE_SETUP;
        setup_mode = SETUP_MODE_MAIN;
        DrawSetupScreen();
       }
@@ -410,7 +468,7 @@ void HandleMainMenu(int mx, int my, int dx, int dy, int button)
        SaveLevelSetup_LastSeries();
        SaveLevelSetup_SeriesInfo();
         if (Request("Do you really want to quit ?", REQ_ASK | REQ_STAY_CLOSED))
-         game_status = EXITGAME;
+         game_status = GAME_MODE_QUIT;
       }
     }
   }
@@ -419,7 +477,7 @@ void HandleMainMenu(int mx, int my, int dx, int dy, int button)
 
   out:
 
-  if (game_status == MAINMENU)
+  if (game_status == GAME_MODE_MAIN)
   {
     DrawMicroLevel(MICROLEV_XPOS, MICROLEV_YPOS, FALSE);
     DoAnimation();
@@ -434,113 +492,214 @@ void HandleMainMenu(int mx, int my, int dx, int dy, int button)
 static long helpscreen_state;
 static int helpscreen_step[MAX_HELPSCREEN_ELS];
 static int helpscreen_frame[MAX_HELPSCREEN_ELS];
-static int helpscreen_delay[MAX_HELPSCREEN_ELS];
+
 static int helpscreen_action[] =
 {
-  GFX_SPIELER1_DOWN,4,2,
-  GFX_SPIELER1_UP,4,2,
-  GFX_SPIELER1_LEFT,4,2,
-  GFX_SPIELER1_RIGHT,4,2,
-  GFX_SPIELER1_PUSH_LEFT,4,2,
-  GFX_SPIELER1_PUSH_RIGHT,4,2,                                 HA_NEXT,
-  GFX_ERDREICH,1,100,                                          HA_NEXT,
-  GFX_LEERRAUM,1,100,                                          HA_NEXT,
-  GFX_MORAST_LEER,1,100,                                       HA_NEXT,
-  GFX_BETON,1,100,                                             HA_NEXT,
-  GFX_MAUERWERK,1,100,                                         HA_NEXT,
-  GFX_MAUER_L1,  3,4, GFX_MAUERWERK,1,20, GFX_LEERRAUM,1,10,
-  GFX_MAUER_R1,  3,4, GFX_MAUERWERK,1,20, GFX_LEERRAUM,1,10,
-  GFX_MAUER_UP,  3,4, GFX_MAUERWERK,1,20, GFX_LEERRAUM,1,10,
-  GFX_MAUER_DOWN,3,4, GFX_MAUERWERK,1,20, GFX_LEERRAUM,1,10,   HA_NEXT,
-  GFX_UNSICHTBAR,1,100,                                                HA_NEXT,
-  GFX_FELSBODEN,1,100,                                         HA_NEXT,
-  GFX_CHAR_A,30,4, GFX_CHAR_AUSRUF,32,4,                       HA_NEXT,
-  GFX_EDELSTEIN,2,5,                                           HA_NEXT,
-  GFX_DIAMANT,2,5,                                             HA_NEXT,
-  GFX_EDELSTEIN_BD,2,5,                                                HA_NEXT,
-  GFX_EDELSTEIN_GELB,2,5, GFX_EDELSTEIN_ROT,2,5,
-  GFX_EDELSTEIN_LILA,2,5,                                      HA_NEXT,
-  GFX_FELSBROCKEN,4,5,                                         HA_NEXT,
-  GFX_BOMBE,1,50, GFX_EXPLOSION,8,1, GFX_LEERRAUM,1,10,                HA_NEXT,
-  GFX_KOKOSNUSS,1,50, GFX_CRACKINGNUT,3,1, GFX_EDELSTEIN,1,10, HA_NEXT,
-  GFX_ERZ_EDEL,1,50, GFX_EXPLOSION,8,1, GFX_EDELSTEIN,1,10,    HA_NEXT,
-  GFX_ERZ_DIAM,1,50, GFX_EXPLOSION,8,1, GFX_DIAMANT,1,10,      HA_NEXT,
-  GFX_ERZ_EDEL_BD,1,50, GFX_EXPLOSION,8,1,GFX_EDELSTEIN_BD,1,10,HA_NEXT,
-  GFX_ERZ_EDEL_GELB,1,50, GFX_EXPLOSION,8,1,
-  GFX_EDELSTEIN_GELB,1,10, GFX_ERZ_EDEL_ROT,1,50,
-  GFX_EXPLOSION,8,1, GFX_EDELSTEIN_ROT,1,10,
-  GFX_ERZ_EDEL_LILA,1,50, GFX_EXPLOSION,8,1,
-  GFX_EDELSTEIN_LILA,1,10,                                     HA_NEXT,
-  GFX_GEBLUBBER,4,4,                                           HA_NEXT,
-  GFX_SCHLUESSEL1,4,25,                                                HA_NEXT,
-  GFX_PFORTE1,4,25,                                            HA_NEXT,
-  GFX_PFORTE1X,4,25,                                           HA_NEXT,
-  GFX_DYNAMIT_AUS,1,100,                                       HA_NEXT,
-  GFX_DYNAMIT,7,6, GFX_EXPLOSION,8,1, GFX_LEERRAUM,1,10,       HA_NEXT,
-  GFX_DYNABOMB+0,4,3, GFX_DYNABOMB+3,1,3, GFX_DYNABOMB+2,1,3,
-  GFX_DYNABOMB+1,1,3, GFX_DYNABOMB+0,1,3, GFX_EXPLOSION,8,1,
-  GFX_LEERRAUM,1,10,                                           HA_NEXT,
-  GFX_DYNABOMB_NR,1,100,                                       HA_NEXT,
-  GFX_DYNABOMB_SZ,1,100,                                       HA_NEXT,
-  GFX_FLIEGER+4,1,3, GFX_FLIEGER+0,1,3, GFX_FLIEGER+4,1,3,
-  GFX_FLIEGER+5,1,3, GFX_FLIEGER+1,1,3, GFX_FLIEGER+5,1,3,
-  GFX_FLIEGER+6,1,3, GFX_FLIEGER+2,1,3, GFX_FLIEGER+6,1,3,
-  GFX_FLIEGER+7,1,3, GFX_FLIEGER+3,1,3, GFX_FLIEGER+7,1,3,     HA_NEXT,
-  GFX_KAEFER+4,1,1, GFX_KAEFER+0,1,1, GFX_KAEFER+4,1,1,
-  GFX_KAEFER+5,1,1, GFX_KAEFER+1,1,1, GFX_KAEFER+5,1,1,
-  GFX_KAEFER+6,1,1, GFX_KAEFER+2,1,1, GFX_KAEFER+6,1,1,
-  GFX_KAEFER+7,1,1, GFX_KAEFER+3,1,1, GFX_KAEFER+7,1,1,                HA_NEXT,
-  GFX_BUTTERFLY,2,2,                                           HA_NEXT,
-  GFX_FIREFLY,2,2,                                             HA_NEXT,
-  GFX_PACMAN+0,1,3, GFX_PACMAN+4,1,2, GFX_PACMAN+0,1,3,
-  GFX_PACMAN+1,1,3, GFX_PACMAN+5,1,2, GFX_PACMAN+1,1,3,
-  GFX_PACMAN+2,1,3, GFX_PACMAN+6,1,2, GFX_PACMAN+2,1,3,
-  GFX_PACMAN+3,1,3, GFX_PACMAN+7,1,2, GFX_PACMAN+3,1,3,                HA_NEXT,
-  GFX_MAMPFER+0,4,1, GFX_MAMPFER+3,1,1, GFX_MAMPFER+2,1,1,
-  GFX_MAMPFER+1,1,1, GFX_MAMPFER+0,1,1,                                HA_NEXT,
-  GFX_MAMPFER2+0,4,1, GFX_MAMPFER2+3,1,1, GFX_MAMPFER2+2,1,1,
-  GFX_MAMPFER2+1,1,1, GFX_MAMPFER2+0,1,1,                      HA_NEXT,
-  GFX_ROBOT+0,4,1, GFX_ROBOT+3,1,1, GFX_ROBOT+2,1,1,
-  GFX_ROBOT+1,1,1, GFX_ROBOT+0,1,1,                            HA_NEXT,
-  GFX_MOLE_DOWN,4,2,
-  GFX_MOLE_UP,4,2,
-  GFX_MOLE_LEFT,4,2,
-  GFX_MOLE_RIGHT,4,2,                                          HA_NEXT,
-  GFX_PINGUIN_DOWN,4,2,
-  GFX_PINGUIN_UP,4,2,
-  GFX_PINGUIN_LEFT,4,2,
-  GFX_PINGUIN_RIGHT,4,2,                                       HA_NEXT,
-  GFX_SCHWEIN_DOWN,4,2,
-  GFX_SCHWEIN_UP,4,2,
-  GFX_SCHWEIN_LEFT,4,2,
-  GFX_SCHWEIN_RIGHT,4,2,                                       HA_NEXT,
-  GFX_DRACHE_DOWN,4,2,
-  GFX_DRACHE_UP,4,2,
-  GFX_DRACHE_LEFT,4,2,
-  GFX_DRACHE_RIGHT,4,2,                                                HA_NEXT,
-  GFX_SONDE_START,8,1,                                         HA_NEXT,
-  GFX_ABLENK,4,1,                                              HA_NEXT,
-  GFX_BIRNE_AUS,1,25, GFX_BIRNE_EIN,1,25,                      HA_NEXT,
-  GFX_ZEIT_VOLL,1,25, GFX_ZEIT_LEER,1,25,                      HA_NEXT,
-  GFX_TROPFEN,1,25, GFX_AMOEBING,4,1, GFX_AMOEBE_LEBT,1,10,    HA_NEXT,
-  GFX_AMOEBE_TOT+2,2,50, GFX_AMOEBE_TOT,2,50,                  HA_NEXT,
-  GFX_AMOEBE_LEBT,4,40,                                                HA_NEXT,
-  GFX_AMOEBE_LEBT,1,10,        GFX_AMOEBING,4,2,                       HA_NEXT,
-  GFX_AMOEBE_LEBT,1,25, GFX_AMOEBE_TOT,1,25, GFX_EXPLOSION,8,1,
-  GFX_DIAMANT,1,10,                                            HA_NEXT,
-  GFX_LIFE,1,100,                                              HA_NEXT,
-  GFX_LIFE_ASYNC,1,100,                                                HA_NEXT,
-  GFX_MAGIC_WALL_OFF,4,2,                                      HA_NEXT,
-  GFX_MAGIC_WALL_BD_OFF,4,2,                                   HA_NEXT,
-  GFX_AUSGANG_ZU,1,100, GFX_AUSGANG_ACT,4,2,
-  GFX_AUSGANG_AUF+0,4,2, GFX_AUSGANG_AUF+3,1,2,
-  GFX_AUSGANG_AUF+2,1,2, GFX_AUSGANG_AUF+1,1,2,                        HA_NEXT,
-  GFX_AUSGANG_AUF+0,4,2, GFX_AUSGANG_AUF+3,1,2,
-  GFX_AUSGANG_AUF+2,1,2, GFX_AUSGANG_AUF+1,1,2,                        HA_NEXT,
-  GFX_SOKOBAN_OBJEKT,1,100,                                    HA_NEXT,
-  GFX_SOKOBAN_FELD_LEER,1,100,                                 HA_NEXT,
-  GFX_SOKOBAN_FELD_VOLL,1,100,                                 HA_NEXT,
-  GFX_SPEED_PILL,1,100,                                                HA_NEXT,
+  IMG_PLAYER_1_MOVING_DOWN,            16,
+  IMG_PLAYER_1_MOVING_UP,              16,
+  IMG_PLAYER_1_MOVING_LEFT,            16,
+  IMG_PLAYER_1_MOVING_RIGHT,           16,
+  IMG_PLAYER_1_PUSHING_LEFT,           16,
+  IMG_PLAYER_1_PUSHING_RIGHT,          16,                     HA_NEXT,
+
+  IMG_SAND,                            -1,                     HA_NEXT,
+
+  IMG_EMPTY_SPACE,                     -1,                     HA_NEXT,
+
+  IMG_QUICKSAND_EMPTY,                 -1,                     HA_NEXT,
+
+  IMG_STEELWALL,                       -1,                     HA_NEXT,
+
+  IMG_WALL,                            -1,                     HA_NEXT,
+
+  IMG_EXPANDABLE_WALL_GROWING_LEFT,    20,
+  IMG_WALL,                            50,
+  IMG_EMPTY_SPACE,                     20,
+  IMG_EXPANDABLE_WALL_GROWING_RIGHT,   20,
+  IMG_WALL,                            50,
+  IMG_EMPTY_SPACE,                     20,
+  IMG_EXPANDABLE_WALL_GROWING_UP,      20,
+  IMG_WALL,                            50,
+  IMG_EMPTY_SPACE,                     20,
+  IMG_EXPANDABLE_WALL_GROWING_DOWN,    20,
+  IMG_WALL,                            50,
+  IMG_EMPTY_SPACE,                     20,                     HA_NEXT,
+
+  IMG_INVISIBLE_WALL,                  -1,                     HA_NEXT,
+
+  IMG_WALL_SLIPPERY,                   -1,                     HA_NEXT,
+
+  IMG_FONT_GAME_INFO,                  -1,                     HA_NEXT,
+
+  IMG_EMERALD,                         -1,                     HA_NEXT,
+
+  IMG_DIAMOND,                         -1,                     HA_NEXT,
+
+  IMG_BD_DIAMOND,                      -1,                     HA_NEXT,
+
+  IMG_EMERALD_YELLOW,                  50,
+  IMG_EMERALD_RED,                     50,
+  IMG_EMERALD_PURPLE,                  50,                     HA_NEXT,
+
+  IMG_BD_ROCK,                         -1,                     HA_NEXT,
+
+  IMG_BOMB,                            100,
+  IMG_EXPLOSION,                       16,
+  IMG_EMPTY_SPACE,                     10,                     HA_NEXT,
+
+  IMG_NUT,                             100,
+  IMG_NUT_BREAKING,                    6,
+  IMG_EMERALD,                         20,                     HA_NEXT,
+
+  IMG_WALL_EMERALD,                    100,
+  IMG_EXPLOSION,                       16,
+  IMG_EMERALD,                         20,                     HA_NEXT,
+
+  IMG_WALL_DIAMOND,                    100,
+  IMG_EXPLOSION,                       16,
+  IMG_DIAMOND,                         20,                     HA_NEXT,
+
+  IMG_WALL_BD_DIAMOND,                         100,
+  IMG_EXPLOSION,                       16,
+  IMG_BD_DIAMOND,                      20,                     HA_NEXT,
+
+  IMG_WALL_EMERALD_YELLOW,             100,
+  IMG_EXPLOSION,                       16,
+  IMG_EMERALD_YELLOW,                  20,
+  IMG_WALL_EMERALD_RED,                        100,
+  IMG_EXPLOSION,                       16,
+  IMG_EMERALD_RED,                     20,
+  IMG_WALL_EMERALD_PURPLE,             100,
+  IMG_EXPLOSION,                       16,
+  IMG_EMERALD_PURPLE,                  20,                     HA_NEXT,
+
+  IMG_ACID,                            -1,                     HA_NEXT,
+
+  IMG_KEY_1,                           50,
+  IMG_KEY_2,                           50,
+  IMG_KEY_3,                           50,
+  IMG_KEY_4,                           50,                     HA_NEXT,
+
+  IMG_GATE_1,                          50,
+  IMG_GATE_2,                          50,
+  IMG_GATE_3,                          50,
+  IMG_GATE_4,                          50,                     HA_NEXT,
+
+  IMG_GATE_1_GRAY,                     50,
+  IMG_GATE_2_GRAY,                     50,
+  IMG_GATE_3_GRAY,                     50,
+  IMG_GATE_4_GRAY,                     50,                     HA_NEXT,
+
+  IMG_DYNAMITE,                                -1,                     HA_NEXT,
+
+  IMG_DYNAMITE_ACTIVE,                 96,
+  IMG_EXPLOSION,                       16,
+  IMG_EMPTY_SPACE,                     20,                     HA_NEXT,
+
+  IMG_DYNABOMB_ACTIVE,                 100,
+  IMG_EXPLOSION,                       16,
+  IMG_EMPTY_SPACE,                     20,                     HA_NEXT,
+
+  IMG_DYNABOMB_INCREASE_NUMBER,                -1,                     HA_NEXT,
+
+  IMG_DYNABOMB_INCREASE_SIZE,          -1,                     HA_NEXT,
+
+  IMG_DYNABOMB_INCREASE_POWER,         -1,                     HA_NEXT,
+
+  IMG_SPACESHIP_RIGHT,                 16,
+  IMG_SPACESHIP_UP,                    16,
+  IMG_SPACESHIP_LEFT,                  16,
+  IMG_SPACESHIP_DOWN,                  16,                     HA_NEXT,
+
+  IMG_BUG_RIGHT,                       16,
+  IMG_BUG_UP,                          16,
+  IMG_BUG_LEFT,                                16,
+  IMG_BUG_DOWN,                                16,                     HA_NEXT,
+
+  IMG_BD_BUTTERFLY,                    -1,                     HA_NEXT,
+
+  IMG_BD_FIREFLY,                      -1,                     HA_NEXT,
+
+  IMG_PACMAN_RIGHT,                    16,
+  IMG_PACMAN_UP,                       16,
+  IMG_PACMAN_LEFT,                     16,
+  IMG_PACMAN_DOWN,                     16,                     HA_NEXT,
+
+  IMG_YAMYAM,                          -1,                     HA_NEXT,
+
+  IMG_DARK_YAMYAM,                     -1,                     HA_NEXT,
+
+  IMG_ROBOT,                           -1,                     HA_NEXT,
+
+  IMG_MOLE_MOVING_RIGHT,               16,
+  IMG_MOLE_MOVING_UP,                  16,
+  IMG_MOLE_MOVING_LEFT,                        16,
+  IMG_MOLE_MOVING_DOWN,                        16,                     HA_NEXT,
+
+  IMG_PENGUIN_MOVING_RIGHT,            16,
+  IMG_PENGUIN_MOVING_UP,               16,
+  IMG_PENGUIN_MOVING_LEFT,             16,
+  IMG_PENGUIN_MOVING_DOWN,             16,                     HA_NEXT,
+
+  IMG_PIG_MOVING_RIGHT,                        16,
+  IMG_PIG_MOVING_UP,                   16,
+  IMG_PIG_MOVING_LEFT,                 16,
+  IMG_PIG_MOVING_DOWN,                 16,                     HA_NEXT,
+
+  IMG_DRAGON_MOVING_RIGHT,             16,
+  IMG_DRAGON_MOVING_UP,                        16,
+  IMG_DRAGON_MOVING_LEFT,              16,
+  IMG_DRAGON_MOVING_DOWN,              16,                     HA_NEXT,
+
+  IMG_SATELLITE,                       -1,                     HA_NEXT,
+
+  IMG_ROBOT_WHEEL,                     50,
+  IMG_ROBOT_WHEEL_ACTIVE,              100,                    HA_NEXT,
+
+  IMG_LAMP,                            50,
+  IMG_LAMP_ACTIVE,                     50,                     HA_NEXT,
+
+  IMG_TIME_ORB_FULL,                   50,
+  IMG_TIME_ORB_EMPTY,                  50,                     HA_NEXT,
+
+  IMG_AMOEBA_DROP,                     50,
+  IMG_AMOEBA_GROWING,                  6,
+  IMG_AMOEBA_WET,                      20,                     HA_NEXT,
+
+  IMG_AMOEBA_DEAD,                     -1,                     HA_NEXT,
+
+  IMG_AMOEBA_WET,                      -1,                     HA_NEXT,
+
+  IMG_AMOEBA_WET,                      100,
+  IMG_AMOEBA_GROWING,                  6,                      HA_NEXT,
+
+  IMG_AMOEBA_FULL,                     50,
+  IMG_AMOEBA_DEAD,                     50,
+  IMG_EXPLOSION,                       16,
+  IMG_DIAMOND,                         20,                     HA_NEXT,
+
+  IMG_GAME_OF_LIFE,                    -1,                     HA_NEXT,
+
+  IMG_BIOMAZE,                         -1,                     HA_NEXT,
+
+  IMG_MAGIC_WALL_ACTIVE,               -1,                     HA_NEXT,
+
+  IMG_BD_MAGIC_WALL_ACTIVE,            -1,                     HA_NEXT,
+
+  IMG_EXIT_CLOSED,                     200,
+  IMG_EXIT_OPENING,                    16,
+  IMG_EXIT_OPEN,                       100,                    HA_NEXT,
+
+  IMG_EXIT_OPEN,                       -1,                     HA_NEXT,
+
+  IMG_SOKOBAN_OBJECT,                  -1,                     HA_NEXT,
+
+  IMG_SOKOBAN_FIELD_EMPTY,             -1,                     HA_NEXT,
+
+  IMG_SOKOBAN_FIELD_FULL,              -1,                     HA_NEXT,
+
+  IMG_SPEED_PILL,                      -1,                     HA_NEXT,
+
   HA_END
 };
 static char *helpscreen_eltext[][2] =
@@ -548,7 +707,7 @@ static char *helpscreen_eltext[][2] =
  {"THE HERO:",                         "(Is _this_ guy good old Rockford?)"},
  {"Normal sand:",                      "You can dig through it"},
  {"Empty field:",                      "You can walk through it"},
- {"Quicksand: You cannot pass it,",    "but rocks can fall though it"},
+ {"Quicksand: You cannot pass it,",    "but rocks can fall through it"},
  {"Massive Wall:",                     "Nothing can go through it"},
  {"Normal Wall: You can't go through", "it, but you can bomb it away"},
  {"Growing Wall: Grows in several di-",        "rections if there is an empty field"},
@@ -575,6 +734,7 @@ static char *helpscreen_eltext[][2] =
  {"Dyna Bomb: Explodes in 4 directions","with variable explosion size"},
  {"Dyna Bomb: Increases the number of",        "dyna bombs available at a time"},
  {"Dyna Bomb: Increases the size of",  "explosion of dyna bombs"},
+ {"Dyna Bomb: Increases the power of", "explosion of dyna bombs"},
  {"Spaceship: Moves at the left side", "of walls; don't touch it!"},
  {"Bug: Moves at the right side",      "of walls; don't touch it!"},
  {"Butterfly: Moves at the right side",        "of walls; don't touch it!"},
@@ -607,7 +767,7 @@ static char *helpscreen_eltext[][2] =
  {"Sokoban element: Field with object", "which can be pushed away"},
  {"Speed pill: Lets the player run",    "twice as fast as normally"},
 };
-static int num_helpscreen_els = sizeof(helpscreen_eltext)/(2*sizeof(char *));
+static int num_helpscreen_els = sizeof(helpscreen_eltext) / (2*sizeof(char *));
 
 static char *helpscreen_music[][3] =
 {
@@ -622,7 +782,8 @@ static char *helpscreen_music[][3] =
 static int num_helpscreen_music = 7;
 static int helpscreen_musicpos;
 
-void DrawHelpScreenElAction(int start)
+#if 0
+void OLD_DrawHelpScreenElAction(int start)
 {
   int i = 0, j = 0;
   int frame, graphic;
@@ -674,7 +835,7 @@ void DrawHelpScreenElAction(int start)
     }
     j++;
 
-    DrawGraphicExt(drawto, xstart, ystart+(i-start)*ystep, graphic+frame);
+    DrawOldGraphicExt(drawto, xstart, ystart+(i-start)*ystep, graphic+frame);
     i++;
   }
 
@@ -684,28 +845,115 @@ void DrawHelpScreenElAction(int start)
     MarkTileDirty(1,i);
   }
 }
+#endif
+
+void DrawHelpScreenElAction(int start)
+{
+  int i = 0, j = 0;
+  int xstart = mSX + 16;
+  int ystart = mSY + 64 + 2 * 32;
+  int ystep = TILEY + 4;
+  int graphic;
+  int frame_count;
+  int sync_frame;
+
+  while (helpscreen_action[j] != HA_END)
+  {
+    if (i >= start + MAX_HELPSCREEN_ELS || i >= num_helpscreen_els)
+      break;
+    else if (i < start)
+    {
+      while (helpscreen_action[j] != HA_NEXT)
+       j++;
+
+      j++;
+      i++;
+
+      continue;
+    }
+
+    j += 2 * helpscreen_step[i-start];
+    graphic = helpscreen_action[j++];
+    frame_count = helpscreen_action[j++];
+    if (frame_count == -1)
+      frame_count = 1000000;
+
+    if (helpscreen_frame[i-start] == 0)
+    {
+      sync_frame = 0;
+      helpscreen_frame[i-start] = frame_count - 1;
+    }
+    else
+    {
+      sync_frame = frame_count - helpscreen_frame[i-start];
+      helpscreen_frame[i-start]--;
+    }
+
+    if (helpscreen_action[j] == HA_NEXT)
+    {
+      if (!helpscreen_frame[i-start])
+       helpscreen_step[i-start] = 0;
+    }
+    else
+    {
+      if (!helpscreen_frame[i-start])
+       helpscreen_step[i-start]++;
+      while(helpscreen_action[j] != HA_NEXT)
+       j++;
+    }
+    j++;
+
+#if 1
+    ClearRectangleOnBackground(drawto, xstart, ystart + (i - start) * ystep,
+                              TILEX, TILEY);
+    DrawGraphicAnimationExt(drawto, xstart, ystart + (i - start) * ystep,
+                           graphic, sync_frame, USE_MASKING);
+#else
+    frame = getGraphicAnimationFrame(graphic, sync_frame);
+
+    DrawGraphicExt(drawto, xstart, ystart + (i-start) * ystep,
+                  graphic, frame);
+#endif
+
+    i++;
+  }
+
+#if 1
+  redraw_mask |= REDRAW_FIELD;
+#else
+  for(i=2; i<16; i++)
+  {
+    MarkTileDirty(0, i);
+    MarkTileDirty(1, i);
+  }
+#endif
+
+  FrameCounter++;
+}
 
 void DrawHelpScreenElText(int start)
 {
   int i;
-  int xstart = SX + 56, ystart = SY + 65 + 2 * 32, ystep = TILEY + 4;
+  int xstart = mSX + 56, ystart = mSY + 65 + 2 * 32, ystep = TILEY + 4;
   int ybottom = SYSIZE - 20;
 
+  SetMainBackgroundImage(IMG_BACKGROUND_INFO);
   ClearWindow();
   DrawHeadline();
 
-  DrawTextFCentered(100, FC_GREEN, "The game elements:");
+  DrawTextFCentered(100, FONT_TEXT_1, "The game elements:");
 
   for(i=start; i < start + MAX_HELPSCREEN_ELS && i < num_helpscreen_els; i++)
   {
     DrawText(xstart,
             ystart + (i - start) * ystep + (*helpscreen_eltext[i][1] ? 0 : 8),
-            helpscreen_eltext[i][0], FS_SMALL, FC_YELLOW);
+            helpscreen_eltext[i][0], FONT_TEXT_2);
     DrawText(xstart, ystart + (i - start) * ystep + 16,
-            helpscreen_eltext[i][1], FS_SMALL, FC_YELLOW);
+            helpscreen_eltext[i][1], FONT_TEXT_2);
   }
 
-  DrawTextFCentered(ybottom, FC_BLUE, "Press any key or button for next page");
+  DrawTextFCentered(ybottom, FONT_TEXT_4,
+                   "Press any key or button for next page");
 }
 
 void DrawHelpScreenMusicText(int num)
@@ -717,22 +965,20 @@ void DrawHelpScreenMusicText(int num)
   ClearWindow();
   DrawHeadline();
 
-  DrawTextFCentered(100, FC_GREEN, "The game background music loops:");
+  DrawTextFCentered(100, FONT_TEXT_1, "The game background music loops:");
 
-  DrawTextFCentered(ystart + 0 * ystep, FC_YELLOW,
-                   "Excerpt from");
-  DrawTextFCentered(ystart + 1 * ystep, FC_RED, "\"%s\"",
-                   helpscreen_music[num][0]);
-  DrawTextFCentered(ystart + 2 * ystep, FC_YELLOW,
-                   "by");
-  DrawTextFCentered(ystart + 3 * ystep, FC_RED,
+  DrawTextFCentered(ystart + 0 * ystep, FONT_TEXT_2, "Excerpt from");
+  DrawTextFCentered(ystart + 1 * ystep, FONT_TEXT_3,
+                   "\"%s\"", helpscreen_music[num][0]);
+  DrawTextFCentered(ystart + 2 * ystep, FONT_TEXT_2, "by");
+  DrawTextFCentered(ystart + 3 * ystep, FONT_TEXT_3,
                    "%s", helpscreen_music[num][1]);
-  DrawTextFCentered(ystart + 4 * ystep, FC_YELLOW,
-                   "from the album");
-  DrawTextFCentered(ystart + 5 * ystep, FC_RED, "\"%s\"",
-                   helpscreen_music[num][2]);
+  DrawTextFCentered(ystart + 4 * ystep, FONT_TEXT_2, "from the album");
+  DrawTextFCentered(ystart + 5 * ystep, FONT_TEXT_3,
+                   "\"%s\"", helpscreen_music[num][2]);
 
-  DrawTextFCentered(ybottom, FC_BLUE, "Press any key or button for next page");
+  DrawTextFCentered(ybottom, FONT_TEXT_4,
+                   "Press any key or button for next page");
 
 #if 0
   PlaySoundLoop(background_loop[num]);
@@ -748,22 +994,17 @@ void DrawHelpScreenCreditsText()
   ClearWindow();
   DrawHeadline();
 
-  DrawTextFCentered(100, FC_GREEN,
-                   "Credits:");
-  DrawTextFCentered(ystart + 0 * ystep, FC_YELLOW,
-                   "DOS port of the game:");
-  DrawTextFCentered(ystart + 1 * ystep, FC_RED,
-                   "Guido Schulz");
-  DrawTextFCentered(ystart + 2 * ystep, FC_YELLOW,
-                   "Additional toons:");
-  DrawTextFCentered(ystart + 3 * ystep, FC_RED,
-                   "Karl Hörnell");
-  DrawTextFCentered(ystart + 5 * ystep, FC_YELLOW,
+  DrawTextFCentered(100, FONT_TEXT_1, "Credits:");
+  DrawTextFCentered(ystart + 0 * ystep, FONT_TEXT_2, "DOS port of the game:");
+  DrawTextFCentered(ystart + 1 * ystep, FONT_TEXT_3, "Guido Schulz");
+  DrawTextFCentered(ystart + 2 * ystep, FONT_TEXT_2, "Additional toons:");
+  DrawTextFCentered(ystart + 3 * ystep, FONT_TEXT_3, "Karl Hörnell");
+  DrawTextFCentered(ystart + 5 * ystep, FONT_TEXT_2,
                    "...and many thanks to all contributors");
-  DrawTextFCentered(ystart + 6 * ystep, FC_YELLOW,
-                   "of new levels!");
+  DrawTextFCentered(ystart + 6 * ystep, FONT_TEXT_2, "of new levels!");
 
-  DrawTextFCentered(ybottom, FC_BLUE, "Press any key or button for next page");
+  DrawTextFCentered(ybottom, FONT_TEXT_4,
+                   "Press any key or button for next page");
 }
 
 void DrawHelpScreenContactText()
@@ -774,33 +1015,34 @@ void DrawHelpScreenContactText()
   ClearWindow();
   DrawHeadline();
 
-  DrawTextFCentered(100, FC_GREEN, "Program information:");
+  DrawTextFCentered(100, FONT_TEXT_1, "Program information:");
 
-  DrawTextFCentered(ystart + 0 * ystep, FC_YELLOW,
+  DrawTextFCentered(ystart + 0 * ystep, FONT_TEXT_2,
                    "This game is Freeware!");
-  DrawTextFCentered(ystart + 1 * ystep, FC_YELLOW,
+  DrawTextFCentered(ystart + 1 * ystep, FONT_TEXT_2,
                    "If you like it, send e-mail to:");
-  DrawTextFCentered(ystart + 2 * ystep, FC_RED,
+  DrawTextFCentered(ystart + 2 * ystep, FONT_TEXT_3,
                    "info@artsoft.org");
-  DrawTextFCentered(ystart + 3 * ystep, FC_YELLOW,
+  DrawTextFCentered(ystart + 3 * ystep, FONT_TEXT_2,
                    "or SnailMail to:");
-  DrawTextFCentered(ystart + 4 * ystep + 0, FC_RED,
+  DrawTextFCentered(ystart + 4 * ystep + 0, FONT_TEXT_3,
                    "Holger Schemel");
-  DrawTextFCentered(ystart + 4 * ystep + 20, FC_RED,
+  DrawTextFCentered(ystart + 4 * ystep + 20, FONT_TEXT_3,
                    "Detmolder Strasse 189");
-  DrawTextFCentered(ystart + 4 * ystep + 40, FC_RED,
+  DrawTextFCentered(ystart + 4 * ystep + 40, FONT_TEXT_3,
                    "33604 Bielefeld");
-  DrawTextFCentered(ystart + 4 * ystep + 60, FC_RED,
+  DrawTextFCentered(ystart + 4 * ystep + 60, FONT_TEXT_3,
                    "Germany");
 
-  DrawTextFCentered(ystart + 7 * ystep, FC_YELLOW,
+  DrawTextFCentered(ystart + 7 * ystep, FONT_TEXT_2,
                    "If you have created new levels,");
-  DrawTextFCentered(ystart + 8 * ystep, FC_YELLOW,
+  DrawTextFCentered(ystart + 8 * ystep, FONT_TEXT_2,
                    "send them to me to include them!");
-  DrawTextFCentered(ystart + 9 * ystep, FC_YELLOW,
+  DrawTextFCentered(ystart + 9 * ystep, FONT_TEXT_2,
                    ":-)");
 
-  DrawTextFCentered(ybottom, FC_BLUE, "Press any key or button for main menu");
+  DrawTextFCentered(ybottom, FONT_TEXT_4,
+                   "Press any key or button for main menu");
 }
 
 void DrawHelpScreen()
@@ -811,15 +1053,21 @@ void DrawHelpScreen()
   CloseDoor(DOOR_CLOSE_2);
 
   for(i=0;i<MAX_HELPSCREEN_ELS;i++)
-    helpscreen_step[i] = helpscreen_frame[i] = helpscreen_delay[i] = 0;
+    helpscreen_step[i] = helpscreen_frame[i] = 0;
   helpscreen_musicpos = 0;
   helpscreen_state = 0;
+
   DrawHelpScreenElText(0);
   DrawHelpScreenElAction(0);
 
   FadeToFront();
   InitAnimation();
-  PlaySoundLoop(SND_MENU_INFO_SCREEN);
+
+#if 0
+  PlaySoundLoop(SND_BACKGROUND_INFO);
+#else
+  PlaySound_Menu_Start(SND_BACKGROUND_INFO);
+#endif
 }
 
 void HandleHelpScreen(int button)
@@ -835,8 +1083,10 @@ void HandleHelpScreen(int button)
     if (helpscreen_state < num_helpscreen_els_pages - 1)
     {
       for(i=0;i<MAX_HELPSCREEN_ELS;i++)
-       helpscreen_step[i] = helpscreen_frame[i] = helpscreen_delay[i] = 0;
+       helpscreen_step[i] = helpscreen_frame[i] = 0;
       helpscreen_state++;
+
+      FrameCounter = 0;
       DrawHelpScreenElText(helpscreen_state * MAX_HELPSCREEN_ELS);
       DrawHelpScreenElAction(helpscreen_state * MAX_HELPSCREEN_ELS);
     }
@@ -861,13 +1111,14 @@ void HandleHelpScreen(int button)
     else
     {
       FadeSounds();
+
+      game_status = GAME_MODE_MAIN;
       DrawMainMenu();
-      game_status = MAINMENU;
     }
   }
   else
   {
-    if (DelayReached(&hs_delay, GAME_FRAME_DELAY * 2))
+    if (DelayReached(&hs_delay, GAME_FRAME_DELAY))
     {
       if (helpscreen_state < num_helpscreen_els_pages)
        DrawHelpScreenElAction(helpscreen_state * MAX_HELPSCREEN_ELS);
@@ -876,7 +1127,11 @@ void HandleHelpScreen(int button)
     /* !!! workaround for playing "music" that is really a sound loop (and
        must therefore periodically be reactivated with the current sound
        engine !!! */
-    PlaySoundLoop(SND_MENU_INFO_SCREEN);
+#if 0
+    PlaySoundLoop(SND_BACKGROUND_INFO);
+#else
+    PlaySound_Menu_Continue(SND_BACKGROUND_INFO);
+#endif
 
     DoAnimation();
   }
@@ -887,12 +1142,18 @@ void HandleHelpScreen(int button)
 void HandleTypeName(int newxpos, Key key)
 {
   static int xpos = 0, ypos = 2;
+  int font_width = getFontWidth(FONT_INPUT_1_ACTIVE);
+  int name_width = getFontWidth(FONT_MENU_1) * strlen("Name:");
+  int startx = mSX + 32 + name_width;
+  int starty = mSY + ypos * 32;
 
   if (newxpos)
   {
     xpos = newxpos;
-    DrawText(SX + 6*32, SY + ypos*32, setup.player_name, FS_BIG, FC_YELLOW);
-    DrawGraphic(xpos + 6, ypos, GFX_KUGEL_ROT);
+
+    DrawText(startx, starty, setup.player_name, FONT_INPUT_1_ACTIVE);
+    DrawText(startx + xpos * font_width, starty, "_", FONT_INPUT_1_ACTIVE);
+
     return;
   }
 
@@ -910,26 +1171,24 @@ void HandleTypeName(int newxpos, Key key)
     setup.player_name[xpos] = ascii;
     setup.player_name[xpos + 1] = 0;
     xpos++;
-    DrawTextExt(drawto, SX + 6*32, SY + ypos*32,
-               setup.player_name, FS_BIG, FC_YELLOW);
-    DrawTextExt(window, SX + 6*32, SY + ypos*32,
-               setup.player_name, FS_BIG, FC_YELLOW);
-    DrawGraphic(xpos + 6, ypos, GFX_KUGEL_ROT);
+
+    DrawText(startx, starty, setup.player_name, FONT_INPUT_1_ACTIVE);
+    DrawText(startx + xpos * font_width, starty, "_", FONT_INPUT_1_ACTIVE);
   }
   else if ((key == KSYM_Delete || key == KSYM_BackSpace) && xpos > 0)
   {
     xpos--;
     setup.player_name[xpos] = 0;
-    DrawGraphic(xpos + 6, ypos, GFX_KUGEL_ROT);
-    DrawGraphic(xpos + 7, ypos, GFX_LEERRAUM);
+
+    DrawText(startx + xpos * font_width, starty, "_ ", FONT_INPUT_1_ACTIVE);
   }
   else if (key == KSYM_Return && xpos > 0)
   {
-    DrawText(SX + 6*32, SY + ypos*32, setup.player_name, FS_BIG, FC_RED);
-    DrawGraphic(xpos + 6, ypos, GFX_LEERRAUM);
+    DrawText(startx, starty, setup.player_name, FONT_INPUT_1);
+    DrawText(startx + xpos * font_width, starty, " ", FONT_INPUT_1_ACTIVE);
 
     SaveSetup();
-    game_status = MAINMENU;
+    game_status = GAME_MODE_MAIN;
   }
 
   BackToFront();
@@ -938,9 +1197,14 @@ void HandleTypeName(int newxpos, Key key)
 static void DrawChooseTree(TreeInfo **ti_ptr)
 {
   UnmapAllGadgets();
+
+  FreeScreenGadgets();
+  CreateScreenGadgets();
+
   CloseDoor(DOOR_CLOSE_2);
 
   ClearWindow();
+
   HandleChooseTree(0,0, 0,0, MB_MENU_INITIALIZE, ti_ptr);
   MapChooseTreeGadgets(*ti_ptr);
 
@@ -954,13 +1218,14 @@ static void AdjustChooseTreeScrollbar(int id, int first_entry, TreeInfo *ti)
   int items_max, items_visible, item_position;
 
   items_max = numTreeInfoInGroup(ti);
-  items_visible = MAX_MENU_ENTRIES_ON_SCREEN - 1;
+  items_visible = NUM_MENU_ENTRIES_ON_SCREEN;
   item_position = first_entry;
 
   if (item_position > items_max - items_visible)
     item_position = items_max - items_visible;
 
   ModifyGadget(gi, GDI_SCROLLBAR_ITEMS_MAX, items_max,
+              GDI_SCROLLBAR_ITEMS_VISIBLE, items_visible,
               GDI_SCROLLBAR_ITEM_POSITION, item_position, GDI_END);
 }
 
@@ -970,11 +1235,14 @@ static void drawChooseTreeList(int first_entry, int num_page_entries,
   int i;
   char buffer[SCR_FIELDX * 2];
   int max_buffer_len = (SCR_FIELDX - 2) * 2;
-  int num_entries = numTreeInfoInGroup(ti);
   char *title_string = NULL;
-  int offset = (ti->type == TREE_TYPE_LEVEL_DIR ? 0 : 16);
+  int xoffset_setup = 16;
+  int yoffset_setup = 16;
+  int xoffset = (ti->type == TREE_TYPE_LEVEL_DIR ? 0 : xoffset_setup);
+  int yoffset = (ti->type == TREE_TYPE_LEVEL_DIR ? 0 : yoffset_setup);
+  int last_game_status = game_status;  /* save current game status */
 
-  ClearRectangle(backbuffer, SX, SY, SXSIZE - 32, SYSIZE);
+  DrawBackground(SX, SY, SXSIZE - 32, SYSIZE);
   redraw_mask |= REDRAW_FIELD;
 
   title_string =
@@ -983,8 +1251,10 @@ static void drawChooseTreeList(int first_entry, int num_page_entries,
      ti->type == TREE_TYPE_SOUNDS_DIR ? "Custom Sounds" :
      ti->type == TREE_TYPE_MUSIC_DIR ? "Custom Music" : "");
 
-  DrawText(SX + offset, SY + offset, title_string, FS_BIG,
-          (ti->type == TREE_TYPE_LEVEL_DIR ? FC_GREEN : FC_YELLOW));
+  DrawText(SX + xoffset, SY + yoffset, title_string, FONT_TITLE_1);
+
+  /* force LEVELS font on artwork setup screen */
+  game_status = GAME_MODE_LEVELS;
 
   for(i=0; i<num_page_entries; i++)
   {
@@ -998,21 +1268,17 @@ static void drawChooseTreeList(int first_entry, int num_page_entries,
     strncpy(buffer, node->name , max_buffer_len);
     buffer[max_buffer_len] = '\0';
 
-    DrawText(SX + 32, SY + ypos * 32, buffer, FS_MEDIUM, node->color);
+    DrawText(mSX + 32, mSY + ypos * 32, buffer, FONT_TEXT_1 + node->color);
 
     if (node->parent_link)
-      initCursor(i, GFX_ARROW_BLUE_LEFT);
+      initCursor(i, IMG_MENU_BUTTON_LEFT);
     else if (node->level_group)
-      initCursor(i, GFX_ARROW_BLUE_RIGHT);
+      initCursor(i, IMG_MENU_BUTTON_RIGHT);
     else
-      initCursor(i, GFX_KUGEL_BLAU);
+      initCursor(i, IMG_MENU_BUTTON);
   }
 
-  if (first_entry > 0)
-    DrawGraphic(0, 1, GFX_ARROW_BLUE_UP);
-
-  if (first_entry + num_page_entries < num_entries)
-    DrawGraphic(0, MAX_MENU_ENTRIES_ON_SCREEN + 1, GFX_ARROW_BLUE_DOWN);
+  game_status = last_game_status;      /* restore current game status */
 }
 
 static void drawChooseTreeInfo(int entry_pos, TreeInfo *ti)
@@ -1026,14 +1292,16 @@ static void drawChooseTreeInfo(int entry_pos, TreeInfo *ti)
   node_first = getTreeInfoFirstGroupEntry(ti);
   node = getTreeInfoFromPos(node_first, entry_pos);
 
-  ClearRectangle(drawto, SX + 32, SY + 32, SXSIZE - 64, 32);
+  DrawBackground(SX + 32, SY + 32, SXSIZE - 64, 32);
 
   if (node->parent_link)
-    DrawTextFCentered(40, FC_RED, "leave group \"%s\"", node->class_desc);
+    DrawTextFCentered(40, FONT_TITLE_2, "leave group \"%s\"",
+                     node->class_desc);
   else if (node->level_group)
-    DrawTextFCentered(40, FC_RED, "enter group \"%s\"", node->class_desc);
+    DrawTextFCentered(40, FONT_TITLE_2, "enter group \"%s\"",
+                     node->class_desc);
   else if (ti->type == TREE_TYPE_LEVEL_DIR)
-    DrawTextFCentered(40, FC_RED, "%3d levels (%s)",
+    DrawTextFCentered(40, FONT_TITLE_2, "%3d levels (%s)",
                      node->levels, node->class_desc);
 
   /* let BackToFront() redraw only what is needed */
@@ -1045,28 +1313,42 @@ static void drawChooseTreeInfo(int entry_pos, TreeInfo *ti)
 static void HandleChooseTree(int mx, int my, int dx, int dy, int button,
                             TreeInfo **ti_ptr)
 {
-  static unsigned long choose_delay = 0;
   TreeInfo *ti = *ti_ptr;
   int x = 0;
   int y = ti->cl_cursor;
   int step = (button == 1 ? 1 : button == 2 ? 5 : 10);
   int num_entries = numTreeInfoInGroup(ti);
   int num_page_entries;
+  int last_game_status = game_status;  /* save current game status */
 
-  if (num_entries <= MAX_MENU_ENTRIES_ON_SCREEN)
+  /* force LEVELS draw offset on choose level and artwork setup screen */
+  game_status = GAME_MODE_LEVELS;
+
+  if (num_entries <= NUM_MENU_ENTRIES_ON_SCREEN)
     num_page_entries = num_entries;
   else
-    num_page_entries = MAX_MENU_ENTRIES_ON_SCREEN - 1;
+    num_page_entries = NUM_MENU_ENTRIES_ON_SCREEN;
+
+  game_status = last_game_status;      /* restore current game status */
 
   if (button == MB_MENU_INITIALIZE)
   {
+    int num_entries = numTreeInfoInGroup(ti);
     int entry_pos = posTreeInfo(ti);
 
     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 &&
+             num_entries - ti->cl_first < num_page_entries))
+    {
+      /* only after change of list size (by custom graphic configuration) */
       ti->cl_first = MAX(0, entry_pos - num_page_entries + 1);
-      ti->cl_cursor =
-       entry_pos - ti->cl_first;
+      ti->cl_cursor = entry_pos - ti->cl_first;
     }
 
     if (dx == 999)     /* first entry is set by scrollbar position */
@@ -1077,7 +1359,8 @@ static void HandleChooseTree(int mx, int my, int dx, int dy, int button,
 
     drawChooseTreeList(ti->cl_first, num_page_entries, ti);
     drawChooseTreeInfo(ti->cl_first + ti->cl_cursor, ti);
-    drawCursor(ti->cl_cursor, FC_RED);
+    drawChooseTreeCursor(ti->cl_cursor, FC_RED);
+
     return;
   }
   else if (button == MB_MENU_LEAVE)
@@ -1087,13 +1370,13 @@ static void HandleChooseTree(int mx, int my, int dx, int dy, int button,
       *ti_ptr = ti->node_parent;
       DrawChooseTree(ti_ptr);
     }
-    else if (game_status == SETUP)
+    else if (game_status == GAME_MODE_SETUP)
     {
       execSetupArtwork();
     }
     else
     {
-      game_status = MAINMENU;
+      game_status = GAME_MODE_MAIN;
       DrawMainMenu();
     }
 
@@ -1102,55 +1385,66 @@ static void HandleChooseTree(int mx, int my, int dx, int dy, int button,
 
   if (mx || my)                /* mouse input */
   {
-    x = (mx - SX) / 32;
-    y = (my - SY) / 32 - MENU_SCREEN_START_YPOS;
-  }
-  else if (dx || dy)   /* keyboard input */
-  {
-    if (dy)
-      y = ti->cl_cursor + dy;
+    int last_game_status = game_status;        /* save current game status */
 
-    if (ABS(dy) == SCR_FIELDY) /* handle KSYM_Page_Up, KSYM_Page_Down */
-    {
-      dy = SIGN(dy);
-      step = num_page_entries - 1;
-      y = (dy < 0 ? -1 : num_page_entries);
-    }
-  }
+    /* force LEVELS draw offset on artwork setup screen */
+    game_status = GAME_MODE_LEVELS;
 
-  if (x == 0 && y == -1)
-  {
-    if (ti->cl_first > 0 &&
-       (dy || DelayReached(&choose_delay, GADGET_FRAME_DELAY)))
-    {
-      ti->cl_first -= step;
-      if (ti->cl_first < 0)
-       ti->cl_first = 0;
+    x = (mx - mSX) / 32;
+    y = (my - mSY) / 32 - MENU_SCREEN_START_YPOS;
 
-      drawChooseTreeList(ti->cl_first, num_page_entries, ti);
-      drawChooseTreeInfo(ti->cl_first + ti->cl_cursor, ti);
-      drawCursor(ti->cl_cursor, FC_RED);
-      AdjustChooseTreeScrollbar(SCREEN_CTRL_ID_SCROLL_VERTICAL,
-                               ti->cl_first, ti);
-      return;
-    }
+    game_status = last_game_status;    /* restore current game status */
   }
-  else if (x == 0 && y > num_page_entries - 1)
+  else if (dx || dy)   /* keyboard or scrollbar/scrollbutton input */
   {
-    if (ti->cl_first + num_page_entries < num_entries &&
-       (dy || DelayReached(&choose_delay, GADGET_FRAME_DELAY)))
+    /* move cursor instead of scrolling when already at start/end of list */
+    if (dy == -1 * SCROLL_LINE && ti->cl_first == 0)
+      dy = -1;
+    else if (dy == +1 * SCROLL_LINE &&
+            ti->cl_first + num_page_entries == num_entries)
+      dy = 1;
+
+    /* handle scrolling screen one line or page */
+    if (ti->cl_cursor + dy < 0 ||
+       ti->cl_cursor + dy > num_page_entries - 1)
     {
-      ti->cl_first += step;
-      if (ti->cl_first + num_page_entries > num_entries)
-       ti->cl_first = MAX(0, num_entries - num_page_entries);
+      if (ABS(dy) == SCROLL_PAGE)
+       step = num_page_entries - 1;
+
+      if (dy < 0 && ti->cl_first > 0)
+      {
+       /* scroll page/line up */
+
+       ti->cl_first -= step;
+       if (ti->cl_first < 0)
+         ti->cl_first = 0;
+
+       drawChooseTreeList(ti->cl_first, num_page_entries, ti);
+       drawChooseTreeInfo(ti->cl_first + ti->cl_cursor, ti);
+       drawChooseTreeCursor(ti->cl_cursor, FC_RED);
+       AdjustChooseTreeScrollbar(SCREEN_CTRL_ID_SCROLL_VERTICAL,
+                                 ti->cl_first, ti);
+      }
+      else if (dy > 0 && ti->cl_first + num_page_entries < num_entries)
+      {
+       /* scroll page/line down */
+
+       ti->cl_first += step;
+       if (ti->cl_first + num_page_entries > num_entries)
+         ti->cl_first = MAX(0, num_entries - num_page_entries);
+
+       drawChooseTreeList(ti->cl_first, num_page_entries, ti);
+       drawChooseTreeInfo(ti->cl_first + ti->cl_cursor, ti);
+       drawChooseTreeCursor(ti->cl_cursor, FC_RED);
+       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);
-      drawCursor(ti->cl_cursor, FC_RED);
-      AdjustChooseTreeScrollbar(SCREEN_CTRL_ID_SCROLL_VERTICAL,
-                               ti->cl_first, ti);
       return;
     }
+
+    /* handle moving cursor one line */
+    y = ti->cl_cursor + dy;
   }
 
   if (dx == 1)
@@ -1167,6 +1461,7 @@ static void HandleChooseTree(int mx, int my, int dx, int dy, int button,
       node_cursor->cl_cursor = ti->cl_cursor;
       *ti_ptr = node_cursor->node_group;
       DrawChooseTree(ti_ptr);
+
       return;
     }
   }
@@ -1174,6 +1469,7 @@ static void HandleChooseTree(int mx, int my, int dx, int dy, int button,
   {
     *ti_ptr = ti->node_parent;
     DrawChooseTree(ti_ptr);
+
     return;
   }
 
@@ -1183,8 +1479,8 @@ static void HandleChooseTree(int mx, int my, int dx, int dy, int button,
     {
       if (y != ti->cl_cursor)
       {
-       drawCursor(y, FC_RED);
-       drawCursor(ti->cl_cursor, FC_BLUE);
+       drawChooseTreeCursor(y, FC_RED);
+       drawChooseTreeCursor(ti->cl_cursor, FC_BLUE);
        drawChooseTreeInfo(ti->cl_first + y, ti);
        ti->cl_cursor = y;
       }
@@ -1224,13 +1520,13 @@ static void HandleChooseTree(int mx, int my, int dx, int dy, int button,
          TapeErase();
        }
 
-       if (game_status == SETUP)
+       if (game_status == GAME_MODE_SETUP)
        {
          execSetupArtwork();
        }
        else
        {
-         game_status = MAINMENU;
+         game_status = GAME_MODE_MAIN;
          DrawMainMenu();
        }
       }
@@ -1239,12 +1535,14 @@ static void HandleChooseTree(int mx, int my, int dx, int dy, int button,
 
   BackToFront();
 
-  if (game_status == CHOOSELEVEL || game_status == SETUP)
+  if (game_status == GAME_MODE_LEVELS || game_status == GAME_MODE_SETUP)
     DoAnimation();
 }
 
 void DrawChooseLevel()
 {
+  SetMainBackgroundImage(IMG_BACKGROUND_LEVELS);
+
   DrawChooseTree(&leveldir_current);
 }
 
@@ -1264,37 +1562,45 @@ void DrawHallOfFame(int highlight_position)
 
   FadeToFront();
   InitAnimation();
+
   HandleHallOfFame(highlight_position,0, 0,0, MB_MENU_INITIALIZE);
-  PlaySound(SND_MENU_HALL_OF_FAME);
+
+#if 0
+  PlaySound(SND_BACKGROUND_SCORES);
+#else
+  PlaySound_Menu_Start(SND_BACKGROUND_SCORES);
+#endif
 }
 
 static void drawHallOfFameList(int first_entry, int highlight_position)
 {
   int i;
 
+  SetMainBackgroundImage(IMG_BACKGROUND_SCORES);
   ClearWindow();
-  DrawText(SX + 80, SY + 8, "Hall Of Fame", FS_BIG, FC_YELLOW);
-  DrawTextFCentered(46, FC_RED, "HighScores of Level %d", level_nr);
 
-  for(i=0; i<MAX_MENU_ENTRIES_ON_SCREEN; i++)
+  DrawText(mSX + 80, mSY + 8, "Hall Of Fame", FONT_TITLE_1);
+  DrawTextFCentered(46, FONT_TITLE_2, "HighScores of Level %d", level_nr);
+
+  for(i=0; i<NUM_MENU_ENTRIES_ON_SCREEN; i++)
   {
     int entry = first_entry + i;
-    int color = (entry == highlight_position ? FC_RED : FC_GREEN);
-
-#if 0
-    DrawText(SX, SY + 64 + i * 32, ".................", FS_BIG, color);
-    DrawText(SX, SY + 64 + i * 32, highscore[i].Name, FS_BIG, color);
-    DrawText(SX + 12 * 32, SY + 64 + i * 32,
-            int2str(highscore[i].Score, 5), FS_BIG, color);
-#else
-    DrawText(SX, SY + 64 + i * 32, "..................................",
-            FS_MEDIUM, FC_YELLOW);
-    DrawText(SX, SY + 64 + i * 32, int2str(entry + 1, 3),
-            FS_MEDIUM, FC_YELLOW);
-    DrawText(SX + 64, SY + 64 + i * 32, highscore[entry].Name, FS_BIG, color);
-    DrawText(SX + 14 * 32 + 16, SY + 64 + i * 32,
-            int2str(highscore[entry].Score, 5), FS_MEDIUM, color);
-#endif
+    boolean active = (entry == highlight_position);
+    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 dx1 = 3 * getFontWidth(font_nr1);
+    int dx2 = dx1 + getFontWidth(font_nr1);
+    int dx3 = dx2 + 25 * getFontWidth(font_nr3);
+    int sy = mSY + 64 + i * 32;
+
+    DrawText(mSX, sy, int2str(entry + 1, 3), font_nr1);
+    DrawText(mSX + dx1, sy, ".", font_nr1);
+    DrawText(mSX + dx2, sy, ".........................", font_nr3);
+    if (strcmp(highscore[entry].Name, EMPTY_PLAYER_NAME) != 0)
+      DrawText(mSX + dx2, sy, highscore[entry].Name, font_nr2);
+    DrawText(mSX + dx3, sy, int2str(highscore[entry].Score, 5), font_nr4);
   }
 }
 
@@ -1310,11 +1616,12 @@ void HandleHallOfFame(int mx, int my, int dx, int dy, int button)
     first_entry = 0;
     highlight_position = mx;
     drawHallOfFameList(first_entry, highlight_position);
+
     return;
   }
 
-  if (ABS(dy) == SCR_FIELDY)   /* handle KSYM_Page_Up, KSYM_Page_Down */
-    step = MAX_MENU_ENTRIES_ON_SCREEN - 1;
+  if (ABS(dy) == SCROLL_PAGE)          /* handle scrolling one page */
+    step = NUM_MENU_ENTRIES_ON_SCREEN - 1;
 
   if (dy < 0)
   {
@@ -1325,33 +1632,40 @@ void HandleHallOfFame(int mx, int my, int dx, int dy, int button)
        first_entry = 0;
 
       drawHallOfFameList(first_entry, highlight_position);
+
       return;
     }
   }
   else if (dy > 0)
   {
-    if (first_entry + MAX_MENU_ENTRIES_ON_SCREEN < MAX_SCORE_ENTRIES)
+    if (first_entry + NUM_MENU_ENTRIES_ON_SCREEN < MAX_SCORE_ENTRIES)
     {
       first_entry += step;
-      if (first_entry + MAX_MENU_ENTRIES_ON_SCREEN > MAX_SCORE_ENTRIES)
-       first_entry = MAX(0, MAX_SCORE_ENTRIES - MAX_MENU_ENTRIES_ON_SCREEN);
+      if (first_entry + NUM_MENU_ENTRIES_ON_SCREEN > MAX_SCORE_ENTRIES)
+       first_entry = MAX(0, MAX_SCORE_ENTRIES - NUM_MENU_ENTRIES_ON_SCREEN);
 
       drawHallOfFameList(first_entry, highlight_position);
+
       return;
     }
   }
 
   if (button_released)
   {
-    FadeSound(SND_MENU_HALL_OF_FAME);
-    game_status = MAINMENU;
+    FadeSound(SND_BACKGROUND_SCORES);
+    game_status = GAME_MODE_MAIN;
     DrawMainMenu();
   }
 
   BackToFront();
 
-  if (game_status == HALLOFFAME)
+  if (game_status == GAME_MODE_SCORES)
+  {
     DoAnimation();
+#if 1
+    PlaySound_Menu_Continue(SND_BACKGROUND_SCORES);
+#endif
+  }
 }
 
 
@@ -1362,6 +1676,10 @@ void HandleHallOfFame(int mx, int my, int dx, int dy, int button)
 static struct TokenInfo *setup_info;
 static int num_setup_info;
 
+static char *graphics_set_name;
+static char *sounds_set_name;
+static char *music_set_name;
+
 static void execSetupMain()
 {
   setup_mode = SETUP_MODE_MAIN;
@@ -1374,6 +1692,12 @@ static void execSetupGame()
   DrawSetupScreen();
 }
 
+static void execSetupEditor()
+{
+  setup_mode = SETUP_MODE_EDITOR;
+  DrawSetupScreen();
+}
+
 static void execSetupGraphics()
 {
   setup_mode = SETUP_MODE_GRAPHICS;
@@ -1388,12 +1712,17 @@ static void execSetupSound()
 
 static void execSetupArtwork()
 {
+  setup.graphics_set = artwork.gfx_current->identifier;
+  setup.sounds_set = artwork.snd_current->identifier;
+  setup.music_set = artwork.mus_current->identifier;
+
   /* needed if last screen (setup choice) changed graphics, sounds or music */
   ReloadCustomArtwork();
 
-  setup.graphics_set = artwork.gfx_current->name;
-  setup.sounds_set = artwork.snd_current->name;
-  setup.music_set = artwork.mus_current->name;
+  /* needed for displaying artwork name instead of artwork identifier */
+  graphics_set_name = artwork.gfx_current->name;
+  sounds_set_name = artwork.snd_current->name;
+  music_set_name = artwork.mus_current->name;
 
   setup_mode = SETUP_MODE_ARTWORK;
   DrawSetupScreen();
@@ -1431,7 +1760,7 @@ static void execSetupShortcut()
 
 static void execExitSetup()
 {
-  game_status = MAINMENU;
+  game_status = GAME_MODE_MAIN;
   DrawMainMenu();
 }
 
@@ -1444,6 +1773,7 @@ static void execSaveAndExitSetup()
 static struct TokenInfo setup_info_main[] =
 {
   { TYPE_ENTER_MENU,   execSetupGame,          "Game Settings"         },
+  { TYPE_ENTER_MENU,   execSetupEditor,        "Editor Settings"       },
   { TYPE_ENTER_MENU,   execSetupGraphics,      "Graphics"              },
   { TYPE_ENTER_MENU,   execSetupSound,         "Sound & Music"         },
   { TYPE_ENTER_MENU,   execSetupArtwork,       "Custom Artwork"        },
@@ -1451,7 +1781,7 @@ static struct TokenInfo setup_info_main[] =
   { TYPE_ENTER_MENU,   execSetupShortcut,      "Key Shortcuts"         },
   { TYPE_EMPTY,                NULL,                   ""                      },
   { TYPE_LEAVE_MENU,   execExitSetup,          "Exit"                  },
-  { TYPE_LEAVE_MENU,   execSaveAndExitSetup,   "Save and exit"         },
+  { TYPE_LEAVE_MENU,   execSaveAndExitSetup,   "Save and Exit"         },
   { 0,                 NULL,                   NULL                    }
 };
 
@@ -1462,7 +1792,24 @@ static struct TokenInfo setup_info_game[] =
   { TYPE_SWITCH,       &setup.time_limit,      "Timelimit:"            },
   { TYPE_SWITCH,       &setup.autorecord,      "Auto-Record:"          },
   { TYPE_EMPTY,                NULL,                   ""                      },
-  { TYPE_LEAVE_MENU,   execSetupMain,          "Exit"                  },
+  { TYPE_LEAVE_MENU,   execSetupMain,          "Back"                  },
+  { 0,                 NULL,                   NULL                    }
+};
+
+static struct TokenInfo setup_info_editor[] =
+{
+  { TYPE_STRING,       NULL,                   "Offer Special Elements:"},
+  { TYPE_SWITCH,       &setup.editor.el_boulderdash,   "BoulderDash:"  },
+  { TYPE_SWITCH,       &setup.editor.el_emerald_mine,  "Emerald Mine:" },
+  { TYPE_SWITCH,       &setup.editor.el_more,          "More:"         },
+  { TYPE_SWITCH,       &setup.editor.el_sokoban,       "Sokoban:"      },
+  { TYPE_SWITCH,       &setup.editor.el_supaplex,      "Supaplex:"     },
+  { TYPE_SWITCH,       &setup.editor.el_diamond_caves, "Diamd. Caves:" },
+  { TYPE_SWITCH,       &setup.editor.el_dx_boulderdash,"DX Boulderd.:" },
+  { TYPE_SWITCH,       &setup.editor.el_chars,         "Characters:"   },
+  { TYPE_SWITCH,       &setup.editor.el_custom,        "Custom:"       },
+  { TYPE_EMPTY,                NULL,                   ""                      },
+  { TYPE_LEAVE_MENU,   execSetupMain,          "Back"                  },
   { 0,                 NULL,                   NULL                    }
 };
 
@@ -1478,7 +1825,7 @@ static struct TokenInfo setup_info_graphics[] =
   { TYPE_SWITCH,       &setup.quick_doors,     "Quick Doors:"          },
   { TYPE_SWITCH,       &setup.toons,           "Toons:"                },
   { TYPE_EMPTY,                NULL,                   ""                      },
-  { TYPE_LEAVE_MENU,   execSetupMain,          "Exit"                  },
+  { TYPE_LEAVE_MENU,   execSetupMain,          "Back"                  },
   { 0,                 NULL,                   NULL                    }
 };
 
@@ -1490,25 +1837,25 @@ static struct TokenInfo setup_info_sound[] =
   { TYPE_SWITCH,       &setup.sound_loops,     "Sound Loops:"          },
   { TYPE_SWITCH,       &setup.sound_music,     "Game Music:"           },
   { TYPE_EMPTY,                NULL,                   ""                      },
-  { TYPE_LEAVE_MENU,   execSetupMain,          "Exit"                  },
+  { TYPE_LEAVE_MENU,   execSetupMain,          "Back"                  },
   { 0,                 NULL,                   NULL                    }
 };
 
 static struct TokenInfo setup_info_artwork[] =
 {
   { TYPE_ENTER_MENU,   execSetupChooseGraphics,"Custom Graphics"       },
-  { TYPE_STRING,       &setup.graphics_set,    ""                      },
+  { TYPE_STRING,       &graphics_set_name,     ""                      },
   { TYPE_ENTER_MENU,   execSetupChooseSounds,  "Custom Sounds"         },
-  { TYPE_STRING,       &setup.sounds_set,      ""                      },
+  { TYPE_STRING,       &sounds_set_name,       ""                      },
   { TYPE_ENTER_MENU,   execSetupChooseMusic,   "Custom Music"          },
-  { TYPE_STRING,       &setup.music_set,       ""                      },
+  { TYPE_STRING,       &music_set_name,        ""                      },
   { TYPE_EMPTY,                NULL,                   ""                      },
   { TYPE_STRING,       NULL,                   "Override Level Artwork:"},
   { TYPE_YES_NO,       &setup.override_level_graphics, "Graphics:"     },
   { TYPE_YES_NO,       &setup.override_level_sounds,   "Sounds:"       },
   { TYPE_YES_NO,       &setup.override_level_music,    "Music:"        },
   { TYPE_EMPTY,                NULL,                   ""                      },
-  { TYPE_LEAVE_MENU,   execSetupMain,          "Exit"                  },
+  { TYPE_LEAVE_MENU,   execSetupMain,          "Back"                  },
   { 0,                 NULL,                   NULL                    }
 };
 
@@ -1523,7 +1870,7 @@ static struct TokenInfo setup_info_shortcut[] =
   { TYPE_EMPTY,                NULL,                   ""                      },
   { TYPE_YES_NO,       &setup.ask_on_escape,   "Ask on Esc:"           },
   { TYPE_EMPTY,                NULL,                   ""                      },
-  { TYPE_LEAVE_MENU,   execSetupMain,          "Exit"                  },
+  { TYPE_LEAVE_MENU,   execSetupMain,          "Back"                  },
   { 0,                 NULL,                   NULL                    }
 };
 
@@ -1578,8 +1925,7 @@ static void drawSetupValue(int pos)
 {
   int xpos = MENU_SCREEN_VALUE_XPOS;
   int ypos = MENU_SCREEN_START_YPOS + pos;
-  int font_size = FS_BIG;
-  int font_color = FC_YELLOW;
+  int font_nr = FONT_VALUE_1;
   char *value_string = getSetupValue(setup_info[pos].type & ~TYPE_GHOSTED,
                                     setup_info[pos].value);
 
@@ -1593,7 +1939,7 @@ static void drawSetupValue(int pos)
     if (setup_info[pos].type & TYPE_QUERY)
     {
       value_string = "<press key>";
-      font_color = FC_RED;
+      font_nr = FONT_INPUT_1_ACTIVE;
     }
   }
   else if (setup_info[pos].type & TYPE_STRING)
@@ -1601,18 +1947,20 @@ static void drawSetupValue(int pos)
     int max_value_len = (SCR_FIELDX - 2) * 2;
 
     xpos = 1;
-    font_size = FS_MEDIUM;
+    font_nr = FONT_VALUE_2;
 
     if (strlen(value_string) > max_value_len)
       value_string[max_value_len] = '\0';
   }
-  else if (setup_info[pos].type & TYPE_BOOLEAN_STYLE &&
-          !*(boolean *)(setup_info[pos].value))
-    font_color = FC_BLUE;
+  else if (setup_info[pos].type & TYPE_BOOLEAN_STYLE)
+  {
+    font_nr = (*(boolean *)(setup_info[pos].value) ? FONT_OPTION_ON :
+              FONT_OPTION_OFF);
+  }
 
-  DrawText(SX + xpos * 32, SY + ypos * 32,
-          (xpos == 3 ? "              " : "   "), FS_BIG, FC_YELLOW);
-  DrawText(SX + xpos * 32, SY + ypos * 32, value_string, font_size,font_color);
+  DrawText(mSX + xpos * 32, mSY + ypos * 32,
+          (xpos == 3 ? "              " : "   "), font_nr);
+  DrawText(mSX + xpos * 32, mSY + ypos * 32, value_string, font_nr);
 }
 
 static void changeSetupValue(int pos)
@@ -1644,6 +1992,7 @@ static void DrawSetupScreen_Generic()
 
   UnmapAllGadgets();
   CloseDoor(DOOR_CLOSE_2);
+
   ClearWindow();
 
   if (setup_mode == SETUP_MODE_MAIN)
@@ -1656,6 +2005,11 @@ static void DrawSetupScreen_Generic()
     setup_info = setup_info_game;
     title_string = "Setup Game";
   }
+  else if (setup_mode == SETUP_MODE_EDITOR)
+  {
+    setup_info = setup_info_editor;
+    title_string = "Setup Editor";
+  }
   else if (setup_mode == SETUP_MODE_GRAPHICS)
   {
     setup_info = setup_info_graphics;
@@ -1677,14 +2031,14 @@ static void DrawSetupScreen_Generic()
     title_string = "Setup Shortcuts";
   }
 
-  DrawText(SX + 16, SY + 16, title_string, FS_BIG, FC_YELLOW);
+  DrawText(mSX + 16, mSY + 16, title_string, FONT_TITLE_1);
 
   num_setup_info = 0;
-  for(i=0; setup_info[i].type != 0 && i < MAX_MENU_ENTRIES_ON_SCREEN; i++)
+  for(i=0; setup_info[i].type != 0 && i < NUM_MENU_ENTRIES_ON_SCREEN; i++)
   {
     void *value_ptr = setup_info[i].value;
     int ypos = MENU_SCREEN_START_YPOS + i;
-    int font_size = FS_BIG;
+    int font_nr = FONT_MENU_1;
 
     /* set some entries to "unchangeable" according to other variables */
     if ((value_ptr == &setup.sound       && !audio.sound_available) ||
@@ -1694,16 +2048,16 @@ static void DrawSetupScreen_Generic()
       setup_info[i].type |= TYPE_GHOSTED;
 
     if (setup_info[i].type & TYPE_STRING)
-      font_size = FS_MEDIUM;
+      font_nr = FONT_MENU_2;
 
-    DrawText(SX + 32, SY + ypos * 32, setup_info[i].text, font_size, FC_GREEN);
+    DrawText(mSX + 32, mSY + ypos * 32, setup_info[i].text, font_nr);
 
     if (setup_info[i].type & TYPE_ENTER_MENU)
-      initCursor(i, GFX_ARROW_BLUE_RIGHT);
+      initCursor(i, IMG_MENU_BUTTON_RIGHT);
     else if (setup_info[i].type & TYPE_LEAVE_MENU)
-      initCursor(i, GFX_ARROW_BLUE_LEFT);
+      initCursor(i, IMG_MENU_BUTTON_LEFT);
     else if (setup_info[i].type & ~TYPE_SKIP_ENTRY)
-      initCursor(i, GFX_KUGEL_BLAU);
+      initCursor(i, IMG_MENU_BUTTON);
 
     if (setup_info[i].type & TYPE_VALUE)
       drawSetupValue(i);
@@ -1719,12 +2073,18 @@ static void DrawSetupScreen_Generic()
 void HandleSetupScreen_Generic(int mx, int my, int dx, int dy, int button)
 {
   static int choice_store[MAX_SETUP_MODES];
-  int choice = choice_store[setup_mode];
+  int choice = choice_store[setup_mode];       /* always starts with 0 */
   int x = 0;
   int y = choice;
 
   if (button == MB_MENU_INITIALIZE)
   {
+    /* advance to first valid menu entry */
+    while (choice < num_setup_info &&
+          (setup_info[choice].type & TYPE_SKIP_ENTRY))
+      choice++;
+    choice_store[setup_mode] = choice;
+
     drawCursor(choice, FC_RED);
     return;
   }
@@ -1746,8 +2106,8 @@ void HandleSetupScreen_Generic(int mx, int my, int dx, int dy, int button)
 
   if (mx || my)                /* mouse input */
   {
-    x = (mx - SX) / 32;
-    y = (my - SY) / 32 - MENU_SCREEN_START_YPOS;
+    x = (mx - mSX) / 32;
+    y = (my - mSY) / 32 - MENU_SCREEN_START_YPOS;
   }
   else if (dx || dy)   /* keyboard input */
   {
@@ -1802,30 +2162,31 @@ void HandleSetupScreen_Generic(int mx, int my, int dx, int dy, int button)
 
   BackToFront();
 
-  if (game_status == SETUP)
+  if (game_status == GAME_MODE_SETUP)
     DoAnimation();
 }
 
 void DrawSetupScreen_Input()
 {
   ClearWindow();
-  DrawText(SX+16, SY+16, "Setup Input", FS_BIG, FC_YELLOW);
 
-  initCursor(0, GFX_KUGEL_BLAU);
-  initCursor(1, GFX_KUGEL_BLAU);
-  initCursor(2, GFX_ARROW_BLUE_RIGHT);
-  initCursor(13, GFX_ARROW_BLUE_LEFT);
+  DrawText(mSX+16, mSY+16, "Setup Input", FONT_TITLE_1);
+
+  initCursor(0, IMG_MENU_BUTTON);
+  initCursor(1, IMG_MENU_BUTTON);
+  initCursor(2, IMG_MENU_BUTTON_RIGHT);
+  initCursor(13, IMG_MENU_BUTTON_LEFT);
 
-  DrawGraphic(10, MENU_SCREEN_START_YPOS, GFX_ARROW_BLUE_LEFT);
-  DrawGraphic(12, MENU_SCREEN_START_YPOS, GFX_ARROW_BLUE_RIGHT);
+  drawCursorXY(10, 0, IMG_MENU_BUTTON_LEFT);
+  drawCursorXY(12, 0, IMG_MENU_BUTTON_RIGHT);
 
-  DrawText(SX+32, SY+2*32, "Player:", FS_BIG, FC_GREEN);
-  DrawText(SX+32, SY+3*32, "Device:", FS_BIG, FC_GREEN);
-  DrawText(SX+32, SY+15*32, "Exit", FS_BIG, FC_GREEN);
+  DrawText(mSX+32, mSY+2*32, "Player:", FONT_MENU_1);
+  DrawText(mSX+32, mSY+3*32, "Device:", FONT_MENU_1);
+  DrawText(mSX+32, mSY+15*32, "Back",   FONT_MENU_1);
 
 #if 0
   DeactivateJoystickForCalibration();
-  DrawTextFCentered(SYSIZE - 20, FC_BLUE,
+  DrawTextFCentered(SYSIZE - 20, FONT_TEXT_4,
                    "Joysticks deactivated on this screen");
 #endif
 
@@ -1882,47 +2243,51 @@ static void drawPlayerSetupInputInfo(int player_nr)
 
   custom_key = setup.input[player_nr].key;
 
-  DrawText(SX+11*32, SY+2*32, int2str(player_nr + 1, 1), FS_BIG, FC_RED);
-  DrawGraphic(8, 2, GFX_SPIELER1 + player_nr);
+  DrawText(mSX+11*32, mSY+2*32, int2str(player_nr +1, 1), FONT_INPUT_1_ACTIVE);
+#if 1
+  DrawGraphicThruMaskExt(drawto, mSX + 8 * TILEX, mSY + 2 * TILEY,
+                        PLAYER_NR_GFX(IMG_PLAYER_1, player_nr), 0);
+#else
+  DrawGraphicThruMask(8, 2, PLAYER_NR_GFX(IMG_PLAYER_1, player_nr), 0);
+#endif
 
   if (setup.input[player_nr].use_joystick)
   {
     char *device_name = setup.input[player_nr].joy.device_name;
 
-    DrawText(SX+8*32, SY+3*32,
+    DrawText(mSX+8*32, mSY+3*32,
             joystick_name[getJoystickNrFromDeviceName(device_name)],
-            FS_BIG, FC_YELLOW);
-    DrawText(SX+32, SY+4*32, "Calibrate", FS_BIG, FC_GREEN);
+            FONT_VALUE_1);
+    DrawText(mSX+32, mSY+4*32, "Calibrate", FONT_MENU_1);
   }
   else
   {
-    DrawText(SX+8*32, SY+3*32, "Keyboard ", FS_BIG, FC_YELLOW);
-    DrawText(SX+32, SY+4*32, "Customize", FS_BIG, FC_GREEN);
+    DrawText(mSX+8*32, mSY+3*32, "Keyboard ", FONT_VALUE_1);
+    DrawText(mSX+32,   mSY+4*32, "Customize", FONT_MENU_1);
   }
 
-  DrawText(SX+32, SY+5*32, "Actual Settings:", FS_BIG, FC_GREEN);
-  DrawGraphic(1, 6, GFX_ARROW_BLUE_LEFT);
-  DrawGraphic(1, 7, GFX_ARROW_BLUE_RIGHT);
-  DrawGraphic(1, 8, GFX_ARROW_BLUE_UP);
-  DrawGraphic(1, 9, GFX_ARROW_BLUE_DOWN);
-  DrawText(SX+2*32, SY+6*32, ":", FS_BIG, FC_BLUE);
-  DrawText(SX+2*32, SY+7*32, ":", FS_BIG, FC_BLUE);
-  DrawText(SX+2*32, SY+8*32, ":", FS_BIG, FC_BLUE);
-  DrawText(SX+2*32, SY+9*32, ":", FS_BIG, FC_BLUE);
-  DrawText(SX+32, SY+10*32, "Snap Field:", FS_BIG, FC_BLUE);
-  DrawText(SX+32, SY+12*32, "Place Bomb:", FS_BIG, FC_BLUE);
+  DrawText(mSX+32, mSY+5*32, "Actual Settings:", FONT_MENU_1);
+  drawCursorXY(1, 4, IMG_MENU_BUTTON_LEFT);
+  drawCursorXY(1, 5, IMG_MENU_BUTTON_RIGHT);
+  drawCursorXY(1, 6, IMG_MENU_BUTTON_UP);
+  drawCursorXY(1, 7, IMG_MENU_BUTTON_DOWN);
+  DrawText(mSX+2*32, mSY+6*32, ":", FONT_VALUE_OLD);
+  DrawText(mSX+2*32, mSY+7*32, ":", FONT_VALUE_OLD);
+  DrawText(mSX+2*32, mSY+8*32, ":", FONT_VALUE_OLD);
+  DrawText(mSX+2*32, mSY+9*32, ":", FONT_VALUE_OLD);
+  DrawText(mSX+32, mSY+10*32, "Snap Field:", FONT_VALUE_OLD);
+  DrawText(mSX+32, mSY+12*32, "Place Bomb:", FONT_VALUE_OLD);
 
   for (i=0; i<6; i++)
   {
     int ypos = 6 + i + (i > 3 ? i-3 : 0);
 
-    DrawText(SX + 3*32, SY + ypos*32,
-            "              ", FS_BIG, FC_YELLOW);
-    DrawText(SX + 3*32, SY + ypos*32,
+    DrawText(mSX + 3*32, mSY + ypos*32,
+            "              ", FONT_VALUE_1);
+    DrawText(mSX + 3*32, mSY + ypos*32,
             (setup.input[player_nr].use_joystick ?
              custom[i].text :
-             getKeyNameFromKey(*custom[i].key)),
-            FS_BIG, FC_YELLOW);
+             getKeyNameFromKey(*custom[i].key)), FONT_VALUE_1);
   }
 }
 
@@ -1952,8 +2317,8 @@ void HandleSetupScreen_Input(int mx, int my, int dx, int dy, int button)
 
   if (mx || my)                /* mouse input */
   {
-    x = (mx - SX) / 32;
-    y = (my - SY) / 32 - MENU_SCREEN_START_YPOS;
+    x = (mx - mSX) / 32;
+    y = (my - mSY) / 32 - MENU_SCREEN_START_YPOS;
   }
   else if (dx || dy)   /* keyboard input */
   {
@@ -2043,7 +2408,7 @@ void HandleSetupScreen_Input(int mx, int my, int dx, int dy, int button)
 
   out:
 
-  if (game_status == SETUP)
+  if (game_status == GAME_MODE_SETUP)
     DoAnimation();
 }
 
@@ -2071,19 +2436,18 @@ void CustomizeKeyboard(int player_nr)
   custom_key = setup.input[player_nr].key;
 
   ClearWindow();
-  DrawText(SX + 16, SY + 16, "Keyboard Input", FS_BIG, FC_YELLOW);
+  DrawText(mSX + 16, mSY + 16, "Keyboard Input", FONT_TITLE_1);
 
   BackToFront();
   InitAnimation();
 
   step_nr = 0;
-  DrawText(SX, SY + (2+2*step_nr)*32,
-          customize_step[step_nr].text, FS_BIG, FC_RED);
-  DrawText(SX, SY + (2+2*step_nr+1)*32,
-          "Key:", FS_BIG, FC_RED);
-  DrawText(SX + 4*32, SY + (2+2*step_nr+1)*32,
-          getKeyNameFromKey(*customize_step[step_nr].key),
-          FS_BIG, FC_BLUE);
+  DrawText(mSX, mSY + (2+2*step_nr)*32,
+          customize_step[step_nr].text, FONT_INPUT_1_ACTIVE);
+  DrawText(mSX, mSY + (2+2*step_nr+1)*32,
+          "Key:", FONT_INPUT_1_ACTIVE);
+  DrawText(mSX + 4*32, mSY + (2+2*step_nr+1)*32,
+          getKeyNameFromKey(*customize_step[step_nr].key), FONT_VALUE_OLD);
 
   while(!finished)
   {
@@ -2122,34 +2486,34 @@ void CustomizeKeyboard(int player_nr)
 
            /* got new key binding */
            *customize_step[step_nr].key = key;
-           DrawText(SX + 4*32, SY + (2+2*step_nr+1)*32,
-                    "             ", FS_BIG, FC_YELLOW);
-           DrawText(SX + 4*32, SY + (2+2*step_nr+1)*32,
-                    getKeyNameFromKey(key), FS_BIG, FC_YELLOW);
+           DrawText(mSX + 4*32, mSY + (2+2*step_nr+1)*32,
+                    "             ", FONT_VALUE_1);
+           DrawText(mSX + 4*32, mSY + (2+2*step_nr+1)*32,
+                    getKeyNameFromKey(key), FONT_VALUE_1);
            step_nr++;
 
            /* un-highlight last query */
-           DrawText(SX, SY+(2+2*(step_nr-1))*32,
-                    customize_step[step_nr-1].text, FS_BIG, FC_GREEN);
-           DrawText(SX, SY+(2+2*(step_nr-1)+1)*32,
-                    "Key:", FS_BIG, FC_GREEN);
+           DrawText(mSX, mSY+(2+2*(step_nr-1))*32,
+                    customize_step[step_nr-1].text, FONT_MENU_1);
+           DrawText(mSX, mSY+(2+2*(step_nr-1)+1)*32,
+                    "Key:", FONT_MENU_1);
 
            /* press 'Enter' to leave */
            if (step_nr == 6)
            {
-             DrawText(SX + 16, SY + 15*32+16,
-                      "Press Enter", FS_BIG, FC_YELLOW);
+             DrawText(mSX + 16, mSY + 15*32+16,
+                      "Press Enter", FONT_TITLE_1);
              break;
            }
 
            /* query next key binding */
-           DrawText(SX, SY+(2+2*step_nr)*32,
-                    customize_step[step_nr].text, FS_BIG, FC_RED);
-           DrawText(SX, SY+(2+2*step_nr+1)*32,
-                    "Key:", FS_BIG, FC_RED);
-           DrawText(SX + 4*32, SY+(2+2*step_nr+1)*32,
+           DrawText(mSX, mSY+(2+2*step_nr)*32,
+                    customize_step[step_nr].text, FONT_INPUT_1_ACTIVE);
+           DrawText(mSX, mSY+(2+2*step_nr+1)*32,
+                    "Key:", FONT_INPUT_1_ACTIVE);
+           DrawText(mSX + 4*32, mSY+(2+2*step_nr+1)*32,
                     getKeyNameFromKey(*customize_step[step_nr].key),
-                    FS_BIG, FC_BLUE);
+                    FONT_VALUE_OLD);
          }
          break;
 
@@ -2201,22 +2565,22 @@ static boolean CalibrateJoystickMain(int player_nr)
 
   ClearWindow();
 
-  for(y=0; y<3; y++)
+  for(y=0; y < 3; y++)
   {
-    for(x=0; x<3; x++)
+    for(x=0; x < 3; x++)
     {
+      DrawGraphic(xpos + x - 1, ypos + y - 1, IMG_MENU_CALIBRATE_BLUE, 0);
       check[x][y] = FALSE;
-      DrawGraphic(xpos + x - 1, ypos + y - 1, GFX_KUGEL_BLAU);
     }
   }
 
-  DrawText(SX,      SY +  6 * 32, " ROTATE JOYSTICK ", FS_BIG, FC_YELLOW);
-  DrawText(SX,      SY +  7 * 32, "IN ALL DIRECTIONS", FS_BIG, FC_YELLOW);
-  DrawText(SX + 16, SY +  9 * 32, "  IF ALL BALLS  ",  FS_BIG, FC_YELLOW);
-  DrawText(SX,      SY + 10 * 32, "   ARE YELLOW,   ", FS_BIG, FC_YELLOW);
-  DrawText(SX,      SY + 11 * 32, " CENTER JOYSTICK ", FS_BIG, FC_YELLOW);
-  DrawText(SX,      SY + 12 * 32, "       AND       ", FS_BIG, FC_YELLOW);
-  DrawText(SX,      SY + 13 * 32, "PRESS ANY BUTTON!", FS_BIG, FC_YELLOW);
+  DrawText(mSX,      mSY +  6 * 32, " ROTATE JOYSTICK ", FONT_TITLE_1);
+  DrawText(mSX,      mSY +  7 * 32, "IN ALL DIRECTIONS", FONT_TITLE_1);
+  DrawText(mSX + 16, mSY +  9 * 32, "  IF ALL BALLS  ",  FONT_TITLE_1);
+  DrawText(mSX,      mSY + 10 * 32, "   ARE YELLOW,   ", FONT_TITLE_1);
+  DrawText(mSX,      mSY + 11 * 32, " CENTER JOYSTICK ", FONT_TITLE_1);
+  DrawText(mSX,      mSY + 12 * 32, "       AND       ", FONT_TITLE_1);
+  DrawText(mSX,      mSY + 13 * 32, "PRESS ANY BUTTON!", FONT_TITLE_1);
 
   joy_value = Joystick(player_nr);
   last_x = (joy_value & JOY_LEFT ? -1 : joy_value & JOY_RIGHT ? +1 : 0);
@@ -2229,7 +2593,7 @@ static boolean CalibrateJoystickMain(int player_nr)
   new_joystick_xmiddle = joy_x;
   new_joystick_ymiddle = joy_y;
 
-  DrawGraphic(xpos + last_x, ypos + last_y, GFX_KUGEL_ROT);
+  DrawGraphic(xpos + last_x, ypos + last_y, IMG_MENU_CALIBRATE_RED, 0);
   BackToFront();
 
   while(Joystick(player_nr) & JOY_BUTTON);     /* wait for released button */
@@ -2299,8 +2663,8 @@ static boolean CalibrateJoystickMain(int player_nr)
 
     if (x != last_x || y != last_y)
     {
-      DrawGraphic(xpos + last_x, ypos + last_y, GFX_KUGEL_GELB);
-      DrawGraphic(xpos + x,      ypos + y,      GFX_KUGEL_ROT);
+      DrawGraphic(xpos + last_x, ypos + last_y, IMG_MENU_CALIBRATE_YELLOW, 0);
+      DrawGraphic(xpos + x,      ypos + y,      IMG_MENU_CALIBRATE_RED,    0);
 
       last_x = x;
       last_y = y;
@@ -2367,8 +2731,8 @@ void CalibrateJoystick(int player_nr)
   {
     ClearWindow();
 
-    DrawText(SX + 16, SY + 6*32, "  JOYSTICK NOT  ",  FS_BIG, FC_YELLOW);
-    DrawText(SX,      SY + 7*32, "    AVAILABLE    ", FS_BIG, FC_YELLOW);
+    DrawText(mSX + 16, mSY + 6*32, "  JOYSTICK NOT  ",  FONT_TITLE_1);
+    DrawText(mSX,      mSY + 7*32, "    AVAILABLE    ", FONT_TITLE_1);
     BackToFront();
     Delay(2000);       /* show error message for two seconds */
   }
@@ -2378,6 +2742,8 @@ void DrawSetupScreen()
 {
   DeactivateJoystick();
 
+  SetMainBackgroundImage(IMG_BACKGROUND_SETUP);
+
   if (setup_mode == SETUP_MODE_INPUT)
     DrawSetupScreen_Input();
   else if (setup_mode == SETUP_MODE_CHOOSE_GRAPHICS)
@@ -2406,7 +2772,7 @@ void HandleSetupScreen(int mx, int my, int dx, int dy, int button)
 
 void HandleGameActions()
 {
-  if (game_status != PLAYING)
+  if (game_status != GAME_MODE_PLAYING)
     return;
 
   if (local_player->LevelSolved)
@@ -2418,47 +2784,50 @@ void HandleGameActions()
   GameActions();
 
   BackToFront();
+
+#if 1
+  if (tape.auto_play && !tape.playing)
+    AutoPlayTape();    /* continue automatically playing next tape */
+#endif
 }
 
 /* ---------- new screen button stuff -------------------------------------- */
 
 /* graphic position and size values for buttons and scrollbars */
-#define SC_SCROLLBUTTON_XPOS           64
-#define SC_SCROLLBUTTON_YPOS           0
-#define SC_SCROLLBAR_XPOS              0
-#define SC_SCROLLBAR_YPOS              64
-
-#define SC_SCROLLBUTTON_XSIZE          32
-#define SC_SCROLLBUTTON_YSIZE          32
+#define SC_SCROLLBUTTON_XSIZE          TILEX
+#define SC_SCROLLBUTTON_YSIZE          TILEY
 
+#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              (SXSIZE - SC_SCROLLBUTTON_XSIZE)
-#define SC_SCROLL_UP_YPOS              SC_SCROLLBUTTON_YSIZE
-#define SC_SCROLL_DOWN_XPOS            SC_SCROLL_UP_XPOS
-#define SC_SCROLL_DOWN_YPOS            (SYSIZE - SC_SCROLLBUTTON_YSIZE)
+#define SC_SCROLL_UP_YPOS              (2 * SC_SCROLLBUTTON_YSIZE)
 #define SC_SCROLL_VERTICAL_XPOS                SC_SCROLL_UP_XPOS
-#define SC_SCROLL_VERTICAL_YPOS          (SC_SCROLL_UP_YPOS + SC_SCROLLBUTTON_YSIZE)
-#define SC_SCROLL_VERTICAL_XSIZE       SC_SCROLLBUTTON_XSIZE
-#define SC_SCROLL_VERTICAL_YSIZE       (SYSIZE - 3 * SC_SCROLLBUTTON_YSIZE)
+#define SC_SCROLL_VERTICAL_YPOS                (SC_SCROLL_UP_YPOS + \
+                                        SC_SCROLLBUTTON_YSIZE)
+#define SC_SCROLL_DOWN_XPOS            SC_SCROLL_UP_XPOS
+#define SC_SCROLL_DOWN_YPOS            (SC_SCROLL_VERTICAL_YPOS + \
+                                        SC_SCROLL_VERTICAL_YSIZE)
 
 #define SC_BORDER_SIZE                 14
 
 static struct
 {
-  int xpos, ypos;
+  int gfx_unpressed, gfx_pressed;
   int x, y;
   int gadget_id;
   char *infotext;
 } scrollbutton_info[NUM_SCREEN_SCROLLBUTTONS] =
 {
   {
-    SC_SCROLLBUTTON_XPOS + 0 * SC_SCROLLBUTTON_XSIZE,   SC_SCROLLBUTTON_YPOS,
-    SC_SCROLL_UP_XPOS,                                 SC_SCROLL_UP_YPOS,
+    IMG_MENU_BUTTON_UP, IMG_MENU_BUTTON_UP_ACTIVE,
+    SC_SCROLL_UP_XPOS, SC_SCROLL_UP_YPOS,
     SCREEN_CTRL_ID_SCROLL_UP,
     "scroll up"
   },
   {
-    SC_SCROLLBUTTON_XPOS + 1 * SC_SCROLLBUTTON_XSIZE,   SC_SCROLLBUTTON_YPOS,
-    SC_SCROLL_DOWN_XPOS,                               SC_SCROLL_DOWN_YPOS,
+    IMG_MENU_BUTTON_DOWN, IMG_MENU_BUTTON_DOWN_ACTIVE,
+    SC_SCROLL_DOWN_XPOS, SC_SCROLL_DOWN_YPOS,
     SCREEN_CTRL_ID_SCROLL_DOWN,
     "scroll down"
   }
@@ -2466,7 +2835,11 @@ static struct
 
 static struct
 {
-  int xpos, ypos;
+#if defined(TARGET_X11_NATIVE_PERFORMANCE_WORKAROUND)
+  Bitmap **gfx_unpressed, **gfx_pressed;
+#else
+  int gfx_unpressed, gfx_pressed;
+#endif
   int x, y;
   int width, height;
   int type;
@@ -2475,9 +2848,13 @@ static struct
 } scrollbar_info[NUM_SCREEN_SCROLLBARS] =
 {
   {
-    SC_SCROLLBAR_XPOS,                 SC_SCROLLBAR_YPOS,
-    SX + SC_SCROLL_VERTICAL_XPOS,      SY + SC_SCROLL_VERTICAL_YPOS,
-    SC_SCROLL_VERTICAL_XSIZE,          SC_SCROLL_VERTICAL_YSIZE,
+#if defined(TARGET_X11_NATIVE_PERFORMANCE_WORKAROUND)
+    &scrollbar_bitmap[0], &scrollbar_bitmap[1],
+#else
+    IMG_MENU_SCROLLBAR, IMG_MENU_SCROLLBAR_ACTIVE,
+#endif
+    SC_SCROLL_VERTICAL_XPOS, SC_SCROLL_VERTICAL_YPOS,
+    SC_SCROLL_VERTICAL_XSIZE, SC_SCROLL_VERTICAL_YSIZE,
     GD_TYPE_SCROLLBAR_VERTICAL,
     SCREEN_CTRL_ID_SCROLL_VERTICAL,
     "scroll level series vertically"
@@ -2486,30 +2863,37 @@ static struct
 
 static void CreateScreenScrollbuttons()
 {
-  Bitmap *gd_bitmap = pix[PIX_MORE];
   struct GadgetInfo *gi;
   unsigned long event_mask;
   int i;
 
   for (i=0; i<NUM_SCREEN_SCROLLBUTTONS; i++)
   {
-    int id = scrollbutton_info[i].gadget_id;
+    Bitmap *gd_bitmap_unpressed, *gd_bitmap_pressed;
+    int gfx_unpressed, gfx_pressed;
     int x, y, width, height;
     int gd_x1, gd_x2, gd_y1, gd_y2;
-
-    x = scrollbutton_info[i].x;
-    y = scrollbutton_info[i].y;
+    int id = scrollbutton_info[i].gadget_id;
 
     event_mask = GD_EVENT_PRESSED | GD_EVENT_REPEATED;
 
-    x += SX;
-    y += SY;
+    x = mSX + scrollbutton_info[i].x + menu.scrollbar_xoffset;
+    y = mSY + scrollbutton_info[i].y;
     width = SC_SCROLLBUTTON_XSIZE;
     height = SC_SCROLLBUTTON_YSIZE;
-    gd_x1 = scrollbutton_info[i].xpos;
-    gd_y1 = scrollbutton_info[i].ypos;
-    gd_x2 = gd_x1;
-    gd_y2 = gd_y1 + SC_SCROLLBUTTON_YSIZE;
+
+    if (id == SCREEN_CTRL_ID_SCROLL_DOWN)
+      y = mSY + (SC_SCROLL_VERTICAL_YPOS +
+                (NUM_MENU_ENTRIES_ON_SCREEN - 2) * SC_SCROLLBUTTON_YSIZE);
+
+    gfx_unpressed = scrollbutton_info[i].gfx_unpressed;
+    gfx_pressed   = scrollbutton_info[i].gfx_pressed;
+    gd_bitmap_unpressed = graphic_info[gfx_unpressed].bitmap;
+    gd_bitmap_pressed   = graphic_info[gfx_pressed].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;
 
     gi = CreateGadget(GDI_CUSTOM_ID, id,
                      GDI_CUSTOM_TYPE_ID, i,
@@ -2520,8 +2904,8 @@ static void CreateScreenScrollbuttons()
                      GDI_HEIGHT, height,
                      GDI_TYPE, GD_TYPE_NORMAL_BUTTON,
                      GDI_STATE, GD_BUTTON_UNPRESSED,
-                     GDI_DESIGN_UNPRESSED, gd_bitmap, gd_x1, gd_y1,
-                     GDI_DESIGN_PRESSED, gd_bitmap, gd_x2, gd_y2,
+                     GDI_DESIGN_UNPRESSED, gd_bitmap_unpressed, gd_x1, gd_y1,
+                     GDI_DESIGN_PRESSED, gd_bitmap_pressed, gd_x2, gd_y2,
                      GDI_EVENT_MASK, event_mask,
                      GDI_CALLBACK_ACTION, HandleScreenGadgets,
                      GDI_END);
@@ -2539,51 +2923,65 @@ static void CreateScreenScrollbars()
 
   for (i=0; i<NUM_SCREEN_SCROLLBARS; i++)
   {
-    int id = scrollbar_info[i].gadget_id;
-    Bitmap *gd_bitmap = pix[PIX_MORE];
+    Bitmap *gd_bitmap_unpressed, *gd_bitmap_pressed;
+#if !defined(TARGET_X11_NATIVE_PERFORMANCE_WORKAROUND)
+    int gfx_unpressed, gfx_pressed;
+#endif
+    int x, y, width, height;
     int gd_x1, gd_x2, gd_y1, gd_y2;
     struct GadgetInfo *gi;
     int items_max, items_visible, item_position;
     unsigned long event_mask;
-    int num_page_entries = MAX_MENU_ENTRIES_ON_SCREEN - 1;
+    int num_page_entries = NUM_MENU_ENTRIES_ON_SCREEN;
+    int id = scrollbar_info[i].gadget_id;
 
-#if 0
-    if (num_leveldirs <= MAX_MENU_ENTRIES_ON_SCREEN)
-      num_page_entries = num_leveldirs;
-    else
-      num_page_entries = MAX_MENU_ENTRIES_ON_SCREEN - 1;
+    event_mask = GD_EVENT_MOVING | GD_EVENT_OFF_BORDERS;
+
+    x = mSX + scrollbar_info[i].x + menu.scrollbar_xoffset;
+    y = mSY + scrollbar_info[i].y;
+    width  = scrollbar_info[i].width;
+    height = scrollbar_info[i].height;
+
+    if (id == SCREEN_CTRL_ID_SCROLL_VERTICAL)
+      height = (NUM_MENU_ENTRIES_ON_SCREEN - 2) * SC_SCROLLBUTTON_YSIZE;
 
-    items_max = MAX(num_leveldirs, num_page_entries);
-    items_visible = num_page_entries;
-    item_position = 0;
-#else
     items_max = num_page_entries;
     items_visible = num_page_entries;
     item_position = 0;
-#endif
 
-    event_mask = GD_EVENT_MOVING | GD_EVENT_OFF_BORDERS;
-
-    gd_x1 = scrollbar_info[i].xpos;
-    gd_x2 = gd_x1 + scrollbar_info[i].width;
-    gd_y1 = scrollbar_info[i].ypos;
-    gd_y2 = scrollbar_info[i].ypos;
+#if defined(TARGET_X11_NATIVE_PERFORMANCE_WORKAROUND)
+    gd_bitmap_unpressed = *scrollbar_info[i].gfx_unpressed;
+    gd_bitmap_pressed   = *scrollbar_info[i].gfx_pressed;
+    gd_x1 = 0;
+    gd_y1 = 0;
+    gd_x2 = 0;
+    gd_y2 = 0;
+#else
+    gfx_unpressed = scrollbar_info[i].gfx_unpressed;
+    gfx_pressed   = scrollbar_info[i].gfx_pressed;
+    gd_bitmap_unpressed = graphic_info[gfx_unpressed].bitmap;
+    gd_bitmap_pressed   = graphic_info[gfx_pressed].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;
+#endif
 
     gi = CreateGadget(GDI_CUSTOM_ID, id,
                      GDI_CUSTOM_TYPE_ID, i,
                      GDI_INFO_TEXT, scrollbar_info[i].infotext,
-                     GDI_X, scrollbar_info[i].x,
-                     GDI_Y, scrollbar_info[i].y,
-                     GDI_WIDTH, scrollbar_info[i].width,
-                     GDI_HEIGHT, scrollbar_info[i].height,
+                     GDI_X, x,
+                     GDI_Y, y,
+                     GDI_WIDTH, width,
+                     GDI_HEIGHT, height,
                      GDI_TYPE, scrollbar_info[i].type,
                      GDI_SCROLLBAR_ITEMS_MAX, items_max,
                      GDI_SCROLLBAR_ITEMS_VISIBLE, items_visible,
                      GDI_SCROLLBAR_ITEM_POSITION, item_position,
                      GDI_STATE, GD_BUTTON_UNPRESSED,
-                     GDI_DESIGN_UNPRESSED, gd_bitmap, gd_x1, gd_y1,
-                     GDI_DESIGN_PRESSED, gd_bitmap, gd_x2, gd_y2,
-                     GDI_BORDER_SIZE, SC_BORDER_SIZE,
+                     GDI_DESIGN_UNPRESSED, gd_bitmap_unpressed, gd_x1, gd_y1,
+                     GDI_DESIGN_PRESSED, gd_bitmap_pressed, gd_x2, gd_y2,
+                     GDI_BORDER_SIZE, SC_BORDER_SIZE, SC_BORDER_SIZE,
                      GDI_EVENT_MASK, event_mask,
                      GDI_CALLBACK_ACTION, HandleScreenGadgets,
                      GDI_END);
@@ -2597,8 +2995,55 @@ static void CreateScreenScrollbars()
 
 void CreateScreenGadgets()
 {
+  int last_game_status = game_status;  /* save current game status */
+
+#if defined(TARGET_X11_NATIVE_PERFORMANCE_WORKAROUND)
+  int i;
+
+  for (i=0; i < NUM_SCROLLBAR_BITMAPS; i++)
+  {
+    scrollbar_bitmap[i] = CreateBitmap(TILEX, TILEY, DEFAULT_DEPTH);
+
+    /* copy pointers to clip mask and GC */
+    scrollbar_bitmap[i]->clip_mask =
+      graphic_info[IMG_MENU_SCROLLBAR + i].clip_mask;
+    scrollbar_bitmap[i]->stored_clip_gc =
+      graphic_info[IMG_MENU_SCROLLBAR + i].clip_gc;
+
+    BlitBitmap(graphic_info[IMG_MENU_SCROLLBAR + i].bitmap,
+              scrollbar_bitmap[i],
+              graphic_info[IMG_MENU_SCROLLBAR + i].src_x,
+              graphic_info[IMG_MENU_SCROLLBAR + i].src_y,
+              TILEX, TILEY, 0, 0);
+  }
+#endif
+
+  /* force LEVELS draw offset for scrollbar / scrollbutton gadgets */
+  game_status = GAME_MODE_LEVELS;
+
   CreateScreenScrollbuttons();
   CreateScreenScrollbars();
+
+  game_status = last_game_status;      /* restore current game status */
+}
+
+void FreeScreenGadgets()
+{
+  int i;
+
+#if defined(TARGET_X11_NATIVE_PERFORMANCE_WORKAROUND)
+  for (i=0; i < NUM_SCROLLBAR_BITMAPS; i++)
+  {
+    /* prevent freeing clip mask and GC twice */
+    scrollbar_bitmap[i]->clip_mask = None;
+    scrollbar_bitmap[i]->stored_clip_gc = None;
+
+    FreeBitmap(scrollbar_bitmap[i]);
+  }
+#endif
+
+  for (i=0; i<NUM_SCREEN_GADGETS; i++)
+    FreeGadget(screen_gadget[i]);
 }
 
 void MapChooseTreeGadgets(TreeInfo *ti)
@@ -2606,7 +3051,7 @@ void MapChooseTreeGadgets(TreeInfo *ti)
   int num_entries = numTreeInfoInGroup(ti);
   int i;
 
-  if (num_entries <= MAX_MENU_ENTRIES_ON_SCREEN)
+  if (num_entries <= NUM_MENU_ENTRIES_ON_SCREEN)
     return;
 
   for (i=0; i<NUM_SCREEN_GADGETS; i++)
@@ -2625,29 +3070,29 @@ static void HandleScreenGadgets(struct GadgetInfo *gi)
 {
   int id = gi->custom_id;
 
-  if (game_status != CHOOSELEVEL && game_status != SETUP)
+  if (game_status != GAME_MODE_LEVELS && game_status != GAME_MODE_SETUP)
     return;
 
   switch (id)
   {
     case SCREEN_CTRL_ID_SCROLL_UP:
-      if (game_status == CHOOSELEVEL)
-       HandleChooseLevel(SX,SY + 32, 0,0, MB_MENU_MARK);
-      else if (game_status == SETUP)
-       HandleSetupScreen(SX,SY + 32, 0,0, MB_MENU_MARK);
+      if (game_status == GAME_MODE_LEVELS)
+       HandleChooseLevel(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);
       break;
 
     case SCREEN_CTRL_ID_SCROLL_DOWN:
-      if (game_status == CHOOSELEVEL)
-       HandleChooseLevel(SX,SY + SYSIZE - 32, 0,0, MB_MENU_MARK);
-      else if (game_status == SETUP)
-       HandleSetupScreen(SX,SY + SYSIZE - 32, 0,0, MB_MENU_MARK);
+      if (game_status == GAME_MODE_LEVELS)
+       HandleChooseLevel(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);
       break;
 
     case SCREEN_CTRL_ID_SCROLL_VERTICAL:
-      if (game_status == CHOOSELEVEL)
+      if (game_status == GAME_MODE_LEVELS)
        HandleChooseLevel(0,0, 999,gi->event.item_position,MB_MENU_INITIALIZE);
-      else if (game_status == SETUP)
+      else if (game_status == GAME_MODE_SETUP)
        HandleSetupScreen(0,0, 999,gi->event.item_position,MB_MENU_INITIALIZE);
       break;
 
index 60f310165c0a8d2c5882ca97d96ca9a137631c4b..f4b704b462553ec3b090f6639c9a918d8ee524c9 100644 (file)
 
 #include "main.h"
 
+/* (randomly chosen) values for HandleChooseTree() */
+#define SCROLL_LINE    (1 * SCR_FIELDY)
+#define SCROLL_PAGE    (2 * SCR_FIELDY)
+
+
 void DrawHeadline(void);
 
 void DrawMainMenu(void);
@@ -42,6 +47,7 @@ void HandleSetupScreen(int, int, int, int, int);
 void HandleGameActions(void);
 
 void CreateScreenGadgets();
+void FreeScreenGadgets();
 void MapChooseTreeGadgets(TreeInfo *);
 void UnmapChooseTreeGadgets();
 
index b219109fb3528b85246a1059312da05891ea742f..3aa2282b2edd6b1c0b5d67139f73b7757511ee15 100644 (file)
@@ -14,6 +14,7 @@
 #include "libgame/libgame.h"
 
 #include "tape.h"
+#include "init.h"
 #include "game.h"
 #include "tools.h"
 #include "files.h"
@@ -49,7 +50,7 @@ static struct GadgetInfo *tape_gadget[NUM_TAPE_BUTTONS];
 #define VIDEO_DATE_LABEL_YPOS  (VIDEO_DISPLAY1_YPOS)
 #define VIDEO_DATE_LABEL_XSIZE (VIDEO_DISPLAY_XSIZE)
 #define VIDEO_DATE_LABEL_YSIZE (VIDEO_DISPLAY_YSIZE)
-#define VIDEO_DATE_XPOS                (VIDEO_DISPLAY1_XPOS + 1)
+#define VIDEO_DATE_XPOS                (VIDEO_DISPLAY1_XPOS + 2)
 #define VIDEO_DATE_YPOS                (VIDEO_DISPLAY1_YPOS + 14)
 #define VIDEO_DATE_XSIZE       (VIDEO_DISPLAY_XSIZE)
 #define VIDEO_DATE_YSIZE       16
@@ -77,7 +78,7 @@ static struct GadgetInfo *tape_gadget[NUM_TAPE_BUTTONS];
 #define VIDEO_PAUSE_SYMBOL_YPOS        (VIDEO_DISPLAY2_YPOS)
 #define VIDEO_PAUSE_SYMBOL_XSIZE 17
 #define VIDEO_PAUSE_SYMBOL_YSIZE 13
-#define VIDEO_TIME_XPOS                (VIDEO_DISPLAY2_XPOS + 38)
+#define VIDEO_TIME_XPOS                (VIDEO_DISPLAY2_XPOS + 39)
 #define VIDEO_TIME_YPOS                (VIDEO_DISPLAY2_YPOS + 14)
 #define VIDEO_TIME_XSIZE       50
 #define VIDEO_TIME_YSIZE       16
@@ -167,7 +168,7 @@ void DrawVideoDisplay(unsigned long state, unsigned long value)
   {
     int cx = DOOR_GFX_PAGEX3, cy = DOOR_GFX_PAGEY2;
 
-    BlitBitmap(pix[PIX_DOOR], drawto,
+    BlitBitmap(graphic_info[IMG_GLOBAL_DOOR].bitmap, drawto,
               cx + VIDEO_REC_LABEL_XPOS,
               cy + VIDEO_REC_LABEL_YPOS,
               VIDEO_PBEND_LABEL_XSIZE,
@@ -188,7 +189,7 @@ void DrawVideoDisplay(unsigned long state, unsigned long value)
        cx = DOOR_GFX_PAGEX3;   /* i gerade => STATE_OFF / PRESS_ON */
 
       if (video_pos[pos][part_label][0] && value != VIDEO_DISPLAY_SYMBOL_ONLY)
-       BlitBitmap(pix[PIX_DOOR], drawto,
+       BlitBitmap(graphic_info[IMG_GLOBAL_DOOR].bitmap, drawto,
                   cx + video_pos[pos][part_label][xpos],
                   cy + video_pos[pos][part_label][ypos],
                   video_pos[pos][part_label][xsize],
@@ -196,7 +197,7 @@ void DrawVideoDisplay(unsigned long state, unsigned long value)
                   VX + video_pos[pos][part_label][xpos],
                   VY + video_pos[pos][part_label][ypos]);
       if (video_pos[pos][part_symbol][0] && value != VIDEO_DISPLAY_LABEL_ONLY)
-       BlitBitmap(pix[PIX_DOOR], drawto,
+       BlitBitmap(graphic_info[IMG_GLOBAL_DOOR].bitmap, drawto,
                   cx + video_pos[pos][part_symbol][xpos],
                   cy + video_pos[pos][part_symbol][ypos],
                   video_pos[pos][part_symbol][xsize],
@@ -210,7 +211,7 @@ void DrawVideoDisplay(unsigned long state, unsigned long value)
   {
     int cx = DOOR_GFX_PAGEX4, cy = DOOR_GFX_PAGEY2;
 
-    BlitBitmap(pix[PIX_DOOR], drawto,
+    BlitBitmap(graphic_info[IMG_GLOBAL_DOOR].bitmap, drawto,
               cx + VIDEO_PLAY_SYMBOL_XPOS,
               cy + VIDEO_PLAY_SYMBOL_YPOS,
               VIDEO_PLAY_SYMBOL_XSIZE - 2,
@@ -223,7 +224,7 @@ void DrawVideoDisplay(unsigned long state, unsigned long value)
   {
     int cx = DOOR_GFX_PAGEX6, cy = DOOR_GFX_PAGEY1;
 
-    BlitBitmap(pix[PIX_DOOR], drawto,
+    BlitBitmap(graphic_info[IMG_GLOBAL_DOOR].bitmap, drawto,
               cx + VIDEO_PBEND_LABEL_XPOS,
               cy + VIDEO_PBEND_LABEL_YPOS,
               VIDEO_PBEND_LABEL_XSIZE,
@@ -238,12 +239,12 @@ void DrawVideoDisplay(unsigned long state, unsigned long value)
     int monat = (value/100) % 100;
     int jahr = (value/10000);
 
-    DrawText(VX+VIDEO_DATE_XPOS,VY+VIDEO_DATE_YPOS,
-            int2str(tag,2),FS_SMALL,FC_SPECIAL1);
-    DrawText(VX+VIDEO_DATE_XPOS+27,VY+VIDEO_DATE_YPOS,
-            monatsname[monat],FS_SMALL,FC_SPECIAL1);
-    DrawText(VX+VIDEO_DATE_XPOS+64,VY+VIDEO_DATE_YPOS,
-            int2str(jahr,2),FS_SMALL,FC_SPECIAL1);
+    DrawText(VX + VIDEO_DATE_XPOS, VY + VIDEO_DATE_YPOS,
+            int2str(tag, 2), FONT_TAPE_RECORDER);
+    DrawText(VX + VIDEO_DATE_XPOS + 27, VY + VIDEO_DATE_YPOS,
+            monatsname[monat], FONT_TAPE_RECORDER);
+    DrawText(VX + VIDEO_DATE_XPOS + 64, VY + VIDEO_DATE_YPOS,
+            int2str(jahr, 2), FONT_TAPE_RECORDER);
   }
 
   if (state & VIDEO_STATE_TIME_ON)
@@ -251,10 +252,10 @@ void DrawVideoDisplay(unsigned long state, unsigned long value)
     int min = value / 60;
     int sec = value % 60;
 
-    DrawText(VX+VIDEO_TIME_XPOS,VY+VIDEO_TIME_YPOS,
-            int2str(min,2),FS_SMALL,FC_SPECIAL1);
-    DrawText(VX+VIDEO_TIME_XPOS+27,VY+VIDEO_TIME_YPOS,
-            int2str(sec,2),FS_SMALL,FC_SPECIAL1);
+    DrawText(VX + VIDEO_TIME_XPOS, VY + VIDEO_TIME_YPOS,
+            int2str(min, 2), FONT_TAPE_RECORDER);
+    DrawText(VX + VIDEO_TIME_XPOS + 27, VY + VIDEO_TIME_YPOS,
+            int2str(sec, 2), FONT_TAPE_RECORDER);
   }
 
   if (state & VIDEO_STATE_DATE)
@@ -267,9 +268,10 @@ void DrawVideoDisplay(unsigned long state, unsigned long value)
 
 void DrawCompleteVideoDisplay()
 {
-  BlitBitmap(pix[PIX_DOOR], drawto, DOOR_GFX_PAGEX3, DOOR_GFX_PAGEY2,
+  BlitBitmap(graphic_info[IMG_GLOBAL_DOOR].bitmap, drawto,
+            DOOR_GFX_PAGEX3, DOOR_GFX_PAGEY2,
             gfx.vxsize, gfx.vysize, gfx.vx, gfx.vy);
-  BlitBitmap(pix[PIX_DOOR], drawto,
+  BlitBitmap(graphic_info[IMG_GLOBAL_DOOR].bitmap, drawto,
             DOOR_GFX_PAGEX4 + VIDEO_CONTROL_XPOS,
             DOOR_GFX_PAGEY2 + VIDEO_CONTROL_YPOS,
             VIDEO_CONTROL_XSIZE, VIDEO_CONTROL_YSIZE,
@@ -282,7 +284,7 @@ void DrawCompleteVideoDisplay()
     DrawVideoDisplay(VIDEO_STATE_TIME_ON, tape.length_seconds);
   }
 
-  BlitBitmap(drawto, pix[PIX_DB_DOOR], gfx.vx, gfx.vy, gfx.vxsize, gfx.vysize,
+  BlitBitmap(drawto, bitmap_db_door, gfx.vx, gfx.vy, gfx.vxsize, gfx.vysize,
             DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2);
 }
 
@@ -300,6 +302,9 @@ void TapeErase()
   tape.length = 0;
   tape.counter = 0;
 
+  if (leveldir_current)
+    setString(&tape.level_identifier, leveldir_current->identifier);
+
   tape.level_nr = level_nr;
   tape.pos[tape.counter].delay = 0;
   tape.changed = TRUE;
@@ -311,6 +316,11 @@ void TapeErase()
   tape.game_version = GAME_VERSION_ACTUAL;
   tape.engine_version = level.game_version;
 
+#if 0
+  printf("::: tape.engine_version = level.game_version = %d \n",
+        level.game_version);
+#endif
+
   for(i=0; i<MAX_PLAYERS; i++)
     tape.player_participates[i] = FALSE;
 }
@@ -324,6 +334,8 @@ static void TapeRewind()
   tape.playing = FALSE;
   tape.fast_forward = FALSE;
   tape.index_search = FALSE;
+  tape.auto_play = (global.autoplay_leveldir != NULL);
+  tape.auto_play_level_solved = FALSE;
   tape.quick_resume = FALSE;
   tape.single_step = FALSE;
 
@@ -359,7 +371,7 @@ static void TapeStartGameRecording()
   else
 #endif
   {
-    game_status = PLAYING;
+    game_status = GAME_MODE_PLAYING;
     StopAnimation();
     InitGame();
   }
@@ -504,7 +516,7 @@ static void TapeStartGamePlaying()
 {
   TapeStartPlaying();
 
-  game_status = PLAYING;
+  game_status = GAME_MODE_PLAYING;
   StopAnimation();
   InitGame();
 }
@@ -551,7 +563,7 @@ byte *TapePlayAction()
 
   if (tape.counter >= tape.length)     /* end of tape reached */
   {
-    if (tape.index_search)
+    if (tape.index_search && !tape.auto_play)
       TapeTogglePause(TAPE_TOGGLE_MANUAL);
     else
       TapeStop();
@@ -583,6 +595,11 @@ void TapeStop()
     DrawVideoDisplay(VIDEO_STATE_DATE_ON, tape.date);
     DrawVideoDisplay(VIDEO_STATE_TIME_ON, tape.length_seconds);
   }
+
+#if 0
+  if (tape.auto_play)
+    AutoPlayTape();    /* continue automatically playing next tape */
+#endif
 }
 
 unsigned int GetTapeLength()
@@ -607,7 +624,7 @@ static void TapeStartIndexSearch()
   {
     tape.pausing = FALSE;
 
-    SetDrawDeactivationMask(REDRAW_FIELD | REDRAW_DOOR_1);
+    SetDrawDeactivationMask(REDRAW_FIELD);
     audio.sound_deactivated = TRUE;
   }
 }
@@ -636,7 +653,7 @@ static void TapeSingleStep()
 
 void TapeQuickSave()
 {
-  if (game_status == PLAYING)
+  if (game_status == GAME_MODE_PLAYING)
   {
     if (tape.recording)
       TapeHaltRecording();     /* prepare tape for saving on-the-fly */
@@ -646,13 +663,13 @@ void TapeQuickSave()
     else
       SaveTape(tape.level_nr);
   }
-  else if (game_status == MAINMENU)
+  else if (game_status == GAME_MODE_MAIN)
     Request("No game that can be saved !", REQ_CONFIRM);
 }
 
 void TapeQuickLoad()
 {
-  if (game_status == PLAYING || game_status == MAINMENU)
+  if (game_status == GAME_MODE_PLAYING || game_status == GAME_MODE_MAIN)
   {
     TapeStop();
     TapeErase();
@@ -671,6 +688,125 @@ void TapeQuickLoad()
 }
 
 
+/* ------------------------------------------------------------------------- *
+ * tape autoplay functions
+ * ------------------------------------------------------------------------- */
+
+#define MAX_NUM_AUTOPLAY_LEVELS                1000
+
+void AutoPlayTape()
+{
+  static LevelDirTree *autoplay_leveldir = NULL;
+  static boolean autoplay_initialized = FALSE;
+  static int autoplay_level_nr = -1;
+  static int num_levels_played = 0;
+  static int num_levels_solved = 0;
+  static boolean levels_failed[MAX_NUM_AUTOPLAY_LEVELS];
+  int i;
+
+  if (autoplay_initialized)
+  {
+    /* just finished auto-playing tape */
+    printf("%s.\n", tape.auto_play_level_solved ? "solved" : "NOT SOLVED");
+
+    num_levels_played++;
+    if (tape.auto_play_level_solved)
+      num_levels_solved++;
+    else if (level_nr >= 0 && level_nr < MAX_NUM_AUTOPLAY_LEVELS)
+      levels_failed[level_nr] = TRUE;
+  }
+  else
+  {
+    DrawCompleteVideoDisplay();
+    audio.sound_enabled = FALSE;
+
+    autoplay_leveldir = getTreeInfoFromIdentifier(leveldir_first,
+                                                 global.autoplay_leveldir);
+
+    if (autoplay_leveldir == NULL)
+      Error(ERR_EXIT, "no such level identifier: '%s'",
+           global.autoplay_leveldir);
+
+    leveldir_current = autoplay_leveldir;
+
+    if (global.autoplay_level_nr != -1)
+    {
+      autoplay_leveldir->first_level = global.autoplay_level_nr;
+      autoplay_leveldir->last_level  = global.autoplay_level_nr;
+    }
+
+    autoplay_level_nr = autoplay_leveldir->first_level;
+
+    printf_line("=", 79);
+    printf("Automatically playing level tapes\n");
+    printf_line("-", 79);
+    printf("Level series identifier: '%s'\n", autoplay_leveldir->identifier);
+    printf("Level series name:       '%s'\n", autoplay_leveldir->name);
+    printf("Level series author:     '%s'\n", autoplay_leveldir->author);
+    printf("Number of levels:        %d\n",   autoplay_leveldir->levels);
+    printf_line("=", 79);
+    printf("\n");
+
+    for (i=0; i<MAX_NUM_AUTOPLAY_LEVELS; i++)
+      levels_failed[i] = FALSE;
+
+    autoplay_initialized = TRUE;
+  }
+
+  while (autoplay_level_nr <= autoplay_leveldir->last_level)
+  {
+    level_nr = autoplay_level_nr++;
+
+    TapeErase();
+
+    printf("Level %03d: ", level_nr);
+
+    LoadLevel(level_nr);
+    if (level.no_level_file)
+    {
+      printf("(no level)\n");
+      continue;
+    }
+
+    LoadTape(level_nr);
+    if (TAPE_IS_EMPTY(tape))
+    {
+      printf("(no tape)\n");
+      continue;
+    }
+
+    printf("playing tape ... ");
+
+    TapeStartGamePlaying();
+    TapeStartIndexSearch();
+
+    return;
+  }
+
+  printf("\n");
+  printf_line("=", 79);
+  printf("Number of levels played: %d\n", num_levels_played);
+  printf("Number of levels solved: %d (%d%%)\n", num_levels_solved,
+        (num_levels_played ? num_levels_solved * 100 / num_levels_played :0));
+  printf_line("-", 79);
+  printf("Summary (for automatic parsing by scripts):\n");
+  printf("LEVELDIR '%s', SOLVED %d/%d (%d%%)",
+        autoplay_leveldir->identifier, num_levels_solved, num_levels_played,
+        (num_levels_played ? num_levels_solved * 100 / num_levels_played :0));
+  if (num_levels_played != num_levels_solved)
+  {
+    printf(", FAILED:");
+    for (i=0; i<MAX_NUM_AUTOPLAY_LEVELS; i++)
+      if (levels_failed[i])
+       printf(" %03d", i);
+  }
+  printf("\n");
+  printf_line("=", 79);
+
+  CloseAllAndExit(0);
+}
+
+
 /* ---------- new tape button stuff ---------------------------------------- */
 
 /* graphic position values for tape buttons */
@@ -731,7 +867,7 @@ void CreateTapeButtons()
 
   for (i=0; i<NUM_TAPE_BUTTONS; i++)
   {
-    Bitmap *gd_bitmap = pix[PIX_DOOR];
+    Bitmap *gd_bitmap = graphic_info[IMG_GLOBAL_DOOR].bitmap;
     struct GadgetInfo *gi;
     int gd_xoffset, gd_yoffset;
     int gd_x1, gd_x2, gd_y;
@@ -770,6 +906,14 @@ void CreateTapeButtons()
   }
 }
 
+void FreeTapeButtons()
+{
+  int i;
+
+  for (i=0; i<NUM_TAPE_BUTTONS; i++)
+    FreeGadget(tape_gadget[i]);
+}
+
 void MapTapeEjectButton()
 {
   UnmapGadget(tape_gadget[TAPE_CTRL_ID_INDEX]);
@@ -806,7 +950,7 @@ static void HandleTapeButtons(struct GadgetInfo *gi)
 {
   int id = gi->custom_id;
 
-  if (game_status != MAINMENU && game_status != PLAYING)
+  if (game_status != GAME_MODE_MAIN && game_status != GAME_MODE_PLAYING)
     return;
 
   switch (id)
index 6a41a94d8bdf96ae53763d725bc4550aa3d8fbb6..f32ad694c634c359ff1b0471a4969129b121b6a7 100644 (file)
 #define VIDEO_STATE_PBEND      (VIDEO_STATE_PBEND_OFF  | VIDEO_STATE_PBEND_ON)
 
 /* tags to draw video display labels or symbols only */
+/* (negative values to prevent misinterpretation in DrawVideoDisplay(), where
+   the variable "value" is also used for tape length -- better fix this) */
 #define VIDEO_DISPLAY_DEFAULT          0
-#define VIDEO_DISPLAY_LABEL_ONLY       1
-#define VIDEO_DISPLAY_SYMBOL_ONLY      2
+#define VIDEO_DISPLAY_LABEL_ONLY       -1
+#define VIDEO_DISPLAY_SYMBOL_ONLY      -2
 
 
 void DrawVideoDisplay(unsigned long, unsigned long);
@@ -98,7 +100,10 @@ unsigned int GetTapeLength(void);
 void TapeQuickSave(void);
 void TapeQuickLoad(void);
 
+void AutoPlayTape(void);
+
 void CreateTapeButtons();
+void FreeTapeButtons();
 void MapTapeEjectButton();
 void MapTapeIndexButton();
 void MapTapeButtons();
index e5055eda6513d061b8f6eaab76c1922a3f4f6158..744065cd5923675762f020124912bc5a78a6dd8e 100644 (file)
 #define NUM_TOOL_BUTTONS       7
 
 /* forward declaration for internal use */
-static int getGraphicAnimationPhase(int, int, int);
-static void DrawGraphicAnimationShiftedThruMask(int, int, int, int, int,
-                                               int, int, int);
 static void UnmapToolButtons();
 static void HandleToolButtons(struct GadgetInfo *);
+static int el_act_dir2crm(int, int, int);
 
 static struct GadgetInfo *tool_gadget[NUM_TOOL_BUTTONS];
 static int request_gadget_id = -1;
@@ -73,7 +71,7 @@ void SetDrawtoField(int mode)
 
 void RedrawPlayfield(boolean force_redraw, int x, int y, int width, int height)
 {
-  if (game_status == PLAYING)
+  if (game_status == GAME_MODE_PLAYING)
   {
     if (force_redraw)
     {
@@ -121,7 +119,7 @@ void BackToFront()
   int x,y;
   DrawBuffer *buffer = (drawto_field == window ? backbuffer : drawto_field);
 
-  if (setup.direct_draw && game_status == PLAYING)
+  if (setup.direct_draw && game_status == GAME_MODE_PLAYING)
     redraw_mask &= ~REDRAW_MAIN;
 
   if (redraw_mask & REDRAW_TILES && redraw_tiles > REDRAWTILES_THRESHOLD)
@@ -133,7 +131,7 @@ void BackToFront()
   if (redraw_mask == REDRAW_NONE)
     return;
 
-  if (global.fps_slowdown && game_status == PLAYING)
+  if (global.fps_slowdown && game_status == GAME_MODE_PLAYING)
   {
     static boolean last_frame_skipped = FALSE;
     boolean skip_even_when_not_scrolling = TRUE;
@@ -178,7 +176,8 @@ void BackToFront()
 
   if (redraw_mask & REDRAW_FIELD)
   {
-    if (game_status != PLAYING || redraw_mask & REDRAW_FROM_BACKBUFFER)
+    if (game_status != GAME_MODE_PLAYING ||
+       redraw_mask & REDRAW_FROM_BACKBUFFER)
     {
       BlitBitmap(backbuffer, window,
                 REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE, REAL_SX, REAL_SY);
@@ -246,19 +245,18 @@ void BackToFront()
                     VX+VIDEO_CONTROL_XPOS,VY+VIDEO_CONTROL_YPOS);
       }
     }
+
     if (redraw_mask & REDRAW_DOOR_3)
       BlitBitmap(backbuffer, window, EX, EY, EXSIZE, EYSIZE, EX, EY);
+
     redraw_mask &= ~REDRAW_DOORS;
   }
 
   if (redraw_mask & REDRAW_MICROLEVEL)
   {
-    BlitBitmap(backbuffer, window,
-              MICROLEV_XPOS, MICROLEV_YPOS, MICROLEV_XSIZE, MICROLEV_YSIZE,
-              MICROLEV_XPOS, MICROLEV_YPOS);
-    BlitBitmap(backbuffer, window,
-              SX, MICROLABEL_YPOS, SXSIZE, FONT4_YSIZE,
-              SX, MICROLABEL_YPOS);
+    BlitBitmap(backbuffer, window, SX, SY + 10 * TILEY, SXSIZE, 7 * TILEY,
+              SX, SY + 10 * TILEY);
+
     redraw_mask &= ~REDRAW_MICROLEVEL;
   }
 
@@ -282,7 +280,7 @@ void BackToFront()
       info1[0] = '\0';
 
     sprintf(text, "%.1f fps%s", global.frames_per_second, info1);
-    DrawTextExt(window, SX, SY, text, FS_SMALL, FC_YELLOW);
+    DrawTextExt(window, SX, SY, text, FONT_TEXT_2, BLIT_OPAQUE);
   }
 
   FlushDisplay();
@@ -365,11 +363,34 @@ void FadeToFront()
   BackToFront();
 }
 
+void SetMainBackgroundImage(int graphic)
+{
+  SetMainBackgroundBitmap(graphic == IMG_UNDEFINED ? NULL :
+                         graphic_info[graphic].bitmap ?
+                         graphic_info[graphic].bitmap :
+                         graphic_info[IMG_BACKGROUND].bitmap);
+}
+
+void SetDoorBackgroundImage(int graphic)
+{
+  SetDoorBackgroundBitmap(graphic == IMG_UNDEFINED ? NULL :
+                         graphic_info[graphic].bitmap ?
+                         graphic_info[graphic].bitmap :
+                         graphic_info[IMG_BACKGROUND].bitmap);
+}
+
+void DrawBackground(int dest_x, int dest_y, int width, int height)
+{
+  ClearRectangleOnBackground(backbuffer, dest_x, dest_y, width, height);
+
+  redraw_mask |= REDRAW_FIELD;
+}
+
 void ClearWindow()
 {
-  ClearRectangle(backbuffer, REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE);
+  DrawBackground(REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE);
 
-  if (setup.soft_scrolling && game_status == PLAYING)
+  if (setup.soft_scrolling && game_status == GAME_MODE_PLAYING)
   {
     ClearRectangle(fieldbuffer, 0, 0, FXSIZE, FYSIZE);
     SetDrawtoField(DRAW_BUFFERED);
@@ -377,13 +398,11 @@ void ClearWindow()
   else
     SetDrawtoField(DRAW_BACKBUFFER);
 
-  if (setup.direct_draw && game_status == PLAYING)
+  if (setup.direct_draw && game_status == GAME_MODE_PLAYING)
   {
     ClearRectangle(window, REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE);
     SetDrawtoField(DRAW_DIRECT);
   }
-
-  redraw_mask |= REDRAW_FIELD;
 }
 
 void MarkTileDirty(int x, int y)
@@ -402,14 +421,14 @@ void SetBorderElement()
 {
   int x, y;
 
-  BorderElement = EL_LEERRAUM;
+  BorderElement = EL_EMPTY;
 
-  for(y=0; y<lev_fieldy && BorderElement == EL_LEERRAUM; y++)
+  for(y=0; y<lev_fieldy && BorderElement == EL_EMPTY; y++)
   {
     for(x=0; x<lev_fieldx; x++)
     {
-      if (!IS_MASSIVE(Feld[x][y]))
-       BorderElement = EL_BETON;
+      if (!IS_INDESTRUCTIBLE(Feld[x][y]))
+       BorderElement = EL_STEELWALL;
 
       if (y != 0 && y != lev_fieldy - 1 && x != lev_fieldx - 1)
        x = lev_fieldx - 2;
@@ -417,6 +436,98 @@ void SetBorderElement()
   }
 }
 
+void SetRandomAnimationValue(int x, int y)
+{
+  gfx.anim_random_frame = GfxRandom[x][y];
+}
+
+inline 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;
+
+  return getAnimationFrame(graphic_info[graphic].anim_frames,
+                          graphic_info[graphic].anim_delay,
+                          graphic_info[graphic].anim_mode,
+                          graphic_info[graphic].anim_start_frame,
+                          sync_frame);
+}
+
+inline void DrawGraphicAnimationExt(DrawBuffer *dst_bitmap, int x, int y,
+                                   int graphic, int sync_frame, int mask_mode)
+{
+  int frame = getGraphicAnimationFrame(graphic, sync_frame);
+
+  if (mask_mode == USE_MASKING)
+    DrawGraphicThruMaskExt(dst_bitmap, x, y, graphic, frame);
+  else
+    DrawGraphicExt(dst_bitmap, x, y, graphic, frame);
+}
+
+inline void DrawGraphicAnimation(int x, int y, int graphic)
+{
+  int lx = LEVELX(x), ly = LEVELY(y);
+
+  if (!IN_SCR_FIELD(x, y))
+    return;
+
+  DrawGraphicAnimationExt(drawto_field, FX + x * TILEX, FY + y * TILEY,
+                         graphic, GfxFrame[lx][ly], NO_MASKING);
+  MarkTileDirty(x, y);
+}
+
+void DrawLevelGraphicAnimation(int x, int y, int graphic)
+{
+  DrawGraphicAnimation(SCREENX(x), SCREENY(y), graphic);
+}
+
+void DrawLevelElementAnimation(int x, int y, int element)
+{
+#if 1
+  int graphic = el_act_dir2img(element, GfxAction[x][y], MovDir[x][y]);
+
+  DrawGraphicAnimation(SCREENX(x), SCREENY(y), graphic);
+#else
+  DrawGraphicAnimation(SCREENX(x), SCREENY(y), el2img(element));
+#endif
+}
+
+inline void DrawLevelGraphicAnimationIfNeeded(int x, int y, int graphic)
+{
+  int sx = SCREENX(x), sy = SCREENY(y);
+
+  if (!IN_LEV_FIELD(x, y) || !IN_SCR_FIELD(sx, sy))
+    return;
+
+  if (!IS_NEW_FRAME(GfxFrame[x][y], graphic))
+    return;
+
+  DrawGraphicAnimation(sx, sy, graphic);
+
+  if (CAN_BE_CRUMBLED(Feld[x][y]))
+    DrawLevelFieldCrumbledSand(x, y);
+}
+
+void DrawLevelElementAnimationIfNeeded(int x, int y, int element)
+{
+  int sx = SCREENX(x), sy = SCREENY(y);
+  int graphic;
+
+  if (!IN_LEV_FIELD(x, y) || !IN_SCR_FIELD(sx, sy))
+    return;
+
+  graphic = el_act_dir2img(element, GfxAction[x][y], MovDir[x][y]);
+
+  if (!IS_NEW_FRAME(GfxFrame[x][y], graphic))
+    return;
+
+  DrawGraphicAnimation(sx, sy, graphic);
+
+  if (CAN_BE_CRUMBLED(element))
+    DrawLevelFieldCrumbledSand(x, y);
+}
+
 void DrawAllPlayers()
 {
   int i;
@@ -436,14 +547,35 @@ void DrawPlayerField(int x, int y)
 
 void DrawPlayer(struct PlayerInfo *player)
 {
+#if 0
   int jx = player->jx, jy = player->jy;
   int last_jx = player->last_jx, last_jy = player->last_jy;
   int next_jx = jx + (jx - last_jx), next_jy = jy + (jy - last_jy);
   int sx = SCREENX(jx), sy = SCREENY(jy);
   int sxx = 0, syy = 0;
   int element = Feld[jx][jy], last_element = Feld[last_jx][last_jy];
-  int graphic, phase;
+  int graphic;
+  int frame = 0;
   boolean player_is_moving = (last_jx != jx || last_jy != jy ? TRUE : FALSE);
+  int move_dir = player->MovDir;
+  int action = ACTION_DEFAULT;
+#else
+  int jx = player->jx, jy = player->jy;
+  int move_dir = player->MovDir;
+  int dx = (move_dir == MV_LEFT ? -1 : move_dir == MV_RIGHT ? +1 : 0);
+  int dy = (move_dir == MV_UP   ? -1 : move_dir == MV_DOWN  ? +1 : 0);
+  int last_jx = (player->is_moving ? jx - dx : jx);
+  int last_jy = (player->is_moving ? jy - dy : jy);
+  int next_jx = jx + dx;
+  int next_jy = jy + dy;
+  int sx = SCREENX(jx), sy = SCREENY(jy);
+  int sxx = 0, syy = 0;
+  int element = Feld[jx][jy], last_element = Feld[last_jx][last_jy];
+  int graphic;
+  int frame = 0;
+  boolean player_is_moving = (player->MovPos ? TRUE : FALSE);
+  int action = ACTION_DEFAULT;
+#endif
 
   if (!player->active || !IN_SCR_FIELD(SCREENX(last_jx), SCREENY(last_jy)))
     return;
@@ -458,37 +590,60 @@ void DrawPlayer(struct PlayerInfo *player)
   }
 #endif
 
-  if (element == EL_EXPLODING)
+  if (element == EL_EXPLOSION)
     return;
 
-  /* draw things in the field the player is leaving, if needed */
+  action = (player->Pushing ? ACTION_PUSHING :
+           player->is_digging ? ACTION_DIGGING :
+           player->is_collecting ? ACTION_COLLECTING :
+           player->is_moving ? ACTION_MOVING :
+           player->snapped ? ACTION_SNAPPING : ACTION_DEFAULT);
+
+  InitPlayerGfxAnimation(player, action, move_dir);
+
+  /* ----------------------------------------------------------------------- */
+  /* draw things in the field the player is leaving, if needed               */
+  /* ----------------------------------------------------------------------- */
 
+#if 1
+  if (player->is_moving)
+#else
   if (player_is_moving)
+#endif
   {
-    if (Store[last_jx][last_jy] && IS_DRAWABLE(last_element))
+    if (Back[last_jx][last_jy] && IS_DRAWABLE(last_element))
     {
-      DrawLevelElement(last_jx, last_jy, Store[last_jx][last_jy]);
-      if (last_element == EL_DYNAMITE_ACTIVE)
+      DrawLevelElement(last_jx, last_jy, Back[last_jx][last_jy]);
+
+      if (last_element == EL_DYNAMITE_ACTIVE ||
+         last_element == EL_SP_DISK_RED_ACTIVE)
        DrawDynamite(last_jx, last_jy);
       else
        DrawLevelFieldThruMask(last_jx, last_jy);
     }
-    else if (last_element == EL_DYNAMITE_ACTIVE)
+    else if (last_element == EL_DYNAMITE_ACTIVE ||
+            last_element == EL_SP_DISK_RED_ACTIVE)
       DrawDynamite(last_jx, last_jy);
     else
       DrawLevelField(last_jx, last_jy);
 
     if (player->Pushing && IN_SCR_FIELD(SCREENX(next_jx), SCREENY(next_jy)))
     {
+#if 1
+#if 1
+      DrawLevelElement(next_jx, next_jy, EL_EMPTY);
+#else
       if (player->GfxPos)
       {
-       if (Feld[next_jx][next_jy] == EL_SOKOBAN_FELD_VOLL)
-         DrawLevelElement(next_jx, next_jy, EL_SOKOBAN_FELD_LEER);
+       if (Feld[next_jx][next_jy] == EL_SOKOBAN_FIELD_FULL)
+         DrawLevelElement(next_jx, next_jy, EL_SOKOBAN_FIELD_EMPTY);
        else
-         DrawLevelElement(next_jx, next_jy, EL_LEERRAUM);
+         DrawLevelElement(next_jx, next_jy, EL_EMPTY);
       }
       else
        DrawLevelField(next_jx, next_jy);
+#endif
+#endif
     }
   }
 
@@ -498,90 +653,66 @@ void DrawPlayer(struct PlayerInfo *player)
   if (setup.direct_draw)
     SetDrawtoField(DRAW_BUFFERED);
 
-  /* draw things behind the player, if needed */
+  /* ----------------------------------------------------------------------- */
+  /* draw things behind the player, if needed                                */
+  /* ----------------------------------------------------------------------- */
 
-  if (Store[jx][jy])
-    DrawLevelElement(jx, jy, Store[jx][jy]);
-  else if (!IS_ACTIVE_BOMB(element))
-    DrawLevelField(jx, jy);
+  if (Back[jx][jy])
+    DrawLevelElement(jx, jy, Back[jx][jy]);
+  else if (IS_ACTIVE_BOMB(element))
+    DrawLevelElement(jx, jy, EL_EMPTY);
   else
-    DrawLevelElement(jx, jy, EL_LEERRAUM);
-
-  /* draw player himself */
-
-  if (game.emulation == EMU_SUPAPLEX)
   {
-    static int last_dir = MV_LEFT;
-    int action = (player->programmed_action ? player->programmed_action :
-                 player->action);
-    boolean action_moving =
-      (player_is_moving ||
-       ((action & (MV_LEFT | MV_RIGHT | MV_UP | MV_DOWN)) &&
-       !(action & ~(MV_LEFT | MV_RIGHT | MV_UP | MV_DOWN))));
-
-    graphic = GFX_SP_MURPHY;
-
-    if (player->Pushing)
+    if (player_is_moving && GfxElement[jx][jy] != EL_UNDEFINED)
     {
-      if (player->MovDir == MV_LEFT)
-       graphic = GFX_MURPHY_PUSH_LEFT;
-      else if (player->MovDir == MV_RIGHT)
-       graphic = GFX_MURPHY_PUSH_RIGHT;
-      else if (player->MovDir & (MV_UP | MV_DOWN) && last_dir == MV_LEFT)
-       graphic = GFX_MURPHY_PUSH_LEFT;
-      else if (player->MovDir & (MV_UP | MV_DOWN) && last_dir == MV_RIGHT)
-       graphic = GFX_MURPHY_PUSH_RIGHT;
-    }
-    else if (player->snapped)
-    {
-      if (player->MovDir == MV_LEFT)
-       graphic = GFX_MURPHY_SNAP_LEFT;
-      else if (player->MovDir == MV_RIGHT)
-       graphic = GFX_MURPHY_SNAP_RIGHT;
-      else if (player->MovDir == MV_UP)
-       graphic = GFX_MURPHY_SNAP_UP;
-      else if (player->MovDir == MV_DOWN)
-       graphic = GFX_MURPHY_SNAP_DOWN;
-    }
-    else if (action_moving)
-    {
-      if (player->MovDir == MV_LEFT)
-       graphic = GFX_MURPHY_GO_LEFT;
-      else if (player->MovDir == MV_RIGHT)
-       graphic = GFX_MURPHY_GO_RIGHT;
-      else if (player->MovDir & (MV_UP | MV_DOWN) && last_dir == MV_LEFT)
-       graphic = GFX_MURPHY_GO_LEFT;
-      else if (player->MovDir & (MV_UP | MV_DOWN) && last_dir == MV_RIGHT)
-       graphic = GFX_MURPHY_GO_RIGHT;
+#if 1
+      if (CAN_BE_CRUMBLED(GfxElement[jx][jy]))
+       DrawLevelFieldCrumbledSandDigging(jx, jy, move_dir, player->StepFrame);
+#else
+      if (GfxElement[jx][jy] == EL_SAND)
+       DrawLevelFieldCrumbledSandDigging(jx, jy, move_dir, player->StepFrame);
+#endif
       else
-       graphic = GFX_MURPHY_GO_LEFT;
+      {
+       int old_element = GfxElement[jx][jy];
+       int old_graphic = el_act_dir2img(old_element, action, move_dir);
+       int frame = getGraphicAnimationFrame(old_graphic, player->StepFrame);
 
-      graphic += getGraphicAnimationPhase(3, 2, ANIM_OSCILLATE);
+       DrawGraphic(sx, sy, old_graphic, frame);
+      }
     }
+    else
+    {
+      GfxElement[jx][jy] = EL_UNDEFINED;
 
-    if (player->MovDir == MV_LEFT || player->MovDir == MV_RIGHT)
-      last_dir = player->MovDir;
+      DrawLevelField(jx, jy);
+    }
   }
-  else
+
+  /* ----------------------------------------------------------------------- */
+  /* draw player himself                                                     */
+  /* ----------------------------------------------------------------------- */
+
+  if (player->use_murphy_graphic)
   {
-    if (player->MovDir == MV_LEFT)
-      graphic =
-       (player->Pushing ? GFX_SPIELER1_PUSH_LEFT : GFX_SPIELER1_LEFT);
-    else if (player->MovDir == MV_RIGHT)
-      graphic =
-       (player->Pushing ? GFX_SPIELER1_PUSH_RIGHT : GFX_SPIELER1_RIGHT);
-    else if (player->MovDir == MV_UP)
-      graphic = GFX_SPIELER1_UP;
-    else       /* MV_DOWN || MV_NO_MOVING */
-      graphic = GFX_SPIELER1_DOWN;
+    static int last_horizontal_dir = MV_LEFT;
+    int direction;
+
+    if (move_dir == MV_LEFT || move_dir == MV_RIGHT)
+      last_horizontal_dir = move_dir;
 
-    graphic += player->index_nr * 3 * HEROES_PER_LINE;
-    graphic += player->Frame;
+    direction = (player->snapped ? move_dir : last_horizontal_dir);
+
+    graphic = el_act_dir2img(EL_SP_MURPHY, player->GfxAction, direction);
   }
+  else
+    graphic = el_act_dir2img(player->element_nr, player->GfxAction, move_dir);
+
+  frame = getGraphicAnimationFrame(graphic, player->Frame);
 
   if (player->GfxPos)
   {
-    if (player->MovDir == MV_LEFT || player->MovDir == MV_RIGHT)
+    if (move_dir == MV_LEFT || move_dir == MV_RIGHT)
       sxx = player->GfxPos;
     else
       syy = player->GfxPos;
@@ -590,86 +721,131 @@ void DrawPlayer(struct PlayerInfo *player)
   if (!setup.soft_scrolling && ScreenMovPos)
     sxx = syy = 0;
 
-  DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, NO_CUTTING);
+  DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
 
   if (SHIELD_ON(player))
   {
-    int graphic = (player->shield_active_time_left ? GFX2_SHIELD_ACTIVE :
-                  GFX2_SHIELD_PASSIVE);
+    int graphic = (player->shield_deadly_time_left ? IMG_SHIELD_DEADLY_ACTIVE :
+                  IMG_SHIELD_NORMAL_ACTIVE);
+    int frame = getGraphicAnimationFrame(graphic, -1);
 
-    DrawGraphicAnimationShiftedThruMask(sx, sy, sxx, syy, graphic,
-                                       3, 8, ANIM_OSCILLATE);
+    DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
   }
 
-  if (player->Pushing && player->GfxPos)
+  /* ----------------------------------------------------------------------- */
+  /* draw things the player is pushing, if needed                            */
+  /* ----------------------------------------------------------------------- */
+
+#if 0
+  printf("::: %d, %d [%d, %d] [%d]\n",
+        player->Pushing, player_is_moving, player->GfxAction,
+        player->is_moving, player_is_moving);
+#endif
+
+#if 1
+  if (player->Pushing && player->is_moving)
+#else
+  if (player->Pushing && player_is_moving)
+#endif
   {
     int px = SCREENX(next_jx), py = SCREENY(next_jy);
 
-    if (element == EL_SOKOBAN_FELD_LEER ||
-       Feld[next_jx][next_jy] == EL_SOKOBAN_FELD_VOLL)
-      DrawGraphicShiftedThruMask(px, py, sxx, syy, GFX_SOKOBAN_OBJEKT,
+    if (Back[next_jx][next_jy])
+      DrawLevelElement(next_jx, next_jy, Back[next_jx][next_jy]);
+
+#if 1
+    if ((sxx || syy) && element == EL_SOKOBAN_OBJECT)
+      DrawGraphicShiftedThruMask(px, py, sxx, syy, IMG_SOKOBAN_OBJECT, 0,
                                 NO_CUTTING);
+#else
+    if ((sxx || syy) &&
+       (element == EL_SOKOBAN_FIELD_EMPTY ||
+        Feld[next_jx][next_jy] == EL_SOKOBAN_FIELD_FULL))
+      DrawGraphicShiftedThruMask(px, py, sxx, syy, IMG_SOKOBAN_OBJECT, 0,
+                                NO_CUTTING);
+#endif
     else
     {
+#if 1
+      int element = MovingOrBlocked2Element(next_jx, next_jy);
+#else
+#if 1
+      int element = Feld[jx][jy];
+#else
       int element = Feld[next_jx][next_jy];
-      int graphic = el2gfx(element);
+#endif
+#endif
 
-      if ((element == EL_FELSBROCKEN ||
-          element == EL_SP_ZONK ||
-          element == EL_BD_ROCK) && sxx)
-      {
-       int phase = (player->GfxPos / (TILEX / 4));
+#if 1
+      int graphic = el2img(element);
+      int frame = 0;
 
-       if (player->MovDir == MV_LEFT)
-         graphic += phase;
-       else
-         graphic += (phase + 4) % 4;
+#if 0
+      if ((sxx || syy) && IS_PUSHABLE(element))
+#endif
+      {
+       graphic = el_act_dir2img(element, ACTION_PUSHING, move_dir);
+       frame = getGraphicAnimationFrame(graphic, player->Frame);
       }
 
-      DrawGraphicShifted(px, py, sxx, syy, graphic, NO_CUTTING, NO_MASKING);
+#if 0
+      printf("::: pushing %d: %d ...\n", sxx, frame);
+#endif
+
+      DrawGraphicShifted(px, py, sxx, syy, graphic, frame,
+                        NO_CUTTING, NO_MASKING);
+#endif
     }
   }
 
-  /* draw things in front of player (active dynamite or dynabombs) */
+  /* ----------------------------------------------------------------------- */
+  /* draw things in front of player (active dynamite or dynabombs)           */
+  /* ----------------------------------------------------------------------- */
 
   if (IS_ACTIVE_BOMB(element))
   {
-    graphic = el2gfx(element);
-
-    if (element == EL_DYNAMITE_ACTIVE)
-    {
-      if ((phase = (96 - MovDelay[jx][jy]) / 12) > 6)
-       phase = 6;
-    }
-    else
-    {
-      if ((phase = ((96 - MovDelay[jx][jy]) / 6) % 8) > 3)
-       phase = 7 - phase;
-    }
+    graphic = el2img(element);
+    frame = getGraphicAnimationFrame(graphic, GfxFrame[jx][jy]);
 
     if (game.emulation == EMU_SUPAPLEX)
-      DrawGraphic(sx, sy, GFX_SP_DISK_RED);
+      DrawGraphic(sx, sy, IMG_SP_DISK_RED, frame);
     else
-      DrawGraphicThruMask(sx, sy, graphic + phase);
+      DrawGraphicThruMask(sx, sy, graphic, frame);
   }
 
-  if (player_is_moving && last_element == EL_EXPLODING)
+  if (player_is_moving && last_element == EL_EXPLOSION)
   {
-    int phase = Frame[last_jx][last_jy];
-    int delay = 2;
+#if 1
+    int graphic = el_act2img(GfxElement[last_jx][last_jy], ACTION_EXPLODING);
+#else
+    int stored = Store[last_jx][last_jy];
+    int graphic = (game.emulation != EMU_SUPAPLEX ? IMG_EXPLOSION :
+                  stored == EL_SP_INFOTRON ? IMG_SP_EXPLOSION_INFOTRON :
+                  IMG_SP_EXPLOSION);
+#endif
+    int delay = (game.emulation == EMU_SUPAPLEX ? 3 : 2);
+    int phase = ExplodePhase[last_jx][last_jy] - 1;
+    int frame = getGraphicAnimationFrame(graphic, phase - delay);
 
-    if (phase > 2)
-      DrawGraphicThruMask(SCREENX(last_jx), SCREENY(last_jy),
-                         GFX_EXPLOSION + ((phase - 1) / delay - 1));
+    if (phase >= delay)
+      DrawGraphicThruMask(SCREENX(last_jx), SCREENY(last_jy), graphic, frame);
   }
 
-  /* draw elements that stay over the player */
+  /* ----------------------------------------------------------------------- */
+  /* draw elements the player is just walking/passing through/under          */
+  /* ----------------------------------------------------------------------- */
+
   /* handle the field the player is leaving ... */
-  if (player_is_moving && IS_OVER_PLAYER(last_element))
+  if (player_is_moving && IS_ACCESSIBLE_INSIDE(last_element))
     DrawLevelField(last_jx, last_jy);
+  else if (player_is_moving && IS_ACCESSIBLE_UNDER(last_element))
+    DrawLevelFieldThruMask(last_jx, last_jy);
+
   /* ... and the field the player is entering */
-  if (IS_OVER_PLAYER(element))
+  if (IS_ACCESSIBLE_INSIDE(element))
     DrawLevelField(jx, jy);
+  else if (IS_ACCESSIBLE_UNDER(element))
+    DrawLevelFieldThruMask(jx, jy);
 
   if (setup.direct_draw)
   {
@@ -686,143 +862,62 @@ void DrawPlayer(struct PlayerInfo *player)
   MarkTileDirty(sx,sy);
 }
 
-static int getGraphicAnimationPhase(int frames, int delay, int mode)
+void getGraphicSource(int graphic, int frame, Bitmap **bitmap, int *x, int *y)
 {
-  int phase;
+  struct GraphicInfo *g = &graphic_info[graphic];
 
-  if (mode == ANIM_OSCILLATE)
-  {
-    int max_anim_frames = 2 * frames - 2;
-    phase = (FrameCounter % (delay * max_anim_frames)) / delay;
-    phase = (phase < frames ? phase : max_anim_frames - phase);
-  }
-  else
-    phase = (FrameCounter % (delay * frames)) / delay;
-
-  if (mode == ANIM_REVERSE)
-    phase = -phase;
+  *bitmap = g->bitmap;
 
-  return(phase);
-}
-
-void DrawGraphicAnimationExt(int x, int y, int graphic,
-                            int frames, int delay, int mode, int mask_mode)
-{
-  int phase = getGraphicAnimationPhase(frames, delay, mode);
-
-  if (!(FrameCounter % delay) && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
+  if (g->offset_y == 0)                /* frames are ordered horizontally */
   {
-    if (mask_mode == USE_MASKING)
-      DrawGraphicThruMask(SCREENX(x), SCREENY(y), graphic + phase);
-    else
-      DrawGraphic(SCREENX(x), SCREENY(y), graphic + phase);
-  }
-}
-
-void DrawGraphicAnimation(int x, int y, int graphic,
-                         int frames, int delay, int mode)
-{
-  DrawGraphicAnimationExt(x, y, graphic, frames, delay, mode, NO_MASKING);
-}
-
-void DrawGraphicAnimationThruMask(int x, int y, int graphic,
-                                 int frames, int delay, int mode)
-{
-  DrawGraphicAnimationExt(x, y, graphic, frames, delay, mode, USE_MASKING);
-}
-
-static void DrawGraphicAnimationShiftedThruMask(int sx, int sy,
-                                               int sxx, int syy,
-                                               int graphic,
-                                               int frames, int delay,
-                                               int mode)
-{
-  int phase = getGraphicAnimationPhase(frames, delay, mode);
-
-  DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic + phase, NO_CUTTING);
-}
+    int max_width = g->anim_frames_per_line * g->width;
 
-void getGraphicSource(int graphic, int *bitmap_nr, int *x, int *y)
-{
-  if (graphic >= GFX_START_ROCKSSCREEN && graphic <= GFX_END_ROCKSSCREEN)
-  {
-    graphic -= GFX_START_ROCKSSCREEN;
-    *bitmap_nr = PIX_BACK;
-    *x = SX + (graphic % GFX_PER_LINE) * TILEX;
-    *y = SY + (graphic / GFX_PER_LINE) * TILEY;
+    *x = (g->src_x + frame * g->offset_x) % max_width;
+    *y = g->src_y + (g->src_x + frame * g->offset_x) / max_width * g->height;
   }
-  else if (graphic >= GFX_START_ROCKSHEROES && graphic <= GFX_END_ROCKSHEROES)
+  else if (g->offset_x == 0)   /* frames are ordered vertically */
   {
-    graphic -= GFX_START_ROCKSHEROES;
-    *bitmap_nr = PIX_HEROES;
-    *x = (graphic % HEROES_PER_LINE) * TILEX;
-    *y = (graphic / HEROES_PER_LINE) * TILEY;
-  }
-  else if (graphic >= GFX_START_ROCKSSP && graphic <= GFX_END_ROCKSSP)
-  {
-    graphic -= GFX_START_ROCKSSP;
-    *bitmap_nr = PIX_SP;
-    *x = (graphic % SP_PER_LINE) * TILEX;
-    *y = (graphic / SP_PER_LINE) * TILEY;
-  }
-  else if (graphic >= GFX_START_ROCKSDC && graphic <= GFX_END_ROCKSDC)
-  {
-    graphic -= GFX_START_ROCKSDC;
-    *bitmap_nr = PIX_DC;
-    *x = (graphic % DC_PER_LINE) * TILEX;
-    *y = (graphic / DC_PER_LINE) * TILEY;
-  }
-  else if (graphic >= GFX_START_ROCKSMORE && graphic <= GFX_END_ROCKSMORE)
-  {
-    graphic -= GFX_START_ROCKSMORE;
-    *bitmap_nr = PIX_MORE;
-    *x = (graphic % MORE_PER_LINE) * TILEX;
-    *y = (graphic / MORE_PER_LINE) * TILEY;
-  }
-  else if (graphic >= GFX_START_ROCKSFONT && graphic <= GFX_END_ROCKSFONT)
-  {
-    graphic -= GFX_START_ROCKSFONT;
-    *bitmap_nr = PIX_BIGFONT;
-    *x = (graphic % FONT_CHARS_PER_LINE) * TILEX;
-    *y = ((graphic / FONT_CHARS_PER_LINE) * TILEY +
-         FC_SPECIAL1 * FONT_LINES_PER_FONT * TILEY);
+    int max_height = g->anim_frames_per_line * g->height;
+
+    *x = g->src_x + (g->src_y + frame * g->offset_y) / max_height * g->width;
+    *y = (g->src_y + frame * g->offset_y) % max_height;
   }
-  else
+  else                         /* frames are ordered diagonally */
   {
-    *bitmap_nr = PIX_SP;
-    *x = 0;
-    *y = 0;
+    *x = g->src_x + frame * g->offset_x;
+    *y = g->src_y + frame * g->offset_y;
   }
 }
 
-void DrawGraphic(int x, int y, int graphic)
+void DrawGraphic(int x, int y, int graphic, int frame)
 {
 #if DEBUG
-  if (!IN_SCR_FIELD(x,y))
+  if (!IN_SCR_FIELD(x, y))
   {
-    printf("DrawGraphic(): x = %d, y = %d, graphic = %d\n",x,y,graphic);
+    printf("DrawGraphic(): x = %d, y = %d, graphic = %d\n", x, y, graphic);
     printf("DrawGraphic(): This should never happen!\n");
     return;
   }
 #endif
 
-  DrawGraphicExt(drawto_field, FX + x*TILEX, FY + y*TILEY, graphic);
-  MarkTileDirty(x,y);
+  DrawGraphicExt(drawto_field, FX + x * TILEX, FY + y * TILEY, graphic, frame);
+  MarkTileDirty(x, y);
 }
 
-void DrawGraphicExt(DrawBuffer *bitmap, int x, int y, int graphic)
+void DrawGraphicExt(DrawBuffer *dst_bitmap, int x, int y, int graphic,
+                   int frame)
 {
-  int bitmap_nr;
+  Bitmap *src_bitmap;
   int src_x, src_y;
 
-  getGraphicSource(graphic, &bitmap_nr, &src_x, &src_y);
-  BlitBitmap(pix[bitmap_nr], bitmap, src_x, src_y, TILEX, TILEY, x, y);
+  getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
+  BlitBitmap(src_bitmap, dst_bitmap, src_x, src_y, TILEX, TILEY, x, y);
 }
 
-void DrawGraphicThruMask(int x, int y, int graphic)
+void DrawGraphicThruMask(int x, int y, int graphic, int frame)
 {
 #if DEBUG
-  if (!IN_SCR_FIELD(x,y))
+  if (!IN_SCR_FIELD(x, y))
   {
     printf("DrawGraphicThruMask(): x = %d,y = %d, graphic = %d\n",x,y,graphic);
     printf("DrawGraphicThruMask(): This should never happen!\n");
@@ -830,154 +925,109 @@ void DrawGraphicThruMask(int x, int y, int graphic)
   }
 #endif
 
-  DrawGraphicThruMaskExt(drawto_field, FX + x*TILEX, FY + y*TILEY, graphic);
-  MarkTileDirty(x,y);
+  DrawGraphicThruMaskExt(drawto_field, FX + x * TILEX, FY + y *TILEY, graphic,
+                        frame);
+  MarkTileDirty(x, y);
 }
 
-void DrawGraphicThruMaskExt(DrawBuffer *d, int dest_x, int dest_y, int graphic)
+void DrawGraphicThruMaskExt(DrawBuffer *d, int dest_x, int dest_y, int graphic,
+                           int frame)
 {
-  int tile = graphic;
-  int bitmap_nr;
-  int src_x, src_y;
+#if 1
   Bitmap *src_bitmap;
+  int src_x, src_y;
   GC drawing_gc;
 
-  if (graphic == GFX_LEERRAUM)
-    return;
+  getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
+  drawing_gc = src_bitmap->stored_clip_gc;
+#else
+  GC drawing_gc = src_bitmap->stored_clip_gc;
+  Bitmap *src_bitmap = graphic_info[graphic].bitmap;
+  int src_x = graphic_info[graphic].src_x;
+  int src_y = graphic_info[graphic].src_y;
+  int offset_x = graphic_info[graphic].offset_x;
+  int offset_y = graphic_info[graphic].offset_y;
 
-  getGraphicSource(graphic, &bitmap_nr, &src_x, &src_y);
-  src_bitmap = pix[bitmap_nr];
-  drawing_gc = pix[bitmap_nr]->stored_clip_gc;
+  src_x += frame * offset_x;
+  src_y += frame * offset_y;
 
-  if (tile_clipmask[tile] != None)
-  {
-    SetClipMask(src_bitmap, tile_clip_gc, tile_clipmask[tile]);
-    SetClipOrigin(src_bitmap, tile_clip_gc, dest_x, dest_y);
-    BlitBitmapMasked(src_bitmap, d,
-                    src_x, src_y, TILEX, TILEY, dest_x, dest_y);
-  }
-  else
-  {
-#if DEBUG
-#ifndef TARGET_SDL
-    printf("DrawGraphicThruMask(): tile '%d' needs clipping!\n", tile);
-#endif
 #endif
 
-    SetClipOrigin(src_bitmap, drawing_gc, dest_x-src_x, dest_y-src_y);
-    BlitBitmapMasked(src_bitmap, d,
-                    src_x, src_y, TILEX, TILEY, dest_x, dest_y);
-  }
+  SetClipOrigin(src_bitmap, drawing_gc, dest_x - src_x, dest_y - src_y);
+  BlitBitmapMasked(src_bitmap, d, src_x, src_y, TILEX, TILEY, dest_x, dest_y);
 }
 
 void DrawMiniGraphic(int x, int y, int graphic)
 {
-  DrawMiniGraphicExt(drawto, SX + x*MINI_TILEX, SY + y*MINI_TILEY, graphic);
-  MarkTileDirty(x/2, y/2);
+  DrawMiniGraphicExt(drawto, SX + x * MINI_TILEX,SY + y * MINI_TILEY, graphic);
+  MarkTileDirty(x / 2, y / 2);
 }
 
 void getMiniGraphicSource(int graphic, Bitmap **bitmap, int *x, int *y)
 {
-  if (graphic >= GFX_START_ROCKSSCREEN && graphic <= GFX_END_ROCKSSCREEN)
-  {
-    graphic -= GFX_START_ROCKSSCREEN;
-    *bitmap = pix[PIX_BACK];
-    *x = MINI_GFX_STARTX + (graphic % MINI_GFX_PER_LINE) * MINI_TILEX;
-    *y = MINI_GFX_STARTY + (graphic / MINI_GFX_PER_LINE) * MINI_TILEY;
-  }
-  else if (graphic >= GFX_START_ROCKSSP && graphic <= GFX_END_ROCKSSP)
-  {
-    graphic -= GFX_START_ROCKSSP;
-    graphic -= ((graphic / SP_PER_LINE) * SP_PER_LINE) / 2;
-    *bitmap = pix[PIX_SP];
-    *x = MINI_SP_STARTX + (graphic % MINI_SP_PER_LINE) * MINI_TILEX;
-    *y = MINI_SP_STARTY + (graphic / MINI_SP_PER_LINE) * MINI_TILEY;
-  }
-  else if (graphic >= GFX_START_ROCKSDC && graphic <= GFX_END_ROCKSDC)
-  {
-    graphic -= GFX_START_ROCKSDC;
-    *bitmap = pix[PIX_DC];
-    *x = MINI_DC_STARTX + (graphic % MINI_DC_PER_LINE) * MINI_TILEX;
-    *y = MINI_DC_STARTY + (graphic / MINI_DC_PER_LINE) * MINI_TILEY;
-  }
-  else if (graphic >= GFX_START_ROCKSMORE && graphic <= GFX_END_ROCKSMORE)
-  {
-    graphic -= GFX_START_ROCKSMORE;
-    *bitmap = pix[PIX_MORE];
-    *x = MINI_MORE_STARTX + (graphic % MINI_MORE_PER_LINE) * MINI_TILEX;
-    *y = MINI_MORE_STARTY + (graphic / MINI_MORE_PER_LINE) * MINI_TILEY;
-  }
-  else if (graphic >= GFX_START_ROCKSFONT && graphic <= GFX_END_ROCKSFONT)
-  {
-    graphic -= GFX_START_ROCKSFONT;
-    *bitmap = pix[PIX_SMALLFONT];
-    *x = (graphic % FONT_CHARS_PER_LINE) * FONT4_XSIZE;
-    *y = ((graphic / FONT_CHARS_PER_LINE) * FONT4_YSIZE +
-             FC_SPECIAL2 * FONT2_YSIZE * FONT_LINES_PER_FONT);
-  }
-  else
-  {
-    *bitmap = pix[PIX_SP];
-    *x = MINI_SP_STARTX;
-    *y = MINI_SP_STARTY;
-  }
+  struct GraphicInfo *g = &graphic_info[graphic];
+  int mini_startx = 0;
+  int mini_starty = g->bitmap->height * 2 / 3;
+
+  *bitmap = g->bitmap;
+  *x = mini_startx + g->src_x / 2;
+  *y = mini_starty + g->src_y / 2;
 }
 
 void DrawMiniGraphicExt(DrawBuffer *d, int x, int y, int graphic)
 {
-  Bitmap *bitmap;
+  Bitmap *src_bitmap;
   int src_x, src_y;
 
-  getMiniGraphicSource(graphic, &bitmap, &src_x, &src_y);
-  BlitBitmap(bitmap, d, src_x, src_y, MINI_TILEX, MINI_TILEY, x, y);
+  getMiniGraphicSource(graphic, &src_bitmap, &src_x, &src_y);
+  BlitBitmap(src_bitmap, d, src_x, src_y, MINI_TILEX, MINI_TILEY, x, y);
 }
 
-void DrawGraphicShifted(int x,int y, int dx,int dy, int graphic,
+void DrawGraphicShifted(int x,int y, int dx,int dy, int graphic, int frame,
                        int cut_mode, int mask_mode)
 {
-  int width = TILEX, height = TILEY;
-  int cx = 0, cy = 0;
-  int src_x, src_y, dest_x, dest_y;
-  int tile = graphic;
-  int bitmap_nr;
   Bitmap *src_bitmap;
   GC drawing_gc;
+  int src_x, src_y;
+  int width = TILEX, height = TILEY;
+  int cx = 0, cy = 0;
+  int dest_x, dest_y;
 
   if (graphic < 0)
   {
-    DrawGraphic(x, y, graphic);
+    DrawGraphic(x, y, graphic, frame);
     return;
   }
 
-  if (dx || dy)                        /* Verschiebung der Grafik? */
+  if (dx || dy)                        /* shifted graphic */
   {
-    if (x < BX1)               /* Element kommt von links ins Bild */
+    if (x < BX1)               /* object enters playfield from the left */
     {
       x = BX1;
       width = dx;
       cx = TILEX - dx;
       dx = 0;
     }
-    else if (x > BX2)          /* Element kommt von rechts ins Bild */
+    else if (x > BX2)          /* object enters playfield from the right */
     {
       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) /* object leaves playfield to the left */
     {
       width += dx;
       cx = -dx;
       dx = 0;
     }
-    else if (x==BX2 && dx > 0) /* Element verläßt rechts das Bild */
+    else if (x==BX2 && dx > 0) /* object leaves playfield to the right */
       width -= dx;
-    else if (dx)               /* allg. Bewegung in x-Richtung */
+    else if (dx)               /* general horizontal movement */
       MarkTileDirty(x + SIGN(dx), y);
 
-    if (y < BY1)               /* Element kommt von oben ins Bild */
+    if (y < BY1)               /* object enters playfield from the top */
     {
-      if (cut_mode==CUT_BELOW) /* Element oberhalb des Bildes */
+      if (cut_mode==CUT_BELOW) /* object completely above top border */
        return;
 
       y = BY1;
@@ -985,13 +1035,13 @@ void DrawGraphicShifted(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)          /* object enters playfield from the bottom */
     {
       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) /* object leaves playfield to the top */
     {
       height += dy;
       cy = -dy;
@@ -999,23 +1049,34 @@ void DrawGraphicShifted(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)            /* object completely above bottom border */
        return;
 
       height = dy;
       cy = TILEY - dy;
       dy = TILEY;
       MarkTileDirty(x, y + 1);
-    }                          /* Element verläßt unten das Bild */
+    }                          /* object leaves playfield to the bottom */
     else if (dy > 0 && (y == BY2 || cut_mode == CUT_BELOW))
       height -= dy;
-    else if (dy)               /* allg. Bewegung in y-Richtung */
+    else if (dy)               /* general vertical movement */
       MarkTileDirty(x, y + SIGN(dy));
   }
 
-  getGraphicSource(graphic, &bitmap_nr, &src_x, &src_y);
-  src_bitmap = pix[bitmap_nr];
-  drawing_gc = pix[bitmap_nr]->stored_clip_gc;
+#if 1
+  getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
+#else
+  src_bitmap = graphic_info[graphic].bitmap;
+  src_x = graphic_info[graphic].src_x;
+  src_y = graphic_info[graphic].src_y;
+  offset_x = graphic_info[graphic].offset_x;
+  offset_y = graphic_info[graphic].offset_y;
+
+  src_x += frame * offset_x;
+  src_y += frame * offset_y;
+#endif
+
+  drawing_gc = src_bitmap->stored_clip_gc;
 
   src_x += cx;
   src_y += cy;
@@ -1034,184 +1095,72 @@ void DrawGraphicShifted(int x,int y, int dx,int dy, int graphic,
 
   if (mask_mode == USE_MASKING)
   {
-    if (tile_clipmask[tile] != None)
-    {
-      SetClipMask(src_bitmap, tile_clip_gc, tile_clipmask[tile]);
-      SetClipOrigin(src_bitmap, tile_clip_gc, dest_x, dest_y);
-      BlitBitmapMasked(src_bitmap, drawto_field,
-                      src_x, src_y, TILEX, TILEY, dest_x, dest_y);
-    }
-    else
-    {
-#if DEBUG
-#ifndef        TARGET_SDL
-      printf("DrawGraphicShifted(): tile '%d' needs clipping!\n", tile);
-#endif
-#endif
-
-      SetClipOrigin(src_bitmap, drawing_gc, dest_x - src_x, dest_y - src_y);
-      BlitBitmapMasked(src_bitmap, drawto_field,
-                      src_x, src_y, width, height, dest_x, dest_y);
-    }
+    SetClipOrigin(src_bitmap, drawing_gc, dest_x - src_x, dest_y - src_y);
+    BlitBitmapMasked(src_bitmap, drawto_field, src_x, src_y, width, height,
+                    dest_x, dest_y);
   }
   else
-    BlitBitmap(pix[bitmap_nr], drawto_field,
-              src_x, src_y, width, height, dest_x, dest_y);
+    BlitBitmap(src_bitmap, drawto_field, src_x, src_y, width, height,
+              dest_x, dest_y);
 
   MarkTileDirty(x,y);
 }
 
-void DrawGraphicShiftedThruMask(int x,int y, int dx,int dy, int graphic,
-                               int cut_mode)
+void DrawGraphicShiftedThruMask(int x, int y, int dx, int dy, int graphic,
+                               int frame, int cut_mode)
 {
-  DrawGraphicShifted(x,y, dx,dy, graphic, cut_mode, USE_MASKING);
+  DrawGraphicShifted(x,y, dx,dy, graphic, frame, cut_mode, USE_MASKING);
 }
 
 void DrawScreenElementExt(int x, int y, int dx, int dy, int element,
                          int cut_mode, int mask_mode)
 {
-  int ux = LEVELX(x), uy = LEVELY(y);
-  int graphic = el2gfx(element);
-  int phase8 = ABS(MovPos[ux][uy]) / (TILEX / 8);
-  int phase4 = phase8 / 2;
-  int phase2  = phase8 / 4;
-  int dir = MovDir[ux][uy];
-
-  if (element == EL_PACMAN || element == EL_KAEFER || element == EL_FLIEGER)
-  {
-    graphic += 4 * !phase2;
+  int lx = LEVELX(x), ly = LEVELY(y);
+  int graphic;
+  int frame;
 
-    if (dir == MV_UP)
-      graphic += 1;
-    else if (dir == MV_LEFT)
-      graphic += 2;
-    else if (dir == MV_DOWN)
-      graphic += 3;
-  }
-  else if (element == EL_SP_SNIKSNAK)
+  if (IN_LEV_FIELD(lx, ly))
   {
-    if (dir == MV_LEFT)
-      graphic = GFX_SP_SNIKSNAK_LEFT;
-    else if (dir == MV_RIGHT)
-      graphic = GFX_SP_SNIKSNAK_RIGHT;
-    else if (dir == MV_UP)
-      graphic = GFX_SP_SNIKSNAK_UP;
-    else
-      graphic = GFX_SP_SNIKSNAK_DOWN;
+    SetRandomAnimationValue(lx, ly);
 
-    graphic += (phase8 < 4 ? phase8 : 7 - phase8);
+    graphic = el_act_dir2img(element, GfxAction[lx][ly], MovDir[lx][ly]);
+    frame = getGraphicAnimationFrame(graphic, GfxFrame[lx][ly]);
   }
-  else if (element == EL_SP_ELECTRON)
+  else /* border element */
   {
-    graphic = GFX2_SP_ELECTRON + getGraphicAnimationPhase(8, 2, ANIM_NORMAL);
+    graphic = el2img(element);
+    frame = getGraphicAnimationFrame(graphic, -1);
   }
-  else if (element == EL_MOLE || element == EL_PINGUIN ||
-          element == EL_SCHWEIN || element == EL_DRACHE)
-  {
-    if (dir == MV_LEFT)
-      graphic = (element == EL_MOLE ? GFX_MOLE_LEFT :
-                element == EL_PINGUIN ? GFX_PINGUIN_LEFT :
-                element == EL_SCHWEIN ? GFX_SCHWEIN_LEFT : GFX_DRACHE_LEFT);
-    else if (dir == MV_RIGHT)
-      graphic = (element == EL_MOLE ? GFX_MOLE_RIGHT :
-                element == EL_PINGUIN ? GFX_PINGUIN_RIGHT :
-                element == EL_SCHWEIN ? GFX_SCHWEIN_RIGHT : GFX_DRACHE_RIGHT);
-    else if (dir == MV_UP)
-      graphic = (element == EL_MOLE ? GFX_MOLE_UP :
-                element == EL_PINGUIN ? GFX_PINGUIN_UP :
-                element == EL_SCHWEIN ? GFX_SCHWEIN_UP : GFX_DRACHE_UP);
-    else
-      graphic = (element == EL_MOLE ? GFX_MOLE_DOWN :
-                element == EL_PINGUIN ? GFX_PINGUIN_DOWN :
-                element == EL_SCHWEIN ? GFX_SCHWEIN_DOWN : GFX_DRACHE_DOWN);
 
-    graphic += phase4;
-  }
-  else if (element == EL_SONDE)
-  {
-    graphic = GFX_SONDE_START + getGraphicAnimationPhase(8, 2, ANIM_NORMAL);
-  }
-  else if (element == EL_SALZSAEURE)
-  {
-    graphic = GFX_GEBLUBBER + getGraphicAnimationPhase(4, 10, ANIM_NORMAL);
-  }
-  else if (element == EL_BUTTERFLY || element == EL_FIREFLY)
-  {
-    graphic += !phase2;
-  }
-  else if (element == EL_BALLOON)
-  {
-    graphic += phase4;
-  }
-  else if ((element == EL_FELSBROCKEN ||
-           element == EL_SP_ZONK ||
-           element == EL_BD_ROCK ||
-           element == EL_SP_INFOTRON ||
-           IS_GEM(element))
-          && !cut_mode)
-  {
-    if (uy >= lev_fieldy-1 || !IS_BELT(Feld[ux][uy+1]))
-    {
-      if (element == EL_FELSBROCKEN ||
-         element == EL_SP_ZONK ||
-         element == EL_BD_ROCK)
-      {
-       if (dir == MV_LEFT)
-         graphic += (4 - phase4) % 4;
-       else if (dir == MV_RIGHT)
-         graphic += phase4;
-       else
-         graphic += phase2 * 2;
-      }
-      else if (element != EL_SP_INFOTRON)
-       graphic += phase2;
-    }
-  }
-  else if (element == EL_MAGIC_WALL_EMPTY ||
-          element == EL_MAGIC_WALL_EMPTYING ||
-          element == EL_MAGIC_WALL_BD_EMPTY ||
-          element == EL_MAGIC_WALL_BD_EMPTYING ||
-          element == EL_MAGIC_WALL_FULL ||
-          element == EL_MAGIC_WALL_BD_FULL)
-  {
-    graphic += 3 + getGraphicAnimationPhase(4, 4, ANIM_REVERSE);
-  }
-  else if (IS_AMOEBOID(element) || element == EL_AMOEBA_DRIPPING)
-  {
-    graphic = (element == EL_AMOEBE_TOT ? GFX_AMOEBE_TOT : GFX_AMOEBE_LEBT);
-    graphic += (x + 2 * y + 4) % 4;
-  }
-  else if (element == EL_MAUER_LEBT)
+  if (element == EL_EXPANDABLE_WALL)
   {
-    boolean links_massiv = FALSE, rechts_massiv = FALSE;
+    boolean left_stopped = FALSE, right_stopped = FALSE;
 
-    if (!IN_LEV_FIELD(ux-1, uy) || IS_MAUER(Feld[ux-1][uy]))
-      links_massiv = TRUE;
-    if (!IN_LEV_FIELD(ux+1, uy) || IS_MAUER(Feld[ux+1][uy]))
-      rechts_massiv = TRUE;
+    if (!IN_LEV_FIELD(lx - 1, ly) || IS_WALL(Feld[lx - 1][ly]))
+      left_stopped = TRUE;
+    if (!IN_LEV_FIELD(lx + 1, ly) || IS_WALL(Feld[lx + 1][ly]))
+      right_stopped = TRUE;
 
-    if (links_massiv && rechts_massiv)
-      graphic = GFX_MAUERWERK;
-    else if (links_massiv)
-      graphic = GFX_MAUER_R;
-    else if (rechts_massiv)
-      graphic = GFX_MAUER_L;
-  }
-  else if ((element == EL_INVISIBLE_STEEL ||
-           element == EL_UNSICHTBAR ||
-           element == EL_SAND_INVISIBLE) && game.light_time_left)
-  {
-    graphic = (element == EL_INVISIBLE_STEEL ? GFX_INVISIBLE_STEEL_ON :
-              element == EL_UNSICHTBAR ? GFX_UNSICHTBAR_ON :
-              GFX_SAND_INVISIBLE_ON);
+    if (left_stopped && right_stopped)
+      graphic = IMG_WALL;
+    else if (left_stopped)
+    {
+      graphic = IMG_EXPANDABLE_WALL_GROWING_RIGHT;
+      frame = graphic_info[graphic].anim_frames - 1;
+    }
+    else if (right_stopped)
+    {
+      graphic = IMG_EXPANDABLE_WALL_GROWING_LEFT;
+      frame = graphic_info[graphic].anim_frames - 1;
+    }
   }
 
   if (dx || dy)
-    DrawGraphicShifted(x, y, dx, dy, graphic, cut_mode, mask_mode);
+    DrawGraphicShifted(x, y, dx, dy, graphic, frame, cut_mode, mask_mode);
   else if (mask_mode == USE_MASKING)
-    DrawGraphicThruMask(x, y, graphic);
+    DrawGraphicThruMask(x, y, graphic, frame);
   else
-    DrawGraphic(x, y, graphic);
+    DrawGraphic(x, y, graphic, frame);
 }
 
 void DrawLevelElementExt(int x, int y, int dx, int dy, int element,
@@ -1234,11 +1183,6 @@ void DrawLevelElementShifted(int x, int y, int dx, int dy, int element,
   DrawLevelElementExt(x, y, dx, dy, element, cut_mode, NO_MASKING);
 }
 
-void DrawScreenElementThruMask(int x, int y, int element)
-{
-  DrawScreenElementExt(x, y, 0, 0, element, NO_CUTTING, USE_MASKING);
-}
-
 void DrawLevelElementThruMask(int x, int y, int element)
 {
   DrawLevelElementExt(x, y, 0, 0, element, NO_CUTTING, USE_MASKING);
@@ -1249,12 +1193,14 @@ void DrawLevelFieldThruMask(int x, int y)
   DrawLevelElementExt(x, y, 0, 0, Feld[x][y], NO_CUTTING, USE_MASKING);
 }
 
-void ErdreichAnbroeckeln(int x, int y)
+static void DrawLevelFieldCrumbledSandExt(int x, int y, int graphic, int frame)
 {
-  int i, width, height, cx,cy;
-  int ux = LEVELX(x), uy = LEVELY(y);
-  int element, graphic;
-  int snip = 4;
+  Bitmap *src_bitmap;
+  int src_x, src_y;
+  int sx = SCREENX(x), sy = SCREENY(y);
+  int element;
+  int width, height, cx, cy, i;
+  int snip = TILEX / 8;        /* number of border pixels from "crumbled graphic" */
   static int xy[4][2] =
   {
     { 0, -1 },
@@ -1263,38 +1209,38 @@ void ErdreichAnbroeckeln(int x, int y)
     { 0, +1 }
   };
 
-  if (!IN_LEV_FIELD(ux, uy))
+  if (!IN_LEV_FIELD(x, y))
     return;
 
-  element = Feld[ux][uy];
+  element = (GfxElement[x][y] != EL_UNDEFINED && Feld[x][y] != EL_EXPLOSION ?
+            GfxElement[x][y] : Feld[x][y]);
 
-  if (element == EL_ERDREICH ||
-      element == EL_LANDMINE ||
-      element == EL_TRAP_INACTIVE ||
-      element == EL_TRAP_ACTIVE)
+  /* crumble field itself */
+  if (CAN_BE_CRUMBLED(element) && !IS_MOVING(x, y))
   {
-    if (!IN_SCR_FIELD(x, y))
+    if (!IN_SCR_FIELD(sx, sy))
       return;
 
-    graphic = GFX_ERDENRAND;
+    getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
 
     for(i=0; i<4; i++)
     {
-      int uxx, uyy;
+      int xx = x + xy[i][0];
+      int yy = y + xy[i][1];
 
-      uxx = ux + xy[i][0];
-      uyy = uy + xy[i][1];
-      if (!IN_LEV_FIELD(uxx, uyy))
-       element = EL_BETON;
-      else
-       element = Feld[uxx][uyy];
+      element = (IN_LEV_FIELD(xx, yy) ? Feld[xx][yy] : BorderElement);
 
-      if (element == EL_ERDREICH ||
-         element == EL_LANDMINE ||
-         element == EL_TRAP_INACTIVE ||
-         element == EL_TRAP_ACTIVE)
+      /* check if neighbour field is of same type */
+      if (CAN_BE_CRUMBLED(element) && !IS_MOVING(xx, yy))
        continue;
 
+#if 0
+      if (Feld[x][y] == EL_CUSTOM_START + 123)
+       printf("::: crumble [%d] THE CHAOS ENGINE (%d, %d): %d, %d\n",
+              i, Feld[x][y], element,
+              CAN_BE_CRUMBLED(element), IS_MOVING(x, y));
+#endif
+
       if (i == 1 || i == 2)
       {
        width = snip;
@@ -1310,33 +1256,27 @@ void ErdreichAnbroeckeln(int x, int y)
        cy = (i == 3 ? TILEY - snip : 0);
       }
 
-      BlitBitmap(pix[PIX_BACK], drawto_field,
-                SX + (graphic % GFX_PER_LINE) * TILEX + cx,
-                SY + (graphic / GFX_PER_LINE) * TILEY + cy,
-                width, height, FX + x * TILEX + cx, FY + y * TILEY + cy);
+      BlitBitmap(src_bitmap, drawto_field, src_x + cx, src_y + cy,
+                width, height, FX + sx * TILEX + cx, FY + sy * TILEY + cy);
     }
 
-    MarkTileDirty(x, y);
+    MarkTileDirty(sx, sy);
   }
-  else
+  else         /* crumble neighbour fields */
   {
-    graphic = GFX_ERDENRAND;
+    getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
 
     for(i=0; i<4; i++)
     {
-      int xx, yy, uxx, uyy;
-
-      xx = x + xy[i][0];
-      yy = y + xy[i][1];
-      uxx = ux + xy[i][0];
-      uyy = uy + xy[i][1];
-
-      if (!IN_LEV_FIELD(uxx, uyy) ||
-         (Feld[uxx][uyy] != EL_ERDREICH &&
-          Feld[uxx][uyy] != EL_LANDMINE &&
-          Feld[uxx][uyy] != EL_TRAP_INACTIVE &&
-          Feld[uxx][uyy] != EL_TRAP_ACTIVE) ||
-         !IN_SCR_FIELD(xx, yy))
+      int xx = x + xy[i][0];
+      int yy = y + xy[i][1];
+      int sxx = sx + xy[i][0];
+      int syy = sy + xy[i][1];
+
+      if (!IN_LEV_FIELD(xx, yy) ||
+         !IN_SCR_FIELD(sxx, syy) ||
+         !CAN_BE_CRUMBLED(Feld[xx][yy]) ||
+         IS_MOVING(xx, yy))
        continue;
 
       if (i == 1 || i == 2)
@@ -1354,20 +1294,93 @@ void ErdreichAnbroeckeln(int x, int y)
        cy = (i==0 ? TILEY-snip : 0);
       }
 
-      BlitBitmap(pix[PIX_BACK], drawto_field,
-                SX + (graphic % GFX_PER_LINE) * TILEX + cx,
-                SY + (graphic / GFX_PER_LINE) * TILEY + cy,
-                width, height, FX + xx * TILEX + cx, FY + yy * TILEY + cy);
+      BlitBitmap(src_bitmap, drawto_field, src_x + cx, src_y + cy,
+                width, height, FX + sxx * TILEX + cx, FY + syy * TILEY + cy);
 
-      MarkTileDirty(xx, yy);
+      MarkTileDirty(sxx, syy);
     }
   }
 }
 
+void DrawLevelFieldCrumbledSand(int x, int y)
+{
+  DrawLevelFieldCrumbledSandExt(x, y, IMG_SAND_CRUMBLED, 0);
+}
+
+void DrawLevelFieldCrumbledSandDigging(int x, int y, int direction,
+                                      int step_frame)
+{
+#if 1
+  int graphic1 = el_act_dir2img(GfxElement[x][y], ACTION_DIGGING, direction);
+  int graphic2 = el_act_dir2crm(GfxElement[x][y], ACTION_DIGGING, direction);
+#else
+  int graphic1 = el_act_dir2img(EL_SAND,          ACTION_DIGGING, direction);
+  int graphic2 = el_act_dir2img(EL_SAND_CRUMBLED, ACTION_DIGGING, direction);
+#endif
+  int frame1 = getGraphicAnimationFrame(graphic1, step_frame);
+  int frame2 = getGraphicAnimationFrame(graphic2, step_frame);
+  int sx = SCREENX(x), sy = SCREENY(y);
+
+  DrawGraphic(sx, sy, graphic1, frame1);
+  DrawLevelFieldCrumbledSandExt(x, y, graphic2, frame2);
+}
+
+void DrawLevelFieldCrumbledSandNeighbours(int x, int y)
+{
+  int sx = SCREENX(x), sy = SCREENY(y);
+  static int xy[4][2] =
+  {
+    { 0, -1 },
+    { -1, 0 },
+    { +1, 0 },
+    { 0, +1 }
+  };
+  int i;
+
+  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];
+
+    if (!IN_LEV_FIELD(xx, yy) ||
+       !IN_SCR_FIELD(sxx, syy) ||
+       !CAN_BE_CRUMBLED(Feld[xx][yy]) ||
+       IS_MOVING(xx, yy))
+      continue;
+
+    DrawLevelField(xx, yy);
+  }
+}
+
+static int getBorderElement(int x, int y)
+{
+  int border[7][2] =
+  {
+    { EL_STEELWALL_TOPLEFT,            EL_INVISIBLE_STEELWALL_TOPLEFT     },
+    { EL_STEELWALL_TOPRIGHT,           EL_INVISIBLE_STEELWALL_TOPRIGHT    },
+    { EL_STEELWALL_BOTTOMLEFT,         EL_INVISIBLE_STEELWALL_BOTTOMLEFT  },
+    { EL_STEELWALL_BOTTOMRIGHT,                EL_INVISIBLE_STEELWALL_BOTTOMRIGHT },
+    { EL_STEELWALL_VERTICAL,           EL_INVISIBLE_STEELWALL_VERTICAL    },
+    { EL_STEELWALL_HORIZONTAL,         EL_INVISIBLE_STEELWALL_HORIZONTAL  },
+    { EL_STEELWALL,                    EL_INVISIBLE_STEELWALL             }
+  };
+  int steel_type = (BorderElement == EL_STEELWALL ? 0 : 1);
+  int steel_position = (x == -1 && y == -1                     ? 0 :
+                       x == lev_fieldx && y == -1              ? 1 :
+                       x == -1 && y == lev_fieldy              ? 2 :
+                       x == lev_fieldx && y == lev_fieldy      ? 3 :
+                       x == -1 || x == lev_fieldx              ? 4 :
+                       y == -1 || y == lev_fieldy              ? 5 : 6);
+
+  return border[steel_position][steel_type];
+}
+
 void DrawScreenElement(int x, int y, int element)
 {
   DrawScreenElementExt(x, y, 0, 0, element, NO_CUTTING, NO_MASKING);
-  ErdreichAnbroeckeln(x, y);
+  DrawLevelFieldCrumbledSand(LEVELX(x), LEVELY(y));
 }
 
 void DrawLevelElement(int x, int y, int element)
@@ -1378,54 +1391,54 @@ void DrawLevelElement(int x, int y, int element)
 
 void DrawScreenField(int x, int y)
 {
-  int ux = LEVELX(x), uy = LEVELY(y);
+  int lx = LEVELX(x), ly = LEVELY(y);
   int element, content;
 
-  if (!IN_LEV_FIELD(ux, uy))
+  if (!IN_LEV_FIELD(lx, ly))
   {
-    if (ux < -1 || ux > lev_fieldx || uy < -1 || uy > lev_fieldy)
-      element = EL_LEERRAUM;
+    if (lx < -1 || lx > lev_fieldx || ly < -1 || ly > lev_fieldy)
+      element = EL_EMPTY;
     else
-      element = BorderElement;
+      element = getBorderElement(lx, ly);
 
     DrawScreenElement(x, y, element);
     return;
   }
 
-  element = Feld[ux][uy];
-  content = Store[ux][uy];
+  element = Feld[lx][ly];
+  content = Store[lx][ly];
 
-  if (IS_MOVING(ux, uy))
+  if (IS_MOVING(lx, ly))
   {
-    int horiz_move = (MovDir[ux][uy] == MV_LEFT || MovDir[ux][uy] == MV_RIGHT);
+    int horiz_move = (MovDir[lx][ly] == MV_LEFT || MovDir[lx][ly] == MV_RIGHT);
     boolean cut_mode = NO_CUTTING;
 
     if (element == EL_QUICKSAND_EMPTYING ||
        element == EL_MAGIC_WALL_EMPTYING ||
-       element == EL_MAGIC_WALL_BD_EMPTYING ||
-       element == EL_AMOEBA_DRIPPING)
+       element == EL_BD_MAGIC_WALL_EMPTYING ||
+       element == EL_AMOEBA_DROPPING)
       cut_mode = CUT_ABOVE;
     else if (element == EL_QUICKSAND_FILLING ||
             element == EL_MAGIC_WALL_FILLING ||
-            element == EL_MAGIC_WALL_BD_FILLING)
+            element == EL_BD_MAGIC_WALL_FILLING)
       cut_mode = CUT_BELOW;
 
     if (cut_mode == CUT_ABOVE)
       DrawScreenElementShifted(x, y, 0, 0, element, NO_CUTTING);
     else
-      DrawScreenElement(x, y, EL_LEERRAUM);
+      DrawScreenElement(x, y, EL_EMPTY);
 
     if (horiz_move)
-      DrawScreenElementShifted(x, y, MovPos[ux][uy], 0, element, NO_CUTTING);
+      DrawScreenElementShifted(x, y, MovPos[lx][ly], 0, element, NO_CUTTING);
     else if (cut_mode == NO_CUTTING)
-      DrawScreenElementShifted(x, y, 0, MovPos[ux][uy], element, cut_mode);
+      DrawScreenElementShifted(x, y, 0, MovPos[lx][ly], element, cut_mode);
     else
-      DrawScreenElementShifted(x, y, 0, MovPos[ux][uy], content, cut_mode);
+      DrawScreenElementShifted(x, y, 0, MovPos[lx][ly], content, cut_mode);
 
-    if (content == EL_SALZSAEURE)
-      DrawLevelElementThruMask(ux, uy + 1, EL_SALZSAEURE);
+    if (content == EL_ACID)
+      DrawLevelElementThruMask(lx, ly + 1, EL_ACID);
   }
-  else if (IS_BLOCKED(ux, uy))
+  else if (IS_BLOCKED(lx, ly))
   {
     int oldx, oldy;
     int sx, sy;
@@ -1433,7 +1446,7 @@ void DrawScreenField(int x, int y)
     boolean cut_mode = NO_CUTTING;
     int element_old, content_old;
 
-    Blocked2Moving(ux, uy, &oldx, &oldy);
+    Blocked2Moving(lx, ly, &oldx, &oldy);
     sx = SCREENX(oldx);
     sy = SCREENY(oldy);
     horiz_move = (MovDir[oldx][oldy] == MV_LEFT ||
@@ -1444,11 +1457,11 @@ void DrawScreenField(int x, int y)
 
     if (element_old == EL_QUICKSAND_EMPTYING ||
        element_old == EL_MAGIC_WALL_EMPTYING ||
-       element_old == EL_MAGIC_WALL_BD_EMPTYING ||
-       element_old == EL_AMOEBA_DRIPPING)
+       element_old == EL_BD_MAGIC_WALL_EMPTYING ||
+       element_old == EL_AMOEBA_DROPPING)
       cut_mode = CUT_ABOVE;
 
-    DrawScreenElement(x, y, EL_LEERRAUM);
+    DrawScreenElement(x, y, EL_EMPTY);
 
     if (horiz_move)
       DrawScreenElementShifted(sx, sy, MovPos[oldx][oldy], 0, element_old,
@@ -1463,7 +1476,7 @@ void DrawScreenField(int x, int y)
   else if (IS_DRAWABLE(element))
     DrawScreenElement(x, y, element);
   else
-    DrawScreenElement(x, y, EL_LEERRAUM);
+    DrawScreenElement(x, y, EL_EMPTY);
 }
 
 void DrawLevelField(int x, int y)
@@ -1492,13 +1505,7 @@ void DrawMiniElement(int x, int y, int element)
 {
   int graphic;
 
-  if (!element)
-  {
-    DrawMiniGraphic(x, y, -1);
-    return;
-  }
-
-  graphic = el2gfx(element);
+  graphic = el2edimg(element);
   DrawMiniGraphic(x, y, graphic);
 }
 
@@ -1507,80 +1514,42 @@ void DrawMiniElementOrWall(int sx, int sy, int scroll_x, int scroll_y)
   int x = sx + scroll_x, y = sy + scroll_y;
 
   if (x < -1 || x > lev_fieldx || y < -1 || y > lev_fieldy)
-    DrawMiniElement(sx, sy, EL_LEERRAUM);
+    DrawMiniElement(sx, sy, EL_EMPTY);
   else if (x > -1 && x < lev_fieldx && y > -1 && y < lev_fieldy)
     DrawMiniElement(sx, sy, Feld[x][y]);
   else
-  {
-    int steel_type, steel_position;
-    int border[6][2] =
-    {
-      { GFX_VSTEEL_UPPER_LEFT, GFX_ISTEEL_UPPER_LEFT  },
-      { GFX_VSTEEL_UPPER_RIGHT,        GFX_ISTEEL_UPPER_RIGHT },
-      { GFX_VSTEEL_LOWER_LEFT, GFX_ISTEEL_LOWER_LEFT  },
-      { GFX_VSTEEL_LOWER_RIGHT,        GFX_ISTEEL_LOWER_RIGHT },
-      { GFX_VSTEEL_VERTICAL,   GFX_ISTEEL_VERTICAL    },
-      { GFX_VSTEEL_HORIZONTAL, GFX_ISTEEL_HORIZONTAL  }
-    };
-
-    steel_type = (BorderElement == EL_BETON ? 0 : 1);
-    steel_position = (x == -1 && y == -1                       ? 0 :
-                     x == lev_fieldx && y == -1                ? 1 :
-                     x == -1 && y == lev_fieldy                ? 2 :
-                     x == lev_fieldx && y == lev_fieldy        ? 3 :
-                     x == -1 || x == lev_fieldx                ? 4 :
-                     y == -1 || y == lev_fieldy                ? 5 : -1);
+    DrawMiniGraphic(sx, sy, el2edimg(getBorderElement(x, y)));
+}
 
-    if (steel_position != -1)
-      DrawMiniGraphic(sx, sy, border[steel_position][steel_type]);
-  }
+void getMicroGraphicSource(int graphic, Bitmap **bitmap, int *x, int *y)
+{
+  Bitmap *src_bitmap = graphic_info[graphic].bitmap;
+  int mini_startx = src_bitmap->width * 3 / 4;
+  int mini_starty = src_bitmap->height * 2 / 3;
+  int src_x = mini_startx + graphic_info[graphic].src_x / 8;
+  int src_y = mini_starty + graphic_info[graphic].src_y / 8;
+
+  *bitmap = src_bitmap;
+  *x = src_x;
+  *y = src_y;
 }
 
 void DrawMicroElement(int xpos, int ypos, int element)
 {
-  int graphic;
-
-  if (element == EL_LEERRAUM)
-    return;
-
-  graphic = el2gfx(element);
+  Bitmap *src_bitmap;
+  int src_x, src_y;
+  int graphic = el2preimg(element);
 
-  if (graphic >= GFX_START_ROCKSSP && graphic <= GFX_END_ROCKSSP)
-  {
-    graphic -= GFX_START_ROCKSSP;
-    graphic -= ((graphic / SP_PER_LINE) * SP_PER_LINE) / 2;
-    BlitBitmap(pix[PIX_SP], drawto,
-              MICRO_SP_STARTX + (graphic % MICRO_SP_PER_LINE) * MICRO_TILEX,
-              MICRO_SP_STARTY + (graphic / MICRO_SP_PER_LINE) * MICRO_TILEY,
-              MICRO_TILEX, MICRO_TILEY, xpos, ypos);
-  }
-  else if (graphic >= GFX_START_ROCKSDC && graphic <= GFX_END_ROCKSDC)
-  {
-    graphic -= GFX_START_ROCKSDC;
-    BlitBitmap(pix[PIX_DC], drawto,
-              MICRO_DC_STARTX + (graphic % MICRO_DC_PER_LINE) * MICRO_TILEX,
-              MICRO_DC_STARTY + (graphic / MICRO_DC_PER_LINE) * MICRO_TILEY,
-              MICRO_TILEX, MICRO_TILEY, xpos, ypos);
-  }
-  else if (graphic >= GFX_START_ROCKSMORE && graphic <= GFX_END_ROCKSMORE)
-  {
-    graphic -= GFX_START_ROCKSMORE;
-    BlitBitmap(pix[PIX_MORE], drawto,
-              MICRO_MORE_STARTX + (graphic % MICRO_MORE_PER_LINE)*MICRO_TILEX,
-              MICRO_MORE_STARTY + (graphic / MICRO_MORE_PER_LINE)*MICRO_TILEY,
-              MICRO_TILEX, MICRO_TILEY, xpos, ypos);
-  }
-  else
-    BlitBitmap(pix[PIX_BACK], drawto,
-              MICRO_GFX_STARTX + (graphic % MICRO_GFX_PER_LINE) * MICRO_TILEX,
-              MICRO_GFX_STARTY + (graphic / MICRO_GFX_PER_LINE) * MICRO_TILEY,
-              MICRO_TILEX, MICRO_TILEY, xpos, ypos);
+  getMicroGraphicSource(graphic, &src_bitmap, &src_x, &src_y);
+  BlitBitmap(src_bitmap, drawto, src_x, src_y, MICRO_TILEX, MICRO_TILEY,
+            xpos, ypos);
 }
 
 void DrawLevel()
 {
   int x,y;
 
+  SetDrawBackgroundMask(REDRAW_NONE);
   ClearWindow();
 
   for(x=BX1; x<=BX2; x++)
@@ -1605,7 +1574,7 @@ static void DrawMicroLevelExt(int xpos, int ypos, int from_x, int from_y)
 {
   int x, y;
 
-  ClearRectangle(drawto, xpos, ypos, MICROLEV_XSIZE, MICROLEV_YSIZE);
+  DrawBackground(xpos, ypos, MICROLEV_XSIZE, MICROLEV_YSIZE);
 
   if (lev_fieldx < STD_LEV_FIELDX)
     xpos += (STD_LEV_FIELDX - lev_fieldx) / 2 * MICRO_TILEX;
@@ -1623,10 +1592,11 @@ static void DrawMicroLevelExt(int xpos, int ypos, int from_x, int from_y)
 
       if (lx >= 0 && lx < lev_fieldx && ly >= 0 && ly < lev_fieldy)
        DrawMicroElement(xpos + x * MICRO_TILEX, ypos + y * MICRO_TILEY,
-                        Ur[lx][ly]);
-      else if (lx >= -1 && lx < lev_fieldx+1 && ly >= -1 && ly < lev_fieldy+1)
+                        level.field[lx][ly]);
+      else if (lx >= -1 && lx < lev_fieldx+1 && ly >= -1 && ly < lev_fieldy+1
+              && BorderElement != EL_EMPTY)
        DrawMicroElement(xpos + x * MICRO_TILEX, ypos + y * MICRO_TILEY,
-                        BorderElement);
+                        getBorderElement(lx, ly));
     }
   }
 
@@ -1640,13 +1610,18 @@ static void DrawMicroLevelExt(int xpos, int ypos, int from_x, int from_y)
 #define MICROLABEL_IMPORTED_FROM       4
 #define MICROLABEL_LEVEL_IMPORT_INFO   5
 
-#define MAX_MICROLABEL_SIZE            (SXSIZE / FONT4_XSIZE)
-
 static void DrawMicroLevelLabelExt(int mode)
 {
-  char label_text[MAX_MICROLABEL_SIZE + 1];
+  char label_text[MAX_OUTPUT_LINESIZE + 1];
+  int max_len_label_text;
+  int font_nr = FONT_TEXT_2;
+
+  if (mode == MICROLABEL_CREATED_BY || mode == MICROLABEL_IMPORTED_FROM)
+    font_nr = FONT_TEXT_3;
 
-  ClearRectangle(drawto, SX, MICROLABEL_YPOS, SXSIZE, FONT4_YSIZE);
+  max_len_label_text = SXSIZE / getFontWidth(font_nr);
+
+  DrawBackground(SX, MICROLABEL_YPOS, SXSIZE, getFontHeight(font_nr));
 
   strncpy(label_text, (mode == MICROLABEL_LEVEL_NAME ? level.name :
                       mode == MICROLABEL_CREATED_BY ? "created by" :
@@ -1654,15 +1629,16 @@ static void DrawMicroLevelLabelExt(int mode)
                       mode == MICROLABEL_IMPORTED_FROM ? "imported from" :
                       mode == MICROLABEL_LEVEL_IMPORT_INFO ?
                       leveldir_current->imported_from : ""),
-         MAX_MICROLABEL_SIZE);
-  label_text[MAX_MICROLABEL_SIZE] = '\0';
+         max_len_label_text);
+  label_text[max_len_label_text] = '\0';
 
   if (strlen(label_text) > 0)
   {
-    int lxpos = SX + (SXSIZE - strlen(label_text) * FONT4_XSIZE) / 2;
+    int text_width = strlen(label_text) * getFontWidth(font_nr);
+    int lxpos = SX + (SXSIZE - text_width) / 2;
     int lypos = MICROLABEL_YPOS;
 
-    DrawText(lxpos, lypos, label_text, FS_SMALL, FC_SPECIAL2);
+    DrawText(lxpos, lypos, label_text, font_nr);
   }
 
   redraw_mask |= REDRAW_MICROLEVEL;
@@ -1674,6 +1650,10 @@ void DrawMicroLevel(int xpos, int ypos, boolean restart)
   static unsigned long label_delay = 0;
   static int from_x, from_y, scroll_direction;
   static int label_state, label_counter;
+  int last_game_status = game_status;  /* save current game status */
+
+  /* force PREVIEW font on preview level */
+  game_status = GAME_MODE_PSEUDO_PREVIEW;
 
   if (restart)
   {
@@ -1689,6 +1669,17 @@ void DrawMicroLevel(int xpos, int ypos, boolean restart)
     DelayReached(&scroll_delay, 0);
     DelayReached(&label_delay, 0);
 
+    if (leveldir_current->name)
+    {
+      int len = strlen(leveldir_current->name);
+      int lxpos = SX + (SXSIZE - len * getFontWidth(FONT_TEXT_1)) / 2;
+      int lypos = SY + 352;
+
+      DrawText(lxpos, lypos, leveldir_current->name, FONT_TEXT_1);
+    }
+
+    game_status = last_game_status;    /* restore current game status */
+
     return;
   }
 
@@ -1757,6 +1748,8 @@ void DrawMicroLevel(int xpos, int ypos, boolean restart)
                   MICROLABEL_LEVEL_IMPORT_INFO : MICROLABEL_EMPTY);
     DrawMicroLevelLabelExt(label_state);
   }
+
+  game_status = last_game_status;      /* restore current game status */
 }
 
 int REQ_in_range(int x, int y)
@@ -1778,28 +1771,38 @@ boolean Request(char *text, unsigned int req_state)
 {
   int mx, my, ty, result = -1;
   unsigned int old_door_state;
+  int last_game_status = game_status;  /* save current game status */
 
 #if defined(PLATFORM_UNIX)
   /* pause network game while waiting for request to answer */
   if (options.network &&
-      game_status == PLAYING &&
+      game_status == GAME_MODE_PLAYING &&
       req_state & REQUEST_WAIT_FOR)
     SendToServer_PausePlaying();
 #endif
 
   old_door_state = GetDoorState();
 
+  /* simulate releasing mouse button over last gadget, if still pressed */
+  if (button_status)
+    HandleGadgets(-1, -1, 0);
+
   UnmapAllGadgets();
 
   CloseDoor(DOOR_CLOSE_1);
 
   /* save old door content */
-  BlitBitmap(pix[PIX_DB_DOOR], pix[PIX_DB_DOOR],
+  BlitBitmap(bitmap_db_door, bitmap_db_door,
             DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE,
             DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY1);
 
+  SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
+
   /* clear door drawing field */
-  ClearRectangle(drawto, DX, DY, DXSIZE, DYSIZE);
+  DrawBackground(DX, DY, DXSIZE, DYSIZE);
+
+  /* force DOOR font on preview level */
+  game_status = GAME_MODE_PSEUDO_DOOR;
 
   /* write text for request */
   for(ty=0; ty < MAX_REQUEST_LINES; ty++)
@@ -1827,12 +1830,15 @@ boolean Request(char *text, unsigned int req_state)
     strncpy(text_line, text, tl);
     text_line[tl] = 0;
 
-    DrawTextExt(drawto, DX + 50 - (tl * 14)/2, DY + 8 + ty * 16,
-               text_line, FS_SMALL, FC_YELLOW);
+    DrawText(DX + (DXSIZE - tl * getFontWidth(FONT_TEXT_2)) / 2,
+            DY + 8 + ty * (getFontHeight(FONT_TEXT_2) + 2),
+            text_line, FONT_TEXT_2);
 
     text += tl + (tc == ' ' ? 1 : 0);
   }
 
+  game_status = last_game_status;      /* restore current game status */
+
   if (req_state & REQ_ASK)
   {
     MapGadget(tool_gadget[TOOL_CTRL_ID_YES]);
@@ -1851,7 +1857,7 @@ boolean Request(char *text, unsigned int req_state)
   }
 
   /* copy request gadgets to door backbuffer */
-  BlitBitmap(drawto, pix[PIX_DB_DOOR],
+  BlitBitmap(drawto, bitmap_db_door,
             DX, DY, DXSIZE, DYSIZE,
             DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
 
@@ -1862,15 +1868,21 @@ boolean Request(char *text, unsigned int req_state)
 #endif
 
   if (!(req_state & REQUEST_WAIT_FOR))
-    return(FALSE);
+  {
+    SetDrawBackgroundMask(REDRAW_FIELD);
+
+    return FALSE;
+  }
 
-  if (game_status != MAINMENU)
+  if (game_status != GAME_MODE_MAIN)
     InitAnimation();
 
   button_status = MB_RELEASED;
 
   request_gadget_id = -1;
 
+  SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
+
   while(result < 0)
   {
     if (PendingEvent())
@@ -1986,7 +1998,7 @@ boolean Request(char *text, unsigned int req_state)
     Delay(10);
   }
 
-  if (game_status != MAINMENU)
+  if (game_status != GAME_MODE_MAIN)
     StopAnimation();
 
   UnmapToolButtons();
@@ -1997,7 +2009,7 @@ boolean Request(char *text, unsigned int req_state)
 
     if (!(req_state & REQ_STAY_CLOSED) && (old_door_state & DOOR_OPEN_1))
     {
-      BlitBitmap(pix[PIX_DB_DOOR], pix[PIX_DB_DOOR],
+      BlitBitmap(bitmap_db_door, bitmap_db_door,
                 DOOR_GFX_PAGEX2,DOOR_GFX_PAGEY1, DXSIZE,DYSIZE,
                 DOOR_GFX_PAGEX1,DOOR_GFX_PAGEY1);
       OpenDoor(DOOR_OPEN_1);
@@ -2006,15 +2018,17 @@ boolean Request(char *text, unsigned int req_state)
 
   RemapAllGadgets();
 
+  SetDrawBackgroundMask(REDRAW_FIELD);
+
 #if defined(PLATFORM_UNIX)
   /* continue network game after request */
   if (options.network &&
-      game_status == PLAYING &&
+      game_status == GAME_MODE_PLAYING &&
       req_state & REQUEST_WAIT_FOR)
     SendToServer_ContinuePlaying();
 #endif
 
-  return(result);
+  return result;
 }
 
 unsigned int OpenDoor(unsigned int door_state)
@@ -2023,7 +2037,7 @@ unsigned int OpenDoor(unsigned int door_state)
 
   if (door_state & DOOR_COPY_BACK)
   {
-    BlitBitmap(pix[PIX_DB_DOOR], pix[PIX_DB_DOOR],
+    BlitBitmap(bitmap_db_door, bitmap_db_door,
               DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE + VYSIZE,
               DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
     door_state &= ~DOOR_COPY_BACK;
@@ -2038,9 +2052,9 @@ unsigned int CloseDoor(unsigned int door_state)
 {
   unsigned int new_door_state;
 
-  BlitBitmap(backbuffer, pix[PIX_DB_DOOR],
+  BlitBitmap(backbuffer, bitmap_db_door,
             DX, DY, DXSIZE, DYSIZE, DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
-  BlitBitmap(backbuffer, pix[PIX_DB_DOOR],
+  BlitBitmap(backbuffer, bitmap_db_door,
             VX, VY, VXSIZE, VYSIZE, DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2);
 
   new_door_state = MoveDoor(door_state);
@@ -2063,8 +2077,8 @@ unsigned int MoveDoor(unsigned int door_state)
   static int door1 = DOOR_OPEN_1;
   static int door2 = DOOR_CLOSE_2;
   static unsigned long door_delay = 0;
-  int x, start, stepsize = 2;
-  unsigned long door_delay_value = stepsize * 5;
+  int x, start, stepsize = door.step_offset;
+  unsigned long door_delay_value = door.step_delay;
 
   if (door_state == DOOR_GET_STATE)
     return(door1 | door2);
@@ -2092,8 +2106,15 @@ unsigned int MoveDoor(unsigned int door_state)
   {
     stepsize = 20;
     door_delay_value = 0;
-    StopSound(SND_MENU_DOOR_OPENING);
-    StopSound(SND_MENU_DOOR_CLOSING);
+
+    StopSound(SND_DOOR_OPENING);
+    StopSound(SND_DOOR_CLOSING);
+  }
+
+  if (global.autoplay_leveldir)
+  {
+    door_state |= DOOR_NO_DELAY;
+    door_state &= ~DOOR_CLOSE_ALL;
   }
 
   if (door_state & DOOR_ACTION)
@@ -2102,26 +2123,27 @@ unsigned int MoveDoor(unsigned int door_state)
     {
       /* opening door sound has priority over simultaneously closing door */
       if (door_state & (DOOR_OPEN_1 | DOOR_OPEN_2))
-       PlaySoundStereo(SND_MENU_DOOR_OPENING, SOUND_MAX_RIGHT);
+       PlaySoundStereo(SND_DOOR_OPENING, SOUND_MIDDLE);
       else if (door_state & (DOOR_CLOSE_1 | DOOR_CLOSE_2))
-       PlaySoundStereo(SND_MENU_DOOR_CLOSING, SOUND_MAX_RIGHT);
+       PlaySoundStereo(SND_DOOR_CLOSING, SOUND_MIDDLE);
     }
 
     start = ((door_state & DOOR_NO_DELAY) ? DXSIZE : 0);
 
     for(x=start; x<=DXSIZE; x+=stepsize)
     {
-      Bitmap *bitmap = pix[PIX_DOOR];
+      Bitmap *bitmap = graphic_info[IMG_GLOBAL_DOOR].bitmap;
       GC gc = bitmap->stored_clip_gc;
 
-      WaitUntilDelayReached(&door_delay, door_delay_value);
+      if (!(door_state & DOOR_NO_DELAY))
+       WaitUntilDelayReached(&door_delay, door_delay_value);
 
       if (door_state & DOOR_ACTION_1)
       {
        int i = (door_state & DOOR_OPEN_1 ? DXSIZE-x : x);
        int j = (DXSIZE - i) / 3;
 
-       BlitBitmap(pix[PIX_DB_DOOR], drawto,
+       BlitBitmap(bitmap_db_door, drawto,
                   DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1 + i/2,
                   DXSIZE,DYSIZE - i/2, DX, DY);
 
@@ -2164,7 +2186,7 @@ unsigned int MoveDoor(unsigned int door_state)
        int i = (door_state & DOOR_OPEN_2 ? VXSIZE - x : x);
        int j = (VXSIZE - i) / 3;
 
-       BlitBitmap(pix[PIX_DB_DOOR], drawto,
+       BlitBitmap(bitmap_db_door, drawto,
                   DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2 + i/2,
                   VXSIZE, VYSIZE - i/2, VX, VY);
 
@@ -2194,15 +2216,15 @@ unsigned int MoveDoor(unsigned int door_state)
 
       BackToFront();
 
-      if (game_status == MAINMENU)
+      if (game_status == GAME_MODE_MAIN)
        DoAnimation();
     }
   }
 
   if (setup.quick_doors)
   {
-    StopSound(SND_MENU_DOOR_OPENING);
-    StopSound(SND_MENU_DOOR_CLOSING);
+    StopSound(SND_DOOR_OPENING);
+    StopSound(SND_DOOR_CLOSING);
   }
 
   if (door_state & DOOR_ACTION_1)
@@ -2216,8 +2238,12 @@ unsigned int MoveDoor(unsigned int door_state)
 void DrawSpecialEditorDoor()
 {
   /* draw bigger toolbox window */
-  BlitBitmap(pix[PIX_DOOR], drawto,
-            DOOR_GFX_PAGEX7, 0, 108, 56, EX - 4, EY - 12);
+  BlitBitmap(graphic_info[IMG_GLOBAL_DOOR].bitmap, drawto,
+            DOOR_GFX_PAGEX7, 0, EXSIZE + 8, 8,
+            EX - 4, EY - 12);
+  BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto,
+            EX - 4, VY - 4, EXSIZE + 8, EYSIZE - VYSIZE + 4,
+            EX - 4, EY - 4);
 
   redraw_mask |= REDRAW_ALL;
 }
@@ -2225,27 +2251,13 @@ void DrawSpecialEditorDoor()
 void UndrawSpecialEditorDoor()
 {
   /* draw normal tape recorder window */
-  BlitBitmap(pix[PIX_BACK], drawto,
-            562, 344, 108, 56, EX - 4, EY - 12);
+  BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto,
+            EX - 4, EY - 12, EXSIZE + 8, EYSIZE - VYSIZE + 12,
+            EX - 4, EY - 12);
 
   redraw_mask |= REDRAW_ALL;
 }
 
-#ifndef        TARGET_SDL
-int ReadPixel(DrawBuffer *bitmap, int x, int y)
-{
-  XImage *pixel_image;
-  unsigned long pixel_value;
-
-  pixel_image = XGetImage(display, bitmap->drawable,
-                         x, y, 1, 1, AllPlanes, ZPixmap);
-  pixel_value = XGetPixel(pixel_image, 0, 0);
-
-  XDestroyImage(pixel_image);
-
-  return pixel_value;
-}
-#endif
 
 /* ---------- new tool button stuff ---------------------------------------- */
 
@@ -2354,7 +2366,7 @@ void CreateToolButtons()
 
   for (i=0; i<NUM_TOOL_BUTTONS; i++)
   {
-    Bitmap *gd_bitmap = pix[PIX_DOOR];
+    Bitmap *gd_bitmap = graphic_info[IMG_GLOBAL_DOOR].bitmap;
     Bitmap *deco_bitmap = None;
     int deco_x = 0, deco_y = 0, deco_xpos = 0, deco_ypos = 0;
     struct GadgetInfo *gi;
@@ -2373,7 +2385,9 @@ void CreateToolButtons()
 
     if (id >= TOOL_CTRL_ID_PLAYER_1 && id <= TOOL_CTRL_ID_PLAYER_4)
     {
-      getMiniGraphicSource(GFX_SPIELER1 + id - TOOL_CTRL_ID_PLAYER_1,
+      int player_nr = id - TOOL_CTRL_ID_PLAYER_1;
+
+      getMiniGraphicSource(PLAYER_NR_GFX(IMG_PLAYER_1, player_nr),
                           &deco_bitmap, &deco_x, &deco_y);
       deco_xpos = (toolbutton_info[i].width - MINI_TILEX) / 2;
       deco_ypos = (toolbutton_info[i].height - MINI_TILEY) / 2;
@@ -2404,6 +2418,14 @@ void CreateToolButtons()
   }
 }
 
+void FreeToolButtons()
+{
+  int i;
+
+  for (i=0; i<NUM_TOOL_BUTTONS; i++)
+    FreeGadget(tool_gadget[i]);
+}
+
 static void UnmapToolButtons()
 {
   int i;
@@ -2421,296 +2443,65 @@ int get_next_element(int element)
 {
   switch(element)
   {
-    case EL_QUICKSAND_FILLING:         return EL_MORAST_VOLL;
-    case EL_QUICKSAND_EMPTYING:                return EL_MORAST_LEER;
+    case EL_QUICKSAND_FILLING:         return EL_QUICKSAND_FULL;
+    case EL_QUICKSAND_EMPTYING:                return EL_QUICKSAND_EMPTY;
     case EL_MAGIC_WALL_FILLING:                return EL_MAGIC_WALL_FULL;
-    case EL_MAGIC_WALL_EMPTYING:       return EL_MAGIC_WALL_EMPTY;
-    case EL_MAGIC_WALL_BD_FILLING:     return EL_MAGIC_WALL_BD_FULL;
-    case EL_MAGIC_WALL_BD_EMPTYING:    return EL_MAGIC_WALL_BD_EMPTY;
-    case EL_AMOEBA_DRIPPING:           return EL_AMOEBE_NASS;
+    case EL_MAGIC_WALL_EMPTYING:       return EL_MAGIC_WALL_ACTIVE;
+    case EL_BD_MAGIC_WALL_FILLING:     return EL_BD_MAGIC_WALL_FULL;
+    case EL_BD_MAGIC_WALL_EMPTYING:    return EL_BD_MAGIC_WALL_ACTIVE;
+    case EL_AMOEBA_DROPPING:           return EL_AMOEBA_WET;
 
     default:                           return element;
   }
 }
 
-int el2gfx(int element)
+int el_act_dir2img(int element, int action, int direction)
 {
-  switch(element)
-  {
-    case EL_LEERRAUM:          return -1;
-    case EL_ERDREICH:          return GFX_ERDREICH;
-    case EL_MAUERWERK:         return GFX_MAUERWERK;
-    case EL_FELSBODEN:         return GFX_FELSBODEN;
-    case EL_FELSBROCKEN:       return GFX_FELSBROCKEN;
-    case EL_SCHLUESSEL:                return GFX_SCHLUESSEL;
-    case EL_EDELSTEIN:         return GFX_EDELSTEIN;
-    case EL_AUSGANG_ZU:                return GFX_AUSGANG_ZU;
-    case EL_AUSGANG_ACT:       return GFX_AUSGANG_ACT;
-    case EL_AUSGANG_AUF:       return GFX_AUSGANG_AUF;
-    case EL_SPIELFIGUR:                return GFX_SPIELFIGUR;
-    case EL_SPIELER1:          return GFX_SPIELER1;
-    case EL_SPIELER2:          return GFX_SPIELER2;
-    case EL_SPIELER3:          return GFX_SPIELER3;
-    case EL_SPIELER4:          return GFX_SPIELER4;
-    case EL_KAEFER:            return GFX_KAEFER;
-    case EL_KAEFER_RIGHT:      return GFX_KAEFER_RIGHT;
-    case EL_KAEFER_UP:         return GFX_KAEFER_UP;
-    case EL_KAEFER_LEFT:       return GFX_KAEFER_LEFT;
-    case EL_KAEFER_DOWN:       return GFX_KAEFER_DOWN;
-    case EL_FLIEGER:           return GFX_FLIEGER;
-    case EL_FLIEGER_RIGHT:     return GFX_FLIEGER_RIGHT;
-    case EL_FLIEGER_UP:                return GFX_FLIEGER_UP;
-    case EL_FLIEGER_LEFT:      return GFX_FLIEGER_LEFT;
-    case EL_FLIEGER_DOWN:      return GFX_FLIEGER_DOWN;
-    case EL_BUTTERFLY:         return GFX_BUTTERFLY;
-    case EL_BUTTERFLY_RIGHT:   return GFX_BUTTERFLY_RIGHT;
-    case EL_BUTTERFLY_UP:      return GFX_BUTTERFLY_UP;
-    case EL_BUTTERFLY_LEFT:    return GFX_BUTTERFLY_LEFT;
-    case EL_BUTTERFLY_DOWN:    return GFX_BUTTERFLY_DOWN;
-    case EL_FIREFLY:           return GFX_FIREFLY;
-    case EL_FIREFLY_RIGHT:     return GFX_FIREFLY_RIGHT;
-    case EL_FIREFLY_UP:                return GFX_FIREFLY_UP;
-    case EL_FIREFLY_LEFT:      return GFX_FIREFLY_LEFT;
-    case EL_FIREFLY_DOWN:      return GFX_FIREFLY_DOWN;
-    case EL_MAMPFER:           return GFX_MAMPFER;
-    case EL_ROBOT:             return GFX_ROBOT;
-    case EL_BETON:             return GFX_BETON;
-    case EL_DIAMANT:           return GFX_DIAMANT;
-    case EL_MORAST_LEER:       return GFX_MORAST_LEER;
-    case EL_MORAST_VOLL:       return GFX_MORAST_VOLL;
-    case EL_QUICKSAND_EMPTYING:        return GFX_MORAST_LEER;
-    case EL_TROPFEN:           return GFX_TROPFEN;
-    case EL_BOMBE:             return GFX_BOMBE;
-    case EL_MAGIC_WALL_OFF:    return GFX_MAGIC_WALL_OFF;
-    case EL_MAGIC_WALL_EMPTY:  return GFX_MAGIC_WALL_EMPTY;
-    case EL_MAGIC_WALL_EMPTYING:return GFX_MAGIC_WALL_EMPTY;
-    case EL_MAGIC_WALL_FULL:   return GFX_MAGIC_WALL_FULL;
-    case EL_MAGIC_WALL_DEAD:   return GFX_MAGIC_WALL_DEAD;
-    case EL_SALZSAEURE:                return GFX_SALZSAEURE;
-    case EL_AMOEBE_TOT:                return GFX_AMOEBE_TOT;
-    case EL_AMOEBE_NASS:       return GFX_AMOEBE_NASS;
-    case EL_AMOEBE_NORM:       return GFX_AMOEBE_NORM;
-    case EL_AMOEBE_VOLL:       return GFX_AMOEBE_VOLL;
-    case EL_AMOEBE_BD:         return GFX_AMOEBE_BD;
-    case EL_AMOEBA2DIAM:       return GFX_AMOEBA2DIAM;
-    case EL_AMOEBA_DRIPPING:   return GFX_AMOEBE_NASS;
-    case EL_KOKOSNUSS:         return GFX_KOKOSNUSS;
-    case EL_LIFE:              return GFX_LIFE;
-    case EL_LIFE_ASYNC:                return GFX_LIFE_ASYNC;
-    case EL_DYNAMITE_ACTIVE:   return GFX_DYNAMIT;
-    case EL_BADEWANNE:         return GFX_BADEWANNE;
-    case EL_BADEWANNE1:                return GFX_BADEWANNE1;
-    case EL_BADEWANNE2:                return GFX_BADEWANNE2;
-    case EL_BADEWANNE3:                return GFX_BADEWANNE3;
-    case EL_BADEWANNE4:                return GFX_BADEWANNE4;
-    case EL_BADEWANNE5:                return GFX_BADEWANNE5;
-    case EL_ABLENK_AUS:                return GFX_ABLENK_AUS;
-    case EL_ABLENK_EIN:                return GFX_ABLENK_EIN;
-    case EL_SCHLUESSEL1:       return GFX_SCHLUESSEL1;
-    case EL_SCHLUESSEL2:       return GFX_SCHLUESSEL2;
-    case EL_SCHLUESSEL3:       return GFX_SCHLUESSEL3;
-    case EL_SCHLUESSEL4:       return GFX_SCHLUESSEL4;
-    case EL_PFORTE1:           return GFX_PFORTE1;
-    case EL_PFORTE2:           return GFX_PFORTE2;
-    case EL_PFORTE3:           return GFX_PFORTE3;
-    case EL_PFORTE4:           return GFX_PFORTE4;
-    case EL_PFORTE1X:          return GFX_PFORTE1X;
-    case EL_PFORTE2X:          return GFX_PFORTE2X;
-    case EL_PFORTE3X:          return GFX_PFORTE3X;
-    case EL_PFORTE4X:          return GFX_PFORTE4X;
-    case EL_DYNAMITE_INACTIVE: return GFX_DYNAMIT_AUS;
-    case EL_PACMAN:            return GFX_PACMAN;
-    case EL_PACMAN_RIGHT:      return GFX_PACMAN_RIGHT;
-    case EL_PACMAN_UP:         return GFX_PACMAN_UP;
-    case EL_PACMAN_LEFT:       return GFX_PACMAN_LEFT;
-    case EL_PACMAN_DOWN:       return GFX_PACMAN_DOWN;
-    case EL_UNSICHTBAR:                return GFX_UNSICHTBAR;
-    case EL_ERZ_EDEL:          return GFX_ERZ_EDEL;
-    case EL_ERZ_DIAM:          return GFX_ERZ_DIAM;
-    case EL_BIRNE_AUS:         return GFX_BIRNE_AUS;
-    case EL_BIRNE_EIN:         return GFX_BIRNE_EIN;
-    case EL_ZEIT_VOLL:         return GFX_ZEIT_VOLL;
-    case EL_ZEIT_LEER:         return GFX_ZEIT_LEER;
-    case EL_MAUER_LEBT:                return GFX_MAUER_LEBT;
-    case EL_MAUER_X:           return GFX_MAUER_X;
-    case EL_MAUER_Y:           return GFX_MAUER_Y;
-    case EL_MAUER_XY:          return GFX_MAUER_XY;
-    case EL_EDELSTEIN_BD:      return GFX_EDELSTEIN_BD;
-    case EL_EDELSTEIN_GELB:    return GFX_EDELSTEIN_GELB;
-    case EL_EDELSTEIN_ROT:     return GFX_EDELSTEIN_ROT;
-    case EL_EDELSTEIN_LILA:    return GFX_EDELSTEIN_LILA;
-    case EL_ERZ_EDEL_BD:       return GFX_ERZ_EDEL_BD;
-    case EL_ERZ_EDEL_GELB:     return GFX_ERZ_EDEL_GELB;
-    case EL_ERZ_EDEL_ROT:      return GFX_ERZ_EDEL_ROT;
-    case EL_ERZ_EDEL_LILA:     return GFX_ERZ_EDEL_LILA;
-    case EL_MAMPFER2:          return GFX_MAMPFER2;
-    case EL_MAGIC_WALL_BD_OFF: return GFX_MAGIC_WALL_BD_OFF;
-    case EL_MAGIC_WALL_BD_EMPTY:return GFX_MAGIC_WALL_BD_EMPTY;
-    case EL_MAGIC_WALL_BD_EMPTYING:return GFX_MAGIC_WALL_BD_EMPTY;
-    case EL_MAGIC_WALL_BD_FULL:        return GFX_MAGIC_WALL_BD_FULL;
-    case EL_MAGIC_WALL_BD_DEAD:        return GFX_MAGIC_WALL_BD_DEAD;
-    case EL_DYNABOMB_ACTIVE_1: return GFX_DYNABOMB;
-    case EL_DYNABOMB_ACTIVE_2: return GFX_DYNABOMB;
-    case EL_DYNABOMB_ACTIVE_3: return GFX_DYNABOMB;
-    case EL_DYNABOMB_ACTIVE_4: return GFX_DYNABOMB;
-    case EL_DYNABOMB_NR:       return GFX_DYNABOMB_NR;
-    case EL_DYNABOMB_SZ:       return GFX_DYNABOMB_SZ;
-    case EL_DYNABOMB_XL:       return GFX_DYNABOMB_XL;
-    case EL_SOKOBAN_OBJEKT:    return GFX_SOKOBAN_OBJEKT;
-    case EL_SOKOBAN_FELD_LEER: return GFX_SOKOBAN_FELD_LEER;
-    case EL_SOKOBAN_FELD_VOLL: return GFX_SOKOBAN_FELD_VOLL;
-    case EL_MOLE:              return GFX_MOLE;
-    case EL_PINGUIN:           return GFX_PINGUIN;
-    case EL_SCHWEIN:           return GFX_SCHWEIN;
-    case EL_DRACHE:            return GFX_DRACHE;
-    case EL_SONDE:             return GFX_SONDE;
-    case EL_PFEIL_LEFT:                return GFX_PFEIL_LEFT;
-    case EL_PFEIL_RIGHT:       return GFX_PFEIL_RIGHT;
-    case EL_PFEIL_UP:          return GFX_PFEIL_UP;
-    case EL_PFEIL_DOWN:                return GFX_PFEIL_DOWN;
-    case EL_SPEED_PILL:                return GFX_SPEED_PILL;
-    case EL_SP_TERMINAL_ACTIVE:        return GFX_SP_TERMINAL;
-    case EL_SP_BUG_ACTIVE:     return GFX_SP_BUG_ACTIVE;
-    case EL_SP_ZONK:           return GFX_SP_ZONK;
-      /* ^^^^^^^^^^ non-standard position in supaplex graphic set! */
-    case EL_INVISIBLE_STEEL:   return GFX_INVISIBLE_STEEL;
-    case EL_BLACK_ORB:         return GFX_BLACK_ORB;
-    case EL_EM_GATE_1:         return GFX_EM_GATE_1;
-    case EL_EM_GATE_2:         return GFX_EM_GATE_2;
-    case EL_EM_GATE_3:         return GFX_EM_GATE_3;
-    case EL_EM_GATE_4:         return GFX_EM_GATE_4;
-    case EL_EM_GATE_1X:                return GFX_EM_GATE_1X;
-    case EL_EM_GATE_2X:                return GFX_EM_GATE_2X;
-    case EL_EM_GATE_3X:                return GFX_EM_GATE_3X;
-    case EL_EM_GATE_4X:                return GFX_EM_GATE_4X;
-    case EL_EM_KEY_1_FILE:     return GFX_EM_KEY_1;
-    case EL_EM_KEY_2_FILE:     return GFX_EM_KEY_2;
-    case EL_EM_KEY_3_FILE:     return GFX_EM_KEY_3;
-    case EL_EM_KEY_4_FILE:     return GFX_EM_KEY_4;
-    case EL_EM_KEY_1:          return GFX_EM_KEY_1;
-    case EL_EM_KEY_2:          return GFX_EM_KEY_2;
-    case EL_EM_KEY_3:          return GFX_EM_KEY_3;
-    case EL_EM_KEY_4:          return GFX_EM_KEY_4;
-    case EL_PEARL:             return GFX_PEARL;
-    case EL_CRYSTAL:           return GFX_CRYSTAL;
-    case EL_WALL_PEARL:                return GFX_WALL_PEARL;
-    case EL_WALL_CRYSTAL:      return GFX_WALL_CRYSTAL;
-    case EL_DOOR_WHITE:                return GFX_DOOR_WHITE;
-    case EL_DOOR_WHITE_GRAY:   return GFX_DOOR_WHITE_GRAY;
-    case EL_KEY_WHITE:         return GFX_KEY_WHITE;
-    case EL_SHIELD_PASSIVE:    return GFX_SHIELD_PASSIVE;
-    case EL_SHIELD_ACTIVE:     return GFX_SHIELD_ACTIVE;
-    case EL_EXTRA_TIME:                return GFX_EXTRA_TIME;
-    case EL_SWITCHGATE_OPEN:   return GFX_SWITCHGATE_OPEN;
-    case EL_SWITCHGATE_CLOSED: return GFX_SWITCHGATE_CLOSED;
-    case EL_SWITCHGATE_SWITCH_1:return GFX_SWITCHGATE_SWITCH_1;
-    case EL_SWITCHGATE_SWITCH_2:return GFX_SWITCHGATE_SWITCH_2;
-    case EL_BELT1_LEFT:                return GFX_BELT1_LEFT;
-    case EL_BELT1_MIDDLE:      return GFX_BELT1_MIDDLE;
-    case EL_BELT1_RIGHT:       return GFX_BELT1_RIGHT;
-    case EL_BELT1_SWITCH_LEFT: return GFX_BELT1_SWITCH_LEFT;
-    case EL_BELT1_SWITCH_MIDDLE:return GFX_BELT1_SWITCH_MIDDLE;
-    case EL_BELT1_SWITCH_RIGHT:        return GFX_BELT1_SWITCH_RIGHT;
-    case EL_BELT2_LEFT:                return GFX_BELT2_LEFT;
-    case EL_BELT2_MIDDLE:      return GFX_BELT2_MIDDLE;
-    case EL_BELT2_RIGHT:       return GFX_BELT2_RIGHT;
-    case EL_BELT2_SWITCH_LEFT: return GFX_BELT2_SWITCH_LEFT;
-    case EL_BELT2_SWITCH_MIDDLE:return GFX_BELT2_SWITCH_MIDDLE;
-    case EL_BELT2_SWITCH_RIGHT:        return GFX_BELT2_SWITCH_RIGHT;
-    case EL_BELT3_LEFT:                return GFX_BELT3_LEFT;
-    case EL_BELT3_MIDDLE:      return GFX_BELT3_MIDDLE;
-    case EL_BELT3_RIGHT:       return GFX_BELT3_RIGHT;
-    case EL_BELT3_SWITCH_LEFT: return GFX_BELT3_SWITCH_LEFT;
-    case EL_BELT3_SWITCH_MIDDLE:return GFX_BELT3_SWITCH_MIDDLE;
-    case EL_BELT3_SWITCH_RIGHT:        return GFX_BELT3_SWITCH_RIGHT;
-    case EL_BELT4_LEFT:                return GFX_BELT4_LEFT;
-    case EL_BELT4_MIDDLE:      return GFX_BELT4_MIDDLE;
-    case EL_BELT4_RIGHT:       return GFX_BELT4_RIGHT;
-    case EL_BELT4_SWITCH_LEFT: return GFX_BELT4_SWITCH_LEFT;
-    case EL_BELT4_SWITCH_MIDDLE:return GFX_BELT4_SWITCH_MIDDLE;
-    case EL_BELT4_SWITCH_RIGHT:        return GFX_BELT4_SWITCH_RIGHT;
-    case EL_LANDMINE:          return GFX_LANDMINE;
-    case EL_ENVELOPE:          return GFX_ENVELOPE;
-    case EL_LIGHT_SWITCH_OFF:  return GFX_LIGHT_SWITCH_OFF;
-    case EL_LIGHT_SWITCH_ON:   return GFX_LIGHT_SWITCH_ON;
-    case EL_SIGN_EXCLAMATION:  return GFX_SIGN_EXCLAMATION;
-    case EL_SIGN_RADIOACTIVITY:        return GFX_SIGN_RADIOACTIVITY;
-    case EL_SIGN_STOP:         return GFX_SIGN_STOP;
-    case EL_SIGN_WHEELCHAIR:   return GFX_SIGN_WHEELCHAIR;
-    case EL_SIGN_PARKING:      return GFX_SIGN_PARKING;
-    case EL_SIGN_ONEWAY:       return GFX_SIGN_ONEWAY;
-    case EL_SIGN_HEART:                return GFX_SIGN_HEART;
-    case EL_SIGN_TRIANGLE:     return GFX_SIGN_TRIANGLE;
-    case EL_SIGN_ROUND:                return GFX_SIGN_ROUND;
-    case EL_SIGN_EXIT:         return GFX_SIGN_EXIT;
-    case EL_SIGN_YINYANG:      return GFX_SIGN_YINYANG;
-    case EL_SIGN_OTHER:                return GFX_SIGN_OTHER;
-    case EL_MOLE_LEFT:         return GFX_MOLE_LEFT;
-    case EL_MOLE_RIGHT:                return GFX_MOLE_RIGHT;
-    case EL_MOLE_UP:           return GFX_MOLE_UP;
-    case EL_MOLE_DOWN:         return GFX_MOLE_DOWN;
-    case EL_STEEL_SLANTED:     return GFX_STEEL_SLANTED;
-    case EL_SAND_INVISIBLE:    return GFX_SAND_INVISIBLE;
-    case EL_DX_UNKNOWN_15:     return GFX_DX_UNKNOWN_15;
-    case EL_DX_UNKNOWN_42:     return GFX_DX_UNKNOWN_42;
-    case EL_TIMEGATE_OPEN:     return GFX_TIMEGATE_OPEN;
-    case EL_TIMEGATE_CLOSED:   return GFX_TIMEGATE_CLOSED;
-    case EL_TIMEGATE_SWITCH_ON:        return GFX_TIMEGATE_SWITCH;
-    case EL_TIMEGATE_SWITCH_OFF:return GFX_TIMEGATE_SWITCH;
-    case EL_BALLOON:           return GFX_BALLOON;
-    case EL_BALLOON_SEND_LEFT: return GFX_BALLOON_SEND_LEFT;
-    case EL_BALLOON_SEND_RIGHT:        return GFX_BALLOON_SEND_RIGHT;
-    case EL_BALLOON_SEND_UP:   return GFX_BALLOON_SEND_UP;
-    case EL_BALLOON_SEND_DOWN: return GFX_BALLOON_SEND_DOWN;
-    case EL_BALLOON_SEND_ANY:  return GFX_BALLOON_SEND_ANY;
-    case EL_EMC_STEEL_WALL_1:  return GFX_EMC_STEEL_WALL_1;
-    case EL_EMC_STEEL_WALL_2:  return GFX_EMC_STEEL_WALL_2;
-    case EL_EMC_STEEL_WALL_3:  return GFX_EMC_STEEL_WALL_3;
-    case EL_EMC_STEEL_WALL_4:  return GFX_EMC_STEEL_WALL_4;
-    case EL_EMC_WALL_1:                return GFX_EMC_WALL_1;
-    case EL_EMC_WALL_2:                return GFX_EMC_WALL_2;
-    case EL_EMC_WALL_3:                return GFX_EMC_WALL_3;
-    case EL_EMC_WALL_4:                return GFX_EMC_WALL_4;
-    case EL_EMC_WALL_5:                return GFX_EMC_WALL_5;
-    case EL_EMC_WALL_6:                return GFX_EMC_WALL_6;
-    case EL_EMC_WALL_7:                return GFX_EMC_WALL_7;
-    case EL_EMC_WALL_8:                return GFX_EMC_WALL_8;
-    case EL_TUBE_CROSS:                return GFX_TUBE_CROSS;
-    case EL_TUBE_VERTICAL:     return GFX_TUBE_VERTICAL;
-    case EL_TUBE_HORIZONTAL:   return GFX_TUBE_HORIZONTAL;
-    case EL_TUBE_VERT_LEFT:    return GFX_TUBE_VERT_LEFT;
-    case EL_TUBE_VERT_RIGHT:   return GFX_TUBE_VERT_RIGHT;
-    case EL_TUBE_HORIZ_UP:     return GFX_TUBE_HORIZ_UP;
-    case EL_TUBE_HORIZ_DOWN:   return GFX_TUBE_HORIZ_DOWN;
-    case EL_TUBE_LEFT_UP:      return GFX_TUBE_LEFT_UP;
-    case EL_TUBE_LEFT_DOWN:    return GFX_TUBE_LEFT_DOWN;
-    case EL_TUBE_RIGHT_UP:     return GFX_TUBE_RIGHT_UP;
-    case EL_TUBE_RIGHT_DOWN:   return GFX_TUBE_RIGHT_DOWN;
-    case EL_SPRING:            return GFX_SPRING;
-    case EL_SPRING_MOVING:     return GFX_SPRING;
-    case EL_TRAP_INACTIVE:     return GFX_TRAP_INACTIVE;
-    case EL_TRAP_ACTIVE:       return GFX_TRAP_ACTIVE;
-    case EL_BD_WALL:           return GFX_BD_WALL;
-    case EL_BD_ROCK:           return GFX_BD_ROCK;
-    case EL_DX_SUPABOMB:       return GFX_DX_SUPABOMB;
-    case EL_SP_MURPHY_CLONE:   return GFX_SP_MURPHY_CLONE;
-
-    default:
-    {
-      if (IS_CHAR(element))
-       return GFX_CHAR_START + (element - EL_CHAR_START);
-      else if (element >= EL_SP_START && element <= EL_SP_END)
-      {
-       int nr_element = element - EL_SP_START;
-       int gfx_per_line = 8;
-       int nr_graphic =
-         (nr_element / gfx_per_line) * SP_PER_LINE +
-         (nr_element % gfx_per_line);
+  element = GFX_ELEMENT(element);
+  direction = MV_DIR_BIT(direction);
 
-       return GFX_START_ROCKSSP + nr_graphic;
-      }
-      else
-       return -1;
-    }
-  }
+  return element_info[element].direction_graphic[action][direction];
+}
+
+static int el_act_dir2crm(int element, int action, int direction)
+{
+  element = GFX_ELEMENT(element);
+  direction = MV_DIR_BIT(direction);
+
+  return element_info[element].direction_crumbled[action][direction];
+}
+
+int el_act2img(int element, int action)
+{
+  element = GFX_ELEMENT(element);
+
+  return element_info[element].graphic[action];
+}
+
+int el_dir2img(int element, int direction)
+{
+  element = GFX_ELEMENT(element);
+
+  return el_act_dir2img(element, ACTION_DEFAULT, direction);
+}
+
+int el2img(int element)
+{
+  element = GFX_ELEMENT(element);
+
+  return element_info[element].graphic[ACTION_DEFAULT];
+}
+
+int el2edimg(int element)
+{
+  element = GFX_ELEMENT(element);
+
+  return element_info[element].special_graphic[GFX_SPECIAL_ARG_EDITOR];
+}
+
+int el2preimg(int element)
+{
+  element = GFX_ELEMENT(element);
+
+  return element_info[element].special_graphic[GFX_SPECIAL_ARG_PREVIEW];
 }
index 1ed8d163f08be0095d64c67702b77a515caa2237..e7a65872bcf2593d3e54ce884610504637990567 100644 (file)
@@ -63,26 +63,38 @@ void RedrawPlayfield(boolean, int, int, int, int);
 void BackToFront();
 void FadeToFront();
 void ClearWindow();
+void SetMainBackgroundImage(int);
+void SetDoorBackgroundImage(int);
+void DrawBackground(int, int, int, int);
 
 void MarkTileDirty(int, int);
 void SetBorderElement();
 
+void SetRandomAnimationValue(int, int);
+int getGraphicAnimationFrame(int, int);
+void DrawGraphicAnimationExt(DrawBuffer *, int, int, int, int, int);
+void DrawGraphicAnimation(int, int, int);
+void DrawLevelGraphicAnimation(int, int, int);
+void DrawLevelElementAnimation(int, int, int);
+void DrawLevelGraphicAnimationIfNeeded(int, int, int);
+void DrawLevelElementAnimationIfNeeded(int, int, int);
+
 void DrawAllPlayers(void);
 void DrawPlayerField(int, int);
 void DrawPlayer(struct PlayerInfo *);
-void DrawGraphicAnimationExt(int, int, int, int, int, int, int);
-void DrawGraphicAnimation(int, int, int, int, int, int);
-void DrawGraphicAnimationThruMask(int, int, int, int, int, int);
-void getGraphicSource(int, int *, int *, int *);
-void DrawGraphic(int, int, int);
-void DrawGraphicExt(DrawBuffer *, int, int, int);
-void DrawGraphicThruMask(int, int, int);
-void DrawGraphicThruMaskExt(DrawBuffer *, int, int, int);
+
+void getGraphicSource(int, int, Bitmap **, int *, int *);
+void DrawGraphic(int, int, int, int);
+void DrawGraphicExt(DrawBuffer *, int, int, int, int);
+void DrawGraphicThruMask(int, int, int, int);
+void DrawGraphicThruMaskExt(DrawBuffer *, int, int, int, int);
+
 void DrawMiniGraphic(int, int, int);
 void getMiniGraphicSource(int, Bitmap **, int *, int *);
 void DrawMiniGraphicExt(DrawBuffer *, int, int, int);
-void DrawGraphicShifted(int, int, int, int, int, int, int);
-void DrawGraphicShiftedThruMask(int, int, int, int, int, int);
+
+void DrawGraphicShifted(int, int, int, int, int, int, int, int);
+void DrawGraphicShiftedThruMask(int, int, int, int, int, int, int);
 void DrawScreenElementExt(int, int, int, int, int, int, int);
 void DrawLevelElementExt(int, int, int, int, int, int, int);
 void DrawScreenElementShifted(int, int, int, int, int, int);
@@ -90,30 +102,42 @@ void DrawLevelElementShifted(int, int, int, int, int, int);
 void DrawScreenElementThruMask(int, int, int);
 void DrawLevelElementThruMask(int, int, int);
 void DrawLevelFieldThruMask(int, int);
-void ErdreichAnbroeckeln(int, int);
+void DrawLevelFieldCrumbledSand(int, int);
+void DrawLevelFieldCrumbledSandDigging(int, int, int, int);
+void DrawLevelFieldCrumbledSandNeighbours(int, int);
 void DrawScreenElement(int, int, int);
 void DrawLevelElement(int, int, int);
 void DrawScreenField(int, int);
 void DrawLevelField(int, int);
+
 void DrawMiniElement(int, int, int);
 void DrawMiniElementOrWall(int, int, int, int);
+
+void getMicroGraphicSource(int, Bitmap **, int *, int *);
 void DrawMicroElement(int, int, int);
 void DrawLevel(void);
 void DrawMiniLevel(int, int, int, int);
 void DrawMicroLevel(int, int, boolean);
+
 boolean Request(char *, unsigned int);
 unsigned int OpenDoor(unsigned int);
 unsigned int CloseDoor(unsigned int);
 unsigned int GetDoorState(void);
 unsigned int SetDoorState(unsigned int);
 unsigned int MoveDoor(unsigned int);
+
 void DrawSpecialEditorDoor();
 void UndrawSpecialEditorDoor();
-int ReadPixel(DrawBuffer *, int, int);
 
 void CreateToolButtons();
+void FreeToolButtons();
 
 int get_next_element(int);
-int el2gfx(int);
+int el_act_dir2img(int, int, int);
+int el_act2img(int, int);
+int el_dir2img(int, int);
+int el2img(int);
+int el2edimg(int);
+int el2preimg(int);
 
 #endif /* TOOLS_H */