Merge branch 'master' into releases 3.2.0
authorHolger Schemel <info@artsoft.org>
Sat, 30 Aug 2014 08:52:13 +0000 (10:52 +0200)
committerHolger Schemel <info@artsoft.org>
Sat, 30 Aug 2014 08:52:13 +0000 (10:52 +0200)
73 files changed:
ChangeLog
Makefile
src/cartoons.c
src/conf_e2g.c
src/conf_esg.c
src/conf_fnt.c
src/conf_g2m.c
src/conf_g2s.c
src/conf_gfx.c
src/conf_gfx.h
src/conf_mus.c
src/conf_mus.h
src/conf_snd.c
src/conf_snd.h
src/conftime.h
src/editor.c
src/engines.h
src/events.c
src/files.c
src/files.h
src/game.c
src/game.h
src/game_em/cave.c
src/game_em/convert.c
src/game_em/display.h [deleted file]
src/game_em/export.h [new file with mode: 0644]
src/game_em/game_em.h
src/game_em/global.h
src/game_em/graphics.c
src/game_em/init.c
src/game_em/input.c
src/game_em/level.h [deleted file]
src/game_em/main_em.h
src/game_em/sample.h
src/game_em/sound.c
src/game_em/synchro_1.c
src/game_em/synchro_2.c
src/game_em/synchro_3.c
src/game_em/tab_generate.c
src/init.c
src/init.h
src/libgame/gadgets.c
src/libgame/image.c
src/libgame/image.h
src/libgame/joystick.c
src/libgame/misc.c
src/libgame/misc.h
src/libgame/msdos.h
src/libgame/pcx.c
src/libgame/sdl.c
src/libgame/sdl.h
src/libgame/setup.c
src/libgame/setup.h
src/libgame/sound.c
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/x11.c
src/libgame/x11.h
src/main.c
src/main.h
src/netserv.c
src/network.c
src/network.h
src/screens.c
src/screens.h
src/tape.c
src/tape.h
src/tools.c
src/tools.h

index b3ae71e4f88d8d2bd5af778a814b326264e720e4..c3ac63a28215d1bebd9d4994cf16150697c30bc5 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,378 @@
+2006-06-23
+       * reorganized level editor element list a bit to match engines better
+
+2006-06-21
+       * fixed newly introduced bug with wrongly initializing clipboard element
+
+2006-06-19
+       * fixed bug with displaying visible/invisible level border in editor
+
+2006-06-14
+       * reorganized some elements in the level editor element list
+
+2006-06-06
+       * fixed bug with displaying any player as "yellow" when moving into acid
+       * fixed bug with displaying running player when player stopped at border
+
+2006-06-03
+       * fixed bug with player exploding when moving into acid
+       * fixed bug with level settings being reset in editor and when playing
+         (some compatibility settings being set not only after level loading)
+       * fixed crash bug when number of custom graphic frames was set to zero
+       * fixed bug with teleporting player on walkable tile not working anymore
+       * added partial compatibility support for pre-release-only "CONF" chunk
+         (to make Alan Bond's "color cycle" demo work again :-) )
+
+2006-05-30
+       * fixed some bugs when displaying title screens from info screen menu
+       * fixed bug which caused EMC doors #5 to #8 to be passable without keys
+
+2006-05-20
+       * changed file major version to 3 to reflect level file format changes
+       * uploaded pre-release (test) version 3.2.0-8 binary and source code
+
+2006-05-19
+       * added new chunk "NAME" to level file format for level name settings
+       * added new chunk "NOTE" to level file format for envelope settings
+       * changed name of chunk "CONF" to "ELEM" (for normal element settings)
+       * updated magic(5) file to recognize changed and new level file chunks
+       * removed change events "change when CE value/score changes" as unneeded
+
+2006-05-17
+       * changed gravity (which only affects the player) from level property
+         to player property (only makes a difference in multi-player levels)
+       * added change events "change when CE value/score changes"
+       * added change events "change when CE value/score changes of <element>"
+
+2006-05-16
+       * added new chunk "INFO" to level file format for global level settings
+       * added all element settings from "HEAD" chunk to "CONF" chunk
+       * added all global level settings from "HEAD" chunk to "INFO" chunk
+
+2006-05-09
+       * changed level file format by adding two new chunks "CUSX" (for custom
+         elements, replacing the previous "CUS4" chunk) and "GRPX" (for group
+         elements, replacing the previous "GRP1" chunk); these new IFF style
+         chunks use the new and flexible "micro chunks inside chunks" technique
+         already used with the new "CONF" chunk (for normal element properties)
+         which makes it possible to easily extend the existing level format
+         (instead of using fixed-length chunks like before, which are either
+         too big due to reserved bytes for future use, or too small when those
+         reserved bytes have all been used and even more data should be stored,
+         requiring the replacement by new and larger chunks just like it went
+         with "CUS1" to "CUS4"); this whole problem now does not exist anymore
+
+2006-05-06
+       * added credits pages to the "credits" section that were really missing
+       * added some missing element descriptions to the level editor
+       * added down position of switchgate switch to the level editor
+         and allowed the use of both switch positions at the same time
+       * changed use of "Insert" and "Delete" keys to navigate element list in
+         level editor to start of previous or next cascading block of elements
+
+2006-05-05
+       * added the possibility to view the title screen to the info screen menu
+       * fixed some minor bugs with viewing title screens
+
+2006-05-02
+       * fixed bug with title (cross)fading in/out when using fullscreen mode
+
+2006-04-30
+       * fixed bug that forced re-defining of menu settings in local graphics
+         config file which are already defined in existing base config file
+       * fixed small bug that caused door sounds playing when music is enabled
+
+2006-04-29
+       * added the possibility to define up to five title screens for each
+         level set that are displayed after loading using (cross)fading in/out
+         (this was added to display the various start images of the EMC sets)
+
+2006-04-28
+       * added "CE score gets zero [of]" to custom element trigger conditions
+       * added setup option to display element token name in level editor
+
+2006-04-19
+       * added compatibility code for Juergen Bonhagen's menu artwork settings
+
+2006-04-15
+       * fixed bug with displaying wrong animation frame 0 after CE changes
+       * fixed bug with creating invisible elements when light switch is on
+
+2006-04-06
+       * added selection between ECS and AGA graphics for EMC levels to setup
+
+2006-04-04
+       * adjusted font handling for various narrow EMC style fonts
+
+2006-04-03
+       * changed EM engine behaviour back to re-allow initial rolling springs
+
+2006-04-02
+       * fixed handling of over-large selectboxes (less error-prone now)
+       * fixed bug when creating GE with walkable element under the player
+
+2006-04-01
+       * added use of "Insert" and "Delete" keys to navigate element list in
+         level editor to start of custom elements or start of group elements
+       * added virtual elements to access CE value and CE score of elements:
+         - "CE value of triggering element"
+         - "CE score of triggering element"
+         - "CE value of current element"
+         - "CE score of current element"
+
+2006-03-30
+       * fixed "grass" to "sand" in older EM levels (up to file version V4)
+
+2006-03-29
+       * changed behaviour of network games with internal errors (because of
+         different client frame counters) from immediately terminating R'n'D
+         to displaying an error message requester and stopping only the game
+         (also to prevent impression of crashes under non command-line runs)
+       * fixed playing network games with the EMC engine (did not work before)
+       * fixed bug with not scrolling the screen in multi-player mode with the
+         focus on player 1 when all players are moving in different directions
+       * fixed bug with keeping pointer to gadget even after its deallocation
+       * fixed bug with allowing "focus on all players" in network games
+       * fixed bug with player focus when playing tapes from network games
+
+2006-03-22
+       * uploaded pre-release (test) version 3.2.0-7 binary and source code
+
+2006-03-19
+       * code cleanup for game action control for R'n'D and EMC game engine
+
+2006-03-18
+       * fixed bug in multi-player movement with focus on both players
+       * added option to control only the focussed player with all input
+
+2006-03-14
+       * added player focus switching to level tape recording and re-playing
+
+2006-03-13
+       * fixed some bugs in player focus switching in EMC and RND game engine
+
+2006-03-11
+       * added special Supaplex animations for Murphy digging and snapping
+       * added special Supaplex animations for Murphy being bored and sleeping
+
+2006-03-10
+       * added four new yam yams with explicit start direction for EMC engine
+       * fixed bug in src/libgame/text.c with printing text outside the window
+
+2006-03-09
+       * fixed small bug in EMC level loader (copyright sign in EM II levels)
+
+2006-03-08
+       * added delayed ignition of EM style dynamite when used in R'n'D engine
+       * added limited movement range to EMC engine when focus on all players
+
+2006-03-06
+       * fixed bug with missing (zero) score values for native Supaplex levels
+
+2006-03-05
+       * added "continuous snapping" (snapping many elements while holding the
+         snap key pressed, without releasing the snap key after each element)
+         as a new player setting for more compatibility with the classic games
+
+2006-03-04
+       * finished scrolling for "focus on all players" in EMC graphics engine
+
+2006-02-28
+       * level sets with "levels: 0" are ignored for levels, but not artwork
+       * fixed bug when scanning empty level group directories (endless loop)
+
+2006-02-26
+       * fixed bug with explosion graphic for player using "Murphy" graphic
+       * fixed bug with explosion graphic if player leaves explosion in time
+       * changed some descriptive text in setup menu to use medium-width font
+       * added key shortcut settings for switching player focus to setup menu
+
+2006-02-25
+       * fixed bug with random value initialization when recording tapes
+       * fixed bug with playing single player tapes when team mode activated
+
+2006-02-22
+       * fixed little bug when trying to switch to player that does not exist
+
+2006-02-19
+       * added player switching (visual and quick) to R'n'D and EM game engine
+       * added setup option to select visual or quick in-game player switching
+
+2006-02-16
+       * added use of "Home" and "End" keys to handle element list in editor
+
+2006-02-15
+       * fixed bug with adding score when playing tape with EMC game engine
+       * added steel wall border for levels using EMC engine without border
+       * finally fixed delayed scrolling in EMC engine also for small levels
+
+2006-02-12
+       * fixed potential crash bug in WarnBuggyBase() (missing boundary check)
+
+2006-02-11
+       * fixed bug with CE change order in TestIfElementTouchesCustomElement()
+       * fixed bug when displaying info element without action, but direction
+
+2006-02-09
+       * fixed minor graphical problems with springs smashing and slurping
+         (when using R'n'D style graphics instead of EMC style graphics)
+
+2006-02-07
+       * added scroll delay (as configured in setup) to EMC graphics engine
+
+2006-02-06
+       * improved screen redraw for EMC graphics engine (faster and smoother)
+       * when not scrolling, do not redraw the whole playfield if not needed
+
+2006-02-03
+       * added multi-player mode for EMC game engine (with up to four players)
+
+2006-01-28
+       * added android (can clone elements) from EMC engine to R'n'D engine
+
+2006-01-14
+       * added spring bumper (reflects spring) from EMC engine to R'n'D engine
+
+2006-01-11
+       * added selectbox for initial player speed to player settings in editor
+
+2006-01-11
+       * version 3.1.2 created that is basically version 3.1.1, but with a
+         major bug fixed that prevented editing your own private levels
+       * version 3.1.2 released
+
+2006-01-09
+       * added magic ball (creates elements) from EMC engine to R'n'D engine
+
+2006-01-07
+       * uploaded fixed pre-release version 3.2.0-6 binary and source code
+
+2006-01-07
+       * fixed bug when using "CE can leave behind <trigger element>"
+       * added new change condition "(after/when) creation of <element>"
+       * added new change condition "(after/when) digging <element>"
+       * fixed bug accessing invalid gadget that caused crashes under Windows
+       * deactivated new possibility for multiple CE changes per frame
+
+2006-01-04
+       * uploaded pre-release (test) version 3.2.0-6 binary and source code
+
+2006-01-02
+       * added animation types "ce_value" and "ce_score" to graphicsinfo.conf
+       * fixed bug with not keeping CE value for moving CEs with only action
+       * changed CE action selectboxes in editor to be only reset when needed
+
+2006-01-01
+       * added option "use artwork from element" for custom player artwork
+       * added option "use explosion from element" for player explosions
+
+2005-12-30
+       * added cascaded element lists in the level editor
+       * added persistence for cascaded element lists by "editorcascade.conf"
+       * added dynamic element list with all elements used in current level
+       * added possibility for multiple CE changes per frame (experimental)
+
+2005-12-28
+       * uploaded pre-release (test) version 3.2.0-5 binary and source code
+
+2005-12-27
+       * changed "score for each 10 seconds/steps left" to "1 second/step"
+       * added own score for collecting "extra time" instead of sharing it
+       * added change events "switched by player" and "player switches <e>"
+       * added change events "snapped by player" and "player snaps <e>"
+       * added "set player artwork: <element choice>" to CE action options
+       * added change event "move of <element>"
+
+2005-12-22
+       * added "set player shield: off / normal / deadly" to CE action options
+       * added new player option "use level start element" in level editor
+         to set the correct focus at level start to elements from which the
+         player is created later (this did not work before for cascaded CE
+         changes resulting in creation of the player; it is now also possible
+         to create the player from a yam yam which is smashed at level start)
+
+2005-12-20
+       * added "set player speed: frozen (not moving)" to CE action options
+       * added "move player: l/r/u/d/trigger/-trigger" to CE action options
+
+2005-12-17
+       * added new player option "block snap field" (enabled by default) to
+         make it possible to show a snapping animation like in Emerald Mine
+
+2005-12-16
+       * added dynamic selectboxes to custom element action settings in editor
+       * added "CE value" counter for custom elements (instead of "CE count")
+       * added option to use the last "CE value" after custom element change
+       * added option to use the "CE value" of other elements in CE actions
+       * fixed odd behaviour when pressing time orb in levels w/o time limit
+       * added checkbox "use time orb bug" for older levels that use this bug
+
+2005-12-15
+       * added missing configuration settings for the following elements:
+         - EL_TIMEGATE_SWITCH          (time of open time gate)
+         - EL_LIGHT_SWITCH_ACTIVE      (time of light switched on)
+         - EL_SHIELD_NORMAL            (time of shield duration)
+         - EL_SHIELD_DEADLY            (time of shield duration)
+         - EL_EXTRA_TIME               (time added to level time)
+         - EL_TIME_ORB_FULL            (time added to level time)
+
+2005-12-14
+       * added "wind direction" as a movement pattern for custom elements
+       * added initial wind direction for balloon / custom elements to editor
+       * added functionality for EL_BALLOON_SWITCH_NONE to R'n'D game engine
+
+2005-12-13
+       * added parameters for "game of life" and "biomaze" elements to editor
+
+2005-12-12
+       * added level file chunk "CONF" for generic level and element settings
+
+2005-12-11
+       * uploaded pre-release (test) version 3.2.0-4 binary and source code
+
+2005-12-11
+       * skip empty level sets (with "levels: 0"; may be artwork base sets)
+       * added sound action ".page[1]" to ".page[32]" for each CE change page
+
+2005-12-10
+       * added image config suffix ".clone_from" to copy whole image settings
+       * fixed bug with invalid ("undefined") CE settings in old level files
+
+2005-12-05
+       * fixed graphical bug with smashing elements falling faster than player
+
+2005-12-03
+       * fixed major bug which prevented private levels from being edited
+       * fixed bug with precedence of general and special font definitions
+
+2005-12-02
+       * fixed graphical bug with player animation when player moves slowly
+
+2005-11-29
+       * uploaded pre-release (test) version 3.2.0-3 binary and source code
+
+2005-11-28
+       * fixed bug which prevented "global.num_toons: 0" from working
+
+2005-11-27
+       * major code cleanup (removed all these annoying "#if 0" blocks)
+
+2005-11-26
+       * added custom element actions for CE change page in level editor
+
+2005-11-19
+       * fixed music initialization bug in init.c (thanks to David Binderman)
+       * fixed mouse wheel "button" bug in editor (thanks to Tomi Belan)
+         (this bug must probably be fixed at other places, too)
+
+2005-10-16
+       * fixed buggy '#include "SDL.h"' statements in src/libgame/sdl.h
+         (should be '#include <SDL.h>' instead)
+
+2005-08-20
+       * fixed bug which prevented "walkable from no direction" from working
+         (due to compatibility code overwriting this setting after loading)
+
 2005-08-15
        * fixed bug on Mac OS X (use of reserved name "Random") in EM engine
 
index 4a242ed022c7a4655e17a3e334bbd703eb9a54b1..f98a1211c870d8adf3217a90e080fc4939722b44 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -127,7 +127,13 @@ leveltest: all
        ./Scripts/make_enginetest.sh leveltest
 
 backup:
-       ./Scripts/make_backup.sh src
+       ./Scripts/make_backup.sh src 1
+
+backup2:
+       ./Scripts/make_backup.sh src 2
+
+backup3:
+       ./Scripts/make_backup.sh src 3
 
 backup_lev:
        ./Scripts/make_backup.sh lev
index fc465fac037bc4dbb32c49b6d7d40a2a8422c749..9b6626b6cc777b76cb8f06908b968007adc09269 100644 (file)
@@ -59,16 +59,7 @@ static void PrepareBackbuffer()
 
 boolean ToonNeedsRedraw()
 {
-#if 1
   return TRUE;
-#else
-  return (game_status == GAME_MODE_INFO ||
-         game_status == GAME_MODE_LEVELS ||
-         game_status == GAME_MODE_SETUP ||
-         (game_status == GAME_MODE_MAIN &&
-          ((redraw_mask & REDRAW_MICROLEVEL) ||
-           (redraw_mask & REDRAW_MICROLABEL))));
-#endif
 }
 
 void InitToons()
@@ -76,10 +67,10 @@ void InitToons()
   int num_toons = MAX_NUM_TOONS;
   int i;
 
-  if (global.num_toons > 0 && global.num_toons < MAX_NUM_TOONS)
+  if (global.num_toons >= 0 && global.num_toons < MAX_NUM_TOONS)
     num_toons = global.num_toons;
 
-  for (i=0; i < num_toons; i++)
+  for (i = 0; i < num_toons; i++)
   {
     int graphic = IMG_TOON_1 + i;
     struct FileInfo *image = getImageListEntryFromImageID(graphic);
index 491ed8f8018db703e91ae359bf8e041a6b4fc98d..212e86bf5bef60c38728c4e675b92c6825adb4c4 100644 (file)
@@ -205,6 +205,14 @@ element_to_graphic[] =
     EL_SP_BASE,                                -1, -1, FALSE,
     IMG_SP_BASE
   },
+  {
+    EL_SP_BASE,                                ACTION_DIGGING, -1, FALSE,
+    IMG_SP_BASE_DIGGING
+  },
+  {
+    EL_SP_BASE,                                ACTION_SNAPPING, -1, FALSE,
+    IMG_SP_BASE_SNAPPING
+  },
   {
     EL_SP_MURPHY,                      -1, -1, FALSE,
     IMG_SP_MURPHY
@@ -257,6 +265,22 @@ element_to_graphic[] =
     EL_SP_MURPHY,                      ACTION_SNAPPING, MV_BIT_DOWN, FALSE,
     IMG_SP_MURPHY_SNAPPING_DOWN
   },
+  {
+    EL_SP_MURPHY,                      ACTION_BORING, -1, FALSE,
+    IMG_SP_MURPHY_BORING
+  },
+  {
+    EL_SP_MURPHY,                      ACTION_BORING_1, -1, FALSE,
+    IMG_SP_MURPHY_BORING_1
+  },
+  {
+    EL_SP_MURPHY,                      ACTION_SLEEPING, MV_BIT_LEFT, FALSE,
+    IMG_SP_MURPHY_SLEEPING_LEFT
+  },
+  {
+    EL_SP_MURPHY,                      ACTION_SLEEPING, MV_BIT_RIGHT, FALSE,
+    IMG_SP_MURPHY_SLEEPING_RIGHT
+  },
   {
     EL_SP_MURPHY_CLONE,                        -1, -1, FALSE,
     IMG_SP_MURPHY_CLONE
@@ -265,6 +289,10 @@ element_to_graphic[] =
     EL_SP_INFOTRON,                    -1, -1, FALSE,
     IMG_SP_INFOTRON
   },
+  {
+    EL_SP_INFOTRON,                    ACTION_COLLECTING, -1, FALSE,
+    IMG_SP_INFOTRON_COLLECTING
+  },
   {
     EL_SP_CHIP_SINGLE,                 -1, -1, FALSE,
     IMG_SP_CHIP_SINGLE
@@ -689,6 +717,18 @@ element_to_graphic[] =
     EL_DYNAMITE,                       ACTION_ACTIVE, -1, FALSE,
     IMG_DYNAMITE_ACTIVE
   },
+  {
+    EL_EM_DYNAMITE,                    -1, -1, FALSE,
+    IMG_EM_DYNAMITE
+  },
+  {
+    EL_EM_DYNAMITE_ACTIVE,             -1, -1, FALSE,
+    IMG_EM_DYNAMITE_ACTIVE
+  },
+  {
+    EL_EM_DYNAMITE,                    ACTION_ACTIVE, -1, FALSE,
+    IMG_EM_DYNAMITE_ACTIVE
+  },
   {
     EL_WALL_EMERALD,                   -1, -1, FALSE,
     IMG_WALL_EMERALD
@@ -869,6 +909,38 @@ element_to_graphic[] =
     EL_YAMYAM,                         -1, -1, FALSE,
     IMG_YAMYAM
   },
+  {
+    EL_YAMYAM_LEFT,                    -1, -1, FALSE,
+    IMG_YAMYAM_LEFT
+  },
+  {
+    EL_YAMYAM,                         -1, MV_BIT_LEFT, FALSE,
+    IMG_YAMYAM_LEFT
+  },
+  {
+    EL_YAMYAM_RIGHT,                   -1, -1, FALSE,
+    IMG_YAMYAM_RIGHT
+  },
+  {
+    EL_YAMYAM,                         -1, MV_BIT_RIGHT, FALSE,
+    IMG_YAMYAM_RIGHT
+  },
+  {
+    EL_YAMYAM_UP,                      -1, -1, FALSE,
+    IMG_YAMYAM_UP
+  },
+  {
+    EL_YAMYAM,                         -1, MV_BIT_UP, FALSE,
+    IMG_YAMYAM_UP
+  },
+  {
+    EL_YAMYAM_DOWN,                    -1, -1, FALSE,
+    IMG_YAMYAM_DOWN
+  },
+  {
+    EL_YAMYAM,                         -1, MV_BIT_DOWN, FALSE,
+    IMG_YAMYAM_DOWN
+  },
   {
     EL_YAMYAM,                         ACTION_MOVING, -1, FALSE,
     IMG_YAMYAM_MOVING
@@ -1057,18 +1129,50 @@ element_to_graphic[] =
     EL_EM_GATE_1_GRAY,                 -1, -1, FALSE,
     IMG_EM_GATE_1_GRAY
   },
+  {
+    EL_EM_GATE_1_GRAY_ACTIVE,          -1, -1, FALSE,
+    IMG_EM_GATE_1_GRAY_ACTIVE
+  },
+  {
+    EL_EM_GATE_1_GRAY,                 ACTION_ACTIVE, -1, FALSE,
+    IMG_EM_GATE_1_GRAY_ACTIVE
+  },
   {
     EL_EM_GATE_2_GRAY,                 -1, -1, FALSE,
     IMG_EM_GATE_2_GRAY
   },
+  {
+    EL_EM_GATE_2_GRAY_ACTIVE,          -1, -1, FALSE,
+    IMG_EM_GATE_2_GRAY_ACTIVE
+  },
+  {
+    EL_EM_GATE_2_GRAY,                 ACTION_ACTIVE, -1, FALSE,
+    IMG_EM_GATE_2_GRAY_ACTIVE
+  },
   {
     EL_EM_GATE_3_GRAY,                 -1, -1, FALSE,
     IMG_EM_GATE_3_GRAY
   },
+  {
+    EL_EM_GATE_3_GRAY_ACTIVE,          -1, -1, FALSE,
+    IMG_EM_GATE_3_GRAY_ACTIVE
+  },
+  {
+    EL_EM_GATE_3_GRAY,                 ACTION_ACTIVE, -1, FALSE,
+    IMG_EM_GATE_3_GRAY_ACTIVE
+  },
   {
     EL_EM_GATE_4_GRAY,                 -1, -1, FALSE,
     IMG_EM_GATE_4_GRAY
   },
+  {
+    EL_EM_GATE_4_GRAY_ACTIVE,          -1, -1, FALSE,
+    IMG_EM_GATE_4_GRAY_ACTIVE
+  },
+  {
+    EL_EM_GATE_4_GRAY,                 ACTION_ACTIVE, -1, FALSE,
+    IMG_EM_GATE_4_GRAY_ACTIVE
+  },
   {
     EL_EXIT_CLOSED,                    -1, -1, FALSE,
     IMG_EXIT_CLOSED
@@ -1701,18 +1805,50 @@ element_to_graphic[] =
     EL_GATE_1_GRAY,                    -1, -1, FALSE,
     IMG_GATE_1_GRAY
   },
+  {
+    EL_GATE_1_GRAY_ACTIVE,             -1, -1, FALSE,
+    IMG_GATE_1_GRAY_ACTIVE
+  },
+  {
+    EL_GATE_1_GRAY,                    ACTION_ACTIVE, -1, FALSE,
+    IMG_GATE_1_GRAY_ACTIVE
+  },
   {
     EL_GATE_2_GRAY,                    -1, -1, FALSE,
     IMG_GATE_2_GRAY
   },
+  {
+    EL_GATE_2_GRAY_ACTIVE,             -1, -1, FALSE,
+    IMG_GATE_2_GRAY_ACTIVE
+  },
+  {
+    EL_GATE_2_GRAY,                    ACTION_ACTIVE, -1, FALSE,
+    IMG_GATE_2_GRAY_ACTIVE
+  },
   {
     EL_GATE_3_GRAY,                    -1, -1, FALSE,
     IMG_GATE_3_GRAY
   },
+  {
+    EL_GATE_3_GRAY_ACTIVE,             -1, -1, FALSE,
+    IMG_GATE_3_GRAY_ACTIVE
+  },
+  {
+    EL_GATE_3_GRAY,                    ACTION_ACTIVE, -1, FALSE,
+    IMG_GATE_3_GRAY_ACTIVE
+  },
   {
     EL_GATE_4_GRAY,                    -1, -1, FALSE,
     IMG_GATE_4_GRAY
   },
+  {
+    EL_GATE_4_GRAY_ACTIVE,             -1, -1, FALSE,
+    IMG_GATE_4_GRAY_ACTIVE
+  },
+  {
+    EL_GATE_4_GRAY,                    ACTION_ACTIVE, -1, FALSE,
+    IMG_GATE_4_GRAY_ACTIVE
+  },
   {
     EL_GAME_OF_LIFE,                   -1, -1, FALSE,
     IMG_GAME_OF_LIFE
@@ -1861,6 +1997,10 @@ element_to_graphic[] =
     EL_EXPANDABLE_WALL_ANY,            -1, -1, FALSE,
     IMG_EXPANDABLE_WALL_ANY
   },
+  {
+    EL_BD_EXPANDABLE_WALL,             -1, -1, FALSE,
+    IMG_BD_EXPANDABLE_WALL
+  },
   {
     EL_EXPANDABLE_WALL,                        ACTION_GROWING, MV_BIT_LEFT, FALSE,
     IMG_EXPANDABLE_WALL_GROWING_LEFT
@@ -2673,6 +2813,22 @@ element_to_graphic[] =
     EL_TRIGGER_PLAYER,                 -1, -1, FALSE,
     IMG_TRIGGER_PLAYER
   },
+  {
+    EL_TRIGGER_CE_VALUE,               -1, -1, FALSE,
+    IMG_TRIGGER_CE_VALUE
+  },
+  {
+    EL_TRIGGER_CE_SCORE,               -1, -1, FALSE,
+    IMG_TRIGGER_CE_SCORE
+  },
+  {
+    EL_CURRENT_CE_VALUE,               -1, -1, FALSE,
+    IMG_CURRENT_CE_VALUE
+  },
+  {
+    EL_CURRENT_CE_SCORE,               -1, -1, FALSE,
+    IMG_CURRENT_CE_SCORE
+  },
   {
     EL_EMC_KEY_5,                      -1, -1, FALSE,
     IMG_EMC_KEY_5
@@ -2693,38 +2849,102 @@ element_to_graphic[] =
     EL_EMC_GATE_5,                     -1, -1, FALSE,
     IMG_EMC_GATE_5
   },
+  {
+    EL_EMC_GATE_6,                     -1, -1, FALSE,
+    IMG_EMC_GATE_6
+  },
+  {
+    EL_EMC_GATE_7,                     -1, -1, FALSE,
+    IMG_EMC_GATE_7
+  },
+  {
+    EL_EMC_GATE_8,                     -1, -1, FALSE,
+    IMG_EMC_GATE_8
+  },
   {
     EL_EMC_GATE_5_GRAY,                        -1, -1, FALSE,
     IMG_EMC_GATE_5_GRAY
   },
   {
-    EL_EMC_GATE_6,                     -1, -1, FALSE,
-    IMG_EMC_GATE_6
+    EL_EMC_GATE_5_GRAY_ACTIVE,         -1, -1, FALSE,
+    IMG_EMC_GATE_5_GRAY_ACTIVE
+  },
+  {
+    EL_EMC_GATE_5_GRAY,                        ACTION_ACTIVE, -1, FALSE,
+    IMG_EMC_GATE_5_GRAY_ACTIVE
   },
   {
     EL_EMC_GATE_6_GRAY,                        -1, -1, FALSE,
     IMG_EMC_GATE_6_GRAY
   },
   {
-    EL_EMC_GATE_7,                     -1, -1, FALSE,
-    IMG_EMC_GATE_7
+    EL_EMC_GATE_6_GRAY_ACTIVE,         -1, -1, FALSE,
+    IMG_EMC_GATE_6_GRAY_ACTIVE
+  },
+  {
+    EL_EMC_GATE_6_GRAY,                        ACTION_ACTIVE, -1, FALSE,
+    IMG_EMC_GATE_6_GRAY_ACTIVE
   },
   {
     EL_EMC_GATE_7_GRAY,                        -1, -1, FALSE,
     IMG_EMC_GATE_7_GRAY
   },
   {
-    EL_EMC_GATE_8,                     -1, -1, FALSE,
-    IMG_EMC_GATE_8
+    EL_EMC_GATE_7_GRAY_ACTIVE,         -1, -1, FALSE,
+    IMG_EMC_GATE_7_GRAY_ACTIVE
+  },
+  {
+    EL_EMC_GATE_7_GRAY,                        ACTION_ACTIVE, -1, FALSE,
+    IMG_EMC_GATE_7_GRAY_ACTIVE
   },
   {
     EL_EMC_GATE_8_GRAY,                        -1, -1, FALSE,
     IMG_EMC_GATE_8_GRAY
   },
+  {
+    EL_EMC_GATE_8_GRAY_ACTIVE,         -1, -1, FALSE,
+    IMG_EMC_GATE_8_GRAY_ACTIVE
+  },
+  {
+    EL_EMC_GATE_8_GRAY,                        ACTION_ACTIVE, -1, FALSE,
+    IMG_EMC_GATE_8_GRAY_ACTIVE
+  },
   {
     EL_EMC_ANDROID,                    -1, -1, FALSE,
     IMG_EMC_ANDROID
   },
+  {
+    EL_EMC_ANDROID,                    ACTION_SHRINKING, MV_BIT_UPLEFT, FALSE,
+    IMG_EMC_ANDROID_SHRINKING_UPLEFT
+  },
+  {
+    EL_EMC_ANDROID,                    ACTION_GROWING, MV_BIT_DOWNRIGHT, FALSE,
+    IMG_EMC_ANDROID_GROWING_DOWNRIGHT
+  },
+  {
+    EL_EMC_ANDROID,                    ACTION_SHRINKING, MV_BIT_DOWNLEFT, FALSE,
+    IMG_EMC_ANDROID_SHRINKING_DOWNLEFT
+  },
+  {
+    EL_EMC_ANDROID,                    ACTION_GROWING, MV_BIT_UPRIGHT, FALSE,
+    IMG_EMC_ANDROID_GROWING_UPRIGHT
+  },
+  {
+    EL_EMC_ANDROID,                    ACTION_SHRINKING, MV_BIT_UPRIGHT, FALSE,
+    IMG_EMC_ANDROID_SHRINKING_UPRIGHT
+  },
+  {
+    EL_EMC_ANDROID,                    ACTION_GROWING, MV_BIT_DOWNLEFT, FALSE,
+    IMG_EMC_ANDROID_GROWING_DOWNLEFT
+  },
+  {
+    EL_EMC_ANDROID,                    ACTION_SHRINKING, MV_BIT_DOWNRIGHT, FALSE,
+    IMG_EMC_ANDROID_SHRINKING_DOWNRIGHT
+  },
+  {
+    EL_EMC_ANDROID,                    ACTION_GROWING, MV_BIT_UPLEFT, FALSE,
+    IMG_EMC_ANDROID_GROWING_UPLEFT
+  },
   {
     EL_EMC_GRASS,                      -1, -1, FALSE,
     IMG_EMC_GRASS
@@ -2777,6 +2997,10 @@ element_to_graphic[] =
     EL_EMC_MAGIC_BALL,                 ACTION_ACTIVE, -1, FALSE,
     IMG_EMC_MAGIC_BALL_ACTIVE
   },
+  {
+    EL_EMC_MAGIC_BALL,                 ACTION_DROPPING, -1, FALSE,
+    IMG_EMC_MAGIC_BALL_DROPPING
+  },
   {
     EL_EMC_MAGIC_BALL_SWITCH,          -1, -1, FALSE,
     IMG_EMC_MAGIC_BALL_SWITCH
@@ -2793,6 +3017,10 @@ element_to_graphic[] =
     EL_EMC_SPRING_BUMPER,              -1, -1, FALSE,
     IMG_EMC_SPRING_BUMPER
   },
+  {
+    EL_EMC_SPRING_BUMPER_ACTIVE,       -1, -1, FALSE,
+    IMG_EMC_SPRING_BUMPER_ACTIVE
+  },
   {
     EL_EMC_SPRING_BUMPER,              ACTION_ACTIVE, -1, FALSE,
     IMG_EMC_SPRING_BUMPER_ACTIVE
@@ -2869,6 +3097,10 @@ element_to_graphic[] =
     EL_EMC_FAKE_GRASS,                 -1, -1, TRUE,
     IMG_EMC_FAKE_GRASS_CRUMBLED
   },
+  {
+    EL_EMC_FAKE_GRASS_ACTIVE,          -1, -1, FALSE,
+    IMG_EMC_FAKE_GRASS_ACTIVE
+  },
   {
     EL_EMC_FAKE_GRASS,                 ACTION_ACTIVE, -1, FALSE,
     IMG_EMC_FAKE_GRASS_ACTIVE
@@ -2877,6 +3109,10 @@ element_to_graphic[] =
     EL_EMC_FAKE_GRASS,                 ACTION_ACTIVE, -1, TRUE,
     IMG_EMC_FAKE_GRASS_ACTIVE_CRUMBLED
   },
+  {
+    EL_EMC_FAKE_GRASS_ACTIVE,          -1, -1, TRUE,
+    IMG_EMC_FAKE_GRASS_ACTIVE_CRUMBLED
+  },
   {
     EL_EMC_FAKE_ACID,                  -1, -1, FALSE,
     IMG_EMC_FAKE_ACID
@@ -2885,6 +3121,10 @@ element_to_graphic[] =
     EL_EMC_DRIPPER,                    -1, -1, FALSE,
     IMG_EMC_DRIPPER
   },
+  {
+    EL_EMC_DRIPPER_ACTIVE,             -1, -1, FALSE,
+    IMG_EMC_DRIPPER_ACTIVE
+  },
   {
     EL_EMC_DRIPPER,                    ACTION_ACTIVE, -1, FALSE,
     IMG_EMC_DRIPPER_ACTIVE
index 7ddf0510a8298f60f40d368254228eaea68551c7..74b6a1cc6ca78071ff12d4ec2715398298b1968c 100644 (file)
@@ -151,6 +151,26 @@ element_to_special_graphic[] =
     EL_DYNAMITE_ACTIVE,                                GFX_SPECIAL_ARG_EDITOR,
     IMG_DYNAMITE_ACTIVE_EDITOR
   },
+  {
+    EL_EM_DYNAMITE_ACTIVE,                     GFX_SPECIAL_ARG_EDITOR,
+    IMG_EM_DYNAMITE_ACTIVE_EDITOR
+  },
+  {
+    EL_YAMYAM_LEFT,                            GFX_SPECIAL_ARG_EDITOR,
+    IMG_YAMYAM_LEFT_EDITOR
+  },
+  {
+    EL_YAMYAM_RIGHT,                           GFX_SPECIAL_ARG_EDITOR,
+    IMG_YAMYAM_RIGHT_EDITOR
+  },
+  {
+    EL_YAMYAM_UP,                              GFX_SPECIAL_ARG_EDITOR,
+    IMG_YAMYAM_UP_EDITOR
+  },
+  {
+    EL_YAMYAM_DOWN,                            GFX_SPECIAL_ARG_EDITOR,
+    IMG_YAMYAM_DOWN_EDITOR
+  },
   {
     EL_QUICKSAND_FULL,                         GFX_SPECIAL_ARG_EDITOR,
     IMG_QUICKSAND_FULL_EDITOR
@@ -243,6 +263,10 @@ element_to_special_graphic[] =
     EL_EXPANDABLE_WALL_ANY,                    GFX_SPECIAL_ARG_EDITOR,
     IMG_EXPANDABLE_WALL_ANY_EDITOR
   },
+  {
+    EL_BD_EXPANDABLE_WALL,                     GFX_SPECIAL_ARG_EDITOR,
+    IMG_BD_EXPANDABLE_WALL_EDITOR
+  },
   {
     EL_PENGUIN,                                        GFX_SPECIAL_ARG_EDITOR,
     IMG_PENGUIN_EDITOR
@@ -327,6 +351,10 @@ element_to_special_graphic[] =
     EL_EMC_GATE_8_GRAY,                                GFX_SPECIAL_ARG_EDITOR,
     IMG_EMC_GATE_8_GRAY_EDITOR
   },
+  {
+    EL_EMC_FAKE_GRASS,                         GFX_SPECIAL_ARG_EDITOR,
+    IMG_EMC_FAKE_GRASS_EDITOR
+  },
   {
     EL_EMC_DRIPPER,                            GFX_SPECIAL_ARG_EDITOR,
     IMG_EMC_DRIPPER_EDITOR
index b00d432fa7a1d9b9de482a87c075cca06bd30533..404adc6f0b8628ca10672923024398d74f322560 100644 (file)
@@ -47,10 +47,6 @@ font_to_graphic[] =
     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
index 1c1864598a2c266b2c6b647581083302c7b4840e..1ad1b39ef8f5289265f122bdf4555781f23ffd65 100644 (file)
@@ -30,6 +30,10 @@ gamemode_to_music[] =
     -1,
     MUS_BACKGROUND
   },
+  {
+    GFX_SPECIAL_ARG_TITLE,
+    MUS_BACKGROUND_TITLE
+  },
   {
     GFX_SPECIAL_ARG_MAIN,
     MUS_BACKGROUND_MAIN
index 7ebfff0c72abc30351be4c1389f42bfc41e32881..703f1453dbb59ccfcf1c5d18a89963568b2b37b2 100644 (file)
@@ -26,6 +26,10 @@ static struct
 }
 gamemode_to_sound[] =
 {
+  {
+    GFX_SPECIAL_ARG_TITLE,
+    SND_BACKGROUND_TITLE
+  },
   {
     GFX_SPECIAL_ARG_MAIN,
     SND_BACKGROUND_MAIN
index 9aa3e6bbe9abb401875199a0d7964572eef92175..a0ce19ebb8ce5c2d26e78c5ff6c2c2c9def749cc 100644 (file)
@@ -59,6 +59,7 @@ struct ConfigTypeInfo image_config_suffix[] =
   { ".post_delay_random",              ARG_UNDEFINED,  TYPE_INTEGER    },
   { ".name",                           ARG_UNDEFINED,  TYPE_STRING     },
   { ".scale_up_factor",                        ARG_UNDEFINED,  TYPE_INTEGER    },
+  { ".clone_from",                     ARG_UNDEFINED,  TYPE_TOKEN      },
 
   { NULL,                              NULL,           0               }
 };
@@ -309,6 +310,16 @@ struct ConfigInfo image_config[] =
   { "sp_base.xpos",                            "2"                     },
   { "sp_base.ypos",                            "0"                     },
   { "sp_base.frames",                          "1"                     },
+  { "sp_base.digging",                         "RocksSP.pcx"           },
+  { "sp_base.digging.xpos",                    "2"                     },
+  { "sp_base.digging.ypos",                    "0"                     },
+  { "sp_base.digging.frames",                  "1"                     },
+  { "sp_base.digging.anim_mode",               "opaque_player"         },
+  { "sp_base.snapping",                                "RocksSP.pcx"           },
+  { "sp_base.snapping.xpos",                   "8"                     },
+  { "sp_base.snapping.ypos",                   "2"                     },
+  { "sp_base.snapping.frames",                 "7"                     },
+  { "sp_base.snapping.anim_mode",              "linear"                },
 
   { "sp_murphy",                               "RocksSP.pcx"           },
   { "sp_murphy.xpos",                          "3"                     },
@@ -374,6 +385,32 @@ struct ConfigInfo image_config[] =
   { "sp_murphy.snapping.down.xpos",            "15"                    },
   { "sp_murphy.snapping.down.ypos",            "0"                     },
   { "sp_murphy.snapping.down.frames",          "1"                     },
+  { "sp_murphy.boring",                                "RocksSP.pcx"           },
+  { "sp_murphy.boring.xpos",                   "11"                    },
+  { "sp_murphy.boring.ypos",                   "12"                    },
+  { "sp_murphy.boring.frames",                 "1"                     },
+  { "sp_murphy.boring[1]",                     "RocksSP.pcx"           },
+  { "sp_murphy.boring[1].xpos",                        "0"                     },
+  { "sp_murphy.boring[1].ypos",                        "12"                    },
+  { "sp_murphy.boring[1].frames",              "12"                    },
+  { "sp_murphy.boring[1].delay",               "10"                    },
+  { "sp_murphy.boring[1].anim_mode",           "linear"                },
+  { "sp_murphy.boring[1].anim_delay_fixed",    "120"                   },
+  { "sp_murphy.boring[1].anim_delay_random",   "0"                     },
+  { "sp_murphy.boring[1].post_delay_fixed",    "500"                   },
+  { "sp_murphy.boring[1].post_delay_random",   "500"                   },
+  { "sp_murphy.sleeping.left",                 "RocksSP.pcx"           },
+  { "sp_murphy.sleeping.left.xpos",            "4"                     },
+  { "sp_murphy.sleeping.left.ypos",            "9"                     },
+  { "sp_murphy.sleeping.left.frames",          "3"                     },
+  { "sp_murphy.sleeping.left.delay",           "100"                   },
+  { "sp_murphy.sleeping.left.anim_mode",       "linear,reverse"        },
+  { "sp_murphy.sleeping.right",                        "RocksSP.pcx"           },
+  { "sp_murphy.sleeping.right.xpos",           "13"                    },
+  { "sp_murphy.sleeping.right.ypos",           "12"                    },
+  { "sp_murphy.sleeping.right.frames",         "3"                     },
+  { "sp_murphy.sleeping.right.delay",          "100"                   },
+  { "sp_murphy.sleeping.right.anim_mode",      "linear"                },
 
   { "sp_murphy_clone",                         "RocksSP.pcx"           },
   { "sp_murphy_clone.xpos",                    "3"                     },
@@ -387,6 +424,11 @@ struct ConfigInfo image_config[] =
   { "sp_infotron.EDITOR",                      "RocksSP.pcx"           },
   { "sp_infotron.EDITOR.xpos",                 "8"                     },
   { "sp_infotron.EDITOR.ypos",                 "11"                    },
+  { "sp_infotron.collecting",                  "RocksSP.pcx"           },
+  { "sp_infotron.collecting.xpos",             "8"                     },
+  { "sp_infotron.collecting.ypos",             "7"                     },
+  { "sp_infotron.collecting.frames",           "8"                     },
+  { "sp_infotron.collecting.anim_mode",                "linear"                },
 
   { "sp_chip_single",                          "RocksSP.pcx"           },
   { "sp_chip_single.xpos",                     "5"                     },
@@ -465,6 +507,7 @@ struct ConfigInfo image_config[] =
   { "sp_disk_red.collecting.xpos",             "8"                     },
   { "sp_disk_red.collecting.ypos",             "5"                     },
   { "sp_disk_red.collecting.frames",           "8"                     },
+  { "sp_disk_red.collecting.anim_mode",                "linear"                },
   { "sp_disk_red.active",                      "RocksSP.pcx"           },
   { "sp_disk_red.active.xpos",                 "4"                     },
   { "sp_disk_red.active.ypos",                 "2"                     },
@@ -947,6 +990,20 @@ struct ConfigInfo image_config[] =
   { "dynamite.active.EDITOR.xpos",             "1"                     },
   { "dynamite.active.EDITOR.ypos",             "14"                    },
 
+  { "em_dynamite",                             "RocksEMC.pcx"          },
+  { "em_dynamite.xpos",                                "0"                     },
+  { "em_dynamite.ypos",                                "15"                    },
+  { "em_dynamite.frames",                      "1"                     },
+  { "em_dynamite.active",                      "RocksEMC.pcx"          },
+  { "em_dynamite.active.xpos",                 "1"                     },
+  { "em_dynamite.active.ypos",                 "15"                    },
+  { "em_dynamite.active.frames",               "4"                     },
+  { "em_dynamite.active.delay",                        "8"                     },
+  { "em_dynamite.active.anim_mode",            "linear"                },
+  { "em_dynamite.active.EDITOR",               "RocksEMC.pcx"          },
+  { "em_dynamite.active.EDITOR.xpos",          "2"                     },
+  { "em_dynamite.active.EDITOR.ypos",          "15"                    },
+
   { "wall_emerald",                            "RocksElements.pcx"     },
   { "wall_emerald.xpos",                       "4"                     },
   { "wall_emerald.ypos",                       "8"                     },
@@ -1150,6 +1207,38 @@ struct ConfigInfo image_config[] =
   { "yamyam.ypos",                             "5"                     },
   { "yamyam.frames",                           "4"                     },
   { "yamyam.anim_mode",                                "pingpong2"             },
+  { "yamyam.left",                             "RocksElements.pcx"     },
+  { "yamyam.left.xpos",                                "0"                     },
+  { "yamyam.left.ypos",                                "5"                     },
+  { "yamyam.left.frames",                      "4"                     },
+  { "yamyam.left.anim_mode",                   "pingpong2"             },
+  { "yamyam.left.EDITOR",                      "RocksEMC.pcx"          },
+  { "yamyam.left.EDITOR.xpos",                 "7"                     },
+  { "yamyam.left.EDITOR.ypos",                 "15"                    },
+  { "yamyam.right",                            "RocksElements.pcx"     },
+  { "yamyam.right.xpos",                       "0"                     },
+  { "yamyam.right.ypos",                       "5"                     },
+  { "yamyam.right.frames",                     "4"                     },
+  { "yamyam.right.anim_mode",                  "pingpong2"             },
+  { "yamyam.right.EDITOR",                     "RocksEMC.pcx"          },
+  { "yamyam.right.EDITOR.xpos",                        "8"                     },
+  { "yamyam.right.EDITOR.ypos",                        "15"                    },
+  { "yamyam.up",                               "RocksElements.pcx"     },
+  { "yamyam.up.xpos",                          "0"                     },
+  { "yamyam.up.ypos",                          "5"                     },
+  { "yamyam.up.frames",                                "4"                     },
+  { "yamyam.up.anim_mode",                     "pingpong2"             },
+  { "yamyam.up.EDITOR",                                "RocksEMC.pcx"          },
+  { "yamyam.up.EDITOR.xpos",                   "5"                     },
+  { "yamyam.up.EDITOR.ypos",                   "15"                    },
+  { "yamyam.down",                             "RocksElements.pcx"     },
+  { "yamyam.down.xpos",                                "0"                     },
+  { "yamyam.down.ypos",                                "5"                     },
+  { "yamyam.down.frames",                      "4"                     },
+  { "yamyam.down.anim_mode",                   "pingpong2"             },
+  { "yamyam.down.EDITOR",                      "RocksEMC.pcx"          },
+  { "yamyam.down.EDITOR.xpos",                 "6"                     },
+  { "yamyam.down.EDITOR.ypos",                 "15"                    },
   { "yamyam.moving",                           "RocksElements.pcx"     },
   { "yamyam.moving.xpos",                      "0"                     },
   { "yamyam.moving.ypos",                      "5"                     },
@@ -1368,6 +1457,10 @@ struct ConfigInfo image_config[] =
   { "em_gate_1_gray.EDITOR",                   "RocksSP.pcx"           },
   { "em_gate_1_gray.EDITOR.xpos",              "12"                    },
   { "em_gate_1_gray.EDITOR.ypos",              "11"                    },
+  { "em_gate_1_gray.active",                   "RocksSP.pcx"           },
+  { "em_gate_1_gray.active.xpos",              "0"                     },
+  { "em_gate_1_gray.active.ypos",              "7"                     },
+  { "em_gate_1_gray.active.frames",            "1"                     },
   { "em_gate_2_gray",                          "RocksSP.pcx"           },
   { "em_gate_2_gray.xpos",                     "5"                     },
   { "em_gate_2_gray.ypos",                     "7"                     },
@@ -1375,6 +1468,10 @@ struct ConfigInfo image_config[] =
   { "em_gate_2_gray.EDITOR",                   "RocksSP.pcx"           },
   { "em_gate_2_gray.EDITOR.xpos",              "13"                    },
   { "em_gate_2_gray.EDITOR.ypos",              "11"                    },
+  { "em_gate_2_gray.active",                   "RocksSP.pcx"           },
+  { "em_gate_2_gray.active.xpos",              "1"                     },
+  { "em_gate_2_gray.active.ypos",              "7"                     },
+  { "em_gate_2_gray.active.frames",            "1"                     },
   { "em_gate_3_gray",                          "RocksSP.pcx"           },
   { "em_gate_3_gray.xpos",                     "6"                     },
   { "em_gate_3_gray.ypos",                     "7"                     },
@@ -1382,6 +1479,10 @@ struct ConfigInfo image_config[] =
   { "em_gate_3_gray.EDITOR",                   "RocksSP.pcx"           },
   { "em_gate_3_gray.EDITOR.xpos",              "14"                    },
   { "em_gate_3_gray.EDITOR.ypos",              "11"                    },
+  { "em_gate_3_gray.active",                   "RocksSP.pcx"           },
+  { "em_gate_3_gray.active.xpos",              "2"                     },
+  { "em_gate_3_gray.active.ypos",              "7"                     },
+  { "em_gate_3_gray.active.frames",            "1"                     },
   { "em_gate_4_gray",                          "RocksSP.pcx"           },
   { "em_gate_4_gray.xpos",                     "7"                     },
   { "em_gate_4_gray.ypos",                     "7"                     },
@@ -1389,6 +1490,10 @@ struct ConfigInfo image_config[] =
   { "em_gate_4_gray.EDITOR",                   "RocksSP.pcx"           },
   { "em_gate_4_gray.EDITOR.xpos",              "15"                    },
   { "em_gate_4_gray.EDITOR.ypos",              "11"                    },
+  { "em_gate_4_gray.active",                   "RocksSP.pcx"           },
+  { "em_gate_4_gray.active.xpos",              "3"                     },
+  { "em_gate_4_gray.active.ypos",              "7"                     },
+  { "em_gate_4_gray.active.frames",            "1"                     },
 
   { "exit_closed",                             "RocksElements.pcx"     },
   { "exit_closed.xpos",                                "0"                     },
@@ -2076,6 +2181,10 @@ struct ConfigInfo image_config[] =
   { "gate_1_gray.EDITOR",                      "RocksElements.pcx"     },
   { "gate_1_gray.EDITOR.xpos",                 "8"                     },
   { "gate_1_gray.EDITOR.ypos",                 "14"                    },
+  { "gate_1_gray.active",                      "RocksElements.pcx"     },
+  { "gate_1_gray.active.xpos",                 "4"                     },
+  { "gate_1_gray.active.ypos",                 "2"                     },
+  { "gate_1_gray.active.frames",               "1"                     },
   { "gate_2_gray",                             "RocksElements.pcx"     },
   { "gate_2_gray.xpos",                                "9"                     },
   { "gate_2_gray.ypos",                                "2"                     },
@@ -2083,6 +2192,10 @@ struct ConfigInfo image_config[] =
   { "gate_2_gray.EDITOR",                      "RocksElements.pcx"     },
   { "gate_2_gray.EDITOR.xpos",                 "9"                     },
   { "gate_2_gray.EDITOR.ypos",                 "14"                    },
+  { "gate_2_gray.active",                      "RocksElements.pcx"     },
+  { "gate_2_gray.active.xpos",                 "5"                     },
+  { "gate_2_gray.active.ypos",                 "2"                     },
+  { "gate_2_gray.active.frames",               "1"                     },
   { "gate_3_gray",                             "RocksElements.pcx"     },
   { "gate_3_gray.xpos",                                "10"                    },
   { "gate_3_gray.ypos",                                "2"                     },
@@ -2090,6 +2203,10 @@ struct ConfigInfo image_config[] =
   { "gate_3_gray.EDITOR",                      "RocksElements.pcx"     },
   { "gate_3_gray.EDITOR.xpos",                 "10"                    },
   { "gate_3_gray.EDITOR.ypos",                 "14"                    },
+  { "gate_3_gray.active",                      "RocksElements.pcx"     },
+  { "gate_3_gray.active.xpos",                 "6"                     },
+  { "gate_3_gray.active.ypos",                 "2"                     },
+  { "gate_3_gray.active.frames",               "1"                     },
   { "gate_4_gray",                             "RocksElements.pcx"     },
   { "gate_4_gray.xpos",                                "11"                    },
   { "gate_4_gray.ypos",                                "2"                     },
@@ -2097,6 +2214,10 @@ struct ConfigInfo image_config[] =
   { "gate_4_gray.EDITOR",                      "RocksElements.pcx"     },
   { "gate_4_gray.EDITOR.xpos",                 "11"                    },
   { "gate_4_gray.EDITOR.ypos",                 "14"                    },
+  { "gate_4_gray.active",                      "RocksElements.pcx"     },
+  { "gate_4_gray.active.xpos",                 "7"                     },
+  { "gate_4_gray.active.ypos",                 "2"                     },
+  { "gate_4_gray.active.frames",               "1"                     },
 
   { "game_of_life",                            "RocksElements.pcx"     },
   { "game_of_life.xpos",                       "8"                     },
@@ -2260,6 +2381,14 @@ struct ConfigInfo image_config[] =
   { "expandable_wall_any.EDITOR.xpos",         "12"                    },
   { "expandable_wall_any.EDITOR.ypos",         "13"                    },
 
+  { "bd_expandable_wall",                      "RocksElements.pcx"     },
+  { "bd_expandable_wall.xpos",                 "5"                     },
+  { "bd_expandable_wall.ypos",                 "9"                     },
+  { "bd_expandable_wall.frames",               "1"                     },
+  { "bd_expandable_wall.EDITOR",               "RocksDC.pcx"           },
+  { "bd_expandable_wall.EDITOR.xpos",          "15"                    },
+  { "bd_expandable_wall.EDITOR.ypos",          "15"                    },
+
   { "expandable_wall.growing.left",            "RocksElements.pcx"     },
   { "expandable_wall.growing.left.xpos",       "8"                     },
   { "expandable_wall.growing.left.ypos",       "10"                    },
@@ -3335,6 +3464,26 @@ struct ConfigInfo image_config[] =
   { "trigger_player.ypos",                     "13"                    },
   { "trigger_player.frames",                   "1"                     },
 
+  { "trigger_ce_value",                                "RocksDC.pcx"           },
+  { "trigger_ce_value.xpos",                   "15"                    },
+  { "trigger_ce_value.ypos",                   "11"                    },
+  { "trigger_ce_value.frames",                 "1"                     },
+
+  { "trigger_ce_score",                                "RocksDC.pcx"           },
+  { "trigger_ce_score.xpos",                   "15"                    },
+  { "trigger_ce_score.ypos",                   "12"                    },
+  { "trigger_ce_score.frames",                 "1"                     },
+
+  { "current_ce_value",                                "RocksDC.pcx"           },
+  { "current_ce_value.xpos",                   "14"                    },
+  { "current_ce_value.ypos",                   "11"                    },
+  { "current_ce_value.frames",                 "1"                     },
+
+  { "current_ce_score",                                "RocksDC.pcx"           },
+  { "current_ce_score.xpos",                   "14"                    },
+  { "current_ce_score.ypos",                   "12"                    },
+  { "current_ce_score.frames",                 "1"                     },
+
   { "emc_key_5",                               "RocksEMC.pcx"          },
   { "emc_key_5.xpos",                          "0"                     },
   { "emc_key_5.ypos",                          "5"                     },
@@ -3356,6 +3505,18 @@ struct ConfigInfo image_config[] =
   { "emc_gate_5.xpos",                         "0"                     },
   { "emc_gate_5.ypos",                         "6"                     },
   { "emc_gate_5.frames",                       "1"                     },
+  { "emc_gate_6",                              "RocksEMC.pcx"          },
+  { "emc_gate_6.xpos",                         "1"                     },
+  { "emc_gate_6.ypos",                         "6"                     },
+  { "emc_gate_6.frames",                       "1"                     },
+  { "emc_gate_7",                              "RocksEMC.pcx"          },
+  { "emc_gate_7.xpos",                         "2"                     },
+  { "emc_gate_7.ypos",                         "6"                     },
+  { "emc_gate_7.frames",                       "1"                     },
+  { "emc_gate_8",                              "RocksEMC.pcx"          },
+  { "emc_gate_8.xpos",                         "3"                     },
+  { "emc_gate_8.ypos",                         "6"                     },
+  { "emc_gate_8.frames",                       "1"                     },
   { "emc_gate_5_gray",                         "RocksEMC.pcx"          },
   { "emc_gate_5_gray.xpos",                    "4"                     },
   { "emc_gate_5_gray.ypos",                    "7"                     },
@@ -3363,10 +3524,10 @@ struct ConfigInfo image_config[] =
   { "emc_gate_5_gray.EDITOR",                  "RocksEMC.pcx"          },
   { "emc_gate_5_gray.EDITOR.xpos",             "0"                     },
   { "emc_gate_5_gray.EDITOR.ypos",             "7"                     },
-  { "emc_gate_6",                              "RocksEMC.pcx"          },
-  { "emc_gate_6.xpos",                         "1"                     },
-  { "emc_gate_6.ypos",                         "6"                     },
-  { "emc_gate_6.frames",                       "1"                     },
+  { "emc_gate_5_gray.active",                  "RocksEMC.pcx"          },
+  { "emc_gate_5_gray.active.xpos",             "0"                     },
+  { "emc_gate_5_gray.active.ypos",             "6"                     },
+  { "emc_gate_5_gray.active.frames",           "1"                     },
   { "emc_gate_6_gray",                         "RocksEMC.pcx"          },
   { "emc_gate_6_gray.xpos",                    "4"                     },
   { "emc_gate_6_gray.ypos",                    "7"                     },
@@ -3374,10 +3535,10 @@ struct ConfigInfo image_config[] =
   { "emc_gate_6_gray.EDITOR",                  "RocksEMC.pcx"          },
   { "emc_gate_6_gray.EDITOR.xpos",             "1"                     },
   { "emc_gate_6_gray.EDITOR.ypos",             "7"                     },
-  { "emc_gate_7",                              "RocksEMC.pcx"          },
-  { "emc_gate_7.xpos",                         "2"                     },
-  { "emc_gate_7.ypos",                         "6"                     },
-  { "emc_gate_7.frames",                       "1"                     },
+  { "emc_gate_6_gray.active",                  "RocksEMC.pcx"          },
+  { "emc_gate_6_gray.active.xpos",             "1"                     },
+  { "emc_gate_6_gray.active.ypos",             "6"                     },
+  { "emc_gate_6_gray.active.frames",           "1"                     },
   { "emc_gate_7_gray",                         "RocksEMC.pcx"          },
   { "emc_gate_7_gray.xpos",                    "4"                     },
   { "emc_gate_7_gray.ypos",                    "7"                     },
@@ -3385,10 +3546,10 @@ struct ConfigInfo image_config[] =
   { "emc_gate_7_gray.EDITOR",                  "RocksEMC.pcx"          },
   { "emc_gate_7_gray.EDITOR.xpos",             "2"                     },
   { "emc_gate_7_gray.EDITOR.ypos",             "7"                     },
-  { "emc_gate_8",                              "RocksEMC.pcx"          },
-  { "emc_gate_8.xpos",                         "3"                     },
-  { "emc_gate_8.ypos",                         "6"                     },
-  { "emc_gate_8.frames",                       "1"                     },
+  { "emc_gate_7_gray.active",                  "RocksEMC.pcx"          },
+  { "emc_gate_7_gray.active.xpos",             "2"                     },
+  { "emc_gate_7_gray.active.ypos",             "6"                     },
+  { "emc_gate_7_gray.active.frames",           "1"                     },
   { "emc_gate_8_gray",                         "RocksEMC.pcx"          },
   { "emc_gate_8_gray.xpos",                    "4"                     },
   { "emc_gate_8_gray.ypos",                    "7"                     },
@@ -3396,11 +3557,64 @@ struct ConfigInfo image_config[] =
   { "emc_gate_8_gray.EDITOR",                  "RocksEMC.pcx"          },
   { "emc_gate_8_gray.EDITOR.xpos",             "3"                     },
   { "emc_gate_8_gray.EDITOR.ypos",             "7"                     },
+  { "emc_gate_8_gray.active",                  "RocksEMC.pcx"          },
+  { "emc_gate_8_gray.active.xpos",             "3"                     },
+  { "emc_gate_8_gray.active.ypos",             "6"                     },
+  { "emc_gate_8_gray.active.frames",           "1"                     },
 
   { "emc_android",                             "RocksEMC.pcx"          },
   { "emc_android.xpos",                                "0"                     },
   { "emc_android.ypos",                                "8"                     },
   { "emc_android.frames",                      "8"                     },
+  { "emc_android.delay",                       "2"                     },
+
+  { "emc_android.shrinking.upleft",            "RocksEMC.pcx"          },
+  { "emc_android.shrinking.upleft.xpos",       "1"                     },
+  { "emc_android.shrinking.upleft.ypos",       "11"                    },
+  { "emc_android.shrinking.upleft.frames",     "8"                     },
+  { "emc_android.shrinking.upleft.anim_mode",  "linear"                },
+
+  { "emc_android.growing.downright",           "RocksEMC.pcx"          },
+  { "emc_android.growing.downright.xpos",      "0"                     },
+  { "emc_android.growing.downright.ypos",      "11"                    },
+  { "emc_android.growing.downright.frames",    "8"                     },
+  { "emc_android.growing.downright.anim_mode", "linear,reverse"        },
+
+  { "emc_android.shrinking.downleft",          "RocksEMC.pcx"          },
+  { "emc_android.shrinking.downleft.xpos",     "1"                     },
+  { "emc_android.shrinking.downleft.ypos",     "12"                    },
+  { "emc_android.shrinking.downleft.frames",   "8"                     },
+  { "emc_android.shrinking.downleft.anim_mode",        "linear"                },
+
+  { "emc_android.growing.upright",             "RocksEMC.pcx"          },
+  { "emc_android.growing.upright.xpos",                "0"                     },
+  { "emc_android.growing.upright.ypos",                "12"                    },
+  { "emc_android.growing.upright.frames",      "8"                     },
+  { "emc_android.growing.upright.anim_mode",   "linear,reverse"        },
+
+  { "emc_android.shrinking.upright",           "RocksEMC.pcx"          },
+  { "emc_android.shrinking.upright.xpos",      "1"                     },
+  { "emc_android.shrinking.upright.ypos",      "13"                    },
+  { "emc_android.shrinking.upright.frames",    "8"                     },
+  { "emc_android.shrinking.upright.anim_mode", "linear"                },
+
+  { "emc_android.growing.downleft",            "RocksEMC.pcx"          },
+  { "emc_android.growing.downleft.xpos",       "0"                     },
+  { "emc_android.growing.downleft.ypos",       "13"                    },
+  { "emc_android.growing.downleft.frames",     "8"                     },
+  { "emc_android.growing.downleft.anim_mode",  "linear,reverse"        },
+
+  { "emc_android.shrinking.downright",         "RocksEMC.pcx"          },
+  { "emc_android.shrinking.downright.xpos",    "1"                     },
+  { "emc_android.shrinking.downright.ypos",    "14"                    },
+  { "emc_android.shrinking.downright.frames",  "8"                     },
+  { "emc_android.shrinking.downright.anim_mode","linear"               },
+
+  { "emc_android.growing.upleft",              "RocksEMC.pcx"          },
+  { "emc_android.growing.upleft.xpos",         "0"                     },
+  { "emc_android.growing.upleft.ypos",         "14"                    },
+  { "emc_android.growing.upleft.frames",       "8"                     },
+  { "emc_android.growing.upleft.anim_mode",    "linear,reverse"        },
 
   { "emc_grass",                               "RocksEMC.pcx"          },
   { "emc_grass.xpos",                          "0"                     },
@@ -3463,18 +3677,21 @@ struct ConfigInfo image_config[] =
   { "emc_magic_ball.xpos",                     "0"                     },
   { "emc_magic_ball.ypos",                     "9"                     },
   { "emc_magic_ball.frames",                   "1"                     },
-
   { "emc_magic_ball.active",                   "RocksEMC.pcx"          },
   { "emc_magic_ball.active.xpos",              "0"                     },
   { "emc_magic_ball.active.ypos",              "9"                     },
   { "emc_magic_ball.active.frames",            "16"                    },
   { "emc_magic_ball.active.frames_per_line",   "8"                     },
+  { "emc_magic_ball.dropping",                 "RocksElements.pcx"     },
+  { "emc_magic_ball.dropping.xpos",            "0"                     },
+  { "emc_magic_ball.dropping.ypos",            "4"                     },
+  { "emc_magic_ball.dropping.frames",          "8"                     },
+  { "emc_magic_ball.dropping.anim_mode",       "linear"                },
 
   { "emc_magic_ball_switch",                   "RocksEMC.pcx"          },
   { "emc_magic_ball_switch.xpos",              "8"                     },
   { "emc_magic_ball_switch.ypos",              "10"                    },
   { "emc_magic_ball_switch.frames",            "1"                     },
-
   { "emc_magic_ball_switch.active",            "RocksEMC.pcx"          },
   { "emc_magic_ball_switch.active.xpos",       "8"                     },
   { "emc_magic_ball_switch.active.ypos",       "9"                     },
@@ -3576,6 +3793,10 @@ struct ConfigInfo image_config[] =
   { "emc_fake_grass.active.CRUMBLED.xpos",     "3"                     },
   { "emc_fake_grass.active.CRUMBLED.ypos",     "4"                     },
   { "emc_fake_grass.active.CRUMBLED.frames",   "1"                     },
+  { "emc_fake_grass.EDITOR",                   "RocksEMC.pcx"          },
+  { "emc_fake_grass.EDITOR.xpos",              "2"                     },
+  { "emc_fake_grass.EDITOR.ypos",              "4"                     },
+  { "emc_fake_grass.EDITOR.frames",            "1"                     },
 
   { "emc_fake_acid",                           "RocksElements.pcx"     },
   { "emc_fake_acid.xpos",                      "12"                    },
@@ -3606,13 +3827,13 @@ struct ConfigInfo image_config[] =
 #if 1
   /* !!! TEMPORARILY STORED HERE -- PROBABLY TO BE CHANGED !!! */
 
-  /* (for testing, change filename back to "emc_object dot pcx") */
+  /* (for testing, change filename back to "emc_objects dot pcx") */
   { "emc_object",                              "RocksEMC.pcx"          },
 #if 0
   { "emc_object.scale_up_factor",              "2"                     },
 #endif
 
-  /* (for testing, change filename back to "emc_sprite dot pcx") */
+  /* (for testing, change filename back to "emc_players dot pcx") */
   { "emc_sprite",                              "RocksEMC.pcx"          },
 #if 0
   { "emc_sprite.scale_up_factor",              "2"                     },
@@ -3831,35 +4052,53 @@ struct ConfigInfo image_config[] =
   { "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",                       "RocksDC.pcx"           },
+  { "menu.button_right.xpos",                  "9"                     },
+  { "menu.button_right.ypos",                  "8"                     },
+  { "menu.button_right.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",                          "RocksDC.pcx"           },
+  { "menu.button_up.xpos",                     "10"                    },
+  { "menu.button_up.ypos",                     "8"                     },
+  { "menu.button_up.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",                                "RocksDC.pcx"           },
+  { "menu.button_down.xpos",                   "11"                    },
+  { "menu.button_down.ypos",                   "8"                     },
+  { "menu.button_down.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.button_enter_menu",                  "RocksDC.pcx"           },
+  { "menu.button_enter_menu.clone_from",       "menu.button_right"     },
+  { "menu.button_enter_menu.active",           "RocksDC.pcx"           },
+  { "menu.button_enter_menu.active.clone_from",        "menu.button_right.active" },
+  { "menu.button_leave_menu",                  "RocksDC.pcx"           },
+  { "menu.button_leave_menu.clone_from",       "menu.button_left"      },
+  { "menu.button_leave_menu.active",           "RocksDC.pcx"           },
+  { "menu.button_leave_menu.active.clone_from",        "menu.button_left.active" },
+
+  { "menu.button_next_level",                  "RocksDC.pcx"           },
+  { "menu.button_next_level.clone_from",       "menu.button_right"     },
+  { "menu.button_next_level.active",           "RocksDC.pcx"           },
+  { "menu.button_next_level.active.clone_from",        "menu.button_right.active" },
+  { "menu.button_last_level",                  "RocksDC.pcx"           },
+  { "menu.button_last_level.clone_from",       "menu.button_left"      },
+  { "menu.button_last_level.active",           "RocksDC.pcx"           },
+  { "menu.button_last_level.active.clone_from",        "menu.button_left.active" },
+
   { "menu.scrollbar",                          "RocksDC.pcx"           },
   { "menu.scrollbar.xpos",                     "8"                     },
   { "menu.scrollbar.ypos",                     "10"                    },
@@ -3895,11 +4134,6 @@ struct ConfigInfo image_config[] =
   { "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"                     },
@@ -4125,6 +4359,15 @@ struct ConfigInfo image_config[] =
   { "editor.element_border_input.xpos",                "0"                     },
   { "editor.element_border_input.ypos",                "0"                     },
 
+  { "editor.cascade_list",                     "RocksDoor.pcx"         },
+  { "editor.cascade_list.x",                   "708"                   },
+  { "editor.cascade_list.y",                   "80"                    },
+  { "editor.cascade_list.frames",              "1"                     },
+  { "editor.cascade_list.active",              "RocksDoor.pcx"         },
+  { "editor.cascade_list.active.x",            "740"                   },
+  { "editor.cascade_list.active.y",            "80"                    },
+  { "editor.cascade_list.active.frames",       "1"                     },
+
   { "background.envelope_1",                   "RocksScreen.pcx"       },
   { "background.envelope_1.x",                 "0"                     },
   { "background.envelope_1.y",                 "0"                     },
@@ -4154,13 +4397,24 @@ struct ConfigInfo image_config[] =
   { "background.envelope_4.anim_mode",         "default"               },
   { "background.envelope_4.draw_masked",       "false"                 },
 
+  { "titlescreen_1",                           UNDEFINED_FILENAME      },
+  { "titlescreen_2",                           UNDEFINED_FILENAME      },
+  { "titlescreen_3",                           UNDEFINED_FILENAME      },
+  { "titlescreen_4",                           UNDEFINED_FILENAME      },
+  { "titlescreen_5",                           UNDEFINED_FILENAME      },
+
   { "background",                              UNDEFINED_FILENAME      },
+  { "background.TITLE",                                UNDEFINED_FILENAME      },
   { "background.MAIN",                         UNDEFINED_FILENAME      },
   { "background.LEVELS",                       UNDEFINED_FILENAME      },
   { "background.SCORES",                       UNDEFINED_FILENAME      },
   { "background.EDITOR",                       UNDEFINED_FILENAME      },
   { "background.INFO",                         UNDEFINED_FILENAME      },
   { "background.INFO[ELEMENTS]",               UNDEFINED_FILENAME      },
+  { "background.INFO[MUSIC]",                  UNDEFINED_FILENAME      },
+  { "background.INFO[CREDITS]",                        UNDEFINED_FILENAME      },
+  { "background.INFO[PROGRAM]",                        UNDEFINED_FILENAME      },
+  { "background.INFO[LEVELSET]",               UNDEFINED_FILENAME      },
   { "background.SETUP",                                UNDEFINED_FILENAME      },
   { "background.DOOR",                         UNDEFINED_FILENAME      },
 
@@ -4191,17 +4445,22 @@ struct ConfigInfo image_config[] =
   { "menu.list_size.SCORES",                   "-1"                    },
   { "menu.list_size.INFO",                     "-1"                    },
 
+  { "door_1.width",                            "-1"                    },
+  { "door_1.height",                           "-1"                    },
   { "door_1.step_offset",                      "2"                     },
   { "door_1.step_delay",                       "10"                    },
   { "door_1.anim_mode",                                "default"               },
+
+  { "door_2.width",                            "-1"                    },
+  { "door_2.height",                           "-1"                    },
   { "door_2.step_offset",                      "2"                     },
   { "door_2.step_delay",                       "10"                    },
   { "door_2.anim_mode",                                "default"               },
 
-  { "[player].boring_delay_fixed",             "-1"                    },
-  { "[player].boring_delay_random",            "-1"                    },
-  { "[player].sleeping_delay_fixed",           "-1"                    },
-  { "[player].sleeping_delay_random",          "-1"                    },
+  { "[player].boring_delay_fixed",             "1000"                  },
+  { "[player].boring_delay_random",            "1000"                  },
+  { "[player].sleeping_delay_fixed",           "2000"                  },
+  { "[player].sleeping_delay_random",          "2000"                  },
 
   { NULL,                                      NULL                    }
 };
index 2d2cc45f745440fbea994ff460ce5e467ae867e0..49ea014a80b412fbd007b19315f5d72229087d39 100644 (file)
 #define IMG_SP_ZONK_PUSHING_LEFT                       41
 #define IMG_SP_ZONK_PUSHING_RIGHT                      42
 #define IMG_SP_BASE                                    43
-#define IMG_SP_MURPHY                                  44
-#define IMG_SP_MURPHY_MOVING_LEFT                      45
-#define IMG_SP_MURPHY_MOVING_RIGHT                     46
-#define IMG_SP_MURPHY_DIGGING_LEFT                     47
-#define IMG_SP_MURPHY_DIGGING_RIGHT                    48
-#define IMG_SP_MURPHY_COLLECTING_LEFT                  49
-#define IMG_SP_MURPHY_COLLECTING_RIGHT                 50
-#define IMG_SP_MURPHY_PUSHING_LEFT                     51
-#define IMG_SP_MURPHY_PUSHING_RIGHT                    52
-#define IMG_SP_MURPHY_SNAPPING_LEFT                    53
-#define IMG_SP_MURPHY_SNAPPING_RIGHT                   54
-#define IMG_SP_MURPHY_SNAPPING_UP                      55
-#define IMG_SP_MURPHY_SNAPPING_DOWN                    56
-#define IMG_SP_MURPHY_CLONE                            57
-#define IMG_SP_INFOTRON                                        58
-#define IMG_SP_INFOTRON_EDITOR                         59
-#define IMG_SP_CHIP_SINGLE                             60
-#define IMG_SP_CHIP_LEFT                               61
-#define IMG_SP_CHIP_RIGHT                              62
-#define IMG_SP_CHIP_TOP                                        63
-#define IMG_SP_CHIP_BOTTOM                             64
-#define IMG_SP_HARDWARE_GRAY                           65
-#define IMG_SP_HARDWARE_GREEN                          66
-#define IMG_SP_HARDWARE_BLUE                           67
-#define IMG_SP_HARDWARE_RED                            68
-#define IMG_SP_HARDWARE_YELLOW                         69
-#define IMG_SP_EXIT_CLOSED                             70
-#define IMG_SP_EXIT_OPENING                            71
-#define IMG_SP_EXIT_OPEN                               72
-#define IMG_SP_EXIT_CLOSING                            73
-#define IMG_SP_DISK_ORANGE                             74
-#define IMG_SP_DISK_YELLOW                             75
-#define IMG_SP_DISK_RED                                        76
-#define IMG_SP_DISK_RED_COLLECTING                     77
-#define IMG_SP_DISK_RED_ACTIVE                         78
-#define IMG_SP_PORT_RIGHT                              79
-#define IMG_SP_PORT_DOWN                               80
-#define IMG_SP_PORT_LEFT                               81
-#define IMG_SP_PORT_UP                                 82
-#define IMG_SP_PORT_HORIZONTAL                         83
-#define IMG_SP_PORT_VERTICAL                           84
-#define IMG_SP_PORT_ANY                                        85
-#define IMG_SP_GRAVITY_PORT_RIGHT                      86
-#define IMG_SP_GRAVITY_PORT_RIGHT_EDITOR               87
-#define IMG_SP_GRAVITY_PORT_DOWN                       88
-#define IMG_SP_GRAVITY_PORT_DOWN_EDITOR                        89
-#define IMG_SP_GRAVITY_PORT_LEFT                       90
-#define IMG_SP_GRAVITY_PORT_LEFT_EDITOR                        91
-#define IMG_SP_GRAVITY_PORT_UP                         92
-#define IMG_SP_GRAVITY_PORT_UP_EDITOR                  93
-#define IMG_SP_GRAVITY_ON_PORT_RIGHT                   94
-#define IMG_SP_GRAVITY_ON_PORT_RIGHT_EDITOR            95
-#define IMG_SP_GRAVITY_ON_PORT_DOWN                    96
-#define IMG_SP_GRAVITY_ON_PORT_DOWN_EDITOR             97
-#define IMG_SP_GRAVITY_ON_PORT_LEFT                    98
-#define IMG_SP_GRAVITY_ON_PORT_LEFT_EDITOR             99
-#define IMG_SP_GRAVITY_ON_PORT_UP                      100
-#define IMG_SP_GRAVITY_ON_PORT_UP_EDITOR               101
-#define IMG_SP_GRAVITY_OFF_PORT_RIGHT                  102
-#define IMG_SP_GRAVITY_OFF_PORT_RIGHT_EDITOR           103
-#define IMG_SP_GRAVITY_OFF_PORT_DOWN                   104
-#define IMG_SP_GRAVITY_OFF_PORT_DOWN_EDITOR            105
-#define IMG_SP_GRAVITY_OFF_PORT_LEFT                   106
-#define IMG_SP_GRAVITY_OFF_PORT_LEFT_EDITOR            107
-#define IMG_SP_GRAVITY_OFF_PORT_UP                     108
-#define IMG_SP_GRAVITY_OFF_PORT_UP_EDITOR              109
-#define IMG_SP_SNIKSNAK                                        110
-#define IMG_SP_SNIKSNAK_LEFT                           111
-#define IMG_SP_SNIKSNAK_RIGHT                          112
-#define IMG_SP_SNIKSNAK_UP                             113
-#define IMG_SP_SNIKSNAK_DOWN                           114
-#define IMG_SP_SNIKSNAK_TURNING_FROM_LEFT_UP           115
-#define IMG_SP_SNIKSNAK_TURNING_FROM_LEFT_DOWN         116
-#define IMG_SP_SNIKSNAK_TURNING_FROM_RIGHT_UP          117
-#define IMG_SP_SNIKSNAK_TURNING_FROM_RIGHT_DOWN                118
-#define IMG_SP_SNIKSNAK_TURNING_FROM_UP_LEFT           119
-#define IMG_SP_SNIKSNAK_TURNING_FROM_UP_RIGHT          120
-#define IMG_SP_SNIKSNAK_TURNING_FROM_DOWN_LEFT         121
-#define IMG_SP_SNIKSNAK_TURNING_FROM_DOWN_RIGHT                122
-#define IMG_SP_ELECTRON                                        123
-#define IMG_SP_ELECTRON_EDITOR                         124
-#define IMG_SP_ELECTRON_EXPLODING                      125
-#define IMG_SP_TERMINAL                                        126
-#define IMG_SP_TERMINAL_EDITOR                         127
-#define IMG_SP_TERMINAL_ACTIVE                         128
-#define IMG_SP_BUGGY_BASE                              129
-#define IMG_SP_BUGGY_BASE_EDITOR                       130
-#define IMG_SP_BUGGY_BASE_ACTIVATING                   131
-#define IMG_SP_BUGGY_BASE_ACTIVE                       132
-#define IMG_SP_HARDWARE_BASE_1                         133
-#define IMG_SP_HARDWARE_BASE_2                         134
-#define IMG_SP_HARDWARE_BASE_3                         135
-#define IMG_SP_HARDWARE_BASE_4                         136
-#define IMG_SP_HARDWARE_BASE_5                         137
-#define IMG_SP_HARDWARE_BASE_6                         138
-#define IMG_SOKOBAN_OBJECT                             139
-#define IMG_SOKOBAN_OBJECT_EDITOR                      140
-#define IMG_SOKOBAN_FIELD_EMPTY                                141
-#define IMG_SOKOBAN_FIELD_FULL                         142
-#define IMG_SOKOBAN_FIELD_PLAYER                       143
-#define IMG_SOKOBAN_FIELD_PLAYER_EDITOR                        144
-#define IMG_EMPTY_SPACE                                        145
-#define IMG_SAND                                       146
-#define IMG_SAND_CRUMBLED                              147
-#define IMG_SAND_DIGGING_LEFT                          148
-#define IMG_SAND_DIGGING_RIGHT                         149
-#define IMG_SAND_DIGGING_UP                            150
-#define IMG_SAND_DIGGING_DOWN                          151
-#define IMG_SAND_DIGGING_LEFT_CRUMBLED                 152
-#define IMG_SAND_DIGGING_RIGHT_CRUMBLED                        153
-#define IMG_SAND_DIGGING_UP_CRUMBLED                   154
-#define IMG_SAND_DIGGING_DOWN_CRUMBLED                 155
-#define IMG_WALL                                       156
-#define IMG_WALL_SLIPPERY                              157
-#define IMG_STEELWALL                                  158
-#define IMG_ROCK                                       159
-#define IMG_ROCK_MOVING_LEFT                           160
-#define IMG_ROCK_MOVING_RIGHT                          161
-#define IMG_ROCK_PUSHING_LEFT                          162
-#define IMG_ROCK_PUSHING_RIGHT                         163
-#define IMG_EMERALD                                    164
-#define IMG_EMERALD_MOVING                             165
-#define IMG_EMERALD_FALLING                            166
-#define IMG_EMERALD_COLLECTING                         167
-#define IMG_DIAMOND                                    168
-#define IMG_DIAMOND_MOVING                             169
-#define IMG_DIAMOND_FALLING                            170
-#define IMG_DIAMOND_COLLECTING                         171
-#define IMG_BOMB                                       172
-#define IMG_NUT                                                173
-#define IMG_NUT_BREAKING                               174
-#define IMG_DYNAMITE                                   175
-#define IMG_DYNAMITE_EDITOR                            176
-#define IMG_DYNAMITE_ACTIVE                            177
-#define IMG_DYNAMITE_ACTIVE_EDITOR                     178
-#define IMG_WALL_EMERALD                               179
-#define IMG_WALL_DIAMOND                               180
-#define IMG_BUG                                                181
-#define IMG_BUG_RIGHT                                  182
-#define IMG_BUG_UP                                     183
-#define IMG_BUG_LEFT                                   184
-#define IMG_BUG_DOWN                                   185
-#define IMG_BUG_MOVING_RIGHT                           186
-#define IMG_BUG_MOVING_UP                              187
-#define IMG_BUG_MOVING_LEFT                            188
-#define IMG_BUG_MOVING_DOWN                            189
-#define IMG_BUG_TURNING_FROM_RIGHT_UP                  190
-#define IMG_BUG_TURNING_FROM_UP_LEFT                   191
-#define IMG_BUG_TURNING_FROM_LEFT_DOWN                 192
-#define IMG_BUG_TURNING_FROM_DOWN_RIGHT                        193
-#define IMG_BUG_TURNING_FROM_RIGHT_DOWN                        194
-#define IMG_BUG_TURNING_FROM_UP_RIGHT                  195
-#define IMG_BUG_TURNING_FROM_LEFT_UP                   196
-#define IMG_BUG_TURNING_FROM_DOWN_LEFT                 197
-#define IMG_SPACESHIP                                  198
-#define IMG_SPACESHIP_RIGHT                            199
-#define IMG_SPACESHIP_UP                               200
-#define IMG_SPACESHIP_LEFT                             201
-#define IMG_SPACESHIP_DOWN                             202
-#define IMG_SPACESHIP_MOVING_RIGHT                     203
-#define IMG_SPACESHIP_MOVING_UP                                204
-#define IMG_SPACESHIP_MOVING_LEFT                      205
-#define IMG_SPACESHIP_MOVING_DOWN                      206
-#define IMG_SPACESHIP_TURNING_FROM_RIGHT_UP            207
-#define IMG_SPACESHIP_TURNING_FROM_UP_LEFT             208
-#define IMG_SPACESHIP_TURNING_FROM_LEFT_DOWN           209
-#define IMG_SPACESHIP_TURNING_FROM_DOWN_RIGHT          210
-#define IMG_SPACESHIP_TURNING_FROM_RIGHT_DOWN          211
-#define IMG_SPACESHIP_TURNING_FROM_UP_RIGHT            212
-#define IMG_SPACESHIP_TURNING_FROM_LEFT_UP             213
-#define IMG_SPACESHIP_TURNING_FROM_DOWN_LEFT           214
-#define IMG_YAMYAM                                     215
-#define IMG_YAMYAM_MOVING                              216
-#define IMG_ROBOT                                      217
-#define IMG_ROBOT_MOVING                               218
-#define IMG_ROBOT_WHEEL                                        219
-#define IMG_ROBOT_WHEEL_ACTIVE                         220
-#define IMG_MAGIC_WALL                                 221
-#define IMG_MAGIC_WALL_ACTIVE                          222
-#define IMG_MAGIC_WALL_FILLING                         223
-#define IMG_MAGIC_WALL_FULL                            224
-#define IMG_MAGIC_WALL_EMPTYING                                225
-#define IMG_MAGIC_WALL_DEAD                            226
-#define IMG_QUICKSAND_EMPTY                            227
-#define IMG_QUICKSAND_FILLING                          228
-#define IMG_QUICKSAND_FULL                             229
-#define IMG_QUICKSAND_FULL_EDITOR                      230
-#define IMG_QUICKSAND_EMPTYING                         231
-#define IMG_ACID_POOL_TOPLEFT                          232
-#define IMG_ACID_POOL_TOPRIGHT                         233
-#define IMG_ACID_POOL_BOTTOMLEFT                       234
-#define IMG_ACID_POOL_BOTTOM                           235
-#define IMG_ACID_POOL_BOTTOMRIGHT                      236
-#define IMG_ACID                                       237
-#define IMG_ACID_SPLASH_LEFT                           238
-#define IMG_ACID_SPLASH_RIGHT                          239
-#define IMG_AMOEBA_DROP                                        240
-#define IMG_AMOEBA_GROWING                             241
-#define IMG_AMOEBA_SHRINKING                           242
-#define IMG_AMOEBA_WET                                 243
-#define IMG_AMOEBA_WET_EDITOR                          244
-#define IMG_AMOEBA_DROPPING                            245
-#define IMG_AMOEBA_DRY                                 246
-#define IMG_AMOEBA_FULL                                        247
-#define IMG_AMOEBA_FULL_EDITOR                         248
-#define IMG_AMOEBA_DEAD                                        249
-#define IMG_AMOEBA_DEAD_EDITOR                         250
-#define IMG_EM_KEY_1                                   251
-#define IMG_EM_KEY_2                                   252
-#define IMG_EM_KEY_3                                   253
-#define IMG_EM_KEY_4                                   254
-#define IMG_EM_GATE_1                                  255
-#define IMG_EM_GATE_2                                  256
-#define IMG_EM_GATE_3                                  257
-#define IMG_EM_GATE_4                                  258
-#define IMG_EM_GATE_1_GRAY                             259
-#define IMG_EM_GATE_1_GRAY_EDITOR                      260
-#define IMG_EM_GATE_2_GRAY                             261
-#define IMG_EM_GATE_2_GRAY_EDITOR                      262
-#define IMG_EM_GATE_3_GRAY                             263
-#define IMG_EM_GATE_3_GRAY_EDITOR                      264
-#define IMG_EM_GATE_4_GRAY                             265
-#define IMG_EM_GATE_4_GRAY_EDITOR                      266
-#define IMG_EXIT_CLOSED                                        267
-#define IMG_EXIT_OPENING                               268
-#define IMG_EXIT_OPEN                                  269
-#define IMG_EXIT_CLOSING                               270
-#define IMG_BALLOON                                    271
-#define IMG_BALLOON_MOVING                             272
-#define IMG_BALLOON_PUSHING                            273
-#define IMG_BALLOON_SWITCH_LEFT                                274
-#define IMG_BALLOON_SWITCH_RIGHT                       275
-#define IMG_BALLOON_SWITCH_UP                          276
-#define IMG_BALLOON_SWITCH_DOWN                                277
-#define IMG_BALLOON_SWITCH_ANY                         278
-#define IMG_BALLOON_SWITCH_NONE                                279
-#define IMG_SPRING                                     280
-#define IMG_EMC_STEELWALL_1                            281
-#define IMG_EMC_STEELWALL_2                            282
-#define IMG_EMC_STEELWALL_3                            283
-#define IMG_EMC_STEELWALL_4                            284
-#define IMG_EMC_WALL_1                                 285
-#define IMG_EMC_WALL_2                                 286
-#define IMG_EMC_WALL_3                                 287
-#define IMG_EMC_WALL_4                                 288
-#define IMG_EMC_WALL_5                                 289
-#define IMG_EMC_WALL_6                                 290
-#define IMG_EMC_WALL_7                                 291
-#define IMG_EMC_WALL_8                                 292
-#define IMG_INVISIBLE_STEELWALL                                293
-#define IMG_INVISIBLE_STEELWALL_EDITOR                 294
-#define IMG_INVISIBLE_STEELWALL_ACTIVE                 295
-#define IMG_INVISIBLE_WALL                             296
-#define IMG_INVISIBLE_WALL_EDITOR                      297
-#define IMG_INVISIBLE_WALL_ACTIVE                      298
-#define IMG_INVISIBLE_SAND                             299
-#define IMG_INVISIBLE_SAND_EDITOR                      300
-#define IMG_INVISIBLE_SAND_ACTIVE                      301
-#define IMG_INVISIBLE_SAND_ACTIVE_CRUMBLED             302
-#define IMG_INVISIBLE_SAND_ACTIVE_DIGGING_LEFT         303
-#define IMG_INVISIBLE_SAND_ACTIVE_DIGGING_RIGHT                304
-#define IMG_INVISIBLE_SAND_ACTIVE_DIGGING_UP           305
-#define IMG_INVISIBLE_SAND_ACTIVE_DIGGING_DOWN         306
-#define IMG_INVISIBLE_SAND_ACTIVE_DIGGING_LEFT_CRUMBLED        307
-#define IMG_INVISIBLE_SAND_ACTIVE_DIGGING_RIGHT_CRUMBLED       308
-#define IMG_INVISIBLE_SAND_ACTIVE_DIGGING_UP_CRUMBLED  309
-#define IMG_INVISIBLE_SAND_ACTIVE_DIGGING_DOWN_CRUMBLED        310
-#define IMG_CONVEYOR_BELT_1_MIDDLE                     311
-#define IMG_CONVEYOR_BELT_1_MIDDLE_ACTIVE              312
-#define IMG_CONVEYOR_BELT_1_LEFT                       313
-#define IMG_CONVEYOR_BELT_1_LEFT_ACTIVE                        314
-#define IMG_CONVEYOR_BELT_1_RIGHT                      315
-#define IMG_CONVEYOR_BELT_1_RIGHT_ACTIVE               316
-#define IMG_CONVEYOR_BELT_1_SWITCH_LEFT                        317
-#define IMG_CONVEYOR_BELT_1_SWITCH_MIDDLE              318
-#define IMG_CONVEYOR_BELT_1_SWITCH_RIGHT               319
-#define IMG_CONVEYOR_BELT_2_MIDDLE                     320
-#define IMG_CONVEYOR_BELT_2_MIDDLE_ACTIVE              321
-#define IMG_CONVEYOR_BELT_2_LEFT                       322
-#define IMG_CONVEYOR_BELT_2_LEFT_ACTIVE                        323
-#define IMG_CONVEYOR_BELT_2_RIGHT                      324
-#define IMG_CONVEYOR_BELT_2_RIGHT_ACTIVE               325
-#define IMG_CONVEYOR_BELT_2_SWITCH_LEFT                        326
-#define IMG_CONVEYOR_BELT_2_SWITCH_MIDDLE              327
-#define IMG_CONVEYOR_BELT_2_SWITCH_RIGHT               328
-#define IMG_CONVEYOR_BELT_3_MIDDLE                     329
-#define IMG_CONVEYOR_BELT_3_MIDDLE_ACTIVE              330
-#define IMG_CONVEYOR_BELT_3_LEFT                       331
-#define IMG_CONVEYOR_BELT_3_LEFT_ACTIVE                        332
-#define IMG_CONVEYOR_BELT_3_RIGHT                      333
-#define IMG_CONVEYOR_BELT_3_RIGHT_ACTIVE               334
-#define IMG_CONVEYOR_BELT_3_SWITCH_LEFT                        335
-#define IMG_CONVEYOR_BELT_3_SWITCH_MIDDLE              336
-#define IMG_CONVEYOR_BELT_3_SWITCH_RIGHT               337
-#define IMG_CONVEYOR_BELT_4_MIDDLE                     338
-#define IMG_CONVEYOR_BELT_4_MIDDLE_ACTIVE              339
-#define IMG_CONVEYOR_BELT_4_LEFT                       340
-#define IMG_CONVEYOR_BELT_4_LEFT_ACTIVE                        341
-#define IMG_CONVEYOR_BELT_4_RIGHT                      342
-#define IMG_CONVEYOR_BELT_4_RIGHT_ACTIVE               343
-#define IMG_CONVEYOR_BELT_4_SWITCH_LEFT                        344
-#define IMG_CONVEYOR_BELT_4_SWITCH_MIDDLE              345
-#define IMG_CONVEYOR_BELT_4_SWITCH_RIGHT               346
-#define IMG_SWITCHGATE_SWITCH_UP                       347
-#define IMG_SWITCHGATE_SWITCH_DOWN                     348
-#define IMG_LIGHT_SWITCH                               349
-#define IMG_LIGHT_SWITCH_ACTIVE                                350
-#define IMG_TIMEGATE_SWITCH                            351
-#define IMG_TIMEGATE_SWITCH_ACTIVE                     352
-#define IMG_ENVELOPE_1                                 353
-#define IMG_ENVELOPE_1_COLLECTING                      354
-#define IMG_ENVELOPE_2                                 355
-#define IMG_ENVELOPE_2_COLLECTING                      356
-#define IMG_ENVELOPE_3                                 357
-#define IMG_ENVELOPE_3_COLLECTING                      358
-#define IMG_ENVELOPE_4                                 359
-#define IMG_ENVELOPE_4_COLLECTING                      360
-#define IMG_SIGN_EXCLAMATION                           361
-#define IMG_SIGN_STOP                                  362
-#define IMG_LANDMINE                                   363
-#define IMG_STEELWALL_SLIPPERY                         364
-#define IMG_EXTRA_TIME                                 365
-#define IMG_SHIELD_NORMAL                              366
-#define IMG_SHIELD_NORMAL_ACTIVE                       367
-#define IMG_SHIELD_DEADLY                              368
-#define IMG_SHIELD_DEADLY_ACTIVE                       369
-#define IMG_SWITCHGATE_CLOSED                          370
-#define IMG_SWITCHGATE_OPENING                         371
-#define IMG_SWITCHGATE_OPEN                            372
-#define IMG_SWITCHGATE_CLOSING                         373
-#define IMG_TIMEGATE_CLOSED                            374
-#define IMG_TIMEGATE_OPENING                           375
-#define IMG_TIMEGATE_OPEN                              376
-#define IMG_TIMEGATE_CLOSING                           377
-#define IMG_PEARL                                      378
-#define IMG_PEARL_BREAKING                             379
-#define IMG_CRYSTAL                                    380
-#define IMG_WALL_PEARL                                 381
-#define IMG_WALL_CRYSTAL                               382
-#define IMG_TUBE_RIGHT_DOWN                            383
-#define IMG_TUBE_HORIZONTAL_DOWN                       384
-#define IMG_TUBE_LEFT_DOWN                             385
-#define IMG_TUBE_HORIZONTAL                            386
-#define IMG_TUBE_VERTICAL_RIGHT                                387
-#define IMG_TUBE_ANY                                   388
-#define IMG_TUBE_VERTICAL_LEFT                         389
-#define IMG_TUBE_VERTICAL                              390
-#define IMG_TUBE_RIGHT_UP                              391
-#define IMG_TUBE_HORIZONTAL_UP                         392
-#define IMG_TUBE_LEFT_UP                               393
-#define IMG_TRAP                                       394
-#define IMG_TRAP_ACTIVE                                        395
-#define IMG_DX_SUPABOMB                                        396
-#define IMG_KEY_1                                      397
-#define IMG_KEY_1_EDITOR                               398
-#define IMG_KEY_2                                      399
-#define IMG_KEY_2_EDITOR                               400
-#define IMG_KEY_3                                      401
-#define IMG_KEY_3_EDITOR                               402
-#define IMG_KEY_4                                      403
-#define IMG_KEY_4_EDITOR                               404
-#define IMG_GATE_1                                     405
-#define IMG_GATE_2                                     406
-#define IMG_GATE_3                                     407
-#define IMG_GATE_4                                     408
-#define IMG_GATE_1_GRAY                                        409
-#define IMG_GATE_1_GRAY_EDITOR                         410
-#define IMG_GATE_2_GRAY                                        411
-#define IMG_GATE_2_GRAY_EDITOR                         412
-#define IMG_GATE_3_GRAY                                        413
-#define IMG_GATE_3_GRAY_EDITOR                         414
-#define IMG_GATE_4_GRAY                                        415
-#define IMG_GATE_4_GRAY_EDITOR                         416
-#define IMG_GAME_OF_LIFE                               417
-#define IMG_BIOMAZE                                    418
-#define IMG_PACMAN                                     419
-#define IMG_PACMAN_RIGHT                               420
-#define IMG_PACMAN_UP                                  421
-#define IMG_PACMAN_LEFT                                        422
-#define IMG_PACMAN_DOWN                                        423
-#define IMG_PACMAN_TURNING_FROM_RIGHT                  424
-#define IMG_PACMAN_TURNING_FROM_UP                     425
-#define IMG_PACMAN_TURNING_FROM_LEFT                   426
-#define IMG_PACMAN_TURNING_FROM_DOWN                   427
-#define IMG_LAMP                                       428
-#define IMG_LAMP_EDITOR                                        429
-#define IMG_LAMP_ACTIVE                                        430
-#define IMG_TIME_ORB_FULL                              431
-#define IMG_TIME_ORB_EMPTY                             432
-#define IMG_EMERALD_YELLOW                             433
-#define IMG_EMERALD_YELLOW_MOVING                      434
-#define IMG_EMERALD_YELLOW_FALLING                     435
-#define IMG_EMERALD_RED                                        436
-#define IMG_EMERALD_RED_MOVING                         437
-#define IMG_EMERALD_RED_FALLING                                438
-#define IMG_EMERALD_PURPLE                             439
-#define IMG_EMERALD_PURPLE_MOVING                      440
-#define IMG_EMERALD_PURPLE_FALLING                     441
-#define IMG_WALL_EMERALD_YELLOW                                442
-#define IMG_WALL_EMERALD_RED                           443
-#define IMG_WALL_EMERALD_PURPLE                                444
-#define IMG_WALL_BD_DIAMOND                            445
-#define IMG_EXPANDABLE_WALL                            446
-#define IMG_EXPANDABLE_WALL_HORIZONTAL                 447
-#define IMG_EXPANDABLE_WALL_HORIZONTAL_EDITOR          448
-#define IMG_EXPANDABLE_WALL_VERTICAL                   449
-#define IMG_EXPANDABLE_WALL_VERTICAL_EDITOR            450
-#define IMG_EXPANDABLE_WALL_ANY                                451
-#define IMG_EXPANDABLE_WALL_ANY_EDITOR                 452
-#define IMG_EXPANDABLE_WALL_GROWING_LEFT               453
-#define IMG_EXPANDABLE_WALL_GROWING_RIGHT              454
-#define IMG_EXPANDABLE_WALL_GROWING_UP                 455
-#define IMG_EXPANDABLE_WALL_GROWING_DOWN               456
-#define IMG_BLACK_ORB                                  457
-#define IMG_SPEED_PILL                                 458
-#define IMG_DARK_YAMYAM                                        459
-#define IMG_DYNABOMB                                   460
-#define IMG_DYNABOMB_ACTIVE                            461
-#define IMG_DYNABOMB_PLAYER_1                          462
-#define IMG_DYNABOMB_PLAYER_1_ACTIVE                   463
-#define IMG_DYNABOMB_PLAYER_2                          464
-#define IMG_DYNABOMB_PLAYER_2_ACTIVE                   465
-#define IMG_DYNABOMB_PLAYER_3                          466
-#define IMG_DYNABOMB_PLAYER_3_ACTIVE                   467
-#define IMG_DYNABOMB_PLAYER_4                          468
-#define IMG_DYNABOMB_PLAYER_4_ACTIVE                   469
-#define IMG_DYNABOMB_INCREASE_NUMBER                   470
-#define IMG_DYNABOMB_INCREASE_SIZE                     471
-#define IMG_DYNABOMB_INCREASE_POWER                    472
-#define IMG_PIG                                                473
-#define IMG_PIG_DOWN                                   474
-#define IMG_PIG_UP                                     475
-#define IMG_PIG_LEFT                                   476
-#define IMG_PIG_RIGHT                                  477
-#define IMG_PIG_MOVING_DOWN                            478
-#define IMG_PIG_MOVING_UP                              479
-#define IMG_PIG_MOVING_LEFT                            480
-#define IMG_PIG_MOVING_RIGHT                           481
-#define IMG_PIG_DIGGING_DOWN                           482
-#define IMG_PIG_DIGGING_UP                             483
-#define IMG_PIG_DIGGING_LEFT                           484
-#define IMG_PIG_DIGGING_RIGHT                          485
-#define IMG_DRAGON                                     486
-#define IMG_DRAGON_DOWN                                        487
-#define IMG_DRAGON_UP                                  488
-#define IMG_DRAGON_LEFT                                        489
-#define IMG_DRAGON_RIGHT                               490
-#define IMG_DRAGON_MOVING_DOWN                         491
-#define IMG_DRAGON_MOVING_UP                           492
-#define IMG_DRAGON_MOVING_LEFT                         493
-#define IMG_DRAGON_MOVING_RIGHT                                494
-#define IMG_DRAGON_ATTACKING_DOWN                      495
-#define IMG_DRAGON_ATTACKING_UP                                496
-#define IMG_DRAGON_ATTACKING_LEFT                      497
-#define IMG_DRAGON_ATTACKING_RIGHT                     498
-#define IMG_MOLE                                       499
-#define IMG_MOLE_DOWN                                  500
-#define IMG_MOLE_UP                                    501
-#define IMG_MOLE_LEFT                                  502
-#define IMG_MOLE_RIGHT                                 503
-#define IMG_MOLE_MOVING_DOWN                           504
-#define IMG_MOLE_MOVING_UP                             505
-#define IMG_MOLE_MOVING_LEFT                           506
-#define IMG_MOLE_MOVING_RIGHT                          507
-#define IMG_MOLE_DIGGING_DOWN                          508
-#define IMG_MOLE_DIGGING_UP                            509
-#define IMG_MOLE_DIGGING_LEFT                          510
-#define IMG_MOLE_DIGGING_RIGHT                         511
-#define IMG_PENGUIN                                    512
-#define IMG_PENGUIN_EDITOR                             513
-#define IMG_PENGUIN_DOWN                               514
-#define IMG_PENGUIN_UP                                 515
-#define IMG_PENGUIN_LEFT                               516
-#define IMG_PENGUIN_RIGHT                              517
-#define IMG_PENGUIN_MOVING_DOWN                                518
-#define IMG_PENGUIN_MOVING_UP                          519
-#define IMG_PENGUIN_MOVING_LEFT                                520
-#define IMG_PENGUIN_MOVING_RIGHT                       521
-#define IMG_SATELLITE                                  522
-#define IMG_FLAMES_1_LEFT                              523
-#define IMG_FLAMES_2_LEFT                              524
-#define IMG_FLAMES_3_LEFT                              525
-#define IMG_FLAMES_1_RIGHT                             526
-#define IMG_FLAMES_2_RIGHT                             527
-#define IMG_FLAMES_3_RIGHT                             528
-#define IMG_FLAMES_1_UP                                        529
-#define IMG_FLAMES_2_UP                                        530
-#define IMG_FLAMES_3_UP                                        531
-#define IMG_FLAMES_1_DOWN                              532
-#define IMG_FLAMES_2_DOWN                              533
-#define IMG_FLAMES_3_DOWN                              534
-#define IMG_STONEBLOCK                                 535
-#define IMG_PLAYER_1                                   536
-#define IMG_PLAYER_1_EDITOR                            537
-#define IMG_PLAYER_1_DOWN                              538
-#define IMG_PLAYER_1_UP                                        539
-#define IMG_PLAYER_1_LEFT                              540
-#define IMG_PLAYER_1_RIGHT                             541
-#define IMG_PLAYER_1_MOVING_DOWN                       542
-#define IMG_PLAYER_1_MOVING_UP                         543
-#define IMG_PLAYER_1_MOVING_LEFT                       544
-#define IMG_PLAYER_1_MOVING_RIGHT                      545
-#define IMG_PLAYER_1_DIGGING_DOWN                      546
-#define IMG_PLAYER_1_DIGGING_UP                                547
-#define IMG_PLAYER_1_DIGGING_LEFT                      548
-#define IMG_PLAYER_1_DIGGING_RIGHT                     549
-#define IMG_PLAYER_1_COLLECTING_DOWN                   550
-#define IMG_PLAYER_1_COLLECTING_UP                     551
-#define IMG_PLAYER_1_COLLECTING_LEFT                   552
-#define IMG_PLAYER_1_COLLECTING_RIGHT                  553
-#define IMG_PLAYER_1_PUSHING_DOWN                      554
-#define IMG_PLAYER_1_PUSHING_UP                                555
-#define IMG_PLAYER_1_PUSHING_LEFT                      556
-#define IMG_PLAYER_1_PUSHING_RIGHT                     557
-#define IMG_PLAYER_1_SNAPPING_DOWN                     558
-#define IMG_PLAYER_1_SNAPPING_UP                       559
-#define IMG_PLAYER_1_SNAPPING_LEFT                     560
-#define IMG_PLAYER_1_SNAPPING_RIGHT                    561
-#define IMG_PLAYER_2                                   562
-#define IMG_PLAYER_2_EDITOR                            563
-#define IMG_PLAYER_2_DOWN                              564
-#define IMG_PLAYER_2_UP                                        565
-#define IMG_PLAYER_2_LEFT                              566
-#define IMG_PLAYER_2_RIGHT                             567
-#define IMG_PLAYER_2_MOVING_DOWN                       568
-#define IMG_PLAYER_2_MOVING_UP                         569
-#define IMG_PLAYER_2_MOVING_LEFT                       570
-#define IMG_PLAYER_2_MOVING_RIGHT                      571
-#define IMG_PLAYER_2_DIGGING_DOWN                      572
-#define IMG_PLAYER_2_DIGGING_UP                                573
-#define IMG_PLAYER_2_DIGGING_LEFT                      574
-#define IMG_PLAYER_2_DIGGING_RIGHT                     575
-#define IMG_PLAYER_2_COLLECTING_DOWN                   576
-#define IMG_PLAYER_2_COLLECTING_UP                     577
-#define IMG_PLAYER_2_COLLECTING_LEFT                   578
-#define IMG_PLAYER_2_COLLECTING_RIGHT                  579
-#define IMG_PLAYER_2_PUSHING_DOWN                      580
-#define IMG_PLAYER_2_PUSHING_UP                                581
-#define IMG_PLAYER_2_PUSHING_LEFT                      582
-#define IMG_PLAYER_2_PUSHING_RIGHT                     583
-#define IMG_PLAYER_2_SNAPPING_DOWN                     584
-#define IMG_PLAYER_2_SNAPPING_UP                       585
-#define IMG_PLAYER_2_SNAPPING_LEFT                     586
-#define IMG_PLAYER_2_SNAPPING_RIGHT                    587
-#define IMG_PLAYER_3                                   588
-#define IMG_PLAYER_3_EDITOR                            589
-#define IMG_PLAYER_3_DOWN                              590
-#define IMG_PLAYER_3_UP                                        591
-#define IMG_PLAYER_3_LEFT                              592
-#define IMG_PLAYER_3_RIGHT                             593
-#define IMG_PLAYER_3_MOVING_DOWN                       594
-#define IMG_PLAYER_3_MOVING_UP                         595
-#define IMG_PLAYER_3_MOVING_LEFT                       596
-#define IMG_PLAYER_3_MOVING_RIGHT                      597
-#define IMG_PLAYER_3_DIGGING_DOWN                      598
-#define IMG_PLAYER_3_DIGGING_UP                                599
-#define IMG_PLAYER_3_DIGGING_LEFT                      600
-#define IMG_PLAYER_3_DIGGING_RIGHT                     601
-#define IMG_PLAYER_3_COLLECTING_DOWN                   602
-#define IMG_PLAYER_3_COLLECTING_UP                     603
-#define IMG_PLAYER_3_COLLECTING_LEFT                   604
-#define IMG_PLAYER_3_COLLECTING_RIGHT                  605
-#define IMG_PLAYER_3_PUSHING_DOWN                      606
-#define IMG_PLAYER_3_PUSHING_UP                                607
-#define IMG_PLAYER_3_PUSHING_LEFT                      608
-#define IMG_PLAYER_3_PUSHING_RIGHT                     609
-#define IMG_PLAYER_3_SNAPPING_DOWN                     610
-#define IMG_PLAYER_3_SNAPPING_UP                       611
-#define IMG_PLAYER_3_SNAPPING_LEFT                     612
-#define IMG_PLAYER_3_SNAPPING_RIGHT                    613
-#define IMG_PLAYER_4                                   614
-#define IMG_PLAYER_4_EDITOR                            615
-#define IMG_PLAYER_4_DOWN                              616
-#define IMG_PLAYER_4_UP                                        617
-#define IMG_PLAYER_4_LEFT                              618
-#define IMG_PLAYER_4_RIGHT                             619
-#define IMG_PLAYER_4_MOVING_DOWN                       620
-#define IMG_PLAYER_4_MOVING_UP                         621
-#define IMG_PLAYER_4_MOVING_LEFT                       622
-#define IMG_PLAYER_4_MOVING_RIGHT                      623
-#define IMG_PLAYER_4_DIGGING_DOWN                      624
-#define IMG_PLAYER_4_DIGGING_UP                                625
-#define IMG_PLAYER_4_DIGGING_LEFT                      626
-#define IMG_PLAYER_4_DIGGING_RIGHT                     627
-#define IMG_PLAYER_4_COLLECTING_DOWN                   628
-#define IMG_PLAYER_4_COLLECTING_UP                     629
-#define IMG_PLAYER_4_COLLECTING_LEFT                   630
-#define IMG_PLAYER_4_COLLECTING_RIGHT                  631
-#define IMG_PLAYER_4_PUSHING_DOWN                      632
-#define IMG_PLAYER_4_PUSHING_UP                                633
-#define IMG_PLAYER_4_PUSHING_LEFT                      634
-#define IMG_PLAYER_4_PUSHING_RIGHT                     635
-#define IMG_PLAYER_4_SNAPPING_DOWN                     636
-#define IMG_PLAYER_4_SNAPPING_UP                       637
-#define IMG_PLAYER_4_SNAPPING_LEFT                     638
-#define IMG_PLAYER_4_SNAPPING_RIGHT                    639
-#define IMG_DEFAULT_EXPLODING                          640
-#define IMG_TWINKLE_BLUE                               641
-#define IMG_TWINKLE_WHITE                              642
-#define IMG_STEELWALL_TOPLEFT                          643
-#define IMG_STEELWALL_TOPRIGHT                         644
-#define IMG_STEELWALL_BOTTOMLEFT                       645
-#define IMG_STEELWALL_BOTTOMRIGHT                      646
-#define IMG_STEELWALL_HORIZONTAL                       647
-#define IMG_STEELWALL_VERTICAL                         648
-#define IMG_STEELWALL_TOPLEFT_EDITOR                   649
-#define IMG_STEELWALL_TOPRIGHT_EDITOR                  650
-#define IMG_STEELWALL_BOTTOMLEFT_EDITOR                        651
-#define IMG_STEELWALL_BOTTOMRIGHT_EDITOR               652
-#define IMG_STEELWALL_HORIZONTAL_EDITOR                        653
-#define IMG_STEELWALL_VERTICAL_EDITOR                  654
-#define IMG_INVISIBLE_STEELWALL_TOPLEFT                        655
-#define IMG_INVISIBLE_STEELWALL_TOPRIGHT               656
-#define IMG_INVISIBLE_STEELWALL_BOTTOMLEFT             657
-#define IMG_INVISIBLE_STEELWALL_BOTTOMRIGHT            658
-#define IMG_INVISIBLE_STEELWALL_HORIZONTAL             659
-#define IMG_INVISIBLE_STEELWALL_VERTICAL               660
-#define IMG_INVISIBLE_STEELWALL_TOPLEFT_EDITOR         661
-#define IMG_INVISIBLE_STEELWALL_TOPRIGHT_EDITOR                662
-#define IMG_INVISIBLE_STEELWALL_BOTTOMLEFT_EDITOR      663
-#define IMG_INVISIBLE_STEELWALL_BOTTOMRIGHT_EDITOR     664
-#define IMG_INVISIBLE_STEELWALL_HORIZONTAL_EDITOR      665
-#define IMG_INVISIBLE_STEELWALL_VERTICAL_EDITOR                666
-#define IMG_ARROW_LEFT                                 667
-#define IMG_ARROW_RIGHT                                        668
-#define IMG_ARROW_UP                                   669
-#define IMG_ARROW_DOWN                                 670
-#define IMG_UNKNOWN                                    671
-#define IMG_TRIGGER_ELEMENT                            672
-#define IMG_TRIGGER_PLAYER                             673
-#define IMG_EMC_KEY_5                                  674
-#define IMG_EMC_KEY_6                                  675
-#define IMG_EMC_KEY_7                                  676
-#define IMG_EMC_KEY_8                                  677
-#define IMG_EMC_GATE_5                                 678
-#define IMG_EMC_GATE_5_GRAY                            679
-#define IMG_EMC_GATE_5_GRAY_EDITOR                     680
-#define IMG_EMC_GATE_6                                 681
-#define IMG_EMC_GATE_6_GRAY                            682
-#define IMG_EMC_GATE_6_GRAY_EDITOR                     683
-#define IMG_EMC_GATE_7                                 684
-#define IMG_EMC_GATE_7_GRAY                            685
-#define IMG_EMC_GATE_7_GRAY_EDITOR                     686
-#define IMG_EMC_GATE_8                                 687
-#define IMG_EMC_GATE_8_GRAY                            688
-#define IMG_EMC_GATE_8_GRAY_EDITOR                     689
-#define IMG_EMC_ANDROID                                        690
-#define IMG_EMC_GRASS                                  691
-#define IMG_EMC_GRASS_CRUMBLED                         692
-#define IMG_EMC_GRASS_DIGGING_LEFT                     693
-#define IMG_EMC_GRASS_DIGGING_RIGHT                    694
-#define IMG_EMC_GRASS_DIGGING_UP                       695
-#define IMG_EMC_GRASS_DIGGING_DOWN                     696
-#define IMG_EMC_GRASS_DIGGING_LEFT_CRUMBLED            697
-#define IMG_EMC_GRASS_DIGGING_RIGHT_CRUMBLED           698
-#define IMG_EMC_GRASS_DIGGING_UP_CRUMBLED              699
-#define IMG_EMC_GRASS_DIGGING_DOWN_CRUMBLED            700
-#define IMG_EMC_MAGIC_BALL                             701
-#define IMG_EMC_MAGIC_BALL_ACTIVE                      702
-#define IMG_EMC_MAGIC_BALL_SWITCH                      703
-#define IMG_EMC_MAGIC_BALL_SWITCH_ACTIVE               704
-#define IMG_EMC_SPRING_BUMPER                          705
-#define IMG_EMC_SPRING_BUMPER_ACTIVE                   706
-#define IMG_EMC_PLANT                                  707
-#define IMG_EMC_PLANT_CRUMBLED                         708
-#define IMG_EMC_LENSES                                 709
-#define IMG_EMC_MAGNIFIER                              710
-#define IMG_EMC_WALL_9                                 711
-#define IMG_EMC_WALL_10                                        712
-#define IMG_EMC_WALL_11                                        713
-#define IMG_EMC_WALL_12                                        714
-#define IMG_EMC_WALL_13                                        715
-#define IMG_EMC_WALL_14                                        716
-#define IMG_EMC_WALL_15                                        717
-#define IMG_EMC_WALL_16                                        718
-#define IMG_EMC_WALL_SLIPPERY_1                                719
-#define IMG_EMC_WALL_SLIPPERY_2                                720
-#define IMG_EMC_WALL_SLIPPERY_3                                721
-#define IMG_EMC_WALL_SLIPPERY_4                                722
-#define IMG_EMC_FAKE_GRASS                             723
-#define IMG_EMC_FAKE_GRASS_CRUMBLED                    724
-#define IMG_EMC_FAKE_GRASS_ACTIVE                      725
-#define IMG_EMC_FAKE_GRASS_ACTIVE_CRUMBLED             726
-#define IMG_EMC_FAKE_ACID                              727
-#define IMG_EMC_DRIPPER                                        728
-#define IMG_EMC_DRIPPER_EDITOR                         729
-#define IMG_EMC_DRIPPER_ACTIVE                         730
-#define IMG_CHAR_SPACE                                 731
-#define IMG_CHAR_EXCLAM                                        732
-#define IMG_CHAR_QUOTEDBL                              733
-#define IMG_CHAR_NUMBERSIGN                            734
-#define IMG_CHAR_DOLLAR                                        735
-#define IMG_CHAR_PERCENT                               736
-#define IMG_CHAR_AMPERSAND                             737
-#define IMG_CHAR_APOSTROPHE                            738
-#define IMG_CHAR_PARENLEFT                             739
-#define IMG_CHAR_PARENRIGHT                            740
-#define IMG_CHAR_ASTERISK                              741
-#define IMG_CHAR_PLUS                                  742
-#define IMG_CHAR_COMMA                                 743
-#define IMG_CHAR_MINUS                                 744
-#define IMG_CHAR_PERIOD                                        745
-#define IMG_CHAR_SLASH                                 746
-#define IMG_CHAR_0                                     747
-#define IMG_CHAR_1                                     748
-#define IMG_CHAR_2                                     749
-#define IMG_CHAR_3                                     750
-#define IMG_CHAR_4                                     751
-#define IMG_CHAR_5                                     752
-#define IMG_CHAR_6                                     753
-#define IMG_CHAR_7                                     754
-#define IMG_CHAR_8                                     755
-#define IMG_CHAR_9                                     756
-#define IMG_CHAR_COLON                                 757
-#define IMG_CHAR_SEMICOLON                             758
-#define IMG_CHAR_LESS                                  759
-#define IMG_CHAR_EQUAL                                 760
-#define IMG_CHAR_GREATER                               761
-#define IMG_CHAR_QUESTION                              762
-#define IMG_CHAR_AT                                    763
-#define IMG_CHAR_A                                     764
-#define IMG_CHAR_B                                     765
-#define IMG_CHAR_C                                     766
-#define IMG_CHAR_D                                     767
-#define IMG_CHAR_E                                     768
-#define IMG_CHAR_F                                     769
-#define IMG_CHAR_G                                     770
-#define IMG_CHAR_H                                     771
-#define IMG_CHAR_I                                     772
-#define IMG_CHAR_J                                     773
-#define IMG_CHAR_K                                     774
-#define IMG_CHAR_L                                     775
-#define IMG_CHAR_M                                     776
-#define IMG_CHAR_N                                     777
-#define IMG_CHAR_O                                     778
-#define IMG_CHAR_P                                     779
-#define IMG_CHAR_Q                                     780
-#define IMG_CHAR_R                                     781
-#define IMG_CHAR_S                                     782
-#define IMG_CHAR_T                                     783
-#define IMG_CHAR_U                                     784
-#define IMG_CHAR_V                                     785
-#define IMG_CHAR_W                                     786
-#define IMG_CHAR_X                                     787
-#define IMG_CHAR_Y                                     788
-#define IMG_CHAR_Z                                     789
-#define IMG_CHAR_BRACKETLEFT                           790
-#define IMG_CHAR_BACKSLASH                             791
-#define IMG_CHAR_BRACKETRIGHT                          792
-#define IMG_CHAR_ASCIICIRCUM                           793
-#define IMG_CHAR_UNDERSCORE                            794
-#define IMG_CHAR_COPYRIGHT                             795
-#define IMG_CHAR_AUMLAUT                               796
-#define IMG_CHAR_OUMLAUT                               797
-#define IMG_CHAR_UUMLAUT                               798
-#define IMG_CHAR_DEGREE                                        799
-#define IMG_CHAR_TRADEMARK                             800
-#define IMG_CHAR_CURSOR                                        801
-#define IMG_CUSTOM_1                                   802
-#define IMG_CUSTOM_1_EDITOR                            803
-#define IMG_CUSTOM_2                                   804
-#define IMG_CUSTOM_2_EDITOR                            805
-#define IMG_CUSTOM_3                                   806
-#define IMG_CUSTOM_3_EDITOR                            807
-#define IMG_CUSTOM_4                                   808
-#define IMG_CUSTOM_4_EDITOR                            809
-#define IMG_CUSTOM_5                                   810
-#define IMG_CUSTOM_5_EDITOR                            811
-#define IMG_CUSTOM_6                                   812
-#define IMG_CUSTOM_6_EDITOR                            813
-#define IMG_CUSTOM_7                                   814
-#define IMG_CUSTOM_7_EDITOR                            815
-#define IMG_CUSTOM_8                                   816
-#define IMG_CUSTOM_8_EDITOR                            817
-#define IMG_CUSTOM_9                                   818
-#define IMG_CUSTOM_9_EDITOR                            819
-#define IMG_CUSTOM_10                                  820
-#define IMG_CUSTOM_10_EDITOR                           821
-#define IMG_CUSTOM_11                                  822
-#define IMG_CUSTOM_11_EDITOR                           823
-#define IMG_CUSTOM_12                                  824
-#define IMG_CUSTOM_12_EDITOR                           825
-#define IMG_CUSTOM_13                                  826
-#define IMG_CUSTOM_13_EDITOR                           827
-#define IMG_CUSTOM_14                                  828
-#define IMG_CUSTOM_14_EDITOR                           829
-#define IMG_CUSTOM_15                                  830
-#define IMG_CUSTOM_15_EDITOR                           831
-#define IMG_CUSTOM_16                                  832
-#define IMG_CUSTOM_16_EDITOR                           833
-#define IMG_CUSTOM_17                                  834
-#define IMG_CUSTOM_17_EDITOR                           835
-#define IMG_CUSTOM_18                                  836
-#define IMG_CUSTOM_18_EDITOR                           837
-#define IMG_CUSTOM_19                                  838
-#define IMG_CUSTOM_19_EDITOR                           839
-#define IMG_CUSTOM_20                                  840
-#define IMG_CUSTOM_20_EDITOR                           841
-#define IMG_CUSTOM_21                                  842
-#define IMG_CUSTOM_21_EDITOR                           843
-#define IMG_CUSTOM_22                                  844
-#define IMG_CUSTOM_22_EDITOR                           845
-#define IMG_CUSTOM_23                                  846
-#define IMG_CUSTOM_23_EDITOR                           847
-#define IMG_CUSTOM_24                                  848
-#define IMG_CUSTOM_24_EDITOR                           849
-#define IMG_CUSTOM_25                                  850
-#define IMG_CUSTOM_25_EDITOR                           851
-#define IMG_CUSTOM_26                                  852
-#define IMG_CUSTOM_26_EDITOR                           853
-#define IMG_CUSTOM_27                                  854
-#define IMG_CUSTOM_27_EDITOR                           855
-#define IMG_CUSTOM_28                                  856
-#define IMG_CUSTOM_28_EDITOR                           857
-#define IMG_CUSTOM_29                                  858
-#define IMG_CUSTOM_29_EDITOR                           859
-#define IMG_CUSTOM_30                                  860
-#define IMG_CUSTOM_30_EDITOR                           861
-#define IMG_CUSTOM_31                                  862
-#define IMG_CUSTOM_31_EDITOR                           863
-#define IMG_CUSTOM_32                                  864
-#define IMG_CUSTOM_32_EDITOR                           865
-#define IMG_CUSTOM_33                                  866
-#define IMG_CUSTOM_33_EDITOR                           867
-#define IMG_CUSTOM_34                                  868
-#define IMG_CUSTOM_34_EDITOR                           869
-#define IMG_CUSTOM_35                                  870
-#define IMG_CUSTOM_35_EDITOR                           871
-#define IMG_CUSTOM_36                                  872
-#define IMG_CUSTOM_36_EDITOR                           873
-#define IMG_CUSTOM_37                                  874
-#define IMG_CUSTOM_37_EDITOR                           875
-#define IMG_CUSTOM_38                                  876
-#define IMG_CUSTOM_38_EDITOR                           877
-#define IMG_CUSTOM_39                                  878
-#define IMG_CUSTOM_39_EDITOR                           879
-#define IMG_CUSTOM_40                                  880
-#define IMG_CUSTOM_40_EDITOR                           881
-#define IMG_CUSTOM_41                                  882
-#define IMG_CUSTOM_41_EDITOR                           883
-#define IMG_CUSTOM_42                                  884
-#define IMG_CUSTOM_42_EDITOR                           885
-#define IMG_CUSTOM_43                                  886
-#define IMG_CUSTOM_43_EDITOR                           887
-#define IMG_CUSTOM_44                                  888
-#define IMG_CUSTOM_44_EDITOR                           889
-#define IMG_CUSTOM_45                                  890
-#define IMG_CUSTOM_45_EDITOR                           891
-#define IMG_CUSTOM_46                                  892
-#define IMG_CUSTOM_46_EDITOR                           893
-#define IMG_CUSTOM_47                                  894
-#define IMG_CUSTOM_47_EDITOR                           895
-#define IMG_CUSTOM_48                                  896
-#define IMG_CUSTOM_48_EDITOR                           897
-#define IMG_CUSTOM_49                                  898
-#define IMG_CUSTOM_49_EDITOR                           899
-#define IMG_CUSTOM_50                                  900
-#define IMG_CUSTOM_50_EDITOR                           901
-#define IMG_CUSTOM_51                                  902
-#define IMG_CUSTOM_51_EDITOR                           903
-#define IMG_CUSTOM_52                                  904
-#define IMG_CUSTOM_52_EDITOR                           905
-#define IMG_CUSTOM_53                                  906
-#define IMG_CUSTOM_53_EDITOR                           907
-#define IMG_CUSTOM_54                                  908
-#define IMG_CUSTOM_54_EDITOR                           909
-#define IMG_CUSTOM_55                                  910
-#define IMG_CUSTOM_55_EDITOR                           911
-#define IMG_CUSTOM_56                                  912
-#define IMG_CUSTOM_56_EDITOR                           913
-#define IMG_CUSTOM_57                                  914
-#define IMG_CUSTOM_57_EDITOR                           915
-#define IMG_CUSTOM_58                                  916
-#define IMG_CUSTOM_58_EDITOR                           917
-#define IMG_CUSTOM_59                                  918
-#define IMG_CUSTOM_59_EDITOR                           919
-#define IMG_CUSTOM_60                                  920
-#define IMG_CUSTOM_60_EDITOR                           921
-#define IMG_CUSTOM_61                                  922
-#define IMG_CUSTOM_61_EDITOR                           923
-#define IMG_CUSTOM_62                                  924
-#define IMG_CUSTOM_62_EDITOR                           925
-#define IMG_CUSTOM_63                                  926
-#define IMG_CUSTOM_63_EDITOR                           927
-#define IMG_CUSTOM_64                                  928
-#define IMG_CUSTOM_64_EDITOR                           929
-#define IMG_CUSTOM_65                                  930
-#define IMG_CUSTOM_65_EDITOR                           931
-#define IMG_CUSTOM_66                                  932
-#define IMG_CUSTOM_66_EDITOR                           933
-#define IMG_CUSTOM_67                                  934
-#define IMG_CUSTOM_67_EDITOR                           935
-#define IMG_CUSTOM_68                                  936
-#define IMG_CUSTOM_68_EDITOR                           937
-#define IMG_CUSTOM_69                                  938
-#define IMG_CUSTOM_69_EDITOR                           939
-#define IMG_CUSTOM_70                                  940
-#define IMG_CUSTOM_70_EDITOR                           941
-#define IMG_CUSTOM_71                                  942
-#define IMG_CUSTOM_71_EDITOR                           943
-#define IMG_CUSTOM_72                                  944
-#define IMG_CUSTOM_72_EDITOR                           945
-#define IMG_CUSTOM_73                                  946
-#define IMG_CUSTOM_73_EDITOR                           947
-#define IMG_CUSTOM_74                                  948
-#define IMG_CUSTOM_74_EDITOR                           949
-#define IMG_CUSTOM_75                                  950
-#define IMG_CUSTOM_75_EDITOR                           951
-#define IMG_CUSTOM_76                                  952
-#define IMG_CUSTOM_76_EDITOR                           953
-#define IMG_CUSTOM_77                                  954
-#define IMG_CUSTOM_77_EDITOR                           955
-#define IMG_CUSTOM_78                                  956
-#define IMG_CUSTOM_78_EDITOR                           957
-#define IMG_CUSTOM_79                                  958
-#define IMG_CUSTOM_79_EDITOR                           959
-#define IMG_CUSTOM_80                                  960
-#define IMG_CUSTOM_80_EDITOR                           961
-#define IMG_CUSTOM_81                                  962
-#define IMG_CUSTOM_81_EDITOR                           963
-#define IMG_CUSTOM_82                                  964
-#define IMG_CUSTOM_82_EDITOR                           965
-#define IMG_CUSTOM_83                                  966
-#define IMG_CUSTOM_83_EDITOR                           967
-#define IMG_CUSTOM_84                                  968
-#define IMG_CUSTOM_84_EDITOR                           969
-#define IMG_CUSTOM_85                                  970
-#define IMG_CUSTOM_85_EDITOR                           971
-#define IMG_CUSTOM_86                                  972
-#define IMG_CUSTOM_86_EDITOR                           973
-#define IMG_CUSTOM_87                                  974
-#define IMG_CUSTOM_87_EDITOR                           975
-#define IMG_CUSTOM_88                                  976
-#define IMG_CUSTOM_88_EDITOR                           977
-#define IMG_CUSTOM_89                                  978
-#define IMG_CUSTOM_89_EDITOR                           979
-#define IMG_CUSTOM_90                                  980
-#define IMG_CUSTOM_90_EDITOR                           981
-#define IMG_CUSTOM_91                                  982
-#define IMG_CUSTOM_91_EDITOR                           983
-#define IMG_CUSTOM_92                                  984
-#define IMG_CUSTOM_92_EDITOR                           985
-#define IMG_CUSTOM_93                                  986
-#define IMG_CUSTOM_93_EDITOR                           987
-#define IMG_CUSTOM_94                                  988
-#define IMG_CUSTOM_94_EDITOR                           989
-#define IMG_CUSTOM_95                                  990
-#define IMG_CUSTOM_95_EDITOR                           991
-#define IMG_CUSTOM_96                                  992
-#define IMG_CUSTOM_96_EDITOR                           993
-#define IMG_CUSTOM_97                                  994
-#define IMG_CUSTOM_97_EDITOR                           995
-#define IMG_CUSTOM_98                                  996
-#define IMG_CUSTOM_98_EDITOR                           997
-#define IMG_CUSTOM_99                                  998
-#define IMG_CUSTOM_99_EDITOR                           999
-#define IMG_CUSTOM_100                                 1000
-#define IMG_CUSTOM_100_EDITOR                          1001
-#define IMG_CUSTOM_101                                 1002
-#define IMG_CUSTOM_101_EDITOR                          1003
-#define IMG_CUSTOM_102                                 1004
-#define IMG_CUSTOM_102_EDITOR                          1005
-#define IMG_CUSTOM_103                                 1006
-#define IMG_CUSTOM_103_EDITOR                          1007
-#define IMG_CUSTOM_104                                 1008
-#define IMG_CUSTOM_104_EDITOR                          1009
-#define IMG_CUSTOM_105                                 1010
-#define IMG_CUSTOM_105_EDITOR                          1011
-#define IMG_CUSTOM_106                                 1012
-#define IMG_CUSTOM_106_EDITOR                          1013
-#define IMG_CUSTOM_107                                 1014
-#define IMG_CUSTOM_107_EDITOR                          1015
-#define IMG_CUSTOM_108                                 1016
-#define IMG_CUSTOM_108_EDITOR                          1017
-#define IMG_CUSTOM_109                                 1018
-#define IMG_CUSTOM_109_EDITOR                          1019
-#define IMG_CUSTOM_110                                 1020
-#define IMG_CUSTOM_110_EDITOR                          1021
-#define IMG_CUSTOM_111                                 1022
-#define IMG_CUSTOM_111_EDITOR                          1023
-#define IMG_CUSTOM_112                                 1024
-#define IMG_CUSTOM_112_EDITOR                          1025
-#define IMG_CUSTOM_113                                 1026
-#define IMG_CUSTOM_113_EDITOR                          1027
-#define IMG_CUSTOM_114                                 1028
-#define IMG_CUSTOM_114_EDITOR                          1029
-#define IMG_CUSTOM_115                                 1030
-#define IMG_CUSTOM_115_EDITOR                          1031
-#define IMG_CUSTOM_116                                 1032
-#define IMG_CUSTOM_116_EDITOR                          1033
-#define IMG_CUSTOM_117                                 1034
-#define IMG_CUSTOM_117_EDITOR                          1035
-#define IMG_CUSTOM_118                                 1036
-#define IMG_CUSTOM_118_EDITOR                          1037
-#define IMG_CUSTOM_119                                 1038
-#define IMG_CUSTOM_119_EDITOR                          1039
-#define IMG_CUSTOM_120                                 1040
-#define IMG_CUSTOM_120_EDITOR                          1041
-#define IMG_CUSTOM_121                                 1042
-#define IMG_CUSTOM_121_EDITOR                          1043
-#define IMG_CUSTOM_122                                 1044
-#define IMG_CUSTOM_122_EDITOR                          1045
-#define IMG_CUSTOM_123                                 1046
-#define IMG_CUSTOM_123_EDITOR                          1047
-#define IMG_CUSTOM_124                                 1048
-#define IMG_CUSTOM_124_EDITOR                          1049
-#define IMG_CUSTOM_125                                 1050
-#define IMG_CUSTOM_125_EDITOR                          1051
-#define IMG_CUSTOM_126                                 1052
-#define IMG_CUSTOM_126_EDITOR                          1053
-#define IMG_CUSTOM_127                                 1054
-#define IMG_CUSTOM_127_EDITOR                          1055
-#define IMG_CUSTOM_128                                 1056
-#define IMG_CUSTOM_128_EDITOR                          1057
-#define IMG_CUSTOM_129                                 1058
-#define IMG_CUSTOM_129_EDITOR                          1059
-#define IMG_CUSTOM_130                                 1060
-#define IMG_CUSTOM_130_EDITOR                          1061
-#define IMG_CUSTOM_131                                 1062
-#define IMG_CUSTOM_131_EDITOR                          1063
-#define IMG_CUSTOM_132                                 1064
-#define IMG_CUSTOM_132_EDITOR                          1065
-#define IMG_CUSTOM_133                                 1066
-#define IMG_CUSTOM_133_EDITOR                          1067
-#define IMG_CUSTOM_134                                 1068
-#define IMG_CUSTOM_134_EDITOR                          1069
-#define IMG_CUSTOM_135                                 1070
-#define IMG_CUSTOM_135_EDITOR                          1071
-#define IMG_CUSTOM_136                                 1072
-#define IMG_CUSTOM_136_EDITOR                          1073
-#define IMG_CUSTOM_137                                 1074
-#define IMG_CUSTOM_137_EDITOR                          1075
-#define IMG_CUSTOM_138                                 1076
-#define IMG_CUSTOM_138_EDITOR                          1077
-#define IMG_CUSTOM_139                                 1078
-#define IMG_CUSTOM_139_EDITOR                          1079
-#define IMG_CUSTOM_140                                 1080
-#define IMG_CUSTOM_140_EDITOR                          1081
-#define IMG_CUSTOM_141                                 1082
-#define IMG_CUSTOM_141_EDITOR                          1083
-#define IMG_CUSTOM_142                                 1084
-#define IMG_CUSTOM_142_EDITOR                          1085
-#define IMG_CUSTOM_143                                 1086
-#define IMG_CUSTOM_143_EDITOR                          1087
-#define IMG_CUSTOM_144                                 1088
-#define IMG_CUSTOM_144_EDITOR                          1089
-#define IMG_CUSTOM_145                                 1090
-#define IMG_CUSTOM_145_EDITOR                          1091
-#define IMG_CUSTOM_146                                 1092
-#define IMG_CUSTOM_146_EDITOR                          1093
-#define IMG_CUSTOM_147                                 1094
-#define IMG_CUSTOM_147_EDITOR                          1095
-#define IMG_CUSTOM_148                                 1096
-#define IMG_CUSTOM_148_EDITOR                          1097
-#define IMG_CUSTOM_149                                 1098
-#define IMG_CUSTOM_149_EDITOR                          1099
-#define IMG_CUSTOM_150                                 1100
-#define IMG_CUSTOM_150_EDITOR                          1101
-#define IMG_CUSTOM_151                                 1102
-#define IMG_CUSTOM_151_EDITOR                          1103
-#define IMG_CUSTOM_152                                 1104
-#define IMG_CUSTOM_152_EDITOR                          1105
-#define IMG_CUSTOM_153                                 1106
-#define IMG_CUSTOM_153_EDITOR                          1107
-#define IMG_CUSTOM_154                                 1108
-#define IMG_CUSTOM_154_EDITOR                          1109
-#define IMG_CUSTOM_155                                 1110
-#define IMG_CUSTOM_155_EDITOR                          1111
-#define IMG_CUSTOM_156                                 1112
-#define IMG_CUSTOM_156_EDITOR                          1113
-#define IMG_CUSTOM_157                                 1114
-#define IMG_CUSTOM_157_EDITOR                          1115
-#define IMG_CUSTOM_158                                 1116
-#define IMG_CUSTOM_158_EDITOR                          1117
-#define IMG_CUSTOM_159                                 1118
-#define IMG_CUSTOM_159_EDITOR                          1119
-#define IMG_CUSTOM_160                                 1120
-#define IMG_CUSTOM_160_EDITOR                          1121
-#define IMG_CUSTOM_161                                 1122
-#define IMG_CUSTOM_161_EDITOR                          1123
-#define IMG_CUSTOM_162                                 1124
-#define IMG_CUSTOM_162_EDITOR                          1125
-#define IMG_CUSTOM_163                                 1126
-#define IMG_CUSTOM_163_EDITOR                          1127
-#define IMG_CUSTOM_164                                 1128
-#define IMG_CUSTOM_164_EDITOR                          1129
-#define IMG_CUSTOM_165                                 1130
-#define IMG_CUSTOM_165_EDITOR                          1131
-#define IMG_CUSTOM_166                                 1132
-#define IMG_CUSTOM_166_EDITOR                          1133
-#define IMG_CUSTOM_167                                 1134
-#define IMG_CUSTOM_167_EDITOR                          1135
-#define IMG_CUSTOM_168                                 1136
-#define IMG_CUSTOM_168_EDITOR                          1137
-#define IMG_CUSTOM_169                                 1138
-#define IMG_CUSTOM_169_EDITOR                          1139
-#define IMG_CUSTOM_170                                 1140
-#define IMG_CUSTOM_170_EDITOR                          1141
-#define IMG_CUSTOM_171                                 1142
-#define IMG_CUSTOM_171_EDITOR                          1143
-#define IMG_CUSTOM_172                                 1144
-#define IMG_CUSTOM_172_EDITOR                          1145
-#define IMG_CUSTOM_173                                 1146
-#define IMG_CUSTOM_173_EDITOR                          1147
-#define IMG_CUSTOM_174                                 1148
-#define IMG_CUSTOM_174_EDITOR                          1149
-#define IMG_CUSTOM_175                                 1150
-#define IMG_CUSTOM_175_EDITOR                          1151
-#define IMG_CUSTOM_176                                 1152
-#define IMG_CUSTOM_176_EDITOR                          1153
-#define IMG_CUSTOM_177                                 1154
-#define IMG_CUSTOM_177_EDITOR                          1155
-#define IMG_CUSTOM_178                                 1156
-#define IMG_CUSTOM_178_EDITOR                          1157
-#define IMG_CUSTOM_179                                 1158
-#define IMG_CUSTOM_179_EDITOR                          1159
-#define IMG_CUSTOM_180                                 1160
-#define IMG_CUSTOM_180_EDITOR                          1161
-#define IMG_CUSTOM_181                                 1162
-#define IMG_CUSTOM_181_EDITOR                          1163
-#define IMG_CUSTOM_182                                 1164
-#define IMG_CUSTOM_182_EDITOR                          1165
-#define IMG_CUSTOM_183                                 1166
-#define IMG_CUSTOM_183_EDITOR                          1167
-#define IMG_CUSTOM_184                                 1168
-#define IMG_CUSTOM_184_EDITOR                          1169
-#define IMG_CUSTOM_185                                 1170
-#define IMG_CUSTOM_185_EDITOR                          1171
-#define IMG_CUSTOM_186                                 1172
-#define IMG_CUSTOM_186_EDITOR                          1173
-#define IMG_CUSTOM_187                                 1174
-#define IMG_CUSTOM_187_EDITOR                          1175
-#define IMG_CUSTOM_188                                 1176
-#define IMG_CUSTOM_188_EDITOR                          1177
-#define IMG_CUSTOM_189                                 1178
-#define IMG_CUSTOM_189_EDITOR                          1179
-#define IMG_CUSTOM_190                                 1180
-#define IMG_CUSTOM_190_EDITOR                          1181
-#define IMG_CUSTOM_191                                 1182
-#define IMG_CUSTOM_191_EDITOR                          1183
-#define IMG_CUSTOM_192                                 1184
-#define IMG_CUSTOM_192_EDITOR                          1185
-#define IMG_CUSTOM_193                                 1186
-#define IMG_CUSTOM_193_EDITOR                          1187
-#define IMG_CUSTOM_194                                 1188
-#define IMG_CUSTOM_194_EDITOR                          1189
-#define IMG_CUSTOM_195                                 1190
-#define IMG_CUSTOM_195_EDITOR                          1191
-#define IMG_CUSTOM_196                                 1192
-#define IMG_CUSTOM_196_EDITOR                          1193
-#define IMG_CUSTOM_197                                 1194
-#define IMG_CUSTOM_197_EDITOR                          1195
-#define IMG_CUSTOM_198                                 1196
-#define IMG_CUSTOM_198_EDITOR                          1197
-#define IMG_CUSTOM_199                                 1198
-#define IMG_CUSTOM_199_EDITOR                          1199
-#define IMG_CUSTOM_200                                 1200
-#define IMG_CUSTOM_200_EDITOR                          1201
-#define IMG_CUSTOM_201                                 1202
-#define IMG_CUSTOM_201_EDITOR                          1203
-#define IMG_CUSTOM_202                                 1204
-#define IMG_CUSTOM_202_EDITOR                          1205
-#define IMG_CUSTOM_203                                 1206
-#define IMG_CUSTOM_203_EDITOR                          1207
-#define IMG_CUSTOM_204                                 1208
-#define IMG_CUSTOM_204_EDITOR                          1209
-#define IMG_CUSTOM_205                                 1210
-#define IMG_CUSTOM_205_EDITOR                          1211
-#define IMG_CUSTOM_206                                 1212
-#define IMG_CUSTOM_206_EDITOR                          1213
-#define IMG_CUSTOM_207                                 1214
-#define IMG_CUSTOM_207_EDITOR                          1215
-#define IMG_CUSTOM_208                                 1216
-#define IMG_CUSTOM_208_EDITOR                          1217
-#define IMG_CUSTOM_209                                 1218
-#define IMG_CUSTOM_209_EDITOR                          1219
-#define IMG_CUSTOM_210                                 1220
-#define IMG_CUSTOM_210_EDITOR                          1221
-#define IMG_CUSTOM_211                                 1222
-#define IMG_CUSTOM_211_EDITOR                          1223
-#define IMG_CUSTOM_212                                 1224
-#define IMG_CUSTOM_212_EDITOR                          1225
-#define IMG_CUSTOM_213                                 1226
-#define IMG_CUSTOM_213_EDITOR                          1227
-#define IMG_CUSTOM_214                                 1228
-#define IMG_CUSTOM_214_EDITOR                          1229
-#define IMG_CUSTOM_215                                 1230
-#define IMG_CUSTOM_215_EDITOR                          1231
-#define IMG_CUSTOM_216                                 1232
-#define IMG_CUSTOM_216_EDITOR                          1233
-#define IMG_CUSTOM_217                                 1234
-#define IMG_CUSTOM_217_EDITOR                          1235
-#define IMG_CUSTOM_218                                 1236
-#define IMG_CUSTOM_218_EDITOR                          1237
-#define IMG_CUSTOM_219                                 1238
-#define IMG_CUSTOM_219_EDITOR                          1239
-#define IMG_CUSTOM_220                                 1240
-#define IMG_CUSTOM_220_EDITOR                          1241
-#define IMG_CUSTOM_221                                 1242
-#define IMG_CUSTOM_221_EDITOR                          1243
-#define IMG_CUSTOM_222                                 1244
-#define IMG_CUSTOM_222_EDITOR                          1245
-#define IMG_CUSTOM_223                                 1246
-#define IMG_CUSTOM_223_EDITOR                          1247
-#define IMG_CUSTOM_224                                 1248
-#define IMG_CUSTOM_224_EDITOR                          1249
-#define IMG_CUSTOM_225                                 1250
-#define IMG_CUSTOM_225_EDITOR                          1251
-#define IMG_CUSTOM_226                                 1252
-#define IMG_CUSTOM_226_EDITOR                          1253
-#define IMG_CUSTOM_227                                 1254
-#define IMG_CUSTOM_227_EDITOR                          1255
-#define IMG_CUSTOM_228                                 1256
-#define IMG_CUSTOM_228_EDITOR                          1257
-#define IMG_CUSTOM_229                                 1258
-#define IMG_CUSTOM_229_EDITOR                          1259
-#define IMG_CUSTOM_230                                 1260
-#define IMG_CUSTOM_230_EDITOR                          1261
-#define IMG_CUSTOM_231                                 1262
-#define IMG_CUSTOM_231_EDITOR                          1263
-#define IMG_CUSTOM_232                                 1264
-#define IMG_CUSTOM_232_EDITOR                          1265
-#define IMG_CUSTOM_233                                 1266
-#define IMG_CUSTOM_233_EDITOR                          1267
-#define IMG_CUSTOM_234                                 1268
-#define IMG_CUSTOM_234_EDITOR                          1269
-#define IMG_CUSTOM_235                                 1270
-#define IMG_CUSTOM_235_EDITOR                          1271
-#define IMG_CUSTOM_236                                 1272
-#define IMG_CUSTOM_236_EDITOR                          1273
-#define IMG_CUSTOM_237                                 1274
-#define IMG_CUSTOM_237_EDITOR                          1275
-#define IMG_CUSTOM_238                                 1276
-#define IMG_CUSTOM_238_EDITOR                          1277
-#define IMG_CUSTOM_239                                 1278
-#define IMG_CUSTOM_239_EDITOR                          1279
-#define IMG_CUSTOM_240                                 1280
-#define IMG_CUSTOM_240_EDITOR                          1281
-#define IMG_CUSTOM_241                                 1282
-#define IMG_CUSTOM_241_EDITOR                          1283
-#define IMG_CUSTOM_242                                 1284
-#define IMG_CUSTOM_242_EDITOR                          1285
-#define IMG_CUSTOM_243                                 1286
-#define IMG_CUSTOM_243_EDITOR                          1287
-#define IMG_CUSTOM_244                                 1288
-#define IMG_CUSTOM_244_EDITOR                          1289
-#define IMG_CUSTOM_245                                 1290
-#define IMG_CUSTOM_245_EDITOR                          1291
-#define IMG_CUSTOM_246                                 1292
-#define IMG_CUSTOM_246_EDITOR                          1293
-#define IMG_CUSTOM_247                                 1294
-#define IMG_CUSTOM_247_EDITOR                          1295
-#define IMG_CUSTOM_248                                 1296
-#define IMG_CUSTOM_248_EDITOR                          1297
-#define IMG_CUSTOM_249                                 1298
-#define IMG_CUSTOM_249_EDITOR                          1299
-#define IMG_CUSTOM_250                                 1300
-#define IMG_CUSTOM_250_EDITOR                          1301
-#define IMG_CUSTOM_251                                 1302
-#define IMG_CUSTOM_251_EDITOR                          1303
-#define IMG_CUSTOM_252                                 1304
-#define IMG_CUSTOM_252_EDITOR                          1305
-#define IMG_CUSTOM_253                                 1306
-#define IMG_CUSTOM_253_EDITOR                          1307
-#define IMG_CUSTOM_254                                 1308
-#define IMG_CUSTOM_254_EDITOR                          1309
-#define IMG_CUSTOM_255                                 1310
-#define IMG_CUSTOM_255_EDITOR                          1311
-#define IMG_CUSTOM_256                                 1312
-#define IMG_CUSTOM_256_EDITOR                          1313
-#define IMG_GROUP_1                                    1314
-#define IMG_GROUP_1_EDITOR                             1315
-#define IMG_GROUP_2                                    1316
-#define IMG_GROUP_2_EDITOR                             1317
-#define IMG_GROUP_3                                    1318
-#define IMG_GROUP_3_EDITOR                             1319
-#define IMG_GROUP_4                                    1320
-#define IMG_GROUP_4_EDITOR                             1321
-#define IMG_GROUP_5                                    1322
-#define IMG_GROUP_5_EDITOR                             1323
-#define IMG_GROUP_6                                    1324
-#define IMG_GROUP_6_EDITOR                             1325
-#define IMG_GROUP_7                                    1326
-#define IMG_GROUP_7_EDITOR                             1327
-#define IMG_GROUP_8                                    1328
-#define IMG_GROUP_8_EDITOR                             1329
-#define IMG_GROUP_9                                    1330
-#define IMG_GROUP_9_EDITOR                             1331
-#define IMG_GROUP_10                                   1332
-#define IMG_GROUP_10_EDITOR                            1333
-#define IMG_GROUP_11                                   1334
-#define IMG_GROUP_11_EDITOR                            1335
-#define IMG_GROUP_12                                   1336
-#define IMG_GROUP_12_EDITOR                            1337
-#define IMG_GROUP_13                                   1338
-#define IMG_GROUP_13_EDITOR                            1339
-#define IMG_GROUP_14                                   1340
-#define IMG_GROUP_14_EDITOR                            1341
-#define IMG_GROUP_15                                   1342
-#define IMG_GROUP_15_EDITOR                            1343
-#define IMG_GROUP_16                                   1344
-#define IMG_GROUP_16_EDITOR                            1345
-#define IMG_GROUP_17                                   1346
-#define IMG_GROUP_17_EDITOR                            1347
-#define IMG_GROUP_18                                   1348
-#define IMG_GROUP_18_EDITOR                            1349
-#define IMG_GROUP_19                                   1350
-#define IMG_GROUP_19_EDITOR                            1351
-#define IMG_GROUP_20                                   1352
-#define IMG_GROUP_20_EDITOR                            1353
-#define IMG_GROUP_21                                   1354
-#define IMG_GROUP_21_EDITOR                            1355
-#define IMG_GROUP_22                                   1356
-#define IMG_GROUP_22_EDITOR                            1357
-#define IMG_GROUP_23                                   1358
-#define IMG_GROUP_23_EDITOR                            1359
-#define IMG_GROUP_24                                   1360
-#define IMG_GROUP_24_EDITOR                            1361
-#define IMG_GROUP_25                                   1362
-#define IMG_GROUP_25_EDITOR                            1363
-#define IMG_GROUP_26                                   1364
-#define IMG_GROUP_26_EDITOR                            1365
-#define IMG_GROUP_27                                   1366
-#define IMG_GROUP_27_EDITOR                            1367
-#define IMG_GROUP_28                                   1368
-#define IMG_GROUP_28_EDITOR                            1369
-#define IMG_GROUP_29                                   1370
-#define IMG_GROUP_29_EDITOR                            1371
-#define IMG_GROUP_30                                   1372
-#define IMG_GROUP_30_EDITOR                            1373
-#define IMG_GROUP_31                                   1374
-#define IMG_GROUP_31_EDITOR                            1375
-#define IMG_GROUP_32                                   1376
-#define IMG_GROUP_32_EDITOR                            1377
-#define IMG_EMC_OBJECT                                 1378
-#define IMG_EMC_SPRITE                                 1379
-#define IMG_TOON_1                                     1380
-#define IMG_TOON_2                                     1381
-#define IMG_TOON_3                                     1382
-#define IMG_TOON_4                                     1383
-#define IMG_TOON_5                                     1384
-#define IMG_TOON_6                                     1385
-#define IMG_TOON_7                                     1386
-#define IMG_TOON_8                                     1387
-#define IMG_TOON_9                                     1388
-#define IMG_TOON_10                                    1389
-#define IMG_TOON_11                                    1390
-#define IMG_TOON_12                                    1391
-#define IMG_TOON_13                                    1392
-#define IMG_TOON_14                                    1393
-#define IMG_TOON_15                                    1394
-#define IMG_TOON_16                                    1395
-#define IMG_TOON_17                                    1396
-#define IMG_TOON_18                                    1397
-#define IMG_TOON_19                                    1398
-#define IMG_TOON_20                                    1399
-#define IMG_MENU_CALIBRATE_RED                         1400
-#define IMG_MENU_CALIBRATE_BLUE                                1401
-#define IMG_MENU_CALIBRATE_YELLOW                      1402
-#define IMG_MENU_BUTTON                                        1403
-#define IMG_MENU_BUTTON_ACTIVE                         1404
-#define IMG_MENU_BUTTON_LEFT                           1405
-#define IMG_MENU_BUTTON_RIGHT                          1406
-#define IMG_MENU_BUTTON_UP                             1407
-#define IMG_MENU_BUTTON_DOWN                           1408
-#define IMG_MENU_BUTTON_LEFT_ACTIVE                    1409
-#define IMG_MENU_BUTTON_RIGHT_ACTIVE                   1410
-#define IMG_MENU_BUTTON_UP_ACTIVE                      1411
-#define IMG_MENU_BUTTON_DOWN_ACTIVE                    1412
-#define IMG_MENU_SCROLLBAR                             1413
-#define IMG_MENU_SCROLLBAR_ACTIVE                      1414
-#define IMG_FONT_INITIAL_1                             1415
-#define IMG_FONT_INITIAL_2                             1416
-#define IMG_FONT_INITIAL_3                             1417
-#define IMG_FONT_INITIAL_4                             1418
-#define IMG_FONT_TITLE_1                               1419
-#define IMG_FONT_TITLE_1_LEVELS                                1420
-#define IMG_FONT_TITLE_2                               1421
-#define IMG_FONT_MENU_1                                        1422
-#define IMG_FONT_MENU_2                                        1423
-#define IMG_FONT_TEXT_1                                        1424
-#define IMG_FONT_TEXT_1_LEVELS                         1425
-#define IMG_FONT_TEXT_1_PREVIEW                                1426
-#define IMG_FONT_TEXT_1_SCORES                         1427
-#define IMG_FONT_TEXT_1_ACTIVE_SCORES                  1428
-#define IMG_FONT_TEXT_2                                        1429
-#define IMG_FONT_TEXT_2_LEVELS                         1430
-#define IMG_FONT_TEXT_2_PREVIEW                                1431
-#define IMG_FONT_TEXT_2_SCORES                         1432
-#define IMG_FONT_TEXT_2_ACTIVE_SCORES                  1433
-#define IMG_FONT_TEXT_3                                        1434
-#define IMG_FONT_TEXT_3_LEVELS                         1435
-#define IMG_FONT_TEXT_3_PREVIEW                                1436
-#define IMG_FONT_TEXT_3_SCORES                         1437
-#define IMG_FONT_TEXT_3_ACTIVE_SCORES                  1438
-#define IMG_FONT_TEXT_4                                        1439
-#define IMG_FONT_TEXT_4_LEVELS                         1440
-#define IMG_FONT_TEXT_4_SCORES                         1441
-#define IMG_FONT_TEXT_4_ACTIVE_SCORES                  1442
-#define IMG_FONT_ENVELOPE_1                            1443
-#define IMG_FONT_ENVELOPE_2                            1444
-#define IMG_FONT_ENVELOPE_3                            1445
-#define IMG_FONT_ENVELOPE_4                            1446
-#define IMG_FONT_INPUT_1                               1447
-#define IMG_FONT_INPUT_1_MAIN                          1448
-#define IMG_FONT_INPUT_1_ACTIVE                                1449
-#define IMG_FONT_INPUT_1_ACTIVE_MAIN                   1450
-#define IMG_FONT_INPUT_1_ACTIVE_SETUP                  1451
-#define IMG_FONT_INPUT_2                               1452
-#define IMG_FONT_INPUT_2_ACTIVE                                1453
-#define IMG_FONT_OPTION_OFF                            1454
-#define IMG_FONT_OPTION_ON                             1455
-#define IMG_FONT_VALUE_1                               1456
-#define IMG_FONT_VALUE_2                               1457
-#define IMG_FONT_VALUE_OLD                             1458
-#define IMG_FONT_LEVEL_NUMBER                          1459
-#define IMG_FONT_TAPE_RECORDER                         1460
-#define IMG_FONT_GAME_INFO                             1461
-#define IMG_GLOBAL_BORDER                              1462
-#define IMG_GLOBAL_DOOR                                        1463
-#define IMG_EDITOR_ELEMENT_BORDER                      1464
-#define IMG_EDITOR_ELEMENT_BORDER_INPUT                        1465
-#define IMG_BACKGROUND_ENVELOPE_1                      1466
-#define IMG_BACKGROUND_ENVELOPE_2                      1467
-#define IMG_BACKGROUND_ENVELOPE_3                      1468
-#define IMG_BACKGROUND_ENVELOPE_4                      1469
-#define IMG_BACKGROUND                                 1470
-#define IMG_BACKGROUND_MAIN                            1471
-#define IMG_BACKGROUND_LEVELS                          1472
-#define IMG_BACKGROUND_SCORES                          1473
-#define IMG_BACKGROUND_EDITOR                          1474
-#define IMG_BACKGROUND_INFO                            1475
-#define IMG_BACKGROUND_INFO_ELEMENTS                   1476
-#define IMG_BACKGROUND_SETUP                           1477
-#define IMG_BACKGROUND_DOOR                            1478
+#define IMG_SP_BASE_DIGGING                            44
+#define IMG_SP_BASE_SNAPPING                           45
+#define IMG_SP_MURPHY                                  46
+#define IMG_SP_MURPHY_MOVING_LEFT                      47
+#define IMG_SP_MURPHY_MOVING_RIGHT                     48
+#define IMG_SP_MURPHY_DIGGING_LEFT                     49
+#define IMG_SP_MURPHY_DIGGING_RIGHT                    50
+#define IMG_SP_MURPHY_COLLECTING_LEFT                  51
+#define IMG_SP_MURPHY_COLLECTING_RIGHT                 52
+#define IMG_SP_MURPHY_PUSHING_LEFT                     53
+#define IMG_SP_MURPHY_PUSHING_RIGHT                    54
+#define IMG_SP_MURPHY_SNAPPING_LEFT                    55
+#define IMG_SP_MURPHY_SNAPPING_RIGHT                   56
+#define IMG_SP_MURPHY_SNAPPING_UP                      57
+#define IMG_SP_MURPHY_SNAPPING_DOWN                    58
+#define IMG_SP_MURPHY_BORING                           59
+#define IMG_SP_MURPHY_BORING_1                         60
+#define IMG_SP_MURPHY_SLEEPING_LEFT                    61
+#define IMG_SP_MURPHY_SLEEPING_RIGHT                   62
+#define IMG_SP_MURPHY_CLONE                            63
+#define IMG_SP_INFOTRON                                        64
+#define IMG_SP_INFOTRON_EDITOR                         65
+#define IMG_SP_INFOTRON_COLLECTING                     66
+#define IMG_SP_CHIP_SINGLE                             67
+#define IMG_SP_CHIP_LEFT                               68
+#define IMG_SP_CHIP_RIGHT                              69
+#define IMG_SP_CHIP_TOP                                        70
+#define IMG_SP_CHIP_BOTTOM                             71
+#define IMG_SP_HARDWARE_GRAY                           72
+#define IMG_SP_HARDWARE_GREEN                          73
+#define IMG_SP_HARDWARE_BLUE                           74
+#define IMG_SP_HARDWARE_RED                            75
+#define IMG_SP_HARDWARE_YELLOW                         76
+#define IMG_SP_EXIT_CLOSED                             77
+#define IMG_SP_EXIT_OPENING                            78
+#define IMG_SP_EXIT_OPEN                               79
+#define IMG_SP_EXIT_CLOSING                            80
+#define IMG_SP_DISK_ORANGE                             81
+#define IMG_SP_DISK_YELLOW                             82
+#define IMG_SP_DISK_RED                                        83
+#define IMG_SP_DISK_RED_COLLECTING                     84
+#define IMG_SP_DISK_RED_ACTIVE                         85
+#define IMG_SP_PORT_RIGHT                              86
+#define IMG_SP_PORT_DOWN                               87
+#define IMG_SP_PORT_LEFT                               88
+#define IMG_SP_PORT_UP                                 89
+#define IMG_SP_PORT_HORIZONTAL                         90
+#define IMG_SP_PORT_VERTICAL                           91
+#define IMG_SP_PORT_ANY                                        92
+#define IMG_SP_GRAVITY_PORT_RIGHT                      93
+#define IMG_SP_GRAVITY_PORT_RIGHT_EDITOR               94
+#define IMG_SP_GRAVITY_PORT_DOWN                       95
+#define IMG_SP_GRAVITY_PORT_DOWN_EDITOR                        96
+#define IMG_SP_GRAVITY_PORT_LEFT                       97
+#define IMG_SP_GRAVITY_PORT_LEFT_EDITOR                        98
+#define IMG_SP_GRAVITY_PORT_UP                         99
+#define IMG_SP_GRAVITY_PORT_UP_EDITOR                  100
+#define IMG_SP_GRAVITY_ON_PORT_RIGHT                   101
+#define IMG_SP_GRAVITY_ON_PORT_RIGHT_EDITOR            102
+#define IMG_SP_GRAVITY_ON_PORT_DOWN                    103
+#define IMG_SP_GRAVITY_ON_PORT_DOWN_EDITOR             104
+#define IMG_SP_GRAVITY_ON_PORT_LEFT                    105
+#define IMG_SP_GRAVITY_ON_PORT_LEFT_EDITOR             106
+#define IMG_SP_GRAVITY_ON_PORT_UP                      107
+#define IMG_SP_GRAVITY_ON_PORT_UP_EDITOR               108
+#define IMG_SP_GRAVITY_OFF_PORT_RIGHT                  109
+#define IMG_SP_GRAVITY_OFF_PORT_RIGHT_EDITOR           110
+#define IMG_SP_GRAVITY_OFF_PORT_DOWN                   111
+#define IMG_SP_GRAVITY_OFF_PORT_DOWN_EDITOR            112
+#define IMG_SP_GRAVITY_OFF_PORT_LEFT                   113
+#define IMG_SP_GRAVITY_OFF_PORT_LEFT_EDITOR            114
+#define IMG_SP_GRAVITY_OFF_PORT_UP                     115
+#define IMG_SP_GRAVITY_OFF_PORT_UP_EDITOR              116
+#define IMG_SP_SNIKSNAK                                        117
+#define IMG_SP_SNIKSNAK_LEFT                           118
+#define IMG_SP_SNIKSNAK_RIGHT                          119
+#define IMG_SP_SNIKSNAK_UP                             120
+#define IMG_SP_SNIKSNAK_DOWN                           121
+#define IMG_SP_SNIKSNAK_TURNING_FROM_LEFT_UP           122
+#define IMG_SP_SNIKSNAK_TURNING_FROM_LEFT_DOWN         123
+#define IMG_SP_SNIKSNAK_TURNING_FROM_RIGHT_UP          124
+#define IMG_SP_SNIKSNAK_TURNING_FROM_RIGHT_DOWN                125
+#define IMG_SP_SNIKSNAK_TURNING_FROM_UP_LEFT           126
+#define IMG_SP_SNIKSNAK_TURNING_FROM_UP_RIGHT          127
+#define IMG_SP_SNIKSNAK_TURNING_FROM_DOWN_LEFT         128
+#define IMG_SP_SNIKSNAK_TURNING_FROM_DOWN_RIGHT                129
+#define IMG_SP_ELECTRON                                        130
+#define IMG_SP_ELECTRON_EDITOR                         131
+#define IMG_SP_ELECTRON_EXPLODING                      132
+#define IMG_SP_TERMINAL                                        133
+#define IMG_SP_TERMINAL_EDITOR                         134
+#define IMG_SP_TERMINAL_ACTIVE                         135
+#define IMG_SP_BUGGY_BASE                              136
+#define IMG_SP_BUGGY_BASE_EDITOR                       137
+#define IMG_SP_BUGGY_BASE_ACTIVATING                   138
+#define IMG_SP_BUGGY_BASE_ACTIVE                       139
+#define IMG_SP_HARDWARE_BASE_1                         140
+#define IMG_SP_HARDWARE_BASE_2                         141
+#define IMG_SP_HARDWARE_BASE_3                         142
+#define IMG_SP_HARDWARE_BASE_4                         143
+#define IMG_SP_HARDWARE_BASE_5                         144
+#define IMG_SP_HARDWARE_BASE_6                         145
+#define IMG_SOKOBAN_OBJECT                             146
+#define IMG_SOKOBAN_OBJECT_EDITOR                      147
+#define IMG_SOKOBAN_FIELD_EMPTY                                148
+#define IMG_SOKOBAN_FIELD_FULL                         149
+#define IMG_SOKOBAN_FIELD_PLAYER                       150
+#define IMG_SOKOBAN_FIELD_PLAYER_EDITOR                        151
+#define IMG_EMPTY_SPACE                                        152
+#define IMG_SAND                                       153
+#define IMG_SAND_CRUMBLED                              154
+#define IMG_SAND_DIGGING_LEFT                          155
+#define IMG_SAND_DIGGING_RIGHT                         156
+#define IMG_SAND_DIGGING_UP                            157
+#define IMG_SAND_DIGGING_DOWN                          158
+#define IMG_SAND_DIGGING_LEFT_CRUMBLED                 159
+#define IMG_SAND_DIGGING_RIGHT_CRUMBLED                        160
+#define IMG_SAND_DIGGING_UP_CRUMBLED                   161
+#define IMG_SAND_DIGGING_DOWN_CRUMBLED                 162
+#define IMG_WALL                                       163
+#define IMG_WALL_SLIPPERY                              164
+#define IMG_STEELWALL                                  165
+#define IMG_ROCK                                       166
+#define IMG_ROCK_MOVING_LEFT                           167
+#define IMG_ROCK_MOVING_RIGHT                          168
+#define IMG_ROCK_PUSHING_LEFT                          169
+#define IMG_ROCK_PUSHING_RIGHT                         170
+#define IMG_EMERALD                                    171
+#define IMG_EMERALD_MOVING                             172
+#define IMG_EMERALD_FALLING                            173
+#define IMG_EMERALD_COLLECTING                         174
+#define IMG_DIAMOND                                    175
+#define IMG_DIAMOND_MOVING                             176
+#define IMG_DIAMOND_FALLING                            177
+#define IMG_DIAMOND_COLLECTING                         178
+#define IMG_BOMB                                       179
+#define IMG_NUT                                                180
+#define IMG_NUT_BREAKING                               181
+#define IMG_DYNAMITE                                   182
+#define IMG_DYNAMITE_EDITOR                            183
+#define IMG_DYNAMITE_ACTIVE                            184
+#define IMG_DYNAMITE_ACTIVE_EDITOR                     185
+#define IMG_EM_DYNAMITE                                        186
+#define IMG_EM_DYNAMITE_ACTIVE                         187
+#define IMG_EM_DYNAMITE_ACTIVE_EDITOR                  188
+#define IMG_WALL_EMERALD                               189
+#define IMG_WALL_DIAMOND                               190
+#define IMG_BUG                                                191
+#define IMG_BUG_RIGHT                                  192
+#define IMG_BUG_UP                                     193
+#define IMG_BUG_LEFT                                   194
+#define IMG_BUG_DOWN                                   195
+#define IMG_BUG_MOVING_RIGHT                           196
+#define IMG_BUG_MOVING_UP                              197
+#define IMG_BUG_MOVING_LEFT                            198
+#define IMG_BUG_MOVING_DOWN                            199
+#define IMG_BUG_TURNING_FROM_RIGHT_UP                  200
+#define IMG_BUG_TURNING_FROM_UP_LEFT                   201
+#define IMG_BUG_TURNING_FROM_LEFT_DOWN                 202
+#define IMG_BUG_TURNING_FROM_DOWN_RIGHT                        203
+#define IMG_BUG_TURNING_FROM_RIGHT_DOWN                        204
+#define IMG_BUG_TURNING_FROM_UP_RIGHT                  205
+#define IMG_BUG_TURNING_FROM_LEFT_UP                   206
+#define IMG_BUG_TURNING_FROM_DOWN_LEFT                 207
+#define IMG_SPACESHIP                                  208
+#define IMG_SPACESHIP_RIGHT                            209
+#define IMG_SPACESHIP_UP                               210
+#define IMG_SPACESHIP_LEFT                             211
+#define IMG_SPACESHIP_DOWN                             212
+#define IMG_SPACESHIP_MOVING_RIGHT                     213
+#define IMG_SPACESHIP_MOVING_UP                                214
+#define IMG_SPACESHIP_MOVING_LEFT                      215
+#define IMG_SPACESHIP_MOVING_DOWN                      216
+#define IMG_SPACESHIP_TURNING_FROM_RIGHT_UP            217
+#define IMG_SPACESHIP_TURNING_FROM_UP_LEFT             218
+#define IMG_SPACESHIP_TURNING_FROM_LEFT_DOWN           219
+#define IMG_SPACESHIP_TURNING_FROM_DOWN_RIGHT          220
+#define IMG_SPACESHIP_TURNING_FROM_RIGHT_DOWN          221
+#define IMG_SPACESHIP_TURNING_FROM_UP_RIGHT            222
+#define IMG_SPACESHIP_TURNING_FROM_LEFT_UP             223
+#define IMG_SPACESHIP_TURNING_FROM_DOWN_LEFT           224
+#define IMG_YAMYAM                                     225
+#define IMG_YAMYAM_LEFT                                        226
+#define IMG_YAMYAM_LEFT_EDITOR                         227
+#define IMG_YAMYAM_RIGHT                               228
+#define IMG_YAMYAM_RIGHT_EDITOR                                229
+#define IMG_YAMYAM_UP                                  230
+#define IMG_YAMYAM_UP_EDITOR                           231
+#define IMG_YAMYAM_DOWN                                        232
+#define IMG_YAMYAM_DOWN_EDITOR                         233
+#define IMG_YAMYAM_MOVING                              234
+#define IMG_ROBOT                                      235
+#define IMG_ROBOT_MOVING                               236
+#define IMG_ROBOT_WHEEL                                        237
+#define IMG_ROBOT_WHEEL_ACTIVE                         238
+#define IMG_MAGIC_WALL                                 239
+#define IMG_MAGIC_WALL_ACTIVE                          240
+#define IMG_MAGIC_WALL_FILLING                         241
+#define IMG_MAGIC_WALL_FULL                            242
+#define IMG_MAGIC_WALL_EMPTYING                                243
+#define IMG_MAGIC_WALL_DEAD                            244
+#define IMG_QUICKSAND_EMPTY                            245
+#define IMG_QUICKSAND_FILLING                          246
+#define IMG_QUICKSAND_FULL                             247
+#define IMG_QUICKSAND_FULL_EDITOR                      248
+#define IMG_QUICKSAND_EMPTYING                         249
+#define IMG_ACID_POOL_TOPLEFT                          250
+#define IMG_ACID_POOL_TOPRIGHT                         251
+#define IMG_ACID_POOL_BOTTOMLEFT                       252
+#define IMG_ACID_POOL_BOTTOM                           253
+#define IMG_ACID_POOL_BOTTOMRIGHT                      254
+#define IMG_ACID                                       255
+#define IMG_ACID_SPLASH_LEFT                           256
+#define IMG_ACID_SPLASH_RIGHT                          257
+#define IMG_AMOEBA_DROP                                        258
+#define IMG_AMOEBA_GROWING                             259
+#define IMG_AMOEBA_SHRINKING                           260
+#define IMG_AMOEBA_WET                                 261
+#define IMG_AMOEBA_WET_EDITOR                          262
+#define IMG_AMOEBA_DROPPING                            263
+#define IMG_AMOEBA_DRY                                 264
+#define IMG_AMOEBA_FULL                                        265
+#define IMG_AMOEBA_FULL_EDITOR                         266
+#define IMG_AMOEBA_DEAD                                        267
+#define IMG_AMOEBA_DEAD_EDITOR                         268
+#define IMG_EM_KEY_1                                   269
+#define IMG_EM_KEY_2                                   270
+#define IMG_EM_KEY_3                                   271
+#define IMG_EM_KEY_4                                   272
+#define IMG_EM_GATE_1                                  273
+#define IMG_EM_GATE_2                                  274
+#define IMG_EM_GATE_3                                  275
+#define IMG_EM_GATE_4                                  276
+#define IMG_EM_GATE_1_GRAY                             277
+#define IMG_EM_GATE_1_GRAY_EDITOR                      278
+#define IMG_EM_GATE_1_GRAY_ACTIVE                      279
+#define IMG_EM_GATE_2_GRAY                             280
+#define IMG_EM_GATE_2_GRAY_EDITOR                      281
+#define IMG_EM_GATE_2_GRAY_ACTIVE                      282
+#define IMG_EM_GATE_3_GRAY                             283
+#define IMG_EM_GATE_3_GRAY_EDITOR                      284
+#define IMG_EM_GATE_3_GRAY_ACTIVE                      285
+#define IMG_EM_GATE_4_GRAY                             286
+#define IMG_EM_GATE_4_GRAY_EDITOR                      287
+#define IMG_EM_GATE_4_GRAY_ACTIVE                      288
+#define IMG_EXIT_CLOSED                                        289
+#define IMG_EXIT_OPENING                               290
+#define IMG_EXIT_OPEN                                  291
+#define IMG_EXIT_CLOSING                               292
+#define IMG_BALLOON                                    293
+#define IMG_BALLOON_MOVING                             294
+#define IMG_BALLOON_PUSHING                            295
+#define IMG_BALLOON_SWITCH_LEFT                                296
+#define IMG_BALLOON_SWITCH_RIGHT                       297
+#define IMG_BALLOON_SWITCH_UP                          298
+#define IMG_BALLOON_SWITCH_DOWN                                299
+#define IMG_BALLOON_SWITCH_ANY                         300
+#define IMG_BALLOON_SWITCH_NONE                                301
+#define IMG_SPRING                                     302
+#define IMG_EMC_STEELWALL_1                            303
+#define IMG_EMC_STEELWALL_2                            304
+#define IMG_EMC_STEELWALL_3                            305
+#define IMG_EMC_STEELWALL_4                            306
+#define IMG_EMC_WALL_1                                 307
+#define IMG_EMC_WALL_2                                 308
+#define IMG_EMC_WALL_3                                 309
+#define IMG_EMC_WALL_4                                 310
+#define IMG_EMC_WALL_5                                 311
+#define IMG_EMC_WALL_6                                 312
+#define IMG_EMC_WALL_7                                 313
+#define IMG_EMC_WALL_8                                 314
+#define IMG_INVISIBLE_STEELWALL                                315
+#define IMG_INVISIBLE_STEELWALL_EDITOR                 316
+#define IMG_INVISIBLE_STEELWALL_ACTIVE                 317
+#define IMG_INVISIBLE_WALL                             318
+#define IMG_INVISIBLE_WALL_EDITOR                      319
+#define IMG_INVISIBLE_WALL_ACTIVE                      320
+#define IMG_INVISIBLE_SAND                             321
+#define IMG_INVISIBLE_SAND_EDITOR                      322
+#define IMG_INVISIBLE_SAND_ACTIVE                      323
+#define IMG_INVISIBLE_SAND_ACTIVE_CRUMBLED             324
+#define IMG_INVISIBLE_SAND_ACTIVE_DIGGING_LEFT         325
+#define IMG_INVISIBLE_SAND_ACTIVE_DIGGING_RIGHT                326
+#define IMG_INVISIBLE_SAND_ACTIVE_DIGGING_UP           327
+#define IMG_INVISIBLE_SAND_ACTIVE_DIGGING_DOWN         328
+#define IMG_INVISIBLE_SAND_ACTIVE_DIGGING_LEFT_CRUMBLED        329
+#define IMG_INVISIBLE_SAND_ACTIVE_DIGGING_RIGHT_CRUMBLED       330
+#define IMG_INVISIBLE_SAND_ACTIVE_DIGGING_UP_CRUMBLED  331
+#define IMG_INVISIBLE_SAND_ACTIVE_DIGGING_DOWN_CRUMBLED        332
+#define IMG_CONVEYOR_BELT_1_MIDDLE                     333
+#define IMG_CONVEYOR_BELT_1_MIDDLE_ACTIVE              334
+#define IMG_CONVEYOR_BELT_1_LEFT                       335
+#define IMG_CONVEYOR_BELT_1_LEFT_ACTIVE                        336
+#define IMG_CONVEYOR_BELT_1_RIGHT                      337
+#define IMG_CONVEYOR_BELT_1_RIGHT_ACTIVE               338
+#define IMG_CONVEYOR_BELT_1_SWITCH_LEFT                        339
+#define IMG_CONVEYOR_BELT_1_SWITCH_MIDDLE              340
+#define IMG_CONVEYOR_BELT_1_SWITCH_RIGHT               341
+#define IMG_CONVEYOR_BELT_2_MIDDLE                     342
+#define IMG_CONVEYOR_BELT_2_MIDDLE_ACTIVE              343
+#define IMG_CONVEYOR_BELT_2_LEFT                       344
+#define IMG_CONVEYOR_BELT_2_LEFT_ACTIVE                        345
+#define IMG_CONVEYOR_BELT_2_RIGHT                      346
+#define IMG_CONVEYOR_BELT_2_RIGHT_ACTIVE               347
+#define IMG_CONVEYOR_BELT_2_SWITCH_LEFT                        348
+#define IMG_CONVEYOR_BELT_2_SWITCH_MIDDLE              349
+#define IMG_CONVEYOR_BELT_2_SWITCH_RIGHT               350
+#define IMG_CONVEYOR_BELT_3_MIDDLE                     351
+#define IMG_CONVEYOR_BELT_3_MIDDLE_ACTIVE              352
+#define IMG_CONVEYOR_BELT_3_LEFT                       353
+#define IMG_CONVEYOR_BELT_3_LEFT_ACTIVE                        354
+#define IMG_CONVEYOR_BELT_3_RIGHT                      355
+#define IMG_CONVEYOR_BELT_3_RIGHT_ACTIVE               356
+#define IMG_CONVEYOR_BELT_3_SWITCH_LEFT                        357
+#define IMG_CONVEYOR_BELT_3_SWITCH_MIDDLE              358
+#define IMG_CONVEYOR_BELT_3_SWITCH_RIGHT               359
+#define IMG_CONVEYOR_BELT_4_MIDDLE                     360
+#define IMG_CONVEYOR_BELT_4_MIDDLE_ACTIVE              361
+#define IMG_CONVEYOR_BELT_4_LEFT                       362
+#define IMG_CONVEYOR_BELT_4_LEFT_ACTIVE                        363
+#define IMG_CONVEYOR_BELT_4_RIGHT                      364
+#define IMG_CONVEYOR_BELT_4_RIGHT_ACTIVE               365
+#define IMG_CONVEYOR_BELT_4_SWITCH_LEFT                        366
+#define IMG_CONVEYOR_BELT_4_SWITCH_MIDDLE              367
+#define IMG_CONVEYOR_BELT_4_SWITCH_RIGHT               368
+#define IMG_SWITCHGATE_SWITCH_UP                       369
+#define IMG_SWITCHGATE_SWITCH_DOWN                     370
+#define IMG_LIGHT_SWITCH                               371
+#define IMG_LIGHT_SWITCH_ACTIVE                                372
+#define IMG_TIMEGATE_SWITCH                            373
+#define IMG_TIMEGATE_SWITCH_ACTIVE                     374
+#define IMG_ENVELOPE_1                                 375
+#define IMG_ENVELOPE_1_COLLECTING                      376
+#define IMG_ENVELOPE_2                                 377
+#define IMG_ENVELOPE_2_COLLECTING                      378
+#define IMG_ENVELOPE_3                                 379
+#define IMG_ENVELOPE_3_COLLECTING                      380
+#define IMG_ENVELOPE_4                                 381
+#define IMG_ENVELOPE_4_COLLECTING                      382
+#define IMG_SIGN_EXCLAMATION                           383
+#define IMG_SIGN_STOP                                  384
+#define IMG_LANDMINE                                   385
+#define IMG_STEELWALL_SLIPPERY                         386
+#define IMG_EXTRA_TIME                                 387
+#define IMG_SHIELD_NORMAL                              388
+#define IMG_SHIELD_NORMAL_ACTIVE                       389
+#define IMG_SHIELD_DEADLY                              390
+#define IMG_SHIELD_DEADLY_ACTIVE                       391
+#define IMG_SWITCHGATE_CLOSED                          392
+#define IMG_SWITCHGATE_OPENING                         393
+#define IMG_SWITCHGATE_OPEN                            394
+#define IMG_SWITCHGATE_CLOSING                         395
+#define IMG_TIMEGATE_CLOSED                            396
+#define IMG_TIMEGATE_OPENING                           397
+#define IMG_TIMEGATE_OPEN                              398
+#define IMG_TIMEGATE_CLOSING                           399
+#define IMG_PEARL                                      400
+#define IMG_PEARL_BREAKING                             401
+#define IMG_CRYSTAL                                    402
+#define IMG_WALL_PEARL                                 403
+#define IMG_WALL_CRYSTAL                               404
+#define IMG_TUBE_RIGHT_DOWN                            405
+#define IMG_TUBE_HORIZONTAL_DOWN                       406
+#define IMG_TUBE_LEFT_DOWN                             407
+#define IMG_TUBE_HORIZONTAL                            408
+#define IMG_TUBE_VERTICAL_RIGHT                                409
+#define IMG_TUBE_ANY                                   410
+#define IMG_TUBE_VERTICAL_LEFT                         411
+#define IMG_TUBE_VERTICAL                              412
+#define IMG_TUBE_RIGHT_UP                              413
+#define IMG_TUBE_HORIZONTAL_UP                         414
+#define IMG_TUBE_LEFT_UP                               415
+#define IMG_TRAP                                       416
+#define IMG_TRAP_ACTIVE                                        417
+#define IMG_DX_SUPABOMB                                        418
+#define IMG_KEY_1                                      419
+#define IMG_KEY_1_EDITOR                               420
+#define IMG_KEY_2                                      421
+#define IMG_KEY_2_EDITOR                               422
+#define IMG_KEY_3                                      423
+#define IMG_KEY_3_EDITOR                               424
+#define IMG_KEY_4                                      425
+#define IMG_KEY_4_EDITOR                               426
+#define IMG_GATE_1                                     427
+#define IMG_GATE_2                                     428
+#define IMG_GATE_3                                     429
+#define IMG_GATE_4                                     430
+#define IMG_GATE_1_GRAY                                        431
+#define IMG_GATE_1_GRAY_EDITOR                         432
+#define IMG_GATE_1_GRAY_ACTIVE                         433
+#define IMG_GATE_2_GRAY                                        434
+#define IMG_GATE_2_GRAY_EDITOR                         435
+#define IMG_GATE_2_GRAY_ACTIVE                         436
+#define IMG_GATE_3_GRAY                                        437
+#define IMG_GATE_3_GRAY_EDITOR                         438
+#define IMG_GATE_3_GRAY_ACTIVE                         439
+#define IMG_GATE_4_GRAY                                        440
+#define IMG_GATE_4_GRAY_EDITOR                         441
+#define IMG_GATE_4_GRAY_ACTIVE                         442
+#define IMG_GAME_OF_LIFE                               443
+#define IMG_BIOMAZE                                    444
+#define IMG_PACMAN                                     445
+#define IMG_PACMAN_RIGHT                               446
+#define IMG_PACMAN_UP                                  447
+#define IMG_PACMAN_LEFT                                        448
+#define IMG_PACMAN_DOWN                                        449
+#define IMG_PACMAN_TURNING_FROM_RIGHT                  450
+#define IMG_PACMAN_TURNING_FROM_UP                     451
+#define IMG_PACMAN_TURNING_FROM_LEFT                   452
+#define IMG_PACMAN_TURNING_FROM_DOWN                   453
+#define IMG_LAMP                                       454
+#define IMG_LAMP_EDITOR                                        455
+#define IMG_LAMP_ACTIVE                                        456
+#define IMG_TIME_ORB_FULL                              457
+#define IMG_TIME_ORB_EMPTY                             458
+#define IMG_EMERALD_YELLOW                             459
+#define IMG_EMERALD_YELLOW_MOVING                      460
+#define IMG_EMERALD_YELLOW_FALLING                     461
+#define IMG_EMERALD_RED                                        462
+#define IMG_EMERALD_RED_MOVING                         463
+#define IMG_EMERALD_RED_FALLING                                464
+#define IMG_EMERALD_PURPLE                             465
+#define IMG_EMERALD_PURPLE_MOVING                      466
+#define IMG_EMERALD_PURPLE_FALLING                     467
+#define IMG_WALL_EMERALD_YELLOW                                468
+#define IMG_WALL_EMERALD_RED                           469
+#define IMG_WALL_EMERALD_PURPLE                                470
+#define IMG_WALL_BD_DIAMOND                            471
+#define IMG_EXPANDABLE_WALL                            472
+#define IMG_EXPANDABLE_WALL_HORIZONTAL                 473
+#define IMG_EXPANDABLE_WALL_HORIZONTAL_EDITOR          474
+#define IMG_EXPANDABLE_WALL_VERTICAL                   475
+#define IMG_EXPANDABLE_WALL_VERTICAL_EDITOR            476
+#define IMG_EXPANDABLE_WALL_ANY                                477
+#define IMG_EXPANDABLE_WALL_ANY_EDITOR                 478
+#define IMG_BD_EXPANDABLE_WALL                         479
+#define IMG_BD_EXPANDABLE_WALL_EDITOR                  480
+#define IMG_EXPANDABLE_WALL_GROWING_LEFT               481
+#define IMG_EXPANDABLE_WALL_GROWING_RIGHT              482
+#define IMG_EXPANDABLE_WALL_GROWING_UP                 483
+#define IMG_EXPANDABLE_WALL_GROWING_DOWN               484
+#define IMG_BLACK_ORB                                  485
+#define IMG_SPEED_PILL                                 486
+#define IMG_DARK_YAMYAM                                        487
+#define IMG_DYNABOMB                                   488
+#define IMG_DYNABOMB_ACTIVE                            489
+#define IMG_DYNABOMB_PLAYER_1                          490
+#define IMG_DYNABOMB_PLAYER_1_ACTIVE                   491
+#define IMG_DYNABOMB_PLAYER_2                          492
+#define IMG_DYNABOMB_PLAYER_2_ACTIVE                   493
+#define IMG_DYNABOMB_PLAYER_3                          494
+#define IMG_DYNABOMB_PLAYER_3_ACTIVE                   495
+#define IMG_DYNABOMB_PLAYER_4                          496
+#define IMG_DYNABOMB_PLAYER_4_ACTIVE                   497
+#define IMG_DYNABOMB_INCREASE_NUMBER                   498
+#define IMG_DYNABOMB_INCREASE_SIZE                     499
+#define IMG_DYNABOMB_INCREASE_POWER                    500
+#define IMG_PIG                                                501
+#define IMG_PIG_DOWN                                   502
+#define IMG_PIG_UP                                     503
+#define IMG_PIG_LEFT                                   504
+#define IMG_PIG_RIGHT                                  505
+#define IMG_PIG_MOVING_DOWN                            506
+#define IMG_PIG_MOVING_UP                              507
+#define IMG_PIG_MOVING_LEFT                            508
+#define IMG_PIG_MOVING_RIGHT                           509
+#define IMG_PIG_DIGGING_DOWN                           510
+#define IMG_PIG_DIGGING_UP                             511
+#define IMG_PIG_DIGGING_LEFT                           512
+#define IMG_PIG_DIGGING_RIGHT                          513
+#define IMG_DRAGON                                     514
+#define IMG_DRAGON_DOWN                                        515
+#define IMG_DRAGON_UP                                  516
+#define IMG_DRAGON_LEFT                                        517
+#define IMG_DRAGON_RIGHT                               518
+#define IMG_DRAGON_MOVING_DOWN                         519
+#define IMG_DRAGON_MOVING_UP                           520
+#define IMG_DRAGON_MOVING_LEFT                         521
+#define IMG_DRAGON_MOVING_RIGHT                                522
+#define IMG_DRAGON_ATTACKING_DOWN                      523
+#define IMG_DRAGON_ATTACKING_UP                                524
+#define IMG_DRAGON_ATTACKING_LEFT                      525
+#define IMG_DRAGON_ATTACKING_RIGHT                     526
+#define IMG_MOLE                                       527
+#define IMG_MOLE_DOWN                                  528
+#define IMG_MOLE_UP                                    529
+#define IMG_MOLE_LEFT                                  530
+#define IMG_MOLE_RIGHT                                 531
+#define IMG_MOLE_MOVING_DOWN                           532
+#define IMG_MOLE_MOVING_UP                             533
+#define IMG_MOLE_MOVING_LEFT                           534
+#define IMG_MOLE_MOVING_RIGHT                          535
+#define IMG_MOLE_DIGGING_DOWN                          536
+#define IMG_MOLE_DIGGING_UP                            537
+#define IMG_MOLE_DIGGING_LEFT                          538
+#define IMG_MOLE_DIGGING_RIGHT                         539
+#define IMG_PENGUIN                                    540
+#define IMG_PENGUIN_EDITOR                             541
+#define IMG_PENGUIN_DOWN                               542
+#define IMG_PENGUIN_UP                                 543
+#define IMG_PENGUIN_LEFT                               544
+#define IMG_PENGUIN_RIGHT                              545
+#define IMG_PENGUIN_MOVING_DOWN                                546
+#define IMG_PENGUIN_MOVING_UP                          547
+#define IMG_PENGUIN_MOVING_LEFT                                548
+#define IMG_PENGUIN_MOVING_RIGHT                       549
+#define IMG_SATELLITE                                  550
+#define IMG_FLAMES_1_LEFT                              551
+#define IMG_FLAMES_2_LEFT                              552
+#define IMG_FLAMES_3_LEFT                              553
+#define IMG_FLAMES_1_RIGHT                             554
+#define IMG_FLAMES_2_RIGHT                             555
+#define IMG_FLAMES_3_RIGHT                             556
+#define IMG_FLAMES_1_UP                                        557
+#define IMG_FLAMES_2_UP                                        558
+#define IMG_FLAMES_3_UP                                        559
+#define IMG_FLAMES_1_DOWN                              560
+#define IMG_FLAMES_2_DOWN                              561
+#define IMG_FLAMES_3_DOWN                              562
+#define IMG_STONEBLOCK                                 563
+#define IMG_PLAYER_1                                   564
+#define IMG_PLAYER_1_EDITOR                            565
+#define IMG_PLAYER_1_DOWN                              566
+#define IMG_PLAYER_1_UP                                        567
+#define IMG_PLAYER_1_LEFT                              568
+#define IMG_PLAYER_1_RIGHT                             569
+#define IMG_PLAYER_1_MOVING_DOWN                       570
+#define IMG_PLAYER_1_MOVING_UP                         571
+#define IMG_PLAYER_1_MOVING_LEFT                       572
+#define IMG_PLAYER_1_MOVING_RIGHT                      573
+#define IMG_PLAYER_1_DIGGING_DOWN                      574
+#define IMG_PLAYER_1_DIGGING_UP                                575
+#define IMG_PLAYER_1_DIGGING_LEFT                      576
+#define IMG_PLAYER_1_DIGGING_RIGHT                     577
+#define IMG_PLAYER_1_COLLECTING_DOWN                   578
+#define IMG_PLAYER_1_COLLECTING_UP                     579
+#define IMG_PLAYER_1_COLLECTING_LEFT                   580
+#define IMG_PLAYER_1_COLLECTING_RIGHT                  581
+#define IMG_PLAYER_1_PUSHING_DOWN                      582
+#define IMG_PLAYER_1_PUSHING_UP                                583
+#define IMG_PLAYER_1_PUSHING_LEFT                      584
+#define IMG_PLAYER_1_PUSHING_RIGHT                     585
+#define IMG_PLAYER_1_SNAPPING_DOWN                     586
+#define IMG_PLAYER_1_SNAPPING_UP                       587
+#define IMG_PLAYER_1_SNAPPING_LEFT                     588
+#define IMG_PLAYER_1_SNAPPING_RIGHT                    589
+#define IMG_PLAYER_2                                   590
+#define IMG_PLAYER_2_EDITOR                            591
+#define IMG_PLAYER_2_DOWN                              592
+#define IMG_PLAYER_2_UP                                        593
+#define IMG_PLAYER_2_LEFT                              594
+#define IMG_PLAYER_2_RIGHT                             595
+#define IMG_PLAYER_2_MOVING_DOWN                       596
+#define IMG_PLAYER_2_MOVING_UP                         597
+#define IMG_PLAYER_2_MOVING_LEFT                       598
+#define IMG_PLAYER_2_MOVING_RIGHT                      599
+#define IMG_PLAYER_2_DIGGING_DOWN                      600
+#define IMG_PLAYER_2_DIGGING_UP                                601
+#define IMG_PLAYER_2_DIGGING_LEFT                      602
+#define IMG_PLAYER_2_DIGGING_RIGHT                     603
+#define IMG_PLAYER_2_COLLECTING_DOWN                   604
+#define IMG_PLAYER_2_COLLECTING_UP                     605
+#define IMG_PLAYER_2_COLLECTING_LEFT                   606
+#define IMG_PLAYER_2_COLLECTING_RIGHT                  607
+#define IMG_PLAYER_2_PUSHING_DOWN                      608
+#define IMG_PLAYER_2_PUSHING_UP                                609
+#define IMG_PLAYER_2_PUSHING_LEFT                      610
+#define IMG_PLAYER_2_PUSHING_RIGHT                     611
+#define IMG_PLAYER_2_SNAPPING_DOWN                     612
+#define IMG_PLAYER_2_SNAPPING_UP                       613
+#define IMG_PLAYER_2_SNAPPING_LEFT                     614
+#define IMG_PLAYER_2_SNAPPING_RIGHT                    615
+#define IMG_PLAYER_3                                   616
+#define IMG_PLAYER_3_EDITOR                            617
+#define IMG_PLAYER_3_DOWN                              618
+#define IMG_PLAYER_3_UP                                        619
+#define IMG_PLAYER_3_LEFT                              620
+#define IMG_PLAYER_3_RIGHT                             621
+#define IMG_PLAYER_3_MOVING_DOWN                       622
+#define IMG_PLAYER_3_MOVING_UP                         623
+#define IMG_PLAYER_3_MOVING_LEFT                       624
+#define IMG_PLAYER_3_MOVING_RIGHT                      625
+#define IMG_PLAYER_3_DIGGING_DOWN                      626
+#define IMG_PLAYER_3_DIGGING_UP                                627
+#define IMG_PLAYER_3_DIGGING_LEFT                      628
+#define IMG_PLAYER_3_DIGGING_RIGHT                     629
+#define IMG_PLAYER_3_COLLECTING_DOWN                   630
+#define IMG_PLAYER_3_COLLECTING_UP                     631
+#define IMG_PLAYER_3_COLLECTING_LEFT                   632
+#define IMG_PLAYER_3_COLLECTING_RIGHT                  633
+#define IMG_PLAYER_3_PUSHING_DOWN                      634
+#define IMG_PLAYER_3_PUSHING_UP                                635
+#define IMG_PLAYER_3_PUSHING_LEFT                      636
+#define IMG_PLAYER_3_PUSHING_RIGHT                     637
+#define IMG_PLAYER_3_SNAPPING_DOWN                     638
+#define IMG_PLAYER_3_SNAPPING_UP                       639
+#define IMG_PLAYER_3_SNAPPING_LEFT                     640
+#define IMG_PLAYER_3_SNAPPING_RIGHT                    641
+#define IMG_PLAYER_4                                   642
+#define IMG_PLAYER_4_EDITOR                            643
+#define IMG_PLAYER_4_DOWN                              644
+#define IMG_PLAYER_4_UP                                        645
+#define IMG_PLAYER_4_LEFT                              646
+#define IMG_PLAYER_4_RIGHT                             647
+#define IMG_PLAYER_4_MOVING_DOWN                       648
+#define IMG_PLAYER_4_MOVING_UP                         649
+#define IMG_PLAYER_4_MOVING_LEFT                       650
+#define IMG_PLAYER_4_MOVING_RIGHT                      651
+#define IMG_PLAYER_4_DIGGING_DOWN                      652
+#define IMG_PLAYER_4_DIGGING_UP                                653
+#define IMG_PLAYER_4_DIGGING_LEFT                      654
+#define IMG_PLAYER_4_DIGGING_RIGHT                     655
+#define IMG_PLAYER_4_COLLECTING_DOWN                   656
+#define IMG_PLAYER_4_COLLECTING_UP                     657
+#define IMG_PLAYER_4_COLLECTING_LEFT                   658
+#define IMG_PLAYER_4_COLLECTING_RIGHT                  659
+#define IMG_PLAYER_4_PUSHING_DOWN                      660
+#define IMG_PLAYER_4_PUSHING_UP                                661
+#define IMG_PLAYER_4_PUSHING_LEFT                      662
+#define IMG_PLAYER_4_PUSHING_RIGHT                     663
+#define IMG_PLAYER_4_SNAPPING_DOWN                     664
+#define IMG_PLAYER_4_SNAPPING_UP                       665
+#define IMG_PLAYER_4_SNAPPING_LEFT                     666
+#define IMG_PLAYER_4_SNAPPING_RIGHT                    667
+#define IMG_DEFAULT_EXPLODING                          668
+#define IMG_TWINKLE_BLUE                               669
+#define IMG_TWINKLE_WHITE                              670
+#define IMG_STEELWALL_TOPLEFT                          671
+#define IMG_STEELWALL_TOPRIGHT                         672
+#define IMG_STEELWALL_BOTTOMLEFT                       673
+#define IMG_STEELWALL_BOTTOMRIGHT                      674
+#define IMG_STEELWALL_HORIZONTAL                       675
+#define IMG_STEELWALL_VERTICAL                         676
+#define IMG_STEELWALL_TOPLEFT_EDITOR                   677
+#define IMG_STEELWALL_TOPRIGHT_EDITOR                  678
+#define IMG_STEELWALL_BOTTOMLEFT_EDITOR                        679
+#define IMG_STEELWALL_BOTTOMRIGHT_EDITOR               680
+#define IMG_STEELWALL_HORIZONTAL_EDITOR                        681
+#define IMG_STEELWALL_VERTICAL_EDITOR                  682
+#define IMG_INVISIBLE_STEELWALL_TOPLEFT                        683
+#define IMG_INVISIBLE_STEELWALL_TOPRIGHT               684
+#define IMG_INVISIBLE_STEELWALL_BOTTOMLEFT             685
+#define IMG_INVISIBLE_STEELWALL_BOTTOMRIGHT            686
+#define IMG_INVISIBLE_STEELWALL_HORIZONTAL             687
+#define IMG_INVISIBLE_STEELWALL_VERTICAL               688
+#define IMG_INVISIBLE_STEELWALL_TOPLEFT_EDITOR         689
+#define IMG_INVISIBLE_STEELWALL_TOPRIGHT_EDITOR                690
+#define IMG_INVISIBLE_STEELWALL_BOTTOMLEFT_EDITOR      691
+#define IMG_INVISIBLE_STEELWALL_BOTTOMRIGHT_EDITOR     692
+#define IMG_INVISIBLE_STEELWALL_HORIZONTAL_EDITOR      693
+#define IMG_INVISIBLE_STEELWALL_VERTICAL_EDITOR                694
+#define IMG_ARROW_LEFT                                 695
+#define IMG_ARROW_RIGHT                                        696
+#define IMG_ARROW_UP                                   697
+#define IMG_ARROW_DOWN                                 698
+#define IMG_UNKNOWN                                    699
+#define IMG_TRIGGER_ELEMENT                            700
+#define IMG_TRIGGER_PLAYER                             701
+#define IMG_TRIGGER_CE_VALUE                           702
+#define IMG_TRIGGER_CE_SCORE                           703
+#define IMG_CURRENT_CE_VALUE                           704
+#define IMG_CURRENT_CE_SCORE                           705
+#define IMG_EMC_KEY_5                                  706
+#define IMG_EMC_KEY_6                                  707
+#define IMG_EMC_KEY_7                                  708
+#define IMG_EMC_KEY_8                                  709
+#define IMG_EMC_GATE_5                                 710
+#define IMG_EMC_GATE_6                                 711
+#define IMG_EMC_GATE_7                                 712
+#define IMG_EMC_GATE_8                                 713
+#define IMG_EMC_GATE_5_GRAY                            714
+#define IMG_EMC_GATE_5_GRAY_EDITOR                     715
+#define IMG_EMC_GATE_5_GRAY_ACTIVE                     716
+#define IMG_EMC_GATE_6_GRAY                            717
+#define IMG_EMC_GATE_6_GRAY_EDITOR                     718
+#define IMG_EMC_GATE_6_GRAY_ACTIVE                     719
+#define IMG_EMC_GATE_7_GRAY                            720
+#define IMG_EMC_GATE_7_GRAY_EDITOR                     721
+#define IMG_EMC_GATE_7_GRAY_ACTIVE                     722
+#define IMG_EMC_GATE_8_GRAY                            723
+#define IMG_EMC_GATE_8_GRAY_EDITOR                     724
+#define IMG_EMC_GATE_8_GRAY_ACTIVE                     725
+#define IMG_EMC_ANDROID                                        726
+#define IMG_EMC_ANDROID_SHRINKING_UPLEFT               727
+#define IMG_EMC_ANDROID_GROWING_DOWNRIGHT              728
+#define IMG_EMC_ANDROID_SHRINKING_DOWNLEFT             729
+#define IMG_EMC_ANDROID_GROWING_UPRIGHT                        730
+#define IMG_EMC_ANDROID_SHRINKING_UPRIGHT              731
+#define IMG_EMC_ANDROID_GROWING_DOWNLEFT               732
+#define IMG_EMC_ANDROID_SHRINKING_DOWNRIGHT            733
+#define IMG_EMC_ANDROID_GROWING_UPLEFT                 734
+#define IMG_EMC_GRASS                                  735
+#define IMG_EMC_GRASS_CRUMBLED                         736
+#define IMG_EMC_GRASS_DIGGING_LEFT                     737
+#define IMG_EMC_GRASS_DIGGING_RIGHT                    738
+#define IMG_EMC_GRASS_DIGGING_UP                       739
+#define IMG_EMC_GRASS_DIGGING_DOWN                     740
+#define IMG_EMC_GRASS_DIGGING_LEFT_CRUMBLED            741
+#define IMG_EMC_GRASS_DIGGING_RIGHT_CRUMBLED           742
+#define IMG_EMC_GRASS_DIGGING_UP_CRUMBLED              743
+#define IMG_EMC_GRASS_DIGGING_DOWN_CRUMBLED            744
+#define IMG_EMC_MAGIC_BALL                             745
+#define IMG_EMC_MAGIC_BALL_ACTIVE                      746
+#define IMG_EMC_MAGIC_BALL_DROPPING                    747
+#define IMG_EMC_MAGIC_BALL_SWITCH                      748
+#define IMG_EMC_MAGIC_BALL_SWITCH_ACTIVE               749
+#define IMG_EMC_SPRING_BUMPER                          750
+#define IMG_EMC_SPRING_BUMPER_ACTIVE                   751
+#define IMG_EMC_PLANT                                  752
+#define IMG_EMC_PLANT_CRUMBLED                         753
+#define IMG_EMC_LENSES                                 754
+#define IMG_EMC_MAGNIFIER                              755
+#define IMG_EMC_WALL_9                                 756
+#define IMG_EMC_WALL_10                                        757
+#define IMG_EMC_WALL_11                                        758
+#define IMG_EMC_WALL_12                                        759
+#define IMG_EMC_WALL_13                                        760
+#define IMG_EMC_WALL_14                                        761
+#define IMG_EMC_WALL_15                                        762
+#define IMG_EMC_WALL_16                                        763
+#define IMG_EMC_WALL_SLIPPERY_1                                764
+#define IMG_EMC_WALL_SLIPPERY_2                                765
+#define IMG_EMC_WALL_SLIPPERY_3                                766
+#define IMG_EMC_WALL_SLIPPERY_4                                767
+#define IMG_EMC_FAKE_GRASS                             768
+#define IMG_EMC_FAKE_GRASS_CRUMBLED                    769
+#define IMG_EMC_FAKE_GRASS_ACTIVE                      770
+#define IMG_EMC_FAKE_GRASS_ACTIVE_CRUMBLED             771
+#define IMG_EMC_FAKE_GRASS_EDITOR                      772
+#define IMG_EMC_FAKE_ACID                              773
+#define IMG_EMC_DRIPPER                                        774
+#define IMG_EMC_DRIPPER_EDITOR                         775
+#define IMG_EMC_DRIPPER_ACTIVE                         776
+#define IMG_CHAR_SPACE                                 777
+#define IMG_CHAR_EXCLAM                                        778
+#define IMG_CHAR_QUOTEDBL                              779
+#define IMG_CHAR_NUMBERSIGN                            780
+#define IMG_CHAR_DOLLAR                                        781
+#define IMG_CHAR_PERCENT                               782
+#define IMG_CHAR_AMPERSAND                             783
+#define IMG_CHAR_APOSTROPHE                            784
+#define IMG_CHAR_PARENLEFT                             785
+#define IMG_CHAR_PARENRIGHT                            786
+#define IMG_CHAR_ASTERISK                              787
+#define IMG_CHAR_PLUS                                  788
+#define IMG_CHAR_COMMA                                 789
+#define IMG_CHAR_MINUS                                 790
+#define IMG_CHAR_PERIOD                                        791
+#define IMG_CHAR_SLASH                                 792
+#define IMG_CHAR_0                                     793
+#define IMG_CHAR_1                                     794
+#define IMG_CHAR_2                                     795
+#define IMG_CHAR_3                                     796
+#define IMG_CHAR_4                                     797
+#define IMG_CHAR_5                                     798
+#define IMG_CHAR_6                                     799
+#define IMG_CHAR_7                                     800
+#define IMG_CHAR_8                                     801
+#define IMG_CHAR_9                                     802
+#define IMG_CHAR_COLON                                 803
+#define IMG_CHAR_SEMICOLON                             804
+#define IMG_CHAR_LESS                                  805
+#define IMG_CHAR_EQUAL                                 806
+#define IMG_CHAR_GREATER                               807
+#define IMG_CHAR_QUESTION                              808
+#define IMG_CHAR_AT                                    809
+#define IMG_CHAR_A                                     810
+#define IMG_CHAR_B                                     811
+#define IMG_CHAR_C                                     812
+#define IMG_CHAR_D                                     813
+#define IMG_CHAR_E                                     814
+#define IMG_CHAR_F                                     815
+#define IMG_CHAR_G                                     816
+#define IMG_CHAR_H                                     817
+#define IMG_CHAR_I                                     818
+#define IMG_CHAR_J                                     819
+#define IMG_CHAR_K                                     820
+#define IMG_CHAR_L                                     821
+#define IMG_CHAR_M                                     822
+#define IMG_CHAR_N                                     823
+#define IMG_CHAR_O                                     824
+#define IMG_CHAR_P                                     825
+#define IMG_CHAR_Q                                     826
+#define IMG_CHAR_R                                     827
+#define IMG_CHAR_S                                     828
+#define IMG_CHAR_T                                     829
+#define IMG_CHAR_U                                     830
+#define IMG_CHAR_V                                     831
+#define IMG_CHAR_W                                     832
+#define IMG_CHAR_X                                     833
+#define IMG_CHAR_Y                                     834
+#define IMG_CHAR_Z                                     835
+#define IMG_CHAR_BRACKETLEFT                           836
+#define IMG_CHAR_BACKSLASH                             837
+#define IMG_CHAR_BRACKETRIGHT                          838
+#define IMG_CHAR_ASCIICIRCUM                           839
+#define IMG_CHAR_UNDERSCORE                            840
+#define IMG_CHAR_COPYRIGHT                             841
+#define IMG_CHAR_AUMLAUT                               842
+#define IMG_CHAR_OUMLAUT                               843
+#define IMG_CHAR_UUMLAUT                               844
+#define IMG_CHAR_DEGREE                                        845
+#define IMG_CHAR_TRADEMARK                             846
+#define IMG_CHAR_CURSOR                                        847
+#define IMG_CUSTOM_1                                   848
+#define IMG_CUSTOM_1_EDITOR                            849
+#define IMG_CUSTOM_2                                   850
+#define IMG_CUSTOM_2_EDITOR                            851
+#define IMG_CUSTOM_3                                   852
+#define IMG_CUSTOM_3_EDITOR                            853
+#define IMG_CUSTOM_4                                   854
+#define IMG_CUSTOM_4_EDITOR                            855
+#define IMG_CUSTOM_5                                   856
+#define IMG_CUSTOM_5_EDITOR                            857
+#define IMG_CUSTOM_6                                   858
+#define IMG_CUSTOM_6_EDITOR                            859
+#define IMG_CUSTOM_7                                   860
+#define IMG_CUSTOM_7_EDITOR                            861
+#define IMG_CUSTOM_8                                   862
+#define IMG_CUSTOM_8_EDITOR                            863
+#define IMG_CUSTOM_9                                   864
+#define IMG_CUSTOM_9_EDITOR                            865
+#define IMG_CUSTOM_10                                  866
+#define IMG_CUSTOM_10_EDITOR                           867
+#define IMG_CUSTOM_11                                  868
+#define IMG_CUSTOM_11_EDITOR                           869
+#define IMG_CUSTOM_12                                  870
+#define IMG_CUSTOM_12_EDITOR                           871
+#define IMG_CUSTOM_13                                  872
+#define IMG_CUSTOM_13_EDITOR                           873
+#define IMG_CUSTOM_14                                  874
+#define IMG_CUSTOM_14_EDITOR                           875
+#define IMG_CUSTOM_15                                  876
+#define IMG_CUSTOM_15_EDITOR                           877
+#define IMG_CUSTOM_16                                  878
+#define IMG_CUSTOM_16_EDITOR                           879
+#define IMG_CUSTOM_17                                  880
+#define IMG_CUSTOM_17_EDITOR                           881
+#define IMG_CUSTOM_18                                  882
+#define IMG_CUSTOM_18_EDITOR                           883
+#define IMG_CUSTOM_19                                  884
+#define IMG_CUSTOM_19_EDITOR                           885
+#define IMG_CUSTOM_20                                  886
+#define IMG_CUSTOM_20_EDITOR                           887
+#define IMG_CUSTOM_21                                  888
+#define IMG_CUSTOM_21_EDITOR                           889
+#define IMG_CUSTOM_22                                  890
+#define IMG_CUSTOM_22_EDITOR                           891
+#define IMG_CUSTOM_23                                  892
+#define IMG_CUSTOM_23_EDITOR                           893
+#define IMG_CUSTOM_24                                  894
+#define IMG_CUSTOM_24_EDITOR                           895
+#define IMG_CUSTOM_25                                  896
+#define IMG_CUSTOM_25_EDITOR                           897
+#define IMG_CUSTOM_26                                  898
+#define IMG_CUSTOM_26_EDITOR                           899
+#define IMG_CUSTOM_27                                  900
+#define IMG_CUSTOM_27_EDITOR                           901
+#define IMG_CUSTOM_28                                  902
+#define IMG_CUSTOM_28_EDITOR                           903
+#define IMG_CUSTOM_29                                  904
+#define IMG_CUSTOM_29_EDITOR                           905
+#define IMG_CUSTOM_30                                  906
+#define IMG_CUSTOM_30_EDITOR                           907
+#define IMG_CUSTOM_31                                  908
+#define IMG_CUSTOM_31_EDITOR                           909
+#define IMG_CUSTOM_32                                  910
+#define IMG_CUSTOM_32_EDITOR                           911
+#define IMG_CUSTOM_33                                  912
+#define IMG_CUSTOM_33_EDITOR                           913
+#define IMG_CUSTOM_34                                  914
+#define IMG_CUSTOM_34_EDITOR                           915
+#define IMG_CUSTOM_35                                  916
+#define IMG_CUSTOM_35_EDITOR                           917
+#define IMG_CUSTOM_36                                  918
+#define IMG_CUSTOM_36_EDITOR                           919
+#define IMG_CUSTOM_37                                  920
+#define IMG_CUSTOM_37_EDITOR                           921
+#define IMG_CUSTOM_38                                  922
+#define IMG_CUSTOM_38_EDITOR                           923
+#define IMG_CUSTOM_39                                  924
+#define IMG_CUSTOM_39_EDITOR                           925
+#define IMG_CUSTOM_40                                  926
+#define IMG_CUSTOM_40_EDITOR                           927
+#define IMG_CUSTOM_41                                  928
+#define IMG_CUSTOM_41_EDITOR                           929
+#define IMG_CUSTOM_42                                  930
+#define IMG_CUSTOM_42_EDITOR                           931
+#define IMG_CUSTOM_43                                  932
+#define IMG_CUSTOM_43_EDITOR                           933
+#define IMG_CUSTOM_44                                  934
+#define IMG_CUSTOM_44_EDITOR                           935
+#define IMG_CUSTOM_45                                  936
+#define IMG_CUSTOM_45_EDITOR                           937
+#define IMG_CUSTOM_46                                  938
+#define IMG_CUSTOM_46_EDITOR                           939
+#define IMG_CUSTOM_47                                  940
+#define IMG_CUSTOM_47_EDITOR                           941
+#define IMG_CUSTOM_48                                  942
+#define IMG_CUSTOM_48_EDITOR                           943
+#define IMG_CUSTOM_49                                  944
+#define IMG_CUSTOM_49_EDITOR                           945
+#define IMG_CUSTOM_50                                  946
+#define IMG_CUSTOM_50_EDITOR                           947
+#define IMG_CUSTOM_51                                  948
+#define IMG_CUSTOM_51_EDITOR                           949
+#define IMG_CUSTOM_52                                  950
+#define IMG_CUSTOM_52_EDITOR                           951
+#define IMG_CUSTOM_53                                  952
+#define IMG_CUSTOM_53_EDITOR                           953
+#define IMG_CUSTOM_54                                  954
+#define IMG_CUSTOM_54_EDITOR                           955
+#define IMG_CUSTOM_55                                  956
+#define IMG_CUSTOM_55_EDITOR                           957
+#define IMG_CUSTOM_56                                  958
+#define IMG_CUSTOM_56_EDITOR                           959
+#define IMG_CUSTOM_57                                  960
+#define IMG_CUSTOM_57_EDITOR                           961
+#define IMG_CUSTOM_58                                  962
+#define IMG_CUSTOM_58_EDITOR                           963
+#define IMG_CUSTOM_59                                  964
+#define IMG_CUSTOM_59_EDITOR                           965
+#define IMG_CUSTOM_60                                  966
+#define IMG_CUSTOM_60_EDITOR                           967
+#define IMG_CUSTOM_61                                  968
+#define IMG_CUSTOM_61_EDITOR                           969
+#define IMG_CUSTOM_62                                  970
+#define IMG_CUSTOM_62_EDITOR                           971
+#define IMG_CUSTOM_63                                  972
+#define IMG_CUSTOM_63_EDITOR                           973
+#define IMG_CUSTOM_64                                  974
+#define IMG_CUSTOM_64_EDITOR                           975
+#define IMG_CUSTOM_65                                  976
+#define IMG_CUSTOM_65_EDITOR                           977
+#define IMG_CUSTOM_66                                  978
+#define IMG_CUSTOM_66_EDITOR                           979
+#define IMG_CUSTOM_67                                  980
+#define IMG_CUSTOM_67_EDITOR                           981
+#define IMG_CUSTOM_68                                  982
+#define IMG_CUSTOM_68_EDITOR                           983
+#define IMG_CUSTOM_69                                  984
+#define IMG_CUSTOM_69_EDITOR                           985
+#define IMG_CUSTOM_70                                  986
+#define IMG_CUSTOM_70_EDITOR                           987
+#define IMG_CUSTOM_71                                  988
+#define IMG_CUSTOM_71_EDITOR                           989
+#define IMG_CUSTOM_72                                  990
+#define IMG_CUSTOM_72_EDITOR                           991
+#define IMG_CUSTOM_73                                  992
+#define IMG_CUSTOM_73_EDITOR                           993
+#define IMG_CUSTOM_74                                  994
+#define IMG_CUSTOM_74_EDITOR                           995
+#define IMG_CUSTOM_75                                  996
+#define IMG_CUSTOM_75_EDITOR                           997
+#define IMG_CUSTOM_76                                  998
+#define IMG_CUSTOM_76_EDITOR                           999
+#define IMG_CUSTOM_77                                  1000
+#define IMG_CUSTOM_77_EDITOR                           1001
+#define IMG_CUSTOM_78                                  1002
+#define IMG_CUSTOM_78_EDITOR                           1003
+#define IMG_CUSTOM_79                                  1004
+#define IMG_CUSTOM_79_EDITOR                           1005
+#define IMG_CUSTOM_80                                  1006
+#define IMG_CUSTOM_80_EDITOR                           1007
+#define IMG_CUSTOM_81                                  1008
+#define IMG_CUSTOM_81_EDITOR                           1009
+#define IMG_CUSTOM_82                                  1010
+#define IMG_CUSTOM_82_EDITOR                           1011
+#define IMG_CUSTOM_83                                  1012
+#define IMG_CUSTOM_83_EDITOR                           1013
+#define IMG_CUSTOM_84                                  1014
+#define IMG_CUSTOM_84_EDITOR                           1015
+#define IMG_CUSTOM_85                                  1016
+#define IMG_CUSTOM_85_EDITOR                           1017
+#define IMG_CUSTOM_86                                  1018
+#define IMG_CUSTOM_86_EDITOR                           1019
+#define IMG_CUSTOM_87                                  1020
+#define IMG_CUSTOM_87_EDITOR                           1021
+#define IMG_CUSTOM_88                                  1022
+#define IMG_CUSTOM_88_EDITOR                           1023
+#define IMG_CUSTOM_89                                  1024
+#define IMG_CUSTOM_89_EDITOR                           1025
+#define IMG_CUSTOM_90                                  1026
+#define IMG_CUSTOM_90_EDITOR                           1027
+#define IMG_CUSTOM_91                                  1028
+#define IMG_CUSTOM_91_EDITOR                           1029
+#define IMG_CUSTOM_92                                  1030
+#define IMG_CUSTOM_92_EDITOR                           1031
+#define IMG_CUSTOM_93                                  1032
+#define IMG_CUSTOM_93_EDITOR                           1033
+#define IMG_CUSTOM_94                                  1034
+#define IMG_CUSTOM_94_EDITOR                           1035
+#define IMG_CUSTOM_95                                  1036
+#define IMG_CUSTOM_95_EDITOR                           1037
+#define IMG_CUSTOM_96                                  1038
+#define IMG_CUSTOM_96_EDITOR                           1039
+#define IMG_CUSTOM_97                                  1040
+#define IMG_CUSTOM_97_EDITOR                           1041
+#define IMG_CUSTOM_98                                  1042
+#define IMG_CUSTOM_98_EDITOR                           1043
+#define IMG_CUSTOM_99                                  1044
+#define IMG_CUSTOM_99_EDITOR                           1045
+#define IMG_CUSTOM_100                                 1046
+#define IMG_CUSTOM_100_EDITOR                          1047
+#define IMG_CUSTOM_101                                 1048
+#define IMG_CUSTOM_101_EDITOR                          1049
+#define IMG_CUSTOM_102                                 1050
+#define IMG_CUSTOM_102_EDITOR                          1051
+#define IMG_CUSTOM_103                                 1052
+#define IMG_CUSTOM_103_EDITOR                          1053
+#define IMG_CUSTOM_104                                 1054
+#define IMG_CUSTOM_104_EDITOR                          1055
+#define IMG_CUSTOM_105                                 1056
+#define IMG_CUSTOM_105_EDITOR                          1057
+#define IMG_CUSTOM_106                                 1058
+#define IMG_CUSTOM_106_EDITOR                          1059
+#define IMG_CUSTOM_107                                 1060
+#define IMG_CUSTOM_107_EDITOR                          1061
+#define IMG_CUSTOM_108                                 1062
+#define IMG_CUSTOM_108_EDITOR                          1063
+#define IMG_CUSTOM_109                                 1064
+#define IMG_CUSTOM_109_EDITOR                          1065
+#define IMG_CUSTOM_110                                 1066
+#define IMG_CUSTOM_110_EDITOR                          1067
+#define IMG_CUSTOM_111                                 1068
+#define IMG_CUSTOM_111_EDITOR                          1069
+#define IMG_CUSTOM_112                                 1070
+#define IMG_CUSTOM_112_EDITOR                          1071
+#define IMG_CUSTOM_113                                 1072
+#define IMG_CUSTOM_113_EDITOR                          1073
+#define IMG_CUSTOM_114                                 1074
+#define IMG_CUSTOM_114_EDITOR                          1075
+#define IMG_CUSTOM_115                                 1076
+#define IMG_CUSTOM_115_EDITOR                          1077
+#define IMG_CUSTOM_116                                 1078
+#define IMG_CUSTOM_116_EDITOR                          1079
+#define IMG_CUSTOM_117                                 1080
+#define IMG_CUSTOM_117_EDITOR                          1081
+#define IMG_CUSTOM_118                                 1082
+#define IMG_CUSTOM_118_EDITOR                          1083
+#define IMG_CUSTOM_119                                 1084
+#define IMG_CUSTOM_119_EDITOR                          1085
+#define IMG_CUSTOM_120                                 1086
+#define IMG_CUSTOM_120_EDITOR                          1087
+#define IMG_CUSTOM_121                                 1088
+#define IMG_CUSTOM_121_EDITOR                          1089
+#define IMG_CUSTOM_122                                 1090
+#define IMG_CUSTOM_122_EDITOR                          1091
+#define IMG_CUSTOM_123                                 1092
+#define IMG_CUSTOM_123_EDITOR                          1093
+#define IMG_CUSTOM_124                                 1094
+#define IMG_CUSTOM_124_EDITOR                          1095
+#define IMG_CUSTOM_125                                 1096
+#define IMG_CUSTOM_125_EDITOR                          1097
+#define IMG_CUSTOM_126                                 1098
+#define IMG_CUSTOM_126_EDITOR                          1099
+#define IMG_CUSTOM_127                                 1100
+#define IMG_CUSTOM_127_EDITOR                          1101
+#define IMG_CUSTOM_128                                 1102
+#define IMG_CUSTOM_128_EDITOR                          1103
+#define IMG_CUSTOM_129                                 1104
+#define IMG_CUSTOM_129_EDITOR                          1105
+#define IMG_CUSTOM_130                                 1106
+#define IMG_CUSTOM_130_EDITOR                          1107
+#define IMG_CUSTOM_131                                 1108
+#define IMG_CUSTOM_131_EDITOR                          1109
+#define IMG_CUSTOM_132                                 1110
+#define IMG_CUSTOM_132_EDITOR                          1111
+#define IMG_CUSTOM_133                                 1112
+#define IMG_CUSTOM_133_EDITOR                          1113
+#define IMG_CUSTOM_134                                 1114
+#define IMG_CUSTOM_134_EDITOR                          1115
+#define IMG_CUSTOM_135                                 1116
+#define IMG_CUSTOM_135_EDITOR                          1117
+#define IMG_CUSTOM_136                                 1118
+#define IMG_CUSTOM_136_EDITOR                          1119
+#define IMG_CUSTOM_137                                 1120
+#define IMG_CUSTOM_137_EDITOR                          1121
+#define IMG_CUSTOM_138                                 1122
+#define IMG_CUSTOM_138_EDITOR                          1123
+#define IMG_CUSTOM_139                                 1124
+#define IMG_CUSTOM_139_EDITOR                          1125
+#define IMG_CUSTOM_140                                 1126
+#define IMG_CUSTOM_140_EDITOR                          1127
+#define IMG_CUSTOM_141                                 1128
+#define IMG_CUSTOM_141_EDITOR                          1129
+#define IMG_CUSTOM_142                                 1130
+#define IMG_CUSTOM_142_EDITOR                          1131
+#define IMG_CUSTOM_143                                 1132
+#define IMG_CUSTOM_143_EDITOR                          1133
+#define IMG_CUSTOM_144                                 1134
+#define IMG_CUSTOM_144_EDITOR                          1135
+#define IMG_CUSTOM_145                                 1136
+#define IMG_CUSTOM_145_EDITOR                          1137
+#define IMG_CUSTOM_146                                 1138
+#define IMG_CUSTOM_146_EDITOR                          1139
+#define IMG_CUSTOM_147                                 1140
+#define IMG_CUSTOM_147_EDITOR                          1141
+#define IMG_CUSTOM_148                                 1142
+#define IMG_CUSTOM_148_EDITOR                          1143
+#define IMG_CUSTOM_149                                 1144
+#define IMG_CUSTOM_149_EDITOR                          1145
+#define IMG_CUSTOM_150                                 1146
+#define IMG_CUSTOM_150_EDITOR                          1147
+#define IMG_CUSTOM_151                                 1148
+#define IMG_CUSTOM_151_EDITOR                          1149
+#define IMG_CUSTOM_152                                 1150
+#define IMG_CUSTOM_152_EDITOR                          1151
+#define IMG_CUSTOM_153                                 1152
+#define IMG_CUSTOM_153_EDITOR                          1153
+#define IMG_CUSTOM_154                                 1154
+#define IMG_CUSTOM_154_EDITOR                          1155
+#define IMG_CUSTOM_155                                 1156
+#define IMG_CUSTOM_155_EDITOR                          1157
+#define IMG_CUSTOM_156                                 1158
+#define IMG_CUSTOM_156_EDITOR                          1159
+#define IMG_CUSTOM_157                                 1160
+#define IMG_CUSTOM_157_EDITOR                          1161
+#define IMG_CUSTOM_158                                 1162
+#define IMG_CUSTOM_158_EDITOR                          1163
+#define IMG_CUSTOM_159                                 1164
+#define IMG_CUSTOM_159_EDITOR                          1165
+#define IMG_CUSTOM_160                                 1166
+#define IMG_CUSTOM_160_EDITOR                          1167
+#define IMG_CUSTOM_161                                 1168
+#define IMG_CUSTOM_161_EDITOR                          1169
+#define IMG_CUSTOM_162                                 1170
+#define IMG_CUSTOM_162_EDITOR                          1171
+#define IMG_CUSTOM_163                                 1172
+#define IMG_CUSTOM_163_EDITOR                          1173
+#define IMG_CUSTOM_164                                 1174
+#define IMG_CUSTOM_164_EDITOR                          1175
+#define IMG_CUSTOM_165                                 1176
+#define IMG_CUSTOM_165_EDITOR                          1177
+#define IMG_CUSTOM_166                                 1178
+#define IMG_CUSTOM_166_EDITOR                          1179
+#define IMG_CUSTOM_167                                 1180
+#define IMG_CUSTOM_167_EDITOR                          1181
+#define IMG_CUSTOM_168                                 1182
+#define IMG_CUSTOM_168_EDITOR                          1183
+#define IMG_CUSTOM_169                                 1184
+#define IMG_CUSTOM_169_EDITOR                          1185
+#define IMG_CUSTOM_170                                 1186
+#define IMG_CUSTOM_170_EDITOR                          1187
+#define IMG_CUSTOM_171                                 1188
+#define IMG_CUSTOM_171_EDITOR                          1189
+#define IMG_CUSTOM_172                                 1190
+#define IMG_CUSTOM_172_EDITOR                          1191
+#define IMG_CUSTOM_173                                 1192
+#define IMG_CUSTOM_173_EDITOR                          1193
+#define IMG_CUSTOM_174                                 1194
+#define IMG_CUSTOM_174_EDITOR                          1195
+#define IMG_CUSTOM_175                                 1196
+#define IMG_CUSTOM_175_EDITOR                          1197
+#define IMG_CUSTOM_176                                 1198
+#define IMG_CUSTOM_176_EDITOR                          1199
+#define IMG_CUSTOM_177                                 1200
+#define IMG_CUSTOM_177_EDITOR                          1201
+#define IMG_CUSTOM_178                                 1202
+#define IMG_CUSTOM_178_EDITOR                          1203
+#define IMG_CUSTOM_179                                 1204
+#define IMG_CUSTOM_179_EDITOR                          1205
+#define IMG_CUSTOM_180                                 1206
+#define IMG_CUSTOM_180_EDITOR                          1207
+#define IMG_CUSTOM_181                                 1208
+#define IMG_CUSTOM_181_EDITOR                          1209
+#define IMG_CUSTOM_182                                 1210
+#define IMG_CUSTOM_182_EDITOR                          1211
+#define IMG_CUSTOM_183                                 1212
+#define IMG_CUSTOM_183_EDITOR                          1213
+#define IMG_CUSTOM_184                                 1214
+#define IMG_CUSTOM_184_EDITOR                          1215
+#define IMG_CUSTOM_185                                 1216
+#define IMG_CUSTOM_185_EDITOR                          1217
+#define IMG_CUSTOM_186                                 1218
+#define IMG_CUSTOM_186_EDITOR                          1219
+#define IMG_CUSTOM_187                                 1220
+#define IMG_CUSTOM_187_EDITOR                          1221
+#define IMG_CUSTOM_188                                 1222
+#define IMG_CUSTOM_188_EDITOR                          1223
+#define IMG_CUSTOM_189                                 1224
+#define IMG_CUSTOM_189_EDITOR                          1225
+#define IMG_CUSTOM_190                                 1226
+#define IMG_CUSTOM_190_EDITOR                          1227
+#define IMG_CUSTOM_191                                 1228
+#define IMG_CUSTOM_191_EDITOR                          1229
+#define IMG_CUSTOM_192                                 1230
+#define IMG_CUSTOM_192_EDITOR                          1231
+#define IMG_CUSTOM_193                                 1232
+#define IMG_CUSTOM_193_EDITOR                          1233
+#define IMG_CUSTOM_194                                 1234
+#define IMG_CUSTOM_194_EDITOR                          1235
+#define IMG_CUSTOM_195                                 1236
+#define IMG_CUSTOM_195_EDITOR                          1237
+#define IMG_CUSTOM_196                                 1238
+#define IMG_CUSTOM_196_EDITOR                          1239
+#define IMG_CUSTOM_197                                 1240
+#define IMG_CUSTOM_197_EDITOR                          1241
+#define IMG_CUSTOM_198                                 1242
+#define IMG_CUSTOM_198_EDITOR                          1243
+#define IMG_CUSTOM_199                                 1244
+#define IMG_CUSTOM_199_EDITOR                          1245
+#define IMG_CUSTOM_200                                 1246
+#define IMG_CUSTOM_200_EDITOR                          1247
+#define IMG_CUSTOM_201                                 1248
+#define IMG_CUSTOM_201_EDITOR                          1249
+#define IMG_CUSTOM_202                                 1250
+#define IMG_CUSTOM_202_EDITOR                          1251
+#define IMG_CUSTOM_203                                 1252
+#define IMG_CUSTOM_203_EDITOR                          1253
+#define IMG_CUSTOM_204                                 1254
+#define IMG_CUSTOM_204_EDITOR                          1255
+#define IMG_CUSTOM_205                                 1256
+#define IMG_CUSTOM_205_EDITOR                          1257
+#define IMG_CUSTOM_206                                 1258
+#define IMG_CUSTOM_206_EDITOR                          1259
+#define IMG_CUSTOM_207                                 1260
+#define IMG_CUSTOM_207_EDITOR                          1261
+#define IMG_CUSTOM_208                                 1262
+#define IMG_CUSTOM_208_EDITOR                          1263
+#define IMG_CUSTOM_209                                 1264
+#define IMG_CUSTOM_209_EDITOR                          1265
+#define IMG_CUSTOM_210                                 1266
+#define IMG_CUSTOM_210_EDITOR                          1267
+#define IMG_CUSTOM_211                                 1268
+#define IMG_CUSTOM_211_EDITOR                          1269
+#define IMG_CUSTOM_212                                 1270
+#define IMG_CUSTOM_212_EDITOR                          1271
+#define IMG_CUSTOM_213                                 1272
+#define IMG_CUSTOM_213_EDITOR                          1273
+#define IMG_CUSTOM_214                                 1274
+#define IMG_CUSTOM_214_EDITOR                          1275
+#define IMG_CUSTOM_215                                 1276
+#define IMG_CUSTOM_215_EDITOR                          1277
+#define IMG_CUSTOM_216                                 1278
+#define IMG_CUSTOM_216_EDITOR                          1279
+#define IMG_CUSTOM_217                                 1280
+#define IMG_CUSTOM_217_EDITOR                          1281
+#define IMG_CUSTOM_218                                 1282
+#define IMG_CUSTOM_218_EDITOR                          1283
+#define IMG_CUSTOM_219                                 1284
+#define IMG_CUSTOM_219_EDITOR                          1285
+#define IMG_CUSTOM_220                                 1286
+#define IMG_CUSTOM_220_EDITOR                          1287
+#define IMG_CUSTOM_221                                 1288
+#define IMG_CUSTOM_221_EDITOR                          1289
+#define IMG_CUSTOM_222                                 1290
+#define IMG_CUSTOM_222_EDITOR                          1291
+#define IMG_CUSTOM_223                                 1292
+#define IMG_CUSTOM_223_EDITOR                          1293
+#define IMG_CUSTOM_224                                 1294
+#define IMG_CUSTOM_224_EDITOR                          1295
+#define IMG_CUSTOM_225                                 1296
+#define IMG_CUSTOM_225_EDITOR                          1297
+#define IMG_CUSTOM_226                                 1298
+#define IMG_CUSTOM_226_EDITOR                          1299
+#define IMG_CUSTOM_227                                 1300
+#define IMG_CUSTOM_227_EDITOR                          1301
+#define IMG_CUSTOM_228                                 1302
+#define IMG_CUSTOM_228_EDITOR                          1303
+#define IMG_CUSTOM_229                                 1304
+#define IMG_CUSTOM_229_EDITOR                          1305
+#define IMG_CUSTOM_230                                 1306
+#define IMG_CUSTOM_230_EDITOR                          1307
+#define IMG_CUSTOM_231                                 1308
+#define IMG_CUSTOM_231_EDITOR                          1309
+#define IMG_CUSTOM_232                                 1310
+#define IMG_CUSTOM_232_EDITOR                          1311
+#define IMG_CUSTOM_233                                 1312
+#define IMG_CUSTOM_233_EDITOR                          1313
+#define IMG_CUSTOM_234                                 1314
+#define IMG_CUSTOM_234_EDITOR                          1315
+#define IMG_CUSTOM_235                                 1316
+#define IMG_CUSTOM_235_EDITOR                          1317
+#define IMG_CUSTOM_236                                 1318
+#define IMG_CUSTOM_236_EDITOR                          1319
+#define IMG_CUSTOM_237                                 1320
+#define IMG_CUSTOM_237_EDITOR                          1321
+#define IMG_CUSTOM_238                                 1322
+#define IMG_CUSTOM_238_EDITOR                          1323
+#define IMG_CUSTOM_239                                 1324
+#define IMG_CUSTOM_239_EDITOR                          1325
+#define IMG_CUSTOM_240                                 1326
+#define IMG_CUSTOM_240_EDITOR                          1327
+#define IMG_CUSTOM_241                                 1328
+#define IMG_CUSTOM_241_EDITOR                          1329
+#define IMG_CUSTOM_242                                 1330
+#define IMG_CUSTOM_242_EDITOR                          1331
+#define IMG_CUSTOM_243                                 1332
+#define IMG_CUSTOM_243_EDITOR                          1333
+#define IMG_CUSTOM_244                                 1334
+#define IMG_CUSTOM_244_EDITOR                          1335
+#define IMG_CUSTOM_245                                 1336
+#define IMG_CUSTOM_245_EDITOR                          1337
+#define IMG_CUSTOM_246                                 1338
+#define IMG_CUSTOM_246_EDITOR                          1339
+#define IMG_CUSTOM_247                                 1340
+#define IMG_CUSTOM_247_EDITOR                          1341
+#define IMG_CUSTOM_248                                 1342
+#define IMG_CUSTOM_248_EDITOR                          1343
+#define IMG_CUSTOM_249                                 1344
+#define IMG_CUSTOM_249_EDITOR                          1345
+#define IMG_CUSTOM_250                                 1346
+#define IMG_CUSTOM_250_EDITOR                          1347
+#define IMG_CUSTOM_251                                 1348
+#define IMG_CUSTOM_251_EDITOR                          1349
+#define IMG_CUSTOM_252                                 1350
+#define IMG_CUSTOM_252_EDITOR                          1351
+#define IMG_CUSTOM_253                                 1352
+#define IMG_CUSTOM_253_EDITOR                          1353
+#define IMG_CUSTOM_254                                 1354
+#define IMG_CUSTOM_254_EDITOR                          1355
+#define IMG_CUSTOM_255                                 1356
+#define IMG_CUSTOM_255_EDITOR                          1357
+#define IMG_CUSTOM_256                                 1358
+#define IMG_CUSTOM_256_EDITOR                          1359
+#define IMG_GROUP_1                                    1360
+#define IMG_GROUP_1_EDITOR                             1361
+#define IMG_GROUP_2                                    1362
+#define IMG_GROUP_2_EDITOR                             1363
+#define IMG_GROUP_3                                    1364
+#define IMG_GROUP_3_EDITOR                             1365
+#define IMG_GROUP_4                                    1366
+#define IMG_GROUP_4_EDITOR                             1367
+#define IMG_GROUP_5                                    1368
+#define IMG_GROUP_5_EDITOR                             1369
+#define IMG_GROUP_6                                    1370
+#define IMG_GROUP_6_EDITOR                             1371
+#define IMG_GROUP_7                                    1372
+#define IMG_GROUP_7_EDITOR                             1373
+#define IMG_GROUP_8                                    1374
+#define IMG_GROUP_8_EDITOR                             1375
+#define IMG_GROUP_9                                    1376
+#define IMG_GROUP_9_EDITOR                             1377
+#define IMG_GROUP_10                                   1378
+#define IMG_GROUP_10_EDITOR                            1379
+#define IMG_GROUP_11                                   1380
+#define IMG_GROUP_11_EDITOR                            1381
+#define IMG_GROUP_12                                   1382
+#define IMG_GROUP_12_EDITOR                            1383
+#define IMG_GROUP_13                                   1384
+#define IMG_GROUP_13_EDITOR                            1385
+#define IMG_GROUP_14                                   1386
+#define IMG_GROUP_14_EDITOR                            1387
+#define IMG_GROUP_15                                   1388
+#define IMG_GROUP_15_EDITOR                            1389
+#define IMG_GROUP_16                                   1390
+#define IMG_GROUP_16_EDITOR                            1391
+#define IMG_GROUP_17                                   1392
+#define IMG_GROUP_17_EDITOR                            1393
+#define IMG_GROUP_18                                   1394
+#define IMG_GROUP_18_EDITOR                            1395
+#define IMG_GROUP_19                                   1396
+#define IMG_GROUP_19_EDITOR                            1397
+#define IMG_GROUP_20                                   1398
+#define IMG_GROUP_20_EDITOR                            1399
+#define IMG_GROUP_21                                   1400
+#define IMG_GROUP_21_EDITOR                            1401
+#define IMG_GROUP_22                                   1402
+#define IMG_GROUP_22_EDITOR                            1403
+#define IMG_GROUP_23                                   1404
+#define IMG_GROUP_23_EDITOR                            1405
+#define IMG_GROUP_24                                   1406
+#define IMG_GROUP_24_EDITOR                            1407
+#define IMG_GROUP_25                                   1408
+#define IMG_GROUP_25_EDITOR                            1409
+#define IMG_GROUP_26                                   1410
+#define IMG_GROUP_26_EDITOR                            1411
+#define IMG_GROUP_27                                   1412
+#define IMG_GROUP_27_EDITOR                            1413
+#define IMG_GROUP_28                                   1414
+#define IMG_GROUP_28_EDITOR                            1415
+#define IMG_GROUP_29                                   1416
+#define IMG_GROUP_29_EDITOR                            1417
+#define IMG_GROUP_30                                   1418
+#define IMG_GROUP_30_EDITOR                            1419
+#define IMG_GROUP_31                                   1420
+#define IMG_GROUP_31_EDITOR                            1421
+#define IMG_GROUP_32                                   1422
+#define IMG_GROUP_32_EDITOR                            1423
+#define IMG_EMC_OBJECT                                 1424
+#define IMG_EMC_SPRITE                                 1425
+#define IMG_TOON_1                                     1426
+#define IMG_TOON_2                                     1427
+#define IMG_TOON_3                                     1428
+#define IMG_TOON_4                                     1429
+#define IMG_TOON_5                                     1430
+#define IMG_TOON_6                                     1431
+#define IMG_TOON_7                                     1432
+#define IMG_TOON_8                                     1433
+#define IMG_TOON_9                                     1434
+#define IMG_TOON_10                                    1435
+#define IMG_TOON_11                                    1436
+#define IMG_TOON_12                                    1437
+#define IMG_TOON_13                                    1438
+#define IMG_TOON_14                                    1439
+#define IMG_TOON_15                                    1440
+#define IMG_TOON_16                                    1441
+#define IMG_TOON_17                                    1442
+#define IMG_TOON_18                                    1443
+#define IMG_TOON_19                                    1444
+#define IMG_TOON_20                                    1445
+#define IMG_MENU_CALIBRATE_RED                         1446
+#define IMG_MENU_CALIBRATE_BLUE                                1447
+#define IMG_MENU_CALIBRATE_YELLOW                      1448
+#define IMG_MENU_BUTTON                                        1449
+#define IMG_MENU_BUTTON_ACTIVE                         1450
+#define IMG_MENU_BUTTON_LEFT                           1451
+#define IMG_MENU_BUTTON_LEFT_ACTIVE                    1452
+#define IMG_MENU_BUTTON_RIGHT                          1453
+#define IMG_MENU_BUTTON_RIGHT_ACTIVE                   1454
+#define IMG_MENU_BUTTON_UP                             1455
+#define IMG_MENU_BUTTON_UP_ACTIVE                      1456
+#define IMG_MENU_BUTTON_DOWN                           1457
+#define IMG_MENU_BUTTON_DOWN_ACTIVE                    1458
+#define IMG_MENU_BUTTON_ENTER_MENU                     1459
+#define IMG_MENU_BUTTON_ENTER_MENU_ACTIVE              1460
+#define IMG_MENU_BUTTON_LEAVE_MENU                     1461
+#define IMG_MENU_BUTTON_LEAVE_MENU_ACTIVE              1462
+#define IMG_MENU_BUTTON_NEXT_LEVEL                     1463
+#define IMG_MENU_BUTTON_NEXT_LEVEL_ACTIVE              1464
+#define IMG_MENU_BUTTON_LAST_LEVEL                     1465
+#define IMG_MENU_BUTTON_LAST_LEVEL_ACTIVE              1466
+#define IMG_MENU_SCROLLBAR                             1467
+#define IMG_MENU_SCROLLBAR_ACTIVE                      1468
+#define IMG_FONT_INITIAL_1                             1469
+#define IMG_FONT_INITIAL_2                             1470
+#define IMG_FONT_INITIAL_3                             1471
+#define IMG_FONT_INITIAL_4                             1472
+#define IMG_FONT_TITLE_1                               1473
+#define IMG_FONT_TITLE_2                               1474
+#define IMG_FONT_MENU_1                                        1475
+#define IMG_FONT_MENU_2                                        1476
+#define IMG_FONT_TEXT_1                                        1477
+#define IMG_FONT_TEXT_1_LEVELS                         1478
+#define IMG_FONT_TEXT_1_PREVIEW                                1479
+#define IMG_FONT_TEXT_1_SCORES                         1480
+#define IMG_FONT_TEXT_1_ACTIVE_SCORES                  1481
+#define IMG_FONT_TEXT_2                                        1482
+#define IMG_FONT_TEXT_2_LEVELS                         1483
+#define IMG_FONT_TEXT_2_PREVIEW                                1484
+#define IMG_FONT_TEXT_2_SCORES                         1485
+#define IMG_FONT_TEXT_2_ACTIVE_SCORES                  1486
+#define IMG_FONT_TEXT_3                                        1487
+#define IMG_FONT_TEXT_3_LEVELS                         1488
+#define IMG_FONT_TEXT_3_PREVIEW                                1489
+#define IMG_FONT_TEXT_3_SCORES                         1490
+#define IMG_FONT_TEXT_3_ACTIVE_SCORES                  1491
+#define IMG_FONT_TEXT_4                                        1492
+#define IMG_FONT_TEXT_4_LEVELS                         1493
+#define IMG_FONT_TEXT_4_SCORES                         1494
+#define IMG_FONT_TEXT_4_ACTIVE_SCORES                  1495
+#define IMG_FONT_ENVELOPE_1                            1496
+#define IMG_FONT_ENVELOPE_2                            1497
+#define IMG_FONT_ENVELOPE_3                            1498
+#define IMG_FONT_ENVELOPE_4                            1499
+#define IMG_FONT_INPUT_1                               1500
+#define IMG_FONT_INPUT_1_MAIN                          1501
+#define IMG_FONT_INPUT_1_ACTIVE                                1502
+#define IMG_FONT_INPUT_1_ACTIVE_MAIN                   1503
+#define IMG_FONT_INPUT_1_ACTIVE_SETUP                  1504
+#define IMG_FONT_INPUT_2                               1505
+#define IMG_FONT_INPUT_2_ACTIVE                                1506
+#define IMG_FONT_OPTION_OFF                            1507
+#define IMG_FONT_OPTION_ON                             1508
+#define IMG_FONT_VALUE_1                               1509
+#define IMG_FONT_VALUE_2                               1510
+#define IMG_FONT_VALUE_OLD                             1511
+#define IMG_FONT_LEVEL_NUMBER                          1512
+#define IMG_FONT_TAPE_RECORDER                         1513
+#define IMG_FONT_GAME_INFO                             1514
+#define IMG_GLOBAL_BORDER                              1515
+#define IMG_GLOBAL_DOOR                                        1516
+#define IMG_EDITOR_ELEMENT_BORDER                      1517
+#define IMG_EDITOR_ELEMENT_BORDER_INPUT                        1518
+#define IMG_EDITOR_CASCADE_LIST                                1519
+#define IMG_EDITOR_CASCADE_LIST_ACTIVE                 1520
+#define IMG_BACKGROUND_ENVELOPE_1                      1521
+#define IMG_BACKGROUND_ENVELOPE_2                      1522
+#define IMG_BACKGROUND_ENVELOPE_3                      1523
+#define IMG_BACKGROUND_ENVELOPE_4                      1524
+#define IMG_TITLESCREEN_1                              1525
+#define IMG_TITLESCREEN_2                              1526
+#define IMG_TITLESCREEN_3                              1527
+#define IMG_TITLESCREEN_4                              1528
+#define IMG_TITLESCREEN_5                              1529
+#define IMG_BACKGROUND                                 1530
+#define IMG_BACKGROUND_TITLE                           1531
+#define IMG_BACKGROUND_MAIN                            1532
+#define IMG_BACKGROUND_LEVELS                          1533
+#define IMG_BACKGROUND_SCORES                          1534
+#define IMG_BACKGROUND_EDITOR                          1535
+#define IMG_BACKGROUND_INFO                            1536
+#define IMG_BACKGROUND_INFO_ELEMENTS                   1537
+#define IMG_BACKGROUND_INFO_MUSIC                      1538
+#define IMG_BACKGROUND_INFO_CREDITS                    1539
+#define IMG_BACKGROUND_INFO_PROGRAM                    1540
+#define IMG_BACKGROUND_INFO_LEVELSET                   1541
+#define IMG_BACKGROUND_SETUP                           1542
+#define IMG_BACKGROUND_DOOR                            1543
 
-#define NUM_IMAGE_FILES                                        1479
+#define NUM_IMAGE_FILES                                        1544
 
 #endif /* CONF_GFX_H */
index 27ec9056f35678f6d3ebe16f29914b254e1ac3ae..bb5f5e79d7e75efc52710aa2a6b9d3d0246824e2 100644 (file)
@@ -29,6 +29,7 @@ struct ConfigTypeInfo music_config_suffix[] =
 struct ConfigInfo music_config[] =
 {
   { "background",                      UNDEFINED_FILENAME              },
+  { "background.TITLE",                        UNDEFINED_FILENAME              },
   { "background.MAIN",                 UNDEFINED_FILENAME              },
   { "background.LEVELS",               UNDEFINED_FILENAME              },
   { "background.SCORES",               UNDEFINED_FILENAME              },
index e6ba90e908cc49d94e218817823a7906475a7d96..a8d757b82a60a561c45d9969bf6f421248cabf32 100644 (file)
 /* values for music configuration */
 
 #define MUS_BACKGROUND                                 0
-#define MUS_BACKGROUND_MAIN                            1
-#define MUS_BACKGROUND_LEVELS                          2
-#define MUS_BACKGROUND_SCORES                          3
-#define MUS_BACKGROUND_EDITOR                          4
-#define MUS_BACKGROUND_INFO                            5
-#define MUS_BACKGROUND_SETUP                           6
+#define MUS_BACKGROUND_TITLE                           1
+#define MUS_BACKGROUND_MAIN                            2
+#define MUS_BACKGROUND_LEVELS                          3
+#define MUS_BACKGROUND_SCORES                          4
+#define MUS_BACKGROUND_EDITOR                          5
+#define MUS_BACKGROUND_INFO                            6
+#define MUS_BACKGROUND_SETUP                           7
 
-#define NUM_MUSIC_FILES                                        7
+#define NUM_MUSIC_FILES                                        8
 
 #endif /* CONF_MUS_H */
index 8cdd4d7b1f0f3740328b663fafdfa0f2aa302cdc..c15e0dec81385f29360c24201a7755b51bb1bc4c 100644 (file)
@@ -240,6 +240,7 @@ struct ConfigInfo sound_config[] =
   { "door.opening",                    "oeffnen.wav"                   },
   { "door.closing",                    "oeffnen.wav"                   },
 
+  { "background.TITLE",                        UNDEFINED_FILENAME              },
   { "background.MAIN",                 UNDEFINED_FILENAME              },
   { "background.LEVELS",               UNDEFINED_FILENAME              },
   { "background.SCORES",               "halloffame.wav"                },
index 91bb12919c557716bfdf656d6a011caed0f21f95..6663812dcf9af83155c617565fc674f30ae629c7 100644 (file)
 #define SND_GAME_SOKOBAN_SOLVING                       179
 #define SND_DOOR_OPENING                               180
 #define SND_DOOR_CLOSING                               181
-#define SND_BACKGROUND_MAIN                            182
-#define SND_BACKGROUND_LEVELS                          183
-#define SND_BACKGROUND_SCORES                          184
-#define SND_BACKGROUND_EDITOR                          185
-#define SND_BACKGROUND_INFO                            186
-#define SND_BACKGROUND_SETUP                           187
+#define SND_BACKGROUND_TITLE                           182
+#define SND_BACKGROUND_MAIN                            183
+#define SND_BACKGROUND_LEVELS                          184
+#define SND_BACKGROUND_SCORES                          185
+#define SND_BACKGROUND_EDITOR                          186
+#define SND_BACKGROUND_INFO                            187
+#define SND_BACKGROUND_SETUP                           188
 
-#define NUM_SOUND_FILES                                        188
+#define NUM_SOUND_FILES                                        189
 
 #endif /* CONF_SND_H */
index 06aa9f53c3b190039ad583c41327b56152bf20b4..98dea38ddf34182ee7dafc2f7ede5bb653b508e9 100644 (file)
@@ -1 +1 @@
-#define COMPILE_DATE_STRING "[2006-01-11 22:26]"
+#define COMPILE_DATE_STRING "[2006-07-16 02:28]"
index 8c1302cc0232b150bc5c004b6bccd13bbd16df36..f80d82e09c4aa220e55af9f4abff1640bf43d3e6 100644 (file)
 /* yamyam content */
 #define ED_AREA_YAMYAM_CONTENT_XPOS(n) (2 * MINI_TILEX +               \
                                         5 * ((n) % 4) * MINI_TILEX)
-#define ED_AREA_YAMYAM_CONTENT_YPOS(n) (17 * MINI_TILEY +              \
+#define ED_AREA_YAMYAM_CONTENT_YPOS(n) (11 * ED_SETTINGS_YOFFSET +     \
                                         6 * ((n) / 4) * MINI_TILEY)
 
 /* magic ball content */
 #define ED_AREA_MAGIC_BALL_CONTENT_XPOS(n) (2 * MINI_TILEX +           \
                                            5 * ((n) % 4) * MINI_TILEX)
-#define ED_AREA_MAGIC_BALL_CONTENT_YPOS(n) (17 * MINI_TILEY +          \
+#define ED_AREA_MAGIC_BALL_CONTENT_YPOS(n) (12 * ED_SETTINGS_YOFFSET + \
                                            6 * ((n) / 4) * MINI_TILEY)
 
 /* values for scrolling gadgets for drawing area */
 #define ED_TEXTBUTTON_XSIZE            ED_WIN_COUNT_XSIZE
 #define ED_TEXTBUTTON_YSIZE            ED_WIN_COUNT_YSIZE
 
-/* values for ClearEditorGadgetInfoText() and HandleGadgetInfoText() */
+/* values for ClearEditorGadgetInfoText() and HandleEditorGadgetInfoText() */
 #define INFOTEXT_XPOS                  SX
 #define INFOTEXT_YPOS                  (SY + SYSIZE - MINI_TILEX + 2)
 #define INFOTEXT_XSIZE                 SXSIZE
 #define GADGET_ID_ELEMENT_VALUE2_DOWN  (GADGET_ID_COUNTER_FIRST + 24)
 #define GADGET_ID_ELEMENT_VALUE2_TEXT  (GADGET_ID_COUNTER_FIRST + 25)
 #define GADGET_ID_ELEMENT_VALUE2_UP    (GADGET_ID_COUNTER_FIRST + 26)
-#define GADGET_ID_YAMYAM_CONTENT_DOWN  (GADGET_ID_COUNTER_FIRST + 27)
-#define GADGET_ID_YAMYAM_CONTENT_TEXT  (GADGET_ID_COUNTER_FIRST + 28)
-#define GADGET_ID_YAMYAM_CONTENT_UP    (GADGET_ID_COUNTER_FIRST + 29)
-#define GADGET_ID_ENVELOPE_XSIZE_DOWN  (GADGET_ID_COUNTER_FIRST + 30)
-#define GADGET_ID_ENVELOPE_XSIZE_TEXT  (GADGET_ID_COUNTER_FIRST + 31)
-#define GADGET_ID_ENVELOPE_XSIZE_UP    (GADGET_ID_COUNTER_FIRST + 32)
-#define GADGET_ID_ENVELOPE_YSIZE_DOWN  (GADGET_ID_COUNTER_FIRST + 33)
-#define GADGET_ID_ENVELOPE_YSIZE_TEXT  (GADGET_ID_COUNTER_FIRST + 34)
-#define GADGET_ID_ENVELOPE_YSIZE_UP    (GADGET_ID_COUNTER_FIRST + 35)
-#define GADGET_ID_CUSTOM_SCORE_DOWN    (GADGET_ID_COUNTER_FIRST + 36)
-#define GADGET_ID_CUSTOM_SCORE_TEXT    (GADGET_ID_COUNTER_FIRST + 37)
-#define GADGET_ID_CUSTOM_SCORE_UP      (GADGET_ID_COUNTER_FIRST + 38)
-#define GADGET_ID_CUSTOM_GEMCOUNT_DOWN (GADGET_ID_COUNTER_FIRST + 39)
-#define GADGET_ID_CUSTOM_GEMCOUNT_TEXT (GADGET_ID_COUNTER_FIRST + 40)
-#define GADGET_ID_CUSTOM_GEMCOUNT_UP   (GADGET_ID_COUNTER_FIRST + 41)
-#define GADGET_ID_PUSH_DELAY_FIX_DOWN  (GADGET_ID_COUNTER_FIRST + 42)
-#define GADGET_ID_PUSH_DELAY_FIX_TEXT  (GADGET_ID_COUNTER_FIRST + 43)
-#define GADGET_ID_PUSH_DELAY_FIX_UP    (GADGET_ID_COUNTER_FIRST + 44)
-#define GADGET_ID_PUSH_DELAY_RND_DOWN  (GADGET_ID_COUNTER_FIRST + 45)
-#define GADGET_ID_PUSH_DELAY_RND_TEXT  (GADGET_ID_COUNTER_FIRST + 46)
-#define GADGET_ID_PUSH_DELAY_RND_UP    (GADGET_ID_COUNTER_FIRST + 47)
-#define GADGET_ID_DROP_DELAY_FIX_DOWN  (GADGET_ID_COUNTER_FIRST + 48)
-#define GADGET_ID_DROP_DELAY_FIX_TEXT  (GADGET_ID_COUNTER_FIRST + 49)
-#define GADGET_ID_DROP_DELAY_FIX_UP    (GADGET_ID_COUNTER_FIRST + 50)
-#define GADGET_ID_DROP_DELAY_RND_DOWN  (GADGET_ID_COUNTER_FIRST + 51)
-#define GADGET_ID_DROP_DELAY_RND_TEXT  (GADGET_ID_COUNTER_FIRST + 52)
-#define GADGET_ID_DROP_DELAY_RND_UP    (GADGET_ID_COUNTER_FIRST + 53)
-#define GADGET_ID_MOVE_DELAY_FIX_DOWN  (GADGET_ID_COUNTER_FIRST + 54)
-#define GADGET_ID_MOVE_DELAY_FIX_TEXT  (GADGET_ID_COUNTER_FIRST + 55)
-#define GADGET_ID_MOVE_DELAY_FIX_UP    (GADGET_ID_COUNTER_FIRST + 56)
-#define GADGET_ID_MOVE_DELAY_RND_DOWN  (GADGET_ID_COUNTER_FIRST + 57)
-#define GADGET_ID_MOVE_DELAY_RND_TEXT  (GADGET_ID_COUNTER_FIRST + 58)
-#define GADGET_ID_MOVE_DELAY_RND_UP    (GADGET_ID_COUNTER_FIRST + 59)
-#define GADGET_ID_EXPLOSION_DELAY_DOWN (GADGET_ID_COUNTER_FIRST + 60)
-#define GADGET_ID_EXPLOSION_DELAY_TEXT (GADGET_ID_COUNTER_FIRST + 61)
-#define GADGET_ID_EXPLOSION_DELAY_UP   (GADGET_ID_COUNTER_FIRST + 62)
-#define GADGET_ID_IGNITION_DELAY_DOWN  (GADGET_ID_COUNTER_FIRST + 63)
-#define GADGET_ID_IGNITION_DELAY_TEXT  (GADGET_ID_COUNTER_FIRST + 64)
-#define GADGET_ID_IGNITION_DELAY_UP    (GADGET_ID_COUNTER_FIRST + 65)
-#define GADGET_ID_CHANGE_DELAY_FIX_DOWN        (GADGET_ID_COUNTER_FIRST + 66)
-#define GADGET_ID_CHANGE_DELAY_FIX_TEXT        (GADGET_ID_COUNTER_FIRST + 67)
-#define GADGET_ID_CHANGE_DELAY_FIX_UP  (GADGET_ID_COUNTER_FIRST + 68)
-#define GADGET_ID_CHANGE_DELAY_RND_DOWN        (GADGET_ID_COUNTER_FIRST + 69)
-#define GADGET_ID_CHANGE_DELAY_RND_TEXT        (GADGET_ID_COUNTER_FIRST + 70)
-#define GADGET_ID_CHANGE_DELAY_RND_UP  (GADGET_ID_COUNTER_FIRST + 71)
-#define GADGET_ID_CHANGE_CONT_RND_DOWN (GADGET_ID_COUNTER_FIRST + 72)
-#define GADGET_ID_CHANGE_CONT_RND_TEXT (GADGET_ID_COUNTER_FIRST + 73)
-#define GADGET_ID_CHANGE_CONT_RND_UP   (GADGET_ID_COUNTER_FIRST + 74)
-#define GADGET_ID_GROUP_CONTENT_DOWN   (GADGET_ID_COUNTER_FIRST + 75)
-#define GADGET_ID_GROUP_CONTENT_TEXT   (GADGET_ID_COUNTER_FIRST + 76)
-#define GADGET_ID_GROUP_CONTENT_UP     (GADGET_ID_COUNTER_FIRST + 77)
+#define GADGET_ID_ELEMENT_VALUE3_DOWN  (GADGET_ID_COUNTER_FIRST + 27)
+#define GADGET_ID_ELEMENT_VALUE3_TEXT  (GADGET_ID_COUNTER_FIRST + 28)
+#define GADGET_ID_ELEMENT_VALUE3_UP    (GADGET_ID_COUNTER_FIRST + 29)
+#define GADGET_ID_ELEMENT_VALUE4_DOWN  (GADGET_ID_COUNTER_FIRST + 30)
+#define GADGET_ID_ELEMENT_VALUE4_TEXT  (GADGET_ID_COUNTER_FIRST + 31)
+#define GADGET_ID_ELEMENT_VALUE4_UP    (GADGET_ID_COUNTER_FIRST + 32)
+#define GADGET_ID_YAMYAM_CONTENT_DOWN  (GADGET_ID_COUNTER_FIRST + 33)
+#define GADGET_ID_YAMYAM_CONTENT_TEXT  (GADGET_ID_COUNTER_FIRST + 34)
+#define GADGET_ID_YAMYAM_CONTENT_UP    (GADGET_ID_COUNTER_FIRST + 35)
+#define GADGET_ID_BALL_CONTENT_DOWN    (GADGET_ID_COUNTER_FIRST + 36)
+#define GADGET_ID_BALL_CONTENT_TEXT    (GADGET_ID_COUNTER_FIRST + 37)
+#define GADGET_ID_BALL_CONTENT_UP      (GADGET_ID_COUNTER_FIRST + 38)
+#define GADGET_ID_ANDROID_CONTENT_DOWN (GADGET_ID_COUNTER_FIRST + 39)
+#define GADGET_ID_ANDROID_CONTENT_TEXT (GADGET_ID_COUNTER_FIRST + 40)
+#define GADGET_ID_ANDROID_CONTENT_UP   (GADGET_ID_COUNTER_FIRST + 41)
+#define GADGET_ID_ENVELOPE_XSIZE_DOWN  (GADGET_ID_COUNTER_FIRST + 42)
+#define GADGET_ID_ENVELOPE_XSIZE_TEXT  (GADGET_ID_COUNTER_FIRST + 43)
+#define GADGET_ID_ENVELOPE_XSIZE_UP    (GADGET_ID_COUNTER_FIRST + 44)
+#define GADGET_ID_ENVELOPE_YSIZE_DOWN  (GADGET_ID_COUNTER_FIRST + 45)
+#define GADGET_ID_ENVELOPE_YSIZE_TEXT  (GADGET_ID_COUNTER_FIRST + 46)
+#define GADGET_ID_ENVELOPE_YSIZE_UP    (GADGET_ID_COUNTER_FIRST + 47)
+#define GADGET_ID_CUSTOM_SCORE_DOWN    (GADGET_ID_COUNTER_FIRST + 48)
+#define GADGET_ID_CUSTOM_SCORE_TEXT    (GADGET_ID_COUNTER_FIRST + 49)
+#define GADGET_ID_CUSTOM_SCORE_UP      (GADGET_ID_COUNTER_FIRST + 50)
+#define GADGET_ID_CUSTOM_GEMCOUNT_DOWN (GADGET_ID_COUNTER_FIRST + 51)
+#define GADGET_ID_CUSTOM_GEMCOUNT_TEXT (GADGET_ID_COUNTER_FIRST + 52)
+#define GADGET_ID_CUSTOM_GEMCOUNT_UP   (GADGET_ID_COUNTER_FIRST + 53)
+#define GADGET_ID_CUSTOM_VALUE_FIX_DOWN        (GADGET_ID_COUNTER_FIRST + 54)
+#define GADGET_ID_CUSTOM_VALUE_FIX_TEXT        (GADGET_ID_COUNTER_FIRST + 55)
+#define GADGET_ID_CUSTOM_VALUE_FIX_UP  (GADGET_ID_COUNTER_FIRST + 56)
+#define GADGET_ID_CUSTOM_VALUE_RND_DOWN        (GADGET_ID_COUNTER_FIRST + 57)
+#define GADGET_ID_CUSTOM_VALUE_RND_TEXT        (GADGET_ID_COUNTER_FIRST + 58)
+#define GADGET_ID_CUSTOM_VALUE_RND_UP  (GADGET_ID_COUNTER_FIRST + 59)
+#define GADGET_ID_PUSH_DELAY_FIX_DOWN  (GADGET_ID_COUNTER_FIRST + 60)
+#define GADGET_ID_PUSH_DELAY_FIX_TEXT  (GADGET_ID_COUNTER_FIRST + 61)
+#define GADGET_ID_PUSH_DELAY_FIX_UP    (GADGET_ID_COUNTER_FIRST + 62)
+#define GADGET_ID_PUSH_DELAY_RND_DOWN  (GADGET_ID_COUNTER_FIRST + 63)
+#define GADGET_ID_PUSH_DELAY_RND_TEXT  (GADGET_ID_COUNTER_FIRST + 64)
+#define GADGET_ID_PUSH_DELAY_RND_UP    (GADGET_ID_COUNTER_FIRST + 65)
+#define GADGET_ID_DROP_DELAY_FIX_DOWN  (GADGET_ID_COUNTER_FIRST + 66)
+#define GADGET_ID_DROP_DELAY_FIX_TEXT  (GADGET_ID_COUNTER_FIRST + 67)
+#define GADGET_ID_DROP_DELAY_FIX_UP    (GADGET_ID_COUNTER_FIRST + 68)
+#define GADGET_ID_DROP_DELAY_RND_DOWN  (GADGET_ID_COUNTER_FIRST + 69)
+#define GADGET_ID_DROP_DELAY_RND_TEXT  (GADGET_ID_COUNTER_FIRST + 70)
+#define GADGET_ID_DROP_DELAY_RND_UP    (GADGET_ID_COUNTER_FIRST + 71)
+#define GADGET_ID_MOVE_DELAY_FIX_DOWN  (GADGET_ID_COUNTER_FIRST + 72)
+#define GADGET_ID_MOVE_DELAY_FIX_TEXT  (GADGET_ID_COUNTER_FIRST + 73)
+#define GADGET_ID_MOVE_DELAY_FIX_UP    (GADGET_ID_COUNTER_FIRST + 74)
+#define GADGET_ID_MOVE_DELAY_RND_DOWN  (GADGET_ID_COUNTER_FIRST + 75)
+#define GADGET_ID_MOVE_DELAY_RND_TEXT  (GADGET_ID_COUNTER_FIRST + 76)
+#define GADGET_ID_MOVE_DELAY_RND_UP    (GADGET_ID_COUNTER_FIRST + 77)
+#define GADGET_ID_EXPLOSION_DELAY_DOWN (GADGET_ID_COUNTER_FIRST + 78)
+#define GADGET_ID_EXPLOSION_DELAY_TEXT (GADGET_ID_COUNTER_FIRST + 79)
+#define GADGET_ID_EXPLOSION_DELAY_UP   (GADGET_ID_COUNTER_FIRST + 80)
+#define GADGET_ID_IGNITION_DELAY_DOWN  (GADGET_ID_COUNTER_FIRST + 81)
+#define GADGET_ID_IGNITION_DELAY_TEXT  (GADGET_ID_COUNTER_FIRST + 82)
+#define GADGET_ID_IGNITION_DELAY_UP    (GADGET_ID_COUNTER_FIRST + 83)
+#define GADGET_ID_CHANGE_DELAY_FIX_DOWN        (GADGET_ID_COUNTER_FIRST + 84)
+#define GADGET_ID_CHANGE_DELAY_FIX_TEXT        (GADGET_ID_COUNTER_FIRST + 85)
+#define GADGET_ID_CHANGE_DELAY_FIX_UP  (GADGET_ID_COUNTER_FIRST + 86)
+#define GADGET_ID_CHANGE_DELAY_RND_DOWN        (GADGET_ID_COUNTER_FIRST + 87)
+#define GADGET_ID_CHANGE_DELAY_RND_TEXT        (GADGET_ID_COUNTER_FIRST + 88)
+#define GADGET_ID_CHANGE_DELAY_RND_UP  (GADGET_ID_COUNTER_FIRST + 89)
+#define GADGET_ID_CHANGE_CONT_RND_DOWN (GADGET_ID_COUNTER_FIRST + 90)
+#define GADGET_ID_CHANGE_CONT_RND_TEXT (GADGET_ID_COUNTER_FIRST + 91)
+#define GADGET_ID_CHANGE_CONT_RND_UP   (GADGET_ID_COUNTER_FIRST + 92)
+#define GADGET_ID_GROUP_CONTENT_DOWN   (GADGET_ID_COUNTER_FIRST + 93)
+#define GADGET_ID_GROUP_CONTENT_TEXT   (GADGET_ID_COUNTER_FIRST + 94)
+#define GADGET_ID_GROUP_CONTENT_UP     (GADGET_ID_COUNTER_FIRST + 95)
 
 /* drawing area identifiers */
-#define GADGET_ID_DRAWING_AREA_FIRST   (GADGET_ID_COUNTER_FIRST + 78)
+#define GADGET_ID_DRAWING_AREA_FIRST   (GADGET_ID_COUNTER_FIRST + 96)
 
 #define GADGET_ID_DRAWING_LEVEL                (GADGET_ID_DRAWING_AREA_FIRST + 0)
 #define GADGET_ID_YAMYAM_CONTENT_0     (GADGET_ID_DRAWING_AREA_FIRST + 1)
 #define GADGET_ID_MAGIC_BALL_CONTENT_5 (GADGET_ID_DRAWING_AREA_FIRST + 14)
 #define GADGET_ID_MAGIC_BALL_CONTENT_6 (GADGET_ID_DRAWING_AREA_FIRST + 15)
 #define GADGET_ID_MAGIC_BALL_CONTENT_7 (GADGET_ID_DRAWING_AREA_FIRST + 16)
-#define GADGET_ID_AMOEBA_CONTENT       (GADGET_ID_DRAWING_AREA_FIRST + 17)
-#define GADGET_ID_CUSTOM_GRAPHIC       (GADGET_ID_DRAWING_AREA_FIRST + 18)
-#define GADGET_ID_CUSTOM_CONTENT       (GADGET_ID_DRAWING_AREA_FIRST + 19)
-#define GADGET_ID_CUSTOM_MOVE_ENTER    (GADGET_ID_DRAWING_AREA_FIRST + 20)
-#define GADGET_ID_CUSTOM_MOVE_LEAVE    (GADGET_ID_DRAWING_AREA_FIRST + 21)
-#define GADGET_ID_CUSTOM_CHANGE_TARGET (GADGET_ID_DRAWING_AREA_FIRST + 22)
-#define GADGET_ID_CUSTOM_CHANGE_CONTENT        (GADGET_ID_DRAWING_AREA_FIRST + 23)
-#define GADGET_ID_CUSTOM_CHANGE_TRIGGER        (GADGET_ID_DRAWING_AREA_FIRST + 24)
-#define GADGET_ID_GROUP_CONTENT                (GADGET_ID_DRAWING_AREA_FIRST + 25)
-#define GADGET_ID_RANDOM_BACKGROUND    (GADGET_ID_DRAWING_AREA_FIRST + 26)
+#define GADGET_ID_ANDROID_CONTENT      (GADGET_ID_DRAWING_AREA_FIRST + 17)
+#define GADGET_ID_AMOEBA_CONTENT       (GADGET_ID_DRAWING_AREA_FIRST + 18)
+#define GADGET_ID_START_ELEMENT                (GADGET_ID_DRAWING_AREA_FIRST + 19)
+#define GADGET_ID_ARTWORK_ELEMENT      (GADGET_ID_DRAWING_AREA_FIRST + 20)
+#define GADGET_ID_EXPLOSION_ELEMENT    (GADGET_ID_DRAWING_AREA_FIRST + 21)
+#define GADGET_ID_CUSTOM_GRAPHIC       (GADGET_ID_DRAWING_AREA_FIRST + 22)
+#define GADGET_ID_CUSTOM_CONTENT       (GADGET_ID_DRAWING_AREA_FIRST + 23)
+#define GADGET_ID_CUSTOM_MOVE_ENTER    (GADGET_ID_DRAWING_AREA_FIRST + 24)
+#define GADGET_ID_CUSTOM_MOVE_LEAVE    (GADGET_ID_DRAWING_AREA_FIRST + 25)
+#define GADGET_ID_CUSTOM_CHANGE_TARGET (GADGET_ID_DRAWING_AREA_FIRST + 26)
+#define GADGET_ID_CUSTOM_CHANGE_CONTENT        (GADGET_ID_DRAWING_AREA_FIRST + 27)
+#define GADGET_ID_CUSTOM_CHANGE_TRIGGER        (GADGET_ID_DRAWING_AREA_FIRST + 28)
+#define GADGET_ID_GROUP_CONTENT                (GADGET_ID_DRAWING_AREA_FIRST + 29)
+#define GADGET_ID_RANDOM_BACKGROUND    (GADGET_ID_DRAWING_AREA_FIRST + 30)
 
 /* text input identifiers */
-#define GADGET_ID_TEXT_INPUT_FIRST     (GADGET_ID_DRAWING_AREA_FIRST + 27)
+#define GADGET_ID_TEXT_INPUT_FIRST     (GADGET_ID_DRAWING_AREA_FIRST + 31)
 
 #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_TIME_OR_STEPS                (GADGET_ID_SELECTBOX_FIRST + 0)
 #define GADGET_ID_GAME_ENGINE_TYPE     (GADGET_ID_SELECTBOX_FIRST + 1)
-#define GADGET_ID_CUSTOM_WALK_TO_ACTION        (GADGET_ID_SELECTBOX_FIRST + 2)
-#define GADGET_ID_CUSTOM_EXPLOSION_TYPE        (GADGET_ID_SELECTBOX_FIRST + 3)
-#define GADGET_ID_CUSTOM_DEADLINESS    (GADGET_ID_SELECTBOX_FIRST + 4)
-#define GADGET_ID_CUSTOM_MOVE_PATTERN  (GADGET_ID_SELECTBOX_FIRST + 5)
-#define GADGET_ID_CUSTOM_MOVE_DIRECTION        (GADGET_ID_SELECTBOX_FIRST + 6)
-#define GADGET_ID_CUSTOM_MOVE_STEPSIZE (GADGET_ID_SELECTBOX_FIRST + 7)
-#define GADGET_ID_CUSTOM_MOVE_LEAVE_TYPE (GADGET_ID_SELECTBOX_FIRST + 8)
-#define GADGET_ID_CUSTOM_SMASH_TARGETS (GADGET_ID_SELECTBOX_FIRST + 9)
-#define GADGET_ID_CUSTOM_SLIPPERY_TYPE (GADGET_ID_SELECTBOX_FIRST + 10)
-#define GADGET_ID_CUSTOM_ACCESS_TYPE   (GADGET_ID_SELECTBOX_FIRST + 11)
-#define GADGET_ID_CUSTOM_ACCESS_LAYER  (GADGET_ID_SELECTBOX_FIRST + 12)
-#define GADGET_ID_CUSTOM_ACCESS_PROTECTED (GADGET_ID_SELECTBOX_FIRST + 13)
-#define GADGET_ID_CUSTOM_ACCESS_DIRECTION (GADGET_ID_SELECTBOX_FIRST + 14)
-#define GADGET_ID_CHANGE_TIME_UNITS    (GADGET_ID_SELECTBOX_FIRST + 15)
-#define GADGET_ID_CHANGE_DIRECT_ACTION (GADGET_ID_SELECTBOX_FIRST + 16)
-#define GADGET_ID_CHANGE_OTHER_ACTION  (GADGET_ID_SELECTBOX_FIRST + 17)
-#define GADGET_ID_CHANGE_SIDE          (GADGET_ID_SELECTBOX_FIRST + 18)
-#define GADGET_ID_CHANGE_PLAYER                (GADGET_ID_SELECTBOX_FIRST + 19)
-#define GADGET_ID_CHANGE_PAGE          (GADGET_ID_SELECTBOX_FIRST + 20)
-#define GADGET_ID_CHANGE_REPLACE_WHEN  (GADGET_ID_SELECTBOX_FIRST + 21)
-#define GADGET_ID_SELECT_CHANGE_PAGE   (GADGET_ID_SELECTBOX_FIRST + 22)
-#define GADGET_ID_GROUP_CHOICE_MODE    (GADGET_ID_SELECTBOX_FIRST + 23)
+#define GADGET_ID_WIND_DIRECTION       (GADGET_ID_SELECTBOX_FIRST + 2)
+#define GADGET_ID_PLAYER_SPEED         (GADGET_ID_SELECTBOX_FIRST + 3)
+#define GADGET_ID_CUSTOM_WALK_TO_ACTION        (GADGET_ID_SELECTBOX_FIRST + 4)
+#define GADGET_ID_CUSTOM_EXPLOSION_TYPE        (GADGET_ID_SELECTBOX_FIRST + 5)
+#define GADGET_ID_CUSTOM_DEADLINESS    (GADGET_ID_SELECTBOX_FIRST + 6)
+#define GADGET_ID_CUSTOM_MOVE_PATTERN  (GADGET_ID_SELECTBOX_FIRST + 7)
+#define GADGET_ID_CUSTOM_MOVE_DIRECTION        (GADGET_ID_SELECTBOX_FIRST + 8)
+#define GADGET_ID_CUSTOM_MOVE_STEPSIZE (GADGET_ID_SELECTBOX_FIRST + 9)
+#define GADGET_ID_CUSTOM_MOVE_LEAVE_TYPE (GADGET_ID_SELECTBOX_FIRST + 10)
+#define GADGET_ID_CUSTOM_SMASH_TARGETS (GADGET_ID_SELECTBOX_FIRST + 11)
+#define GADGET_ID_CUSTOM_SLIPPERY_TYPE (GADGET_ID_SELECTBOX_FIRST + 12)
+#define GADGET_ID_CUSTOM_ACCESS_TYPE   (GADGET_ID_SELECTBOX_FIRST + 13)
+#define GADGET_ID_CUSTOM_ACCESS_LAYER  (GADGET_ID_SELECTBOX_FIRST + 14)
+#define GADGET_ID_CUSTOM_ACCESS_PROTECTED (GADGET_ID_SELECTBOX_FIRST + 15)
+#define GADGET_ID_CUSTOM_ACCESS_DIRECTION (GADGET_ID_SELECTBOX_FIRST + 16)
+#define GADGET_ID_CHANGE_TIME_UNITS    (GADGET_ID_SELECTBOX_FIRST + 17)
+#define GADGET_ID_CHANGE_DIRECT_ACTION (GADGET_ID_SELECTBOX_FIRST + 18)
+#define GADGET_ID_CHANGE_OTHER_ACTION  (GADGET_ID_SELECTBOX_FIRST + 19)
+#define GADGET_ID_CHANGE_SIDE          (GADGET_ID_SELECTBOX_FIRST + 20)
+#define GADGET_ID_CHANGE_PLAYER                (GADGET_ID_SELECTBOX_FIRST + 21)
+#define GADGET_ID_CHANGE_PAGE          (GADGET_ID_SELECTBOX_FIRST + 22)
+#define GADGET_ID_CHANGE_REPLACE_WHEN  (GADGET_ID_SELECTBOX_FIRST + 23)
+#define GADGET_ID_ACTION_TYPE          (GADGET_ID_SELECTBOX_FIRST + 24)
+#define GADGET_ID_ACTION_MODE          (GADGET_ID_SELECTBOX_FIRST + 25)
+#define GADGET_ID_ACTION_ARG           (GADGET_ID_SELECTBOX_FIRST + 26)
+#define GADGET_ID_SELECT_CHANGE_PAGE   (GADGET_ID_SELECTBOX_FIRST + 27)
+#define GADGET_ID_GROUP_CHOICE_MODE    (GADGET_ID_SELECTBOX_FIRST + 28)
 
 /* textbutton identifiers */
-#define GADGET_ID_TEXTBUTTON_FIRST     (GADGET_ID_SELECTBOX_FIRST + 24)
+#define GADGET_ID_TEXTBUTTON_FIRST     (GADGET_ID_SELECTBOX_FIRST + 29)
 
 #define GADGET_ID_PROPERTIES_INFO      (GADGET_ID_TEXTBUTTON_FIRST + 0)
 #define GADGET_ID_PROPERTIES_CONFIG    (GADGET_ID_TEXTBUTTON_FIRST + 1)
 #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_INITIAL_GRAVITY      (GADGET_ID_CHECKBUTTON_FIRST + 3)
-#define GADGET_ID_STICK_ELEMENT                (GADGET_ID_CHECKBUTTON_FIRST + 4)
-#define GADGET_ID_EM_SLIPPERY_GEMS     (GADGET_ID_CHECKBUTTON_FIRST + 5)
-#define GADGET_ID_USE_SPRING_BUG       (GADGET_ID_CHECKBUTTON_FIRST + 6)
-#define GADGET_ID_GROW_INTO_DIGGABLE   (GADGET_ID_CHECKBUTTON_FIRST + 7)
-#define GADGET_ID_DOUBLE_SPEED         (GADGET_ID_CHECKBUTTON_FIRST + 8)
-#define GADGET_ID_BLOCK_LAST_FIELD     (GADGET_ID_CHECKBUTTON_FIRST + 9)
-#define GADGET_ID_SP_BLOCK_LAST_FIELD  (GADGET_ID_CHECKBUTTON_FIRST + 10)
-#define GADGET_ID_INSTANT_RELOCATION   (GADGET_ID_CHECKBUTTON_FIRST + 11)
-#define GADGET_ID_CAN_PASS_TO_WALKABLE (GADGET_ID_CHECKBUTTON_FIRST + 12)
-#define GADGET_ID_CAN_FALL_INTO_ACID   (GADGET_ID_CHECKBUTTON_FIRST + 13)
-#define GADGET_ID_CAN_MOVE_INTO_ACID   (GADGET_ID_CHECKBUTTON_FIRST + 14)
-#define GADGET_ID_DONT_COLLIDE_WITH    (GADGET_ID_CHECKBUTTON_FIRST + 15)
-#define GADGET_ID_CUSTOM_INDESTRUCTIBLE        (GADGET_ID_CHECKBUTTON_FIRST + 16)
-#define GADGET_ID_CUSTOM_CAN_EXPLODE   (GADGET_ID_CHECKBUTTON_FIRST + 17)
-#define GADGET_ID_CUSTOM_EXPLODE_FIRE  (GADGET_ID_CHECKBUTTON_FIRST + 18)
-#define GADGET_ID_CUSTOM_EXPLODE_SMASH (GADGET_ID_CHECKBUTTON_FIRST + 19)
-#define GADGET_ID_CUSTOM_EXPLODE_IMPACT        (GADGET_ID_CHECKBUTTON_FIRST + 20)
-#define GADGET_ID_CUSTOM_WALK_TO_OBJECT        (GADGET_ID_CHECKBUTTON_FIRST + 21)
-#define GADGET_ID_CUSTOM_DEADLY                (GADGET_ID_CHECKBUTTON_FIRST + 22)
-#define GADGET_ID_CUSTOM_CAN_MOVE      (GADGET_ID_CHECKBUTTON_FIRST + 23)
-#define GADGET_ID_CUSTOM_CAN_FALL      (GADGET_ID_CHECKBUTTON_FIRST + 24)
-#define GADGET_ID_CUSTOM_CAN_SMASH     (GADGET_ID_CHECKBUTTON_FIRST + 25)
-#define GADGET_ID_CUSTOM_SLIPPERY      (GADGET_ID_CHECKBUTTON_FIRST + 26)
-#define GADGET_ID_CUSTOM_ACCESSIBLE    (GADGET_ID_CHECKBUTTON_FIRST + 27)
-#define GADGET_ID_CUSTOM_GRAV_REACHABLE        (GADGET_ID_CHECKBUTTON_FIRST + 28)
-#define GADGET_ID_CUSTOM_USE_GRAPHIC   (GADGET_ID_CHECKBUTTON_FIRST + 29)
-#define GADGET_ID_CUSTOM_USE_TEMPLATE  (GADGET_ID_CHECKBUTTON_FIRST + 30)
-#define GADGET_ID_CUSTOM_CAN_CHANGE    (GADGET_ID_CHECKBUTTON_FIRST + 31)
-#define GADGET_ID_CHANGE_USE_CONTENT   (GADGET_ID_CHECKBUTTON_FIRST + 32)
-#define GADGET_ID_CHANGE_USE_EXPLOSION (GADGET_ID_CHECKBUTTON_FIRST + 33)
-#define GADGET_ID_CHANGE_ONLY_COMPLETE (GADGET_ID_CHECKBUTTON_FIRST + 34)
-#define GADGET_ID_CHANGE_USE_RANDOM    (GADGET_ID_CHECKBUTTON_FIRST + 35)
-#define GADGET_ID_CHANGE_DELAY         (GADGET_ID_CHECKBUTTON_FIRST + 36)
-#define GADGET_ID_CHANGE_BY_DIRECT_ACT (GADGET_ID_CHECKBUTTON_FIRST + 37)
-#define GADGET_ID_CHANGE_BY_OTHER_ACT  (GADGET_ID_CHECKBUTTON_FIRST + 38)
+#define GADGET_ID_STICK_ELEMENT                (GADGET_ID_CHECKBUTTON_FIRST + 3)
+#define GADGET_ID_EM_SLIPPERY_GEMS     (GADGET_ID_CHECKBUTTON_FIRST + 4)
+#define GADGET_ID_USE_SPRING_BUG       (GADGET_ID_CHECKBUTTON_FIRST + 5)
+#define GADGET_ID_USE_TIME_ORB_BUG     (GADGET_ID_CHECKBUTTON_FIRST + 6)
+#define GADGET_ID_RANDOM_BALL_CONTENT  (GADGET_ID_CHECKBUTTON_FIRST + 7)
+#define GADGET_ID_INITIAL_BALL_STATE   (GADGET_ID_CHECKBUTTON_FIRST + 8)
+#define GADGET_ID_GROW_INTO_DIGGABLE   (GADGET_ID_CHECKBUTTON_FIRST + 9)
+#define GADGET_ID_CONTINUOUS_SNAPPING  (GADGET_ID_CHECKBUTTON_FIRST + 10)
+#define GADGET_ID_BLOCK_SNAP_FIELD     (GADGET_ID_CHECKBUTTON_FIRST + 11)
+#define GADGET_ID_BLOCK_LAST_FIELD     (GADGET_ID_CHECKBUTTON_FIRST + 12)
+#define GADGET_ID_SP_BLOCK_LAST_FIELD  (GADGET_ID_CHECKBUTTON_FIRST + 13)
+#define GADGET_ID_INSTANT_RELOCATION   (GADGET_ID_CHECKBUTTON_FIRST + 14)
+#define GADGET_ID_USE_START_ELEMENT    (GADGET_ID_CHECKBUTTON_FIRST + 15)
+#define GADGET_ID_USE_ARTWORK_ELEMENT  (GADGET_ID_CHECKBUTTON_FIRST + 16)
+#define GADGET_ID_USE_EXPLOSION_ELEMENT        (GADGET_ID_CHECKBUTTON_FIRST + 17)
+#define GADGET_ID_INITIAL_GRAVITY      (GADGET_ID_CHECKBUTTON_FIRST + 18)
+#define GADGET_ID_CAN_PASS_TO_WALKABLE (GADGET_ID_CHECKBUTTON_FIRST + 19)
+#define GADGET_ID_CAN_FALL_INTO_ACID   (GADGET_ID_CHECKBUTTON_FIRST + 20)
+#define GADGET_ID_CAN_MOVE_INTO_ACID   (GADGET_ID_CHECKBUTTON_FIRST + 21)
+#define GADGET_ID_DONT_COLLIDE_WITH    (GADGET_ID_CHECKBUTTON_FIRST + 22)
+#define GADGET_ID_CUSTOM_INDESTRUCTIBLE        (GADGET_ID_CHECKBUTTON_FIRST + 23)
+#define GADGET_ID_CUSTOM_CAN_EXPLODE   (GADGET_ID_CHECKBUTTON_FIRST + 24)
+#define GADGET_ID_CUSTOM_EXPLODE_FIRE  (GADGET_ID_CHECKBUTTON_FIRST + 25)
+#define GADGET_ID_CUSTOM_EXPLODE_SMASH (GADGET_ID_CHECKBUTTON_FIRST + 26)
+#define GADGET_ID_CUSTOM_EXPLODE_IMPACT        (GADGET_ID_CHECKBUTTON_FIRST + 27)
+#define GADGET_ID_CUSTOM_WALK_TO_OBJECT        (GADGET_ID_CHECKBUTTON_FIRST + 28)
+#define GADGET_ID_CUSTOM_DEADLY                (GADGET_ID_CHECKBUTTON_FIRST + 29)
+#define GADGET_ID_CUSTOM_CAN_MOVE      (GADGET_ID_CHECKBUTTON_FIRST + 30)
+#define GADGET_ID_CUSTOM_CAN_FALL      (GADGET_ID_CHECKBUTTON_FIRST + 31)
+#define GADGET_ID_CUSTOM_CAN_SMASH     (GADGET_ID_CHECKBUTTON_FIRST + 32)
+#define GADGET_ID_CUSTOM_SLIPPERY      (GADGET_ID_CHECKBUTTON_FIRST + 33)
+#define GADGET_ID_CUSTOM_ACCESSIBLE    (GADGET_ID_CHECKBUTTON_FIRST + 34)
+#define GADGET_ID_CUSTOM_GRAV_REACHABLE        (GADGET_ID_CHECKBUTTON_FIRST + 35)
+#define GADGET_ID_CUSTOM_USE_LAST_VALUE        (GADGET_ID_CHECKBUTTON_FIRST + 36)
+#define GADGET_ID_CUSTOM_USE_GRAPHIC   (GADGET_ID_CHECKBUTTON_FIRST + 37)
+#define GADGET_ID_CUSTOM_USE_TEMPLATE  (GADGET_ID_CHECKBUTTON_FIRST + 38)
+#define GADGET_ID_CUSTOM_CAN_CHANGE    (GADGET_ID_CHECKBUTTON_FIRST + 39)
+#define GADGET_ID_CHANGE_USE_CONTENT   (GADGET_ID_CHECKBUTTON_FIRST + 40)
+#define GADGET_ID_CHANGE_USE_EXPLOSION (GADGET_ID_CHECKBUTTON_FIRST + 41)
+#define GADGET_ID_CHANGE_ONLY_COMPLETE (GADGET_ID_CHECKBUTTON_FIRST + 42)
+#define GADGET_ID_CHANGE_USE_RANDOM    (GADGET_ID_CHECKBUTTON_FIRST + 43)
+#define GADGET_ID_CHANGE_HAS_ACTION    (GADGET_ID_CHECKBUTTON_FIRST + 44)
+#define GADGET_ID_CHANGE_DELAY         (GADGET_ID_CHECKBUTTON_FIRST + 45)
+#define GADGET_ID_CHANGE_BY_DIRECT_ACT (GADGET_ID_CHECKBUTTON_FIRST + 46)
+#define GADGET_ID_CHANGE_BY_OTHER_ACT  (GADGET_ID_CHECKBUTTON_FIRST + 47)
 
 /* gadgets for buttons in element list */
-#define GADGET_ID_ELEMENTLIST_FIRST    (GADGET_ID_CHECKBUTTON_FIRST + 39)
+#define GADGET_ID_ELEMENTLIST_FIRST    (GADGET_ID_CHECKBUTTON_FIRST + 48)
 #define GADGET_ID_ELEMENTLIST_LAST     (GADGET_ID_ELEMENTLIST_FIRST +  \
                                        ED_NUM_ELEMENTLIST_BUTTONS - 1)
 
 #define ED_COUNTER_ID_LEVEL_RANDOM     6
 #define ED_COUNTER_ID_ELEMENT_VALUE1   7
 #define ED_COUNTER_ID_ELEMENT_VALUE2   8
-#define ED_COUNTER_ID_YAMYAM_CONTENT   9
-#define ED_COUNTER_ID_ENVELOPE_XSIZE   10
-#define ED_COUNTER_ID_ENVELOPE_YSIZE   11
-#define ED_COUNTER_ID_CUSTOM_SCORE     12
-#define ED_COUNTER_ID_CUSTOM_GEMCOUNT  13
-#define ED_COUNTER_ID_PUSH_DELAY_FIX   14
-#define ED_COUNTER_ID_PUSH_DELAY_RND   15
-#define ED_COUNTER_ID_DROP_DELAY_FIX   16
-#define ED_COUNTER_ID_DROP_DELAY_RND   17
-#define ED_COUNTER_ID_MOVE_DELAY_FIX   18
-#define ED_COUNTER_ID_MOVE_DELAY_RND   19
-#define ED_COUNTER_ID_EXPLOSION_DELAY  20
-#define ED_COUNTER_ID_IGNITION_DELAY   21
-#define ED_COUNTER_ID_GROUP_CONTENT    22
-#define ED_COUNTER_ID_CHANGE_DELAY_FIX 23
-#define ED_COUNTER_ID_CHANGE_DELAY_RND 24
-#define ED_COUNTER_ID_CHANGE_CONT_RND  25
-
-#define ED_NUM_COUNTERBUTTONS          26
+#define ED_COUNTER_ID_ELEMENT_VALUE3   9
+#define ED_COUNTER_ID_ELEMENT_VALUE4   10
+#define ED_COUNTER_ID_YAMYAM_CONTENT   11
+#define ED_COUNTER_ID_BALL_CONTENT     12
+#define ED_COUNTER_ID_ANDROID_CONTENT  13
+#define ED_COUNTER_ID_ENVELOPE_XSIZE   14
+#define ED_COUNTER_ID_ENVELOPE_YSIZE   15
+#define ED_COUNTER_ID_CUSTOM_SCORE     16
+#define ED_COUNTER_ID_CUSTOM_GEMCOUNT  17
+#define ED_COUNTER_ID_CUSTOM_VALUE_FIX 18
+#define ED_COUNTER_ID_CUSTOM_VALUE_RND 19
+#define ED_COUNTER_ID_PUSH_DELAY_FIX   20
+#define ED_COUNTER_ID_PUSH_DELAY_RND   21
+#define ED_COUNTER_ID_DROP_DELAY_FIX   22
+#define ED_COUNTER_ID_DROP_DELAY_RND   23
+#define ED_COUNTER_ID_MOVE_DELAY_FIX   24
+#define ED_COUNTER_ID_MOVE_DELAY_RND   25
+#define ED_COUNTER_ID_EXPLOSION_DELAY  26
+#define ED_COUNTER_ID_IGNITION_DELAY   27
+#define ED_COUNTER_ID_GROUP_CONTENT    28
+#define ED_COUNTER_ID_CHANGE_DELAY_FIX 29
+#define ED_COUNTER_ID_CHANGE_DELAY_RND 30
+#define ED_COUNTER_ID_CHANGE_CONT_RND  31
+
+#define ED_NUM_COUNTERBUTTONS          32
 
 #define ED_COUNTER_ID_LEVEL_FIRST      ED_COUNTER_ID_LEVEL_XSIZE
 #define ED_COUNTER_ID_LEVEL_LAST       ED_COUNTER_ID_LEVEL_RANDOM
 /* values for selectbox gadgets */
 #define ED_SELECTBOX_ID_TIME_OR_STEPS          0
 #define ED_SELECTBOX_ID_GAME_ENGINE_TYPE       1
-#define ED_SELECTBOX_ID_CUSTOM_ACCESS_TYPE     2
-#define ED_SELECTBOX_ID_CUSTOM_ACCESS_LAYER    3
-#define ED_SELECTBOX_ID_CUSTOM_ACCESS_PROTECTED        4
-#define ED_SELECTBOX_ID_CUSTOM_ACCESS_DIRECTION        5
-#define ED_SELECTBOX_ID_CUSTOM_WALK_TO_ACTION  6
-#define ED_SELECTBOX_ID_CUSTOM_MOVE_PATTERN    7
-#define ED_SELECTBOX_ID_CUSTOM_MOVE_DIRECTION  8
-#define ED_SELECTBOX_ID_CUSTOM_MOVE_STEPSIZE   9
-#define ED_SELECTBOX_ID_CUSTOM_MOVE_LEAVE_TYPE 10
-#define ED_SELECTBOX_ID_CUSTOM_SMASH_TARGETS   11
-#define ED_SELECTBOX_ID_CUSTOM_SLIPPERY_TYPE   12
-#define ED_SELECTBOX_ID_CUSTOM_DEADLINESS      13
-#define ED_SELECTBOX_ID_CUSTOM_EXPLOSION_TYPE  14
-#define ED_SELECTBOX_ID_CHANGE_TIME_UNITS      15
-#define ED_SELECTBOX_ID_CHANGE_DIRECT_ACTION   16
-#define ED_SELECTBOX_ID_CHANGE_OTHER_ACTION    17
-#define ED_SELECTBOX_ID_CHANGE_SIDE            18
-#define ED_SELECTBOX_ID_CHANGE_PLAYER          19
-#define ED_SELECTBOX_ID_CHANGE_PAGE            20
-#define ED_SELECTBOX_ID_CHANGE_REPLACE_WHEN    21
-#define ED_SELECTBOX_ID_SELECT_CHANGE_PAGE     22
-#define ED_SELECTBOX_ID_GROUP_CHOICE_MODE      23
-
-#define ED_NUM_SELECTBOX                       24
+#define ED_SELECTBOX_ID_WIND_DIRECTION         2
+#define ED_SELECTBOX_ID_PLAYER_SPEED           3
+#define ED_SELECTBOX_ID_CUSTOM_ACCESS_TYPE     4
+#define ED_SELECTBOX_ID_CUSTOM_ACCESS_LAYER    5
+#define ED_SELECTBOX_ID_CUSTOM_ACCESS_PROTECTED        6
+#define ED_SELECTBOX_ID_CUSTOM_ACCESS_DIRECTION        7
+#define ED_SELECTBOX_ID_CUSTOM_WALK_TO_ACTION  8
+#define ED_SELECTBOX_ID_CUSTOM_MOVE_PATTERN    9
+#define ED_SELECTBOX_ID_CUSTOM_MOVE_DIRECTION  10      
+#define ED_SELECTBOX_ID_CUSTOM_MOVE_STEPSIZE   11
+#define ED_SELECTBOX_ID_CUSTOM_MOVE_LEAVE_TYPE 12
+#define ED_SELECTBOX_ID_CUSTOM_SMASH_TARGETS   13
+#define ED_SELECTBOX_ID_CUSTOM_SLIPPERY_TYPE   14
+#define ED_SELECTBOX_ID_CUSTOM_DEADLINESS      15
+#define ED_SELECTBOX_ID_CUSTOM_EXPLOSION_TYPE  16
+#define ED_SELECTBOX_ID_CHANGE_TIME_UNITS      17
+#define ED_SELECTBOX_ID_CHANGE_DIRECT_ACTION   18
+#define ED_SELECTBOX_ID_CHANGE_OTHER_ACTION    19
+#define ED_SELECTBOX_ID_CHANGE_SIDE            20
+#define ED_SELECTBOX_ID_CHANGE_PLAYER          21
+#define ED_SELECTBOX_ID_CHANGE_PAGE            22
+#define ED_SELECTBOX_ID_CHANGE_REPLACE_WHEN    23
+#define ED_SELECTBOX_ID_ACTION_TYPE            24
+#define ED_SELECTBOX_ID_ACTION_MODE            25
+#define ED_SELECTBOX_ID_ACTION_ARG             26
+#define ED_SELECTBOX_ID_SELECT_CHANGE_PAGE     27
+#define ED_SELECTBOX_ID_GROUP_CHOICE_MODE      28
+
+#define ED_NUM_SELECTBOX                       29
 
 #define ED_SELECTBOX_ID_LEVEL_FIRST    ED_SELECTBOX_ID_TIME_OR_STEPS
-#define ED_SELECTBOX_ID_LEVEL_LAST     ED_SELECTBOX_ID_GAME_ENGINE_TYPE
+#define ED_SELECTBOX_ID_LEVEL_LAST     ED_SELECTBOX_ID_WIND_DIRECTION
 
 #define ED_SELECTBOX_ID_CUSTOM1_FIRST  ED_SELECTBOX_ID_CUSTOM_ACCESS_TYPE
 #define ED_SELECTBOX_ID_CUSTOM1_LAST   ED_SELECTBOX_ID_CUSTOM_WALK_TO_ACTION
 #define ED_GRAPHICBUTTON_ID_CHANGE_LAST   ED_GRAPHICBUTTON_ID_PASTE_CHANGE_PAGE
 
 /* values for checkbutton gadgets */
-#define ED_CHECKBUTTON_ID_INITIAL_GRAVITY      0
-#define ED_CHECKBUTTON_ID_RANDOM_RESTRICTED    1
-#define ED_CHECKBUTTON_ID_STICK_ELEMENT                2
-#define ED_CHECKBUTTON_ID_EM_SLIPPERY_GEMS     3
-#define ED_CHECKBUTTON_ID_USE_SPRING_BUG       4
-#define ED_CHECKBUTTON_ID_GROW_INTO_DIGGABLE   5
-#define ED_CHECKBUTTON_ID_DOUBLE_SPEED         6
-#define ED_CHECKBUTTON_ID_BLOCK_LAST_FIELD     7
-#define ED_CHECKBUTTON_ID_SP_BLOCK_LAST_FIELD  8
-#define ED_CHECKBUTTON_ID_INSTANT_RELOCATION   9
-#define ED_CHECKBUTTON_ID_CAN_PASS_TO_WALKABLE 10
-#define ED_CHECKBUTTON_ID_CAN_FALL_INTO_ACID   11
-#define ED_CHECKBUTTON_ID_CAN_MOVE_INTO_ACID   12
-#define ED_CHECKBUTTON_ID_DONT_COLLIDE_WITH    13
-#define ED_CHECKBUTTON_ID_CUSTOM_USE_GRAPHIC   14
-#define ED_CHECKBUTTON_ID_CUSTOM_USE_TEMPLATE  15
-#define ED_CHECKBUTTON_ID_CUSTOM_ACCESSIBLE    16
-#define ED_CHECKBUTTON_ID_CUSTOM_GRAV_REACHABLE        17
-#define ED_CHECKBUTTON_ID_CUSTOM_WALK_TO_OBJECT        18
-#define ED_CHECKBUTTON_ID_CUSTOM_INDESTRUCTIBLE        19
-#define ED_CHECKBUTTON_ID_CUSTOM_CAN_MOVE      20
-#define ED_CHECKBUTTON_ID_CUSTOM_CAN_FALL      21
-#define ED_CHECKBUTTON_ID_CUSTOM_CAN_SMASH     22
-#define ED_CHECKBUTTON_ID_CUSTOM_SLIPPERY      23
-#define ED_CHECKBUTTON_ID_CUSTOM_DEADLY                24
-#define ED_CHECKBUTTON_ID_CUSTOM_CAN_EXPLODE   25
-#define ED_CHECKBUTTON_ID_CUSTOM_EXPLODE_FIRE  26
-#define ED_CHECKBUTTON_ID_CUSTOM_EXPLODE_SMASH 27
-#define ED_CHECKBUTTON_ID_CUSTOM_EXPLODE_IMPACT        28
-#define ED_CHECKBUTTON_ID_CUSTOM_CAN_CHANGE    29
-#define ED_CHECKBUTTON_ID_CHANGE_DELAY         30
-#define ED_CHECKBUTTON_ID_CHANGE_BY_DIRECT_ACT 31
-#define ED_CHECKBUTTON_ID_CHANGE_BY_OTHER_ACT  32
-#define ED_CHECKBUTTON_ID_CHANGE_USE_EXPLOSION 33
-#define ED_CHECKBUTTON_ID_CHANGE_USE_CONTENT   34
-#define ED_CHECKBUTTON_ID_CHANGE_ONLY_COMPLETE 35
-#define ED_CHECKBUTTON_ID_CHANGE_USE_RANDOM    36
-
-#define ED_NUM_CHECKBUTTONS                    37
-
-#define ED_CHECKBUTTON_ID_LEVEL_FIRST  ED_CHECKBUTTON_ID_INITIAL_GRAVITY
+#define ED_CHECKBUTTON_ID_RANDOM_RESTRICTED    0
+#define ED_CHECKBUTTON_ID_STICK_ELEMENT                1
+#define ED_CHECKBUTTON_ID_EM_SLIPPERY_GEMS     2
+#define ED_CHECKBUTTON_ID_USE_SPRING_BUG       3
+#define ED_CHECKBUTTON_ID_USE_TIME_ORB_BUG     4
+#define ED_CHECKBUTTON_ID_RANDOM_BALL_CONTENT  5
+#define ED_CHECKBUTTON_ID_INITIAL_BALL_STATE   6
+#define ED_CHECKBUTTON_ID_GROW_INTO_DIGGABLE   7
+#define ED_CHECKBUTTON_ID_CONTINUOUS_SNAPPING  8
+#define ED_CHECKBUTTON_ID_BLOCK_SNAP_FIELD     9
+#define ED_CHECKBUTTON_ID_BLOCK_LAST_FIELD     10
+#define ED_CHECKBUTTON_ID_SP_BLOCK_LAST_FIELD  11
+#define ED_CHECKBUTTON_ID_INSTANT_RELOCATION   12
+#define ED_CHECKBUTTON_ID_USE_START_ELEMENT    13
+#define ED_CHECKBUTTON_ID_USE_ARTWORK_ELEMENT  14
+#define ED_CHECKBUTTON_ID_USE_EXPLOSION_ELEMENT        15
+#define ED_CHECKBUTTON_ID_INITIAL_GRAVITY      16
+#define ED_CHECKBUTTON_ID_CAN_PASS_TO_WALKABLE 17
+#define ED_CHECKBUTTON_ID_CAN_FALL_INTO_ACID   18
+#define ED_CHECKBUTTON_ID_CAN_MOVE_INTO_ACID   19
+#define ED_CHECKBUTTON_ID_DONT_COLLIDE_WITH    20
+#define ED_CHECKBUTTON_ID_CUSTOM_USE_GRAPHIC   21
+#define ED_CHECKBUTTON_ID_CUSTOM_USE_TEMPLATE  22
+#define ED_CHECKBUTTON_ID_CUSTOM_ACCESSIBLE    23
+#define ED_CHECKBUTTON_ID_CUSTOM_GRAV_REACHABLE        24
+#define ED_CHECKBUTTON_ID_CUSTOM_USE_LAST_VALUE        25
+#define ED_CHECKBUTTON_ID_CUSTOM_WALK_TO_OBJECT        26
+#define ED_CHECKBUTTON_ID_CUSTOM_INDESTRUCTIBLE        27
+#define ED_CHECKBUTTON_ID_CUSTOM_CAN_MOVE      28
+#define ED_CHECKBUTTON_ID_CUSTOM_CAN_FALL      29
+#define ED_CHECKBUTTON_ID_CUSTOM_CAN_SMASH     30
+#define ED_CHECKBUTTON_ID_CUSTOM_SLIPPERY      31
+#define ED_CHECKBUTTON_ID_CUSTOM_DEADLY                32
+#define ED_CHECKBUTTON_ID_CUSTOM_CAN_EXPLODE   33
+#define ED_CHECKBUTTON_ID_CUSTOM_EXPLODE_FIRE  34
+#define ED_CHECKBUTTON_ID_CUSTOM_EXPLODE_SMASH 35
+#define ED_CHECKBUTTON_ID_CUSTOM_EXPLODE_IMPACT        36
+#define ED_CHECKBUTTON_ID_CUSTOM_CAN_CHANGE    37
+#define ED_CHECKBUTTON_ID_CHANGE_DELAY         38
+#define ED_CHECKBUTTON_ID_CHANGE_BY_DIRECT_ACT 39
+#define ED_CHECKBUTTON_ID_CHANGE_BY_OTHER_ACT  40
+#define ED_CHECKBUTTON_ID_CHANGE_USE_EXPLOSION 41
+#define ED_CHECKBUTTON_ID_CHANGE_USE_CONTENT   42
+#define ED_CHECKBUTTON_ID_CHANGE_ONLY_COMPLETE 43
+#define ED_CHECKBUTTON_ID_CHANGE_USE_RANDOM    44
+#define ED_CHECKBUTTON_ID_CHANGE_HAS_ACTION    45
+
+#define ED_NUM_CHECKBUTTONS                    46
+
+#define ED_CHECKBUTTON_ID_LEVEL_FIRST  ED_CHECKBUTTON_ID_RANDOM_RESTRICTED
 #define ED_CHECKBUTTON_ID_LEVEL_LAST   ED_CHECKBUTTON_ID_RANDOM_RESTRICTED
 
 #define ED_CHECKBUTTON_ID_CUSTOM1_FIRST        ED_CHECKBUTTON_ID_CUSTOM_USE_GRAPHIC
 #define ED_CHECKBUTTON_ID_CUSTOM_LAST  ED_CHECKBUTTON_ID_CUSTOM2_LAST
 
 #define ED_CHECKBUTTON_ID_CHANGE_FIRST ED_CHECKBUTTON_ID_CUSTOM_CAN_CHANGE
-#define ED_CHECKBUTTON_ID_CHANGE_LAST  ED_CHECKBUTTON_ID_CHANGE_USE_RANDOM
+#define ED_CHECKBUTTON_ID_CHANGE_LAST  ED_CHECKBUTTON_ID_CHANGE_HAS_ACTION
 
 /* values for radiobutton gadgets */
 #define ED_RADIOBUTTON_ID_PERCENTAGE   0
 #define ED_DRAWING_ID_MAGIC_BALL_CONTENT_5     14
 #define ED_DRAWING_ID_MAGIC_BALL_CONTENT_6     15
 #define ED_DRAWING_ID_MAGIC_BALL_CONTENT_7     16
-#define ED_DRAWING_ID_AMOEBA_CONTENT           17
-#define ED_DRAWING_ID_CUSTOM_GRAPHIC           18
-#define ED_DRAWING_ID_CUSTOM_CONTENT           19
-#define ED_DRAWING_ID_CUSTOM_MOVE_ENTER                20
-#define ED_DRAWING_ID_CUSTOM_MOVE_LEAVE                21
-#define ED_DRAWING_ID_CUSTOM_CHANGE_TARGET     22
-#define ED_DRAWING_ID_CUSTOM_CHANGE_CONTENT    23
-#define ED_DRAWING_ID_CUSTOM_CHANGE_TRIGGER    24
-#define ED_DRAWING_ID_GROUP_CONTENT            25
-#define ED_DRAWING_ID_RANDOM_BACKGROUND                26
-
-#define ED_NUM_DRAWING_AREAS                   27
+#define ED_DRAWING_ID_ANDROID_CONTENT          17
+#define ED_DRAWING_ID_AMOEBA_CONTENT           18
+#define ED_DRAWING_ID_START_ELEMENT            19
+#define ED_DRAWING_ID_ARTWORK_ELEMENT          20
+#define ED_DRAWING_ID_EXPLOSION_ELEMENT                21
+#define ED_DRAWING_ID_CUSTOM_GRAPHIC           22
+#define ED_DRAWING_ID_CUSTOM_CONTENT           23
+#define ED_DRAWING_ID_CUSTOM_MOVE_ENTER                24
+#define ED_DRAWING_ID_CUSTOM_MOVE_LEAVE                25
+#define ED_DRAWING_ID_CUSTOM_CHANGE_TARGET     26
+#define ED_DRAWING_ID_CUSTOM_CHANGE_CONTENT    27
+#define ED_DRAWING_ID_CUSTOM_CHANGE_TRIGGER    28
+#define ED_DRAWING_ID_GROUP_CONTENT            29
+#define ED_DRAWING_ID_RANDOM_BACKGROUND                30
+
+#define ED_NUM_DRAWING_AREAS                   31
 
 
 /*
 
 /* values for elements with count for collecting */
 #define MIN_COLLECT_COUNT              0
-#define MAX_COLLECT_COUNT              100
+#define MAX_COLLECT_COUNT              255
 
 /* values for random placement */
 #define RANDOM_USE_PERCENTAGE          0
@@ -966,7 +1026,7 @@ static struct
     NULL,                              " ", "height",
   },
   {
-    ED_LEVEL_SETTINGS_XPOS(0),         ED_LEVEL_SETTINGS_YPOS(6),
+    ED_LEVEL_SETTINGS_XPOS(0),         ED_LEVEL_SETTINGS_YPOS(5),
     0,                                 999,
     GADGET_ID_LEVEL_GEMSLIMIT_DOWN,    GADGET_ID_LEVEL_GEMSLIMIT_UP,
     GADGET_ID_LEVEL_GEMSLIMIT_TEXT,    GADGET_ID_NONE,
@@ -974,7 +1034,7 @@ static struct
     NULL, "number of gems to collect:",        NULL
   },
   {
-    ED_LEVEL_SETTINGS_XPOS(0),         ED_LEVEL_SETTINGS_YPOS(8),
+    ED_LEVEL_SETTINGS_XPOS(0),         ED_LEVEL_SETTINGS_YPOS(7),
     0,                                 9999,
     GADGET_ID_LEVEL_TIMELIMIT_DOWN,    GADGET_ID_LEVEL_TIMELIMIT_UP,
     GADGET_ID_LEVEL_TIMELIMIT_TEXT,    GADGET_ID_NONE,
@@ -982,12 +1042,12 @@ static struct
     "time or step limit to solve level:", NULL, NULL
   },
   {
-    ED_LEVEL_SETTINGS_XPOS(0),         ED_LEVEL_SETTINGS_YPOS(10),
+    ED_LEVEL_SETTINGS_XPOS(0),         ED_LEVEL_SETTINGS_YPOS(9),
     0,                                 255,
     GADGET_ID_LEVEL_TIMESCORE_DOWN,    GADGET_ID_LEVEL_TIMESCORE_UP,
     GADGET_ID_LEVEL_TIMESCORE_TEXT,    GADGET_ID_NONE,
     &level.score[SC_TIME_BONUS],
-    "score for each 10 sec/steps left:", NULL, NULL
+    "score for each second/step left:",        NULL, NULL
   },
   {
     ED_LEVEL_SETTINGS_XPOS(0),         ED_COUNTER2_YPOS(8),
@@ -1016,6 +1076,22 @@ static struct
     NULL,                              /* will be set when used */
     NULL,                              NULL, NULL
   },
+  {
+    ED_ELEMENT_SETTINGS_XPOS(0),       ED_ELEMENT_SETTINGS_YPOS(2),
+    MIN_SCORE,                         MAX_SCORE,
+    GADGET_ID_ELEMENT_VALUE3_DOWN,     GADGET_ID_ELEMENT_VALUE3_UP,
+    GADGET_ID_ELEMENT_VALUE3_TEXT,     GADGET_ID_NONE,
+    NULL,                              /* will be set when used */
+    NULL,                              NULL, NULL
+  },
+  {
+    ED_ELEMENT_SETTINGS_XPOS(0),       ED_ELEMENT_SETTINGS_YPOS(3),
+    MIN_SCORE,                         MAX_SCORE,
+    GADGET_ID_ELEMENT_VALUE4_DOWN,     GADGET_ID_ELEMENT_VALUE4_UP,
+    GADGET_ID_ELEMENT_VALUE4_TEXT,     GADGET_ID_NONE,
+    NULL,                              /* will be set when used */
+    NULL,                              NULL, NULL
+  },
   {
     ED_ELEMENT_SETTINGS_XPOS(0),       ED_ELEMENT_SETTINGS_YPOS(3),
     MIN_ELEMENT_CONTENTS,              MAX_ELEMENT_CONTENTS,
@@ -1024,6 +1100,22 @@ static struct
     &level.num_yamyam_contents,
     NULL,                              NULL, "number of content areas"
   },
+  {
+    ED_ELEMENT_SETTINGS_XPOS(0),       ED_ELEMENT_SETTINGS_YPOS(4),
+    MIN_ELEMENT_CONTENTS,              MAX_ELEMENT_CONTENTS,
+    GADGET_ID_BALL_CONTENT_DOWN,       GADGET_ID_BALL_CONTENT_UP,
+    GADGET_ID_BALL_CONTENT_TEXT,       GADGET_ID_NONE,
+    &level.num_ball_contents,
+    NULL,                              NULL, "number of content areas"
+  },
+  {
+    ED_ELEMENT_SETTINGS_XPOS(0),       ED_ELEMENT_SETTINGS_YPOS(4),
+    MIN_ANDROID_ELEMENTS,              MAX_ANDROID_ELEMENTS,
+    GADGET_ID_ANDROID_CONTENT_DOWN,    GADGET_ID_ANDROID_CONTENT_UP,
+    GADGET_ID_ANDROID_CONTENT_TEXT,    GADGET_ID_NONE,
+    &level.num_android_clone_elements,
+    NULL,                              NULL, "number of clonable elements"
+  },
   {
     ED_ELEMENT_SETTINGS_XPOS(0),       ED_ELEMENT_SETTINGS_YPOS(0),
     MIN_ENVELOPE_XSIZE,                        MAX_ENVELOPE_XSIZE,
@@ -1048,16 +1140,32 @@ static struct
     MIN_SCORE,                         MAX_SCORE,
     GADGET_ID_CUSTOM_SCORE_DOWN,       GADGET_ID_CUSTOM_SCORE_UP,
     GADGET_ID_CUSTOM_SCORE_TEXT,       GADGET_ID_NONE,
-    &custom_element.collect_score,
-    NULL,                              "score", " "
+    &custom_element.collect_score_initial,
+    NULL,                              "CE score", " "
   },
   {
     -1,                                        ED_ELEMENT_SETTINGS_YPOS(6),
     MIN_COLLECT_COUNT,                 MAX_COLLECT_COUNT,
     GADGET_ID_CUSTOM_GEMCOUNT_DOWN,    GADGET_ID_CUSTOM_GEMCOUNT_UP,
     GADGET_ID_CUSTOM_GEMCOUNT_TEXT,    GADGET_ID_CUSTOM_SCORE_UP,
-    &custom_element.collect_count,
-    NULL,                              "count", NULL
+    &custom_element.collect_count_initial,
+    NULL,                              "CE count", NULL
+  },
+  {
+    ED_ELEMENT_SETTINGS_XPOS(0),       ED_ELEMENT_SETTINGS_YPOS(12),
+    0,                                 9999,
+    GADGET_ID_CUSTOM_VALUE_FIX_DOWN,   GADGET_ID_CUSTOM_VALUE_FIX_UP,
+    GADGET_ID_CUSTOM_VALUE_FIX_TEXT,   GADGET_ID_NONE,
+    &custom_element.ce_value_fixed_initial,
+    NULL,                              "CE value", NULL
+  },
+  {
+    ED_ELEMENT_SETTINGS_XPOS(0),       ED_ELEMENT_SETTINGS_YPOS(12),
+    0,                                 9999,
+    GADGET_ID_CUSTOM_VALUE_RND_DOWN,   GADGET_ID_CUSTOM_VALUE_RND_UP,
+    GADGET_ID_CUSTOM_VALUE_RND_TEXT,   GADGET_ID_CUSTOM_VALUE_FIX_UP,
+    &custom_element.ce_value_random_initial,
+    NULL,                              "+random", NULL
   },
   {
     ED_ELEMENT_SETTINGS_XPOS(1),       ED_ELEMENT_SETTINGS_YPOS(7),
@@ -1146,7 +1254,7 @@ static struct
     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,
+    NULL,                              "CE delay", NULL,
   },
   {
     -1,                                        ED_ELEMENT_SETTINGS_YPOS(2),
@@ -1232,6 +1340,30 @@ static struct ValueTextInfo options_game_engine_type[] =
   { -1,                                NULL                            }
 };
 
+static struct ValueTextInfo options_wind_direction[] =
+{
+  { MV_START_NONE,             "none"                          },
+  { MV_START_LEFT,             "left"                          },
+  { MV_START_RIGHT,            "right"                         },
+  { MV_START_UP,               "up"                            },
+  { MV_START_DOWN,             "down"                          },
+
+  { -1,                                NULL                            }
+};
+
+static struct ValueTextInfo options_player_speed[] =
+{
+  { 0,                         "frozen"                        },
+  { 1,                         "very slow"                     },
+  { 2,                         "slow"                          },
+  { 4,                         "normal"                        },
+  { 8,                         "fast"                          },
+  { 16,                                "very fast"                     },
+  { 32,                                "ultrafast"                     },
+
+  { -1,                                NULL                            }
+};
+
 static struct ValueTextInfo options_access_type[] =
 {
   { EP_WALKABLE,               "walkable"                      },
@@ -1259,7 +1391,7 @@ static struct ValueTextInfo options_access_protected[] =
 
 static struct ValueTextInfo options_access_direction[] =
 {
-  { MV_NO_DIRECTIONS,          "no direction"                  },
+  { MV_NO_DIRECTION          "no direction"                  },
   { MV_LEFT,                   "left"                          },
   { MV_RIGHT,                  "right"                         },
   { MV_UP,                     "up"                            },
@@ -1299,6 +1431,7 @@ static struct ValueTextInfo options_move_pattern[] =
   { MV_HORIZONTAL,             "horizontal"                    },
   { MV_VERTICAL,               "vertical"                      },
   { MV_ALL_DIRECTIONS,         "all directions"                },
+  { MV_WIND_DIRECTION,         "wind direction"                },
   { MV_TOWARDS_PLAYER,         "towards player"                },
   { MV_AWAY_FROM_PLAYER,       "away from player"              },
   { MV_ALONG_LEFT_SIDE,                "along left side"               },
@@ -1337,9 +1470,7 @@ static struct ValueTextInfo options_move_stepsize[] =
   { 4,                         "normal"                        },
   { 8,                         "fast"                          },
   { 16,                                "very fast"                     },
-#if 1
   { 32,                                "even faster"                   },
-#endif
 
   { -1,                                NULL                            }
 };
@@ -1388,9 +1519,6 @@ static struct ValueTextInfo options_explosion_type[] =
   { EXPLODES_3X3,              "3x3"                           },
   { EXPLODES_CROSS,            "3+3"                           },
   { EXPLODES_1X1,              "1x1"                           },
-#if 0
-  { EP_INDESTRUCTIBLE,         "indestructible"                },
-#endif
 
   { -1,                                NULL                            }
 };
@@ -1407,24 +1535,26 @@ static struct ValueTextInfo options_change_direct_action[] =
 {
   { CE_TOUCHED_BY_PLAYER,      "touched by player"             },
   { CE_PRESSED_BY_PLAYER,      "pressed by player"             },
+  { CE_SWITCHED_BY_PLAYER,     "switched by player"            },
+  { CE_SNAPPED_BY_PLAYER,      "snapped by player"             },
   { CE_PUSHED_BY_PLAYER,       "pushed by player"              },
   { CE_ENTERED_BY_PLAYER,      "entered by player"             },
   { CE_LEFT_BY_PLAYER,         "left by player"                },
   { CE_DROPPED_BY_PLAYER,      "dropped/thrown by player"      },
   { CE_SWITCHED,               "switched"                      },
-#if 1
   { CE_HITTING_SOMETHING,      "hitting something"             },
   { CE_HIT_BY_SOMETHING,       "hit by something"              },
-#else
-  { CE_HITTING_SOMETHING,      "collision"                     },
-#endif
-
 #if 0
   { CE_BLOCKED,                        "blocked"                       },
 #endif
-
   { CE_IMPACT,                 "impact (on something)"         },
   { CE_SMASHED,                        "smashed (from above)"          },
+#if 0
+  { CE_VALUE_CHANGES,          "CE value changes"              },
+  { CE_SCORE_CHANGES,          "CE score changes"              },
+#endif
+  { CE_VALUE_GETS_ZERO,                "CE value gets 0"               },
+  { CE_SCORE_GETS_ZERO,                "CE score gets 0"               },
 
   { -1,                                NULL                            }
 };
@@ -1433,6 +1563,8 @@ static struct ValueTextInfo options_change_other_action[] =
 {
   { CE_PLAYER_TOUCHES_X,       "player touches"                },
   { CE_PLAYER_PRESSES_X,       "player presses"                },
+  { CE_PLAYER_SWITCHES_X,      "player switches"               },
+  { CE_PLAYER_SNAPS_X,         "player snaps"                  },
   { CE_PLAYER_PUSHES_X,                "player pushes"                 },
   { CE_PLAYER_ENTERS_X,                "player enters"                 },
   { CE_PLAYER_LEAVES_X,                "player leaves"                 },
@@ -1440,13 +1572,18 @@ static struct ValueTextInfo options_change_other_action[] =
   { CE_PLAYER_COLLECTS_X,      "player collects"               },
   { CE_PLAYER_DROPS_X,         "player drops/throws"           },
   { CE_TOUCHING_X,             "touching"                      },
-#if 1
   { CE_HITTING_X,              "hitting"                       },
+  { CE_DIGGING_X,              "digging"                       },
   { CE_HIT_BY_X,               "hit by"                        },
-#endif
   { CE_SWITCH_OF_X,            "switch of"                     },
   { CE_CHANGE_OF_X,            "change by page of"             },
   { CE_EXPLOSION_OF_X,         "explosion of"                  },
+  { CE_MOVE_OF_X,              "move of"                       },
+  { CE_CREATION_OF_X,          "creation of"                   },
+  { CE_VALUE_CHANGES_OF_X,     "CE value changes of"           },
+  { CE_SCORE_CHANGES_OF_X,     "CE score changes of"           },
+  { CE_VALUE_GETS_ZERO_OF_X,   "CE value gets 0 of"            },
+  { CE_SCORE_GETS_ZERO_OF_X,   "CE score gets 0 of"            },
 
   { -1,                                NULL                            }
 };
@@ -1526,6 +1663,277 @@ static struct ValueTextInfo options_change_replace_when[] =
   { -1,                                NULL                            }
 };
 
+static struct ValueTextInfo options_action_type[] =
+{
+  { CA_NO_ACTION,              "no action"                     },
+  { CA_UNDEFINED,              " "                             },
+  { CA_HEADLINE_LEVEL_ACTIONS, "[level actions]"               },
+  { CA_RESTART_LEVEL,          "restart level"                 },
+  { CA_SHOW_ENVELOPE,          "show envelope"                 },
+  { CA_SET_LEVEL_TIME,         "set time"                      },
+  { CA_SET_LEVEL_SCORE,                "set score"                     },
+  { CA_SET_LEVEL_GEMS,         "set needed gems"               },
+  { CA_SET_LEVEL_WIND,         "set wind dir."                 },
+  { CA_UNDEFINED,              " "                             },
+  { CA_HEADLINE_PLAYER_ACTIONS,        "[player actions]"              },
+  { CA_MOVE_PLAYER,            "move player"                   },
+  { CA_EXIT_PLAYER,            "exit player"                   },
+  { CA_KILL_PLAYER,            "kill player"                   },
+  { CA_SET_PLAYER_KEYS,                "set keys"                      },
+  { CA_SET_PLAYER_SPEED,       "set speed"                     },
+  { CA_SET_PLAYER_SHIELD,      "set shield"                    },
+  { CA_SET_PLAYER_GRAVITY,     "set gravity"                   },
+  { CA_SET_PLAYER_ARTWORK,     "set artwork"                   },
+  { CA_UNDEFINED,              " "                             },
+  { CA_HEADLINE_CE_ACTIONS,    "[CE actions]"                  },
+  { CA_SET_CE_VALUE,           "set CE value"                  },
+  { CA_SET_CE_SCORE,           "set CE score"                  },
+  { CA_UNDEFINED,              " "                             },
+  { CA_HEADLINE_ENGINE_ACTIONS,        "[engine actions]"              },
+  { CA_SET_ENGINE_SCAN_MODE,   "set scan mode"                 },
+
+  { -1,                                NULL                            }
+};
+
+static struct ValueTextInfo options_action_mode_none[] =
+{
+  { CA_MODE_UNDEFINED,         " "                             },
+
+  { -1,                                NULL                            }
+};
+
+static struct ValueTextInfo options_action_mode_assign[] =
+{
+  { CA_MODE_SET,               "="                             },
+
+  { -1,                                NULL                            }
+};
+
+static struct ValueTextInfo options_action_mode_add_remove[] =
+{
+  { CA_MODE_ADD,               "+"                             },
+  { CA_MODE_SUBTRACT,          "-"                             },
+
+  { -1,                                NULL                            }
+};
+
+static struct ValueTextInfo options_action_mode_calculate[] =
+{
+  { CA_MODE_SET,               "="                             },
+  { CA_MODE_ADD,               "+"                             },
+  { CA_MODE_SUBTRACT,          "-"                             },
+  { CA_MODE_MULTIPLY,          "*"                             },
+  { CA_MODE_DIVIDE,            "/"                             },
+  { CA_MODE_MODULO,            "%"                             },
+
+  { -1,                                NULL                            }
+};
+
+static struct ValueTextInfo options_action_arg_none[] =
+{
+  { CA_ARG_UNDEFINED,          "         "                     },
+
+  { -1,                                NULL                            }
+};
+
+static struct ValueTextInfo options_action_arg_player[] =
+{
+  { CA_ARG_PLAYER_HEADLINE,    "[player]"                      },
+  { CA_ARG_PLAYER_1,           "1"                             },
+  { CA_ARG_PLAYER_2,           "2"                             },
+  { CA_ARG_PLAYER_3,           "3"                             },
+  { CA_ARG_PLAYER_4,           "4"                             },
+  { CA_ARG_PLAYER_ANY,         "any"                           },
+  { CA_ARG_PLAYER_TRIGGER,     "trigger"                       },
+
+  { -1,                                NULL                            }
+};
+
+static struct ValueTextInfo options_action_arg_number[] =
+{
+  { CA_ARG_NUMBER_HEADLINE,    "[number]"                      },
+  { CA_ARG_0,                  "0"                             },
+  { CA_ARG_1,                  "1"                             },
+  { CA_ARG_2,                  "2"                             },
+  { CA_ARG_3,                  "3"                             },
+  { CA_ARG_4,                  "4"                             },
+  { CA_ARG_5,                  "5"                             },
+  { CA_ARG_10,                 "10"                            },
+  { CA_ARG_100,                        "100"                           },
+  { CA_ARG_1000,               "1000"                          },
+  { CA_ARG_UNDEFINED,          " "                             },
+  { CA_ARG_NUMBER_MIN,         "min"                           },
+  { CA_ARG_NUMBER_MAX,         "max"                           },
+  { CA_ARG_UNDEFINED,          " "                             },
+  { CA_ARG_NUMBER_RESET,       "reset"                         },
+  { CA_ARG_UNDEFINED,          " "                             },
+  { CA_ARG_NUMBER_CE_VALUE,    "CE value"                      },
+  { CA_ARG_NUMBER_CE_SCORE,    "CE score"                      },
+  { CA_ARG_NUMBER_CE_DELAY,    "CE delay"                      },
+  { CA_ARG_UNDEFINED,          " "                             },
+  { CA_ARG_NUMBER_LEVEL_TIME,  "time"                          },
+  { CA_ARG_NUMBER_LEVEL_GEMS,  "gems"                          },
+  { CA_ARG_NUMBER_LEVEL_SCORE, "score"                         },
+  { CA_ARG_UNDEFINED,          " "                             },
+  { CA_ARG_ELEMENT_CV_HEADLINE,        "[CE value]"                    },
+  { CA_ARG_ELEMENT_CV_TARGET,  "target"                        },
+  { CA_ARG_ELEMENT_CV_TRIGGER, "trigger"                       },
+  { CA_ARG_UNDEFINED,          " "                             },
+  { CA_ARG_ELEMENT_CS_HEADLINE,        "[CE score]"                    },
+  { CA_ARG_ELEMENT_CS_TARGET,  "target"                        },
+  { CA_ARG_ELEMENT_CS_TRIGGER, "trigger"                       },
+
+  { -1,                                NULL                            }
+};
+
+static struct ValueTextInfo options_action_arg_value[] =
+{
+  { CA_ARG_NUMBER_HEADLINE,    "[number]"                      },
+  { CA_ARG_0,                  "0"                             },
+  { CA_ARG_1,                  "1"                             },
+  { CA_ARG_2,                  "2"                             },
+  { CA_ARG_3,                  "3"                             },
+  { CA_ARG_4,                  "4"                             },
+  { CA_ARG_5,                  "5"                             },
+  { CA_ARG_10,                 "10"                            },
+  { CA_ARG_100,                        "100"                           },
+  { CA_ARG_1000,               "1000"                          },
+  { CA_ARG_UNDEFINED,          " "                             },
+  { CA_ARG_NUMBER_MIN,         "min"                           },
+  { CA_ARG_NUMBER_MAX,         "max"                           },
+  { CA_ARG_UNDEFINED,          " "                             },
+  { CA_ARG_NUMBER_RESET,       "reset"                         },
+  { CA_ARG_UNDEFINED,          " "                             },
+  { CA_ARG_NUMBER_CE_VALUE,    "CE value"                      },
+  { CA_ARG_NUMBER_CE_SCORE,    "CE score"                      },
+  { CA_ARG_NUMBER_CE_DELAY,    "CE delay"                      },
+  { CA_ARG_UNDEFINED,          " "                             },
+  { CA_ARG_NUMBER_LEVEL_TIME,  "time"                          },
+  { CA_ARG_NUMBER_LEVEL_GEMS,  "gems"                          },
+  { CA_ARG_NUMBER_LEVEL_SCORE, "score"                         },
+  { CA_ARG_UNDEFINED,          " "                             },
+  { CA_ARG_ELEMENT_CV_HEADLINE,        "[CE value]"                    },
+  { CA_ARG_ELEMENT_CV_TARGET,  "target"                        },
+  { CA_ARG_ELEMENT_CV_TRIGGER, "trigger"                       },
+  { CA_ARG_UNDEFINED,          " "                             },
+  { CA_ARG_ELEMENT_CS_HEADLINE,        "[CE score]"                    },
+  { CA_ARG_ELEMENT_CS_TARGET,  "target"                        },
+  { CA_ARG_ELEMENT_CS_TRIGGER, "trigger"                       },
+  { CA_ARG_UNDEFINED,          " "                             },
+  { CA_ARG_ELEMENT_NR_HEADLINE,        "[element]"                     },
+  { CA_ARG_ELEMENT_NR_TARGET,  "target"                        },
+  { CA_ARG_ELEMENT_NR_TRIGGER, "trigger"                       },
+
+  { -1,                                NULL                            }
+};
+
+static struct ValueTextInfo options_action_arg_envelope[] =
+{
+  { CA_ARG_NUMBER_HEADLINE,    "[number]"                      },
+  { CA_ARG_1,                  "1"                             },
+  { CA_ARG_2,                  "2"                             },
+  { CA_ARG_3,                  "3"                             },
+  { CA_ARG_4,                  "4"                             },
+  { CA_ARG_UNDEFINED,          " "                             },
+  { CA_ARG_ELEMENT_HEADLINE,   "[element]"                     },
+  { CA_ARG_ELEMENT_TARGET,     "target"                        },
+  { CA_ARG_ELEMENT_TRIGGER,    "trigger"                       },
+
+  { -1,                                NULL                            }
+};
+
+static struct ValueTextInfo options_action_arg_key[] =
+{
+  { CA_ARG_NUMBER_HEADLINE,    "[number]"                      },
+  { CA_ARG_1,                  "1"                             },
+  { CA_ARG_2,                  "2"                             },
+  { CA_ARG_3,                  "3"                             },
+  { CA_ARG_4,                  "4"                             },
+  { CA_ARG_5,                  "5"                             },
+  { CA_ARG_6,                  "6"                             },
+  { CA_ARG_7,                  "7"                             },
+  { CA_ARG_8,                  "8"                             },
+  { CA_ARG_UNDEFINED,          " "                             },
+  { CA_ARG_ELEMENT_HEADLINE,   "[element]"                     },
+  { CA_ARG_ELEMENT_TARGET,     "target"                        },
+  { CA_ARG_ELEMENT_TRIGGER,    "trigger"                       },
+
+  { -1,                                NULL                            }
+};
+
+static struct ValueTextInfo options_action_arg_speed[] =
+{
+  { CA_ARG_SPEED_HEADLINE,     "[speed]"                       },
+  { CA_ARG_SPEED_NOT_MOVING,   "frozen"                        },
+  { CA_ARG_SPEED_VERY_SLOW,    "very slow"                     },
+  { CA_ARG_SPEED_SLOW,         "slow"                          },
+  { CA_ARG_SPEED_NORMAL,       "normal"                        },
+  { CA_ARG_SPEED_FAST,         "fast"                          },
+  { CA_ARG_SPEED_VERY_FAST,    "very fast"                     },
+  { CA_ARG_SPEED_EVEN_FASTER,  "ultrafast"                     },
+  { CA_ARG_UNDEFINED,          " "                             },
+  { CA_ARG_SPEED_SLOWER,       "slower"                        },
+  { CA_ARG_SPEED_FASTER,       "faster"                        },
+  { CA_ARG_UNDEFINED,          " "                             },
+  { CA_ARG_SPEED_RESET,                "reset"                         },
+
+  { -1,                                NULL                            }
+};
+
+static struct ValueTextInfo options_action_arg_shield[] =
+{
+  { CA_ARG_SHIELD_HEADLINE,    "[shield]"                      },
+  { CA_ARG_SHIELD_OFF,         "off"                           },
+  { CA_ARG_SHIELD_NORMAL,      "normal"                        },
+  { CA_ARG_SHIELD_DEADLY,      "deadly"                        },
+
+  { -1,                                NULL                            }
+};
+
+static struct ValueTextInfo options_action_arg_artwork[] =
+{
+  { CA_ARG_ELEMENT_HEADLINE,   "[element]"                     },
+  { CA_ARG_ELEMENT_TARGET,     "target"                        },
+  { CA_ARG_ELEMENT_TRIGGER,    "trigger"                       },
+  { CA_ARG_UNDEFINED,          " "                             },
+  { CA_ARG_ELEMENT_RESET,      "reset"                         },
+
+  { -1,                                NULL                            }
+};
+
+static struct ValueTextInfo options_action_arg_gravity[] =
+{
+  { CA_ARG_GRAVITY_HEADLINE,   "[gravity]"                     },
+  { CA_ARG_GRAVITY_ON,         "on"                            },
+  { CA_ARG_GRAVITY_OFF,                "off"                           },
+  { CA_ARG_GRAVITY_TOGGLE,     "toggle"                        },
+
+  { -1,                                NULL                            }
+};
+
+static struct ValueTextInfo options_action_arg_direction[] =
+{
+  { CA_ARG_DIRECTION_HEADLINE, "[dir.]"                        },
+  { CA_ARG_DIRECTION_NONE,     "none"                          },
+  { CA_ARG_DIRECTION_LEFT,     "left"                          },
+  { CA_ARG_DIRECTION_RIGHT,    "right"                         },
+  { CA_ARG_DIRECTION_UP,       "up"                            },
+  { CA_ARG_DIRECTION_DOWN,     "down"                          },
+  { CA_ARG_DIRECTION_TRIGGER,  "trigger"                       },
+  { CA_ARG_DIRECTION_TRIGGER_BACK, "-trigger"                  },
+
+  { -1,                                NULL                            }
+};
+
+static struct ValueTextInfo options_action_arg_scan_mode[] =
+{
+  { CA_ARG_SCAN_MODE_HEADLINE, "[mode]"                        },
+  { CA_ARG_SCAN_MODE_NORMAL,   "normal"                        },
+  { CA_ARG_SCAN_MODE_REVERSE,  "reverse"                       },
+
+  { -1,                                NULL                            }
+};
+
 static char options_change_page_strings[MAX_CHANGE_PAGES][10];
 static struct ValueTextInfo options_change_page[MAX_CHANGE_PAGES + 1] =
 {
@@ -1543,6 +1951,44 @@ static struct ValueTextInfo options_group_choice_mode[] =
   { -1,                                NULL                            }
 };
 
+static struct ValueTextInfo *action_arg_modes[] =
+{
+  options_action_mode_none,
+  options_action_mode_assign,
+  options_action_mode_add_remove,
+  options_action_mode_calculate,
+};
+
+static struct
+{
+  int value;
+  int mode;
+  struct ValueTextInfo *options;
+}
+action_arg_options[] =
+{
+  { CA_NO_ACTION,              0,      options_action_arg_none,        },
+  { CA_EXIT_PLAYER,            0,      options_action_arg_player,      },
+  { CA_KILL_PLAYER,            0,      options_action_arg_player,      },
+  { CA_MOVE_PLAYER,            0,      options_action_arg_direction,   },
+  { CA_RESTART_LEVEL,          0,      options_action_arg_none,        },
+  { CA_SHOW_ENVELOPE,          0,      options_action_arg_envelope,    },
+  { CA_SET_LEVEL_TIME,         3,      options_action_arg_number,      },
+  { CA_SET_LEVEL_GEMS,         3,      options_action_arg_number,      },
+  { CA_SET_LEVEL_SCORE,                3,      options_action_arg_number,      },
+  { CA_SET_LEVEL_WIND,         1,      options_action_arg_direction,   },
+  { CA_SET_PLAYER_KEYS,                2,      options_action_arg_key,         },
+  { CA_SET_PLAYER_SPEED,       1,      options_action_arg_speed,       },
+  { CA_SET_PLAYER_SHIELD,      1,      options_action_arg_shield,      },
+  { CA_SET_PLAYER_GRAVITY,     1,      options_action_arg_gravity,     },
+  { CA_SET_PLAYER_ARTWORK,     1,      options_action_arg_artwork,     },
+  { CA_SET_CE_VALUE,           3,      options_action_arg_value,       },
+  { CA_SET_CE_SCORE,           3,      options_action_arg_value,       },
+  { CA_SET_ENGINE_SCAN_MODE,   1,      options_action_arg_scan_mode,   },
+
+  { -1,                                FALSE,  NULL                            }
+};
+
 static struct
 {
   int x, y;
@@ -1557,7 +2003,7 @@ static struct
   /* ---------- level and editor settings ---------------------------------- */
 
   {
-    -1,                                        ED_LEVEL_SETTINGS_YPOS(8),
+    -1,                                        ED_LEVEL_SETTINGS_YPOS(7),
     GADGET_ID_TIME_OR_STEPS,           GADGET_ID_LEVEL_TIMELIMIT_UP,
     -1,
     options_time_or_steps,
@@ -1565,15 +2011,34 @@ static struct
     NULL, "(0 => no limit)",           "time or step limit"
   },
   {
-    ED_LEVEL_SETTINGS_XPOS(0),         ED_LEVEL_SETTINGS_YPOS(5),
+    ED_LEVEL_SETTINGS_XPOS(0),         ED_LEVEL_SETTINGS_YPOS(11),
     GADGET_ID_GAME_ENGINE_TYPE,                GADGET_ID_NONE,
     -1,
     options_game_engine_type,
     &level.game_engine_type,
     "game engine:", NULL,              "game engine"
   },
+  {
+    ED_LEVEL_SETTINGS_XPOS(0),         ED_LEVEL_SETTINGS_YPOS(10),
+    GADGET_ID_WIND_DIRECTION,          GADGET_ID_NONE,
+    -1,
+    options_wind_direction,
+    &level.wind_direction_initial,
+    "initial wind direction:", NULL,   "initial wind direction"
+  },
 
-  /* ---------- element settings: configure 1 (custom elements) ----------- */
+  /* ---------- element settings: configure (several elements) ------------- */
+
+  {
+    ED_ELEMENT_SETTINGS_XPOS(0),       ED_ELEMENT_SETTINGS_YPOS(5),
+    GADGET_ID_PLAYER_SPEED,            GADGET_ID_NONE,
+    -1,
+    options_player_speed,
+    &level.initial_player_stepsize[0],
+    "initial player speed:", NULL,     "initial player speed"
+  },
+
+  /* ---------- element settings: configure 1 (custom elements) ------------ */
 
   {
     ED_ELEMENT_SETTINGS_XPOS(1),       ED_ELEMENT_SETTINGS_YPOS(3),
@@ -1616,7 +2081,7 @@ static struct
     NULL, NULL,                                "diggable/collectible/pushable"
   },
 
-  /* ---------- element settings: configure 2 (custom elements) ----------- */
+  /* ---------- element settings: configure 2 (custom elements) ------------ */
 
   {
     ED_ELEMENT_SETTINGS_XPOS(1),       ED_ELEMENT_SETTINGS_YPOS(1),
@@ -1715,7 +2180,7 @@ static struct
     -1,
     options_change_trigger_side,
     &custom_element_change.trigger_side,
-    "at", "side",                      "element side that causes change"
+    "at", "side",                      "element side triggering change"
   },
   {
     ED_ELEMENT_SETTINGS_XPOS(2),       ED_ELEMENT_SETTINGS_YPOS(7),
@@ -1741,6 +2206,30 @@ static struct
     &custom_element_change.replace_when,
     "replace when", NULL,              "which elements can be replaced"
   },
+  {
+    ED_ELEMENT_SETTINGS_XPOS(1),       ED_ELEMENT_SETTINGS_YPOS(13),
+    GADGET_ID_ACTION_TYPE,             GADGET_ID_NONE,
+    -1,
+    options_action_type,
+    &custom_element_change.action_type,
+    NULL, NULL,                                "action on specified condition"
+  },
+  {
+    -1,                                        ED_ELEMENT_SETTINGS_YPOS(13),
+    GADGET_ID_ACTION_MODE,             GADGET_ID_ACTION_TYPE,
+    -1,
+    options_action_mode_none,
+    &custom_element_change.action_mode,
+    NULL, NULL,                                "action operator"
+  },
+  {
+    -1,                                        ED_ELEMENT_SETTINGS_YPOS(13),
+    GADGET_ID_ACTION_ARG,              GADGET_ID_ACTION_MODE,
+    -1,
+    options_action_arg_none,
+    &custom_element_change.action_arg,
+    NULL, NULL,                                "action parameter"
+  },
   {
     ED_ELEMENT_SETTINGS_XPOS(1),       ED_ELEMENT_SETTINGS_YPOS(14),
     GADGET_ID_SELECT_CHANGE_PAGE,      GADGET_ID_NONE,
@@ -1772,7 +2261,6 @@ static struct
   char *text_left, *text_right, *infotext;
 } textbutton_info[ED_NUM_TEXTBUTTONS] =
 {
-#if 1
   {
     ED_ELEMENT_SETTINGS_XPOS(0),       ED_COUNTER_YPOS(1),
     GADGET_ID_PROPERTIES_INFO,         GADGET_ID_NONE,
@@ -1803,26 +2291,6 @@ static struct
     8,                                 "Change",
     NULL, NULL,                                "Custom element change configuration"
   },
-#else
-  {
-    ED_ELEMENT_SETTINGS_XPOS(0),       ED_COUNTER_YPOS(1),
-    GADGET_ID_PROPERTIES_INFO,         GADGET_ID_NONE,
-    11,                                        "Information",                  
-    NULL, NULL,                                "Show information about element"
-  },
-  {
-    ED_ELEMENT_SETTINGS_XPOS(0) + 166, ED_COUNTER_YPOS(1),
-    GADGET_ID_PROPERTIES_CONFIG,       GADGET_ID_NONE,
-    11,                                        "Configure",
-    NULL, NULL,                                "Configure element properties"
-  },
-  {
-    ED_ELEMENT_SETTINGS_XPOS(0) + 332, ED_COUNTER_YPOS(1),
-    GADGET_ID_PROPERTIES_CHANGE,       GADGET_ID_NONE,
-    11,                                        "Advanced",
-    NULL, NULL,                                "Advanced element configuration"
-  },
-#endif
   {
     -1,                                        ED_ELEMENT_SETTINGS_YPOS(2),
     GADGET_ID_SAVE_AS_TEMPLATE,                GADGET_ID_CUSTOM_USE_TEMPLATE,
@@ -2003,13 +2471,6 @@ static struct
 {
   /* ---------- level and editor settings ---------------------------------- */
 
-  {
-    ED_LEVEL_SETTINGS_XPOS(0),         ED_LEVEL_SETTINGS_YPOS(11),
-    GADGET_ID_INITIAL_GRAVITY,         GADGET_ID_NONE,
-    &level.initial_gravity,
-    NULL,
-    "initial gravity",                 "set initial level gravity"
-  },
   {
     ED_LEVEL_SETTINGS_XPOS(0),         ED_COUNTER2_YPOS(9) - MINI_TILEY,
     GADGET_ID_RANDOM_RESTRICTED,       GADGET_ID_NONE,
@@ -2035,12 +2496,33 @@ static struct
     "slip down from certain flat walls","use EM style slipping behaviour"
   },
   {
-    ED_ELEMENT_SETTINGS_XPOS(0),       ED_ELEMENT_SETTINGS_YPOS(1),
+    ED_ELEMENT_SETTINGS_XPOS(0),       ED_ELEMENT_SETTINGS_YPOS(2),
     GADGET_ID_USE_SPRING_BUG,          GADGET_ID_NONE,
     &level.use_spring_bug,
     NULL,
     "use spring pushing bug",          "use odd spring pushing behaviour"
   },
+  {
+    ED_ELEMENT_SETTINGS_XPOS(0),       ED_ELEMENT_SETTINGS_YPOS(1),
+    GADGET_ID_USE_TIME_ORB_BUG,                GADGET_ID_NONE,
+    &level.use_time_orb_bug,
+    NULL,
+    "use time orb bug",                        "use odd time orb behaviour"
+  },
+  {
+    ED_ELEMENT_SETTINGS_XPOS(0),       ED_ELEMENT_SETTINGS_YPOS(2),
+    GADGET_ID_RANDOM_BALL_CONTENT,     GADGET_ID_NONE,
+    &level.ball_random,
+    NULL,
+    "create single random element",    "only create one element from content"
+  },
+  {
+    ED_ELEMENT_SETTINGS_XPOS(0),       ED_ELEMENT_SETTINGS_YPOS(1),
+    GADGET_ID_INITIAL_BALL_STATE,      GADGET_ID_NONE,
+    &level.ball_state_initial,
+    NULL,
+    "magic ball initially activated",  "activate magic ball after level start"
+  },
   {
     ED_ELEMENT_SETTINGS_XPOS(0),       ED_ELEMENT_SETTINGS_YPOS(0),
     GADGET_ID_GROW_INTO_DIGGABLE,      GADGET_ID_NONE,
@@ -2049,42 +2531,77 @@ static struct
     "can grow into anything diggable", "grow into more than just sand"
   },
   {
-    ED_ELEMENT_SETTINGS_XPOS(0),       ED_ELEMENT_SETTINGS_YPOS(4),
-    GADGET_ID_DOUBLE_SPEED,            GADGET_ID_NONE,
-    &level.double_speed,
+    ED_ELEMENT_SETTINGS_XPOS(0),       ED_ELEMENT_SETTINGS_YPOS(7),
+    GADGET_ID_CONTINUOUS_SNAPPING,     GADGET_ID_NONE,
+    &level.continuous_snapping,
     NULL,
-    "double speed movement",           "set initial movement speed of player"
+    "continuos snapping",              "use snapping without releasing key"
   },
   {
-    ED_ELEMENT_SETTINGS_XPOS(0),       ED_ELEMENT_SETTINGS_YPOS(1),
+    ED_ELEMENT_SETTINGS_XPOS(0),       ED_ELEMENT_SETTINGS_YPOS(6),
+    GADGET_ID_BLOCK_SNAP_FIELD,                GADGET_ID_NONE,
+    &level.block_snap_field,
+    NULL,
+    "block snapped field when snapping", "use snapping delay to show animation"
+  },
+  {
+    ED_ELEMENT_SETTINGS_XPOS(0),       ED_ELEMENT_SETTINGS_YPOS(2),
     GADGET_ID_BLOCK_LAST_FIELD,                GADGET_ID_NONE,
     &level.block_last_field,
     NULL,
     "block last field when moving",    "player blocks last field when moving"
   },
   {
-    ED_ELEMENT_SETTINGS_XPOS(0),       ED_ELEMENT_SETTINGS_YPOS(1),
+    ED_ELEMENT_SETTINGS_XPOS(0),       ED_ELEMENT_SETTINGS_YPOS(2),
     GADGET_ID_SP_BLOCK_LAST_FIELD,     GADGET_ID_NONE,
     &level.sp_block_last_field,
     NULL,
     "block last field when moving",    "player blocks last field when moving"
   },
   {
-    ED_ELEMENT_SETTINGS_XPOS(0),       ED_ELEMENT_SETTINGS_YPOS(2),
+    ED_ELEMENT_SETTINGS_XPOS(0),       ED_ELEMENT_SETTINGS_YPOS(3),
     GADGET_ID_INSTANT_RELOCATION,      GADGET_ID_NONE,
     &level.instant_relocation,
     NULL,
     "no scrolling when relocating",    "player gets relocated without delay"
   },
   {
-    ED_ELEMENT_SETTINGS_XPOS(0),       ED_ELEMENT_SETTINGS_YPOS(3),
+    ED_ELEMENT_SETTINGS_XPOS(0),       ED_ELEMENT_SETTINGS_YPOS(8),
+    GADGET_ID_USE_START_ELEMENT,       GADGET_ID_NONE,
+    &level.use_start_element[0],
+    NULL,
+    "use level start element:",               "start level at this element's position"
+  },
+  {
+    ED_ELEMENT_SETTINGS_XPOS(0),       ED_ELEMENT_SETTINGS_YPOS(9),
+    GADGET_ID_USE_ARTWORK_ELEMENT,     GADGET_ID_NONE,
+    &level.use_artwork_element[0],
+    NULL,
+    "use artwork from element:",       "use player artwork from other element"
+  },
+  {
+    ED_ELEMENT_SETTINGS_XPOS(0),       ED_ELEMENT_SETTINGS_YPOS(10),
+    GADGET_ID_USE_EXPLOSION_ELEMENT,   GADGET_ID_NONE,
+    &level.use_explosion_element[0],
+    NULL,
+    "use explosion from element:",     "use explosion properties from element"
+  },
+  {
+    ED_ELEMENT_SETTINGS_XPOS(0),       ED_ELEMENT_SETTINGS_YPOS(11),
+    GADGET_ID_INITIAL_GRAVITY,         GADGET_ID_NONE,
+    &level.initial_player_gravity[0],
+    NULL,
+    "use initial gravity",             "set initial player gravity"
+  },
+  {
+    ED_ELEMENT_SETTINGS_XPOS(0),       ED_ELEMENT_SETTINGS_YPOS(4),
     GADGET_ID_CAN_PASS_TO_WALKABLE,    GADGET_ID_NONE,
     &level.can_pass_to_walkable,
     NULL,
     "can pass to walkable element",    "player can pass to empty or walkable"
   },
   {
-    ED_ELEMENT_SETTINGS_XPOS(0),       ED_ELEMENT_SETTINGS_YPOS(0),
+    ED_ELEMENT_SETTINGS_XPOS(0),       ED_ELEMENT_SETTINGS_YPOS(1),
     GADGET_ID_CAN_FALL_INTO_ACID,      GADGET_ID_NONE,
     &custom_element_properties[EP_CAN_MOVE_INTO_ACID],
     NULL,
@@ -2137,6 +2654,12 @@ static struct
     &custom_element_properties[EP_GRAVITY_REACHABLE],
     NULL, "reachable despite gravity", "player can walk/dig despite gravity"
   },
+  {
+    ED_ELEMENT_SETTINGS_XPOS(0),       ED_ELEMENT_SETTINGS_YPOS(13),
+    GADGET_ID_CUSTOM_USE_LAST_VALUE,   GADGET_ID_NONE,
+    &custom_element.use_last_ce_value,
+    NULL, "use last CE value after change", "use last CE value after change"
+  },
   {
     ED_ELEMENT_SETTINGS_XPOS(0),       ED_ELEMENT_SETTINGS_YPOS(5),
     GADGET_ID_CUSTOM_WALK_TO_OBJECT,   GADGET_ID_NONE,
@@ -2213,7 +2736,7 @@ static struct
     ED_ELEMENT_SETTINGS_XPOS(0),       ED_ELEMENT_SETTINGS_YPOS(1),
     GADGET_ID_CUSTOM_CAN_CHANGE,       GADGET_ID_NONE,
     &custom_element_change.can_change,
-    NULL, "element changes to:",       "element can change to other element"
+    NULL, "element changes to:",       "change element on specified condition"
   },
   {
     ED_ELEMENT_SETTINGS_XPOS(1),       ED_ELEMENT_SETTINGS_YPOS(2),
@@ -2257,146 +2780,189 @@ static struct
     &custom_element_change.use_random_replace,
     NULL, NULL,                                "use percentage for random replace"
   },
+  {
+    ED_ELEMENT_SETTINGS_XPOS(0),       ED_ELEMENT_SETTINGS_YPOS(13),
+    GADGET_ID_CHANGE_HAS_ACTION,       GADGET_ID_NONE,
+    &custom_element_change.has_action,
+    NULL, NULL,                                "execute action on specified condition"
+  },
 };
 
 static struct
 {
   int x, y;
-  int area_xsize, area_ysize;
   int gadget_id;
   int gadget_id_align;
-  char *text_left, *text_right, *text_below;
+  int *value;
+  int area_xsize, area_ysize;
+  char *text_left, *text_right, *text_below, *infotext;
 } drawingarea_info[ED_NUM_DRAWING_AREAS] =
 {
   /* ---------- level playfield content ------------------------------------ */
 
   {
-    0, 0,
-    MAX_ED_FIELDX, MAX_ED_FIELDY,
+    0,                                 0,
     GADGET_ID_DRAWING_LEVEL,           GADGET_ID_NONE,
-    NULL, NULL,                                NULL
+    NULL,                              MAX_ED_FIELDX, MAX_ED_FIELDY,
+    NULL, NULL, NULL,                  NULL
   },
 
   /* ---------- yam yam content -------------------------------------------- */
 
   {
     ED_AREA_YAMYAM_CONTENT_XPOS(0),    ED_AREA_YAMYAM_CONTENT_YPOS(0),
-    3, 3,
     GADGET_ID_YAMYAM_CONTENT_0,                GADGET_ID_NONE,
-    NULL, NULL,                                "1"
+    &level.yamyam_content[0].e[0][0],  3, 3,
+    NULL, NULL, "1",                   NULL
   },
   {
     ED_AREA_YAMYAM_CONTENT_XPOS(1),    ED_AREA_YAMYAM_CONTENT_YPOS(1),
-    3, 3,
     GADGET_ID_YAMYAM_CONTENT_1,                GADGET_ID_NONE,
-    NULL, NULL,                                "2"
+    &level.yamyam_content[1].e[0][0],  3, 3,
+    NULL, NULL, "2",                   NULL
   },
   {
     ED_AREA_YAMYAM_CONTENT_XPOS(2),    ED_AREA_YAMYAM_CONTENT_YPOS(2),
-    3, 3,
     GADGET_ID_YAMYAM_CONTENT_2,                GADGET_ID_NONE,
-    NULL, NULL,                                "3"
+    &level.yamyam_content[2].e[0][0],  3, 3,
+    NULL, NULL, "3",                   NULL
   },
   {
     ED_AREA_YAMYAM_CONTENT_XPOS(3),    ED_AREA_YAMYAM_CONTENT_YPOS(3),
-    3, 3,
     GADGET_ID_YAMYAM_CONTENT_3,                GADGET_ID_NONE,
-    NULL, NULL,                                "4"
+    &level.yamyam_content[3].e[0][0],  3, 3,
+    NULL, NULL, "4",                   NULL
   },
   {
     ED_AREA_YAMYAM_CONTENT_XPOS(4),    ED_AREA_YAMYAM_CONTENT_YPOS(4),
-    3, 3,
     GADGET_ID_YAMYAM_CONTENT_4,                GADGET_ID_NONE,
-    NULL, NULL,                                "5"
+    &level.yamyam_content[4].e[0][0],  3, 3,
+    NULL, NULL, "5",                   NULL
   },
   {
     ED_AREA_YAMYAM_CONTENT_XPOS(5),    ED_AREA_YAMYAM_CONTENT_YPOS(5),
-    3, 3,
     GADGET_ID_YAMYAM_CONTENT_5,                GADGET_ID_NONE,
-    NULL, NULL,                                "6"
+    &level.yamyam_content[5].e[0][0],  3, 3,
+    NULL, NULL, "6",                   NULL
   },
   {
     ED_AREA_YAMYAM_CONTENT_XPOS(6),    ED_AREA_YAMYAM_CONTENT_YPOS(6),
-    3, 3,
     GADGET_ID_YAMYAM_CONTENT_6,                GADGET_ID_NONE,
-    NULL, NULL,                                "7"
+    &level.yamyam_content[6].e[0][0],  3, 3,
+    NULL, NULL, "7",                   NULL
   },
   {
     ED_AREA_YAMYAM_CONTENT_XPOS(7),    ED_AREA_YAMYAM_CONTENT_YPOS(7),
-    3, 3,
     GADGET_ID_YAMYAM_CONTENT_7,                GADGET_ID_NONE,
-    NULL, NULL,                                "8"
+    &level.yamyam_content[7].e[0][0],  3, 3,
+    NULL, NULL, "8",                   NULL
   },
 
   /* ---------- magic ball content ----------------------------------------- */
 
   {
     ED_AREA_MAGIC_BALL_CONTENT_XPOS(0),        ED_AREA_MAGIC_BALL_CONTENT_YPOS(0),
-    3, 3,
     GADGET_ID_MAGIC_BALL_CONTENT_0,    GADGET_ID_NONE,
-    NULL, NULL,                                "1"
+    &level.ball_content[0].e[0][0],    3, 3,
+    NULL, NULL, "1",                   NULL
   },
   {
     ED_AREA_MAGIC_BALL_CONTENT_XPOS(1),        ED_AREA_MAGIC_BALL_CONTENT_YPOS(1),
-    3, 3,
     GADGET_ID_MAGIC_BALL_CONTENT_1,    GADGET_ID_NONE,
-    NULL, NULL,                                "2"
+    &level.ball_content[1].e[0][0],    3, 3,
+    NULL, NULL, "2",                   NULL
   },
   {
     ED_AREA_MAGIC_BALL_CONTENT_XPOS(2),        ED_AREA_MAGIC_BALL_CONTENT_YPOS(2),
-    3, 3,
     GADGET_ID_MAGIC_BALL_CONTENT_2,    GADGET_ID_NONE,
-    NULL, NULL,                                "3"
+    &level.ball_content[2].e[0][0],    3, 3,
+    NULL, NULL, "3",                   NULL
   },
   {
     ED_AREA_MAGIC_BALL_CONTENT_XPOS(3),        ED_AREA_MAGIC_BALL_CONTENT_YPOS(3),
-    3, 3,
     GADGET_ID_MAGIC_BALL_CONTENT_3,    GADGET_ID_NONE,
-    NULL, NULL,                                "4"
+    &level.ball_content[3].e[0][0],    3, 3,
+    NULL, NULL, "4",                   NULL
   },
   {
     ED_AREA_MAGIC_BALL_CONTENT_XPOS(4),        ED_AREA_MAGIC_BALL_CONTENT_YPOS(4),
-    3, 3,
     GADGET_ID_MAGIC_BALL_CONTENT_4,    GADGET_ID_NONE,
-    NULL, NULL,                                "5"
+    &level.ball_content[4].e[0][0],    3, 3,
+    NULL, NULL, "5",                   NULL
   },
   {
     ED_AREA_MAGIC_BALL_CONTENT_XPOS(5),        ED_AREA_MAGIC_BALL_CONTENT_YPOS(5),
-    3, 3,
     GADGET_ID_MAGIC_BALL_CONTENT_5,    GADGET_ID_NONE,
-    NULL, NULL,                                "6"
+    &level.ball_content[5].e[0][0],    3, 3,
+    NULL, NULL, "6",                   NULL
   },
   {
     ED_AREA_MAGIC_BALL_CONTENT_XPOS(6),        ED_AREA_MAGIC_BALL_CONTENT_YPOS(6),
-    3, 3,
     GADGET_ID_MAGIC_BALL_CONTENT_6,    GADGET_ID_NONE,
-    NULL, NULL,                                "7"
+    &level.ball_content[6].e[0][0],    3, 3,
+    NULL, NULL, "7",                   NULL
   },
   {
     ED_AREA_MAGIC_BALL_CONTENT_XPOS(7),        ED_AREA_MAGIC_BALL_CONTENT_YPOS(7),
-    3, 3,
     GADGET_ID_MAGIC_BALL_CONTENT_7,    GADGET_ID_NONE,
-    NULL, NULL,                                "8"
+    &level.ball_content[7].e[0][0],    3, 3,
+    NULL, NULL, "8",                   NULL
+  },
+
+  /* ---------- android content -------------------------------------------- */
+
+  {
+    ED_AREA_1X1_SETTINGS_XPOS(0),      ED_AREA_1X1_SETTINGS_YPOS(5),
+    GADGET_ID_ANDROID_CONTENT,         GADGET_ID_NONE,
+    &level.android_clone_element[0],   MAX_ANDROID_ELEMENTS, 1,
+    "elements:", NULL, NULL,           "elements android can clone"
   },
 
   /* ---------- amoeba content --------------------------------------------- */
 
   {
     ED_AREA_1X1_SETTINGS_XPOS(0),      ED_AREA_1X1_SETTINGS_YPOS(3),
-    1, 1,
     GADGET_ID_AMOEBA_CONTENT,          GADGET_ID_NONE,
-    "content:", NULL,                  NULL
+    &level.amoeba_content,             1, 1,
+    "content:", NULL, NULL,            "amoeba content"
   },
 
-  /* ---------- element settings: configure 1 (custom elements) ----------- */
+  /* ---------- level start element ---------------------------------------- */
 
-  /* ---------- custom graphic --------------------------------------------- */
+  {
+    -1,                                        ED_AREA_1X1_SETTINGS_YPOS(8),
+    GADGET_ID_START_ELEMENT,           GADGET_ID_USE_START_ELEMENT,
+    &level.start_element[0],           1, 1,
+    NULL, NULL, NULL,                  "level start element"
+  },
+
+  /* ---------- player artwork element ------------------------------------- */
+
+  {
+    -1,                                        ED_AREA_1X1_SETTINGS_YPOS(9),
+    GADGET_ID_ARTWORK_ELEMENT,         GADGET_ID_USE_ARTWORK_ELEMENT,
+    &level.artwork_element[0],         1, 1,
+    NULL, NULL, NULL,                  "element for player artwork"
+  },
+
+  /* ---------- player explosion element ----------------------------------- */
+
+  {
+    -1,                                        ED_AREA_1X1_SETTINGS_YPOS(10),
+    GADGET_ID_EXPLOSION_ELEMENT,       GADGET_ID_USE_EXPLOSION_ELEMENT,
+    &level.explosion_element[0],       1, 1,
+    NULL, NULL, NULL,                  "element for player explosion"
+  },
+
+  /* ---------- element settings: configure 1 (custom elements) ----------- */
+
+  /* ---------- custom graphic --------------------------------------------- */
 
   {
     -1,                                        ED_AREA_1X1_SETTINGS_YPOS(1),
-    1, 1,
     GADGET_ID_CUSTOM_GRAPHIC,          GADGET_ID_CUSTOM_USE_GRAPHIC,
-    NULL, NULL,                                NULL
+    &custom_element.gfx_element,       1, 1,
+    NULL, NULL, NULL,                  "custom graphic element"
   },
 
   /* ---------- element settings: configure 2 (custom elements) ----------- */
@@ -2405,24 +2971,24 @@ static struct
 
   {
     -1,                                        ED_AREA_3X3_SETTINGS_YPOS(10),
-    3, 3,
     GADGET_ID_CUSTOM_CONTENT,          GADGET_ID_NONE, /* align three rows */
-    "content:", NULL,                  NULL
+    &custom_element.content.e[0][0],   3, 3,
+    "content:", NULL, NULL,            NULL
   },
 
   /* ---------- custom enter and leave element (when moving) --------------- */
 
   {
     ED_AREA_1X1_SETTINGS_XPOS(1),      ED_AREA_1X1_SETTINGS_YPOS(3),
-    1, 1,
     GADGET_ID_CUSTOM_MOVE_ENTER,       GADGET_ID_NONE,
-    "can dig:", " ",                   NULL
+    &custom_element.move_enter_element,        1, 1,
+    "can dig:", " ", NULL,             "element that can be digged/collected"
   },
   {
     -1,                                        ED_AREA_1X1_SETTINGS_YPOS(3),
-    1, 1,
     GADGET_ID_CUSTOM_MOVE_LEAVE,       GADGET_ID_CUSTOM_MOVE_LEAVE_TYPE,
-    NULL, NULL,                                NULL
+    &custom_element.move_leave_element,        1, 1,
+    NULL, NULL, NULL,                  "element that will be left behind"
   },
 
   /* ---------- element settings: advanced (custom elements) --------------- */
@@ -2431,45 +2997,45 @@ static struct
 
   {
     -1,                                        ED_AREA_1X1_SETTINGS_YPOS(1),
-    1, 1,
     GADGET_ID_CUSTOM_CHANGE_TARGET,    GADGET_ID_CUSTOM_CAN_CHANGE,
-    NULL, "after/when:",               NULL
+    &custom_element_change.target_element, 1, 1,
+    NULL, "after/when:", NULL,         "new target element after change"
   },
 
   /* ---------- custom change content (extended change target) ------------- */
 
   {
-    -1,                                        ED_AREA_3X3_SETTINGS_YPOS(10),
-    3, 3,
+    -1,                                        ED_AREA_3X3_SETTINGS_YPOS(9),
     GADGET_ID_CUSTOM_CHANGE_CONTENT,   GADGET_ID_NONE, /* align three rows */
-    NULL, NULL,                                NULL
+    &custom_element_change.target_content.e[0][0], 3, 3,
+    NULL, NULL, NULL,                  "new extended elements after change"
   },
 
   /* ---------- custom change trigger (element causing change) ------------- */
 
   {
     -1,                                        ED_AREA_1X1_SETTINGS_YPOS(5),
-    1, 1,
     GADGET_ID_CUSTOM_CHANGE_TRIGGER,   GADGET_ID_CHANGE_OTHER_ACTION,
-    NULL, NULL,                                NULL
+    &custom_element_change.trigger_element, 1, 1,
+    NULL, NULL, NULL,                  "other element triggering change"
   },
 
   /* ---------- group element content -------------------------------------- */
 
   {
     ED_AREA_1X1_SETTINGS_XPOS(0),      ED_AREA_1X1_SETTINGS_YPOS(4),
-    MAX_ELEMENTS_IN_GROUP, 1,
     GADGET_ID_GROUP_CONTENT,           GADGET_ID_NONE,
-    "content:", NULL,                  NULL
+    &group_element_info.element[0],    MAX_ELEMENTS_IN_GROUP, 1,
+    "content:", NULL, NULL,            NULL
   },
 
   /* ---------- random background (for random painting) -------------------- */
 
   {
     -1,                                        ED_ELEMENT_SETTINGS_YPOS(14),
-    1, 1,
     GADGET_ID_RANDOM_BACKGROUND,       GADGET_ID_RANDOM_RESTRICTED,
-    NULL, NULL,                                NULL
+    &random_placement_background_element, 1, 1,
+    NULL, NULL, NULL,                  "random placement background"
   },
 };
 
@@ -2493,17 +3059,20 @@ static int new_element1 = EL_WALL;
 static int new_element2 = EL_EMPTY;
 static int new_element3 = EL_SAND;
 
+#define IS_VALID_BUTTON(button) (button >= 1 && button <= 3)
 #define BUTTON_ELEMENT(button) ((button) == 1 ? new_element1 : \
                                (button) == 2 ? new_element2 : \
                                (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 ModifyEditorCounterValue(int, int);
 static void ModifyEditorCounterLimits(int, int, int);
-static void ModifyEditorSelectbox(int, int);
+static void ModifyEditorSelectboxValue(int, int);
+static void ModifyEditorSelectboxOptions(int, struct ValueTextInfo *);
 static void ModifyEditorDrawingArea(int, int, int);
 static void ModifyEditorElementList();
+static void AdjustElementListScrollbar();
 static void RedrawDrawingElements();
 static void DrawDrawingWindow();
 static void DrawLevelInfoWindow();
@@ -2522,6 +3091,7 @@ static void HandleRadiobuttons(struct GadgetInfo *);
 static void HandleCheckbuttons(struct GadgetInfo *);
 static void HandleControlButtons(struct GadgetInfo *);
 static void HandleDrawingAreaInfo(struct GadgetInfo *);
+static void PrintEditorGadgetInfoText(struct GadgetInfo *);
 
 static struct GadgetInfo *level_editor_gadget[NUM_EDITOR_GADGETS];
 static int right_gadget_border[NUM_EDITOR_GADGETS];
@@ -2541,8 +3111,24 @@ static int edit_mode_properties;
 
 static int element_shift = 0;
 
+static int editor_el_players[] =
+{
+  EL_PLAYER_1,
+  EL_PLAYER_2,
+  EL_PLAYER_3,
+  EL_PLAYER_4
+};
+static int *editor_el_players_ptr = editor_el_players;
+static int num_editor_el_players = SIZEOF_ARRAY_INT(editor_el_players);
+
 static int editor_hl_boulderdash[] =
 {
+  EL_INTERNAL_CASCADE_BD_ACTIVE,
+  EL_CHAR('B'),
+  EL_CHAR('D'),
+  EL_EMPTY,
+
+#if 0
   EL_CHAR('B'),
   EL_CHAR('O'),
   EL_CHAR('U'),
@@ -2557,10 +3143,39 @@ static int editor_hl_boulderdash[] =
   EL_CHAR('A'),
   EL_CHAR('S'),
   EL_CHAR('H'),
+#endif
 };
 
 static int editor_el_boulderdash[] =
 {
+#if 1
+  EL_EMPTY,
+  EL_SAND,
+  EL_BD_ROCK,
+  EL_BD_DIAMOND,
+
+  EL_STEELWALL,
+  EL_BD_WALL,
+  EL_BD_EXPANDABLE_WALL,
+  EL_BD_MAGIC_WALL,
+
+  EL_BD_AMOEBA,
+  EL_BD_BUTTERFLY_UP,
+  EL_BD_FIREFLY_UP,
+  EL_EXIT_CLOSED,
+
+  EL_BD_BUTTERFLY_LEFT,
+  EL_BD_FIREFLY_LEFT,
+  EL_BD_BUTTERFLY_RIGHT,
+  EL_BD_FIREFLY_RIGHT,
+
+  EL_EMPTY,
+  EL_BD_BUTTERFLY_DOWN,
+  EL_BD_FIREFLY_DOWN,
+  EL_EXIT_OPEN,
+
+#else
+
   EL_PLAYER_1,
   EL_EMPTY,
   EL_SAND,
@@ -2584,7 +3199,8 @@ static int editor_el_boulderdash[] =
   EL_BD_AMOEBA,
   EL_BD_BUTTERFLY_DOWN,
   EL_BD_FIREFLY_DOWN,
-  EL_EMPTY,
+  EL_BD_EXPANDABLE_WALL,
+#endif
 };
 static int *editor_hl_boulderdash_ptr = editor_hl_boulderdash;
 static int *editor_el_boulderdash_ptr = editor_el_boulderdash;
@@ -2593,6 +3209,12 @@ static int num_editor_el_boulderdash = SIZEOF_ARRAY_INT(editor_el_boulderdash);
 
 static int editor_hl_emerald_mine[] =
 {
+  EL_INTERNAL_CASCADE_EM_ACTIVE,
+  EL_CHAR('E'),
+  EL_CHAR('M'),
+  EL_EMPTY,
+
+#if 0
   EL_CHAR('E'),
   EL_CHAR('M'),
   EL_CHAR('E'),
@@ -2607,17 +3229,76 @@ static int editor_hl_emerald_mine[] =
   EL_CHAR('I'),
   EL_CHAR('N'),
   EL_CHAR('E'),
+#endif
 };
 
 static int editor_el_emerald_mine[] =
 {
-  EL_PLAYER_1,
-  EL_PLAYER_2,
-  EL_PLAYER_3,
-  EL_PLAYER_4,
+#if 1
+  EL_SAND,
+  EL_ROCK,
+  EL_QUICKSAND_EMPTY,
+  EL_QUICKSAND_FULL,
+
+  EL_STEELWALL,
+  EL_WALL,
+  EL_WALL_SLIPPERY,
+  EL_MAGIC_WALL,
+
+  EL_EMERALD,
+  EL_DIAMOND,
+  EL_NUT,
+  EL_BOMB,
+
+  EL_WALL_EMERALD,
+  EL_WALL_DIAMOND,
+  EL_DYNAMITE,
+  EL_DYNAMITE_ACTIVE,
+
+  EL_YAMYAM,
+  EL_BUG_UP,
+  EL_SPACESHIP_UP,
+  EL_ROBOT,
+
+  EL_BUG_LEFT,
+  EL_SPACESHIP_LEFT,
+  EL_BUG_RIGHT,
+  EL_SPACESHIP_RIGHT,
+
+  EL_ROBOT_WHEEL,
+  EL_BUG_DOWN,
+  EL_SPACESHIP_DOWN,
+  EL_INVISIBLE_WALL,
+
+  EL_ACID_POOL_TOPLEFT,
+  EL_ACID,
+  EL_ACID_POOL_TOPRIGHT,
+  EL_AMOEBA_DROP,
+
+  EL_ACID_POOL_BOTTOMLEFT,
+  EL_ACID_POOL_BOTTOM,
+  EL_ACID_POOL_BOTTOMRIGHT,
+  EL_AMOEBA_WET,
+
+  EL_EM_KEY_1,
+  EL_EM_KEY_2,
+  EL_EM_KEY_3,
+  EL_EM_KEY_4,
+
+  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,
+
+#else
 
   EL_PLAYER_1,
-  EL_EMPTY,
+  EL_PLAYER_2,
   EL_SAND,
   EL_ROCK,
 
@@ -2671,17 +3352,10 @@ static int editor_el_emerald_mine[] =
   EL_AMOEBA_WET,
   EL_AMOEBA_DRY,
 
-#if 1
   EL_EM_KEY_1,
   EL_EM_KEY_2,
   EL_EM_KEY_3,
   EL_EM_KEY_4,
-#else
-  EL_EM_KEY_1_FILE,
-  EL_EM_KEY_2_FILE,
-  EL_EM_KEY_3_FILE,
-  EL_EM_KEY_4_FILE,
-#endif
 
   EL_EM_GATE_1,
   EL_EM_GATE_2,
@@ -2692,6 +3366,7 @@ static int editor_el_emerald_mine[] =
   EL_EM_GATE_2_GRAY,
   EL_EM_GATE_3_GRAY,
   EL_EM_GATE_4_GRAY,
+#endif
 };
 static int *editor_hl_emerald_mine_ptr = editor_hl_emerald_mine;
 static int *editor_el_emerald_mine_ptr = editor_el_emerald_mine;
@@ -2700,6 +3375,12 @@ static int num_editor_el_emerald_mine=SIZEOF_ARRAY_INT(editor_el_emerald_mine);
 
 static int editor_hl_emerald_mine_club[] =
 {
+  EL_INTERNAL_CASCADE_EMC_ACTIVE,
+  EL_CHAR('E'),
+  EL_CHAR('M'),
+  EL_CHAR('C'),
+
+#if 0
   EL_CHAR('E'),
   EL_CHAR('M'),
   EL_CHAR('E'),
@@ -2719,10 +3400,12 @@ static int editor_hl_emerald_mine_club[] =
   EL_CHAR('L'),
   EL_CHAR('U'),
   EL_CHAR('B'),
+#endif
 };
 
 static int editor_el_emerald_mine_club[] =
 {
+#if 1
   EL_EMC_KEY_5,
   EL_EMC_KEY_6,
   EL_EMC_KEY_7,
@@ -2768,18 +3451,87 @@ static int editor_el_emerald_mine_club[] =
   EL_EMC_WALL_11,
   EL_EMC_WALL_12,
 
-#if RELEASE_312
-  EL_EMPTY,
+  EL_EMC_GRASS,
+  EL_EMC_FAKE_GRASS,
+  EL_EMC_PLANT,
+  EL_EMC_DRIPPER,
+
+  EL_EMC_MAGIC_BALL,
+  EL_EMC_MAGIC_BALL_SWITCH,
+  EL_SPRING,
+  EL_EMC_SPRING_BUMPER,
+
+  EL_EMC_LENSES,
+  EL_EMC_MAGNIFIER,
+  EL_EM_DYNAMITE,
+  EL_EM_DYNAMITE_ACTIVE,
+
+  EL_BALLOON,
+  EL_YAMYAM_UP,
+  EL_BALLOON_SWITCH_UP,
+  EL_BALLOON_SWITCH_ANY,
+
+  EL_YAMYAM_LEFT,
+  EL_BALLOON_SWITCH_LEFT,
+  EL_YAMYAM_RIGHT,
+  EL_BALLOON_SWITCH_RIGHT,
+
+  EL_EMC_ANDROID,
+  EL_YAMYAM_DOWN,
+  EL_BALLOON_SWITCH_DOWN,
+  EL_BALLOON_SWITCH_NONE,
+
 #else
+
+  EL_EMC_KEY_5,
+  EL_EMC_KEY_6,
+  EL_EMC_KEY_7,
+  EL_EMC_KEY_8,
+
+  EL_EMC_GATE_5,
+  EL_EMC_GATE_6,
+  EL_EMC_GATE_7,
+  EL_EMC_GATE_8,
+
+  EL_EMC_GATE_5_GRAY,
+  EL_EMC_GATE_6_GRAY,
+  EL_EMC_GATE_7_GRAY,
+  EL_EMC_GATE_8_GRAY,
+
+  EL_EMC_STEELWALL_1,
+  EL_EMC_STEELWALL_2,
+  EL_EMC_STEELWALL_3,
+  EL_EMC_STEELWALL_4,
+
+  EL_EMC_WALL_13,
+  EL_EMC_WALL_14,
+  EL_EMC_WALL_15,
+  EL_EMC_WALL_16,
+
+  EL_EMC_WALL_SLIPPERY_1,
+  EL_EMC_WALL_SLIPPERY_2,
+  EL_EMC_WALL_SLIPPERY_3,
+  EL_EMC_WALL_SLIPPERY_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_EMC_WALL_9,
+  EL_EMC_WALL_10,
+  EL_EMC_WALL_11,
+  EL_EMC_WALL_12,
+
   EL_EMC_ANDROID,
-#endif
   EL_BALLOON,
   EL_BALLOON_SWITCH_ANY,
-#if RELEASE_312
-  EL_EMPTY,
-#else
   EL_BALLOON_SWITCH_NONE,
-#endif
 
   EL_BALLOON_SWITCH_LEFT,
   EL_BALLOON_SWITCH_RIGHT,
@@ -2788,52 +3540,53 @@ static int editor_el_emerald_mine_club[] =
 
   EL_EMC_GRASS,
   EL_EMC_PLANT,
-#if RELEASE_312
-  EL_EMPTY,
-  EL_EMPTY,
-#else
   EL_EMC_LENSES,
   EL_EMC_MAGNIFIER,
-#endif
 
-#if RELEASE_312
-  EL_EMPTY,
-  EL_EMPTY,
-#else
   EL_EMC_MAGIC_BALL,
   EL_EMC_MAGIC_BALL_SWITCH,
-#endif
   EL_SPRING,
-#if RELEASE_312
-  EL_EMPTY,
-#else
   EL_EMC_SPRING_BUMPER,
-#endif
 
-#if RELEASE_312
-  EL_EMPTY,
-#else
   EL_EMC_DRIPPER,
-#endif
   EL_EMC_FAKE_GRASS,
   EL_EMPTY,
   EL_EMPTY,
+
+  EL_EM_DYNAMITE,
+  EL_EM_DYNAMITE_ACTIVE,
+  EL_EMPTY,
+  EL_EMPTY,
+
+  EL_YAMYAM_LEFT,
+  EL_YAMYAM_RIGHT,
+  EL_YAMYAM_UP,
+  EL_YAMYAM_DOWN,
+#endif
 };
 static int *editor_hl_emerald_mine_club_ptr = editor_hl_emerald_mine_club;
 static int *editor_el_emerald_mine_club_ptr = editor_el_emerald_mine_club;
 static int num_editor_hl_emerald_mine_club=SIZEOF_ARRAY_INT(editor_hl_emerald_mine_club);
 static int num_editor_el_emerald_mine_club=SIZEOF_ARRAY_INT(editor_el_emerald_mine_club);
 
-static int editor_hl_more[] =
+static int editor_hl_rnd[] =
 {
+  EL_INTERNAL_CASCADE_RND_ACTIVE,
+  EL_CHAR('R'),
+  EL_CHAR('N'),
+  EL_CHAR('D'),
+
+#if 0
   EL_CHAR('M'),
   EL_CHAR('O'),
   EL_CHAR('R'),
   EL_CHAR('E'),
+#endif
 };
 
-static int editor_el_more[] =
+static int editor_el_rnd[] =
 {
+#if 1
   EL_KEY_1,
   EL_KEY_2,
   EL_KEY_3,
@@ -2854,7 +3607,94 @@ static int editor_el_more[] =
   EL_ARROW_UP,
   EL_ARROW_DOWN,
 
+  EL_AMOEBA_DEAD,
+  EL_AMOEBA_DRY,
   EL_AMOEBA_FULL,
+  EL_GAME_OF_LIFE,
+
+  EL_EMERALD_YELLOW,
+  EL_EMERALD_RED,
+  EL_EMERALD_PURPLE,
+  EL_BIOMAZE,
+
+  EL_WALL_EMERALD_YELLOW,
+  EL_WALL_EMERALD_RED,
+  EL_WALL_EMERALD_PURPLE,
+  EL_WALL_BD_DIAMOND,
+
+  EL_SPEED_PILL,
+  EL_PACMAN_UP,
+  EL_TIME_ORB_FULL,
+  EL_TIME_ORB_EMPTY,
+
+  EL_PACMAN_LEFT,
+  EL_DARK_YAMYAM,
+  EL_PACMAN_RIGHT,
+  EL_EMPTY,
+
+  EL_BLACK_ORB,
+  EL_PACMAN_DOWN,
+  EL_LAMP,
+  EL_LAMP_ACTIVE,
+
+  EL_DYNABOMB_INCREASE_NUMBER,
+  EL_DYNABOMB_INCREASE_SIZE,
+  EL_DYNABOMB_INCREASE_POWER,
+  EL_STONEBLOCK,
+
+  EL_MOLE,
+  EL_PENGUIN,
+  EL_PIG,
+  EL_DRAGON,
+
+  EL_BUG,
+  EL_MOLE_UP,
+  EL_BD_BUTTERFLY,
+  EL_BD_FIREFLY,
+
+  EL_MOLE_LEFT,
+  EL_SATELLITE,
+  EL_MOLE_RIGHT,
+  EL_PACMAN,
+
+  EL_SPACESHIP,
+  EL_MOLE_DOWN,
+  EL_INVISIBLE_STEELWALL,
+  EL_INVISIBLE_WALL,
+
+  EL_EXPANDABLE_WALL,
+  EL_EXPANDABLE_WALL_HORIZONTAL,
+  EL_EXPANDABLE_WALL_VERTICAL,
+  EL_EXPANDABLE_WALL_ANY,
+
+#else
+
+  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_DEAD,
+  EL_AMOEBA_DRY,
+  EL_AMOEBA_FULL,
+  EL_EMPTY,
+
+  EL_EMPTY,
   EL_EMERALD_YELLOW,
   EL_EMERALD_RED,
   EL_EMERALD_PURPLE,
@@ -2913,14 +3753,21 @@ static int editor_el_more[] =
   EL_INVISIBLE_WALL,
   EL_SPEED_PILL,
   EL_BLACK_ORB,
+#endif
 };
-static int *editor_hl_more_ptr = editor_hl_more;
-static int *editor_el_more_ptr = editor_el_more;
-static int num_editor_hl_more = SIZEOF_ARRAY_INT(editor_hl_more);
-static int num_editor_el_more = SIZEOF_ARRAY_INT(editor_el_more);
+static int *editor_hl_rnd_ptr = editor_hl_rnd;
+static int *editor_el_rnd_ptr = editor_el_rnd;
+static int num_editor_hl_rnd = SIZEOF_ARRAY_INT(editor_hl_rnd);
+static int num_editor_el_rnd = SIZEOF_ARRAY_INT(editor_el_rnd);
 
 static int editor_hl_sokoban[] =
 {
+  EL_INTERNAL_CASCADE_SB_ACTIVE,
+  EL_CHAR('S'),
+  EL_CHAR('B'),
+  EL_EMPTY,
+
+#if 0
   EL_CHAR('S'),
   EL_CHAR('O'),
   EL_CHAR('K'),
@@ -2930,6 +3777,7 @@ static int editor_hl_sokoban[] =
   EL_CHAR('B'),
   EL_CHAR('A'),
   EL_CHAR('N'),
+#endif
 };
 
 static int editor_el_sokoban[] =
@@ -2946,6 +3794,12 @@ static int num_editor_el_sokoban = SIZEOF_ARRAY_INT(editor_el_sokoban);
 
 static int editor_hl_supaplex[] =
 {
+  EL_INTERNAL_CASCADE_SP_ACTIVE,
+  EL_CHAR('S'),
+  EL_CHAR('P'),
+  EL_EMPTY,
+
+#if 0
   EL_CHAR('S'),
   EL_CHAR('U'),
   EL_CHAR('P'),
@@ -2955,10 +3809,64 @@ static int editor_hl_supaplex[] =
   EL_CHAR('L'),
   EL_CHAR('E'),
   EL_CHAR('X'),
+#endif
 };
 
 static int editor_el_supaplex[] =
 {
+#if 1
+  EL_SP_MURPHY,
+  EL_EMPTY,
+  EL_SP_BASE,
+  EL_SP_BUGGY_BASE,
+
+  EL_SP_INFOTRON,
+  EL_SP_ZONK,
+  EL_SP_SNIKSNAK,
+  EL_SP_ELECTRON,
+
+  EL_SP_DISK_RED,
+  EL_SP_DISK_ORANGE,
+  EL_SP_DISK_YELLOW,
+  EL_SP_TERMINAL,
+
+  EL_SP_EXIT_CLOSED,
+  EL_SP_PORT_HORIZONTAL,
+  EL_SP_PORT_VERTICAL,
+  EL_SP_PORT_ANY,
+
+  EL_SP_PORT_LEFT,
+  EL_SP_PORT_RIGHT,
+  EL_SP_PORT_UP,
+  EL_SP_PORT_DOWN,
+
+  EL_SP_GRAVITY_PORT_LEFT,
+  EL_SP_GRAVITY_PORT_RIGHT,
+  EL_SP_GRAVITY_PORT_UP,
+  EL_SP_GRAVITY_PORT_DOWN,
+
+  EL_SP_HARDWARE_GRAY,
+  EL_SP_HARDWARE_GREEN,
+  EL_SP_HARDWARE_BLUE,
+  EL_SP_HARDWARE_RED,
+
+  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_HARDWARE_YELLOW,
+  EL_SP_CHIP_TOP,
+
+  EL_SP_CHIP_SINGLE,
+  EL_SP_CHIP_LEFT,
+  EL_SP_CHIP_RIGHT,
+  EL_SP_CHIP_BOTTOM,
+
+#else
+
 #if 1
   EL_EMPTY,
 #else
@@ -3012,6 +3920,7 @@ static int editor_el_supaplex[] =
   EL_SP_HARDWARE_BASE_6,
   EL_SP_CHIP_TOP,
   EL_SP_CHIP_BOTTOM,
+#endif
 };
 static int *editor_hl_supaplex_ptr = editor_hl_supaplex;
 static int *editor_el_supaplex_ptr = editor_el_supaplex;
@@ -3020,6 +3929,12 @@ static int num_editor_el_supaplex = SIZEOF_ARRAY_INT(editor_el_supaplex);
 
 static int editor_hl_diamond_caves[] =
 {
+  EL_INTERNAL_CASCADE_DC_ACTIVE,
+  EL_CHAR('D'),
+  EL_CHAR('C'),
+  EL_CHAR('2'),
+
+#if 0
   EL_CHAR('D'),
   EL_CHAR('I'),
   EL_CHAR('A'),
@@ -3039,10 +3954,12 @@ static int editor_hl_diamond_caves[] =
   EL_CHAR(' '),
   EL_CHAR('I'),
   EL_CHAR('I'),
+#endif
 };
 
 static int editor_el_diamond_caves[] =
 {
+#if 1
   EL_PEARL,
   EL_CRYSTAL,
   EL_WALL_PEARL,
@@ -3078,9 +3995,29 @@ static int editor_el_diamond_caves[] =
   EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
   EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
 
-  EL_SWITCHGATE_OPEN,
   EL_SWITCHGATE_CLOSED,
+  EL_SWITCHGATE_OPEN,
   EL_SWITCHGATE_SWITCH_UP,
+  EL_SWITCHGATE_SWITCH_DOWN,
+
+  EL_TIMEGATE_CLOSED,
+  EL_TIMEGATE_OPEN,
+  EL_TIMEGATE_SWITCH,
+  EL_EMPTY,
+
+  EL_SIGN_EXCLAMATION,
+  EL_SIGN_STOP,
+  EL_LIGHT_SWITCH,
+  EL_LIGHT_SWITCH_ACTIVE,
+
+  EL_STEELWALL_SLIPPERY,
+  EL_INVISIBLE_SAND,
+  EL_LANDMINE,
+  EL_EMPTY,
+
+  EL_SHIELD_NORMAL,
+  EL_SHIELD_DEADLY,
+  EL_EXTRA_TIME,
   EL_EMPTY,
 
   EL_ENVELOPE_1,
@@ -3088,6 +4025,53 @@ static int editor_el_diamond_caves[] =
   EL_ENVELOPE_3,
   EL_ENVELOPE_4,
 
+#else
+
+  EL_PEARL,
+  EL_CRYSTAL,
+  EL_WALL_PEARL,
+  EL_WALL_CRYSTAL,
+
+  EL_CONVEYOR_BELT_1_LEFT,
+  EL_CONVEYOR_BELT_1_MIDDLE,
+  EL_CONVEYOR_BELT_1_RIGHT,
+  EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
+
+  EL_CONVEYOR_BELT_2_LEFT,
+  EL_CONVEYOR_BELT_2_MIDDLE,
+  EL_CONVEYOR_BELT_2_RIGHT,
+  EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
+
+  EL_CONVEYOR_BELT_3_LEFT,
+  EL_CONVEYOR_BELT_3_MIDDLE,
+  EL_CONVEYOR_BELT_3_RIGHT,
+  EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
+
+  EL_CONVEYOR_BELT_4_LEFT,
+  EL_CONVEYOR_BELT_4_MIDDLE,
+  EL_CONVEYOR_BELT_4_RIGHT,
+  EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
+
+  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_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_UP,
+  EL_SWITCHGATE_SWITCH_DOWN,
+
+  EL_ENVELOPE_1,
+  EL_ENVELOPE_2,
+  EL_ENVELOPE_3,
+  EL_ENVELOPE_4,
+
   EL_TIMEGATE_CLOSED,
   EL_TIMEGATE_OPEN,
   EL_TIMEGATE_SWITCH,
@@ -3107,6 +4091,8 @@ static int editor_el_diamond_caves[] =
   EL_SHIELD_DEADLY,
   EL_EXTRA_TIME,
   EL_EMPTY,
+
+#endif
 };
 static int *editor_hl_diamond_caves_ptr = editor_hl_diamond_caves;
 static int *editor_el_diamond_caves_ptr = editor_el_diamond_caves;
@@ -3115,6 +4101,12 @@ static int num_editor_el_diamond_caves = SIZEOF_ARRAY_INT(editor_el_diamond_cave
 
 static int editor_hl_dx_boulderdash[] =
 {
+  EL_INTERNAL_CASCADE_DX_ACTIVE,
+  EL_CHAR('D'),
+  EL_CHAR('X'),
+  EL_EMPTY,
+
+#if 0
   EL_CHAR('D'),
   EL_CHAR('X'),
   EL_CHAR('-'),
@@ -3134,6 +4126,7 @@ static int editor_hl_dx_boulderdash[] =
   EL_CHAR('A'),
   EL_CHAR('S'),
   EL_CHAR('H'),
+#endif
 };
 
 static int editor_el_dx_boulderdash[] =
@@ -3165,10 +4158,17 @@ static int num_editor_el_dx_boulderdash = SIZEOF_ARRAY_INT(editor_el_dx_boulderd
 
 static int editor_hl_chars[] =
 {
+  EL_INTERNAL_CASCADE_CHARS_ACTIVE,
+  EL_CHAR('T'),
+  EL_CHAR('X'),
+  EL_CHAR('T'),
+
+#if 0
   EL_CHAR('T'),
   EL_CHAR('E'),
   EL_CHAR('X'),
   EL_CHAR('T'),
+#endif
 };
 
 static int editor_el_chars[] =
@@ -3270,6 +4270,12 @@ static int num_editor_el_chars = SIZEOF_ARRAY_INT(editor_el_chars);
 
 static int editor_hl_custom[] =
 {
+  EL_INTERNAL_CASCADE_CE_ACTIVE,
+  EL_CHAR('C'),
+  EL_CHAR('E'),
+  EL_EMPTY,
+
+#if 0
   EL_CHAR('C'),
   EL_CHAR('U'),
   EL_CHAR('S'),
@@ -3289,6 +4295,7 @@ static int editor_hl_custom[] =
   EL_CHAR('N'),
   EL_CHAR('T'),
   EL_CHAR('S'),
+#endif
 };
 
 static int editor_el_custom[] =
@@ -3451,19 +4458,8 @@ static int editor_el_custom[] =
   EL_CUSTOM_START + 124,
   EL_CUSTOM_START + 125,
   EL_CUSTOM_START + 126,
-  EL_CUSTOM_START + 127
-};
-static int *editor_hl_custom_ptr = editor_hl_custom;
-static int *editor_el_custom_ptr = editor_el_custom;
-static int num_editor_hl_custom = SIZEOF_ARRAY_INT(editor_hl_custom);
-static int num_editor_el_custom = SIZEOF_ARRAY_INT(editor_el_custom);
-
-static int editor_hl_custom_more[] =
-{
-};
+  EL_CUSTOM_START + 127,
 
-static int editor_el_custom_more[] =
-{
   EL_CUSTOM_START + 128,
   EL_CUSTOM_START + 129,
   EL_CUSTOM_START + 130,
@@ -3624,29 +4620,44 @@ static int editor_el_custom_more[] =
   EL_CUSTOM_START + 254,
   EL_CUSTOM_START + 255
 };
-static int *editor_hl_custom_more_ptr = editor_hl_custom_more;
-static int *editor_el_custom_more_ptr = editor_el_custom_more;
-static int num_editor_hl_custom_more = SIZEOF_ARRAY_INT(editor_hl_custom_more);
-static int num_editor_el_custom_more = SIZEOF_ARRAY_INT(editor_el_custom_more);
+static int *editor_hl_custom_ptr = editor_hl_custom;
+static int *editor_el_custom_ptr = editor_el_custom;
+static int num_editor_hl_custom = SIZEOF_ARRAY_INT(editor_hl_custom);
+static int num_editor_el_custom = SIZEOF_ARRAY_INT(editor_el_custom);
 
-static int editor_hl_custom_special[] =
+static int editor_hl_reference[] =
 {
+  EL_INTERNAL_CASCADE_REF_ACTIVE,
+  EL_CHAR('R'),
+  EL_CHAR('E'),
+  EL_CHAR('F')
 };
 
-static int editor_el_custom_special[] =
+static int editor_el_reference[] =
 {
-  EL_TRIGGER_ELEMENT,
   EL_TRIGGER_PLAYER,
+  EL_TRIGGER_ELEMENT,
+  EL_TRIGGER_CE_VALUE,
+  EL_TRIGGER_CE_SCORE,
+
   EL_EMPTY,
-  EL_EMPTY
+  EL_EMPTY,
+  EL_CURRENT_CE_VALUE,
+  EL_CURRENT_CE_SCORE
 };
-static int *editor_hl_custom_special_ptr = editor_hl_custom_special;
-static int *editor_el_custom_special_ptr = editor_el_custom_special;
-static int num_editor_hl_custom_special = SIZEOF_ARRAY_INT(editor_hl_custom_special);
-static int num_editor_el_custom_special = SIZEOF_ARRAY_INT(editor_el_custom_special);
+static int *editor_hl_reference_ptr = editor_hl_reference;
+static int *editor_el_reference_ptr = editor_el_reference;
+static int num_editor_hl_reference = SIZEOF_ARRAY_INT(editor_hl_reference);
+static int num_editor_el_reference = SIZEOF_ARRAY_INT(editor_el_reference);
 
 static int editor_hl_group[] =
 {
+  EL_INTERNAL_CASCADE_GE_ACTIVE,
+  EL_CHAR('G'),
+  EL_CHAR('E'),
+  EL_EMPTY,
+
+#if 0
   EL_CHAR('G'),
   EL_CHAR('R'),
   EL_CHAR('O'),
@@ -3666,6 +4677,7 @@ static int editor_hl_group[] =
   EL_CHAR('N'),
   EL_CHAR('T'),
   EL_CHAR('S'),
+#endif
 };
 
 static int editor_el_group[] =
@@ -3688,19 +4700,8 @@ static int editor_el_group[] =
   EL_GROUP_START + 12,
   EL_GROUP_START + 13,
   EL_GROUP_START + 14,
-  EL_GROUP_START + 15
-};
-static int *editor_hl_group_ptr = editor_hl_group;
-static int *editor_el_group_ptr = editor_el_group;
-static int num_editor_hl_group = SIZEOF_ARRAY_INT(editor_hl_group);
-static int num_editor_el_group = SIZEOF_ARRAY_INT(editor_el_group);
+  EL_GROUP_START + 15,
 
-static int editor_hl_group_more[] =
-{
-};
-
-static int editor_el_group_more[] =
-{
   EL_GROUP_START + 16,
   EL_GROUP_START + 17,
   EL_GROUP_START + 18,
@@ -3721,13 +4722,19 @@ static int editor_el_group_more[] =
   EL_GROUP_START + 30,
   EL_GROUP_START + 31
 };
-static int *editor_hl_group_more_ptr = editor_hl_group_more;
-static int *editor_el_group_more_ptr = editor_el_group_more;
-static int num_editor_hl_group_more = SIZEOF_ARRAY_INT(editor_hl_group_more);
-static int num_editor_el_group_more = SIZEOF_ARRAY_INT(editor_el_group_more);
+static int *editor_hl_group_ptr = editor_hl_group;
+static int *editor_el_group_ptr = editor_el_group;
+static int num_editor_hl_group = SIZEOF_ARRAY_INT(editor_hl_group);
+static int num_editor_el_group = SIZEOF_ARRAY_INT(editor_el_group);
 
 static int editor_hl_user_defined[] =
 {
+  EL_INTERNAL_CASCADE_USER_ACTIVE,
+  EL_CHAR('M'),
+  EL_CHAR('Y'),
+  EL_EMPTY,
+
+#if 0
   EL_CHAR('U'),
   EL_CHAR('S'),
   EL_CHAR('E'),
@@ -3742,6 +4749,7 @@ static int editor_hl_user_defined[] =
   EL_CHAR('N'),
   EL_CHAR('E'),
   EL_CHAR('D'),
+#endif
 };
 
 static int *editor_hl_user_defined_ptr = editor_hl_user_defined;
@@ -3749,6 +4757,19 @@ static int *editor_el_user_defined_ptr = NULL;
 static int num_editor_hl_user_defined=SIZEOF_ARRAY_INT(editor_hl_user_defined);
 static int num_editor_el_user_defined = 0;
 
+static int editor_hl_dynamic[] =
+{
+  EL_INTERNAL_CASCADE_DYNAMIC_ACTIVE,
+  EL_CHAR('U'),
+  EL_CHAR('S'),
+  EL_CHAR('E'),
+};
+
+static int *editor_hl_dynamic_ptr = editor_hl_dynamic;
+static int *editor_el_dynamic_ptr = NULL;
+static int num_editor_hl_dynamic = SIZEOF_ARRAY_INT(editor_hl_dynamic);
+static int num_editor_el_dynamic = 0;
+
 static int editor_hl_empty[] = { };
 static int editor_el_empty[ED_NUM_ELEMENTLIST_BUTTONS];
 
@@ -3762,9 +4783,17 @@ static boolean use_el_empty = FALSE;
 static int *editor_elements = NULL;    /* dynamically allocated */
 static int num_editor_elements = 0;    /* dynamically determined */
 
+static boolean setup_editor_show_always = TRUE;
+static boolean setup_editor_cascade_never = FALSE;
+
+static int editor_hl_unused[] = { EL_EMPTY };
+static int *editor_hl_unused_ptr = editor_hl_unused;
+static int num_editor_hl_unused = 0;
+
 static struct
 {
   boolean *setup_value;
+  boolean *setup_cascade_value;
 
   int **headline_list;
   int *headline_list_size;
@@ -3776,296 +4805,110 @@ static struct
 }
 editor_elements_info[] =
 {
+  {
+    &setup_editor_show_always,
+    &setup_editor_cascade_never,
+    &editor_hl_unused_ptr,             &num_editor_hl_unused,
+    &editor_el_players_ptr,            &num_editor_el_players
+  },
   {
     &setup.editor.el_boulderdash,
+    &setup.editor_cascade.el_bd,
     &editor_hl_boulderdash_ptr,                &num_editor_hl_boulderdash,
     &editor_el_boulderdash_ptr,                &num_editor_el_boulderdash
   },
   {
     &setup.editor.el_emerald_mine,
+    &setup.editor_cascade.el_em,
     &editor_hl_emerald_mine_ptr,       &num_editor_hl_emerald_mine,
     &editor_el_emerald_mine_ptr,       &num_editor_el_emerald_mine
   },
   {
     &setup.editor.el_emerald_mine_club,
+    &setup.editor_cascade.el_emc,
     &editor_hl_emerald_mine_club_ptr,  &num_editor_hl_emerald_mine_club,
     &editor_el_emerald_mine_club_ptr,  &num_editor_el_emerald_mine_club
   },
   {
     &setup.editor.el_more,
-    &editor_hl_more_ptr,               &num_editor_hl_more,
-    &editor_el_more_ptr,               &num_editor_el_more
+    &setup.editor_cascade.el_rnd,
+    &editor_hl_rnd_ptr,                        &num_editor_hl_rnd,
+    &editor_el_rnd_ptr,                        &num_editor_el_rnd
   },
   {
     &setup.editor.el_sokoban,
+    &setup.editor_cascade.el_sb,
     &editor_hl_sokoban_ptr,            &num_editor_hl_sokoban,
     &editor_el_sokoban_ptr,            &num_editor_el_sokoban
   },
   {
     &setup.editor.el_supaplex,
+    &setup.editor_cascade.el_sp,
     &editor_hl_supaplex_ptr,           &num_editor_hl_supaplex,
     &editor_el_supaplex_ptr,           &num_editor_el_supaplex
   },
   {
     &setup.editor.el_diamond_caves,
+    &setup.editor_cascade.el_dc,
     &editor_hl_diamond_caves_ptr,      &num_editor_hl_diamond_caves,
     &editor_el_diamond_caves_ptr,      &num_editor_el_diamond_caves
   },
   {
     &setup.editor.el_dx_boulderdash,
+    &setup.editor_cascade.el_dx,
     &editor_hl_dx_boulderdash_ptr,     &num_editor_hl_dx_boulderdash,
     &editor_el_dx_boulderdash_ptr,     &num_editor_el_dx_boulderdash
   },
   {
     &setup.editor.el_chars,
+    &setup.editor_cascade.el_chars,
     &editor_hl_chars_ptr,              &num_editor_hl_chars,
     &editor_el_chars_ptr,              &num_editor_el_chars
   },
   {
     &setup.editor.el_custom,
+    &setup.editor_cascade.el_ce,
     &editor_hl_custom_ptr,             &num_editor_hl_custom,
     &editor_el_custom_ptr,             &num_editor_el_custom
   },
-  {
-    &setup.editor.el_custom_more,
-    &editor_hl_custom_more_ptr,                &num_editor_hl_custom_more,
-    &editor_el_custom_more_ptr,                &num_editor_el_custom_more
-  },
   {
     &setup.editor.el_custom,
-    &editor_hl_custom_special_ptr,     &num_editor_hl_custom_special,
-    &editor_el_custom_special_ptr,     &num_editor_el_custom_special
+    &setup.editor_cascade.el_ref,
+    &editor_hl_reference_ptr,          &num_editor_hl_reference,
+    &editor_el_reference_ptr,          &num_editor_el_reference
   },
   {
     &setup.editor.el_custom,
+    &setup.editor_cascade.el_ge,
     &editor_hl_group_ptr,              &num_editor_hl_group,
     &editor_el_group_ptr,              &num_editor_el_group
   },
-  {
-    &setup.editor.el_custom_more,
-    &editor_hl_group_more_ptr,         &num_editor_hl_group_more,
-    &editor_el_group_more_ptr,         &num_editor_el_group_more
-  },
   {
     &setup.editor.el_user_defined,
+    &setup.editor_cascade.el_user,
     &editor_hl_user_defined_ptr,       &num_editor_hl_user_defined,
     &editor_el_user_defined_ptr,       &num_editor_el_user_defined
   },
   {
+    &setup.editor.el_dynamic,
+    &setup.editor_cascade.el_dynamic,
+    &editor_hl_dynamic_ptr,            &num_editor_hl_dynamic,
+    &editor_el_dynamic_ptr,            &num_editor_el_dynamic,
+  },
+  {
+    &use_el_empty,
     &use_el_empty,
     &editor_hl_empty_ptr,              &num_editor_hl_empty,
     &editor_el_empty_ptr,              &num_editor_el_empty,
   },
   {
+    NULL,
     NULL,
     NULL,                              NULL,
     NULL,                              NULL
   }
 };
 
-#if 0
-
-static struct
-{
-  short element;
-  short element_mapped;
-}
-forum_sketch_element_mapping[] =
-{
-  { EL_WALL_SLIPPERY,                  EL_WALL                 },
-  { EL_EXPANDABLE_WALL,                        EL_WALL                 },
-  { EL_EXPANDABLE_WALL_HORIZONTAL,     EL_WALL                 },
-  { EL_EXPANDABLE_WALL_VERTICAL,       EL_WALL                 },
-  { EL_EXPANDABLE_WALL_ANY,            EL_WALL                 },
-  { EL_WALL_EMERALD,                   EL_WALL                 },
-  { EL_WALL_DIAMOND,                   EL_WALL                 },
-  { EL_WALL_BD_DIAMOND,                        EL_WALL                 },
-  { EL_WALL_EMERALD_YELLOW,            EL_WALL                 },
-  { EL_WALL_EMERALD_RED,               EL_WALL                 },
-  { EL_WALL_EMERALD_PURPLE,            EL_WALL                 },
-  { EL_ACID_POOL_TOPLEFT,              EL_WALL                 },
-  { EL_ACID_POOL_TOPRIGHT,             EL_WALL                 },
-  { EL_ACID_POOL_BOTTOMLEFT,           EL_WALL                 },
-  { EL_ACID_POOL_BOTTOM,               EL_WALL                 },
-  { EL_ACID_POOL_BOTTOMRIGHT,          EL_WALL                 },
-  { EL_BD_WALL,                                EL_WALL                 },
-
-  { EL_BD_ROCK,                                EL_ROCK                 },
-
-  { EL_SP_ZONK,                                EL_ROCK                 },
-  { EL_SP_BASE,                                EL_SAND                 },
-  { EL_SP_MURPHY,                      EL_PLAYER_1             },
-  { EL_SP_INFOTRON,                    EL_EMERALD              },
-  { EL_SP_HARDWARE_GRAY,               EL_STEELWALL            },
-  { EL_SP_EXIT_CLOSED,                 EL_EXIT_OPEN            },
-  { EL_SP_DISK_ORANGE,                 EL_BOMB                 },
-  { EL_SP_DISK_RED,                    EL_BOMB                 },
-  { EL_SP_DISK_YELLOW,                 EL_BOMB                 },
-  { EL_SP_PORT_RIGHT,                  EL_GATE_1_GRAY          },
-  { EL_SP_PORT_DOWN,                   EL_GATE_1_GRAY          },
-  { EL_SP_PORT_LEFT,                   EL_GATE_1_GRAY          },
-  { EL_SP_PORT_UP,                     EL_GATE_1_GRAY          },
-  { EL_SP_GRAVITY_PORT_RIGHT,          EL_GATE_1_GRAY          },
-  { EL_SP_GRAVITY_PORT_DOWN,           EL_GATE_1_GRAY          },
-  { EL_SP_GRAVITY_PORT_LEFT,           EL_GATE_1_GRAY          },
-  { EL_SP_GRAVITY_PORT_UP,             EL_GATE_1_GRAY          },
-  { EL_SP_PORT_VERTICAL,               EL_GATE_1_GRAY          },
-  { EL_SP_PORT_HORIZONTAL,             EL_GATE_1_GRAY          },
-  { EL_SP_PORT_ANY,                    EL_GATE_1_GRAY          },
-  { EL_SP_SNIKSNAK,                    EL_BUG                  },
-  { EL_SP_ELECTRON,                    EL_SPACESHIP            },
-  { EL_SP_CHIP_SINGLE,                 EL_WALL                 },
-  { EL_SP_CHIP_LEFT,                   EL_WALL                 },
-  { EL_SP_CHIP_RIGHT,                  EL_WALL                 },
-  { EL_SP_CHIP_TOP,                    EL_WALL                 },
-  { EL_SP_CHIP_BOTTOM,                 EL_WALL                 },
-  { EL_SP_HARDWARE_BASE_1,             EL_STEELWALL            },
-  { EL_SP_HARDWARE_GREEN,              EL_STEELWALL            },
-  { EL_SP_HARDWARE_BLUE,               EL_STEELWALL            },
-  { EL_SP_HARDWARE_RED,                        EL_STEELWALL            },
-  { EL_SP_HARDWARE_YELLOW,             EL_STEELWALL            },
-  { EL_SP_HARDWARE_BASE_2,             EL_STEELWALL            },
-  { EL_SP_HARDWARE_BASE_3,             EL_STEELWALL            },
-  { EL_SP_HARDWARE_BASE_3,             EL_STEELWALL            },
-  { EL_SP_HARDWARE_BASE_4,             EL_STEELWALL            },
-  { EL_SP_HARDWARE_BASE_5,             EL_STEELWALL            },
-  { EL_SP_HARDWARE_BASE_6,             EL_STEELWALL            },
-
-  { EL_STEELWALL_SLIPPERY,             EL_STEELWALL            },
-
-  { EL_EXIT_CLOSED,                    EL_EXIT_OPEN            },
-
-  { EL_DIAMOND,                                EL_EMERALD              },
-  { EL_BD_DIAMOND,                     EL_EMERALD              },
-  { EL_EMERALD_YELLOW,                 EL_EMERALD              },
-  { EL_EMERALD_RED,                    EL_EMERALD              },
-  { EL_EMERALD_PURPLE,                 EL_EMERALD              },
-
-  { EL_AMOEBA_DEAD,                    EL_AMOEBA               },
-  { EL_AMOEBA_DROP,                    EL_AMOEBA               },
-  { EL_AMOEBA_WET,                     EL_AMOEBA               },
-  { EL_AMOEBA_DRY,                     EL_AMOEBA               },
-  { EL_AMOEBA_FULL,                    EL_AMOEBA               },
-  { EL_BD_AMOEBA,                      EL_AMOEBA               },
-  { EL_AMOEBA_TO_DIAMOND,              EL_AMOEBA               },
-
-  { EL_DYNAMITE_ACTIVE,                        EL_DYNAMITE             },
-
-  { EL_GATE_2_GRAY,                    EL_GATE_1_GRAY          },
-  { EL_GATE_3_GRAY,                    EL_GATE_1_GRAY          },
-  { EL_GATE_4_GRAY,                    EL_GATE_1_GRAY          },
-
-  { EL_EM_KEY_1,                       EL_KEY_1                },
-  { EL_EM_KEY_2,                       EL_KEY_2                },
-  { EL_EM_KEY_3,                       EL_KEY_3                },
-  { EL_EM_KEY_4,                       EL_KEY_4                },
-
-  { EL_EM_GATE_1,                      EL_GATE_1               },
-  { EL_EM_GATE_2,                      EL_GATE_2               },
-  { EL_EM_GATE_3,                      EL_GATE_3               },
-  { EL_EM_GATE_4,                      EL_GATE_4               },
-
-  { EL_EM_GATE_1_GRAY,                 EL_GATE_1_GRAY          },
-  { EL_EM_GATE_2_GRAY,                 EL_GATE_1_GRAY          },
-  { EL_EM_GATE_3_GRAY,                 EL_GATE_1_GRAY          },
-  { EL_EM_GATE_4_GRAY,                 EL_GATE_1_GRAY          },
-
-  { EL_INVISIBLE_SAND,                 EL_EMPTY                },
-  { EL_INVISIBLE_WALL,                 EL_EMPTY                },
-  { EL_INVISIBLE_STEELWALL,            EL_EMPTY                },
-
-  { EL_PACMAN,                         EL_YAMYAM               },
-  { EL_DARK_YAMYAM,                    EL_YAMYAM               },
-
-  { EL_BD_MAGIC_WALL,                  EL_MAGIC_WALL           },
-
-  { EL_DYNABOMB_INCREASE_NUMBER,       EL_BOMB                 },
-  { EL_DYNABOMB_INCREASE_SIZE,         EL_BOMB                 },
-  { EL_DYNABOMB_INCREASE_POWER,                EL_BOMB                 },
-  { EL_BLACK_ORB,                      EL_BOMB                 },
-  { EL_DX_SUPABOMB,                    EL_BOMB                 },
-
-  { EL_SOKOBAN_OBJECT,                 EL_KEY_1                },
-  { EL_SOKOBAN_FIELD_EMPTY,            EL_GATE_1_GRAY          },
-  { EL_SOKOBAN_FIELD_FULL,             EL_GATE_1               },
-  { EL_SOKOBAN_FIELD_PLAYER,           EL_PLAYER_1             },
-
-  { EL_BD_BUTTERFLY_RIGHT,             EL_BD_BUTTERFLY         },
-  { EL_BD_BUTTERFLY_UP,                        EL_BD_BUTTERFLY         },
-  { EL_BD_BUTTERFLY_LEFT,              EL_BD_BUTTERFLY         },
-  { EL_BD_BUTTERFLY_DOWN,              EL_BD_BUTTERFLY         },
-
-  { EL_BD_FIREFLY_RIGHT,               EL_BD_FIREFLY           },
-  { EL_BD_FIREFLY_UP,                  EL_BD_FIREFLY           },
-  { EL_BD_FIREFLY_LEFT,                        EL_BD_FIREFLY           },
-  { EL_BD_FIREFLY_DOWN,                        EL_BD_FIREFLY           },
-
-  { EL_PLAYER_2,                       EL_PLAYER_1             },
-  { EL_PLAYER_3,                       EL_PLAYER_1             },
-  { EL_PLAYER_4,                       EL_PLAYER_1             },
-
-  { EL_BUG_RIGHT,                      EL_BUG                  },
-  { EL_BUG_UP,                         EL_BUG                  },
-  { EL_BUG_LEFT,                       EL_BUG                  },
-  { EL_BUG_DOWN,                       EL_BUG                  },
-
-  { EL_SPACESHIP_RIGHT,                        EL_SPACESHIP            },
-  { EL_SPACESHIP_UP,                   EL_SPACESHIP            },
-  { EL_SPACESHIP_LEFT,                 EL_SPACESHIP            },
-  { EL_SPACESHIP_DOWN,                 EL_SPACESHIP            },
-
-  { EL_PACMAN_RIGHT,                   EL_YAMYAM               },
-  { EL_PACMAN_UP,                      EL_YAMYAM               },
-  { EL_PACMAN_LEFT,                    EL_YAMYAM               },
-  { EL_PACMAN_DOWN,                    EL_YAMYAM               },
-
-  { -1,                                        -1                      }
-};
-
-static struct
-{
-  short element;
-  char *element_string;
-}
-forum_sketch_element_strings[] =
-{
-  { EL_PLAYER_1,               "p" },
-  { EL_EMPTY,                  "_" },
-  { EL_SAND,                   "s" },
-  { EL_ROCK,                   "b" },
-  { EL_EMERALD,                        "e" },
-  { EL_BUG,                    "u" },
-  { EL_SPACESHIP,              "h" },
-  { EL_BD_FIREFLY,             "f" },
-  { EL_BD_BUTTERFLY,           "b" },
-  { EL_AMOEBA,                 "a" },
-  { EL_YAMYAM,                 "y" },
-  { EL_WALL,                   "w" },
-  { EL_STEELWALL,              "t" },
-  { EL_MAGIC_WALL,             "m" },
-  { EL_EXIT_OPEN,              "x" },
-  { EL_DYNAMITE,               "d" },
-  { EL_KEY_1,                  "1" },
-  { EL_KEY_2,                  "2" },
-  { EL_KEY_3,                  "3" },
-  { EL_KEY_4,                  "4" },
-  { EL_GATE_1,                 "5" },
-  { EL_GATE_2,                 "6" },
-  { EL_GATE_3,                 "7" },
-  { EL_GATE_4,                 "8" },
-  { EL_GATE_1_GRAY,            "9" },
-  { EL_BOMB,                   "@" },
-  { EL_ROBOT,                  "r" },
-  { EL_ROBOT_WHEEL,            "0" },
-  { EL_NUT,                    "n" },
-  { EL_CUSTOM_1,               "c" },
-  { EL_CHAR_QUESTION,          "?" },
-
-  { -1,                                NULL }
-};
-
-#endif
-
 
 /*
   -----------------------------------------------------------------------------
@@ -4103,7 +4946,11 @@ static char *getElementInfoText(int element)
 {
   char *info_text = NULL;
 
+#if 1
+  if (element < MAX_NUM_ELEMENTS)
+#else
   if (element < NUM_FILE_ELEMENTS)
+#endif
   {
     if (strlen(element_info[element].description) > 0)
       info_text = element_info[element].description;
@@ -4119,44 +4966,131 @@ static char *getElementInfoText(int element)
   return info_text;
 }
 
+char *getElementDescriptionFilename(int element)
+{
+  char *docs_dir = options.docs_directory;
+  char *elements_subdir = "elements";
+  static char *filename = NULL;
+  char basename[MAX_FILENAME_LEN];
+
+  checked_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 void InitDynamicEditorElementList(int **elements, int *num_elements)
+{
+  boolean element_found[NUM_FILE_ELEMENTS];
+  int i, x, y;
+
+  /* initialize list of used elements to "not used" */
+  for (i = 0; i < NUM_FILE_ELEMENTS; i++)
+    element_found[i] = FALSE;
+
+  /* find all elements used in current level */
+  for (y = 0; y < lev_fieldy; y++)
+    for (x = 0; x < lev_fieldx; x++)
+      if (Feld[x][y] < NUM_FILE_ELEMENTS)      /* should always be true */
+       element_found[Feld[x][y]] = TRUE;
+
+  *num_elements = 0;
+
+  /* count number of elements used in current level */
+  for (i = 0; i < NUM_FILE_ELEMENTS; i++)
+    if (element_found[i])
+      (*num_elements)++;
+
+  /* add space for up to 3 more elements for padding that may be needed */
+  *num_elements += 3;
+
+  /* free memory for old list of elements, if needed */
+  checked_free(*elements);
+
+  /* allocate memory for new list of elements */
+  *elements = checked_malloc(*num_elements * sizeof(int));
+
+  *num_elements = 0;
+
+  /* add all elements used in current level (non-custom/group elements) */
+  for (i = 0; i < NUM_FILE_ELEMENTS; i++)
+    if (element_found[i] && !(IS_CUSTOM_ELEMENT(i) || IS_GROUP_ELEMENT(i)))
+      (*elements)[(*num_elements)++] = i;
+
+  /* add all elements used in current level (custom/group elements) */
+  for (i = 0; i < NUM_FILE_ELEMENTS; i++)
+    if (element_found[i] && (IS_CUSTOM_ELEMENT(i) || IS_GROUP_ELEMENT(i)))
+      (*elements)[(*num_elements)++] = i;
+
+  while (*num_elements % 4)    /* pad with empty elements, if needed */
+    (*elements)[(*num_elements)++] = EL_EMPTY;
+}
+
 static void ReinitializeElementList()
 {
-  static boolean initialized = FALSE;
+  static boolean initialization_needed = TRUE;
   int pos = 0;
   int i, j;
 
+  if (initialization_needed)
+  {
+    LoadSetup_EditorCascade();         /* load last editor cascade state */
+
+    /* initialize editor cascade element from saved cascade state */
+    for (i = 0; editor_elements_info[i].setup_value != NULL; i++)
+    {
+      int *cascade_element = &(*editor_elements_info[i].headline_list)[0];
+      boolean cascade_value = *editor_elements_info[i].setup_cascade_value;
+
+      if (IS_EDITOR_CASCADE(*cascade_element))
+       *cascade_element =
+         (cascade_value ? EL_CASCADE_ACTIVE(*cascade_element) :
+          EL_CASCADE_INACTIVE(*cascade_element));
+    }
+
+    initialization_needed = FALSE;
+  }
+
   checked_free(editor_elements);
 
-#if 0
-  if (!initialized)
-#else
-  /* reload user defined element list for each invocation of level editor */
-#endif
-  {
-    /* initialize optional user defined element list */
-    LoadUserDefinedEditorElementList(&editor_el_user_defined_ptr,
-                                    &num_editor_el_user_defined);
+  /* reload optional user defined element list for each invocation of editor */
+  LoadUserDefinedEditorElementList(&editor_el_user_defined_ptr,
+                                  &num_editor_el_user_defined);
 
-    /* initialize list of empty elements (used for padding, if needed) */
-    for (i = 0; i < ED_NUM_ELEMENTLIST_BUTTONS; i++)
-      editor_el_empty[i] = EL_EMPTY;
+  /* initialize dynamic level element list for each invocation of editor */
+  InitDynamicEditorElementList(&editor_el_dynamic_ptr,
+                              &num_editor_el_dynamic);
 
-    /* do some sanity checks for each element from element list */
-    for (i = 0; editor_elements_info[i].setup_value != NULL; i++)
+  /* initialize list of empty elements (used for padding, if needed) */
+  for (i = 0; i < ED_NUM_ELEMENTLIST_BUTTONS; i++)
+    editor_el_empty[i] = EL_EMPTY;
+
+  /* do some sanity checks for each element from element list */
+  for (i = 0; editor_elements_info[i].setup_value != NULL; i++)
+  {
+    for (j = 0; j < *editor_elements_info[i].element_list_size; j++)
     {
-      for (j = 0; j < *editor_elements_info[i].element_list_size; j++)
-      {
-       int element = (*editor_elements_info[i].element_list)[j];
+      int element = (*editor_elements_info[i].element_list)[j];
 
-       if (element >= NUM_FILE_ELEMENTS)
-         Error(ERR_WARN, "editor element %d is runtime element", element);
+      if (element >= NUM_FILE_ELEMENTS)
+       Error(ERR_WARN, "editor element %d is runtime element", element);
 
-       if (strcmp(getElementInfoText(element), INFOTEXT_UNKNOWN_ELEMENT) == 0)
-         Error(ERR_WARN, "no element description for element %d", element);
-      }
+      if (strEqual(getElementInfoText(element), INFOTEXT_UNKNOWN_ELEMENT))
+       Error(ERR_WARN, "no element description for element %d", element);
     }
-
-    initialized = TRUE;
   }
 
   num_editor_elements = 0;
@@ -4165,11 +5099,26 @@ static void ReinitializeElementList()
   /* determine size of element list */
   for (i = 0; editor_elements_info[i].setup_value != NULL; i++)
   {
+    boolean found_inactive_cascade = FALSE;
+
     if (*editor_elements_info[i].setup_value)
     {
       if (setup.editor.el_headlines)
+      {
        num_editor_elements += *editor_elements_info[i].headline_list_size;
 
+       for (j = 0; j < *editor_elements_info[i].headline_list_size; j++)
+       {
+         int element = (*editor_elements_info[i].headline_list)[j];
+
+         if (IS_EDITOR_CASCADE_INACTIVE(element))
+           found_inactive_cascade = TRUE;
+       }
+      }
+
+      if (found_inactive_cascade)
+       continue;
+
       num_editor_elements += *editor_elements_info[i].element_list_size;
     }
   }
@@ -4188,22 +5137,33 @@ static void ReinitializeElementList()
   /* fill element list */
   for (i = 0; editor_elements_info[i].setup_value != NULL; i++)
   {
+    boolean found_inactive_cascade = FALSE;
+
     if (*editor_elements_info[i].setup_value)
     {
       if (setup.editor.el_headlines)
+      {
        for (j = 0; j < *editor_elements_info[i].headline_list_size; j++)
-         editor_elements[pos++] = (*editor_elements_info[i].headline_list)[j];
+       {
+         int element = (*editor_elements_info[i].headline_list)[j];
+
+         editor_elements[pos++] = element;
+
+         if (IS_EDITOR_CASCADE_INACTIVE(element))
+           found_inactive_cascade = TRUE;
+       }
+      }
+
+      if (found_inactive_cascade)
+       continue;
 
       for (j = 0; j < *editor_elements_info[i].element_list_size; j++)
        editor_elements[pos++] = (*editor_elements_info[i].element_list)[j];
     }
   }
 
-  /* correct position of element list scrollbar */
-  if (element_shift < 0)
-    element_shift = 0;
-  if (element_shift > num_editor_elements - ED_NUM_ELEMENTLIST_BUTTONS)
-    element_shift = num_editor_elements - ED_NUM_ELEMENTLIST_BUTTONS;
+  /* (this function is also called before editor gadgets are initialized!) */
+  AdjustElementListScrollbar();
 }
 
 void PrintEditorElementList()
@@ -4213,10 +5173,25 @@ void PrintEditorElementList()
 
   for (i = 0; editor_elements_info[i].setup_value != stop; i++)
   {
+    int cascade_element = (*editor_elements_info[i].headline_list)[0];
+
+    if (IS_EDITOR_CASCADE(cascade_element))
+    {
+      int cascade_element_show = EL_CASCADE_INACTIVE(cascade_element);
+      char *headline = element_info[cascade_element_show].editor_description;
+
+      printf_line_with_prefix("# ", "-", 77);
+      printf("# %s\n", headline);
+      printf_line_with_prefix("# ", "-", 77);
+    }
+
     for (j = 0; j < *editor_elements_info[i].headline_list_size; j++)
     {
       int element = (*editor_elements_info[i].headline_list)[j];
 
+      if (IS_EDITOR_CASCADE(element))
+       element = EL_CHAR_MINUS;
+
       printf("# %s\n", element_info[element].token_name);
     }
 
@@ -4276,6 +5251,10 @@ static void DrawElementBorder(int dest_x, int dest_y, int width, int height,
   int src_x, src_y;
   int num_mini_tilex = width  / MINI_TILEX + 1;
   int num_mini_tiley = height / MINI_TILEY + 1;
+  int from_x = dest_x - MINI_TILEX / 2;
+  int from_y = dest_y - MINI_TILEY / 2;
+  int to_x = from_x + num_mini_tilex * MINI_TILEX - 1;
+  int to_y = from_y + num_mini_tiley * MINI_TILEY - 1;
   int x, y;
 
   getMiniGraphicSource(border_graphic, &src_bitmap, &src_x, &src_y);
@@ -4283,10 +5262,14 @@ static void DrawElementBorder(int dest_x, int dest_y, int width, int height,
   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);
+                from_x + x * MINI_TILEX, from_y + y * MINI_TILEY);
 
   ClearRectangle(drawto, dest_x - 1, dest_y - 1, width + 2, height + 2);
+
+  DrawSimpleBlackLine(drawto, from_x, from_y, to_x, from_y);
+  DrawSimpleBlackLine(drawto, to_x, from_y, to_x, to_y);
+  DrawSimpleBlackLine(drawto, to_x, to_y, from_x, to_y);
+  DrawSimpleBlackLine(drawto, from_x, to_y, from_x, from_y);
 }
 
 static void DrawDrawingArea(int id)
@@ -4294,64 +5277,16 @@ static void DrawDrawingArea(int id)
   struct GadgetInfo *gi = level_editor_gadget[drawingarea_info[id].gadget_id];
   int x, y;
 
-  if (id == ED_DRAWING_ID_RANDOM_BACKGROUND)
-    DrawMiniGraphicExt(drawto, gi->x, gi->y,
-                      el2edimg(random_placement_background_element));
-  else if (id == ED_DRAWING_ID_AMOEBA_CONTENT)
-    DrawMiniGraphicExt(drawto, gi->x, gi->y, el2edimg(level.amoeba_content));
-  else if (id == ED_DRAWING_ID_CUSTOM_GRAPHIC)
-    DrawMiniGraphicExt(drawto, gi->x, gi->y,
-                      el2edimg(custom_element.gfx_element));
-  else if (id == ED_DRAWING_ID_CUSTOM_CONTENT)
-    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]));
-  else if (id == ED_DRAWING_ID_CUSTOM_MOVE_ENTER)
-    DrawMiniGraphicExt(drawto, gi->x, gi->y,
-                      el2edimg(custom_element.move_enter_element));
-  else if (id == ED_DRAWING_ID_CUSTOM_MOVE_LEAVE)
-    DrawMiniGraphicExt(drawto, gi->x, gi->y,
-                      el2edimg(custom_element.move_leave_element));
-  else if (id == ED_DRAWING_ID_CUSTOM_CHANGE_TARGET)
-    DrawMiniGraphicExt(drawto, gi->x, gi->y,
-                      el2edimg(custom_element_change.target_element));
-  else if (id == ED_DRAWING_ID_CUSTOM_CHANGE_CONTENT)
-    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.target_content[x][y]));
-  else if (id == ED_DRAWING_ID_CUSTOM_CHANGE_TRIGGER)
-    DrawMiniGraphicExt(drawto, gi->x, gi->y,
-                      el2edimg(custom_element_change.trigger_element));
-  else if (id == ED_DRAWING_ID_GROUP_CONTENT)
-    for (x = 0; x < group_element_info.num_elements; x++)
-      DrawMiniGraphicExt(drawto, gi->x + x * MINI_TILEX, gi->y,
-                        el2edimg(group_element_info.element[x]));
-  else if (id >= ED_DRAWING_ID_YAMYAM_CONTENT_0 &&
-          id <= ED_DRAWING_ID_YAMYAM_CONTENT_7)
-  {
-    int nr = id - ED_DRAWING_ID_YAMYAM_CONTENT_0;
-
-    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(level.yamyam_content[nr][x][y]));
-  }
-  else if (id >= ED_DRAWING_ID_MAGIC_BALL_CONTENT_0 &&
-          id <= ED_DRAWING_ID_MAGIC_BALL_CONTENT_7)
-  {
-    int nr = id - ED_DRAWING_ID_MAGIC_BALL_CONTENT_0;
+  int *value = drawingarea_info[id].value;
+  int area_xsize = drawingarea_info[id].area_xsize;
+  int area_ysize = drawingarea_info[id].area_ysize;
 
-    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(level.ball_content[nr][x][y]));
-  }
+  for (x = 0; x < area_xsize; x++)
+    for (y = 0; y < area_ysize; y++)
+      DrawMiniGraphicExt(drawto,
+                        gi->x + x * MINI_TILEX,
+                        gi->y + y * MINI_TILEY,
+                        el2edimg(value[x * area_ysize + y]));
 }
 
 static void ScrollMiniLevel(int from_x, int from_y, int scroll)
@@ -5377,7 +6312,11 @@ void FreeLevelEditorGadgets()
   int i;
 
   for (i = 0; i < NUM_EDITOR_GADGETS; i++)
+  {
     FreeGadget(level_editor_gadget[i]);
+
+    level_editor_gadget[i] = NULL;
+  }
 }
 
 static void MapCounterButtons(int id)
@@ -5388,34 +6327,39 @@ static void MapCounterButtons(int id)
   struct GadgetInfo *gi_down = level_editor_gadget[gadget_id_down];
   struct GadgetInfo *gi_text = level_editor_gadget[gadget_id_text];
   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 = getTextWidthForGadget(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;
+#if 1
+  int x_right; /* set after gadget position was modified */
+#else
   int x_right = gi_up->x + gi_up->width + xoffset_right;
+#endif
   int y_above = gi_down->y - yoffset_above;
   int x = gi_down->x;
   int y;       /* set after gadget position was modified */
-#endif
 
-  /* set position for "value1/value2" counter gadgets (score in most cases) */
-  if (id == ED_COUNTER_ID_ELEMENT_VALUE1 ||
-      id == ED_COUNTER_ID_ELEMENT_VALUE2)
+  /* counter limits must be changed first to prevent value truncation */
+  ModifyEditorCounterLimits(id, counterbutton_info[id].min_value,
+                           counterbutton_info[id].max_value);
+
+  /* right text position might have changed after setting position above */
+  x_right = gi_up->x + gi_up->width + xoffset_right;
+
+  ModifyEditorCounterValue(id, *counterbutton_info[id].value);
+
+  /* set position for "value[1,2,3,4]" counter gadgets (score in most cases) */
+  if (id >= ED_COUNTER_ID_ELEMENT_VALUE1 &&
+      id <= ED_COUNTER_ID_ELEMENT_VALUE4)
   {
     ModifyGadget(gi_down, GDI_Y, SY + counterbutton_info[id].y, GDI_END);
     ModifyGadget(gi_text, GDI_Y, SY + counterbutton_info[id].y, GDI_END);
     ModifyGadget(gi_up,   GDI_Y, SY + counterbutton_info[id].y, GDI_END);
   }
 
+  /* vertical position might have changed after setting position above */
   y = gi_up->y + yoffset;
 
   if (counterbutton_info[id].text_above)
@@ -5427,8 +6371,6 @@ static void MapCounterButtons(int id)
   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(gi_down);
   MapGadget(gi_text);
   MapGadget(gi_up);
@@ -5452,9 +6394,8 @@ static void MapControlButtons()
 
   /* map buttons to select level */
   counter_id = ED_COUNTER_ID_SELECT_LEVEL;
-  ModifyEditorCounterLimits(counter_id,
-                           leveldir_current->first_level,
-                           leveldir_current->last_level);
+  counterbutton_info[counter_id].min_value = leveldir_current->first_level;
+  counterbutton_info[counter_id].max_value = leveldir_current->last_level;
   MapCounterButtons(counter_id);
 }
 
@@ -5539,7 +6480,7 @@ static void MapSelectboxGadget(int id)
   if (selectbox_info[id].text_right)
     DrawText(x_right, y, selectbox_info[id].text_right, FONT_TEXT_1);
 
-  ModifyEditorSelectbox(id, *selectbox_info[id].value);
+  ModifyEditorSelectboxValue(id, *selectbox_info[id].value);
 
   MapGadget(gi);
 }
@@ -5806,11 +6747,12 @@ static boolean LevelContainsPlayer()
 
   return TRUE;         /* !!! CURRENTLY DEACTIVATED !!! */
 
-  for (y = 0; y < lev_fieldy; y++) 
-    for (x = 0; x < lev_fieldx; x++)
-      if (Feld[x][y] == EL_PLAYER_1 ||
-         Feld[x][y] == EL_SP_MURPHY) 
-       player_found = TRUE;
+  for (y = 0; y < lev_fieldy; y++) for (x = 0; x < lev_fieldx; x++)
+  {
+    if (Feld[x][y] == EL_PLAYER_1 ||
+       Feld[x][y] == EL_SP_MURPHY) 
+      player_found = TRUE;
+  }
 
   return player_found;
 }
@@ -5825,57 +6767,96 @@ static void CopyPlayfield(short src[MAX_LEV_FIELDX][MAX_LEV_FIELDY],
       dst[x][y] = src[x][y];
 }
 
-static int setSelectboxValue(int selectbox_id, int new_value)
+static int setSelectboxValue(int selectbox_id, int new_value)
+{
+  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;
+
+  return new_index_value;
+}
+
+static void setSelectboxSpecialActionVariablesIfNeeded()
+{
+  int i;
+
+  /* change action mode and arg variables according to action type variable */
+  for (i = 0; action_arg_options[i].value != -1; i++)
+  {
+    if (action_arg_options[i].value == custom_element_change.action_type)
+    {
+      int mode = action_arg_options[i].mode;
+
+      /* only change if corresponding selectbox has changed */
+      if (selectbox_info[ED_SELECTBOX_ID_ACTION_MODE].options !=
+         action_arg_modes[mode])
+#if 0
+       custom_element_change.action_mode =
+         (action_arg_modes[mode])[0].value;
+#else
+       custom_element_change.action_mode = -1;
+#endif
+
+      /* only change if corresponding selectbox has changed */
+      if (selectbox_info[ED_SELECTBOX_ID_ACTION_ARG].options !=
+         action_arg_options[i].options)
+#if 0
+       custom_element_change.action_arg =
+         action_arg_options[i].options[0].value;
+#else
+       custom_element_change.action_arg = -1;
+#endif
+
+      break;
+    }
+  }
+}
+
+static void setSelectboxSpecialActionOptions()
 {
-  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;
+  /* change action mode and arg selectbox according to action type selectbox */
+  for (i = 0; action_arg_options[i].value != -1; i++)
+  {
+    if (action_arg_options[i].value == custom_element_change.action_type)
+    {
+      int mode = action_arg_options[i].mode;
 
-  *selectbox_info[selectbox_id].value =
-    selectbox_info[selectbox_id].options[new_index_value].value;
+      ModifyEditorSelectboxOptions(ED_SELECTBOX_ID_ACTION_MODE,
+                                  action_arg_modes[mode]);
+      ModifyEditorSelectboxValue(ED_SELECTBOX_ID_ACTION_MODE,
+                                custom_element_change.action_mode);
 
-  return new_index_value;
+      ModifyEditorSelectboxOptions(ED_SELECTBOX_ID_ACTION_ARG,
+                                  action_arg_options[i].options);
+      ModifyEditorSelectboxValue(ED_SELECTBOX_ID_ACTION_ARG,
+                                custom_element_change.action_arg);
+      break;
+    }
+  }
 }
 
+#if 1
+
 static void copy_custom_element_settings(int element_from, int element_to)
 {
-#if 0
-  struct ElementInfo ei_to_old = element_info[element_to];
   struct ElementInfo *ei_from = &element_info[element_from];
   struct ElementInfo *ei_to = &element_info[element_to];
-  int i;
-
-  /* ---------- copy whole element structure ---------- */
-  *ei_to = *ei_from;
-
-  /* ---------- restore structure pointers which cannot be copied ---------- */
-  ei_to->token_name         = ei_to_old.token_name;
-  ei_to->class_name         = ei_to_old.class_name;
-  ei_to->editor_description = ei_to_old.editor_description;
-  ei_to->custom_description = ei_to_old.custom_description;
-  ei_to->change_page        = ei_to_old.change_page;
-  ei_to->change             = ei_to_old.change;
-  ei_to->group              = ei_to_old.group;
-
-  /* ---------- copy element base properties ---------- */
-  Properties[element_to][EP_BITFIELD_BASE] =
-    Properties[element_from][EP_BITFIELD_BASE];
-
-  /* ---------- reinitialize and copy change pages ---------- */
-  setElementChangePages(ei_to, ei_to->num_change_pages);
-
-  for (i=0; i < ei_to->num_change_pages; i++)
-    ei_to->change_page[i] = ei_from->change_page[i];
 
-  /* ---------- copy group element info ---------- */
-  if (ei_from->group != NULL && ei_to->group != NULL)  /* group or internal */
-    *ei_to->group = *ei_from->group;
+  copyElementInfo(ei_from, ei_to);
+}
 
 #else
 
+static void copy_custom_element_settings(int element_from, int element_to)
+{
   struct ElementInfo *ei_from = &element_info[element_from];
   struct ElementInfo *ei_to = &element_info[element_to];
   int i, x, y;
@@ -5885,8 +6866,13 @@ static void copy_custom_element_settings(int element_from, int element_to)
     ei_to->description[i] = ei_from->description[i];
 
   /* ---------- copy element base properties ---------- */
-  Properties[element_to][EP_BITFIELD_BASE] =
-    Properties[element_from][EP_BITFIELD_BASE];
+#if 1
+  ei_to->properties[EP_BITFIELD_BASE_NR] =
+    ei_from->properties[EP_BITFIELD_BASE_NR];
+#else
+  Properties[element_to][EP_BITFIELD_BASE_NR] =
+    Properties[element_from][EP_BITFIELD_BASE_NR];
+#endif
 
   /* ---------- copy custom property values ---------- */
 
@@ -5895,8 +6881,12 @@ static void copy_custom_element_settings(int element_from, int element_to)
 
   ei_to->access_direction = ei_from->access_direction;
 
-  ei_to->collect_score = ei_from->collect_score;
-  ei_to->collect_count = ei_from->collect_count;
+  ei_to->collect_score_initial = ei_from->collect_score_initial;
+  ei_to->collect_count_initial = ei_from->collect_count_initial;
+
+  ei_to->ce_value_fixed_initial = ei_from->ce_value_fixed_initial;
+  ei_to->ce_value_random_initial = ei_from->ce_value_random_initial;
+  ei_to->use_last_ce_value = ei_from->use_last_ce_value;
 
   ei_to->push_delay_fixed = ei_from->push_delay_fixed;
   ei_to->push_delay_random = ei_from->push_delay_random;
@@ -5915,14 +6905,14 @@ static void copy_custom_element_settings(int element_from, int element_to)
 
   ei_to->slippery_type = ei_from->slippery_type;
 
-  for (y = 0; y < 3; y++)
-    for (x = 0; x < 3; x++)
-      ei_to->content[x][y] = ei_from->content[x][y];
-
   ei_to->explosion_type = ei_from->explosion_type;
   ei_to->explosion_delay = ei_from->explosion_delay;
   ei_to->ignition_delay = ei_from->ignition_delay;
 
+  for (y = 0; y < 3; y++)
+    for (x = 0; x < 3; x++)
+      ei_to->content.e[x][y] = ei_from->content.e[x][y];
+
   /* ---------- reinitialize and copy change pages ---------- */
 
   ei_to->num_change_pages = ei_from->num_change_pages;
@@ -5930,18 +6920,17 @@ static void copy_custom_element_settings(int element_from, int element_to)
 
   setElementChangePages(ei_to, ei_to->num_change_pages);
 
-  for (i=0; i < ei_to->num_change_pages; i++)
+  for (i = 0; i < ei_to->num_change_pages; i++)
     ei_to->change_page[i] = ei_from->change_page[i];
 
   /* ---------- copy group element info ---------- */
   if (ei_from->group != NULL && ei_to->group != NULL)  /* group or internal */
     *ei_to->group = *ei_from->group;
 
-#endif
-
   /* mark this custom element as modified */
   ei_to->modified_settings = TRUE;
 }
+#endif
 
 static void replace_custom_element_in_settings(int element_from,
                                               int element_to)
@@ -5954,8 +6943,8 @@ static void replace_custom_element_in_settings(int element_from,
 
     for (y = 0; y < 3; y++)
       for (x = 0; x < 3; x++)
-       if (ei->content[x][y] == element_from)
-         ei->content[x][y] = element_to;
+       if (ei->content.e[x][y] == element_from)
+         ei->content.e[x][y] = element_to;
 
     for (j = 0; j < ei->num_change_pages; j++)
     {
@@ -5969,8 +6958,8 @@ static void replace_custom_element_in_settings(int element_from,
 
       for (y = 0; y < 3; y++)
        for (x = 0; x < 3; x++)
-         if (change->target_content[x][y] == element_from)
-           change->target_content[x][y] = element_to;
+         if (change->target_content.e[x][y] == element_from)
+           change->target_content.e[x][y] = element_to;
     }
 
     if (ei->group != NULL)                             /* group or internal */
@@ -6080,6 +7069,9 @@ static void CopyCustomElementPropertiesToEditor(int element)
   custom_element = element_info[element];
   custom_element_change = *element_info[element].change;
 
+  /* needed to initially set selectbox options for special action options */
+  setSelectboxSpecialActionOptions();
+
   /* needed to initially set selectbox value variables to reliable defaults */
   for (i = 0; i < ED_NUM_SELECTBOX; i++)
     setSelectboxValue(i, *selectbox_info[i].value);
@@ -6146,49 +7138,14 @@ static void CopyCustomElementPropertiesToEditor(int element)
      DONT_COLLIDE_WITH(element) ||
      DONT_RUN_INTO(element));
 
-#if 0
-  /* set explosion type selectbox help value */
-  custom_element.explosion_type =
-    (
-#if 0
-     IS_INDESTRUCTIBLE(element) ? EP_INDESTRUCTIBLE :
-#endif
-     CAN_EXPLODE_1X1(element) ? EP_CAN_EXPLODE_1X1 :
-     CAN_EXPLODE_3X3(element) ? EP_CAN_EXPLODE_3X3 :
-     CAN_EXPLODE_CROSS(element) ? EP_CAN_EXPLODE_CROSS :
-     custom_element.explosion_type);
-  custom_element_properties[EP_CAN_EXPLODE_AT_ALL] =
-    (
-#if 0
-     IS_INDESTRUCTIBLE(element) ||
-#endif
-     CAN_EXPLODE_1X1(element) ||
-     CAN_EXPLODE_3X3(element) ||
-     CAN_EXPLODE_CROSS(element));
-#endif
-
-#if 0
-  /* special case: sub-settings dependent from main setting */
-#if 0
-  custom_element.can_explode_by_fire = CAN_EXPLODE_BY_FIRE(element);
-  custom_element.can_explode_smashed = CAN_EXPLODE_SMASHED(element);
-  custom_element.can_explode_impact  = CAN_EXPLODE_IMPACT(element);
-#else
-  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;
-#endif
-#endif
-
   /* ---------- element settings: advanced (custom elements) --------------- */
 
   /* set "change by direct action" selectbox help value */
   custom_element_change.direct_action =
     (HAS_CHANGE_EVENT(element, CE_TOUCHED_BY_PLAYER) ? CE_TOUCHED_BY_PLAYER :
      HAS_CHANGE_EVENT(element, CE_PRESSED_BY_PLAYER) ? CE_PRESSED_BY_PLAYER :
+     HAS_CHANGE_EVENT(element, CE_SWITCHED_BY_PLAYER) ? CE_SWITCHED_BY_PLAYER :
+     HAS_CHANGE_EVENT(element, CE_SNAPPED_BY_PLAYER) ? CE_SNAPPED_BY_PLAYER :
      HAS_CHANGE_EVENT(element, CE_PUSHED_BY_PLAYER) ? CE_PUSHED_BY_PLAYER :
      HAS_CHANGE_EVENT(element, CE_ENTERED_BY_PLAYER) ? CE_ENTERED_BY_PLAYER :
      HAS_CHANGE_EVENT(element, CE_LEFT_BY_PLAYER) ? CE_LEFT_BY_PLAYER :
@@ -6199,12 +7156,18 @@ static void CopyCustomElementPropertiesToEditor(int element)
      HAS_CHANGE_EVENT(element, CE_BLOCKED) ? CE_BLOCKED :
      HAS_CHANGE_EVENT(element, CE_IMPACT) ? CE_IMPACT :
      HAS_CHANGE_EVENT(element, CE_SMASHED) ? CE_SMASHED :
+     HAS_CHANGE_EVENT(element, CE_VALUE_CHANGES) ? CE_VALUE_CHANGES :
+     HAS_CHANGE_EVENT(element, CE_SCORE_CHANGES) ? CE_SCORE_CHANGES :
+     HAS_CHANGE_EVENT(element, CE_VALUE_GETS_ZERO) ? CE_VALUE_GETS_ZERO :
+     HAS_CHANGE_EVENT(element, CE_SCORE_GETS_ZERO) ? CE_SCORE_GETS_ZERO :
      custom_element_change.direct_action);
 
   /* set "change by other element action" selectbox help value */
   custom_element_change.other_action =
     (HAS_CHANGE_EVENT(element, CE_PLAYER_TOUCHES_X) ? CE_PLAYER_TOUCHES_X :
      HAS_CHANGE_EVENT(element, CE_PLAYER_PRESSES_X) ? CE_PLAYER_PRESSES_X :
+     HAS_CHANGE_EVENT(element, CE_PLAYER_SWITCHES_X) ? CE_PLAYER_SWITCHES_X :
+     HAS_CHANGE_EVENT(element, CE_PLAYER_SNAPS_X) ? CE_PLAYER_SNAPS_X :
      HAS_CHANGE_EVENT(element, CE_PLAYER_PUSHES_X) ? CE_PLAYER_PUSHES_X :
      HAS_CHANGE_EVENT(element, CE_PLAYER_ENTERS_X) ? CE_PLAYER_ENTERS_X :
      HAS_CHANGE_EVENT(element, CE_PLAYER_LEAVES_X) ? CE_PLAYER_LEAVES_X :
@@ -6213,10 +7176,17 @@ static void CopyCustomElementPropertiesToEditor(int element)
      HAS_CHANGE_EVENT(element, CE_PLAYER_DROPS_X) ? CE_PLAYER_DROPS_X :
      HAS_CHANGE_EVENT(element, CE_TOUCHING_X) ? CE_TOUCHING_X :
      HAS_CHANGE_EVENT(element, CE_HITTING_X) ? CE_HITTING_X :
+     HAS_CHANGE_EVENT(element, CE_DIGGING_X) ? CE_DIGGING_X :
      HAS_CHANGE_EVENT(element, CE_HIT_BY_X) ? CE_HIT_BY_X :
      HAS_CHANGE_EVENT(element, CE_SWITCH_OF_X) ? CE_SWITCH_OF_X :
      HAS_CHANGE_EVENT(element, CE_CHANGE_OF_X) ? CE_CHANGE_OF_X :
      HAS_CHANGE_EVENT(element, CE_EXPLOSION_OF_X) ? CE_EXPLOSION_OF_X :
+     HAS_CHANGE_EVENT(element, CE_MOVE_OF_X) ? CE_MOVE_OF_X :
+     HAS_CHANGE_EVENT(element, CE_CREATION_OF_X) ? CE_CREATION_OF_X :
+     HAS_CHANGE_EVENT(element, CE_VALUE_CHANGES_OF_X) ? CE_VALUE_CHANGES_OF_X :
+     HAS_CHANGE_EVENT(element, CE_SCORE_CHANGES_OF_X) ? CE_SCORE_CHANGES_OF_X :
+     HAS_CHANGE_EVENT(element, CE_VALUE_GETS_ZERO_OF_X) ? CE_VALUE_GETS_ZERO_OF_X :
+     HAS_CHANGE_EVENT(element, CE_SCORE_GETS_ZERO_OF_X) ? CE_SCORE_GETS_ZERO_OF_X :
      custom_element_change.other_action);
 }
 
@@ -6228,7 +7198,6 @@ static void CopyGroupElementPropertiesToEditor(int element)
 
 static void CopyClassicElementPropertiesToEditor(int element)
 {
-#if 1
   if (ELEM_IS_PLAYER(element) || COULD_MOVE_INTO_ACID(element))
     custom_element_properties[EP_CAN_MOVE_INTO_ACID] =
       getMoveIntoAcidProperty(&level, element);
@@ -6236,17 +7205,6 @@ static void CopyClassicElementPropertiesToEditor(int element)
   if (MAYBE_DONT_COLLIDE_WITH(element))
     custom_element_properties[EP_DONT_COLLIDE_WITH] =
       getDontCollideWithProperty(&level, element);
-#else
-
-  if (COULD_MOVE_INTO_ACID(element))
-  {
-    int bit_nr = get_special_property_bit(element, EP_CAN_MOVE_INTO_ACID);
-
-    if (bit_nr > -1)
-      custom_element_properties[EP_CAN_MOVE_INTO_ACID] =
-       ((level.can_move_into_acid_bits & (1 << bit_nr)) != 0);
-  }
-#endif
 }
 
 static void CopyElementPropertiesToEditor(int element)
@@ -6263,9 +7221,6 @@ static void CopyCustomElementPropertiesToGame(int element)
 {
   int i;
   int access_type_and_layer;
-#if 0
-  boolean can_explode;
-#endif
 
   /* mark that this custom element has been modified */
   custom_element.modified_settings = TRUE;
@@ -6331,53 +7286,13 @@ static void CopyCustomElementPropertiesToGame(int element)
   custom_element_properties[custom_element.deadliness] =
     custom_element_properties[EP_DEADLY];
 
-#if 0
-  /* set explosion type property from checkbox and selectbox */
-#if 0
-  custom_element_properties[EP_INDESTRUCTIBLE] = FALSE;
-#endif
-  custom_element_properties[EP_CAN_EXPLODE_1X1] = FALSE;
-  custom_element_properties[EP_CAN_EXPLODE_3X3] = FALSE;
-  custom_element_properties[EP_CAN_EXPLODE_CROSS] = 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.explosion_type] =
-    custom_element_properties[EP_CAN_EXPLODE_AT_ALL];
-#endif
-
-#if 0
-  /* special case: sub-settings dependent from main setting */
-#if 0
-  can_explode = (custom_element_properties[EP_CAN_EXPLODE_1X1] ||
-                custom_element_properties[EP_CAN_EXPLODE_3X3] ||
-                custom_element_properties[EP_CAN_EXPLODE_CROSS]);
-  custom_element_properties[EP_CAN_EXPLODE_BY_FIRE] =
-    (can_explode && custom_element.can_explode_by_fire);
-  custom_element_properties[EP_CAN_EXPLODE_SMASHED] =
-    (can_explode && custom_element.can_explode_smashed);
-  custom_element_properties[EP_CAN_EXPLODE_IMPACT] =
-    (can_explode && custom_element.can_explode_impact);
-#else
-  if (custom_element_properties[EP_CAN_EXPLODE_1X1] ||
-      custom_element_properties[EP_CAN_EXPLODE_3X3] ||
-      custom_element_properties[EP_CAN_EXPLODE_CROSS])
-  {
-    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;
-  }
-#endif
-#endif
-
   /* ---------- 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_SWITCHED_BY_PLAYER] = FALSE;
+  custom_element_change_events[CE_SNAPPED_BY_PLAYER] = FALSE;
   custom_element_change_events[CE_PUSHED_BY_PLAYER] = FALSE;
   custom_element_change_events[CE_ENTERED_BY_PLAYER] = FALSE;
   custom_element_change_events[CE_LEFT_BY_PLAYER] = FALSE;
@@ -6388,12 +7303,18 @@ static void CopyCustomElementPropertiesToGame(int element)
   custom_element_change_events[CE_BLOCKED] = FALSE;
   custom_element_change_events[CE_IMPACT] = FALSE;
   custom_element_change_events[CE_SMASHED] = FALSE;
+  custom_element_change_events[CE_VALUE_CHANGES] = FALSE;
+  custom_element_change_events[CE_SCORE_CHANGES] = FALSE;
+  custom_element_change_events[CE_VALUE_GETS_ZERO] = FALSE;
+  custom_element_change_events[CE_SCORE_GETS_ZERO] = FALSE;
   custom_element_change_events[custom_element_change.direct_action] =
     custom_element_change_events[CE_BY_DIRECT_ACTION];
 
   /* set other element action change event from checkbox and selectbox */
   custom_element_change_events[CE_PLAYER_TOUCHES_X] = FALSE;
   custom_element_change_events[CE_PLAYER_PRESSES_X] = FALSE;
+  custom_element_change_events[CE_PLAYER_SWITCHES_X] = FALSE;
+  custom_element_change_events[CE_PLAYER_SNAPS_X] = FALSE;
   custom_element_change_events[CE_PLAYER_PUSHES_X] = FALSE;
   custom_element_change_events[CE_PLAYER_ENTERS_X] = FALSE;
   custom_element_change_events[CE_PLAYER_LEAVES_X] = FALSE;
@@ -6402,10 +7323,17 @@ static void CopyCustomElementPropertiesToGame(int element)
   custom_element_change_events[CE_PLAYER_DROPS_X] = FALSE;
   custom_element_change_events[CE_TOUCHING_X] = FALSE;
   custom_element_change_events[CE_HITTING_X] = FALSE;
+  custom_element_change_events[CE_DIGGING_X] = FALSE;
   custom_element_change_events[CE_HIT_BY_X] = FALSE;
   custom_element_change_events[CE_SWITCH_OF_X] = FALSE;
   custom_element_change_events[CE_CHANGE_OF_X] = FALSE;
   custom_element_change_events[CE_EXPLOSION_OF_X] = FALSE;
+  custom_element_change_events[CE_MOVE_OF_X] = FALSE;
+  custom_element_change_events[CE_CREATION_OF_X] = FALSE;
+  custom_element_change_events[CE_VALUE_CHANGES_OF_X] = FALSE;
+  custom_element_change_events[CE_SCORE_CHANGES_OF_X] = FALSE;
+  custom_element_change_events[CE_VALUE_GETS_ZERO_OF_X] = FALSE;
+  custom_element_change_events[CE_SCORE_GETS_ZERO_OF_X] = FALSE;
   custom_element_change_events[custom_element_change.other_action] =
     custom_element_change_events[CE_BY_OTHER_ACTION];
 
@@ -6432,7 +7360,6 @@ static void CopyGroupElementPropertiesToGame(int element)
 
 static void CopyClassicElementPropertiesToGame(int element)
 {
-#if 1
   if (ELEM_IS_PLAYER(element) || COULD_MOVE_INTO_ACID(element))
     setMoveIntoAcidProperty(&level, element,
                            custom_element_properties[EP_CAN_MOVE_INTO_ACID]);
@@ -6440,21 +7367,6 @@ static void CopyClassicElementPropertiesToGame(int element)
   if (MAYBE_DONT_COLLIDE_WITH(element))
     setDontCollideWithProperty(&level, element,
                              custom_element_properties[EP_DONT_COLLIDE_WITH]);
-#else
-
-  if (COULD_MOVE_INTO_ACID(element))
-  {
-    int bit_nr = get_special_property_bit(element, EP_CAN_MOVE_INTO_ACID);
-
-    if (bit_nr > -1)
-    {
-      level.can_move_into_acid_bits &= ~(1 << bit_nr);
-
-      if (custom_element_properties[EP_CAN_MOVE_INTO_ACID])
-       level.can_move_into_acid_bits |= (1 << bit_nr);
-    }
-  }
-#endif
 }
 
 static void CopyElementPropertiesToGame(int element)
@@ -6467,11 +7379,24 @@ static void CopyElementPropertiesToGame(int element)
     CopyClassicElementPropertiesToGame(element);
 }
 
+void CheckElementDescriptions()
+{
+  int i;
+
+  for (i = 0; i < NUM_FILE_ELEMENTS; i++)
+    if (getElementDescriptionFilename(i) == NULL && !IS_OBSOLETE(i))
+      Error(ERR_WARN, "no element description for element '%s'", EL_NAME(i));
+}
+
 void DrawLevelEd()
 {
   CloseDoor(DOOR_CLOSE_ALL);
   OpenDoor(DOOR_OPEN_2 | DOOR_NO_DELAY);
 
+#if DEBUG
+  CheckElementDescriptions();
+#endif
+
   if (level_editor_test_game)
   {
     CopyPlayfield(level.field, Feld);
@@ -6494,11 +7419,6 @@ void DrawLevelEd()
   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 */
-  RedrawDrawingElements();
-#endif
-
   /* draw bigger door */
   DrawSpecialEditorDoor();
 
@@ -6508,10 +7428,8 @@ void DrawLevelEd()
 
   redraw_mask |= REDRAW_ALL;
 
+  ReinitializeElementList();           /* update dynamic level element list */
   ReinitializeElementListButtons();    /* custom element may look different */
-#if 0
-  ModifyEditorElementList();           /* may be needed for custom elements */
-#endif
 
   UnmapTapeButtons();
   MapControlButtons();
@@ -6629,7 +7547,27 @@ static void AdjustEditorScrollbar(int id)
               GDI_SCROLLBAR_ITEM_POSITION, item_position, GDI_END);
 }
 
-static void ModifyEditorCounter(int counter_id, int new_value)
+static void AdjustElementListScrollbar()
+{
+  struct GadgetInfo *gi = level_editor_gadget[GADGET_ID_SCROLL_LIST_VERTICAL];
+  int items_max, items_visible, item_position;
+
+  /* correct position of element list scrollbar */
+  if (element_shift < 0)
+    element_shift = 0;
+  if (element_shift > num_editor_elements - ED_NUM_ELEMENTLIST_BUTTONS)
+    element_shift = num_editor_elements - ED_NUM_ELEMENTLIST_BUTTONS;
+
+  items_max = num_editor_elements / ED_ELEMENTLIST_BUTTONS_HORIZ;
+  items_visible = ED_ELEMENTLIST_BUTTONS_VERT;
+  item_position = element_shift / ED_ELEMENTLIST_BUTTONS_HORIZ;
+
+  ModifyGadget(gi, GDI_SCROLLBAR_ITEMS_MAX, items_max,
+              GDI_SCROLLBAR_ITEMS_VISIBLE, items_visible,
+              GDI_SCROLLBAR_ITEM_POSITION, item_position, GDI_END);
+}
+
+static void ModifyEditorCounterValue(int counter_id, int new_value)
 {
   int *counter_value = counterbutton_info[counter_id].value;
   int gadget_id = counterbutton_info[counter_id].gadget_id_text;
@@ -6647,9 +7585,19 @@ static void ModifyEditorCounterLimits(int counter_id, int min, int max)
   struct GadgetInfo *gi = level_editor_gadget[gadget_id];
 
   ModifyGadget(gi, GDI_NUMBER_MIN, min, GDI_NUMBER_MAX, max, GDI_END);
+
+  if (counter_id >= ED_COUNTER_ID_ELEMENT_VALUE1 &&
+      counter_id <= ED_COUNTER_ID_ELEMENT_VALUE4)
+  {
+    int gadget_id_up = counterbutton_info[counter_id].gadget_id_up;
+    struct GadgetInfo *gi_up = level_editor_gadget[gadget_id_up];
+
+    ModifyGadget(gi, GDI_TEXT_SIZE, (max < 10 ? 1 : 3), GDI_END);
+    ModifyGadget(gi_up, GDI_X, gi->x + gi->width + ED_GADGET_DISTANCE,GDI_END);
+  }
 }
 
-static void ModifyEditorSelectbox(int selectbox_id, int new_value)
+static void ModifyEditorSelectboxValue(int selectbox_id, int new_value)
 {
   int gadget_id = selectbox_info[selectbox_id].gadget_id;
   struct GadgetInfo *gi = level_editor_gadget[gadget_id];
@@ -6658,11 +7606,27 @@ static void ModifyEditorSelectbox(int selectbox_id, int new_value)
   ModifyGadget(gi, GDI_SELECTBOX_INDEX, new_index_value, GDI_END);
 }
 
+static void ModifyEditorSelectboxOptions(int selectbox_id,
+                                        struct ValueTextInfo *options)
+{
+  int gadget_id = selectbox_info[selectbox_id].gadget_id;
+  struct GadgetInfo *gi = level_editor_gadget[gadget_id];
+
+  selectbox_info[selectbox_id].options = options;
+
+  /* set index to zero -- list may be shorter now (correct later, if needed) */
+  ModifyGadget(gi, GDI_SELECTBOX_INDEX, 0,
+              GDI_SELECTBOX_OPTIONS, options, GDI_END);
+}
+
 static void ModifyEditorDrawingArea(int drawingarea_id, int xsize, int ysize)
 {
   int gadget_id = drawingarea_info[drawingarea_id].gadget_id;
   struct GadgetInfo *gi = level_editor_gadget[gadget_id];
 
+  drawingarea_info[drawingarea_id].area_xsize = xsize;
+  drawingarea_info[drawingarea_id].area_ysize = ysize;
+
   ModifyGadget(gi, GDI_AREA_SIZE, xsize, ysize, GDI_END);
 }
 
@@ -6678,8 +7642,10 @@ static void ModifyEditorElementList()
     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);
   }
 }
@@ -6752,10 +7718,15 @@ static void DrawLevelInfoWindow()
   ClearWindow();
   UnmapLevelEditorWindowGadgets();
 
+#if 0
+  DrawTextSCentered(ED_SETTINGS1_YPOS, FONT_TITLE_1, "Level Settings");
+  DrawTextSCentered(ED_SETTINGS2_YPOS, FONT_TITLE_1, "Editor Settings");
+#else
   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", FONT_TITLE_1);
+#endif
 
   /* draw counter gadgets */
   for (i = ED_COUNTER_ID_LEVEL_FIRST; i <= ED_COUNTER_ID_LEVEL_LAST; i++)
@@ -6854,14 +7825,61 @@ static void DrawMagicBallContentAreas()
   int y = SY + ED_AREA_MAGIC_BALL_CONTENT_YPOS(0) + ED_BORDER_AREA_YSIZE;
   int i;
 
-  for (i = 0; i < NUM_MAGIC_BALL_CONTENTS; i++)
-    MapDrawingArea(ED_DRAWING_ID_MAGIC_BALL_CONTENT_0 + i);
+  /* display counter to choose number of element content areas */
+  MapCounterButtons(ED_COUNTER_ID_BALL_CONTENT);
+
+  for (i = 0; i < MAX_ELEMENT_CONTENTS; i++)
+  {
+    int id = ED_DRAWING_ID_MAGIC_BALL_CONTENT_0 + i;
+
+    if (i < level.num_ball_contents)
+    {
+      MapDrawingArea(id);
+    }
+    else
+    {
+      int font_height = getFontHeight(FONT_TEXT_1);
+
+      UnmapDrawingArea(id);
+
+      /* delete content areas in case of reducing number of them */
+      DrawBackground(SX + drawingarea_info[id].x - MINI_TILEX / 2,
+                    SY + drawingarea_info[id].y - MINI_TILEY / 2,
+                    4 * MINI_TILEX,
+                    4 * MINI_TILEY + ED_GADGET_TEXT_DISTANCE + font_height);
+    }
+  }
 
   DrawText(x, y + 0 * MINI_TILEY, "generated", FONT_TEXT_1);
   DrawText(x, y + 1 * MINI_TILEY, "when",      FONT_TEXT_1);
   DrawText(x, y + 2 * MINI_TILEY, "active",    FONT_TEXT_1);
 }
 
+static void DrawAndroidElementArea(int element)
+{
+  int num_elements = level.num_android_clone_elements;
+  int id = ED_DRAWING_ID_ANDROID_CONTENT;
+  int sx = SX + drawingarea_info[id].x - MINI_TILEX / 2;
+  int sy = SY + drawingarea_info[id].y - MINI_TILEY / 2;
+  int xsize = MAX_ANDROID_ELEMENTS;
+  int ysize = 1;
+
+  /* display counter to choose number of element areas */
+  MapCounterButtons(ED_COUNTER_ID_ANDROID_CONTENT);
+
+  if (drawingarea_info[id].text_left != NULL)
+    sx += getTextWidthForDrawingArea(drawingarea_info[id].text_left);
+
+  UnmapDrawingArea(id);
+
+  ModifyEditorDrawingArea(id, num_elements, 1);
+
+  /* delete content areas in case of reducing number of them */
+  DrawBackground(sx, sy, (xsize + 1) * MINI_TILEX, (ysize + 1) * MINI_TILEY);
+
+  MapDrawingArea(id);
+}
+
 static void DrawGroupElementArea(int element)
 {
   int num_elements = group_element_info.num_elements;
@@ -6893,7 +7911,7 @@ static void DrawEnvelopeTextArea(int envelope_nr)
   DrawBackground(gi->x, gi->y, gi->width, gi->height);
 
   if (envelope_nr != -1)
-    textarea_info[id].value = level.envelope_text[envelope_nr];
+    textarea_info[id].value = level.envelope[envelope_nr].text;
 
   ModifyGadget(gi, GDI_AREA_SIZE,
               *counterbutton_info[ED_COUNTER_ID_ENVELOPE_XSIZE].value,
@@ -6903,32 +7921,6 @@ static void DrawEnvelopeTextArea(int envelope_nr)
   MapTextAreaGadget(ED_TEXTAREA_ID_ENVELOPE_INFO);
 }
 
-char *getElementDescriptionFilename(int element)
-{
-  char *docs_dir = options.docs_directory;
-  char *elements_subdir = "elements";
-  static char *filename = NULL;
-  char basename[MAX_FILENAME_LEN];
-
-  checked_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 start_line)
 {
   int font_height = getFontHeight(font_nr);
@@ -6946,8 +7938,6 @@ static boolean PrintInfoText(char *text, int font_nr, int start_line)
   return TRUE;
 }
 
-#if 1
-
 static int PrintElementDescriptionFromFile(char *filename, int start_line)
 {
   int font_nr = FONT_TEXT_2;
@@ -6961,100 +7951,9 @@ static int PrintElementDescriptionFromFile(char *filename, int start_line)
   int max_lines_per_screen = (SYSIZE - pad_y) / font_height - 1;
 
   return DrawTextFromFile(sx, sy, filename, font_nr, max_chars_per_line,
-                         max_lines_per_screen);
-}
-
-#else
-
-static int PrintElementDescriptionFromFile(char *filename, int start_line)
-{
-  int font_nr = FONT_TEXT_2;
-  int font_width = getFontWidth(font_nr);
-  int font_height = getFontHeight(font_nr);
-  int pad_x = ED_ELEMENT_SETTINGS_XPOS(0);
-  int pad_y = ED_ELEMENT_SETTINGS_YPOS(0) + ED_BORDER_SIZE;
-  int sx = SX + pad_x;
-  int sy = SY + pad_y;
-  int max_chars_per_line = (SXSIZE - 2 * pad_x) / font_width;
-  int max_lines_per_screen = (SYSIZE - pad_y) / font_height - 1;
-  int current_line = start_line;
-  char line[MAX_LINE_LEN];
-  char buffer[max_chars_per_line + 1];
-  int buffer_len;
-  FILE *file;
-
-  if (current_line >= max_lines_per_screen)
-    return 0;
-
-  if (filename == NULL)
-    return 0;
-
-  if (!(file = fopen(filename, MODE_READ)))
-    return 0;
-
-  buffer[0] = '\0';
-  buffer_len = 0;
-
-  while (!feof(file) && current_line < max_lines_per_screen)
-  {
-    char *line_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");
-
-    line_ptr = line;
-
-    while (*line_ptr && current_line < max_lines_per_screen)
-    {
-      boolean buffer_filled = RenderLineToBuffer(&line_ptr,
-                                                buffer, &buffer_len,
-                                                last_line_was_empty,
-                                                max_chars_per_line);
-      if (buffer_filled)
-      {
-       DrawText(sx, sy + current_line * font_height, buffer, font_nr);
-       current_line++;
-
-       last_line_was_empty = (buffer_len == 0);
-
-       buffer[0] = '\0';
-       buffer_len = 0;
-      }
-    }
-  }
-
-  fclose(file);
-
-  if (buffer_len > 0 && current_line < max_lines_per_screen)
-  {
-    DrawText(sx, sy + current_line * font_height, buffer, font_nr);
-    current_line++;
-  }
-
-  return (current_line - start_line);
+                         max_lines_per_screen);
 }
 
-#endif
-
 static void DrawPropertiesTabulatorGadgets()
 {
   struct GadgetInfo *gd_gi = level_editor_gadget[GADGET_ID_PROPERTIES_INFO];
@@ -7152,7 +8051,9 @@ static void DrawPropertiesInfo()
     /* pre-defined properties */
     { EP_CAN_PASS_MAGIC_WALL,  "- can pass magic walls"                },
     { EP_SWITCHABLE,           "- can be switched"                     },
-    { EP_HAS_CONTENT,          "- can contain other elements"          },
+#if 0
+    { EP_HAS_EDITOR_CONTENT,   "- can contain other elements"          },
+#endif
 
     { -1,                      NULL                                    }
   };
@@ -7171,6 +8072,16 @@ static void DrawPropertiesInfo()
   int screen_line = 0;
   int i, x, y;
 
+#if 1
+  if (setup.editor.show_element_token)
+  {
+    DrawTextF(pad_x, pad_y + screen_line++ * font2_height, FONT_TEXT_3,
+             "[%s]", element_info[properties_element].token_name);
+    screen_line++;
+  }
+
+#else
+
 #if DEBUG
   if (IS_CUSTOM_ELEMENT(properties_element))
   {
@@ -7184,6 +8095,7 @@ static void DrawPropertiesInfo()
              "[Group Element %d]", properties_element - EL_GROUP_START + 1);
     screen_line++;
   }
+#endif
 #endif
 
   /* ----- print number of elements / percentage of this element in level */
@@ -7233,13 +8145,18 @@ static void DrawPropertiesInfo()
 
 #define TEXT_COLLECTING                "Score for collecting"
 #define TEXT_SMASHING          "Score for smashing"
-#define TEXT_SLURPING          "Score for slurping"
+#define TEXT_SLURPING          "Score for slurping robot"
 #define TEXT_CRACKING          "Score for cracking"
 #define TEXT_AMOEBA_SPEED      "Speed of amoeba growth"
 #define TEXT_DURATION          "Duration when activated"
 #define TEXT_BALL_DELAY                "Element generation delay"
 #define TEXT_MOVE_SPEED                "Speed of android moving"
 #define TEXT_CLONE_SPEED       "Speed of android cloning"
+#define TEXT_GAME_OF_LIFE_1    "Min neighbours to survive"
+#define TEXT_GAME_OF_LIFE_2    "Max neighbours to survive"
+#define TEXT_GAME_OF_LIFE_3    "Min neighbours to create"
+#define TEXT_GAME_OF_LIFE_4    "Max neighbours to create"
+#define TEXT_TIME_BONUS                "Extra time to solve level"
 
 static struct
 {
@@ -7280,6 +8197,10 @@ static struct
   { EL_BD_FIREFLY_DOWN, &level.score[SC_SPACESHIP],    TEXT_SMASHING   },
   { EL_SP_SNIKSNAK,    &level.score[SC_SPACESHIP],     TEXT_SMASHING   },
   { EL_YAMYAM,         &level.score[SC_YAMYAM],        TEXT_SMASHING   },
+  { EL_YAMYAM_LEFT,    &level.score[SC_YAMYAM],        TEXT_SMASHING   },
+  { EL_YAMYAM_RIGHT,   &level.score[SC_YAMYAM],        TEXT_SMASHING   },
+  { EL_YAMYAM_UP,      &level.score[SC_YAMYAM],        TEXT_SMASHING   },
+  { EL_YAMYAM_DOWN,    &level.score[SC_YAMYAM],        TEXT_SMASHING   },
   { EL_DARK_YAMYAM,    &level.score[SC_YAMYAM],        TEXT_SMASHING   },
   { EL_ROBOT,          &level.score[SC_ROBOT],         TEXT_SMASHING   },
   { EL_PACMAN,         &level.score[SC_PACMAN],        TEXT_SMASHING   },
@@ -7289,27 +8210,21 @@ static struct
   { EL_PACMAN_DOWN,    &level.score[SC_PACMAN],        TEXT_SMASHING   },
   { EL_NUT,            &level.score[SC_NUT],           TEXT_CRACKING   },
   { EL_DYNAMITE,       &level.score[SC_DYNAMITE],      TEXT_COLLECTING },
+  { EL_EM_DYNAMITE,    &level.score[SC_DYNAMITE],      TEXT_COLLECTING },
   { EL_DYNABOMB_INCREASE_NUMBER,&level.score[SC_DYNAMITE],TEXT_COLLECTING },
   { EL_DYNABOMB_INCREASE_SIZE, &level.score[SC_DYNAMITE],TEXT_COLLECTING },
   { EL_DYNABOMB_INCREASE_POWER,        &level.score[SC_DYNAMITE],TEXT_COLLECTING },
   { EL_SHIELD_NORMAL,  &level.score[SC_SHIELD],        TEXT_COLLECTING },
   { EL_SHIELD_DEADLY,  &level.score[SC_SHIELD],        TEXT_COLLECTING },
-  { EL_EXTRA_TIME,     &level.score[SC_TIME_BONUS],    TEXT_COLLECTING },
+  { EL_EXTRA_TIME,     &level.extra_time_score,        TEXT_COLLECTING },
   { EL_KEY_1,          &level.score[SC_KEY],           TEXT_COLLECTING },
   { EL_KEY_2,          &level.score[SC_KEY],           TEXT_COLLECTING },
   { EL_KEY_3,          &level.score[SC_KEY],           TEXT_COLLECTING },
   { EL_KEY_4,          &level.score[SC_KEY],           TEXT_COLLECTING },
-#if 1
   { EL_EM_KEY_1,       &level.score[SC_KEY],           TEXT_COLLECTING },
   { EL_EM_KEY_2,       &level.score[SC_KEY],           TEXT_COLLECTING },
   { EL_EM_KEY_3,       &level.score[SC_KEY],           TEXT_COLLECTING },
   { EL_EM_KEY_4,       &level.score[SC_KEY],           TEXT_COLLECTING },
-#else
-  { 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 },
-#endif
   { EL_EMC_KEY_5,      &level.score[SC_KEY],           TEXT_COLLECTING },
   { EL_EMC_KEY_6,      &level.score[SC_KEY],           TEXT_COLLECTING },
   { EL_EMC_KEY_7,      &level.score[SC_KEY],           TEXT_COLLECTING },
@@ -7318,16 +8233,36 @@ static struct
   { EL_AMOEBA_DRY,     &level.amoeba_speed,            TEXT_AMOEBA_SPEED },
   { EL_AMOEBA_FULL,    &level.amoeba_speed,            TEXT_AMOEBA_SPEED },
   { EL_BD_AMOEBA,      &level.amoeba_speed,            TEXT_AMOEBA_SPEED },
+  { EL_EMC_DRIPPER,    &level.amoeba_speed,            TEXT_AMOEBA_SPEED },
   { EL_MAGIC_WALL,     &level.time_magic_wall,         TEXT_DURATION   },
+  { EL_BD_MAGIC_WALL,  &level.time_magic_wall,         TEXT_DURATION   },
   { EL_ROBOT_WHEEL,    &level.time_wheel,              TEXT_DURATION   },
 
+#if 1
+  { EL_TIMEGATE_SWITCH,        &level.time_timegate,           TEXT_DURATION   },
+  { EL_LIGHT_SWITCH,   &level.time_light,              TEXT_DURATION   },
+  { EL_LIGHT_SWITCH_ACTIVE, &level.time_light,         TEXT_DURATION   },
+  { EL_SHIELD_NORMAL,  &level.shield_normal_time,      TEXT_DURATION   },
+  { EL_SHIELD_DEADLY,  &level.shield_deadly_time,      TEXT_DURATION   },
+  { EL_EXTRA_TIME,     &level.extra_time,              TEXT_TIME_BONUS },
+  { EL_TIME_ORB_FULL,  &level.time_orb_time,           TEXT_TIME_BONUS },
+  { EL_GAME_OF_LIFE,   &level.game_of_life[0],         TEXT_GAME_OF_LIFE_1 },
+  { EL_GAME_OF_LIFE,   &level.game_of_life[1],         TEXT_GAME_OF_LIFE_2 },
+  { EL_GAME_OF_LIFE,   &level.game_of_life[2],         TEXT_GAME_OF_LIFE_3 },
+  { EL_GAME_OF_LIFE,   &level.game_of_life[3],         TEXT_GAME_OF_LIFE_4 },
+  { EL_BIOMAZE,                &level.biomaze[0],              TEXT_GAME_OF_LIFE_1 },
+  { EL_BIOMAZE,                &level.biomaze[1],              TEXT_GAME_OF_LIFE_2 },
+  { EL_BIOMAZE,                &level.biomaze[2],              TEXT_GAME_OF_LIFE_3 },
+  { EL_BIOMAZE,                &level.biomaze[3],              TEXT_GAME_OF_LIFE_4 },
+#endif
+
 #if 1
   { EL_EMC_ANDROID,    &level.android_move_time,       TEXT_MOVE_SPEED },
   { EL_EMC_ANDROID,    &level.android_clone_time,      TEXT_CLONE_SPEED },
   { EL_EMC_MAGIC_BALL, &level.ball_time,               TEXT_BALL_DELAY },
   { EL_EMC_LENSES,     &level.lenses_score,            TEXT_COLLECTING },
   { EL_EMC_MAGNIFIER,  &level.magnify_score,           TEXT_COLLECTING },
-  { EL_ROBOT,          &level.slurp_score,             TEXT_SLURPING   },
+  { EL_SPRING,         &level.slurp_score,             TEXT_SLURPING   },
   { EL_EMC_LENSES,     &level.lenses_time,             TEXT_DURATION   },
   { EL_EMC_MAGNIFIER,  &level.magnify_time,            TEXT_DURATION   },
 #endif
@@ -7344,7 +8279,7 @@ static boolean checkPropertiesConfig(int element)
       IS_GROUP_ELEMENT(element) ||
       IS_ENVELOPE(element) ||
       ELEM_IS_PLAYER(element) ||
-      HAS_CONTENT(element) ||
+      HAS_EDITOR_CONTENT(element) ||
       CAN_GROW(element) ||
       COULD_MOVE_INTO_ACID(element) ||
       MAYBE_DONT_COLLIDE_WITH(element))
@@ -7359,7 +8294,7 @@ static boolean checkPropertiesConfig(int element)
 
 static void DrawPropertiesConfig()
 {
-  int max_num_element_counters = 2;
+  int max_num_element_counters = 4;
   int num_element_counters = 0;
   int i;
 
@@ -7378,18 +8313,29 @@ static void DrawPropertiesConfig()
       int counter_id = ED_COUNTER_ID_ELEMENT_VALUE1 + num_element_counters;
 
       counterbutton_info[counter_id].y =
-       ED_ELEMENT_SETTINGS_YPOS((HAS_CONTENT(properties_element) ? 1 : 0) +
-                        (CAN_GROW(properties_element) ? 1 : 0) +
-                        (COULD_MOVE_INTO_ACID(properties_element) ? 1 : 0) +
-                        (MAYBE_DONT_COLLIDE_WITH(properties_element) ? 1 : 0)+
-                        num_element_counters);
+       ED_ELEMENT_SETTINGS_YPOS(
+               (HAS_EDITOR_CONTENT(properties_element)      ? 1 : 0) +
+               (CAN_GROW(properties_element)                ? 1 : 0) +
+               (COULD_MOVE_INTO_ACID(properties_element)    ? 1 : 0) +
+               (MAYBE_DONT_COLLIDE_WITH(properties_element) ? 1 : 0) +
+               (properties_element == EL_EMC_MAGIC_BALL     ? 2 : 0) +
+               num_element_counters);
 
       counterbutton_info[counter_id].value = elements_with_counter[i].value;
       counterbutton_info[counter_id].text_right= elements_with_counter[i].text;
 
-      /* !!! CHANGE THIS FOR CERTAIN ELEMENTS !!! */
-      counterbutton_info[counter_id].min_value = MIN_SCORE;
-      counterbutton_info[counter_id].max_value = MAX_SCORE;
+      if (properties_element == EL_GAME_OF_LIFE ||
+         properties_element == EL_BIOMAZE)
+      {
+       counterbutton_info[counter_id].min_value = 0;   /* min neighbours */
+       counterbutton_info[counter_id].max_value = 8;   /* max neighbours */
+      }
+      else
+      {
+       /* !!! CHANGE THIS FOR CERTAIN ELEMENTS !!! */
+       counterbutton_info[counter_id].min_value = MIN_SCORE;
+       counterbutton_info[counter_id].max_value = MAX_SCORE;
+      }
 
       MapCounterButtons(counter_id);
 
@@ -7399,29 +8345,73 @@ static void DrawPropertiesConfig()
     }
   }
 
-  if (HAS_CONTENT(properties_element))
+  if (HAS_EDITOR_CONTENT(properties_element))
   {
     /* draw stickybutton gadget */
     MapCheckbuttonGadget(ED_CHECKBUTTON_ID_STICK_ELEMENT);
 
     if (IS_AMOEBOID(properties_element))
       MapDrawingArea(ED_DRAWING_ID_AMOEBA_CONTENT);
-    else if (properties_element == EL_YAMYAM)
+    else if (properties_element == EL_YAMYAM ||
+            properties_element == EL_YAMYAM_LEFT ||
+            properties_element == EL_YAMYAM_RIGHT ||
+            properties_element == EL_YAMYAM_UP ||
+            properties_element == EL_YAMYAM_DOWN)
       DrawYamYamContentAreas();
-  }
+    else if (properties_element == EL_EMC_MAGIC_BALL)
+    {
+      DrawMagicBallContentAreas();
 
-  if (properties_element == EL_EMC_MAGIC_BALL)
-    DrawMagicBallContentAreas();
+      MapCheckbuttonGadget(ED_CHECKBUTTON_ID_RANDOM_BALL_CONTENT);
+      MapCheckbuttonGadget(ED_CHECKBUTTON_ID_INITIAL_BALL_STATE);
+    }
+    else if (properties_element == EL_EMC_ANDROID)
+      DrawAndroidElementArea(properties_element);
+  }
 
   if (ELEM_IS_PLAYER(properties_element))
   {
+    int player_nr = GET_PLAYER_NR(properties_element);
+
+    /* these properties can be set for every player individually */
+
+    drawingarea_info[ED_DRAWING_ID_START_ELEMENT].value =
+      &level.start_element[player_nr];
+    drawingarea_info[ED_DRAWING_ID_ARTWORK_ELEMENT].value =
+      &level.artwork_element[player_nr];
+    drawingarea_info[ED_DRAWING_ID_EXPLOSION_ELEMENT].value =
+      &level.explosion_element[player_nr];
+
+    checkbutton_info[ED_CHECKBUTTON_ID_USE_START_ELEMENT].value =
+      &level.use_start_element[player_nr];
+    checkbutton_info[ED_CHECKBUTTON_ID_USE_ARTWORK_ELEMENT].value =
+      &level.use_artwork_element[player_nr];
+    checkbutton_info[ED_CHECKBUTTON_ID_USE_EXPLOSION_ELEMENT].value =
+      &level.use_explosion_element[player_nr];
+    checkbutton_info[ED_CHECKBUTTON_ID_INITIAL_GRAVITY].value =
+      &level.initial_player_gravity[player_nr];
+
+    selectbox_info[ED_SELECTBOX_ID_PLAYER_SPEED].value =
+      &level.initial_player_stepsize[player_nr];
+
     MapCheckbuttonGadget(ED_CHECKBUTTON_ID_CAN_FALL_INTO_ACID);
     MapCheckbuttonGadget(properties_element == EL_SP_MURPHY ?
                         ED_CHECKBUTTON_ID_SP_BLOCK_LAST_FIELD :
                         ED_CHECKBUTTON_ID_BLOCK_LAST_FIELD);
+    MapCheckbuttonGadget(ED_CHECKBUTTON_ID_BLOCK_SNAP_FIELD);
+    MapCheckbuttonGadget(ED_CHECKBUTTON_ID_CONTINUOUS_SNAPPING);
     MapCheckbuttonGadget(ED_CHECKBUTTON_ID_INSTANT_RELOCATION);
+    MapCheckbuttonGadget(ED_CHECKBUTTON_ID_USE_START_ELEMENT);
+    MapCheckbuttonGadget(ED_CHECKBUTTON_ID_USE_ARTWORK_ELEMENT);
+    MapCheckbuttonGadget(ED_CHECKBUTTON_ID_USE_EXPLOSION_ELEMENT);
+    MapCheckbuttonGadget(ED_CHECKBUTTON_ID_INITIAL_GRAVITY);
     MapCheckbuttonGadget(ED_CHECKBUTTON_ID_CAN_PASS_TO_WALKABLE);
-    MapCheckbuttonGadget(ED_CHECKBUTTON_ID_DOUBLE_SPEED);
+
+    MapDrawingArea(ED_DRAWING_ID_START_ELEMENT);
+    MapDrawingArea(ED_DRAWING_ID_ARTWORK_ELEMENT);
+    MapDrawingArea(ED_DRAWING_ID_EXPLOSION_ELEMENT);
+
+    MapSelectboxGadget(ED_SELECTBOX_ID_PLAYER_SPEED);
   }
 
   if (IS_GEM(properties_element))
@@ -7437,7 +8427,7 @@ static void DrawPropertiesConfig()
       ED_ELEMENT_SETTINGS_XPOS(IS_CUSTOM_ELEMENT(properties_element) ? 1 : 0);
     checkbutton_info[ED_CHECKBUTTON_ID_CAN_MOVE_INTO_ACID].y =
       ED_ELEMENT_SETTINGS_YPOS(IS_CUSTOM_ELEMENT(properties_element) ? 6 :
-                      HAS_CONTENT(properties_element) ? 1 : 0);
+                      HAS_EDITOR_CONTENT(properties_element) ? 1 : 0);
 
     MapCheckbuttonGadget(ED_CHECKBUTTON_ID_CAN_MOVE_INTO_ACID);
   }
@@ -7448,10 +8438,18 @@ static void DrawPropertiesConfig()
   if (properties_element == EL_SPRING)
     MapCheckbuttonGadget(ED_CHECKBUTTON_ID_USE_SPRING_BUG);
 
+  if (properties_element == EL_TIME_ORB_FULL)
+    MapCheckbuttonGadget(ED_CHECKBUTTON_ID_USE_TIME_ORB_BUG);
+
+#if 0
+  if (properties_element == EL_BALLOON)
+    MapSelectboxGadget(ED_SELECTBOX_ID_WIND_DIRECTION);
+#endif
+
   if (CAN_GROW(properties_element))
   {
     checkbutton_info[ED_CHECKBUTTON_ID_GROW_INTO_DIGGABLE].y =
-      ED_ELEMENT_SETTINGS_YPOS(HAS_CONTENT(properties_element) ? 1 : 0);
+      ED_ELEMENT_SETTINGS_YPOS(HAS_EDITOR_CONTENT(properties_element) ? 1 : 0);
 
     MapCheckbuttonGadget(ED_CHECKBUTTON_ID_GROW_INTO_DIGGABLE);
   }
@@ -7462,8 +8460,8 @@ static void DrawPropertiesConfig()
     int counter2_id = ED_COUNTER_ID_ENVELOPE_YSIZE;
     int envelope_nr = properties_element - EL_ENVELOPE_1;
 
-    counterbutton_info[counter1_id].value = &level.envelope_xsize[envelope_nr];
-    counterbutton_info[counter2_id].value = &level.envelope_ysize[envelope_nr];
+    counterbutton_info[counter1_id].value = &level.envelope[envelope_nr].xsize;
+    counterbutton_info[counter2_id].value = &level.envelope[envelope_nr].ysize;
 
     /* display counter to choose size of envelope text area */
     MapCounterButtons(ED_COUNTER_ID_ENVELOPE_XSIZE);
@@ -7572,6 +8570,9 @@ static void DrawPropertiesChange()
 {
   int i;
 
+  /* needed to initially set selectbox options for special action options */
+  setSelectboxSpecialActionOptions();
+
   /* draw stickybutton gadget */
   MapCheckbuttonGadget(ED_CHECKBUTTON_ID_STICK_ELEMENT);
 
@@ -7604,7 +8605,18 @@ static void DrawPropertiesChange()
   DrawPropertiesChangeDrawingAreas();
 }
 
-static void DrawElementName(int x, int y, int element)
+static void DrawEditorElementAnimation(int x, int y)
+{
+  int graphic = el2img(properties_element);
+  int frame = (ANIM_MODE(graphic) == ANIM_CE_VALUE ?
+              custom_element.ce_value_fixed_initial :
+              ANIM_MODE(graphic) == ANIM_CE_SCORE ?
+              custom_element.collect_score_initial : FrameCounter);
+
+  DrawGraphicAnimationExt(drawto, x, y, graphic, frame, NO_MASKING);
+}
+
+static void DrawEditorElementName(int x, int y, int element)
 {
   char *element_name = getElementInfoText(element);
   int font_nr = FONT_TEXT_1;
@@ -7678,21 +8690,37 @@ static void DrawPropertiesWindow()
   SetMainBackgroundImage(IMG_BACKGROUND_EDITOR);
   ClearWindow();
 
+#if 0
+  DrawTextSCentered(ED_SETTINGS1_YPOS, FONT_TITLE_1, "Element Settings");
+#else
   DrawText(SX + ED_SETTINGS2_XPOS, SY + ED_SETTINGS1_YPOS,
           "Element Settings", FONT_TITLE_1);
+#endif
+
+#if 1
+  FrameCounter = 0;    /* restart animation frame counter */
+#endif
 
   DrawElementBorder(SX + xstart * MINI_TILEX,
                    SY + ystart * MINI_TILEY + MINI_TILEY / 2,
                    TILEX, TILEY, FALSE);
+#if 1
+  DrawEditorElementAnimation(SX + xstart * MINI_TILEX,
+                            SY + ystart * MINI_TILEY + MINI_TILEY / 2);
+#else
   DrawGraphicAnimationExt(drawto,
                          SX + xstart * MINI_TILEX,
                          SY + ystart * MINI_TILEY + MINI_TILEY / 2,
                          el2img(properties_element), -1, NO_MASKING);
+#endif
 
+#if 0
   FrameCounter = 0;    /* restart animation frame counter */
+#endif
 
-  DrawElementName((xstart + 3) * MINI_TILEX + 1, (ystart + 1) * MINI_TILEY + 1,
-                 properties_element);
+  DrawEditorElementName((xstart + 3) * MINI_TILEX + 1,
+                       (ystart + 1) * MINI_TILEY + 1,
+                       properties_element);
 
   DrawPropertiesTabulatorGadgets();
 
@@ -7868,6 +8896,7 @@ static void DrawArc(int from_x, int from_y, int to_x, int to_y,
 }
 
 #define DRAW_CIRCLES_BUTTON_AVAILABLE  0
+
 #if DRAW_CIRCLES_BUTTON_AVAILABLE
 static void DrawCircle(int from_x, int from_y, int to_x, int to_y,
                       int element, boolean change_level)
@@ -7955,35 +8984,6 @@ static void CopyBrushExt(int from_x, int from_y, int to_x, int to_y,
        int element = brush_buffer[x][y];
        int element_mapped = element;
 
-#if 0
-       char *element_string = "?";
-       int k;
-
-       for (k = 0; forum_sketch_element_mapping[k].element != -1; k++)
-       {
-         if (forum_sketch_element_mapping[k].element == element)
-         {
-           element_mapped = forum_sketch_element_mapping[k].element_mapped;
-           break;
-         }
-       }
-
-       if (IS_CUSTOM_ELEMENT(element))
-         element_mapped = EL_CUSTOM_1;
-
-       for (k = 0; forum_sketch_element_strings[k].element != -1; k++)
-       {
-         if (forum_sketch_element_strings[k].element == element_mapped)
-         {
-           element_string = forum_sketch_element_strings[k].element_string;
-           break;
-         }
-       }
-
-       printf("`%s", element_string);
-
-#else
-
        if (IS_CUSTOM_ELEMENT(element))
          element_mapped = EL_CUSTOM_START;
        else if (IS_GROUP_ELEMENT(element))
@@ -7992,7 +8992,6 @@ static void CopyBrushExt(int from_x, int from_y, int to_x, int to_y,
          element_mapped = EL_UNKNOWN;
 
        printf("%c%03d", (mode == CB_DUMP_BRUSH ? '`' : '¸'), element_mapped);
-#endif
       }
 
       printf("\n");
@@ -8283,11 +9282,20 @@ static void SetTextCursor(int unused_sx, int unused_sy, int sx, int sy,
     DrawAreaBorder(sx, sy, sx, sy);
 }
 
+static void CheckLevelBorderElement(boolean redraw_playfield)
+{
+  int last_border_element = BorderElement;
+
+  SetBorderElement();
+
+  if (redraw_playfield && BorderElement != last_border_element)
+    DrawMiniLevel(ed_fieldx, ed_fieldy, level_xpos, level_ypos);
+}
+
 static void CopyLevelToUndoBuffer(int mode)
 {
   static boolean accumulated_undo = FALSE;
   boolean new_undo_buffer_position = TRUE;
-  int last_border_element;
   int x, y;
 
   switch (mode)
@@ -8320,10 +9328,7 @@ static void CopyLevelToUndoBuffer(int mode)
       UndoBuffer[undo_buffer_position][x][y] = Feld[x][y];
 
   /* check if drawing operation forces change of border style */
-  last_border_element = BorderElement;
-  SetBorderElement();
-  if (BorderElement != last_border_element)
-    DrawMiniLevel(ed_fieldx, ed_fieldy, level_xpos, level_ypos);
+  CheckLevelBorderElement(TRUE);
 
   level.changed = TRUE;
 }
@@ -8454,6 +9459,11 @@ static void HandleDrawingAreas(struct GadgetInfo *gi)
   if (!started_inside_drawing_area)
     return;
 
+#if 1
+  if (!IS_VALID_BUTTON(button))
+    return;
+#endif
+
   if (!button && !button_release_event)
     return;
 
@@ -8518,6 +9528,9 @@ static void HandleDrawingAreas(struct GadgetInfo *gi)
       }
       else
       {
+       int type_id = gi->custom_type_id;
+       int pos = sx * drawingarea_info[type_id].area_ysize + sy;
+
        if (item_xsize == MINI_TILEX && item_ysize == MINI_TILEY)
          DrawMiniGraphicExt(drawto,
                             gi->x + sx * MINI_TILEX,
@@ -8529,71 +9542,19 @@ static void HandleDrawingAreas(struct GadgetInfo *gi)
                         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)
-       {
+       if (id == GADGET_ID_CUSTOM_GRAPHIC)
          new_element = GFX_ELEMENT(new_element);
-         custom_element.gfx_element = new_element;
-
-         CopyElementPropertiesToGame(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_MOVE_ENTER)
-       {
-         custom_element.move_enter_element = new_element;
-
-         CopyCustomElementPropertiesToGame(properties_element);
-       }
-       else if (id == GADGET_ID_CUSTOM_MOVE_LEAVE)
-       {
-         custom_element.move_leave_element = new_element;
-
-         CopyCustomElementPropertiesToGame(properties_element);
-       }
-       else if (id == GADGET_ID_CUSTOM_CHANGE_TARGET)
-       {
-         custom_element_change.target_element = new_element;
+       drawingarea_info[type_id].value[pos] = new_element;
 
-         CopyCustomElementPropertiesToGame(properties_element);
-       }
-       else if (id == GADGET_ID_CUSTOM_CHANGE_CONTENT)
-       {
-         custom_element_change.target_content[sx][sy] = new_element;
-
-         CopyCustomElementPropertiesToGame(properties_element);
-       }
-       else if (id == GADGET_ID_CUSTOM_CHANGE_TRIGGER)
-       {
-         custom_element_change.trigger_element = new_element;
+       CopyElementPropertiesToGame(properties_element);
 
-         CopyCustomElementPropertiesToGame(properties_element);
-       }
-       else if (id == GADGET_ID_GROUP_CONTENT)
+       if (id == GADGET_ID_CUSTOM_GRAPHIC)
        {
-         group_element_info.element[sx] = new_element;
+         UpdateCustomElementGraphicGadgets();
 
-         CopyGroupElementPropertiesToGame(properties_element);
+         FrameCounter = 0;     /* restart animation frame counter */
        }
-       else if (id == GADGET_ID_RANDOM_BACKGROUND)
-         random_placement_background_element = new_element;
-       else if (id >= GADGET_ID_YAMYAM_CONTENT_0 &&
-                id <= GADGET_ID_YAMYAM_CONTENT_7)
-         level.yamyam_content[id - GADGET_ID_YAMYAM_CONTENT_0][sx][sy] =
-           new_element;
-       else if (id >= GADGET_ID_MAGIC_BALL_CONTENT_0 &&
-                id <= GADGET_ID_MAGIC_BALL_CONTENT_7)
-         level.ball_content[id - GADGET_ID_MAGIC_BALL_CONTENT_0][sx][sy] =
-           new_element;
       }
       break;
 
@@ -8692,39 +9653,12 @@ static void HandleDrawingAreas(struct GadgetInfo *gi)
                      MB_LEFTBUTTON);
       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_MOVE_ENTER)
-       PickDrawingElement(button, custom_element.move_enter_element);
-      else if (id == GADGET_ID_CUSTOM_MOVE_LEAVE)
-       PickDrawingElement(button, custom_element.move_leave_element);
-      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.target_content[sx][sy]);
-      else if (id == GADGET_ID_CUSTOM_CHANGE_TRIGGER)
-       PickDrawingElement(button, custom_element_change.trigger_element);
-      else if (id == GADGET_ID_GROUP_CONTENT)
-       PickDrawingElement(button, group_element_info.element[sx]);
-      else if (id == GADGET_ID_RANDOM_BACKGROUND)
-       PickDrawingElement(button, random_placement_background_element);
-      else if (id >= GADGET_ID_YAMYAM_CONTENT_0 &&
-              id <= GADGET_ID_YAMYAM_CONTENT_7)
-      {
-       int i = id - GADGET_ID_YAMYAM_CONTENT_0;
-
-       PickDrawingElement(button, level.yamyam_content[i][sx][sy]);
-      }
-      else if (id >= GADGET_ID_MAGIC_BALL_CONTENT_0 &&
-              id <= GADGET_ID_MAGIC_BALL_CONTENT_7)
+      else
       {
-       int i = id - GADGET_ID_MAGIC_BALL_CONTENT_0;
+       int type_id = gi->custom_type_id;
+       int pos = sx * drawingarea_info[type_id].area_ysize + sy;
 
-       PickDrawingElement(button, level.ball_content[i][sx][sy]);
+       PickDrawingElement(button, drawingarea_info[type_id].value[pos]);
       }
 
       break;
@@ -8756,7 +9690,7 @@ static void HandleCounterButtons(struct GadgetInfo *gi)
                                  REQ_ASK))
     {
       if (gadget_id == counterbutton_info[counter_id].gadget_id_text)
-       ModifyEditorCounter(counter_id, *counter_value);
+       ModifyEditorCounterValue(counter_id, *counter_value);
 
       return;
     }
@@ -8765,7 +9699,7 @@ static void HandleCounterButtons(struct GadgetInfo *gi)
   if (gadget_id == counterbutton_info[counter_id].gadget_id_text)
     *counter_value = gi->textinput.number_value;
   else
-    ModifyEditorCounter(counter_id, *counter_value + step);
+    ModifyEditorCounterValue(counter_id, *counter_value + step);
 
   if (counter_id == ED_COUNTER_ID_SELECT_LEVEL)
   {
@@ -8783,6 +9717,14 @@ static void HandleCounterButtons(struct GadgetInfo *gi)
       DrawYamYamContentAreas();
       break;
 
+    case ED_COUNTER_ID_BALL_CONTENT:
+      DrawMagicBallContentAreas();
+      break;
+
+    case ED_COUNTER_ID_ANDROID_CONTENT:
+      DrawAndroidElementArea(properties_element);
+      break;
+
     case ED_COUNTER_ID_GROUP_CONTENT:
       DrawGroupElementArea(properties_element);
       CopyGroupElementPropertiesToGame(properties_element);
@@ -8840,9 +9782,10 @@ static void HandleTextAreaGadgets(struct GadgetInfo *gi)
 static void HandleSelectboxGadgets(struct GadgetInfo *gi)
 {
   int type_id = gi->custom_type_id;
+  int value_old = *selectbox_info[type_id].value;
+  int value_new = selectbox_info[type_id].options[gi->selectbox.index].value;
 
-  *selectbox_info[type_id].value =
-    selectbox_info[type_id].options[gi->selectbox.index].value;
+  *selectbox_info[type_id].value = value_new;
 
   if (type_id == ED_SELECTBOX_ID_SELECT_CHANGE_PAGE)
   {
@@ -8856,6 +9799,22 @@ static void HandleSelectboxGadgets(struct GadgetInfo *gi)
            type_id <= ED_SELECTBOX_ID_CHANGE_LAST) ||
           (type_id == ED_SELECTBOX_ID_GROUP_CHOICE_MODE))
   {
+    if (type_id == ED_SELECTBOX_ID_ACTION_TYPE)
+    {
+      /* when changing action type, also check action mode and action arg */
+      if (value_old != value_new)
+      {
+#if 1
+       setSelectboxSpecialActionVariablesIfNeeded();
+#else
+       custom_element_change.action_mode = -1;
+       custom_element_change.action_arg = -1;
+#endif
+      }
+
+      DrawPropertiesChange();
+    }
+
     CopyElementPropertiesToGame(properties_element);
 
     level.changed = TRUE;
@@ -9024,6 +9983,14 @@ static void HandleControlButtons(struct GadgetInfo *gi)
   int new_element = BUTTON_ELEMENT(button);
   int x, y;
 
+#if 0
+  /* MAKES PROBLEMS WITH ELEMENT LIST SCROLLBAR AND IS PROBABLY NOT NEEDED */
+  /* !!! CHECK WHAT HAPPENS WHEN MOUSE WHEEL IS USED OVER ELEMENT LIST !!! */
+
+  if (!IS_VALID_BUTTON(button))
+    return;
+#endif
+
   if (edit_mode == ED_MODE_DRAWING && drawing_function == GADGET_ID_TEXT)
     DrawLevelText(0, 0, 0, TEXT_END);
 
@@ -9247,7 +10214,12 @@ static void HandleControlButtons(struct GadgetInfo *gi)
       for (x = 0; x < lev_fieldx; x++)
        for (y = 0; y < lev_fieldy; y++)
          Feld[x][y] = UndoBuffer[undo_buffer_position][x][y];
-      DrawMiniLevel(ed_fieldx, ed_fieldy, level_xpos,level_ypos);
+
+      /* check if undo operation forces change of border style */
+      CheckLevelBorderElement(FALSE);
+
+      DrawMiniLevel(ed_fieldx, ed_fieldy, level_xpos, level_ypos);
+
       break;
 
     case GADGET_ID_INFO:
@@ -9331,13 +10303,9 @@ static void HandleControlButtons(struct GadgetInfo *gi)
 
        DrawCompleteVideoDisplay();
 
-       if (setup.autorecord)
-         TapeStartRecording();
-
        level_editor_test_game = TRUE;
-       game_status = GAME_MODE_PLAYING;
 
-       InitGame();
+       StartGameActions(FALSE, setup.autorecord, NEW_RANDOMIZE);
       }
       break;
 
@@ -9352,6 +10320,37 @@ static void HandleControlButtons(struct GadgetInfo *gi)
        int element_position = id - GADGET_ID_ELEMENTLIST_FIRST;
        int new_element = editor_elements[element_position + element_shift];
 
+       if (IS_EDITOR_CASCADE(new_element))
+       {
+         int i;
+
+         for (i = 0; editor_elements_info[i].setup_value != NULL; i++)
+         {
+           int *cascade_element= &(*editor_elements_info[i].headline_list)[0];
+           boolean *cascade_value=editor_elements_info[i].setup_cascade_value;
+
+           if (*cascade_element == new_element)
+           {
+             *cascade_element = EL_CASCADE_TOGGLE(*cascade_element);
+             *cascade_value = IS_EDITOR_CASCADE_ACTIVE(*cascade_element);
+
+             /* update element selection list */
+             ReinitializeElementList();
+             ModifyEditorElementList();
+
+             /* update cascading gadget info text */
+             PrintEditorGadgetInfoText(level_editor_gadget[id]);
+
+             /* save current editor cascading state */
+             SaveSetup_EditorCascade();
+
+             break;
+           }
+         }
+
+         break;
+       }
+
        if (last_custom_copy_mode != -1)
        {
          if (CopyCustomElement(properties_element, new_element,
@@ -9414,7 +10413,9 @@ void HandleLevelEditorKeyInput(Key key)
   }
   else if (button_status == MB_RELEASED)
   {
-    int i, id = GADGET_ID_NONE;
+    int id = GADGET_ID_NONE;
+    int new_element_shift = element_shift;
+    int i;
 
     switch (key)
     {
@@ -9439,10 +10440,82 @@ void HandleLevelEditorKeyInput(Key key)
        button = MB_RIGHTBUTTON;
        break;
 
+      case KSYM_Home:
+      case KSYM_End:
+       element_shift = (key == KSYM_Home ? 0 :
+                        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);
+
+       ModifyEditorElementList();
+
+       break;
+
+      case KSYM_Insert:
+      case KSYM_Delete:
+#if 1
+       /* IS_EDITOR_CASCADE */
+       for (i = 0; i < num_editor_elements; i++)
+       {
+         if ((key == KSYM_Insert && i == element_shift) ||
+             (key == KSYM_Delete && new_element_shift > element_shift))
+           break;
+
+         /* jump to next cascade block (or to start of element list) */
+         if (i == 0 || IS_EDITOR_CASCADE(editor_elements[i]))
+           new_element_shift = i;
+       }
+
+       if (i < num_editor_elements)
+         element_shift = new_element_shift;
+
+       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);
+
+       ModifyEditorElementList();
+
+#else
+
+       for (i = 0; i < num_editor_elements; i++)
+       {
+         int e = editor_elements[i];
+
+         if ((key == KSYM_Insert &&
+              (e == EL_INTERNAL_CASCADE_CE ||
+               e == EL_INTERNAL_CASCADE_CE_ACTIVE)) ||
+             (key == KSYM_Delete &&
+              (e == EL_INTERNAL_CASCADE_GE ||
+               e == EL_INTERNAL_CASCADE_GE_ACTIVE)))
+           break;
+       }
+
+       if (i < num_editor_elements)
+       {
+         element_shift = i;
+
+         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);
+
+         ModifyEditorElementList();
+       }
+#endif
+
+       break;
+
       case KSYM_Escape:
         if (edit_mode == ED_MODE_DRAWING)
        {
-         RequestExitLevelEditor(setup.ask_on_escape);
+         RequestExitLevelEditor(setup.ask_on_escape_editor);
        }
         else if (edit_mode == ED_MODE_INFO)
        {
@@ -9489,10 +10562,15 @@ void HandleLevelEditorIdle()
   if (!DelayReached(&action_delay, action_delay_value))
     return;
 
+#if 1
+  DrawEditorElementAnimation(SX + xpos * TILEX,
+                            SY + ypos * TILEY + MINI_TILEY / 2);
+#else
   DrawGraphicAnimationExt(drawto,
                          SX + xpos * TILEX,
                          SY + ypos * TILEY + MINI_TILEY / 2,
                          el2img(properties_element), -1, NO_MASKING);
+#endif
 
   MarkTileDirty(xpos, ypos);
   MarkTileDirty(xpos, ypos + 1);
@@ -9505,25 +10583,66 @@ void ClearEditorGadgetInfoText()
   DrawBackground(INFOTEXT_XPOS, INFOTEXT_YPOS, INFOTEXT_XSIZE, INFOTEXT_YSIZE);
 }
 
+void PrintEditorGadgetInfoText(struct GadgetInfo *gi)
+{
+  char infotext[MAX_OUTPUT_LINESIZE + 1];
+  char shortcut[MAX_OUTPUT_LINESIZE + 1];
+  int max_infotext_len = getMaxInfoTextLength();
+
+  if (gi == NULL || gi->info_text == NULL)
+    return;
+
+  strncpy(infotext, gi->info_text, max_infotext_len);
+  infotext[max_infotext_len] = '\0';
+
+  if (gi->custom_id < ED_NUM_CTRL_BUTTONS)
+  {
+    int key = control_info[gi->custom_id].shortcut;
+
+    if (key)
+    {
+      if (gi->custom_id == GADGET_ID_SINGLE_ITEMS)     /* special case 1 */
+       sprintf(shortcut, " ('.' or '%c')", key);
+      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)
+       strcat(infotext, shortcut);
+    }
+  }
+
+  DrawText(INFOTEXT_XPOS, INFOTEXT_YPOS, infotext, FONT_TEXT_2);
+}
+
 void HandleEditorGadgetInfoText(void *ptr)
 {
   struct GadgetInfo *gi = (struct GadgetInfo *)ptr;
+#if 0
   char infotext[MAX_OUTPUT_LINESIZE + 1];
   char shortcut[MAX_OUTPUT_LINESIZE + 1];
   int max_infotext_len = getMaxInfoTextLength();
+#endif
 
   if (game_status != GAME_MODE_EDITOR)
     return;
 
   ClearEditorGadgetInfoText();
 
-  if (gi->event.type == GD_EVENT_INFO_LEAVING)
+  if (gi == NULL || gi->event.type == GD_EVENT_INFO_LEAVING)
     return;
 
   /* misuse this function to delete brush cursor, if needed */
   if (edit_mode == ED_MODE_DRAWING && draw_with_brush)
     DeleteBrushFromCursor();
 
+#if 1
+  PrintEditorGadgetInfoText(gi);
+#else
   if (gi == NULL || gi->info_text == NULL)
     return;
 
@@ -9552,12 +10671,14 @@ void HandleEditorGadgetInfoText(void *ptr)
   }
 
   DrawText(INFOTEXT_XPOS, INFOTEXT_YPOS, infotext, FONT_TEXT_2);
+#endif
 }
 
 static void HandleDrawingAreaInfo(struct GadgetInfo *gi)
 {
   static int start_lx, start_ly;
   int id = gi->custom_id;
+  int type_id = gi->custom_type_id;
   int sx = gi->event.x;
   int sy = gi->event.y;
   int lx = sx + level_xpos;
@@ -9653,35 +10774,16 @@ static void HandleDrawingAreaInfo(struct GadgetInfo *gi)
            break;
        }
 
-#if 1
        if (actual_drawing_function == GADGET_ID_PICK_ELEMENT)
          sprintf(infotext, "%s: %d, %d", text, lx, ly);
        else
          sprintf(infotext, "%s: %d, %d", text,
                  ABS(lx - start_lx) + 1, ABS(ly - start_ly) + 1);
-#else
-       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, FONT_TEXT_2,
-                   "%s: %d, %d", infotext,
-                   ABS(lx - start_lx) + 1, ABS(ly - start_ly) + 1);
-#endif
       }
-#if 1
       else if (actual_drawing_function == GADGET_ID_PICK_ELEMENT)
        strncpy(infotext, getElementInfoText(Feld[lx][ly]), max_infotext_len);
       else
        sprintf(infotext, "Level position: %d, %d", lx, ly);
-#else
-      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, FONT_TEXT_2,
-                 "Level position: %d, %d", lx, ly);
-#endif
     }
 
     /* misuse this function to draw brush cursor, if needed */
@@ -9695,67 +10797,29 @@ static void HandleDrawingAreaInfo(struct GadgetInfo *gi)
   }
   else if (actual_drawing_function == GADGET_ID_PICK_ELEMENT)
   {
-    int element = EL_EMPTY;
-
-    if (id == GADGET_ID_AMOEBA_CONTENT)
-      element = level.amoeba_content;
-    else if (id == GADGET_ID_CUSTOM_GRAPHIC)
-      element = custom_element.gfx_element;
-    else if (id == GADGET_ID_CUSTOM_CONTENT)
-      element = custom_element.content[sx][sy];
-    else if (id == GADGET_ID_CUSTOM_MOVE_ENTER)
-      element = custom_element.move_enter_element;
-    else if (id == GADGET_ID_CUSTOM_MOVE_LEAVE)
-      element = custom_element.move_leave_element;
-    else if (id == GADGET_ID_CUSTOM_CHANGE_TARGET)
-      element = custom_element_change.target_element;
-    else if (id == GADGET_ID_CUSTOM_CHANGE_CONTENT)
-      element = custom_element_change.target_content[sx][sy];
-    else if (id == GADGET_ID_CUSTOM_CHANGE_TRIGGER)
-      element = custom_element_change.trigger_element;
-    else if (id == GADGET_ID_GROUP_CONTENT)
-      element = group_element_info.element[sx];
-    else if (id == GADGET_ID_RANDOM_BACKGROUND)
-      element = random_placement_background_element;
-    else if (id >= GADGET_ID_YAMYAM_CONTENT_0 &&
-            id <= GADGET_ID_YAMYAM_CONTENT_7)
-      element = level.yamyam_content[id - GADGET_ID_YAMYAM_CONTENT_0][sx][sy];
-    else if (id >= GADGET_ID_MAGIC_BALL_CONTENT_0 &&
-            id <= GADGET_ID_MAGIC_BALL_CONTENT_7)
-      element = level.ball_content[id -GADGET_ID_MAGIC_BALL_CONTENT_0][sx][sy];
+    int pos = sx * drawingarea_info[type_id].area_ysize + sy;
+    int element = drawingarea_info[type_id].value[pos];
 
     strncpy(infotext, getElementInfoText(element), max_infotext_len);
   }
   else
   {
-    if (id == GADGET_ID_AMOEBA_CONTENT)
-      strcpy(infotext, "Amoeba content");
-    else if (id == GADGET_ID_CUSTOM_GRAPHIC)
-      strcpy(infotext, "Custom graphic element");
-    else if (id == GADGET_ID_CUSTOM_CONTENT)
-      sprintf(infotext, "Custom element content position: %d, %d", sx, sy);
-    else if (id == GADGET_ID_CUSTOM_MOVE_ENTER)
-      strcpy(infotext, "Element that can be digged/collected");
-    else if (id == GADGET_ID_CUSTOM_MOVE_LEAVE)
-      strcpy(infotext, "Element that will be left behind");
-    else if (id == GADGET_ID_CUSTOM_CHANGE_TARGET)
-      strcpy(infotext, "New element after change");
-    else if (id == GADGET_ID_CUSTOM_CHANGE_CONTENT)
-      strcpy(infotext, "New extended elements after change");
-    else if (id == GADGET_ID_CUSTOM_CHANGE_TRIGGER)
-      strcpy(infotext, "Other element triggering change");
+    if (id == GADGET_ID_CUSTOM_CONTENT)
+      sprintf(infotext, "custom element content position: %d, %d", sx, sy);
     else if (id == GADGET_ID_GROUP_CONTENT)
-      sprintf(infotext, "Group element position: %d", sx + 1);
-    else if (id == GADGET_ID_RANDOM_BACKGROUND)
-      strcpy(infotext, "Random placement background");
+      sprintf(infotext, "group element position: %d", sx + 1);
     else if (id >= GADGET_ID_YAMYAM_CONTENT_0 &&
             id <= GADGET_ID_YAMYAM_CONTENT_7)
-      sprintf(infotext, "Content area %d position: %d, %d",
+      sprintf(infotext, "content area %d position: %d, %d",
              id - GADGET_ID_YAMYAM_CONTENT_0 + 1, sx, sy);
     else if (id >= GADGET_ID_MAGIC_BALL_CONTENT_0 &&
             id <= GADGET_ID_MAGIC_BALL_CONTENT_7)
-      sprintf(infotext, "Content area %d position: %d, %d",
+      sprintf(infotext, "content area %d position: %d, %d",
              id - GADGET_ID_MAGIC_BALL_CONTENT_0 + 1, sx, sy);
+    else if (id == GADGET_ID_ANDROID_CONTENT)
+      sprintf(infotext, "android element position: %d", sx + 1);
+    else if (drawingarea_info[type_id].infotext != NULL)
+      strcpy(infotext, drawingarea_info[type_id].infotext);
   }
 
   infotext[max_infotext_len] = '\0';
index 54a54325554b85a25d51d99a062d35fc9f458e32..8559dc55b043de334efe694ee0cdfc8cfc7124cc 100644 (file)
 /* functions and definitions exported from main program to game_em           */
 /* ========================================================================= */
 
+#include "game.h"
+
 extern void SetBitmaps_EM(Bitmap **);
 extern void UpdateEngineValues(int, int);
 extern void DrawAllGameValues(int, int, int, int, int);
+
+extern int getNumActivePlayers_EM();
 extern int getGameFrameDelay_EM(int);
+
 extern void PlayLevelSound_EM(int, int, int, int);
 extern void InitGraphicInfo_EM(void);
 
index debb368b11c0d06426fc6b00898a04af2f1b7a37..134a5e73f536a54d9ac7288c7502df7a69a62ce5 100644 (file)
@@ -104,10 +104,8 @@ static boolean NextValidEvent(Event *event)
     if (FilterMouseMotionEvents(event))
       handle_this_event = TRUE;
 
-#if 1
     if (SkipPressedMouseMotionEvent(event))
       handle_this_event = FALSE;
-#endif
 
     if (handle_this_event)
       return TRUE;
@@ -173,7 +171,9 @@ void EventLoop(void)
        has its own synchronization and is CPU friendly, too */
 
     if (game_status == GAME_MODE_PLAYING)
+    {
       HandleGameActions();
+    }
     else
     {
       SyncDisplay();
@@ -322,11 +322,6 @@ void HandleButtonEvent(ButtonEvent *event)
   else
     button_status = MB_RELEASED;
 
-#if 0
-  printf("::: button %s\n", event->type == EVENT_BUTTONPRESS ?
-       "pressed" : "released");
-#endif
-
   HandleButton(event->x, event->y, button_status);
 }
 
@@ -335,17 +330,11 @@ void HandleMotionEvent(MotionEvent *event)
   if (!PointerInWindow(window))
     return;    /* window and pointer are on different screens */
 
-#if 1
   if (button_status == MB_RELEASED && game_status != GAME_MODE_EDITOR)
     return;
-#endif
 
   motion_status = TRUE;
 
-#if 0
-  printf("::: %d, %d\n", event->x, event->y);
-#endif
-
   HandleButton(event->x, event->y, button_status);
 }
 
@@ -431,6 +420,10 @@ void HandleButton(int mx, int my, int button)
 
   switch(game_status)
   {
+    case GAME_MODE_TITLE:
+      HandleTitleScreen(mx,my, 0,0, button);
+      break;
+
     case GAME_MODE_MAIN:
       HandleMainMenu(mx,my, 0,0, button);
       break;
@@ -448,6 +441,7 @@ void HandleButton(int mx, int my, int button)
       break;
 
     case GAME_MODE_EDITOR:
+      HandleLevelEditorIdle();
       break;
 
     case GAME_MODE_INFO:
@@ -478,7 +472,7 @@ static boolean is_string_suffix(char *string, char *suffix)
   if (suffix_len > string_len)
     return FALSE;
 
-  return (strcmp(&string[string_len - suffix_len], suffix) == 0);
+  return (strEqual(&string[string_len - suffix_len], suffix));
 }
 
 #define MAX_CHEAT_INPUT_LEN    32
@@ -556,10 +550,7 @@ static void HandleKeysSpecial(Key key)
   {
 #ifdef DEBUG
     if (is_string_suffix(cheat_input, ".q"))
-      for (i = 0; i < MAX_INVENTORY_SIZE; i++)
-       if (local_player->inventory_size < MAX_INVENTORY_SIZE)
-         local_player->inventory_element[local_player->inventory_size++] =
-           EL_DYNAMITE;
+      DEBUG_SetMaximumDynamite();
 #endif
   }
   else if (game_status == GAME_MODE_EDITOR)
@@ -578,7 +569,6 @@ static void HandleKeysSpecial(Key key)
 
 void HandleKey(Key key, int key_status)
 {
-  int joy = 0;
   boolean anyTextGadgetActiveOrJustFinished = anyTextGadgetActive();
   static struct SetupKeyboardInfo custom_key;
   static struct
@@ -595,6 +585,8 @@ void HandleKey(Key key, int key_status)
     { &custom_key.snap,  DEFAULT_KEY_SNAP,  JOY_BUTTON_1 },
     { &custom_key.drop,  DEFAULT_KEY_DROP,  JOY_BUTTON_2 }
   };
+  int joy = 0;
+  int i;
 
   if (game_status == GAME_MODE_PLAYING)
   {
@@ -605,7 +597,6 @@ void HandleKey(Key key, int key_status)
 
     for (pnr = 0; pnr < MAX_PLAYERS; pnr++)
     {
-      int i;
       byte key_action = 0;
 
       if (setup.input[pnr].use_joystick)
@@ -661,8 +652,6 @@ void HandleKey(Key key, int key_status)
   }
   else
   {
-    int i;
-
     for (i = 0; i < 6; i++)
       if (key == key_info[i].key_default)
        joy |= key_info[i].action;
@@ -694,21 +683,10 @@ void HandleKey(Key key, int key_status)
     return;
   }
 
-  if (game_status == GAME_MODE_MAIN && key == setup.shortcut.toggle_pause)
+  if (game_status == GAME_MODE_MAIN &&
+      (key == setup.shortcut.toggle_pause || key == KSYM_space))
   {
-    if (setup.autorecord)
-      TapeStartRecording();
-
-#if defined(NETWORK_AVALIABLE)
-    if (options.network)
-      SendToServer_StartPlaying();
-    else
-#endif
-    {
-      game_status = GAME_MODE_PLAYING;
-      StopAnimation();
-      InitGame();
-    }
+    StartGameActions(options.network, setup.autorecord, NEW_RANDOMIZE);
 
     return;
   }
@@ -723,6 +701,30 @@ void HandleKey(Key key, int key_status)
       TapeTogglePause(TAPE_TOGGLE_MANUAL);
   }
 
+  if (game_status == GAME_MODE_PLAYING && !network_playing)
+  {
+    int centered_player_nr_next = -999;
+
+    if (key == setup.shortcut.focus_player_all)
+      centered_player_nr_next = -1;
+    else
+      for (i = 0; i < MAX_PLAYERS; i++)
+       if (key == setup.shortcut.focus_player[i])
+         centered_player_nr_next = i;
+
+    if (centered_player_nr_next != -999)
+    {
+      game.centered_player_nr_next = centered_player_nr_next;
+      game.set_centered_player = TRUE;
+
+      if (tape.recording)
+      {
+       tape.centered_player_nr_next = game.centered_player_nr_next;
+       tape.set_centered_player = TRUE;
+      }
+    }
+  }
+
   HandleKeysSpecial(key);
 
   if (HandleGadgetsKeyInput(key))
@@ -737,15 +739,23 @@ void HandleKey(Key key, int key_status)
       HandleTypeName(0, key);
       break;
 
+    case GAME_MODE_TITLE:
     case GAME_MODE_MAIN:
     case GAME_MODE_LEVELS:
     case GAME_MODE_SETUP:
     case GAME_MODE_INFO:
       switch(key)
       {
+#if 1
+       case KSYM_space:
+#else
+       /* !!! only use "space" key to start game from main menu !!! */
        case KSYM_space:
+#endif
        case KSYM_Return:
-         if (game_status == GAME_MODE_MAIN)
+         if (game_status == GAME_MODE_TITLE)
+           HandleTitleScreen(0,0, 0,0, MB_MENU_CHOICE);
+         else if (game_status == GAME_MODE_MAIN)
            HandleMainMenu(0,0, 0,0, MB_MENU_CHOICE);
           else if (game_status == GAME_MODE_LEVELS)
             HandleChooseLevel(0,0, 0,0, MB_MENU_CHOICE);
@@ -756,7 +766,9 @@ void HandleKey(Key key, int key_status)
          break;
 
        case KSYM_Escape:
-          if (game_status == GAME_MODE_LEVELS)
+         if (game_status == GAME_MODE_TITLE)
+           HandleTitleScreen(0,0, 0,0, MB_MENU_LEAVE);
+          else if (game_status == GAME_MODE_LEVELS)
             HandleChooseLevel(0,0, 0,0, MB_MENU_LEAVE);
          else if (game_status == GAME_MODE_SETUP)
            HandleSetupScreen(0,0, 0,0, MB_MENU_LEAVE);
@@ -782,6 +794,12 @@ void HandleKey(Key key, int key_status)
            HandleInfoScreen(0,0, 0, +1 * SCROLL_PAGE, MB_MENU_MARK);
          break;
 
+#ifdef DEBUG
+       case KSYM_0:
+         GameFrameDelay = (GameFrameDelay == 500 ? GAME_FRAME_DELAY : 500);
+         break;
+#endif
+
        default:
          break;
       }
@@ -825,6 +843,7 @@ void HandleKey(Key key, int key_status)
 
 #ifdef DEBUG
        case KSYM_0:
+#if 0
        case KSYM_1:
        case KSYM_2:
        case KSYM_3:
@@ -834,6 +853,7 @@ void HandleKey(Key key, int key_status)
        case KSYM_7:
        case KSYM_8:
        case KSYM_9:
+#endif
          if (key == KSYM_0)
          {
            if (GameFrameDelay == 500)
@@ -880,32 +900,6 @@ void HandleKey(Key key, int key_status)
          }
          break;
 
-#if 0
-       case KSYM_a:
-         if (ScrollStepSize == TILEX/8)
-           ScrollStepSize = TILEX/4;
-         else
-           ScrollStepSize = TILEX/8;
-         printf("ScrollStepSize == %d\n", ScrollStepSize);
-         break;
-#endif
-
-#if 0
-       case KSYM_m:
-         if (MoveSpeed == 8)
-         {
-           MoveSpeed = 4;
-           ScrollStepSize = TILEX/4;
-         }
-         else
-         {
-           MoveSpeed = 8;
-           ScrollStepSize = TILEX/8;
-         }
-         printf("MoveSpeed == %d\n", MoveSpeed);
-         break;
-#endif
-
        case KSYM_f:
          ScrollStepSize = TILEX/8;
          printf("ScrollStepSize == %d (1/8)\n", ScrollStepSize);
@@ -930,26 +924,6 @@ void HandleKey(Key key, int key_status)
          printf("::: currently using game engine version %d\n",
                 game.engine_version);
          break;
-
-#if 0
-
-       case KSYM_z:
-         {
-           int i;
-
-           for (i = 0; i < MAX_PLAYERS; i++)
-           {
-             printf("Player %d:\n", i);
-             printf("  jx == %d, jy == %d\n",
-                    stored_player[i].jx, stored_player[i].jy);
-             printf("  last_jx == %d, last_jy == %d\n",
-                    stored_player[i].last_jx, stored_player[i].last_jy);
-           }
-           printf("\n");
-         }
-
-         break;
-#endif
 #endif
 
        default:
@@ -1027,6 +1001,7 @@ void HandleJoystick()
 
   switch(game_status)
   {
+    case GAME_MODE_TITLE:
     case GAME_MODE_MAIN:
     case GAME_MODE_LEVELS:
     case GAME_MODE_SETUP:
@@ -1038,7 +1013,9 @@ void HandleJoystick()
          !DelayReached(&joystickmove_delay, GADGET_FRAME_DELAY))
        newbutton = dx = dy = 0;
 
-      if (game_status == GAME_MODE_MAIN)
+      if (game_status == GAME_MODE_TITLE)
+       HandleTitleScreen(0,0,dx,dy,newbutton ? MB_MENU_CHOICE : MB_MENU_MARK);
+      else if (game_status == GAME_MODE_MAIN)
        HandleMainMenu(0,0,dx,dy,newbutton ? MB_MENU_CHOICE : MB_MENU_MARK);
       else if (game_status == GAME_MODE_LEVELS)
         HandleChooseLevel(0,0,dx,dy,newbutton ? MB_MENU_CHOICE : MB_MENU_MARK);
index 93ab6bc8e1b564612179ae24109ec3be17b2684c..152d6528b6648dcb164d9f1b7f41a4ca66f104a5 100644 (file)
 #define CHUNK_ID_LEN           4       /* IFF style chunk id length  */
 #define CHUNK_SIZE_UNDEFINED   0       /* undefined chunk size == 0  */
 #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    0       /* unused level header bytes  */
+
+#define LEVEL_CHUNK_NAME_SIZE  MAX_LEVEL_NAME_LEN
+#define LEVEL_CHUNK_AUTH_SIZE  MAX_LEVEL_AUTHOR_LEN
+
+#define LEVEL_CHUNK_VERS_SIZE  8       /* size of file version chunk */
+#define LEVEL_CHUNK_DATE_SIZE  4       /* size of file date chunk    */
+#define LEVEL_CHUNK_HEAD_SIZE  80      /* size of level file header  */
+#define LEVEL_CHUNK_HEAD_UNUSED        0       /* 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_CHUNK_CNT3_HEADER        16      /* size of level CNT3 header  */
 #define LEVEL_CPART_CUS3_SIZE  134     /* size of CUS3 chunk part    */
 #define LEVEL_CPART_CUS3_UNUSED        15      /* unused CUS3 bytes / part   */
 #define LEVEL_CHUNK_GRP1_SIZE  74      /* size of level GRP1 chunk   */
-#define TAPE_HEADER_SIZE       20      /* size of tape file header   */
-#define TAPE_HEADER_UNUSED     3       /* unused tape header bytes   */
 
-#define LEVEL_CHUNK_CNT3_SIZE(x) (LEVEL_CHUNK_CNT3_HEADER + (x))
-#define LEVEL_CHUNK_CUS3_SIZE(x) (2 + (x) * LEVEL_CPART_CUS3_SIZE)
-#define LEVEL_CHUNK_CUS4_SIZE(x) (48 + 48 + (x) * 48)
+/* (element number, number of change pages, change page number) */
+#define LEVEL_CHUNK_CUSX_UNCHANGED     (2 + (1 + 1) + (1 + 1))
+
+/* (element number only) */
+#define LEVEL_CHUNK_GRPX_UNCHANGED     2
+#define LEVEL_CHUNK_NOTE_UNCHANGED     2
+
+/* (nothing at all if unchanged) */
+#define LEVEL_CHUNK_ELEM_UNCHANGED     0
+
+#define TAPE_CHUNK_VERS_SIZE   8       /* size of file version chunk */
+#define TAPE_CHUNK_HEAD_SIZE   20      /* size of tape file header   */
+#define TAPE_CHUNK_HEAD_UNUSED 3       /* unused tape header bytes   */
+
+#define LEVEL_CHUNK_CNT3_SIZE(x)        (LEVEL_CHUNK_CNT3_HEADER + (x))
+#define LEVEL_CHUNK_CUS3_SIZE(x)        (2 + (x) * LEVEL_CPART_CUS3_SIZE)
+#define LEVEL_CHUNK_CUS4_SIZE(x)        (96 + (x) * 48)
+
+/* file identifier strings */
+#define LEVEL_COOKIE_TMPL              "ROCKSNDIAMONDS_LEVEL_FILE_VERSION_x.x"
+#define TAPE_COOKIE_TMPL               "ROCKSNDIAMONDS_TAPE_FILE_VERSION_x.x"
+#define SCORE_COOKIE                   "ROCKSNDIAMONDS_SCORE_FILE_VERSION_1.2"
+
+/* values for deciding when (not) to save configuration data */
+#define SAVE_CONF_NEVER                        0
+#define SAVE_CONF_ALWAYS               1
+#define SAVE_CONF_WHEN_CHANGED         -1
+
+/* values for chunks using micro chunks */
+#define CONF_MASK_1_BYTE               0x00
+#define CONF_MASK_2_BYTE               0x40
+#define CONF_MASK_4_BYTE               0x80
+#define CONF_MASK_MULTI_BYTES          0xc0
+
+#define CONF_MASK_BYTES                        0xc0
+#define CONF_MASK_TOKEN                        0x3f
+
+#define CONF_VALUE_1_BYTE(x)           (CONF_MASK_1_BYTE       | (x))
+#define CONF_VALUE_2_BYTE(x)           (CONF_MASK_2_BYTE       | (x))
+#define CONF_VALUE_4_BYTE(x)           (CONF_MASK_4_BYTE       | (x))
+#define CONF_VALUE_MULTI_BYTES(x)      (CONF_MASK_MULTI_BYTES  | (x))
+
+/* these definitions are just for convenience of use and readability */
+#define CONF_VALUE_8_BIT(x)            CONF_VALUE_1_BYTE(x)
+#define CONF_VALUE_16_BIT(x)           CONF_VALUE_2_BYTE(x)
+#define CONF_VALUE_32_BIT(x)           CONF_VALUE_4_BYTE(x)
+#define CONF_VALUE_BYTES(x)            CONF_VALUE_MULTI_BYTES(x)
+
+#define CONF_VALUE_NUM_BYTES(x)                ((x) == CONF_MASK_1_BYTE ? 1 :  \
+                                        (x) == CONF_MASK_2_BYTE ? 2 :  \
+                                        (x) == CONF_MASK_4_BYTE ? 4 : 0)
+
+#define CONF_CONTENT_NUM_ELEMENTS      (3 * 3)
+#define CONF_CONTENT_NUM_BYTES         (CONF_CONTENT_NUM_ELEMENTS * 2)
+#define CONF_ELEMENT_NUM_BYTES         (2)
+
+#define CONF_ENTITY_NUM_BYTES(t)       ((t) == TYPE_ELEMENT ||         \
+                                        (t) == TYPE_ELEMENT_LIST ?     \
+                                        CONF_ELEMENT_NUM_BYTES :       \
+                                        (t) == TYPE_CONTENT ||         \
+                                        (t) == TYPE_CONTENT_LIST ?     \
+                                        CONF_CONTENT_NUM_BYTES : 1)
+
+#define CONF_ELEMENT_BYTE_POS(i)       ((i) * CONF_ELEMENT_NUM_BYTES)
+#define CONF_ELEMENTS_ELEMENT(b,i)     ((b[CONF_ELEMENT_BYTE_POS(i)] << 8) |  \
+                                       (b[CONF_ELEMENT_BYTE_POS(i) + 1]))
+
+#define CONF_CONTENT_ELEMENT_POS(c,x,y)        ((c) * CONF_CONTENT_NUM_ELEMENTS +    \
+                                        (y) * 3 + (x))
+#define CONF_CONTENT_BYTE_POS(c,x,y)   (CONF_CONTENT_ELEMENT_POS(c,x,y) *    \
+                                        CONF_ELEMENT_NUM_BYTES)
+#define CONF_CONTENTS_ELEMENT(b,c,x,y) ((b[CONF_CONTENT_BYTE_POS(c,x,y)]<< 8)|\
+                                       (b[CONF_CONTENT_BYTE_POS(c,x,y) + 1]))
+
+/* temporary variables used to store pointers to structure members */
+static struct LevelInfo li;
+static struct ElementInfo xx_ei, yy_ei;
+static struct ElementChangeInfo xx_change;
+static struct ElementGroupInfo xx_group;
+static struct EnvelopeInfo xx_envelope;
+static unsigned int xx_event_bits[NUM_CE_BITFIELDS];
+static char xx_default_description[MAX_ELEMENT_NAME_LEN + 1];
+static int xx_num_contents;
+static int xx_current_change_page;
+static char xx_default_string_empty[1] = "";
+static int xx_string_length_unused;
+
+struct LevelFileConfigInfo
+{
+  int element;                 /* element for which data is to be stored */
+  int save_type;               /* save data always, never or when changed */
+  int data_type;               /* data type (used internally, not stored) */
+  int conf_type;               /* micro chunk identifier (stored in file) */
+
+  /* (mandatory) */
+  void *value;                 /* variable that holds the data to be stored */
+  int default_value;           /* initial default value for this variable */
+
+  /* (optional) */
+  void *value_copy;            /* variable that holds the data to be copied */
+  void *num_entities;          /* number of entities for multi-byte data */
+  int default_num_entities;    /* default number of entities for this data */
+  int max_num_entities;                /* maximal number of entities for this data */
+  char *default_string;                /* optional default string for string data */
+};
+
+static struct LevelFileConfigInfo chunk_config_INFO[] =
+{
+  /* ---------- values not related to single elements ----------------------- */
+
+  {
+    -1,                                        SAVE_CONF_ALWAYS,
+    TYPE_INTEGER,                      CONF_VALUE_8_BIT(1),
+    &li.game_engine_type,              GAME_ENGINE_TYPE_RND
+  },
+
+  {
+    -1,                                        SAVE_CONF_ALWAYS,
+    TYPE_INTEGER,                      CONF_VALUE_16_BIT(1),
+    &li.fieldx,                                STD_LEV_FIELDX
+  },
+  {
+    -1,                                        SAVE_CONF_ALWAYS,
+    TYPE_INTEGER,                      CONF_VALUE_16_BIT(2),
+    &li.fieldy,                                STD_LEV_FIELDY
+  },
+
+  {
+    -1,                                        SAVE_CONF_ALWAYS,
+    TYPE_INTEGER,                      CONF_VALUE_16_BIT(3),
+    &li.time,                          100
+  },
+
+  {
+    -1,                                        SAVE_CONF_ALWAYS,
+    TYPE_INTEGER,                      CONF_VALUE_16_BIT(4),
+    &li.gems_needed,                   0
+  },
+
+  {
+    -1,                                        -1,
+    TYPE_BOOLEAN,                      CONF_VALUE_8_BIT(2),
+    &li.use_step_counter,              FALSE
+  },
+
+  {
+    -1,                                        -1,
+    TYPE_BITFIELD,                     CONF_VALUE_8_BIT(4),
+    &li.wind_direction_initial,                MV_NONE
+  },
+
+  {
+    -1,                                        -1,
+    TYPE_BOOLEAN,                      CONF_VALUE_8_BIT(5),
+    &li.em_slippery_gems,              FALSE
+  },
+
+  {
+    -1,                                        -1,
+    TYPE_BOOLEAN,                      CONF_VALUE_8_BIT(6),
+    &li.use_custom_template,           FALSE
+  },
+
+  {
+    -1,                                        -1,
+    TYPE_BITFIELD,                     CONF_VALUE_32_BIT(1),
+    &li.can_move_into_acid_bits,       ~0      /* default: everything can */
+  },
+
+  {
+    -1,                                        -1,
+    TYPE_BITFIELD,                     CONF_VALUE_8_BIT(7),
+    &li.dont_collide_with_bits,                ~0      /* default: always deadly */
+  },
+
+  {
+    -1,                                        -1,
+    TYPE_INTEGER,                      CONF_VALUE_16_BIT(5),
+    &li.score[SC_TIME_BONUS],          1
+  },
+
+  {
+    -1,                                        -1,
+    -1,                                        -1,
+    NULL,                              -1
+  }
+};
+
+static struct LevelFileConfigInfo chunk_config_ELEM[] =
+{
+  /* (these values are the same for each player) */
+  {
+    EL_PLAYER_1,                       -1,
+    TYPE_BOOLEAN,                      CONF_VALUE_8_BIT(1),
+    &li.block_last_field,              FALSE   /* default case for EM levels */
+  },
+  {
+    EL_PLAYER_1,                       -1,
+    TYPE_BOOLEAN,                      CONF_VALUE_8_BIT(2),
+    &li.sp_block_last_field,           TRUE    /* default case for SP levels */
+  },
+  {
+    EL_PLAYER_1,                       -1,
+    TYPE_BOOLEAN,                      CONF_VALUE_8_BIT(3),
+    &li.instant_relocation,            FALSE
+  },
+  {
+    EL_PLAYER_1,                       -1,
+    TYPE_BOOLEAN,                      CONF_VALUE_8_BIT(4),
+    &li.can_pass_to_walkable,          FALSE
+  },
+  {
+    EL_PLAYER_1,                       -1,
+    TYPE_BOOLEAN,                      CONF_VALUE_8_BIT(5),
+    &li.block_snap_field,              TRUE
+  },
+  {
+    EL_PLAYER_1,                       -1,
+    TYPE_BOOLEAN,                      CONF_VALUE_8_BIT(6),
+    &li.continuous_snapping,           TRUE
+  },
+
+  /* (these values are different for each player) */
+  {
+    EL_PLAYER_1,                       -1,
+    TYPE_INTEGER,                      CONF_VALUE_8_BIT(7),
+    &li.initial_player_stepsize[0],    STEPSIZE_NORMAL
+  },
+  {
+    EL_PLAYER_1,                       -1,
+    TYPE_BOOLEAN,                      CONF_VALUE_8_BIT(8),
+    &li.initial_player_gravity[0],     FALSE
+  },
+  {
+    EL_PLAYER_1,                       -1,
+    TYPE_BOOLEAN,                      CONF_VALUE_8_BIT(9),
+    &li.use_start_element[0],          FALSE
+  },
+  {
+    EL_PLAYER_1,                       -1,
+    TYPE_ELEMENT,                      CONF_VALUE_16_BIT(1),
+    &li.start_element[0],              EL_PLAYER_1
+  },
+  {
+    EL_PLAYER_1,                       -1,
+    TYPE_BOOLEAN,                      CONF_VALUE_8_BIT(10),
+    &li.use_artwork_element[0],                FALSE
+  },
+  {
+    EL_PLAYER_1,                       -1,
+    TYPE_ELEMENT,                      CONF_VALUE_16_BIT(2),
+    &li.artwork_element[0],            EL_PLAYER_1
+  },
+  {
+    EL_PLAYER_1,                       -1,
+    TYPE_BOOLEAN,                      CONF_VALUE_8_BIT(11),
+    &li.use_explosion_element[0],      FALSE
+  },
+  {
+    EL_PLAYER_1,                       -1,
+    TYPE_ELEMENT,                      CONF_VALUE_16_BIT(3),
+    &li.explosion_element[0],          EL_PLAYER_1
+  },
+
+  {
+    EL_PLAYER_2,                       -1,
+    TYPE_INTEGER,                      CONF_VALUE_8_BIT(7),
+    &li.initial_player_stepsize[1],    STEPSIZE_NORMAL
+  },
+  {
+    EL_PLAYER_2,                       -1,
+    TYPE_BOOLEAN,                      CONF_VALUE_8_BIT(8),
+    &li.initial_player_gravity[1],     FALSE
+  },
+  {
+    EL_PLAYER_2,                       -1,
+    TYPE_BOOLEAN,                      CONF_VALUE_8_BIT(9),
+    &li.use_start_element[1],          FALSE
+  },
+  {
+    EL_PLAYER_2,                       -1,
+    TYPE_ELEMENT,                      CONF_VALUE_16_BIT(1),
+    &li.start_element[1],              EL_PLAYER_2
+  },
+  {
+    EL_PLAYER_2,                       -1,
+    TYPE_BOOLEAN,                      CONF_VALUE_8_BIT(10),
+    &li.use_artwork_element[1],                FALSE
+  },
+  {
+    EL_PLAYER_2,                       -1,
+    TYPE_ELEMENT,                      CONF_VALUE_16_BIT(2),
+    &li.artwork_element[1],            EL_PLAYER_2
+  },
+  {
+    EL_PLAYER_2,                       -1,
+    TYPE_BOOLEAN,                      CONF_VALUE_8_BIT(11),
+    &li.use_explosion_element[1],      FALSE
+  },
+  {
+    EL_PLAYER_2,                       -1,
+    TYPE_ELEMENT,                      CONF_VALUE_16_BIT(3),
+    &li.explosion_element[1],          EL_PLAYER_2
+  },
+
+  {
+    EL_PLAYER_3,                       -1,
+    TYPE_INTEGER,                      CONF_VALUE_8_BIT(7),
+    &li.initial_player_stepsize[2],    STEPSIZE_NORMAL
+  },
+  {
+    EL_PLAYER_3,                       -1,
+    TYPE_BOOLEAN,                      CONF_VALUE_8_BIT(8),
+    &li.initial_player_gravity[2],     FALSE
+  },
+  {
+    EL_PLAYER_3,                       -1,
+    TYPE_BOOLEAN,                      CONF_VALUE_8_BIT(9),
+    &li.use_start_element[2],          FALSE
+  },
+  {
+    EL_PLAYER_3,                       -1,
+    TYPE_ELEMENT,                      CONF_VALUE_16_BIT(1),
+    &li.start_element[2],              EL_PLAYER_3
+  },
+  {
+    EL_PLAYER_3,                       -1,
+    TYPE_BOOLEAN,                      CONF_VALUE_8_BIT(10),
+    &li.use_artwork_element[2],                FALSE
+  },
+  {
+    EL_PLAYER_3,                       -1,
+    TYPE_ELEMENT,                      CONF_VALUE_16_BIT(2),
+    &li.artwork_element[2],            EL_PLAYER_3
+  },
+  {
+    EL_PLAYER_3,                       -1,
+    TYPE_BOOLEAN,                      CONF_VALUE_8_BIT(11),
+    &li.use_explosion_element[2],      FALSE
+  },
+  {
+    EL_PLAYER_3,                       -1,
+    TYPE_ELEMENT,                      CONF_VALUE_16_BIT(3),
+    &li.explosion_element[2],          EL_PLAYER_3
+  },
+
+  {
+    EL_PLAYER_4,                       -1,
+    TYPE_INTEGER,                      CONF_VALUE_8_BIT(7),
+    &li.initial_player_stepsize[3],    STEPSIZE_NORMAL
+  },
+  {
+    EL_PLAYER_4,                       -1,
+    TYPE_BOOLEAN,                      CONF_VALUE_8_BIT(8),
+    &li.initial_player_gravity[3],     FALSE
+  },
+  {
+    EL_PLAYER_4,                       -1,
+    TYPE_BOOLEAN,                      CONF_VALUE_8_BIT(9),
+    &li.use_start_element[3],          FALSE
+  },
+  {
+    EL_PLAYER_4,                       -1,
+    TYPE_ELEMENT,                      CONF_VALUE_16_BIT(1),
+    &li.start_element[3],              EL_PLAYER_4
+  },
+  {
+    EL_PLAYER_4,                       -1,
+    TYPE_BOOLEAN,                      CONF_VALUE_8_BIT(10),
+    &li.use_artwork_element[3],                FALSE
+  },
+  {
+    EL_PLAYER_4,                       -1,
+    TYPE_ELEMENT,                      CONF_VALUE_16_BIT(2),
+    &li.artwork_element[3],            EL_PLAYER_4
+  },
+  {
+    EL_PLAYER_4,                       -1,
+    TYPE_BOOLEAN,                      CONF_VALUE_8_BIT(11),
+    &li.use_explosion_element[3],      FALSE
+  },
+  {
+    EL_PLAYER_4,                       -1,
+    TYPE_ELEMENT,                      CONF_VALUE_16_BIT(3),
+    &li.explosion_element[3],          EL_PLAYER_4
+  },
+
+  {
+    EL_EMERALD,                                -1,
+    TYPE_INTEGER,                      CONF_VALUE_16_BIT(1),
+    &li.score[SC_EMERALD],             10
+  },
+
+  {
+    EL_DIAMOND,                                -1,
+    TYPE_INTEGER,                      CONF_VALUE_16_BIT(1),
+    &li.score[SC_DIAMOND],             10
+  },
+
+  {
+    EL_BUG,                            -1,
+    TYPE_INTEGER,                      CONF_VALUE_16_BIT(1),
+    &li.score[SC_BUG],                 10
+  },
+
+  {
+    EL_SPACESHIP,                      -1,
+    TYPE_INTEGER,                      CONF_VALUE_16_BIT(1),
+    &li.score[SC_SPACESHIP],           10
+  },
+
+  {
+    EL_PACMAN,                         -1,
+    TYPE_INTEGER,                      CONF_VALUE_16_BIT(1),
+    &li.score[SC_PACMAN],              10
+  },
+
+  {
+    EL_NUT,                            -1,
+    TYPE_INTEGER,                      CONF_VALUE_16_BIT(1),
+    &li.score[SC_NUT],                 10
+  },
+
+  {
+    EL_DYNAMITE,                       -1,
+    TYPE_INTEGER,                      CONF_VALUE_16_BIT(1),
+    &li.score[SC_DYNAMITE],            10
+  },
+
+  {
+    EL_KEY_1,                          -1,
+    TYPE_INTEGER,                      CONF_VALUE_16_BIT(1),
+    &li.score[SC_KEY],                 10
+  },
+
+  {
+    EL_PEARL,                          -1,
+    TYPE_INTEGER,                      CONF_VALUE_16_BIT(1),
+    &li.score[SC_PEARL],               10
+  },
+
+  {
+    EL_CRYSTAL,                                -1,
+    TYPE_INTEGER,                      CONF_VALUE_16_BIT(1),
+    &li.score[SC_CRYSTAL],             10
+  },
+
+  {
+    EL_BD_AMOEBA,                      -1,
+    TYPE_ELEMENT,                      CONF_VALUE_16_BIT(1),
+    &li.amoeba_content,                        EL_DIAMOND
+  },
+  {
+    EL_BD_AMOEBA,                      -1,
+    TYPE_INTEGER,                      CONF_VALUE_16_BIT(2),
+    &li.amoeba_speed,                  10
+  },
+  {
+    EL_BD_AMOEBA,                      -1,
+    TYPE_BOOLEAN,                      CONF_VALUE_8_BIT(1),
+    &li.grow_into_diggable,            TRUE
+  },
+
+  {
+    EL_YAMYAM,                         -1,
+    TYPE_CONTENT_LIST,                 CONF_VALUE_BYTES(1),
+    &li.yamyam_content,                        EL_ROCK, NULL,
+    &li.num_yamyam_contents,           4, MAX_ELEMENT_CONTENTS
+  },
+  {
+    EL_YAMYAM,                         -1,
+    TYPE_INTEGER,                      CONF_VALUE_16_BIT(1),
+    &li.score[SC_YAMYAM],              10
+  },
+
+  {
+    EL_ROBOT,                          -1,
+    TYPE_INTEGER,                      CONF_VALUE_16_BIT(1),
+    &li.score[SC_ROBOT],               10
+  },
+  {
+    EL_ROBOT,                          -1,
+    TYPE_INTEGER,                      CONF_VALUE_16_BIT(2),
+    &li.slurp_score,                   10
+  },
+
+  {
+    EL_ROBOT_WHEEL,                    -1,
+    TYPE_INTEGER,                      CONF_VALUE_16_BIT(1),
+    &li.time_wheel,                    10
+  },
+
+  {
+    EL_MAGIC_WALL,                     -1,
+    TYPE_INTEGER,                      CONF_VALUE_16_BIT(1),
+    &li.time_magic_wall,               10
+  },
+
+  {
+    EL_GAME_OF_LIFE,                   -1,
+    TYPE_INTEGER,                      CONF_VALUE_8_BIT(1),
+    &li.game_of_life[0],               2
+  },
+  {
+    EL_GAME_OF_LIFE,                   -1,
+    TYPE_INTEGER,                      CONF_VALUE_8_BIT(2),
+    &li.game_of_life[1],               3
+  },
+  {
+    EL_GAME_OF_LIFE,                   -1,
+    TYPE_INTEGER,                      CONF_VALUE_8_BIT(3),
+    &li.game_of_life[2],               3
+  },
+  {
+    EL_GAME_OF_LIFE,                   -1,
+    TYPE_INTEGER,                      CONF_VALUE_8_BIT(4),
+    &li.game_of_life[3],               3
+  },
+
+  {
+    EL_BIOMAZE,                                -1,
+    TYPE_INTEGER,                      CONF_VALUE_8_BIT(1),
+    &li.biomaze[0],                    2
+  },
+  {
+    EL_BIOMAZE,                                -1,
+    TYPE_INTEGER,                      CONF_VALUE_8_BIT(2),
+    &li.biomaze[1],                    3
+  },
+  {
+    EL_BIOMAZE,                                -1,
+    TYPE_INTEGER,                      CONF_VALUE_8_BIT(3),
+    &li.biomaze[2],                    3
+  },
+  {
+    EL_BIOMAZE,                                -1,
+    TYPE_INTEGER,                      CONF_VALUE_8_BIT(4),
+    &li.biomaze[3],                    3
+  },
+
+  {
+    EL_TIMEGATE_SWITCH,                        -1,
+    TYPE_INTEGER,                      CONF_VALUE_16_BIT(1),
+    &li.time_timegate,                 10
+  },
+
+  {
+    EL_LIGHT_SWITCH_ACTIVE,            -1,
+    TYPE_INTEGER,                      CONF_VALUE_16_BIT(1),
+    &li.time_light,                    10
+  },
+
+  {
+    EL_SHIELD_NORMAL,                  -1,
+    TYPE_INTEGER,                      CONF_VALUE_16_BIT(1),
+    &li.shield_normal_time,            10
+  },
+  {
+    EL_SHIELD_NORMAL,                  -1,
+    TYPE_INTEGER,                      CONF_VALUE_16_BIT(2),
+    &li.score[SC_SHIELD],              10
+  },
+
+  {
+    EL_SHIELD_DEADLY,                  -1,
+    TYPE_INTEGER,                      CONF_VALUE_16_BIT(1),
+    &li.shield_deadly_time,            10
+  },
+  {
+    EL_SHIELD_DEADLY,                  -1,
+    TYPE_INTEGER,                      CONF_VALUE_16_BIT(2),
+    &li.score[SC_SHIELD],              10
+  },
+
+  {
+    EL_EXTRA_TIME,                     -1,
+    TYPE_INTEGER,                      CONF_VALUE_16_BIT(1),
+    &li.extra_time,                    10
+  },
+  {
+    EL_EXTRA_TIME,                     -1,
+    TYPE_INTEGER,                      CONF_VALUE_16_BIT(2),
+    &li.extra_time_score,              10
+  },
+
+  {
+    EL_TIME_ORB_FULL,                  -1,
+    TYPE_INTEGER,                      CONF_VALUE_16_BIT(1),
+    &li.time_orb_time,                 10
+  },
+  {
+    EL_TIME_ORB_FULL,                  -1,
+    TYPE_BOOLEAN,                      CONF_VALUE_8_BIT(1),
+    &li.use_time_orb_bug,              FALSE
+  },
+
+  {
+    EL_SPRING,                         -1,
+    TYPE_BOOLEAN,                      CONF_VALUE_8_BIT(1),
+    &li.use_spring_bug,                        FALSE
+  },
+
+  {
+    EL_EMC_ANDROID,                    -1,
+    TYPE_INTEGER,                      CONF_VALUE_16_BIT(1),
+    &li.android_move_time,             10
+  },
+  {
+    EL_EMC_ANDROID,                    -1,
+    TYPE_INTEGER,                      CONF_VALUE_16_BIT(2),
+    &li.android_clone_time,            10
+  },
+  {
+    EL_EMC_ANDROID,                    -1,
+    TYPE_ELEMENT_LIST,                 CONF_VALUE_BYTES(1),
+    &li.android_clone_element[0],      EL_EMPTY, NULL,
+    &li.num_android_clone_elements,    1, MAX_ANDROID_ELEMENTS
+  },
+
+  {
+    EL_EMC_LENSES,                     -1,
+    TYPE_INTEGER,                      CONF_VALUE_16_BIT(1),
+    &li.lenses_score,                  10
+  },
+  {
+    EL_EMC_LENSES,                     -1,
+    TYPE_INTEGER,                      CONF_VALUE_16_BIT(2),
+    &li.lenses_time,                   10
+  },
+
+  {
+    EL_EMC_MAGNIFIER,                  -1,
+    TYPE_INTEGER,                      CONF_VALUE_16_BIT(1),
+    &li.magnify_score,                 10
+  },
+  {
+    EL_EMC_MAGNIFIER,                  -1,
+    TYPE_INTEGER,                      CONF_VALUE_16_BIT(2),
+    &li.magnify_time,                  10
+  },
+
+  {
+    EL_EMC_MAGIC_BALL,                 -1,
+    TYPE_INTEGER,                      CONF_VALUE_16_BIT(1),
+    &li.ball_time,                     10
+  },
+  {
+    EL_EMC_MAGIC_BALL,                 -1,
+    TYPE_BOOLEAN,                      CONF_VALUE_8_BIT(1),
+    &li.ball_random,                   FALSE
+  },
+  {
+    EL_EMC_MAGIC_BALL,                 -1,
+    TYPE_BOOLEAN,                      CONF_VALUE_8_BIT(2),
+    &li.ball_state_initial,            FALSE
+  },
+  {
+    EL_EMC_MAGIC_BALL,                 -1,
+    TYPE_CONTENT_LIST,                 CONF_VALUE_BYTES(1),
+    &li.ball_content,                  EL_EMPTY, NULL,
+    &li.num_ball_contents,             4, MAX_ELEMENT_CONTENTS
+  },
+
+  /* ---------- unused values ----------------------------------------------- */
+
+  {
+    EL_UNKNOWN,                                SAVE_CONF_NEVER,
+    TYPE_INTEGER,                      CONF_VALUE_16_BIT(1),
+    &li.score[SC_UNKNOWN_14],          10
+  },
+  {
+    EL_UNKNOWN,                                SAVE_CONF_NEVER,
+    TYPE_INTEGER,                      CONF_VALUE_16_BIT(2),
+    &li.score[SC_UNKNOWN_15],          10
+  },
+
+  {
+    -1,                                        -1,
+    -1,                                        -1,
+    NULL,                              -1
+  }
+};
+
+static struct LevelFileConfigInfo chunk_config_NOTE[] =
+{
+  {
+    -1,                                        -1,
+    TYPE_INTEGER,                      CONF_VALUE_8_BIT(1),
+    &xx_envelope.xsize,                        MAX_ENVELOPE_XSIZE,
+  },
+  {
+    -1,                                        -1,
+    TYPE_INTEGER,                      CONF_VALUE_8_BIT(2),
+    &xx_envelope.ysize,                        MAX_ENVELOPE_YSIZE,
+  },
+
+  {
+    -1,                                        -1,
+    TYPE_STRING,                       CONF_VALUE_BYTES(1),
+    &xx_envelope.text,                 -1, NULL,
+    &xx_string_length_unused,          -1, MAX_ENVELOPE_TEXT_LEN,
+    &xx_default_string_empty[0]
+  },
+
+  {
+    -1,                                        -1,
+    -1,                                        -1,
+    NULL,                              -1
+  }
+};
+
+static struct LevelFileConfigInfo chunk_config_CUSX_base[] =
+{
+  {
+    -1,                                        -1,
+    TYPE_STRING,                       CONF_VALUE_BYTES(1),
+    &xx_ei.description[0],             -1,
+    &yy_ei.description[0],
+    &xx_string_length_unused,          -1, MAX_ELEMENT_NAME_LEN,
+    &xx_default_description[0]
+  },
+
+  {
+    -1,                                        -1,
+    TYPE_BITFIELD,                     CONF_VALUE_32_BIT(1),
+    &xx_ei.properties[EP_BITFIELD_BASE_NR], EP_BITMASK_BASE_DEFAULT,
+    &yy_ei.properties[EP_BITFIELD_BASE_NR]
+  },
+#if 0
+  /* (reserved) */
+  {
+    -1,                                        -1,
+    TYPE_BITFIELD,                     CONF_VALUE_32_BIT(2),
+    &xx_ei.properties[EP_BITFIELD_BASE_NR + 1], EP_BITMASK_DEFAULT,
+    &yy_ei.properties[EP_BITFIELD_BASE_NR + 1]
+  },
+#endif
+
+  {
+    -1,                                        -1,
+    TYPE_BOOLEAN,                      CONF_VALUE_8_BIT(1),
+    &xx_ei.use_gfx_element,            FALSE,
+    &yy_ei.use_gfx_element
+  },
+  {
+    -1,                                        -1,
+    TYPE_ELEMENT,                      CONF_VALUE_16_BIT(1),
+    &xx_ei.gfx_element,                        EL_EMPTY_SPACE,
+    &yy_ei.gfx_element
+  },
+
+  {
+    -1,                                        -1,
+    TYPE_BITFIELD,                     CONF_VALUE_8_BIT(2),
+    &xx_ei.access_direction,           MV_ALL_DIRECTIONS,
+    &yy_ei.access_direction
+  },
+
+  {
+    -1,                                        -1,
+    TYPE_INTEGER,                      CONF_VALUE_16_BIT(2),
+    &xx_ei.collect_score_initial,      10,
+    &yy_ei.collect_score_initial
+  },
+  {
+    -1,                                        -1,
+    TYPE_INTEGER,                      CONF_VALUE_16_BIT(3),
+    &xx_ei.collect_count_initial,      1,
+    &yy_ei.collect_count_initial
+  },
+
+  {
+    -1,                                        -1,
+    TYPE_INTEGER,                      CONF_VALUE_16_BIT(4),
+    &xx_ei.ce_value_fixed_initial,     0,
+    &yy_ei.ce_value_fixed_initial
+  },
+  {
+    -1,                                        -1,
+    TYPE_INTEGER,                      CONF_VALUE_16_BIT(5),
+    &xx_ei.ce_value_random_initial,    0,
+    &yy_ei.ce_value_random_initial
+  },
+  {
+    -1,                                        -1,
+    TYPE_BOOLEAN,                      CONF_VALUE_8_BIT(3),
+    &xx_ei.use_last_ce_value,          FALSE,
+    &yy_ei.use_last_ce_value
+  },
+
+  {
+    -1,                                        -1,
+    TYPE_INTEGER,                      CONF_VALUE_16_BIT(6),
+    &xx_ei.push_delay_fixed,           8,
+    &yy_ei.push_delay_fixed
+  },
+  {
+    -1,                                        -1,
+    TYPE_INTEGER,                      CONF_VALUE_16_BIT(7),
+    &xx_ei.push_delay_random,          8,
+    &yy_ei.push_delay_random
+  },
+  {
+    -1,                                        -1,
+    TYPE_INTEGER,                      CONF_VALUE_16_BIT(8),
+    &xx_ei.drop_delay_fixed,           0,
+    &yy_ei.drop_delay_fixed
+  },
+  {
+    -1,                                        -1,
+    TYPE_INTEGER,                      CONF_VALUE_16_BIT(9),
+    &xx_ei.drop_delay_random,          0,
+    &yy_ei.drop_delay_random
+  },
+  {
+    -1,                                        -1,
+    TYPE_INTEGER,                      CONF_VALUE_16_BIT(10),
+    &xx_ei.move_delay_fixed,           0,
+    &yy_ei.move_delay_fixed
+  },
+  {
+    -1,                                        -1,
+    TYPE_INTEGER,                      CONF_VALUE_16_BIT(11),
+    &xx_ei.move_delay_random,          0,
+    &yy_ei.move_delay_random
+  },
+
+  {
+    -1,                                        -1,
+    TYPE_BITFIELD,                     CONF_VALUE_32_BIT(3),
+    &xx_ei.move_pattern,               MV_ALL_DIRECTIONS,
+    &yy_ei.move_pattern
+  },
+  {
+    -1,                                        -1,
+    TYPE_BITFIELD,                     CONF_VALUE_8_BIT(4),
+    &xx_ei.move_direction_initial,     MV_START_AUTOMATIC,
+    &yy_ei.move_direction_initial
+  },
+  {
+    -1,                                        -1,
+    TYPE_INTEGER,                      CONF_VALUE_8_BIT(5),
+    &xx_ei.move_stepsize,              TILEX / 8,
+    &yy_ei.move_stepsize
+  },
+
+  {
+    -1,                                        -1,
+    TYPE_ELEMENT,                      CONF_VALUE_16_BIT(12),
+    &xx_ei.move_enter_element,         EL_EMPTY_SPACE,
+    &yy_ei.move_enter_element
+  },
+  {
+    -1,                                        -1,
+    TYPE_ELEMENT,                      CONF_VALUE_16_BIT(13),
+    &xx_ei.move_leave_element,         EL_EMPTY_SPACE,
+    &yy_ei.move_leave_element
+  },
+  {
+    -1,                                        -1,
+    TYPE_INTEGER,                      CONF_VALUE_8_BIT(6),
+    &xx_ei.move_leave_type,            LEAVE_TYPE_UNLIMITED,
+    &yy_ei.move_leave_type
+  },
+
+  {
+    -1,                                        -1,
+    TYPE_INTEGER,                      CONF_VALUE_8_BIT(7),
+    &xx_ei.slippery_type,              SLIPPERY_ANY_RANDOM,
+    &yy_ei.slippery_type
+  },
+
+  {
+    -1,                                        -1,
+    TYPE_INTEGER,                      CONF_VALUE_8_BIT(8),
+    &xx_ei.explosion_type,             EXPLODES_3X3,
+    &yy_ei.explosion_type
+  },
+  {
+    -1,                                        -1,
+    TYPE_INTEGER,                      CONF_VALUE_16_BIT(14),
+    &xx_ei.explosion_delay,            16,
+    &yy_ei.explosion_delay
+  },
+  {
+    -1,                                        -1,
+    TYPE_INTEGER,                      CONF_VALUE_16_BIT(15),
+    &xx_ei.ignition_delay,             8,
+    &yy_ei.ignition_delay
+  },
+
+  {
+    -1,                                        -1,
+    TYPE_CONTENT_LIST,                 CONF_VALUE_BYTES(2),
+    &xx_ei.content,                    EL_EMPTY_SPACE,
+    &yy_ei.content,
+    &xx_num_contents,                  1, 1
+  },
+
+  /* ---------- "num_change_pages" must be the last entry ------------------- */
+
+  {
+    -1,                                        SAVE_CONF_ALWAYS,
+    TYPE_INTEGER,                      CONF_VALUE_8_BIT(9),
+    &xx_ei.num_change_pages,           1,
+    &yy_ei.num_change_pages
+  },
+
+  {
+    -1,                                        -1,
+    -1,                                        -1,
+    NULL,                              -1,
+    NULL
+  }
+};
+
+static struct LevelFileConfigInfo chunk_config_CUSX_change[] =
+{
+  /* ---------- "current_change_page" must be the first entry --------------- */
+
+  {
+    -1,                                        SAVE_CONF_ALWAYS,
+    TYPE_INTEGER,                      CONF_VALUE_8_BIT(1),
+    &xx_current_change_page,           -1
+  },
+
+  /* ---------- (the remaining entries can be in any order) ----------------- */
+
+  {
+    -1,                                        -1,
+    TYPE_BOOLEAN,                      CONF_VALUE_8_BIT(2),
+    &xx_change.can_change,             FALSE
+  },
+
+  {
+    -1,                                        -1,
+    TYPE_BITFIELD,                     CONF_VALUE_32_BIT(1),
+    &xx_event_bits[0],                 0
+  },
+  {
+    -1,                                        -1,
+    TYPE_BITFIELD,                     CONF_VALUE_32_BIT(2),
+    &xx_event_bits[1],                 0
+  },
+
+  {
+    -1,                                        -1,
+    TYPE_BITFIELD,                     CONF_VALUE_8_BIT(3),
+    &xx_change.trigger_player,         CH_PLAYER_ANY
+  },
+  {
+    -1,                                        -1,
+    TYPE_BITFIELD,                     CONF_VALUE_8_BIT(4),
+    &xx_change.trigger_side,           CH_SIDE_ANY
+  },
+  {
+    -1,                                        -1,
+    TYPE_BITFIELD,                     CONF_VALUE_32_BIT(3),
+    &xx_change.trigger_page,           CH_PAGE_ANY
+  },
+
+  {
+    -1,                                        -1,
+    TYPE_ELEMENT,                      CONF_VALUE_16_BIT(1),
+    &xx_change.target_element,         EL_EMPTY_SPACE
+  },
+
+  {
+    -1,                                        -1,
+    TYPE_INTEGER,                      CONF_VALUE_16_BIT(2),
+    &xx_change.delay_fixed,            0
+  },
+  {
+    -1,                                        -1,
+    TYPE_INTEGER,                      CONF_VALUE_16_BIT(3),
+    &xx_change.delay_random,           0
+  },
+  {
+    -1,                                        -1,
+    TYPE_INTEGER,                      CONF_VALUE_16_BIT(4),
+    &xx_change.delay_frames,           FRAMES_PER_SECOND
+  },
+
+  {
+    -1,                                        -1,
+    TYPE_ELEMENT,                      CONF_VALUE_16_BIT(5),
+    &xx_change.trigger_element,                EL_EMPTY_SPACE
+  },
+
+  {
+    -1,                                        -1,
+    TYPE_BOOLEAN,                      CONF_VALUE_8_BIT(6),
+    &xx_change.explode,                        FALSE
+  },
+  {
+    -1,                                        -1,
+    TYPE_BOOLEAN,                      CONF_VALUE_8_BIT(7),
+    &xx_change.use_target_content,     FALSE
+  },
+  {
+    -1,                                        -1,
+    TYPE_BOOLEAN,                      CONF_VALUE_8_BIT(8),
+    &xx_change.only_if_complete,       FALSE
+  },
+  {
+    -1,                                        -1,
+    TYPE_BOOLEAN,                      CONF_VALUE_8_BIT(9),
+    &xx_change.use_random_replace,     FALSE
+  },
+  {
+    -1,                                        -1,
+    TYPE_INTEGER,                      CONF_VALUE_8_BIT(10),
+    &xx_change.random_percentage,      100
+  },
+  {
+    -1,                                        -1,
+    TYPE_INTEGER,                      CONF_VALUE_8_BIT(11),
+    &xx_change.replace_when,           CP_WHEN_EMPTY
+  },
+
+  {
+    -1,                                        -1,
+    TYPE_BOOLEAN,                      CONF_VALUE_8_BIT(12),
+    &xx_change.has_action,             FALSE
+  },
+  {
+    -1,                                        -1,
+    TYPE_INTEGER,                      CONF_VALUE_8_BIT(13),
+    &xx_change.action_type,            CA_NO_ACTION
+  },
+  {
+    -1,                                        -1,
+    TYPE_INTEGER,                      CONF_VALUE_8_BIT(14),
+    &xx_change.action_mode,            CA_MODE_UNDEFINED
+  },
+  {
+    -1,                                        -1,
+    TYPE_INTEGER,                      CONF_VALUE_16_BIT(6),
+    &xx_change.action_arg,             CA_ARG_UNDEFINED
+  },
+
+  {
+    -1,                                        -1,
+    TYPE_CONTENT_LIST,                 CONF_VALUE_BYTES(1),
+    &xx_change.target_content,         EL_EMPTY_SPACE, NULL,
+    &xx_num_contents,                  1, 1
+  },
+
+  {
+    -1,                                        -1,
+    -1,                                        -1,
+    NULL,                              -1
+  }
+};
+
+static struct LevelFileConfigInfo chunk_config_GRPX[] =
+{
+  {
+    -1,                                        -1,
+    TYPE_STRING,                       CONF_VALUE_BYTES(1),
+    &xx_ei.description[0],             -1, NULL,
+    &xx_string_length_unused,          -1, MAX_ELEMENT_NAME_LEN,
+    &xx_default_description[0]
+  },
+
+  {
+    -1,                                        -1,
+    TYPE_BOOLEAN,                      CONF_VALUE_8_BIT(1),
+    &xx_ei.use_gfx_element,            FALSE
+  },
+  {
+    -1,                                        -1,
+    TYPE_ELEMENT,                      CONF_VALUE_16_BIT(1),
+    &xx_ei.gfx_element,                        EL_EMPTY_SPACE
+  },
+
+  {
+    -1,                                        -1,
+    TYPE_INTEGER,                      CONF_VALUE_8_BIT(2),
+    &xx_group.choice_mode,             ANIM_RANDOM
+  },
+
+  {
+    -1,                                        -1,
+    TYPE_ELEMENT_LIST,                 CONF_VALUE_BYTES(2),
+    &xx_group.element[0],              EL_EMPTY_SPACE, NULL,
+    &xx_group.num_elements,            1, MAX_ELEMENTS_IN_GROUP
+  },
+
+  {
+    -1,                                        -1,
+    -1,                                        -1,
+    NULL,                              -1
+  }
+};
+
+static struct LevelFileConfigInfo chunk_config_CONF[] =                /* (OBSOLETE) */
+{
+  {
+    EL_PLAYER_1,                       -1,
+    TYPE_BOOLEAN,                      CONF_VALUE_8_BIT(9),
+    &li.block_snap_field,              TRUE
+  },
+  {
+    EL_PLAYER_1,                       -1,
+    TYPE_BOOLEAN,                      CONF_VALUE_8_BIT(13),
+    &li.continuous_snapping,           TRUE
+  },
+  {
+    EL_PLAYER_1,                       -1,
+    TYPE_INTEGER,                      CONF_VALUE_8_BIT(1),
+    &li.initial_player_stepsize[0],    STEPSIZE_NORMAL
+  },
+  {
+    EL_PLAYER_1,                       -1,
+    TYPE_BOOLEAN,                      CONF_VALUE_8_BIT(10),
+    &li.use_start_element[0],          FALSE
+  },
+  {
+    EL_PLAYER_1,                       -1,
+    TYPE_ELEMENT,                      CONF_VALUE_16_BIT(1),
+    &li.start_element[0],              EL_PLAYER_1
+  },
+  {
+    EL_PLAYER_1,                       -1,
+    TYPE_BOOLEAN,                      CONF_VALUE_8_BIT(11),
+    &li.use_artwork_element[0],                FALSE
+  },
+  {
+    EL_PLAYER_1,                       -1,
+    TYPE_ELEMENT,                      CONF_VALUE_16_BIT(2),
+    &li.artwork_element[0],            EL_PLAYER_1
+  },
+  {
+    EL_PLAYER_1,                       -1,
+    TYPE_BOOLEAN,                      CONF_VALUE_8_BIT(12),
+    &li.use_explosion_element[0],      FALSE
+  },
+  {
+    EL_PLAYER_1,                       -1,
+    TYPE_ELEMENT,                      CONF_VALUE_16_BIT(3),
+    &li.explosion_element[0],          EL_PLAYER_1
+  },
+
+  {
+    -1,                                        -1,
+    -1,                                        -1,
+    NULL,                              -1
+  }
+};
+
+static struct
+{
+  int filetype;
+  char *id;
+}
+filetype_id_list[] =
+{
+  { LEVEL_FILE_TYPE_RND,       "RND"   },
+  { LEVEL_FILE_TYPE_BD,                "BD"    },
+  { LEVEL_FILE_TYPE_EM,                "EM"    },
+  { LEVEL_FILE_TYPE_SP,                "SP"    },
+  { LEVEL_FILE_TYPE_DX,                "DX"    },
+  { LEVEL_FILE_TYPE_SB,                "SB"    },
+  { LEVEL_FILE_TYPE_DC,                "DC"    },
+  { -1,                                NULL    },
+};
+
+
+/* ========================================================================= */
+/* level file functions                                                      */
+/* ========================================================================= */
+
+static struct DateInfo getCurrentDate()
+{
+  time_t epoch_seconds = time(NULL);
+  struct tm *now = localtime(&epoch_seconds);
+  struct DateInfo date;
+
+  date.year  = now->tm_year + 1900;
+  date.month = now->tm_mon  + 1;
+  date.day   = now->tm_mday;
+
+  return date;
+}
+
+static void resetEventFlags(struct ElementChangeInfo *change)
+{
+  int i;
+
+  for (i = 0; i < NUM_CHANGE_EVENTS; i++)
+    change->has_event[i] = FALSE;
+}
+
+static void resetEventBits()
+{
+  int i;
+
+  for (i = 0; i < NUM_CE_BITFIELDS; i++)
+    xx_event_bits[i] = 0;
+}
+
+static void setEventFlagsFromEventBits(struct ElementChangeInfo *change)
+{
+  int i;
+
+  /* important: only change event flag if corresponding event bit is set */
+  for (i = 0; i < NUM_CHANGE_EVENTS; i++)
+    if (xx_event_bits[CH_EVENT_BITFIELD_NR(i)] & CH_EVENT_BIT(i))
+      change->has_event[i] = TRUE;
+}
+
+static void setEventBitsFromEventFlags(struct ElementChangeInfo *change)
+{
+  int i;
+
+  /* important: only change event bit if corresponding event flag is set */
+  for (i = 0; i < NUM_CHANGE_EVENTS; i++)
+    if (change->has_event[i])
+      xx_event_bits[CH_EVENT_BITFIELD_NR(i)] |= CH_EVENT_BIT(i);
+}
+
+static char *getDefaultElementDescription(struct ElementInfo *ei)
+{
+  static char description[MAX_ELEMENT_NAME_LEN + 1];
+  char *default_description = (ei->custom_description != NULL ?
+                              ei->custom_description :
+                              ei->editor_description);
+  int i;
+
+  /* always start with reliable default values */
+  for (i = 0; i < MAX_ELEMENT_NAME_LEN + 1; i++)
+    description[i] = '\0';
+
+  /* truncate element description to MAX_ELEMENT_NAME_LEN bytes */
+  strncpy(description, default_description, MAX_ELEMENT_NAME_LEN);
+
+  return &description[0];
+}
+
+static void setElementDescriptionToDefault(struct ElementInfo *ei)
+{
+  char *default_description = getDefaultElementDescription(ei);
+  int i;
+
+  for (i = 0; i < MAX_ELEMENT_NAME_LEN + 1; i++)
+    ei->description[i] = default_description[i];
+}
+
+static void setConfigToDefaultsFromConfigList(struct LevelFileConfigInfo *conf)
+{
+  int i;
+
+  for (i = 0; conf[i].data_type != -1; i++)
+  {
+    int default_value = conf[i].default_value;
+    int data_type = conf[i].data_type;
+    int conf_type = conf[i].conf_type;
+    int byte_mask = conf_type & CONF_MASK_BYTES;
+
+    if (byte_mask == CONF_MASK_MULTI_BYTES)
+    {
+      int default_num_entities = conf[i].default_num_entities;
+      int max_num_entities = conf[i].max_num_entities;
+
+      *(int *)(conf[i].num_entities) = default_num_entities;
+
+      if (data_type == TYPE_STRING)
+      {
+       char *default_string = conf[i].default_string;
+       char *string = (char *)(conf[i].value);
+
+       strncpy(string, default_string, max_num_entities);
+      }
+      else if (data_type == TYPE_ELEMENT_LIST)
+      {
+       int *element_array = (int *)(conf[i].value);
+       int j;
+
+       for (j = 0; j < max_num_entities; j++)
+         element_array[j] = default_value;
+      }
+      else if (data_type == TYPE_CONTENT_LIST)
+      {
+       struct Content *content = (struct Content *)(conf[i].value);
+       int c, x, y;
+
+       for (c = 0; c < max_num_entities; c++)
+         for (y = 0; y < 3; y++)
+           for (x = 0; x < 3; x++)
+             content[c].e[x][y] = default_value;
+      }
+    }
+    else       /* constant size configuration data (1, 2 or 4 bytes) */
+    {
+      if (data_type == TYPE_BOOLEAN)
+       *(boolean *)(conf[i].value) = default_value;
+      else
+       *(int *)    (conf[i].value) = default_value;
+    }
+  }
+}
+
+static void copyConfigFromConfigList(struct LevelFileConfigInfo *conf)
+{
+  int i;
+
+  for (i = 0; conf[i].data_type != -1; i++)
+  {
+    int data_type = conf[i].data_type;
+    int conf_type = conf[i].conf_type;
+    int byte_mask = conf_type & CONF_MASK_BYTES;
+
+    if (byte_mask == CONF_MASK_MULTI_BYTES)
+    {
+      int max_num_entities = conf[i].max_num_entities;
+
+      if (data_type == TYPE_STRING)
+      {
+       char *string      = (char *)(conf[i].value);
+       char *string_copy = (char *)(conf[i].value_copy);
+
+       strncpy(string_copy, string, max_num_entities);
+      }
+      else if (data_type == TYPE_ELEMENT_LIST)
+      {
+       int *element_array      = (int *)(conf[i].value);
+       int *element_array_copy = (int *)(conf[i].value_copy);
+       int j;
+
+       for (j = 0; j < max_num_entities; j++)
+         element_array_copy[j] = element_array[j];
+      }
+      else if (data_type == TYPE_CONTENT_LIST)
+      {
+       struct Content *content      = (struct Content *)(conf[i].value);
+       struct Content *content_copy = (struct Content *)(conf[i].value_copy);
+       int c, x, y;
+
+       for (c = 0; c < max_num_entities; c++)
+         for (y = 0; y < 3; y++)
+           for (x = 0; x < 3; x++)
+             content_copy[c].e[x][y] = content[c].e[x][y];
+      }
+    }
+    else       /* constant size configuration data (1, 2 or 4 bytes) */
+    {
+      if (data_type == TYPE_BOOLEAN)
+       *(boolean *)(conf[i].value_copy) = *(boolean *)(conf[i].value);
+      else
+       *(int *)    (conf[i].value_copy) = *(int *)    (conf[i].value);
+    }
+  }
+}
+
+#if 1
+void copyElementInfo(struct ElementInfo *ei_from, struct ElementInfo *ei_to)
+{
+#if 1
+  int i;
+#else
+  int i, x, y;
+#endif
 
-/* file identifier strings */
-#define LEVEL_COOKIE_TMPL      "ROCKSNDIAMONDS_LEVEL_FILE_VERSION_x.x"
-#define TAPE_COOKIE_TMPL       "ROCKSNDIAMONDS_TAPE_FILE_VERSION_x.x"
-#define SCORE_COOKIE           "ROCKSNDIAMONDS_SCORE_FILE_VERSION_1.2"
+#if 1
+  xx_ei = *ei_from;    /* copy element data into temporary buffer */
+  yy_ei = *ei_to;      /* copy element data into temporary buffer */
 
-static struct
-{
-  int filetype;
-  char *id;
-}
-filetype_id_list[] =
-{
-  { LEVEL_FILE_TYPE_RND,       "RND"   },
-  { LEVEL_FILE_TYPE_BD,                "BD"    },
-  { LEVEL_FILE_TYPE_EM,                "EM"    },
-  { LEVEL_FILE_TYPE_SP,                "SP"    },
-  { LEVEL_FILE_TYPE_DX,                "DX"    },
-  { LEVEL_FILE_TYPE_SB,                "SB"    },
-  { LEVEL_FILE_TYPE_DC,                "DC"    },
-  { -1,                                NULL    },
-};
+  copyConfigFromConfigList(chunk_config_CUSX_base);
+
+  *ei_from = xx_ei;
+  *ei_to   = yy_ei;
+#endif
 
+#if 0
+  /* ---------- copy element description ---------- */
+  for (i = 0; i < MAX_ELEMENT_NAME_LEN + 1; i++)
+    ei_to->description[i] = ei_from->description[i];
 
-/* ========================================================================= */
-/* level file functions                                                      */
-/* ========================================================================= */
+  /* ---------- copy element base properties ---------- */
+  ei_to->properties[EP_BITFIELD_BASE_NR] =
+    ei_from->properties[EP_BITFIELD_BASE_NR];
+
+  /* ---------- copy custom property values ---------- */
+
+  ei_to->use_gfx_element = ei_from->use_gfx_element;
+  ei_to->gfx_element = ei_from->gfx_element;
+
+  ei_to->access_direction = ei_from->access_direction;
+
+  ei_to->collect_score_initial = ei_from->collect_score_initial;
+  ei_to->collect_count_initial = ei_from->collect_count_initial;
+
+  ei_to->ce_value_fixed_initial = ei_from->ce_value_fixed_initial;
+  ei_to->ce_value_random_initial = ei_from->ce_value_random_initial;
+  ei_to->use_last_ce_value = ei_from->use_last_ce_value;
+
+  ei_to->push_delay_fixed = ei_from->push_delay_fixed;
+  ei_to->push_delay_random = ei_from->push_delay_random;
+  ei_to->drop_delay_fixed = ei_from->drop_delay_fixed;
+  ei_to->drop_delay_random = ei_from->drop_delay_random;
+  ei_to->move_delay_fixed = ei_from->move_delay_fixed;
+  ei_to->move_delay_random = ei_from->move_delay_random;
+
+  ei_to->move_pattern = ei_from->move_pattern;
+  ei_to->move_direction_initial = ei_from->move_direction_initial;
+  ei_to->move_stepsize = ei_from->move_stepsize;
+
+  ei_to->move_enter_element = ei_from->move_enter_element;
+  ei_to->move_leave_element = ei_from->move_leave_element;
+  ei_to->move_leave_type = ei_from->move_leave_type;
+
+  ei_to->slippery_type = ei_from->slippery_type;
+
+  ei_to->explosion_type = ei_from->explosion_type;
+  ei_to->explosion_delay = ei_from->explosion_delay;
+  ei_to->ignition_delay = ei_from->ignition_delay;
+
+  for (y = 0; y < 3; y++)
+    for (x = 0; x < 3; x++)
+      ei_to->content.e[x][y] = ei_from->content.e[x][y];
+#endif
+
+  /* ---------- reinitialize and copy change pages ---------- */
+
+  ei_to->num_change_pages = ei_from->num_change_pages;
+  ei_to->current_change_page = ei_from->current_change_page;
+
+  setElementChangePages(ei_to, ei_to->num_change_pages);
+
+  for (i = 0; i < ei_to->num_change_pages; i++)
+    ei_to->change_page[i] = ei_from->change_page[i];
+
+  /* ---------- copy group element info ---------- */
+  if (ei_from->group != NULL && ei_to->group != NULL)  /* group or internal */
+    *ei_to->group = *ei_from->group;
+
+  /* mark this custom element as modified */
+  ei_to->modified_settings = TRUE;
+}
+#endif
 
 void setElementChangePages(struct ElementInfo *ei, int change_pages)
 {
@@ -88,8 +1502,22 @@ void setElementChangePages(struct ElementInfo *ei, int change_pages)
 
 void setElementChangeInfoToDefaults(struct ElementChangeInfo *change)
 {
+#if 0
   int i, x, y;
+#endif
+
+#if 1
+  xx_change = *change;         /* copy change data into temporary buffer */
+  xx_num_contents = 1;
 
+  setConfigToDefaultsFromConfigList(chunk_config_CUSX_change);
+
+  *change = xx_change;
+
+  resetEventFlags(change);
+#endif
+
+#if 0
   change->can_change = FALSE;
 
   for (i = 0; i < NUM_CHANGE_EVENTS; i++)
@@ -103,7 +1531,7 @@ void setElementChangeInfoToDefaults(struct ElementChangeInfo *change)
 
   change->delay_fixed = 0;
   change->delay_random = 0;
-  change->delay_frames = 1;
+  change->delay_frames = FRAMES_PER_SECOND;
 
   change->trigger_element = EL_EMPTY_SPACE;
 
@@ -114,9 +1542,15 @@ void setElementChangeInfoToDefaults(struct ElementChangeInfo *change)
   change->random_percentage = 100;
   change->replace_when = CP_WHEN_EMPTY;
 
+  change->has_action = FALSE;
+  change->action_type = CA_NO_ACTION;
+  change->action_mode = CA_MODE_UNDEFINED;
+  change->action_arg = CA_ARG_UNDEFINED;
+
   for (x = 0; x < 3; x++)
     for (y = 0; y < 3; y++)
-      change->target_content[x][y] = EL_EMPTY_SPACE;
+      change->target_content.e[x][y] = EL_EMPTY_SPACE;
+#endif
 
   change->direct_action = 0;
   change->other_action = 0;
@@ -129,28 +1563,58 @@ void setElementChangeInfoToDefaults(struct ElementChangeInfo *change)
 static void setLevelInfoToDefaults(struct LevelInfo *level)
 {
   static boolean clipboard_elements_initialized = FALSE;
+#if 0
   int i, j, x, y;
+#else
+  int i, x, y;
+#endif
+
+#if 1
+  InitElementPropertiesStatic();
+#endif
+
+#if 1
+  li = *level;         /* copy level data into temporary buffer */
+
+  setConfigToDefaultsFromConfigList(chunk_config_INFO);
+  setConfigToDefaultsFromConfigList(chunk_config_ELEM);
+
+  *level = li;         /* copy temporary buffer back to level data */
+#endif
 
   setLevelInfoToDefaults_EM();
 
   level->native_em_level = &native_em_level;
 
+#if 0
   level->game_engine_type = GAME_ENGINE_TYPE_RND;
+#endif
 
   level->file_version = FILE_VERSION_ACTUAL;
   level->game_version = GAME_VERSION_ACTUAL;
 
+  level->creation_date = getCurrentDate();
+
+#if 1
+  level->encoding_16bit_field  = TRUE;
+  level->encoding_16bit_yamyam = TRUE;
+  level->encoding_16bit_amoeba = TRUE;
+#else
   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 */
+#endif
 
+#if 0
   level->fieldx = STD_LEV_FIELDX;
   level->fieldy = STD_LEV_FIELDY;
+#endif
 
   for (x = 0; x < MAX_LEV_FIELDX; x++)
     for (y = 0; y < MAX_LEV_FIELDY; y++)
       level->field[x][y] = EL_SAND;
 
+#if 0
   level->time = 100;
   level->gems_needed = 0;
 
@@ -158,52 +1622,82 @@ static void setLevelInfoToDefaults(struct LevelInfo *level)
 
   level->time_magic_wall = 10;
   level->time_wheel = 10;
+#endif
+#if 0
   level->time_light = 10;
   level->time_timegate = 10;
+#endif
 
+#if 0
   level->amoeba_content = EL_DIAMOND;
+#endif
+
+#if 0
+  level->game_of_life[0] = 2;
+  level->game_of_life[1] = 3;
+  level->game_of_life[2] = 3;
+  level->game_of_life[3] = 3;
+
+  level->biomaze[0] = 2;
+  level->biomaze[1] = 3;
+  level->biomaze[2] = 3;
+  level->biomaze[3] = 3;
+#endif
 
+#if 0
   level->double_speed = FALSE;
+#endif
+#if 0
   level->initial_gravity = FALSE;
   level->em_slippery_gems = FALSE;
   level->instant_relocation = FALSE;
   level->can_pass_to_walkable = FALSE;
   level->grow_into_diggable = TRUE;
+#endif
 
+#if 0
+  level->block_snap_field = TRUE;
+#endif
+
+#if 0
   level->block_last_field = FALSE;     /* EM does not block by default */
   level->sp_block_last_field = TRUE;   /* SP blocks the last field */
 
-#if 0  /* !!! THIS IS NOT A LEVEL SETTING => LOGIC MOVED TO "game.c" !!! */
-  level->block_delay = 8;              /* when blocking, block 8 frames */
-  level->sp_block_delay = 9;           /* SP indeed blocks 9 frames, not 8 */
-#endif
-
   level->can_move_into_acid_bits = ~0; /* everything can move into acid */
   level->dont_collide_with_bits = ~0;  /* always deadly when colliding */
 
   level->use_spring_bug = FALSE;
+  level->use_time_orb_bug = FALSE;
+
   level->use_step_counter = FALSE;
+#endif
 
   /* values for the new EMC elements */
+#if 0
   level->android_move_time = 10;
   level->android_clone_time = 10;
-  level->ball_random = FALSE;
-  level->ball_state_initial = FALSE;
   level->ball_time = 10;
   level->lenses_score = 10;
-  level->magnify_score = 10;
-  level->slurp_score = 10;
   level->lenses_time = 10;
+  level->magnify_score = 10;
   level->magnify_time = 10;
-  level->wind_direction_initial = MV_NO_MOVING;
-  for (i = 0; i < NUM_MAGIC_BALL_CONTENTS; i++)
+  level->slurp_score = 10;
+  level->wind_direction_initial = MV_NONE;
+  level->ball_random = FALSE;
+  level->ball_state_initial = FALSE;
+
+  for (i = 0; i < MAX_ELEMENT_CONTENTS; i++)
     for (x = 0; x < 3; x++)
       for (y = 0; y < 3; y++)
-       level->ball_content[i][x][y] = EL_EMPTY;
+       level->ball_content[i].e[x][y] = EL_EMPTY;
+
   for (i = 0; i < 16; i++)
     level->android_array[i] = FALSE;
+#endif
 
+#if 0
   level->use_custom_template = FALSE;
+#endif
 
   for (i = 0; i < MAX_LEVEL_NAME_LEN; i++)
     level->name[i] = '\0';
@@ -213,22 +1707,28 @@ static void setLevelInfoToDefaults(struct LevelInfo *level)
   strcpy(level->name, NAMELESS_LEVEL_NAME);
   strcpy(level->author, ANONYMOUS_NAME);
 
+#if 0
   for (i = 0; i < 4; i++)
   {
     level->envelope_text[i][0] = '\0';
     level->envelope_xsize[i] = MAX_ENVELOPE_XSIZE;
     level->envelope_ysize[i] = MAX_ENVELOPE_YSIZE;
   }
+#endif
 
+#if 0
   for (i = 0; i < LEVEL_SCORE_ELEMENTS; i++)
-    level->score[i] = 10;
+    level->score[i] = (i == SC_TIME_BONUS ? 1 : 10);
+#endif
 
+#if 0
   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->yamyam_content[i][x][y] =
+       level->yamyam_content[i].e[x][y] =
          (i < STD_ELEMENT_CONTENTS ? EL_ROCK : EL_EMPTY);
+#endif
 
   level->field[0][0] = EL_PLAYER_1;
   level->field[STD_LEV_FIELDX - 1][STD_LEV_FIELDY - 1] = EL_EXIT_CLOSED;
@@ -236,103 +1736,167 @@ static void setLevelInfoToDefaults(struct LevelInfo *level)
   for (i = 0; i < MAX_NUM_ELEMENTS; i++)
   {
     int element = i;
+    struct ElementInfo *ei = &element_info[element];
 
     /* never initialize clipboard elements after the very first time */
+    /* (to be able to use clipboard elements between several levels) */
     if (IS_CLIPBOARD_ELEMENT(element) && clipboard_elements_initialized)
       continue;
 
-    setElementChangePages(&element_info[element], 1);
-    setElementChangeInfoToDefaults(element_info[element].change);
+    if (IS_ENVELOPE(element))
+    {
+      int envelope_nr = element - EL_ENVELOPE_1;
+
+      setConfigToDefaultsFromConfigList(chunk_config_NOTE);
+
+      level->envelope[envelope_nr] = xx_envelope;
+    }
+
+#if 1
+    if (IS_CUSTOM_ELEMENT(element) ||
+       IS_GROUP_ELEMENT(element) ||
+       IS_INTERNAL_ELEMENT(element))
+    {
+      xx_ei = *ei;     /* copy element data into temporary buffer */
+
+      setConfigToDefaultsFromConfigList(chunk_config_CUSX_base);
+
+      *ei = xx_ei;
+    }
+#endif
+
+    setElementChangePages(ei, 1);
+    setElementChangeInfoToDefaults(ei->change);
 
     if (IS_CUSTOM_ELEMENT(element) ||
        IS_GROUP_ELEMENT(element) ||
        IS_INTERNAL_ELEMENT(element))
     {
+#if 1
+      setElementDescriptionToDefault(ei);
+#else
       for (j = 0; j < MAX_ELEMENT_NAME_LEN + 1; j++)
-       element_info[element].description[j] = '\0';
+       ei->description[j] = '\0';
 
-      if (element_info[element].custom_description != NULL)
-       strncpy(element_info[element].description,
-               element_info[element].custom_description,MAX_ELEMENT_NAME_LEN);
+      if (ei->custom_description != NULL)
+       strncpy(ei->description, ei->custom_description,MAX_ELEMENT_NAME_LEN);
       else
-       strcpy(element_info[element].description,
-              element_info[element].editor_description);
+       strcpy(ei->description, ei->editor_description);
+#endif
 
-      element_info[element].use_gfx_element = FALSE;
-      element_info[element].gfx_element = EL_EMPTY_SPACE;
+#if 0
+      ei->use_gfx_element = FALSE;
+      ei->gfx_element = EL_EMPTY_SPACE;
+#endif
 
-      element_info[element].modified_settings = FALSE;
+      ei->modified_settings = FALSE;
     }
 
     if (IS_CUSTOM_ELEMENT(element) ||
        IS_INTERNAL_ELEMENT(element))
     {
-      element_info[element].access_direction = MV_ALL_DIRECTIONS;
+#if 0
+      ei->access_direction = MV_ALL_DIRECTIONS;
 
-      element_info[element].collect_score = 10;                /* special default */
-      element_info[element].collect_count = 1;         /* special default */
+      ei->collect_score_initial = 10;  /* special default */
+      ei->collect_count_initial = 1;   /* special default */
 
-      element_info[element].push_delay_fixed = -1;     /* initialize later */
-      element_info[element].push_delay_random = -1;    /* initialize later */
-      element_info[element].drop_delay_fixed = 0;
-      element_info[element].drop_delay_random = 0;
-      element_info[element].move_delay_fixed = 0;
-      element_info[element].move_delay_random = 0;
+      ei->ce_value_fixed_initial = 0;
+      ei->ce_value_random_initial = 0;
+      ei->use_last_ce_value = FALSE;
+
+#endif
+#if 0
+      ei->push_delay_fixed = -1;       /* initialize later */
+      ei->push_delay_random = -1;      /* initialize later */
+#endif
+#if 0
+      ei->drop_delay_fixed = 0;
+      ei->drop_delay_random = 0;
+      ei->move_delay_fixed = 0;
+      ei->move_delay_random = 0;
 
-      element_info[element].move_pattern = MV_ALL_DIRECTIONS;
-      element_info[element].move_direction_initial = MV_START_AUTOMATIC;
-      element_info[element].move_stepsize = TILEX / 8;
+      ei->move_pattern = MV_ALL_DIRECTIONS;
+      ei->move_direction_initial = MV_START_AUTOMATIC;
+      ei->move_stepsize = TILEX / 8;
 
-      element_info[element].move_enter_element = EL_EMPTY_SPACE;
-      element_info[element].move_leave_element = EL_EMPTY_SPACE;
-      element_info[element].move_leave_type = LEAVE_TYPE_UNLIMITED;
+      ei->move_enter_element = EL_EMPTY_SPACE;
+      ei->move_leave_element = EL_EMPTY_SPACE;
+      ei->move_leave_type = LEAVE_TYPE_UNLIMITED;
 
-      element_info[element].slippery_type = SLIPPERY_ANY_RANDOM;
+      ei->slippery_type = SLIPPERY_ANY_RANDOM;
 
-      element_info[element].explosion_type = EXPLODES_3X3;
-      element_info[element].explosion_delay = 16;
-      element_info[element].ignition_delay = 8;
+      ei->explosion_type = EXPLODES_3X3;
+      ei->explosion_delay = 16;
+      ei->ignition_delay = 8;
 
       for (x = 0; x < 3; x++)
        for (y = 0; y < 3; y++)
-         element_info[element].content[x][y] = EL_EMPTY_SPACE;
+         ei->content.e[x][y] = EL_EMPTY_SPACE;
+#endif
 
-      element_info[element].access_type = 0;
-      element_info[element].access_layer = 0;
-      element_info[element].access_protected = 0;
-      element_info[element].walk_to_action = 0;
-      element_info[element].smash_targets = 0;
-      element_info[element].deadliness = 0;
+      /* internal values used in level editor */
 
-      element_info[element].can_explode_by_fire = FALSE;
-      element_info[element].can_explode_smashed = FALSE;
-      element_info[element].can_explode_impact = FALSE;
+      ei->access_type = 0;
+      ei->access_layer = 0;
+      ei->access_protected = 0;
+      ei->walk_to_action = 0;
+      ei->smash_targets = 0;
+      ei->deadliness = 0;
 
-      element_info[element].current_change_page = 0;
+      ei->can_explode_by_fire = FALSE;
+      ei->can_explode_smashed = FALSE;
+      ei->can_explode_impact = FALSE;
 
+      ei->current_change_page = 0;
+
+#if 0
+      /* !!! now done in InitElementPropertiesStatic() (see above) !!! */
+      /* !!! (else properties set there will be overwritten here)  !!! */
       /* start with no properties at all */
+#if 1
+      for (j = 0; j < NUM_EP_BITFIELDS; j++)
+       ei->properties[j] = EP_BITMASK_DEFAULT;
+#else
       for (j = 0; j < NUM_EP_BITFIELDS; j++)
        Properties[element][j] = EP_BITMASK_DEFAULT;
+#endif
+#endif
 
+#if 0
       /* now set default properties */
       SET_PROPERTY(element, EP_CAN_MOVE_INTO_ACID, TRUE);
+#endif
     }
 
     if (IS_GROUP_ELEMENT(element) ||
        IS_INTERNAL_ELEMENT(element))
     {
+      struct ElementGroupInfo *group;
+
       /* initialize memory for list of elements in group */
-      if (element_info[element].group == NULL)
-       element_info[element].group =
-         checked_malloc(sizeof(struct ElementGroupInfo));
+      if (ei->group == NULL)
+       ei->group = checked_malloc(sizeof(struct ElementGroupInfo));
+
+      group = ei->group;
+
+#if 1
+      xx_group = *group;       /* copy group data into temporary buffer */
+
+      setConfigToDefaultsFromConfigList(chunk_config_GRPX);
 
+      *group = xx_group;
+#endif
+
+#if 0
       for (j = 0; j < MAX_ELEMENTS_IN_GROUP; j++)
-       element_info[element].group->element[j] = EL_EMPTY_SPACE;
+       group->element[j] = EL_EMPTY_SPACE;
 
       /* default: only one element in group */
-      element_info[element].group->num_elements = 1;
+      group->num_elements = 1;
 
-      element_info[element].group->choice_mode = ANIM_RANDOM;
+      group->choice_mode = ANIM_RANDOM;
+#endif
     }
   }
 
@@ -348,7 +1912,7 @@ static void setLevelInfoToDefaults(struct LevelInfo *level)
     return;
 
   /* try to determine better author name than 'anonymous' */
-  if (strcmp(leveldir_current->author, ANONYMOUS_NAME) != 0)
+  if (!strEqual(leveldir_current->author, ANONYMOUS_NAME))
   {
     strncpy(level->author, leveldir_current->author, MAX_LEVEL_AUTHOR_LEN);
     level->author[MAX_LEVEL_AUTHOR_LEN] = '\0';
@@ -389,9 +1953,15 @@ static void setFileInfoToDefaults(struct LevelFileInfo *level_file_info)
 
 static void ActivateLevelTemplate()
 {
+#if 1
+  /* Currently there is no special action needed to activate the template
+     data, because 'element_info' property settings overwrite the original
+     level data, while all other variables do not change. */
+#else
   /* 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. */
+#endif
 }
 
 static char *getLevelFilenameFromBasename(char *basename)
@@ -550,7 +2120,7 @@ static int getFiletypeFromID(char *filetype_id)
   {
     char *id_lower = getStringToLower(filetype_id_list[i].id);
     
-    if (strcmp(filetype_id_lower, id_lower) == 0)
+    if (strEqual(filetype_id_lower, id_lower))
       filetype = filetype_id_list[i].filetype;
 
     free(id_lower);
@@ -564,48 +2134,6 @@ static int getFiletypeFromID(char *filetype_id)
   return filetype;
 }
 
-#if 0
-static void OLD_determineLevelFileInfo_Filename(struct LevelFileInfo *lfi)
-{
-  /* special case: level number is negative => check for level template file */
-  if (lfi->nr < 0)
-  {
-    setLevelFileInfo_SingleLevelFilename(lfi, LEVEL_FILE_TYPE_RND);
-
-    return;
-  }
-
-  if (leveldir_current->level_filename != NULL)
-  {
-    int filetype = getFiletypeFromID(leveldir_current->level_filetype);
-
-    /* check for file name/pattern specified in "levelinfo.conf" */
-    setLevelFileInfo_SingleLevelFilename(lfi, filetype);
-
-    if (fileExists(lfi->filename))
-      return;
-  }
-
-  /* check for native Rocks'n'Diamonds level file */
-  setLevelFileInfo_SingleLevelFilename(lfi, LEVEL_FILE_TYPE_RND);
-  if (fileExists(lfi->filename))
-    return;
-
-  /* check for classic Emerald Mine level file */
-  setLevelFileInfo_SingleLevelFilename(lfi, LEVEL_FILE_TYPE_EM);
-  if (fileExists(lfi->filename))
-    return;
-
-  /* check for various packed level file formats */
-  setLevelFileInfo_PackedLevelFilename(lfi, LEVEL_FILE_TYPE_UNKNOWN);
-  if (fileExists(lfi->filename))
-    return;
-
-  /* no known level file found -- try to use default values */
-  setLevelFileInfo_SingleLevelFilename(lfi, LEVEL_FILE_TYPE_UNKNOWN);
-}
-#endif
-
 static void determineLevelFileInfo_Filename(struct LevelFileInfo *lfi)
 {
   int nr = lfi->nr;
@@ -684,7 +2212,6 @@ static void determineLevelFileInfo_Filetype(struct LevelFileInfo *lfi)
     lfi->type = getFileTypeFromBasename(lfi->basename);
 }
 
-#if 1
 static void setLevelFileInfo(struct LevelFileInfo *level_file_info, int nr)
 {
   /* always start with reliable default values */
@@ -696,24 +2223,6 @@ static void setLevelFileInfo(struct LevelFileInfo *level_file_info, int nr)
   determineLevelFileInfo_Filetype(level_file_info);
 }
 
-#else
-
-static struct LevelFileInfo *getLevelFileInfo(int nr)
-{
-  static struct LevelFileInfo level_file_info;
-
-  /* always start with reliable default values */
-  setFileInfoToDefaults(&level_file_info);
-
-  level_file_info.nr = nr;     /* set requested level number */
-
-  determineLevelFileInfo_Filename(&level_file_info);
-  determineLevelFileInfo_Filetype(&level_file_info);
-
-  return &level_file_info;
-}
-#endif
-
 /* ------------------------------------------------------------------------- */
 /* functions for loading R'n'D level                                         */
 /* ------------------------------------------------------------------------- */
@@ -722,7 +2231,6 @@ int getMappedElement(int element)
 {
   /* remap some (historic, now obsolete) elements */
 
-#if 1
   switch (element)
   {
     case EL_PLAYER_OBSOLETE:
@@ -765,18 +2273,6 @@ int getMappedElement(int element)
       }
       break;
   }
-#else
-  if (element >= NUM_FILE_ELEMENTS)
-  {
-    Error(ERR_WARN, "invalid level element %d", element);
-
-    element = EL_UNKNOWN;
-  }
-  else if (element == EL_PLAYER_OBSOLETE)
-    element = EL_PLAYER_1;
-  else if (element == EL_KEY_OBSOLETE)
-    element = EL_KEY_1;
-#endif
 
   return element;
 }
@@ -815,8 +2311,19 @@ static int LoadLevel_VERS(FILE *file, int chunk_size, struct LevelInfo *level)
   return chunk_size;
 }
 
+static int LoadLevel_DATE(FILE *file, int chunk_size, struct LevelInfo *level)
+{
+  level->creation_date.year  = getFile16BitBE(file);
+  level->creation_date.month = getFile8Bit(file);
+  level->creation_date.day   = getFile8Bit(file);
+
+  return chunk_size;
+}
+
 static int LoadLevel_HEAD(FILE *file, int chunk_size, struct LevelInfo *level)
 {
+  int initial_player_stepsize;
+  int initial_player_gravity;
   int i, x, y;
 
   level->fieldx = getFile8Bit(file);
@@ -836,14 +2343,24 @@ static int LoadLevel_HEAD(FILE *file, int chunk_size, struct LevelInfo *level)
   for (i = 0; i < STD_ELEMENT_CONTENTS; i++)
     for (y = 0; y < 3; y++)
       for (x = 0; x < 3; x++)
-       level->yamyam_content[i][x][y] = getMappedElement(getFile8Bit(file));
+       level->yamyam_content[i].e[x][y] = getMappedElement(getFile8Bit(file));
 
   level->amoeba_speed          = getFile8Bit(file);
   level->time_magic_wall       = getFile8Bit(file);
   level->time_wheel            = getFile8Bit(file);
   level->amoeba_content                = getMappedElement(getFile8Bit(file));
-  level->double_speed          = (getFile8Bit(file) == 1 ? TRUE : FALSE);
-  level->initial_gravity       = (getFile8Bit(file) == 1 ? TRUE : FALSE);
+
+  initial_player_stepsize      = (getFile8Bit(file) == 1 ? STEPSIZE_FAST :
+                                  STEPSIZE_NORMAL);
+
+  for (i = 0; i < MAX_PLAYERS; i++)
+    level->initial_player_stepsize[0] = initial_player_stepsize;
+
+  initial_player_gravity       = (getFile8Bit(file) == 1 ? TRUE : FALSE);
+
+  for (i = 0; i < MAX_PLAYERS; i++)
+    level->initial_player_gravity[0] = initial_player_gravity;
+
   level->encoding_16bit_field  = (getFile8Bit(file) == 1 ? TRUE : FALSE);
   level->em_slippery_gems      = (getFile8Bit(file) == 1 ? TRUE : FALSE);
 
@@ -863,7 +2380,18 @@ static int LoadLevel_HEAD(FILE *file, int chunk_size, struct LevelInfo *level)
 
   level->game_engine_type      = getFile8Bit(file);
 
-  ReadUnusedBytesFromFile(file, LEVEL_HEADER_UNUSED);
+  ReadUnusedBytesFromFile(file, LEVEL_CHUNK_HEAD_UNUSED);
+
+  return chunk_size;
+}
+
+static int LoadLevel_NAME(FILE *file, int chunk_size, struct LevelInfo *level)
+{
+  int i;
+
+  for (i = 0; i < MAX_LEVEL_NAME_LEN; i++)
+    level->name[i] = getFile8Bit(file);
+  level->name[MAX_LEVEL_NAME_LEN] = 0;
 
   return chunk_size;
 }
@@ -874,7 +2402,7 @@ static int LoadLevel_AUTH(FILE *file, int chunk_size, struct LevelInfo *level)
 
   for (i = 0; i < MAX_LEVEL_AUTHOR_LEN; i++)
     level->author[i] = getFile8Bit(file);
-  level->author[MAX_LEVEL_NAME_LEN] = 0;
+  level->author[MAX_LEVEL_AUTHOR_LEN] = 0;
 
   return chunk_size;
 }
@@ -940,7 +2468,7 @@ static int LoadLevel_CONT(FILE *file, int chunk_size, struct LevelInfo *level)
   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] =
+       level->yamyam_content[i].e[x][y] =
          getMappedElement(level->encoding_16bit_field ?
                           getFile16BitBE(file) : getFile8Bit(file));
   return chunk_size;
@@ -976,7 +2504,7 @@ static int LoadLevel_CNT2(FILE *file, int chunk_size, struct LevelInfo *level)
     for (i = 0; i < num_contents; i++)
       for (y = 0; y < 3; y++)
        for (x = 0; x < 3; x++)
-         level->yamyam_content[i][x][y] = content_array[i][x][y];
+         level->yamyam_content[i].e[x][y] = content_array[i][x][y];
   }
   else if (element == EL_BD_AMOEBA)
   {
@@ -1006,8 +2534,8 @@ static int LoadLevel_CNT3(FILE *file, int chunk_size, struct LevelInfo *level)
 
   envelope_len = getFile16BitBE(file);
 
-  level->envelope_xsize[envelope_nr] = getFile8Bit(file);
-  level->envelope_ysize[envelope_nr] = getFile8Bit(file);
+  level->envelope[envelope_nr].xsize = getFile8Bit(file);
+  level->envelope[envelope_nr].ysize = getFile8Bit(file);
 
   ReadUnusedBytesFromFile(file, LEVEL_CHUNK_CNT3_UNUSED);
 
@@ -1019,7 +2547,7 @@ static int LoadLevel_CNT3(FILE *file, int chunk_size, struct LevelInfo *level)
   }
 
   for (i = 0; i < envelope_len; i++)
-    level->envelope_text[envelope_nr][i] = getFile8Bit(file);
+    level->envelope[envelope_nr].text[i] = getFile8Bit(file);
 
   return chunk_size;
 }
@@ -1038,13 +2566,31 @@ static int LoadLevel_CUS1(FILE *file, int chunk_size, struct LevelInfo *level)
 
   for (i = 0; i < num_changed_custom_elements; i++)
   {
-    int element = getFile16BitBE(file);
+    int element = getMappedElement(getFile16BitBE(file));
     int properties = getFile32BitBE(file);
 
+#if 1
+    if (IS_CUSTOM_ELEMENT(element))
+      element_info[element].properties[EP_BITFIELD_BASE_NR] = properties;
+    else
+      Error(ERR_WARN, "invalid custom element number %d", element);
+#else
     if (IS_CUSTOM_ELEMENT(element))
-      Properties[element][EP_BITFIELD_BASE] = properties;
+      Properties[element][EP_BITFIELD_BASE_NR] = properties;
     else
       Error(ERR_WARN, "invalid custom element number %d", element);
+#endif
+
+#if 1
+    /* older game versions that wrote level files with CUS1 chunks used
+       different default push delay values (not yet stored in level file) */
+    element_info[element].push_delay_fixed = 2;
+    element_info[element].push_delay_random = 8;
+#else
+    /* needed for older levels (see src/init.c for details) */
+    element_info[element].push_delay_fixed = -1;       /* initialize later */
+    element_info[element].push_delay_random = -1;      /* initialize later */
+#endif
   }
 
   return chunk_size;
@@ -1064,8 +2610,8 @@ static int LoadLevel_CUS2(FILE *file, int chunk_size, struct LevelInfo *level)
 
   for (i = 0; i < num_changed_custom_elements; i++)
   {
-    int element = getFile16BitBE(file);
-    int custom_target_element = getFile16BitBE(file);
+    int element = getMappedElement(getFile16BitBE(file));
+    int custom_target_element = getMappedElement(getFile16BitBE(file));
 
     if (IS_CUSTOM_ELEMENT(element))
       element_info[element].change->target_element = custom_target_element;
@@ -1090,8 +2636,9 @@ static int LoadLevel_CUS3(FILE *file, int chunk_size, struct LevelInfo *level)
 
   for (i = 0; i < num_changed_custom_elements; i++)
   {
-    int element = getFile16BitBE(file);
-    unsigned long event_bits;
+    int element = getMappedElement(getFile16BitBE(file));
+    struct ElementInfo *ei = &element_info[element];
+    unsigned int event_bits;
 
     if (!IS_CUSTOM_ELEMENT(element))
     {
@@ -1101,261 +2648,697 @@ static int LoadLevel_CUS3(FILE *file, int chunk_size, struct LevelInfo *level)
     }
 
     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;
+      ei->description[j] = getFile8Bit(file);
+    ei->description[MAX_ELEMENT_NAME_LEN] = 0;
 
-    Properties[element][EP_BITFIELD_BASE] = getFile32BitBE(file);
+#if 1
+    ei->properties[EP_BITFIELD_BASE_NR] = getFile32BitBE(file);
+#else
+    Properties[element][EP_BITFIELD_BASE_NR] = getFile32BitBE(file);
+#endif
 
     /* some free bytes for future properties and padding */
     ReadUnusedBytesFromFile(file, 7);
 
-    element_info[element].use_gfx_element = getFile8Bit(file);
-    element_info[element].gfx_element =
-      getMappedElement(getFile16BitBE(file));
+    ei->use_gfx_element = getFile8Bit(file);
+    ei->gfx_element = getMappedElement(getFile16BitBE(file));
+
+    ei->collect_score_initial = getFile8Bit(file);
+    ei->collect_count_initial = getFile8Bit(file);
+
+    ei->push_delay_fixed = getFile16BitBE(file);
+    ei->push_delay_random = getFile16BitBE(file);
+    ei->move_delay_fixed = getFile16BitBE(file);
+    ei->move_delay_random = getFile16BitBE(file);
+
+    ei->move_pattern = getFile16BitBE(file);
+    ei->move_direction_initial = getFile8Bit(file);
+    ei->move_stepsize = getFile8Bit(file);
+
+    for (y = 0; y < 3; y++)
+      for (x = 0; x < 3; x++)
+       ei->content.e[x][y] = getMappedElement(getFile16BitBE(file));
+
+    event_bits = getFile32BitBE(file);
+    for (j = 0; j < NUM_CHANGE_EVENTS; j++)
+      if (event_bits & (1 << j))
+       ei->change->has_event[j] = TRUE;
+
+    ei->change->target_element = getMappedElement(getFile16BitBE(file));
+
+    ei->change->delay_fixed = getFile16BitBE(file);
+    ei->change->delay_random = getFile16BitBE(file);
+    ei->change->delay_frames = getFile16BitBE(file);
+
+    ei->change->trigger_element = getMappedElement(getFile16BitBE(file));
+
+    ei->change->explode = getFile8Bit(file);
+    ei->change->use_target_content = getFile8Bit(file);
+    ei->change->only_if_complete = getFile8Bit(file);
+    ei->change->use_random_replace = getFile8Bit(file);
+
+    ei->change->random_percentage = getFile8Bit(file);
+    ei->change->replace_when = getFile8Bit(file);
+
+    for (y = 0; y < 3; y++)
+      for (x = 0; x < 3; x++)
+       ei->change->target_content.e[x][y] =
+         getMappedElement(getFile16BitBE(file));
+
+    ei->slippery_type = getFile8Bit(file);
+
+    /* some free bytes for future properties and padding */
+    ReadUnusedBytesFromFile(file, LEVEL_CPART_CUS3_UNUSED);
+
+    /* mark that this custom element has been modified */
+    ei->modified_settings = TRUE;
+  }
+
+  return chunk_size;
+}
+
+static int LoadLevel_CUS4(FILE *file, int chunk_size, struct LevelInfo *level)
+{
+  struct ElementInfo *ei;
+  int chunk_size_expected;
+  int element;
+  int i, j, x, y;
+
+  /* ---------- custom element base property values (96 bytes) ------------- */
+
+  element = getMappedElement(getFile16BitBE(file));
+
+  if (!IS_CUSTOM_ELEMENT(element))
+  {
+    Error(ERR_WARN, "invalid custom element number %d", element);
+
+    ReadUnusedBytesFromFile(file, chunk_size - 2);
+    return chunk_size;
+  }
+
+  ei = &element_info[element];
+
+  for (i = 0; i < MAX_ELEMENT_NAME_LEN; i++)
+    ei->description[i] = getFile8Bit(file);
+  ei->description[MAX_ELEMENT_NAME_LEN] = 0;
+
+#if 1
+  ei->properties[EP_BITFIELD_BASE_NR] = getFile32BitBE(file);
+#else
+  Properties[element][EP_BITFIELD_BASE_NR] = getFile32BitBE(file);
+#endif
+  ReadUnusedBytesFromFile(file, 4);    /* reserved for more base properties */
+
+  ei->num_change_pages = getFile8Bit(file);
+
+  chunk_size_expected = LEVEL_CHUNK_CUS4_SIZE(ei->num_change_pages);
+  if (chunk_size_expected != chunk_size)
+  {
+    ReadUnusedBytesFromFile(file, chunk_size - 43);
+    return chunk_size_expected;
+  }
+
+  ei->ce_value_fixed_initial = getFile16BitBE(file);
+  ei->ce_value_random_initial = getFile16BitBE(file);
+  ei->use_last_ce_value = getFile8Bit(file);
+
+  ei->use_gfx_element = getFile8Bit(file);
+  ei->gfx_element = getMappedElement(getFile16BitBE(file));
+
+  ei->collect_score_initial = getFile8Bit(file);
+  ei->collect_count_initial = getFile8Bit(file);
+
+  ei->drop_delay_fixed = getFile8Bit(file);
+  ei->push_delay_fixed = getFile8Bit(file);
+  ei->drop_delay_random = getFile8Bit(file);
+  ei->push_delay_random = getFile8Bit(file);
+  ei->move_delay_fixed = getFile16BitBE(file);
+  ei->move_delay_random = getFile16BitBE(file);
+
+  /* bits 0 - 15 of "move_pattern" ... */
+  ei->move_pattern = getFile16BitBE(file);
+  ei->move_direction_initial = getFile8Bit(file);
+  ei->move_stepsize = getFile8Bit(file);
+
+  ei->slippery_type = getFile8Bit(file);
+
+  for (y = 0; y < 3; y++)
+    for (x = 0; x < 3; x++)
+      ei->content.e[x][y] = getMappedElement(getFile16BitBE(file));
+
+  ei->move_enter_element = getMappedElement(getFile16BitBE(file));
+  ei->move_leave_element = getMappedElement(getFile16BitBE(file));
+  ei->move_leave_type = getFile8Bit(file);
+
+  /* ... bits 16 - 31 of "move_pattern" (not nice, but downward compatible) */
+  ei->move_pattern |= (getFile16BitBE(file) << 16);
+
+  ei->access_direction = getFile8Bit(file);
+
+  ei->explosion_delay = getFile8Bit(file);
+  ei->ignition_delay = getFile8Bit(file);
+  ei->explosion_type = getFile8Bit(file);
+
+  /* some free bytes for future custom property values and padding */
+  ReadUnusedBytesFromFile(file, 1);
+
+  /* ---------- change page property values (48 bytes) --------------------- */
+
+  setElementChangePages(ei, ei->num_change_pages);
+
+  for (i = 0; i < ei->num_change_pages; i++)
+  {
+    struct ElementChangeInfo *change = &ei->change_page[i];
+    unsigned int event_bits;
+
+    /* always start with reliable default values */
+    setElementChangeInfoToDefaults(change);
+
+    /* bits 0 - 31 of "has_event[]" ... */
+    event_bits = getFile32BitBE(file);
+    for (j = 0; j < MIN(NUM_CHANGE_EVENTS, 32); j++)
+      if (event_bits & (1 << j))
+       change->has_event[j] = TRUE;
+
+    change->target_element = getMappedElement(getFile16BitBE(file));
+
+    change->delay_fixed = getFile16BitBE(file);
+    change->delay_random = getFile16BitBE(file);
+    change->delay_frames = getFile16BitBE(file);
+
+    change->trigger_element = getMappedElement(getFile16BitBE(file));
+
+    change->explode = getFile8Bit(file);
+    change->use_target_content = getFile8Bit(file);
+    change->only_if_complete = getFile8Bit(file);
+    change->use_random_replace = getFile8Bit(file);
+
+    change->random_percentage = getFile8Bit(file);
+    change->replace_when = getFile8Bit(file);
+
+    for (y = 0; y < 3; y++)
+      for (x = 0; x < 3; x++)
+       change->target_content.e[x][y]= getMappedElement(getFile16BitBE(file));
+
+    change->can_change = getFile8Bit(file);
+
+    change->trigger_side = getFile8Bit(file);
+
+    change->trigger_player = getFile8Bit(file);
+    change->trigger_page = getFile8Bit(file);
+
+    change->trigger_page = (change->trigger_page == CH_PAGE_ANY_FILE ?
+                           CH_PAGE_ANY : (1 << change->trigger_page));
+
+    change->has_action = getFile8Bit(file);
+    change->action_type = getFile8Bit(file);
+    change->action_mode = getFile8Bit(file);
+    change->action_arg = getFile16BitBE(file);
+
+    /* ... bits 32 - 39 of "has_event[]" (not nice, but downward compatible) */
+    event_bits = getFile8Bit(file);
+    for (j = 32; j < NUM_CHANGE_EVENTS; j++)
+      if (event_bits & (1 << (j - 32)))
+       change->has_event[j] = TRUE;
+  }
+
+  /* mark this custom element as modified */
+  ei->modified_settings = TRUE;
+
+  return chunk_size;
+}
+
+static int LoadLevel_GRP1(FILE *file, int chunk_size, struct LevelInfo *level)
+{
+  struct ElementInfo *ei;
+  struct ElementGroupInfo *group;
+  int element;
+  int i;
+
+  element = getMappedElement(getFile16BitBE(file));
+
+  if (!IS_GROUP_ELEMENT(element))
+  {
+    Error(ERR_WARN, "invalid group element number %d", element);
+
+    ReadUnusedBytesFromFile(file, chunk_size - 2);
+    return chunk_size;
+  }
+
+  ei = &element_info[element];
+
+  for (i = 0; i < MAX_ELEMENT_NAME_LEN; i++)
+    ei->description[i] = getFile8Bit(file);
+  ei->description[MAX_ELEMENT_NAME_LEN] = 0;
+
+  group = element_info[element].group;
+
+  group->num_elements = getFile8Bit(file);
+
+  ei->use_gfx_element = getFile8Bit(file);
+  ei->gfx_element = getMappedElement(getFile16BitBE(file));
+
+  group->choice_mode = getFile8Bit(file);
+
+  /* some free bytes for future values and padding */
+  ReadUnusedBytesFromFile(file, 3);
+
+  for (i = 0; i < MAX_ELEMENTS_IN_GROUP; i++)
+    group->element[i] = getMappedElement(getFile16BitBE(file));
+
+  /* mark this group element as modified */
+  element_info[element].modified_settings = TRUE;
+
+  return chunk_size;
+}
+
+static int LoadLevel_MicroChunk(FILE *file, struct LevelFileConfigInfo *conf,
+                               int element, int real_element)
+{
+  int micro_chunk_size = 0;
+  int conf_type = getFile8Bit(file);
+  int byte_mask = conf_type & CONF_MASK_BYTES;
+  boolean element_found = FALSE;
+  int i;
+
+  micro_chunk_size += 1;
+
+  if (byte_mask == CONF_MASK_MULTI_BYTES)
+  {
+    int num_bytes = getFile16BitBE(file);
+    byte *buffer = checked_malloc(num_bytes);
 
-    element_info[element].collect_score = getFile8Bit(file);
-    element_info[element].collect_count = getFile8Bit(file);
+#if 0
+    printf("::: - found multi bytes\n");
+#endif
+
+    ReadBytesFromFile(file, buffer, num_bytes);
+
+    for (i = 0; conf[i].data_type != -1; i++)
+    {
+      if (conf[i].element == element &&
+         conf[i].conf_type == conf_type)
+      {
+       int data_type = conf[i].data_type;
+       int num_entities = num_bytes / CONF_ENTITY_NUM_BYTES(data_type);
+       int max_num_entities = conf[i].max_num_entities;
+
+       if (num_entities > max_num_entities)
+       {
+         Error(ERR_WARN,
+               "truncating number of entities for element %d from %d to %d",
+               element, num_entities, max_num_entities);
+
+         num_entities = max_num_entities;
+       }
+
+       *(int *)(conf[i].num_entities) = num_entities;
+
+       element_found = TRUE;
+
+       if (data_type == TYPE_STRING)
+       {
+         char *string = (char *)(conf[i].value);
+         int j;
+
+         for (j = 0; j < max_num_entities; j++)
+           string[j] = (j < num_entities ? buffer[j] : '\0');
+       }
+       else if (data_type == TYPE_ELEMENT_LIST)
+       {
+         int *element_array = (int *)(conf[i].value);
+         int j;
+
+         for (j = 0; j < num_entities; j++)
+           element_array[j] =
+             getMappedElement(CONF_ELEMENTS_ELEMENT(buffer, j));
+       }
+       else if (data_type == TYPE_CONTENT_LIST)
+       {
+         struct Content *content= (struct Content *)(conf[i].value);
+         int c, x, y;
+
+         for (c = 0; c < num_entities; c++)
+           for (y = 0; y < 3; y++)
+             for (x = 0; x < 3; x++)
+               content[c].e[x][y] =
+                 getMappedElement(CONF_CONTENTS_ELEMENT(buffer, c, x, y));
+       }
+       else
+         element_found = FALSE;
+
+       break;
+      }
+    }
+
+    checked_free(buffer);
+
+    micro_chunk_size += 2 + num_bytes;
+  }
+  else         /* constant size configuration data (1, 2 or 4 bytes) */
+  {
+    int value = (byte_mask == CONF_MASK_1_BYTE ? getFile8Bit   (file) :
+                byte_mask == CONF_MASK_2_BYTE ? getFile16BitBE(file) :
+                byte_mask == CONF_MASK_4_BYTE ? getFile32BitBE(file) : 0);
+
+#if 0
+    printf("::: - found single bytes\n");
+#endif
 
-    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);
+    for (i = 0; conf[i].data_type != -1; i++)
+    {
+      if (conf[i].element == element &&
+         conf[i].conf_type == conf_type)
+      {
+       int data_type = conf[i].data_type;
 
-    element_info[element].move_pattern = getFile16BitBE(file);
-    element_info[element].move_direction_initial = getFile8Bit(file);
-    element_info[element].move_stepsize = getFile8Bit(file);
+       if (data_type == TYPE_ELEMENT)
+         value = getMappedElement(value);
 
-    for (y = 0; y < 3; y++)
-      for (x = 0; x < 3; x++)
-       element_info[element].content[x][y] =
-         getMappedElement(getFile16BitBE(file));
+       if (data_type == TYPE_BOOLEAN)
+         *(boolean *)(conf[i].value) = value;
+       else
+         *(int *)    (conf[i].value) = value;
 
-    event_bits = getFile32BitBE(file);
-    for (j = 0; j < NUM_CHANGE_EVENTS; j++)
-      if (event_bits & (1 << j))
-       element_info[element].change->has_event[j] = TRUE;
+       element_found = TRUE;
 
-    element_info[element].change->target_element =
-      getMappedElement(getFile16BitBE(file));
+       break;
+      }
+    }
 
-    element_info[element].change->delay_fixed = getFile16BitBE(file);
-    element_info[element].change->delay_random = getFile16BitBE(file);
-    element_info[element].change->delay_frames = getFile16BitBE(file);
+    micro_chunk_size += CONF_VALUE_NUM_BYTES(byte_mask);
+  }
 
-    element_info[element].change->trigger_element =
-      getMappedElement(getFile16BitBE(file));
+  if (!element_found)
+  {
+    char *error_conf_chunk_bytes =
+      (byte_mask == CONF_MASK_1_BYTE ? "CONF_VALUE_8_BIT" :
+       byte_mask == CONF_MASK_2_BYTE ? "CONF_VALUE_16_BIT" :
+       byte_mask == CONF_MASK_4_BYTE ? "CONF_VALUE_32_BIT" :"CONF_VALUE_BYTES");
+    int error_conf_chunk_token = conf_type & CONF_MASK_TOKEN;
+    int error_element = real_element;
 
-    element_info[element].change->explode = getFile8Bit(file);
-    element_info[element].change->use_target_content = getFile8Bit(file);
-    element_info[element].change->only_if_complete = getFile8Bit(file);
-    element_info[element].change->use_random_replace = getFile8Bit(file);
+    Error(ERR_WARN, "cannot load micro chunk '%s(%d)' value for element %d ['%s']",
+         error_conf_chunk_bytes, error_conf_chunk_token,
+         error_element, EL_NAME(error_element));
+  }
 
-    element_info[element].change->random_percentage = getFile8Bit(file);
-    element_info[element].change->replace_when = getFile8Bit(file);
+  return micro_chunk_size;
+}
 
-    for (y = 0; y < 3; y++)
-      for (x = 0; x < 3; x++)
-       element_info[element].change->target_content[x][y] =
-         getMappedElement(getFile16BitBE(file));
+static int LoadLevel_INFO(FILE *file, int chunk_size, struct LevelInfo *level)
+{
+  int real_chunk_size = 0;
 
-    element_info[element].slippery_type = getFile8Bit(file);
+  li = *level;         /* copy level data into temporary buffer */
 
-    /* some free bytes for future properties and padding */
-    ReadUnusedBytesFromFile(file, LEVEL_CPART_CUS3_UNUSED);
+  while (!feof(file))
+  {
+    real_chunk_size += LoadLevel_MicroChunk(file, chunk_config_INFO, -1, -1);
 
-    /* mark that this custom element has been modified */
-    element_info[element].modified_settings = TRUE;
+    if (real_chunk_size >= chunk_size)
+      break;
   }
 
-  return chunk_size;
+  *level = li;         /* copy temporary buffer back to level data */
+
+  return real_chunk_size;
 }
 
-static int LoadLevel_CUS4(FILE *file, int chunk_size, struct LevelInfo *level)
+static int LoadLevel_CONF(FILE *file, int chunk_size, struct LevelInfo *level)
 {
-  struct ElementInfo *ei;
-  int chunk_size_expected;
-  int element;
-  int i, j, x, y;
+  int real_chunk_size = 0;
 
-  element = getFile16BitBE(file);
+  li = *level;         /* copy level data into temporary buffer */
 
-  if (!IS_CUSTOM_ELEMENT(element))
+  while (!feof(file))
   {
-    Error(ERR_WARN, "invalid custom element number %d", element);
+    int element = getMappedElement(getFile16BitBE(file));
 
-    ReadUnusedBytesFromFile(file, chunk_size - 2);
-    return chunk_size;
+    real_chunk_size += 2;
+    real_chunk_size += LoadLevel_MicroChunk(file, chunk_config_CONF,
+                                           element, element);
+    if (real_chunk_size >= chunk_size)
+      break;
   }
 
-  ei = &element_info[element];
-
-  for (i = 0; i < MAX_ELEMENT_NAME_LEN; i++)
-    ei->description[i] = getFile8Bit(file);
-  ei->description[MAX_ELEMENT_NAME_LEN] = 0;
+  *level = li;         /* copy temporary buffer back to level data */
 
-  Properties[element][EP_BITFIELD_BASE] = getFile32BitBE(file);
-  ReadUnusedBytesFromFile(file, 4);    /* reserved for more base properties */
+  return real_chunk_size;
+}
 
-  ei->num_change_pages = getFile8Bit(file);
+static int LoadLevel_ELEM(FILE *file, int chunk_size, struct LevelInfo *level)
+{
+  int real_chunk_size = 0;
 
-  /* some free bytes for future base property values and padding */
-  ReadUnusedBytesFromFile(file, 5);
+#if 1
+  li = *level;         /* copy level data into temporary buffer */
+#endif
 
-  chunk_size_expected = LEVEL_CHUNK_CUS4_SIZE(ei->num_change_pages);
-  if (chunk_size_expected != chunk_size)
+  while (!feof(file))
   {
-    ReadUnusedBytesFromFile(file, chunk_size - 48);
-    return chunk_size_expected;
-  }
+    int element = getMappedElement(getFile16BitBE(file));
+#if 1
+    real_chunk_size += 2;
+    real_chunk_size += LoadLevel_MicroChunk(file, chunk_config_ELEM,
+                                           element, element);
+#else
+    int conf_type = getFile8Bit(file);
+    int byte_mask = conf_type & CONF_MASK_BYTES;
+    boolean element_found = FALSE;
+    int i;
 
-  /* read custom property values */
+    real_chunk_size += 3;
 
-  ei->use_gfx_element = getFile8Bit(file);
-  ei->gfx_element = getMappedElement(getFile16BitBE(file));
+#if 0
+    li = *level;       /* copy level data into temporary buffer */
+#endif
 
-  ei->collect_score = getFile8Bit(file);
-  ei->collect_count = getFile8Bit(file);
+    if (byte_mask == CONF_MASK_MULTI_BYTES)
+    {
+      int num_bytes = getFile16BitBE(file);
+      byte *buffer = checked_malloc(num_bytes);
 
-  ei->drop_delay_fixed = getFile8Bit(file);
-  ei->push_delay_fixed = getFile8Bit(file);
-  ei->drop_delay_random = getFile8Bit(file);
-  ei->push_delay_random = getFile8Bit(file);
-  ei->move_delay_fixed = getFile16BitBE(file);
-  ei->move_delay_random = getFile16BitBE(file);
+      ReadBytesFromFile(file, buffer, num_bytes);
 
-  /* bits 0 - 15 of "move_pattern" ... */
-  ei->move_pattern = getFile16BitBE(file);
-  ei->move_direction_initial = getFile8Bit(file);
-  ei->move_stepsize = getFile8Bit(file);
+      for (i = 0; chunk_config_ELEM[i].data_type != -1; i++)
+      {
+       if (chunk_config_ELEM[i].element == element &&
+           chunk_config_ELEM[i].conf_type == conf_type)
+       {
+         int data_type = chunk_config_ELEM[i].data_type;
+         int num_entities = num_bytes / CONF_ENTITY_NUM_BYTES(data_type);
+         int max_num_entities = chunk_config_ELEM[i].max_num_entities;
+
+         if (num_entities > max_num_entities)
+         {
+           Error(ERR_WARN,
+                 "truncating number of entities for element %d from %d to %d",
+                 element, num_entities, max_num_entities);
+
+           num_entities = max_num_entities;
+         }
+
+         *(int *)(chunk_config_ELEM[i].num_entities) = num_entities;
+
+         element_found = TRUE;
+
+         if (data_type == TYPE_ELEMENT_LIST)
+         {
+           int *element_array = (int *)(chunk_config_ELEM[i].value);
+           int j;
+
+           for (j = 0; j < num_entities; j++)
+             element_array[j] =
+               getMappedElement(CONF_ELEMENTS_ELEMENT(buffer, j));
+         }
+         else if (data_type == TYPE_CONTENT_LIST)
+         {
+           struct Content *content= (struct Content *)(chunk_config_ELEM[i].value);
+           int c, x, y;
+
+           for (c = 0; c < num_entities; c++)
+             for (y = 0; y < 3; y++)
+               for (x = 0; x < 3; x++)
+                 content[c].e[x][y] =
+                   getMappedElement(CONF_CONTENTS_ELEMENT(buffer, c, x, y));
+         }
+         else
+           element_found = FALSE;
+
+         break;
+       }
+      }
 
-  ei->slippery_type = getFile8Bit(file);
+      checked_free(buffer);
 
-  for (y = 0; y < 3; y++)
-    for (x = 0; x < 3; x++)
-      ei->content[x][y] = getMappedElement(getFile16BitBE(file));
+      real_chunk_size += 2 + num_bytes;
+    }
+    else       /* constant size configuration data (1, 2 or 4 bytes) */
+    {
+      int value = (byte_mask == CONF_MASK_1_BYTE ? getFile8Bit   (file) :
+                  byte_mask == CONF_MASK_2_BYTE ? getFile16BitBE(file) :
+                  byte_mask == CONF_MASK_4_BYTE ? getFile32BitBE(file) : 0);
 
-  ei->move_enter_element = getMappedElement(getFile16BitBE(file));
-  ei->move_leave_element = getMappedElement(getFile16BitBE(file));
-  ei->move_leave_type = getFile8Bit(file);
+      for (i = 0; chunk_config_ELEM[i].data_type != -1; i++)
+      {
+       if (chunk_config_ELEM[i].element == element &&
+           chunk_config_ELEM[i].conf_type == conf_type)
+       {
+         int data_type = chunk_config_ELEM[i].data_type;
 
-  /* ... bits 16 - 31 of "move_pattern" (not nice, but downward compatible) */
-  ei->move_pattern |= (getFile16BitBE(file) << 16);
+         if (data_type == TYPE_BOOLEAN)
+           *(boolean *)(chunk_config_ELEM[i].value) = value;
+         else
+           *(int *)    (chunk_config_ELEM[i].value) = value;
 
-  ei->access_direction = getFile8Bit(file);
+         element_found = TRUE;
 
-  ei->explosion_delay = getFile8Bit(file);
-  ei->ignition_delay = getFile8Bit(file);
-  ei->explosion_type = getFile8Bit(file);
+         break;
+       }
+      }
 
-  /* some free bytes for future custom property values and padding */
-  ReadUnusedBytesFromFile(file, 1);
+      real_chunk_size += CONF_VALUE_NUM_BYTES(byte_mask);
+    }
 
-  /* read change property values */
+    if (!element_found)
+      Error(ERR_WARN, "cannot load CONF value for element %d", element);
+#endif
 
-  setElementChangePages(ei, ei->num_change_pages);
+#if 0
+    *level = li;       /* copy temporary buffer back to level data */
+#endif
 
-  for (i = 0; i < ei->num_change_pages; i++)
-  {
-    struct ElementChangeInfo *change = &ei->change_page[i];
-    unsigned long event_bits;
+    if (real_chunk_size >= chunk_size)
+      break;
+  }
 
-    /* always start with reliable default values */
-    setElementChangeInfoToDefaults(change);
+#if 1
+  *level = li;         /* copy temporary buffer back to level data */
+#endif
 
-    event_bits = getFile32BitBE(file);
-    for (j = 0; j < NUM_CHANGE_EVENTS; j++)
-      if (event_bits & (1 << j))
-       change->has_event[j] = TRUE;
+  return real_chunk_size;
+}
 
-    change->target_element = getMappedElement(getFile16BitBE(file));
+static int LoadLevel_NOTE(FILE *file, int chunk_size, struct LevelInfo *level)
+{
+  int element = getMappedElement(getFile16BitBE(file));
+  int envelope_nr = element - EL_ENVELOPE_1;
+  int real_chunk_size = 2;
 
-    change->delay_fixed = getFile16BitBE(file);
-    change->delay_random = getFile16BitBE(file);
-    change->delay_frames = getFile16BitBE(file);
+  while (!feof(file))
+  {
+    real_chunk_size += LoadLevel_MicroChunk(file, chunk_config_NOTE,
+                                           -1, element);
 
-    change->trigger_element = getMappedElement(getFile16BitBE(file));
+    if (real_chunk_size >= chunk_size)
+      break;
+  }
 
-    change->explode = getFile8Bit(file);
-    change->use_target_content = getFile8Bit(file);
-    change->only_if_complete = getFile8Bit(file);
-    change->use_random_replace = getFile8Bit(file);
+  level->envelope[envelope_nr] = xx_envelope;
 
-    change->random_percentage = getFile8Bit(file);
-    change->replace_when = getFile8Bit(file);
+  return real_chunk_size;
+}
 
-    for (y = 0; y < 3; y++)
-      for (x = 0; x < 3; x++)
-       change->target_content[x][y] = getMappedElement(getFile16BitBE(file));
+static int LoadLevel_CUSX(FILE *file, int chunk_size, struct LevelInfo *level)
+{
+  int element = getMappedElement(getFile16BitBE(file));
+  int real_chunk_size = 2;
+  struct ElementInfo *ei = &element_info[element];
+  int i;
 
-    change->can_change = getFile8Bit(file);
+#if 0
+  printf("::: CUSX: loading element '%s' ...\n", EL_NAME(element));
+#endif
 
-    change->trigger_side = getFile8Bit(file);
+  xx_ei = *ei;         /* copy element data into temporary buffer */
 
-#if 1
-    change->trigger_player = getFile8Bit(file);
-    change->trigger_page = getFile8Bit(file);
+  xx_ei.num_change_pages = -1;
 
-    change->trigger_page = (change->trigger_page == CH_PAGE_ANY_FILE ?
-                           CH_PAGE_ANY : (1 << change->trigger_page));
+  while (!feof(file))
+  {
+    real_chunk_size += LoadLevel_MicroChunk(file, chunk_config_CUSX_base,
+                                           -1, element);
 
-    /* some free bytes for future change property values and padding */
-    ReadUnusedBytesFromFile(file, 6);
+#if 0
+    printf("::: - real_chunk_size now %d\n", real_chunk_size);
+#endif
 
-#else
+    if (xx_ei.num_change_pages != -1)
+      break;
 
-    /* some free bytes for future change property values and padding */
-    ReadUnusedBytesFromFile(file, 8);
-#endif
+    if (real_chunk_size >= chunk_size)
+      break;
   }
 
-  /* mark this custom element as modified */
-  ei->modified_settings = TRUE;
+  *ei = xx_ei;
 
-  return chunk_size;
-}
+  if (ei->num_change_pages == -1)
+  {
+    Error(ERR_WARN, "LoadLevel_CUSX(): missing 'num_change_pages' for '%s'",
+         EL_NAME(element));
 
-static int LoadLevel_GRP1(FILE *file, int chunk_size, struct LevelInfo *level)
-{
-  struct ElementInfo *ei;
-  struct ElementGroupInfo *group;
-  int element;
-  int i;
+    ei->num_change_pages = 1;
 
-  element = getFile16BitBE(file);
+    setElementChangePages(ei, 1);
+    setElementChangeInfoToDefaults(ei->change);
 
-  if (!IS_GROUP_ELEMENT(element))
+    return real_chunk_size;
+  }
+
+  /* initialize number of change pages stored for this custom element */
+  setElementChangePages(ei, ei->num_change_pages);
+  for (i = 0; i < ei->num_change_pages; i++)
+    setElementChangeInfoToDefaults(&ei->change_page[i]);
+
+  /* start with reading properties for the first change page */
+  xx_current_change_page = 0;
+
+  while (!feof(file))
   {
-    Error(ERR_WARN, "invalid group element number %d", element);
+    struct ElementChangeInfo *change = &ei->change_page[xx_current_change_page];
 
-    ReadUnusedBytesFromFile(file, chunk_size - 2);
-    return chunk_size;
-  }
+    xx_change = *change;       /* copy change data into temporary buffer */
 
-  ei = &element_info[element];
+    resetEventBits();          /* reset bits; change page might have changed */
 
-  for (i = 0; i < MAX_ELEMENT_NAME_LEN; i++)
-    ei->description[i] = getFile8Bit(file);
-  ei->description[MAX_ELEMENT_NAME_LEN] = 0;
+    real_chunk_size += LoadLevel_MicroChunk(file, chunk_config_CUSX_change,
+                                           -1, element);
 
-  group = element_info[element].group;
+    *change = xx_change;
 
-  group->num_elements = getFile8Bit(file);
+    setEventFlagsFromEventBits(change);
 
-  ei->use_gfx_element = getFile8Bit(file);
-  ei->gfx_element = getMappedElement(getFile16BitBE(file));
+    if (real_chunk_size >= chunk_size)
+      break;
+  }
 
-  group->choice_mode = getFile8Bit(file);
+  return real_chunk_size;
+}
 
-  /* some free bytes for future values and padding */
-  ReadUnusedBytesFromFile(file, 3);
+static int LoadLevel_GRPX(FILE *file, int chunk_size, struct LevelInfo *level)
+{
+  int element = getMappedElement(getFile16BitBE(file));
+  int real_chunk_size = 2;
+  struct ElementInfo *ei = &element_info[element];
+  struct ElementGroupInfo *group = ei->group;
 
-  for (i = 0; i < MAX_ELEMENTS_IN_GROUP; i++)
-    group->element[i] = getMappedElement(getFile16BitBE(file));
+  xx_ei = *ei;         /* copy element data into temporary buffer */
+  xx_group = *group;   /* copy group data into temporary buffer */
 
-  /* mark this group element as modified */
-  element_info[element].modified_settings = TRUE;
+  while (!feof(file))
+  {
+    real_chunk_size += LoadLevel_MicroChunk(file, chunk_config_GRPX,
+                                           -1, element);
 
-  return chunk_size;
+    if (real_chunk_size >= chunk_size)
+      break;
+  }
+
+  *ei = xx_ei;
+  *group = xx_group;
+
+  return real_chunk_size;
 }
 
 static void LoadLevelFromFileInfo_RND(struct LevelInfo *level,
@@ -1378,12 +3361,12 @@ static void LoadLevelFromFileInfo_RND(struct LevelInfo *level,
   }
 
   getFileChunkBE(file, chunk_name, NULL);
-  if (strcmp(chunk_name, "RND1") == 0)
+  if (strEqual(chunk_name, "RND1"))
   {
     getFile32BitBE(file);              /* not used */
 
     getFileChunkBE(file, chunk_name, NULL);
-    if (strcmp(chunk_name, "CAVE") != 0)
+    if (!strEqual(chunk_name, "CAVE"))
     {
       level->no_valid_file = TRUE;
 
@@ -1424,7 +3407,7 @@ static void LoadLevelFromFileInfo_RND(struct LevelInfo *level,
   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_HEAD(file, LEVEL_CHUNK_HEAD_SIZE,         level);
     LoadLevel_BODY(file, level->fieldx * level->fieldy, level);
   }
   else
@@ -1437,9 +3420,12 @@ static void LoadLevelFromFileInfo_RND(struct LevelInfo *level,
     }
     chunk_info[] =
     {
-      { "VERS", FILE_VERS_CHUNK_SIZE,  LoadLevel_VERS },
-      { "HEAD", LEVEL_HEADER_SIZE,     LoadLevel_HEAD },
-      { "AUTH", MAX_LEVEL_AUTHOR_LEN,  LoadLevel_AUTH },
+      { "VERS", LEVEL_CHUNK_VERS_SIZE, LoadLevel_VERS },
+      { "DATE", LEVEL_CHUNK_DATE_SIZE, LoadLevel_DATE },
+      { "HEAD", LEVEL_CHUNK_HEAD_SIZE, LoadLevel_HEAD },
+      { "NAME", LEVEL_CHUNK_NAME_SIZE, LoadLevel_NAME },
+      { "AUTH", LEVEL_CHUNK_AUTH_SIZE, LoadLevel_AUTH },
+      { "INFO", -1,                    LoadLevel_INFO },
       { "BODY", -1,                    LoadLevel_BODY },
       { "CONT", -1,                    LoadLevel_CONT },
       { "CNT2", LEVEL_CHUNK_CNT2_SIZE, LoadLevel_CNT2 },
@@ -1449,6 +3435,12 @@ static void LoadLevelFromFileInfo_RND(struct LevelInfo *level,
       { "CUS3", -1,                    LoadLevel_CUS3 },
       { "CUS4", -1,                    LoadLevel_CUS4 },
       { "GRP1", -1,                    LoadLevel_GRP1 },
+      { "CONF", -1,                    LoadLevel_CONF },
+      { "ELEM", -1,                    LoadLevel_ELEM },
+      { "NOTE", -1,                    LoadLevel_NOTE },
+      { "CUSX", -1,                    LoadLevel_CUSX },
+      { "GRPX", -1,                    LoadLevel_GRPX },
+
       {  NULL,  0,                     NULL }
     };
 
@@ -1457,7 +3449,7 @@ static void LoadLevelFromFileInfo_RND(struct LevelInfo *level,
       int i = 0;
 
       while (chunk_info[i].name != NULL &&
-            strcmp(chunk_name, chunk_info[i].name) != 0)
+            !strEqual(chunk_name, chunk_info[i].name))
        i++;
 
       if (chunk_info[i].name == NULL)
@@ -1891,7 +3883,7 @@ static void OLD_LoadLevelFromFileInfo_EM(struct LevelInfo *level,
   for (i = 0; i < level->num_yamyam_contents; i++)
     for (y = 0; y < 3; y++)
       for (x = 0; x < 3; x++)
-       level->yamyam_content[i][x][y] =
+       level->yamyam_content[i].e[x][y] =
          map_em_element_yam(header[i * 9 + y * 3 + x]);
 
   level->amoeba_speed          = (header[52] * 256 + header[53]) % 256;
@@ -1918,7 +3910,7 @@ static void OLD_LoadLevelFromFileInfo_EM(struct LevelInfo *level,
   level->field[x][y] = EL_PLAYER_2;
 }
 
-#else
+#endif
 
 void CopyNativeLevel_RND_to_EM(struct LevelInfo *level)
 {
@@ -1935,10 +3927,17 @@ void CopyNativeLevel_RND_to_EM(struct LevelInfo *level)
   };
   struct LevelInfo_EM *level_em = level->native_em_level;
   struct LEVEL *lev = level_em->lev;
-  struct PLAYER *ply1 = level_em->ply1;
-  struct PLAYER *ply2 = level_em->ply2;
+  struct PLAYER **ply = level_em->ply;
   int i, j, x, y;
 
+#if 0
+  printf("::: A\n");
+  for (i = 0; i < MAX_ELEMENT_CONTENTS; i++)
+    for (j = 0; j < 8; j++)
+      printf("::: ball %d, %d: %d\n", i, j,
+            level->ball_content[i].e[ball_xy[j][0]][ball_xy[j][1]]);
+#endif
+
   lev->width  = MIN(level->fieldx, EM_MAX_CAVE_WIDTH);
   lev->height = MIN(level->fieldy, EM_MAX_CAVE_HEIGHT);
 
@@ -1960,7 +3959,7 @@ void CopyNativeLevel_RND_to_EM(struct LevelInfo *level)
     for (y = 0; y < 3; y++)
       for (x = 0; x < 3; x++)
        lev->eater_array[i][y * 3 + x] =
-         map_element_RND_to_EM(level->yamyam_content[i][x][y]);
+         map_element_RND_to_EM(level->yamyam_content[i].e[x][y]);
 
   lev->amoeba_time             = level->amoeba_speed;
   lev->wonderwall_time_initial = level->time_magic_wall;
@@ -1971,6 +3970,7 @@ void CopyNativeLevel_RND_to_EM(struct LevelInfo *level)
   lev->ball_random             = level->ball_random;
   lev->ball_state_initial      = level->ball_state_initial;
   lev->ball_time               = level->ball_time;
+  lev->num_ball_arrays         = level->num_ball_contents;
 
   lev->lenses_score            = level->lenses_score;
   lev->magnify_score           = level->magnify_score;
@@ -1978,22 +3978,76 @@ void CopyNativeLevel_RND_to_EM(struct LevelInfo *level)
 
   lev->lenses_time             = level->lenses_time;
   lev->magnify_time            = level->magnify_time;
-  lev->wind_direction_initial  = level->wind_direction_initial;
 
-  for (i = 0; i < NUM_MAGIC_BALL_CONTENTS; i++)
+  lev->wind_direction_initial =
+    map_direction_RND_to_EM(level->wind_direction_initial);
+  lev->wind_cnt_initial = (level->wind_direction_initial != MV_NONE ?
+                          lev->wind_time : 0);
+
+  for (i = 0; i < MAX_ELEMENT_CONTENTS; i++)
     for (j = 0; j < 8; j++)
       lev->ball_array[i][j] =
        map_element_RND_to_EM(level->
-                             ball_content[i][ball_xy[j][0]][ball_xy[j][1]]);
+                             ball_content[i].e[ball_xy[j][0]][ball_xy[j][1]]);
+
+#if 0
+  for (i = 0; i < MAX_ELEMENT_CONTENTS; i++)
+    for (j = 0; j < 8; j++)
+      printf("::: ball %d, %d: %d\n", i, j,
+            level->ball_content[i].e[ball_xy[j][0]][ball_xy[j][1]]);
+#endif
 
+  map_android_clone_elements_RND_to_EM(level);
+
+#if 0
   for (i = 0; i < 16; i++)
     lev->android_array[i] = FALSE;     /* !!! YET TO COME !!! */
+#endif
 
   /* first fill the complete playfield with the default border element */
   for (y = 0; y < EM_MAX_CAVE_HEIGHT; y++)
     for (x = 0; x < EM_MAX_CAVE_WIDTH; x++)
       level_em->cave[x][y] = ZBORDER;
 
+#if 1
+
+#if 0
+#if 1
+  LoadLevel_InitPlayfield();
+#else
+  lev_fieldx = lev->width;     /* !!! also in LoadLevel_InitPlayfield() !!! */
+  lev_fieldy = lev->height;    /* !!! also in LoadLevel_InitPlayfield() !!! */
+  SetBorderElement();          /* !!! also in LoadLevel_InitPlayfield() !!! */
+#endif
+#endif
+
+#if 0
+  printf("::: BorderElement == %d\n", BorderElement);
+#endif
+
+  if (BorderElement == EL_STEELWALL)
+  {
+    for (y = 0; y < lev->height + 2; y++)
+      for (x = 0; x < lev->width + 2; x++)
+       level_em->cave[x + 1][y + 1] = map_element_RND_to_EM(EL_STEELWALL);
+  }
+
+  /* then copy the real level contents from level file into the playfield */
+  for (y = 0; y < lev->height; y++) for (x = 0; x < lev->width; x++)
+  {
+    int new_element = map_element_RND_to_EM(level->field[x][y]);
+    int offset = (BorderElement == EL_STEELWALL ? 1 : 0);
+    int xx = x + 1 + offset;
+    int yy = y + 1 + offset;
+
+    if (level->field[x][y] == EL_AMOEBA_DEAD)
+      new_element = map_element_RND_to_EM(EL_AMOEBA_WET);
+
+    level_em->cave[xx][yy] = new_element;
+  }
+
+#else
+
   /* then copy the real level contents from level file into the playfield */
   for (y = 0; y < lev->height; y++) for (x = 0; x < lev->width; x++)
   {
@@ -2005,15 +4059,56 @@ void CopyNativeLevel_RND_to_EM(struct LevelInfo *level)
     level_em->cave[x + 1][y + 1] = new_element;
   }
 
+#endif
+
+#if 1
+
+  for (i = 0; i < MAX_PLAYERS; i++)
+  {
+    ply[i]->x_initial = 0;
+    ply[i]->y_initial = 0;
+  }
+
+#else
+
   ply1->x_initial = 0;
   ply1->y_initial = 0;
 
   ply2->x_initial = 0;
   ply2->y_initial = 0;
 
+#endif
+
   /* initialize player positions and delete players from the playfield */
   for (y = 0; y < lev->height; y++) for (x = 0; x < lev->width; x++)
   {
+
+#if 1
+    if (ELEM_IS_PLAYER(level->field[x][y]))
+    {
+      int player_nr = GET_PLAYER_NR(level->field[x][y]);
+      int offset = (BorderElement == EL_STEELWALL ? 1 : 0);
+      int xx = x + 1 + offset;
+      int yy = y + 1 + offset;
+
+      ply[player_nr]->x_initial = xx;
+      ply[player_nr]->y_initial = yy;
+
+      level_em->cave[xx][yy] = map_element_RND_to_EM(EL_EMPTY);
+    }
+
+#else
+
+#if 1
+    /* !!! CURRENTLY ONLY SUPPORT FOR ONE PLAYER !!! */
+    if (ELEM_IS_PLAYER(level->field[x][y]))
+    {
+      ply1->x_initial = x + 1;
+      ply1->y_initial = y + 1;
+      level_em->cave[x + 1][y + 1] = map_element_RND_to_EM(EL_EMPTY);
+    }
+#else
+    /* !!! ADD SUPPORT FOR MORE THAN ONE PLAYER !!! */
     if (level->field[x][y] == EL_PLAYER_1)
     {
       ply1->x_initial = x + 1;
@@ -2026,6 +4121,18 @@ void CopyNativeLevel_RND_to_EM(struct LevelInfo *level)
       ply2->y_initial = y + 1;
       level_em->cave[x + 1][y + 1] = map_element_RND_to_EM(EL_EMPTY);
     }
+#endif
+
+#endif
+
+  }
+
+  if (BorderElement == EL_STEELWALL)
+  {
+#if 1
+    lev->width  += 2;
+    lev->height += 2;
+#endif
   }
 }
 
@@ -2044,8 +4151,7 @@ void CopyNativeLevel_EM_to_RND(struct LevelInfo *level)
   };
   struct LevelInfo_EM *level_em = level->native_em_level;
   struct LEVEL *lev = level_em->lev;
-  struct PLAYER *ply1 = level_em->ply1;
-  struct PLAYER *ply2 = level_em->ply2;
+  struct PLAYER **ply = level_em->ply;
   int i, j, x, y;
 
   level->fieldx = MIN(lev->width,  MAX_LEV_FIELDX);
@@ -2072,7 +4178,7 @@ void CopyNativeLevel_EM_to_RND(struct LevelInfo *level)
   for (i = 0; i < level->num_yamyam_contents; i++)
     for (y = 0; y < 3; y++)
       for (x = 0; x < 3; x++)
-       level->yamyam_content[i][x][y] =
+       level->yamyam_content[i].e[x][y] =
          map_element_EM_to_RND(lev->eater_array[i][y * 3 + x]);
 
   level->amoeba_speed          = lev->amoeba_time;
@@ -2084,6 +4190,7 @@ void CopyNativeLevel_EM_to_RND(struct LevelInfo *level)
   level->ball_random           = lev->ball_random;
   level->ball_state_initial    = lev->ball_state_initial;
   level->ball_time             = lev->ball_time;
+  level->num_ball_contents     = lev->num_ball_arrays;
 
   level->lenses_score          = lev->lenses_score;
   level->magnify_score         = lev->magnify_score;
@@ -2091,15 +4198,37 @@ void CopyNativeLevel_EM_to_RND(struct LevelInfo *level)
 
   level->lenses_time           = lev->lenses_time;
   level->magnify_time          = lev->magnify_time;
-  level->wind_direction_initial        = lev->wind_direction_initial;
 
-  for (i = 0; i < NUM_MAGIC_BALL_CONTENTS; i++)
+  level->wind_direction_initial =
+    map_direction_EM_to_RND(lev->wind_direction_initial);
+
+#if 0
+  printf("::: foo\n");
+  for (i = 0; i < MAX_ELEMENT_CONTENTS; i++)
+    for (j = 0; j < 8; j++)
+      printf("::: ball %d, %d: %d\n", i, j,
+            level->ball_content[i].e[ball_xy[j][0]][ball_xy[j][1]]);
+#endif
+
+  for (i = 0; i < MAX_ELEMENT_CONTENTS; i++)
     for (j = 0; j < 8; j++)
-      level->ball_content[i][ball_xy[j][0]][ball_xy[j][1]] =
+      level->ball_content[i].e[ball_xy[j][0]][ball_xy[j][1]] =
        map_element_EM_to_RND(lev->ball_array[i][j]);
 
+#if 0
+  printf("::: bar\n");
+  for (i = 0; i < MAX_ELEMENT_CONTENTS; i++)
+    for (j = 0; j < 8; j++)
+      printf("::: ball %d, %d: %d\n", i, j,
+            level->ball_content[i].e[ball_xy[j][0]][ball_xy[j][1]]);
+#endif
+
+  map_android_clone_elements_EM_to_RND(level);
+
+#if 0
   for (i = 0; i < 16; i++)
     level->android_array[i] = FALSE;   /* !!! YET TO COME !!! */
+#endif
 
   /* convert the playfield (some elements need special treatment) */
   for (y = 0; y < level->fieldy; y++) for (x = 0; x < level->fieldx; x++)
@@ -2112,13 +4241,50 @@ void CopyNativeLevel_EM_to_RND(struct LevelInfo *level)
     level->field[x][y] = new_element;
   }
 
+#if 0
+  printf("::: bar 0\n");
+  for (i = 0; i < MAX_ELEMENT_CONTENTS; i++)
+    for (j = 0; j < 8; j++)
+      printf("::: ball %d, %d: %d\n", i, j,
+            level->ball_content[i].e[ball_xy[j][0]][ball_xy[j][1]]);
+#endif
+
+#if 1
+
+  for (i = 0; i < MAX_PLAYERS; i++)
+  {
+    /* in case of all players set to the same field, use the first player */
+    int nr = MAX_PLAYERS - i - 1;
+    int jx = ply[nr]->x_initial - 1;
+    int jy = ply[nr]->y_initial - 1;
+
+#if 0
+    printf("::: player %d: %d, %d\n", nr, jx, jy);
+#endif
+
+    if (jx != -1 && jy != -1)
+      level->field[jx][jy] = EL_PLAYER_1 + nr;
+  }
+
+#else
+
   /* in case of both players set to the same field, use the first player */
   level->field[ply2->x_initial - 1][ply2->y_initial - 1] = EL_PLAYER_2;
   level->field[ply1->x_initial - 1][ply1->y_initial - 1] = EL_PLAYER_1;
 
+#endif
+
 #if 0
   printf("::: native Emerald Mine file version: %d\n", level_em->file_version);
 #endif
+
+#if 0
+  printf("::: bar 2\n");
+  for (i = 0; i < MAX_ELEMENT_CONTENTS; i++)
+    for (j = 0; j < 8; j++)
+      printf("::: ball %d, %d: %d\n", i, j,
+            level->ball_content[i].e[ball_xy[j][0]][ball_xy[j][1]]);
+#endif
 }
 
 static void LoadLevelFromFileInfo_EM(struct LevelInfo *level,
@@ -2128,8 +4294,6 @@ static void LoadLevelFromFileInfo_EM(struct LevelInfo *level,
     level->no_valid_file = TRUE;
 }
 
-#endif
-
 void CopyNativeLevel_RND_to_Native(struct LevelInfo *level)
 {
   if (level->game_engine_type == GAME_ENGINE_TYPE_EM)
@@ -2138,6 +4302,30 @@ void CopyNativeLevel_RND_to_Native(struct LevelInfo *level)
 
 void CopyNativeLevel_Native_to_RND(struct LevelInfo *level)
 {
+
+#if 0
+  {
+    static int ball_xy[8][2] =
+      {
+       { 0, 0 },
+       { 1, 0 },
+       { 2, 0 },
+       { 0, 1 },
+       { 2, 1 },
+       { 0, 2 },
+       { 1, 2 },
+       { 2, 2 },
+      };
+    int i, j;
+
+    printf("::: A6\n");
+    for (i = 0; i < MAX_ELEMENT_CONTENTS; i++)
+      for (j = 0; j < 8; j++)
+       printf("::: ball %d, %d: %d\n", i, j,
+              level->ball_content[i].e[ball_xy[j][0]][ball_xy[j][1]]);
+  }
+#endif
+
   if (level->game_engine_type == GAME_ENGINE_TYPE_EM)
     CopyNativeLevel_EM_to_RND(level);
 }
@@ -2156,6 +4344,7 @@ void CopyNativeLevel_Native_to_RND(struct LevelInfo *level)
 static void LoadLevelFromFileStream_SP(FILE *file, struct LevelInfo *level,
                                       int nr)
 {
+  int initial_player_gravity;
   int num_special_ports;
   int i, x, y;
 
@@ -2189,7 +4378,10 @@ static void LoadLevelFromFileStream_SP(FILE *file, struct LevelInfo *level,
   ReadUnusedBytesFromFile(file, 4);    /* (not used by Supaplex engine) */
 
   /* initial gravity: 1 == "on", anything else (0) == "off" */
-  level->initial_gravity = (fgetc(file) == 1 ? TRUE : FALSE);
+  initial_player_gravity = (fgetc(file) == 1 ? TRUE : FALSE);
+
+  for (i = 0; i < MAX_PLAYERS; i++)
+    level->initial_player_gravity[i] = initial_player_gravity;
 
   ReadUnusedBytesFromFile(file, 1);    /* (not used by Supaplex engine) */
 
@@ -2294,14 +4486,18 @@ static void LoadLevelFromFileStream_SP(FILE *file, struct LevelInfo *level,
   level->time_wheel = 0;
   level->amoeba_content = EL_EMPTY;
 
+#if 1
+  /* original Supaplex does not use score values -- use default values */
+#else
   for (i = 0; i < LEVEL_SCORE_ELEMENTS; i++)
     level->score[i] = 0;               /* !!! CORRECT THIS !!! */
+#endif
 
   /* there are no yamyams in supaplex levels */
   for (i = 0; i < level->num_yamyam_contents; i++)
     for (y = 0; y < 3; y++)
       for (x = 0; x < 3; x++)
-       level->yamyam_content[i][x][y] = EL_EMPTY;
+       level->yamyam_content[i].e[x][y] = EL_EMPTY;
 }
 
 static void LoadLevelFromFileInfo_SP(struct LevelInfo *level,
@@ -2398,7 +4594,7 @@ static void LoadLevelFromFileInfo_SP(struct LevelInfo *level,
 
     if (reading_multipart_level &&
        (!is_multipart_level ||
-        strcmp(level->name, multipart_level.name) != 0))
+        !strEqual(level->name, multipart_level.name)))
     {
       /* we are already reading parts of a multi-part level, but this level is
         either not a multi-part level, or a part of a different multi-part
@@ -2520,10 +4716,15 @@ void LoadLevelFromFileInfo(struct LevelInfo *level,
   if (level->game_engine_type == GAME_ENGINE_TYPE_UNKNOWN)
     level->game_engine_type = GAME_ENGINE_TYPE_RND;
 
+#if 1
+  if (level_file_info->type != LEVEL_FILE_TYPE_RND)
+    CopyNativeLevel_Native_to_RND(level);
+#else
   if (level_file_info->type == LEVEL_FILE_TYPE_RND)
     CopyNativeLevel_RND_to_Native(level);
   else
     CopyNativeLevel_Native_to_RND(level);
+#endif
 }
 
 void LoadLevelFromFilename(struct LevelInfo *level, char *filename)
@@ -2542,160 +4743,134 @@ void LoadLevelFromFilename(struct LevelInfo *level, char *filename)
 
 static void LoadLevel_InitVersion(struct LevelInfo *level, char *filename)
 {
+  int i;
+
   if (leveldir_current == NULL)                /* only when dumping level */
     return;
 
-#if 0
-  printf("::: sort_priority: %d\n", leveldir_current->sort_priority);
-#endif
-
-  /* determine correct game engine version of current level */
+  /* all engine modifications also valid for levels which use latest engine */
 #if 1
-  if (!leveldir_current->latest_engine)
-#else
-  if (IS_LEVELCLASS_CONTRIB(leveldir_current) ||
-      IS_LEVELCLASS_PRIVATE(leveldir_current) ||
-      IS_LEVELCLASS_UNDEFINED(leveldir_current))
-#endif
+  if (level->game_version < VERSION_IDENT(3,2,0,5))
   {
-#if 0
-    printf("\n::: This level is private or contributed: '%s'\n", filename);
+    /* time bonus score was given for 10 s instead of 1 s before 3.2.0-5 */
+    level->score[SC_TIME_BONUS] /= 10;
+  }
 #endif
 
 #if 0
-    printf("\n::: Use the stored game engine version for this level\n");
+  leveldir_current->latest_engine = TRUE;      /* !!! TEST ONLY !!! */
 #endif
 
-    /* For all levels which are not forced to use the latest game engine
-       version (normally user contributed, private and undefined levels),
-       use the version of the game engine the levels were created for.
+  if (leveldir_current->latest_engine)
+  {
+    /* ---------- use latest game engine ----------------------------------- */
 
-       Since 2.0.1, the game engine version is now directly stored
-       in the level file (chunk "VERS"), so there is no need anymore
-       to set the game version from the file version (except for old,
-       pre-2.0 levels, where the game version is still taken from the
-       file format version used to store the level -- see above). */
+    /* For all levels which are forced to use the latest game engine version
+       (normally all but user contributed, private and undefined levels), set
+       the game engine version to the actual version; this allows for actual
+       corrections in the game engine to take effect for existing, converted
+       levels (from "classic" or other existing games) to make the emulation
+       of the corresponding game more accurate, while (hopefully) not breaking
+       existing levels created from other players. */
 
-#if 1
-    /* player was faster than enemies in 1.0.0 and before */
-    if (level->file_version == FILE_VERSION_1_0)
-      level->double_speed = TRUE;
-#else
-    /* do some special adjustments to support older level versions */
-    if (level->file_version == FILE_VERSION_1_0)
-    {
-      Error(ERR_WARN, "level file '%s' has version number 1.0", filename);
-      Error(ERR_WARN, "using high speed movement for player");
+    level->game_version = GAME_VERSION_ACTUAL;
 
-      /* player was faster than monsters in (pre-)1.0 levels */
-      level->double_speed = TRUE;
-    }
-#endif
+    /* Set special EM style gems behaviour: EM style gems slip down from
+       normal, steel and growing wall. As this is a more fundamental change,
+       it seems better to set the default behaviour to "off" (as it is more
+       natural) and make it configurable in the level editor (as a property
+       of gem style elements). Already existing converted levels (neither
+       private nor contributed levels) are changed to the new behaviour. */
 
-    /* default behaviour for EM style gems was "slippery" only in 2.0.1 */
-    if (level->game_version == VERSION_IDENT(2,0,1,0))
+    if (level->file_version < FILE_VERSION_2_0)
       level->em_slippery_gems = TRUE;
 
-    /* springs could be pushed over pits before (pre-release version) 2.2.0 */
-    if (level->game_version < VERSION_IDENT(2,2,0,0))
-      level->use_spring_bug = TRUE;
+    return;
+  }
 
-    /* only few elements were able to actively move into acid before 3.1.0 */
-    /* trigger settings did not exist before 3.1.0; set to default "any" */
-    if (level->game_version < VERSION_IDENT(3,1,0,0))
-    {
-      int i, j;
+  /* ---------- use game engine the level was created with ----------------- */
 
-      /* correct "can move into acid" settings (all zero in old levels) */
+  /* For all levels which are not forced to use the latest game engine
+     version (normally user contributed, private and undefined levels),
+     use the version of the game engine the levels were created for.
 
-      level->can_move_into_acid_bits = 0; /* nothing can move into acid */
-      level->dont_collide_with_bits = 0; /* nothing is deadly when colliding */
+     Since 2.0.1, the game engine version is now directly stored
+     in the level file (chunk "VERS"), so there is no need anymore
+     to set the game version from the file version (except for old,
+     pre-2.0 levels, where the game version is still taken from the
+     file format version used to store the level -- see above). */
 
-      setMoveIntoAcidProperty(level, EL_ROBOT,     TRUE);
-      setMoveIntoAcidProperty(level, EL_SATELLITE, TRUE);
-      setMoveIntoAcidProperty(level, EL_PENGUIN,   TRUE);
-      setMoveIntoAcidProperty(level, EL_BALLOON,   TRUE);
+  /* player was faster than enemies in 1.0.0 and before */
+  if (level->file_version == FILE_VERSION_1_0)
+    for (i = 0; i < MAX_PLAYERS; i++)
+      level->initial_player_stepsize[i] = STEPSIZE_FAST;
 
-      for (i = 0; i < NUM_CUSTOM_ELEMENTS; i++)
-       SET_PROPERTY(EL_CUSTOM_START + i, EP_CAN_MOVE_INTO_ACID, TRUE);
+  /* default behaviour for EM style gems was "slippery" only in 2.0.1 */
+  if (level->game_version == VERSION_IDENT(2,0,1,0))
+    level->em_slippery_gems = TRUE;
 
-      /* correct trigger settings (stored as zero == "none" in old levels) */
+  /* springs could be pushed over pits before (pre-release version) 2.2.0 */
+  if (level->game_version < VERSION_IDENT(2,2,0,0))
+    level->use_spring_bug = TRUE;
 
-      for (i = 0; i < NUM_CUSTOM_ELEMENTS; i++)
-      {
-       int element = EL_CUSTOM_START + i;
-       struct ElementInfo *ei = &element_info[element];
+  if (level->game_version < VERSION_IDENT(3,2,0,5))
+  {
+    /* time orb caused limited time in endless time levels before 3.2.0-5 */
+    level->use_time_orb_bug = TRUE;
 
-       for (j = 0; j < ei->num_change_pages; j++)
-       {
-         struct ElementChangeInfo *change = &ei->change_page[j];
+    /* default behaviour for snapping was "no snap delay" before 3.2.0-5 */
+    level->block_snap_field = FALSE;
 
-         change->trigger_player = CH_PLAYER_ANY;
-         change->trigger_page = CH_PAGE_ANY;
-       }
-      }
-    }
+    /* extra time score was same value as time left score before 3.2.0-5 */
+    level->extra_time_score = level->score[SC_TIME_BONUS];
 
-#if 0  /* !!! MOVED TO "game.c", BECAUSE CAN CHANGE INSIDE LEVEL EDITOR !!! */
-#if 1  /* USE_NEW_BLOCK_STYLE */
-    /* blocking the last field when moving was corrected in version 3.1.1 */
-    if (level->game_version < VERSION_IDENT(3,1,1,0))
-    {
 #if 0
-      printf("::: %d\n", level->block_last_field);
-#endif
-
-      /* even "not blocking" was blocking the last field for one frame */
-      level->block_delay    = (level->block_last_field    ? 7 : 1);
-      level->sp_block_delay = (level->sp_block_last_field ? 7 : 1);
-
-      level->block_last_field = TRUE;
-      level->sp_block_last_field = TRUE;
-    }
-#endif
+    /* time bonus score was given for 10 s instead of 1 s before 3.2.0-5 */
+    level->score[SC_TIME_BONUS] /= 10;
 #endif
+  }
 
+  if (level->game_version < VERSION_IDENT(3,2,0,7))
+  {
+    /* default behaviour for snapping was "not continuous" before 3.2.0-7 */
+    level->continuous_snapping = FALSE;
   }
-  else         /* always use the latest game engine version */
+
+  /* only few elements were able to actively move into acid before 3.1.0 */
+  /* trigger settings did not exist before 3.1.0; set to default "any" */
+  if (level->game_version < VERSION_IDENT(3,1,0,0))
   {
-#if 0
-    printf("\n::: ALWAYS USE LATEST ENGINE FOR THIS LEVEL: [%d] '%s'\n",
-          leveldir_current->sort_priority, filename);
-#endif
+    int i, j;
 
-#if 0
-    printf("\n::: Use latest game engine version for this level.\n");
-#endif
+    /* correct "can move into acid" settings (all zero in old levels) */
 
-    /* For all levels which are forced to use the latest game engine version
-       (normally all but user contributed, private and undefined levels), set
-       the game engine version to the actual version; this allows for actual
-       corrections in the game engine to take effect for existing, converted
-       levels (from "classic" or other existing games) to make the emulation
-       of the corresponding game more accurate, while (hopefully) not breaking
-       existing levels created from other players. */
+    level->can_move_into_acid_bits = 0; /* nothing can move into acid */
+    level->dont_collide_with_bits = 0; /* nothing is deadly when colliding */
 
-#if 0
-    printf("::: changing engine from %d to %d\n",
-          level->game_version, GAME_VERSION_ACTUAL);
-#endif
+    setMoveIntoAcidProperty(level, EL_ROBOT,     TRUE);
+    setMoveIntoAcidProperty(level, EL_SATELLITE, TRUE);
+    setMoveIntoAcidProperty(level, EL_PENGUIN,   TRUE);
+    setMoveIntoAcidProperty(level, EL_BALLOON,   TRUE);
 
-    level->game_version = GAME_VERSION_ACTUAL;
+    for (i = 0; i < NUM_CUSTOM_ELEMENTS; i++)
+      SET_PROPERTY(EL_CUSTOM_START + i, EP_CAN_MOVE_INTO_ACID, TRUE);
 
-    /* Set special EM style gems behaviour: EM style gems slip down from
-       normal, steel and growing wall. As this is a more fundamental change,
-       it seems better to set the default behaviour to "off" (as it is more
-       natural) and make it configurable in the level editor (as a property
-       of gem style elements). Already existing converted levels (neither
-       private nor contributed levels) are changed to the new behaviour. */
+    /* correct trigger settings (stored as zero == "none" in old levels) */
 
-    if (level->file_version < FILE_VERSION_2_0)
-      level->em_slippery_gems = TRUE;
-  }
+    for (i = 0; i < NUM_CUSTOM_ELEMENTS; i++)
+    {
+      int element = EL_CUSTOM_START + i;
+      struct ElementInfo *ei = &element_info[element];
 
-#if 0
-  printf("::: => %d\n", level->game_version);
-#endif
+      for (j = 0; j < ei->num_change_pages; j++)
+      {
+       struct ElementChangeInfo *change = &ei->change_page[j];
+
+       change->trigger_player = CH_PLAYER_ANY;
+       change->trigger_page = CH_PAGE_ANY;
+      }
+    }
+  }
 }
 
 static void LoadLevel_InitElements(struct LevelInfo *level, char *filename)
@@ -2703,7 +4878,8 @@ static void LoadLevel_InitElements(struct LevelInfo *level, char *filename)
   int i, j, x, y;
 
   /* map custom element change events that have changed in newer versions
-     (these following values were accidentally changed in version 3.0.1) */
+     (these following values were accidentally changed in version 3.0.1)
+     (this seems to be needed only for 'ab_levelset3' and 'ab_levelset4') */
   if (level->game_version <= VERSION_IDENT(3,0,0,0))
   {
     for (i = 0; i < NUM_CUSTOM_ELEMENTS; i++)
@@ -2711,7 +4887,8 @@ static void LoadLevel_InitElements(struct LevelInfo *level, char *filename)
       int element = EL_CUSTOM_START + i;
 
       /* order of checking and copying events to be mapped is important */
-      for (j = CE_BY_OTHER_ACTION; j >= CE_BY_PLAYER_OBSOLETE; j--)
+      /* (do not change the start and end value -- they are constant) */
+      for (j = CE_BY_OTHER_ACTION; j >= CE_VALUE_GETS_ZERO; j--)
       {
        if (HAS_CHANGE_EVENT(element, j - 2))
        {
@@ -2721,6 +4898,7 @@ static void LoadLevel_InitElements(struct LevelInfo *level, char *filename)
       }
 
       /* order of checking and copying events to be mapped is important */
+      /* (do not change the start and end value -- they are constant) */
       for (j = CE_PLAYER_COLLECTS_X; j >= CE_HITTING_SOMETHING; j--)
       {
        if (HAS_CHANGE_EVENT(element, j - 1))
@@ -2732,21 +4910,6 @@ static void LoadLevel_InitElements(struct LevelInfo *level, char *filename)
     }
   }
 
-  /* some custom element change events get mapped since version 3.0.3 */
-  for (i = 0; i < NUM_CUSTOM_ELEMENTS; i++)
-  {
-    int element = EL_CUSTOM_START + i;
-
-    if (HAS_CHANGE_EVENT(element, CE_BY_PLAYER_OBSOLETE) ||
-       HAS_CHANGE_EVENT(element, CE_BY_COLLISION_OBSOLETE))
-    {
-      SET_CHANGE_EVENT(element, CE_BY_PLAYER_OBSOLETE, FALSE);
-      SET_CHANGE_EVENT(element, CE_BY_COLLISION_OBSOLETE, FALSE);
-
-      SET_CHANGE_EVENT(element, CE_BY_DIRECT_ACTION, TRUE);
-    }
-  }
-
   /* initialize "can_change" field for old levels with only one change page */
   if (level->game_version <= VERSION_IDENT(3,0,2,0))
   {
@@ -2760,22 +4923,50 @@ static void LoadLevel_InitElements(struct LevelInfo *level, char *filename)
   }
 
   /* correct custom element values (for old levels without these options) */
-  for (i = 0; i < NUM_CUSTOM_ELEMENTS; i++)
+  if (level->game_version < VERSION_IDENT(3,1,1,0))
   {
-    int element = EL_CUSTOM_START + i;
-    struct ElementInfo *ei = &element_info[element];
+    for (i = 0; i < NUM_CUSTOM_ELEMENTS; i++)
+    {
+      int element = EL_CUSTOM_START + i;
+      struct ElementInfo *ei = &element_info[element];
 
-    if (ei->access_direction == MV_NO_MOVING)
-      ei->access_direction = MV_ALL_DIRECTIONS;
+      if (ei->access_direction == MV_NO_DIRECTION)
+       ei->access_direction = MV_ALL_DIRECTIONS;
+
+#if 0
+      for (j = 0; j < ei->num_change_pages; j++)
+      {
+       struct ElementChangeInfo *change = &ei->change_page[j];
+
+       if (change->trigger_side == CH_SIDE_NONE)
+         change->trigger_side = CH_SIDE_ANY;
+      }
+#endif
+    }
+  }
 
-    for (j = 0; j < ei->num_change_pages; j++)
+#if 1
+  /* correct custom element values (fix invalid values for all versions) */
+  if (1)
+  {
+    for (i = 0; i < NUM_CUSTOM_ELEMENTS; i++)
     {
-      struct ElementChangeInfo *change = &ei->change_page[j];
+      int element = EL_CUSTOM_START + i;
+      struct ElementInfo *ei = &element_info[element];
+
+      for (j = 0; j < ei->num_change_pages; j++)
+      {
+       struct ElementChangeInfo *change = &ei->change_page[j];
+
+       if (change->trigger_player == CH_PLAYER_NONE)
+         change->trigger_player = CH_PLAYER_ANY;
 
-      if (change->trigger_side == CH_SIDE_NONE)
-       change->trigger_side = CH_SIDE_ANY;
+       if (change->trigger_side == CH_SIDE_NONE)
+         change->trigger_side = CH_SIDE_ANY;
+      }
     }
   }
+#endif
 
   /* initialize "can_explode" field for old levels which did not store this */
   /* !!! CHECK THIS -- "<= 3,1,0,0" IS PROBABLY WRONG !!! */
@@ -2810,43 +5001,19 @@ static void LoadLevel_InitElements(struct LevelInfo *level, char *filename)
     }
   }
 
-#if 0
-  /* set default push delay values (corrected since version 3.0.7-1) */
-  if (level->game_version < VERSION_IDENT(3,0,7,1))
-  {
-    game.default_push_delay_fixed = 2;
-    game.default_push_delay_random = 8;
-  }
-  else
-  {
-    game.default_push_delay_fixed = 8;
-    game.default_push_delay_random = 8;
-  }
-
-  /* set uninitialized push delay values of custom elements in older levels */
-  for (i = 0; i < NUM_CUSTOM_ELEMENTS; i++)
-  {
-    int element = EL_CUSTOM_START + i;
-
-    if (element_info[element].push_delay_fixed == -1)
-      element_info[element].push_delay_fixed = game.default_push_delay_fixed;
-    if (element_info[element].push_delay_random == -1)
-      element_info[element].push_delay_random = game.default_push_delay_random;
-  }
-#endif
-
   /* map elements that have changed in newer versions */
   level->amoeba_content = getMappedElementByVersion(level->amoeba_content,
                                                    level->game_version);
   for (i = 0; i < MAX_ELEMENT_CONTENTS; i++)
     for (x = 0; x < 3; x++)
       for (y = 0; y < 3; y++)
-       level->yamyam_content[i][x][y] =
-         getMappedElementByVersion(level->yamyam_content[i][x][y],
+       level->yamyam_content[i].e[x][y] =
+         getMappedElementByVersion(level->yamyam_content[i].e[x][y],
                                    level->game_version);
 
   /* initialize element properties for level editor etc. */
   InitElementPropertiesEngine(level->game_version);
+  InitElementPropertiesAfterLoading(level->game_version);
 }
 
 static void LoadLevel_InitPlayfield(struct LevelInfo *level, char *filename)
@@ -2855,37 +5022,9 @@ static void LoadLevel_InitPlayfield(struct LevelInfo *level, char *filename)
 
   /* map elements that 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 1
-      element = getMappedElementByVersion(element, level->game_version);
-#else
-      if (level->game_version <= VERSION_IDENT(2,2,0,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,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);
-      }
-#endif
-
-      level->field[x][y] = element;
-    }
-  }
+      level->field[x][y] = getMappedElementByVersion(level->field[x][y],
+                                                    level->game_version);
 
   /* copy elements to runtime playfield array */
   for (x = 0; x < MAX_LEV_FIELDX; x++)
@@ -2900,9 +5039,23 @@ static void LoadLevel_InitPlayfield(struct LevelInfo *level, char *filename)
   SetBorderElement();
 }
 
-void LoadLevelTemplate(int nr)
+static void LoadLevel_InitNativeEngines(struct LevelInfo *level,char *filename)
 {
+  struct LevelFileInfo *level_file_info = &level->file_info;
+
 #if 1
+  if (level_file_info->type == LEVEL_FILE_TYPE_RND)
+    CopyNativeLevel_RND_to_Native(level);
+#else
+  if (level_file_info->type == LEVEL_FILE_TYPE_RND)
+    CopyNativeLevel_RND_to_Native(level);
+  else
+    CopyNativeLevel_Native_to_RND(level);
+#endif
+}
+
+void LoadLevelTemplate(int nr)
+{
   char *filename;
 
   setLevelFileInfo(&level_template.file_info, nr);
@@ -2910,34 +5063,14 @@ void LoadLevelTemplate(int nr)
 
   LoadLevelFromFileInfo(&level_template, &level_template.file_info);
 
-#else
-
-#if 1
-  struct LevelFileInfo *level_file_info = getLevelFileInfo(nr);
-  char *filename = level_file_info->filename;
-
-  LoadLevelFromFileInfo(&level_template, level_file_info);
-#else
-  char *filename = getDefaultLevelFilename(nr);
-
-  LoadLevelFromFilename_RND(&level_template, filename);
-#endif
-#endif
-
-#if 1
   LoadLevel_InitVersion(&level_template, filename);
   LoadLevel_InitElements(&level_template, filename);
-#else
-  LoadLevel_InitVersion(&level, filename);
-  LoadLevel_InitElements(&level, filename);
-#endif
 
   ActivateLevelTemplate();
 }
 
 void LoadLevel(int nr)
 {
-#if 1
   char *filename;
 
   setLevelFileInfo(&level.file_info, nr);
@@ -2945,38 +5078,38 @@ void LoadLevel(int nr)
 
   LoadLevelFromFileInfo(&level, &level.file_info);
 
-#else
-
-#if 1
-  struct LevelFileInfo *level_file_info = getLevelFileInfo(nr);
-  char *filename = level_file_info->filename;
-
-  LoadLevelFromFileInfo(&level, level_file_info);
-#else
-  char *filename = getLevelFilename(nr);
-
-  LoadLevelFromFilename_RND(&level, filename);
-#endif
-#endif
-
   if (level.use_custom_template)
     LoadLevelTemplate(-1);
 
-#if 1
   LoadLevel_InitVersion(&level, filename);
   LoadLevel_InitElements(&level, filename);
   LoadLevel_InitPlayfield(&level, filename);
-#else
-  LoadLevel_InitLevel(&level, filename);
-#endif
+
+  LoadLevel_InitNativeEngines(&level, filename);
+}
+
+static int SaveLevel_VERS(FILE *file, struct LevelInfo *level)
+{
+  int chunk_size = 0;
+
+  chunk_size += putFileVersion(file, level->file_version);
+  chunk_size += putFileVersion(file, level->game_version);
+
+  return chunk_size;
 }
 
-static void SaveLevel_VERS(FILE *file, struct LevelInfo *level)
+static int SaveLevel_DATE(FILE *file, struct LevelInfo *level)
 {
-  putFileVersion(file, level->file_version);
-  putFileVersion(file, level->game_version);
+  int chunk_size = 0;
+
+  chunk_size += putFile16BitBE(file, level->creation_date.year);
+  chunk_size += putFile8Bit(file,    level->creation_date.month);
+  chunk_size += putFile8Bit(file,    level->creation_date.day);
+
+  return chunk_size;
 }
 
+#if 0
 static void SaveLevel_HEAD(FILE *file, struct LevelInfo *level)
 {
   int i, x, y;
@@ -2997,13 +5130,13 @@ static void SaveLevel_HEAD(FILE *file, struct LevelInfo *level)
     for (y = 0; y < 3; y++)
       for (x = 0; x < 3; x++)
        putFile8Bit(file, (level->encoding_16bit_yamyam ? EL_EMPTY :
-                          level->yamyam_content[i][x][y]));
+                          level->yamyam_content[i].e[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->initial_player_stepsize == STEPSIZE_FAST ? 1 : 0));
   putFile8Bit(file, (level->initial_gravity ? 1 : 0));
   putFile8Bit(file, (level->encoding_16bit_field ? 1 : 0));
   putFile8Bit(file, (level->em_slippery_gems ? 1 : 0));
@@ -3024,27 +5157,59 @@ static void SaveLevel_HEAD(FILE *file, struct LevelInfo *level)
 
   putFile8Bit(file, level->game_engine_type);
 
-  WriteUnusedBytesToFile(file, LEVEL_HEADER_UNUSED);
+  WriteUnusedBytesToFile(file, LEVEL_CHUNK_HEAD_UNUSED);
+}
+#endif
+
+static int SaveLevel_NAME(FILE *file, struct LevelInfo *level)
+{
+  int chunk_size = 0;
+  int i;
+
+  for (i = 0; i < MAX_LEVEL_NAME_LEN; i++)
+    chunk_size += putFile8Bit(file, level->name[i]);
+
+  return chunk_size;
 }
 
-static void SaveLevel_AUTH(FILE *file, struct LevelInfo *level)
+static int SaveLevel_AUTH(FILE *file, struct LevelInfo *level)
 {
+  int chunk_size = 0;
   int i;
 
   for (i = 0; i < MAX_LEVEL_AUTHOR_LEN; i++)
-    putFile8Bit(file, level->author[i]);
+    chunk_size += putFile8Bit(file, level->author[i]);
+
+  return chunk_size;
 }
 
-static void SaveLevel_BODY(FILE *file, struct LevelInfo *level)
+#if 0
+static int SaveLevel_BODY(FILE *file, struct LevelInfo *level)
 {
+  int chunk_size = 0;
   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]);
+       chunk_size += putFile16BitBE(file, level->field[x][y]);
       else
-       putFile8Bit(file, level->field[x][y]);
+       chunk_size += putFile8Bit(file, level->field[x][y]);
+
+  return chunk_size;
+}
+#endif
+
+static int SaveLevel_BODY(FILE *file, struct LevelInfo *level)
+{
+  int chunk_size = 0;
+  int x, y;
+
+  for (y = 0; y < level->fieldy; y++) 
+    for (x = 0; x < level->fieldx; x++) 
+      chunk_size += putFile16BitBE(file, level->field[x][y]);
+
+  return chunk_size;
 }
 
 #if 0
@@ -3061,12 +5226,13 @@ static void SaveLevel_CONT(FILE *file, struct LevelInfo *level)
     for (y = 0; y < 3; y++)
       for (x = 0; x < 3; x++)
        if (level->encoding_16bit_field)
-         putFile16BitBE(file, level->yamyam_content[i][x][y]);
+         putFile16BitBE(file, level->yamyam_content[i].e[x][y]);
        else
-         putFile8Bit(file, level->yamyam_content[i][x][y]);
+         putFile8Bit(file, level->yamyam_content[i].e[x][y]);
 }
 #endif
 
+#if 0
 static void SaveLevel_CNT2(FILE *file, struct LevelInfo *level, int element)
 {
   int i, x, y;
@@ -3082,7 +5248,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] = level->yamyam_content[i][x][y];
+         content_array[i][x][y] = level->yamyam_content[i].e[x][y];
   }
   else if (element == EL_BD_AMOEBA)
   {
@@ -3117,23 +5283,30 @@ static void SaveLevel_CNT2(FILE *file, struct LevelInfo *level, int element)
       for (x = 0; x < 3; x++)
        putFile16BitBE(file, content_array[i][x][y]);
 }
+#endif
 
-static void SaveLevel_CNT3(FILE *file, struct LevelInfo *level, int element)
+#if 0
+static int SaveLevel_CNT3(FILE *file, struct LevelInfo *level, int element)
 {
-  int i;
   int envelope_nr = element - EL_ENVELOPE_1;
   int envelope_len = strlen(level->envelope_text[envelope_nr]) + 1;
+  int chunk_size = 0;
+  int i;
 
-  putFile16BitBE(file, element);
-  putFile16BitBE(file, envelope_len);
-  putFile8Bit(file, level->envelope_xsize[envelope_nr]);
-  putFile8Bit(file, level->envelope_ysize[envelope_nr]);
+  chunk_size += putFile16BitBE(file, element);
+  chunk_size += putFile16BitBE(file, envelope_len);
+  chunk_size += putFile8Bit(file, level->envelope_xsize[envelope_nr]);
+  chunk_size += putFile8Bit(file, level->envelope_ysize[envelope_nr]);
 
   WriteUnusedBytesToFile(file, LEVEL_CHUNK_CNT3_UNUSED);
+  chunk_size += LEVEL_CHUNK_CNT3_UNUSED;
 
   for (i = 0; i < envelope_len; i++)
-    putFile8Bit(file, level->envelope_text[envelope_nr][i]);
+    chunk_size += putFile8Bit(file, level->envelope_text[envelope_nr][i]);
+
+  return chunk_size;
 }
+#endif
 
 #if 0
 static void SaveLevel_CUS1(FILE *file, struct LevelInfo *level,
@@ -3147,16 +5320,31 @@ static void SaveLevel_CUS1(FILE *file, struct LevelInfo *level,
   {
     int element = EL_CUSTOM_START + i;
 
-    if (Properties[element][EP_BITFIELD_BASE] != EP_BITMASK_DEFAULT)
+#if 1
+    struct ElementInfo *ei = &element_info[element];
+
+    if (ei->properties[EP_BITFIELD_BASE_NR] != EP_BITMASK_DEFAULT)
+    {
+      if (check < num_changed_custom_elements)
+      {
+       putFile16BitBE(file, element);
+       putFile32BitBE(file, ei->properties[EP_BITFIELD_BASE_NR]);
+      }
+
+      check++;
+    }
+#else
+    if (Properties[element][EP_BITFIELD_BASE_NR] != EP_BITMASK_DEFAULT)
     {
       if (check < num_changed_custom_elements)
       {
        putFile16BitBE(file, element);
-       putFile32BitBE(file, Properties[element][EP_BITFIELD_BASE]);
+       putFile32BitBE(file, Properties[element][EP_BITFIELD_BASE_NR]);
       }
 
       check++;
     }
+#endif
   }
 
   if (check != num_changed_custom_elements)    /* should not happen */
@@ -3204,63 +5392,68 @@ static void SaveLevel_CUS3(FILE *file, struct LevelInfo *level,
   for (i = 0; i < NUM_CUSTOM_ELEMENTS; i++)
   {
     int element = EL_CUSTOM_START + i;
+    struct ElementInfo *ei = &element_info[element];
 
-    if (element_info[element].modified_settings)
+    if (ei->modified_settings)
     {
       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]);
+         putFile8Bit(file, ei->description[j]);
 
-       putFile32BitBE(file, Properties[element][EP_BITFIELD_BASE]);
+#if 1
+       putFile32BitBE(file, ei->properties[EP_BITFIELD_BASE_NR]);
+#else
+       putFile32BitBE(file, Properties[element][EP_BITFIELD_BASE_NR]);
+#endif
 
        /* 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, ei->use_gfx_element);
+       putFile16BitBE(file, ei->gfx_element);
 
-       putFile8Bit(file, element_info[element].collect_score);
-       putFile8Bit(file, element_info[element].collect_count);
+       putFile8Bit(file, ei->collect_score_initial);
+       putFile8Bit(file, ei->collect_count_initial);
 
-       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, ei->push_delay_fixed);
+       putFile16BitBE(file, ei->push_delay_random);
+       putFile16BitBE(file, ei->move_delay_fixed);
+       putFile16BitBE(file, ei->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);
+       putFile16BitBE(file, ei->move_pattern);
+       putFile8Bit(file, ei->move_direction_initial);
+       putFile8Bit(file, ei->move_stepsize);
 
        for (y = 0; y < 3; y++)
          for (x = 0; x < 3; x++)
-           putFile16BitBE(file, element_info[element].content[x][y]);
+           putFile16BitBE(file, ei->content.e[x][y]);
 
-       putFile32BitBE(file, element_info[element].change->events);
+       putFile32BitBE(file, ei->change->events);
 
-       putFile16BitBE(file, element_info[element].change->target_element);
+       putFile16BitBE(file, ei->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, ei->change->delay_fixed);
+       putFile16BitBE(file, ei->change->delay_random);
+       putFile16BitBE(file, ei->change->delay_frames);
 
-       putFile16BitBE(file, element_info[element].change->trigger_element);
+       putFile16BitBE(file, ei->change->trigger_element);
 
-       putFile8Bit(file, element_info[element].change->explode);
-       putFile8Bit(file, element_info[element].change->use_target_content);
-       putFile8Bit(file, element_info[element].change->only_if_complete);
-       putFile8Bit(file, element_info[element].change->use_random_replace);
+       putFile8Bit(file, ei->change->explode);
+       putFile8Bit(file, ei->change->use_target_content);
+       putFile8Bit(file, ei->change->only_if_complete);
+       putFile8Bit(file, ei->change->use_random_replace);
 
-       putFile8Bit(file, element_info[element].change->random_percentage);
-       putFile8Bit(file, element_info[element].change->replace_when);
+       putFile8Bit(file, ei->change->random_percentage);
+       putFile8Bit(file, ei->change->replace_when);
 
        for (y = 0; y < 3; y++)
          for (x = 0; x < 3; x++)
-           putFile16BitBE(file, element_info[element].change->content[x][y]);
+           putFile16BitBE(file, ei->change->content.e[x][y]);
 
-       putFile8Bit(file, element_info[element].slippery_type);
+       putFile8Bit(file, ei->slippery_type);
 
        /* some free bytes for future properties and padding */
        WriteUnusedBytesToFile(file, LEVEL_CPART_CUS3_UNUSED);
@@ -3275,31 +5468,37 @@ static void SaveLevel_CUS3(FILE *file, struct LevelInfo *level,
 }
 #endif
 
+#if 0
 static void SaveLevel_CUS4(FILE *file, struct LevelInfo *level, int element)
 {
   struct ElementInfo *ei = &element_info[element];
   int i, j, x, y;
 
+  /* ---------- custom element base property values (96 bytes) ------------- */
+
   putFile16BitBE(file, element);
 
   for (i = 0; i < MAX_ELEMENT_NAME_LEN; i++)
     putFile8Bit(file, ei->description[i]);
 
-  putFile32BitBE(file, Properties[element][EP_BITFIELD_BASE]);
+#if 1
+  putFile32BitBE(file, ei->properties[EP_BITFIELD_BASE_NR]);
+#else
+  putFile32BitBE(file, Properties[element][EP_BITFIELD_BASE_NR]);
+#endif
   WriteUnusedBytesToFile(file, 4);     /* reserved for more base properties */
 
   putFile8Bit(file, ei->num_change_pages);
 
-  /* some free bytes for future base property values and padding */
-  WriteUnusedBytesToFile(file, 5);
-
-  /* write custom property values */
+  putFile16BitBE(file, ei->ce_value_fixed_initial);
+  putFile16BitBE(file, ei->ce_value_random_initial);
+  putFile8Bit(file, ei->use_last_ce_value);
 
   putFile8Bit(file, ei->use_gfx_element);
   putFile16BitBE(file, ei->gfx_element);
 
-  putFile8Bit(file, ei->collect_score);
-  putFile8Bit(file, ei->collect_count);
+  putFile8Bit(file, ei->collect_score_initial);
+  putFile8Bit(file, ei->collect_count_initial);
 
   putFile8Bit(file, ei->drop_delay_fixed);
   putFile8Bit(file, ei->push_delay_fixed);
@@ -3317,106 +5516,484 @@ static void SaveLevel_CUS4(FILE *file, struct LevelInfo *level, int element)
 
   for (y = 0; y < 3; y++)
     for (x = 0; x < 3; x++)
-      putFile16BitBE(file, ei->content[x][y]);
+      putFile16BitBE(file, ei->content.e[x][y]);
 
   putFile16BitBE(file, ei->move_enter_element);
   putFile16BitBE(file, ei->move_leave_element);
   putFile8Bit(file, ei->move_leave_type);
 
-  /* ... bits 16 - 31 of "move_pattern" (not nice, but downward compatible) */
-  putFile16BitBE(file, (ei->move_pattern >> 16) & 0xffff);
+  /* ... bits 16 - 31 of "move_pattern" (not nice, but downward compatible) */
+  putFile16BitBE(file, (ei->move_pattern >> 16) & 0xffff);
+
+  putFile8Bit(file, ei->access_direction);
+
+  putFile8Bit(file, ei->explosion_delay);
+  putFile8Bit(file, ei->ignition_delay);
+  putFile8Bit(file, ei->explosion_type);
+
+  /* some free bytes for future custom property values and padding */
+  WriteUnusedBytesToFile(file, 1);
+
+  /* ---------- change page property values (48 bytes) --------------------- */
+
+  for (i = 0; i < ei->num_change_pages; i++)
+  {
+    struct ElementChangeInfo *change = &ei->change_page[i];
+    unsigned int event_bits;
+
+    /* bits 0 - 31 of "has_event[]" ... */
+    event_bits = 0;
+    for (j = 0; j < MIN(NUM_CHANGE_EVENTS, 32); j++)
+      if (change->has_event[j])
+       event_bits |= (1 << j);
+    putFile32BitBE(file, event_bits);
+
+    putFile16BitBE(file, change->target_element);
+
+    putFile16BitBE(file, change->delay_fixed);
+    putFile16BitBE(file, change->delay_random);
+    putFile16BitBE(file, change->delay_frames);
+
+    putFile16BitBE(file, change->trigger_element);
+
+    putFile8Bit(file, change->explode);
+    putFile8Bit(file, change->use_target_content);
+    putFile8Bit(file, change->only_if_complete);
+    putFile8Bit(file, change->use_random_replace);
+
+    putFile8Bit(file, change->random_percentage);
+    putFile8Bit(file, change->replace_when);
+
+    for (y = 0; y < 3; y++)
+      for (x = 0; x < 3; x++)
+       putFile16BitBE(file, change->target_content.e[x][y]);
+
+    putFile8Bit(file, change->can_change);
+
+    putFile8Bit(file, change->trigger_side);
+
+    putFile8Bit(file, change->trigger_player);
+    putFile8Bit(file, (change->trigger_page == CH_PAGE_ANY ? CH_PAGE_ANY_FILE :
+                      log_2(change->trigger_page)));
+
+    putFile8Bit(file, change->has_action);
+    putFile8Bit(file, change->action_type);
+    putFile8Bit(file, change->action_mode);
+    putFile16BitBE(file, change->action_arg);
+
+    /* ... bits 32 - 39 of "has_event[]" (not nice, but downward compatible) */
+    event_bits = 0;
+    for (j = 32; j < NUM_CHANGE_EVENTS; j++)
+      if (change->has_event[j])
+       event_bits |= (1 << (j - 32));
+    putFile8Bit(file, event_bits);
+  }
+}
+#endif
+
+#if 0
+static void SaveLevel_GRP1(FILE *file, struct LevelInfo *level, int element)
+{
+  struct ElementInfo *ei = &element_info[element];
+  struct ElementGroupInfo *group = ei->group;
+  int i;
+
+  putFile16BitBE(file, element);
+
+  for (i = 0; i < MAX_ELEMENT_NAME_LEN; i++)
+    putFile8Bit(file, ei->description[i]);
+
+  putFile8Bit(file, group->num_elements);
+
+  putFile8Bit(file, ei->use_gfx_element);
+  putFile16BitBE(file, ei->gfx_element);
+
+  putFile8Bit(file, group->choice_mode);
+
+  /* some free bytes for future values and padding */
+  WriteUnusedBytesToFile(file, 3);
+
+  for (i = 0; i < MAX_ELEMENTS_IN_GROUP; i++)
+    putFile16BitBE(file, group->element[i]);
+}
+#endif
+
+static int SaveLevel_MicroChunk(FILE *file, struct LevelFileConfigInfo *entry,
+                               boolean write_element)
+{
+  int save_type = entry->save_type;
+  int data_type = entry->data_type;
+  int conf_type = entry->conf_type;
+  int byte_mask = conf_type & CONF_MASK_BYTES;
+  int element = entry->element;
+  int default_value = entry->default_value;
+  int num_bytes = 0;
+  boolean modified = FALSE;
+
+  if (byte_mask != CONF_MASK_MULTI_BYTES)
+  {
+    void *value_ptr = entry->value;
+    int value = (data_type == TYPE_BOOLEAN ? *(boolean *)value_ptr :
+                *(int *)value_ptr);
+
+    /* check if any settings have been modified before saving them */
+    if (value != default_value)
+      modified = TRUE;
+
+    /* do not save if explicitly told or if unmodified default settings */
+    if ((save_type == SAVE_CONF_NEVER) ||
+       (save_type == SAVE_CONF_WHEN_CHANGED && !modified))
+      return 0;
+
+    if (write_element)
+      num_bytes += putFile16BitBE(file, element);
+
+    num_bytes += putFile8Bit(file, conf_type);
+    num_bytes += (byte_mask == CONF_MASK_1_BYTE ? putFile8Bit   (file, value) :
+                 byte_mask == CONF_MASK_2_BYTE ? putFile16BitBE(file, value) :
+                 byte_mask == CONF_MASK_4_BYTE ? putFile32BitBE(file, value) :
+                 0);
+  }
+  else if (data_type == TYPE_STRING)
+  {
+    char *default_string = entry->default_string;
+    char *string = (char *)(entry->value);
+    int string_length = strlen(string);
+    int i;
+
+    /* check if any settings have been modified before saving them */
+    if (!strEqual(string, default_string))
+      modified = TRUE;
+
+    /* do not save if explicitly told or if unmodified default settings */
+    if ((save_type == SAVE_CONF_NEVER) ||
+       (save_type == SAVE_CONF_WHEN_CHANGED && !modified))
+      return 0;
+
+    if (write_element)
+      num_bytes += putFile16BitBE(file, element);
+
+    num_bytes += putFile8Bit(file, conf_type);
+    num_bytes += putFile16BitBE(file, string_length);
+
+    for (i = 0; i < string_length; i++)
+      num_bytes += putFile8Bit(file, string[i]);
+  }
+  else if (data_type == TYPE_ELEMENT_LIST)
+  {
+    int *element_array = (int *)(entry->value);
+    int num_elements = *(int *)(entry->num_entities);
+    int i;
+
+    /* check if any settings have been modified before saving them */
+    for (i = 0; i < num_elements; i++)
+      if (element_array[i] != default_value)
+       modified = TRUE;
+
+    /* do not save if explicitly told or if unmodified default settings */
+    if ((save_type == SAVE_CONF_NEVER) ||
+       (save_type == SAVE_CONF_WHEN_CHANGED && !modified))
+      return 0;
+
+    if (write_element)
+      num_bytes += putFile16BitBE(file, element);
+
+    num_bytes += putFile8Bit(file, conf_type);
+    num_bytes += putFile16BitBE(file, num_elements * CONF_ELEMENT_NUM_BYTES);
+
+    for (i = 0; i < num_elements; i++)
+      num_bytes += putFile16BitBE(file, element_array[i]);
+  }
+  else if (data_type == TYPE_CONTENT_LIST)
+  {
+    struct Content *content = (struct Content *)(entry->value);
+    int num_contents = *(int *)(entry->num_entities);
+    int i, x, y;
+
+    /* check if any settings have been modified before saving them */
+    for (i = 0; i < num_contents; i++)
+      for (y = 0; y < 3; y++)
+       for (x = 0; x < 3; x++)
+         if (content[i].e[x][y] != default_value)
+           modified = TRUE;
+
+    /* do not save if explicitly told or if unmodified default settings */
+    if ((save_type == SAVE_CONF_NEVER) ||
+       (save_type == SAVE_CONF_WHEN_CHANGED && !modified))
+      return 0;
+
+    if (write_element)
+      num_bytes += putFile16BitBE(file, element);
+
+    num_bytes += putFile8Bit(file, conf_type);
+    num_bytes += putFile16BitBE(file, num_contents * CONF_CONTENT_NUM_BYTES);
+
+    for (i = 0; i < num_contents; i++)
+      for (y = 0; y < 3; y++)
+       for (x = 0; x < 3; x++)
+         num_bytes += putFile16BitBE(file, content[i].e[x][y]);
+  }
+
+  return num_bytes;
+}
+
+#if 0
+
+static int SaveLevel_MicroChunk_SingleValue(FILE *file,
+                                           struct LevelFileConfigInfo *entry)
+{
+  int default_value = entry->default_value;
+  int element = entry->element;
+  int data_type = entry->data_type;
+  int conf_type = entry->conf_type;
+  int byte_mask = conf_type & CONF_MASK_BYTES;
+  void *value_ptr = entry->value;
+  int value = (data_type == TYPE_BOOLEAN ? *(boolean *)value_ptr :
+              *(int *)value_ptr);
+  int num_bytes = 0;
+  boolean modified = FALSE;
+
+  /* check if any settings have been modified before saving them */
+  if (value != default_value)
+    modified = TRUE;
+
+  if (!modified)               /* do not save unmodified default settings */
+    return 0;
+
+#if 0
+  printf("::: %02x, %d: %d != %d\n",
+        byte_mask, conf_type & CONF_MASK_TOKEN,
+        value, default_value);
+#endif
+
+  if (element != -1)
+    num_bytes += putFile16BitBE(file, element);
+
+  num_bytes += putFile8Bit(file, conf_type);
+  num_bytes += (byte_mask == CONF_MASK_1_BYTE ? putFile8Bit   (file, value) :
+               byte_mask == CONF_MASK_2_BYTE ? putFile16BitBE(file, value) :
+               byte_mask == CONF_MASK_4_BYTE ? putFile32BitBE(file, value) :0);
+
+  return num_bytes;
+}
+
+static int SaveLevel_MicroChunk_ElementList(FILE *file,
+                                           struct LevelFileConfigInfo *entry)
+{
+  int *element_array = (int *)(entry->value);
+  int num_elements = *(int *)(entry->num_entities);
+  int default_value = entry->default_value;
+  int element = entry->element;
+  int conf_type = entry->conf_type;
+  int num_bytes = 0;
+  boolean modified = FALSE;
+  int i;
+
+  /* check if any settings have been modified before saving them */
+  for (i = 0; i < num_elements; i++)
+    if (element_array[i] != default_value)
+      modified = TRUE;
+
+  if (!modified)               /* do not save unmodified default settings */
+    return 0;
+
+  if (element != -1)
+    num_bytes += putFile16BitBE(file, element);
+
+  num_bytes += putFile8Bit(file, conf_type);
+  num_bytes += putFile16BitBE(file, num_elements * CONF_ELEMENT_NUM_BYTES);
+
+  for (i = 0; i < num_elements; i++)
+    num_bytes += putFile16BitBE(file, element_array[i]);
+
+  return num_bytes;
+}
+
+static int SaveLevel_MicroChunk_ContentList(FILE *file,
+                                           struct LevelFileConfigInfo *entry)
+{
+  struct Content *content = (struct Content *)(entry->value);
+  int num_contents = *(int *)(entry->num_entities);
+  int default_value = entry->default_value;
+  int element = entry->element;
+  int conf_type = entry->conf_type;
+  int num_bytes = 0;
+  boolean modified = FALSE;
+  int i, x, y;
+
+  /* check if any settings have been modified before saving them */
+  for (i = 0; i < num_contents; i++)
+    for (y = 0; y < 3; y++)
+      for (x = 0; x < 3; x++)
+       if (content[i].e[x][y] != default_value)
+         modified = TRUE;
+
+  if (!modified)               /* do not save unmodified default settings */
+    return 0;
+
+  if (element != -1)
+    num_bytes += putFile16BitBE(file, element);
+
+  num_bytes += putFile8Bit(file, conf_type);
+  num_bytes += putFile16BitBE(file, num_contents * CONF_CONTENT_NUM_BYTES);
+
+  for (i = 0; i < num_contents; i++)
+    for (y = 0; y < 3; y++)
+      for (x = 0; x < 3; x++)
+       num_bytes += putFile16BitBE(file, content[i].e[x][y]);
+
+  return num_bytes;
+}
+
+#endif
+
+static int SaveLevel_INFO(FILE *file, struct LevelInfo *level)
+{
+  int chunk_size = 0;
+  int i;
+
+  li = *level;         /* copy level data into temporary buffer */
+
+  for (i = 0; chunk_config_INFO[i].data_type != -1; i++)
+    chunk_size += SaveLevel_MicroChunk(file, &chunk_config_INFO[i], FALSE);
+
+  return chunk_size;
+}
+
+static int SaveLevel_ELEM(FILE *file, struct LevelInfo *level)
+{
+  int chunk_size = 0;
+  int i;
+
+  li = *level;         /* copy level data into temporary buffer */
+
+  for (i = 0; chunk_config_ELEM[i].data_type != -1; i++)
+  {
+#if 1
+    chunk_size += SaveLevel_MicroChunk(file, &chunk_config_ELEM[i], TRUE);
+#else
+    struct LevelFileConfigInfo *conf = &chunk_config_ELEM[i];
+    int data_type = conf->data_type;
+    int conf_type = conf->conf_type;
+    int byte_mask = conf_type & CONF_MASK_BYTES;
+
+    if (byte_mask != CONF_MASK_MULTI_BYTES)
+      chunk_size += SaveLevel_MicroChunk_SingleValue(file, conf);
+    else if (data_type == TYPE_ELEMENT_LIST)
+      chunk_size += SaveLevel_MicroChunk_ElementList(file, conf);
+    else if (data_type == TYPE_CONTENT_LIST)
+      chunk_size += SaveLevel_MicroChunk_ContentList(file, conf);
+#endif
+  }
+
+  return chunk_size;
+}
 
-  putFile8Bit(file, ei->access_direction);
+static int SaveLevel_NOTE(FILE *file, struct LevelInfo *level, int element)
+{
+  int envelope_nr = element - EL_ENVELOPE_1;
+  int chunk_size = 0;
+  int i;
 
-  putFile8Bit(file, ei->explosion_delay);
-  putFile8Bit(file, ei->ignition_delay);
-  putFile8Bit(file, ei->explosion_type);
+  chunk_size += putFile16BitBE(file, element);
 
-  /* some free bytes for future custom property values and padding */
-  WriteUnusedBytesToFile(file, 1);
+  /* copy envelope data into temporary buffer */
+  xx_envelope = level->envelope[envelope_nr];
 
-  /* write change property values */
+  for (i = 0; chunk_config_NOTE[i].data_type != -1; i++)
+    chunk_size += SaveLevel_MicroChunk(file, &chunk_config_NOTE[i], FALSE);
 
-  for (i = 0; i < ei->num_change_pages; i++)
-  {
-    struct ElementChangeInfo *change = &ei->change_page[i];
-    unsigned long event_bits = 0;
+  return chunk_size;
+}
 
-    for (j = 0; j < NUM_CHANGE_EVENTS; j++)
-      if (change->has_event[j])
-       event_bits |= (1 << j);
+static int SaveLevel_CUSX(FILE *file, struct LevelInfo *level, int element)
+{
+  struct ElementInfo *ei = &element_info[element];
+  int chunk_size = 0;
+  int i, j;
 
-    putFile32BitBE(file, event_bits);
+  chunk_size += putFile16BitBE(file, element);
 
-    putFile16BitBE(file, change->target_element);
+  xx_ei = *ei;         /* copy element data into temporary buffer */
 
-    putFile16BitBE(file, change->delay_fixed);
-    putFile16BitBE(file, change->delay_random);
-    putFile16BitBE(file, change->delay_frames);
+  /* set default description string for this specific element */
+  strcpy(xx_default_description, getDefaultElementDescription(ei));
 
-    putFile16BitBE(file, change->trigger_element);
+  /* set (fixed) number of content areas (may have been overwritten earlier) */
+  xx_num_contents = 1;
 
-    putFile8Bit(file, change->explode);
-    putFile8Bit(file, change->use_target_content);
-    putFile8Bit(file, change->only_if_complete);
-    putFile8Bit(file, change->use_random_replace);
+#if 0
+  printf("::: - element config\n");
+#endif
 
-    putFile8Bit(file, change->random_percentage);
-    putFile8Bit(file, change->replace_when);
+  for (i = 0; chunk_config_CUSX_base[i].data_type != -1; i++)
+    chunk_size += SaveLevel_MicroChunk(file, &chunk_config_CUSX_base[i], FALSE);
 
-    for (y = 0; y < 3; y++)
-      for (x = 0; x < 3; x++)
-       putFile16BitBE(file, change->target_content[x][y]);
+#if 0
+  printf("::: - change pages\n");
+#endif
 
-    putFile8Bit(file, change->can_change);
+  for (i = 0; i < ei->num_change_pages; i++)
+  {
+    struct ElementChangeInfo *change = &ei->change_page[i];
 
-    putFile8Bit(file, change->trigger_side);
+    xx_current_change_page = i;
 
-#if 1
-    putFile8Bit(file, change->trigger_player);
-    putFile8Bit(file, (change->trigger_page == CH_PAGE_ANY ? CH_PAGE_ANY_FILE :
-                      log_2(change->trigger_page)));
+    xx_change = *change;       /* copy change data into temporary buffer */
 
-    /* some free bytes for future change property values and padding */
-    WriteUnusedBytesToFile(file, 6);
+#if 0
+    printf(":::   %d: xx_change.action_mode == %d\n",
+          i, xx_change.action_mode);
+    printf(":::   %d: xx_change.action_arg == %d\n",
+          i, xx_change.action_arg);
+#endif
 
-#else
+    resetEventBits();
+    setEventBitsFromEventFlags(change);
+
+    for (j = 0; chunk_config_CUSX_change[j].data_type != -1; j++)
+      chunk_size += SaveLevel_MicroChunk(file, &chunk_config_CUSX_change[j],
+                                        FALSE);
 
-    /* some free bytes for future change property values and padding */
-    WriteUnusedBytesToFile(file, 8);
+#if 0
+    if (element == EL_CUSTOM_START)
+      printf("::: - saving change page %d / %d (%d bytes)\n",
+            i, ei->num_change_pages, chunk_size);
 #endif
   }
+
+  return chunk_size;
 }
 
-static void SaveLevel_GRP1(FILE *file, struct LevelInfo *level, int element)
+static int SaveLevel_GRPX(FILE *file, struct LevelInfo *level, int element)
 {
   struct ElementInfo *ei = &element_info[element];
   struct ElementGroupInfo *group = ei->group;
+  int chunk_size = 0;
   int i;
 
-  putFile16BitBE(file, element);
-
-  for (i = 0; i < MAX_ELEMENT_NAME_LEN; i++)
-    putFile8Bit(file, ei->description[i]);
-
-  putFile8Bit(file, group->num_elements);
+  chunk_size += putFile16BitBE(file, element);
 
-  putFile8Bit(file, ei->use_gfx_element);
-  putFile16BitBE(file, ei->gfx_element);
+  xx_ei = *ei;         /* copy element data into temporary buffer */
+  xx_group = *group;   /* copy group data into temporary buffer */
 
-  putFile8Bit(file, group->choice_mode);
+  /* set default description string for this specific element */
+  strcpy(xx_default_description, getDefaultElementDescription(ei));
 
-  /* some free bytes for future values and padding */
-  WriteUnusedBytesToFile(file, 3);
+  for (i = 0; chunk_config_GRPX[i].data_type != -1; i++)
+    chunk_size += SaveLevel_MicroChunk(file, &chunk_config_GRPX[i], FALSE);
 
-  for (i = 0; i < MAX_ELEMENTS_IN_GROUP; i++)
-    putFile16BitBE(file, group->element[i]);
+  return chunk_size;
 }
 
 static void SaveLevelFromFilename(struct LevelInfo *level, char *filename)
 {
-  int body_chunk_size;
+  int chunk_size;
+#if 1
+  int i;
+#else
   int i, x, y;
+#endif
   FILE *file;
 
   if (!(file = fopen(filename, MODE_WRITE)))
@@ -3428,45 +6005,73 @@ static void SaveLevelFromFilename(struct LevelInfo *level, char *filename)
   level->file_version = FILE_VERSION_ACTUAL;
   level->game_version = GAME_VERSION_ACTUAL;
 
+  level->creation_date = getCurrentDate();
+
+#if 0
   /* 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 (level->field[x][y] > 255)
        level->encoding_16bit_field = TRUE;
+#endif
 
+#if 0
   /* check yamyam content for 16-bit elements */
   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->yamyam_content[i][x][y] > 255)
+       if (level->yamyam_content[i].e[x][y] > 255)
          level->encoding_16bit_yamyam = TRUE;
+#endif
 
+#if 0
   /* check amoeba content for 16-bit elements */
   level->encoding_16bit_amoeba = FALSE;
   if (level->amoeba_content > 255)
     level->encoding_16bit_amoeba = TRUE;
+#endif
 
+#if 0
   /* calculate size of "BODY" chunk */
   body_chunk_size =
     level->fieldx * level->fieldy * (level->encoding_16bit_field ? 2 : 1);
+#endif
 
   putFileChunkBE(file, "RND1", CHUNK_SIZE_UNDEFINED);
   putFileChunkBE(file, "CAVE", CHUNK_SIZE_NONE);
 
-  putFileChunkBE(file, "VERS", FILE_VERS_CHUNK_SIZE);
+  chunk_size = SaveLevel_VERS(NULL, level);
+  putFileChunkBE(file, "VERS", chunk_size);
   SaveLevel_VERS(file, level);
 
-  putFileChunkBE(file, "HEAD", LEVEL_HEADER_SIZE);
+  chunk_size = SaveLevel_DATE(NULL, level);
+  putFileChunkBE(file, "DATE", chunk_size);
+  SaveLevel_DATE(file, level);
+
+#if 0
+  putFileChunkBE(file, "HEAD", LEVEL_CHUNK_HEAD_SIZE);
   SaveLevel_HEAD(file, level);
+#endif
 
-  putFileChunkBE(file, "AUTH", MAX_LEVEL_AUTHOR_LEN);
+  chunk_size = SaveLevel_NAME(NULL, level);
+  putFileChunkBE(file, "NAME", chunk_size);
+  SaveLevel_NAME(file, level);
+
+  chunk_size = SaveLevel_AUTH(NULL, level);
+  putFileChunkBE(file, "AUTH", chunk_size);
   SaveLevel_AUTH(file, level);
 
-  putFileChunkBE(file, "BODY", body_chunk_size);
+  chunk_size = SaveLevel_INFO(NULL, level);
+  putFileChunkBE(file, "INFO", chunk_size);
+  SaveLevel_INFO(file, level);
+
+  chunk_size = SaveLevel_BODY(NULL, level);
+  putFileChunkBE(file, "BODY", chunk_size);
   SaveLevel_BODY(file, level);
 
+#if 0
   if (level->encoding_16bit_yamyam ||
       level->num_yamyam_contents != STD_ELEMENT_CONTENTS)
   {
@@ -3479,7 +6084,9 @@ static void SaveLevelFromFilename(struct LevelInfo *level, char *filename)
     putFileChunkBE(file, "CNT2", LEVEL_CHUNK_CNT2_SIZE);
     SaveLevel_CNT2(file, level, EL_BD_AMOEBA);
   }
+#endif
 
+#if 0
   /* check for envelope content */
   for (i = 0; i < 4; i++)
   {
@@ -3491,8 +6098,10 @@ static void SaveLevelFromFilename(struct LevelInfo *level, char *filename)
       SaveLevel_CNT3(file, level, EL_ENVELOPE_1 + i);
     }
   }
+#endif
 
-  /* check for non-default custom elements (unless using template level) */
+#if 0
+  /* if not using template level, check for non-default custom/group elements */
   if (!level->use_custom_template)
   {
     for (i = 0; i < NUM_CUSTOM_ELEMENTS; i++)
@@ -3507,11 +6116,7 @@ static void SaveLevelFromFilename(struct LevelInfo *level, char *filename)
        SaveLevel_CUS4(file, level, element);
       }
     }
-  }
 
-  /* check for non-default group elements (unless using template level) */
-  if (!level->use_custom_template)
-  {
     for (i = 0; i < NUM_GROUP_ELEMENTS; i++)
     {
       int element = EL_GROUP_START + i;
@@ -3523,6 +6128,58 @@ static void SaveLevelFromFilename(struct LevelInfo *level, char *filename)
       }
     }
   }
+#endif
+
+  chunk_size = SaveLevel_ELEM(NULL, level);
+  if (chunk_size > LEVEL_CHUNK_ELEM_UNCHANGED)         /* save if changed */
+  {
+    putFileChunkBE(file, "ELEM", chunk_size);
+    SaveLevel_ELEM(file, level);
+  }
+
+#if 1
+  for (i = 0; i < NUM_ENVELOPES; i++)
+  {
+    int element = EL_ENVELOPE_1 + i;
+
+    chunk_size = SaveLevel_NOTE(NULL, level, element);
+    if (chunk_size > LEVEL_CHUNK_NOTE_UNCHANGED)       /* save if changed */
+    {
+      putFileChunkBE(file, "NOTE", chunk_size);
+      SaveLevel_NOTE(file, level, element);
+    }
+  }
+#endif
+
+#if 1
+  /* if not using template level, check for non-default custom/group elements */
+  if (!level->use_custom_template)
+  {
+    for (i = 0; i < NUM_CUSTOM_ELEMENTS; i++)
+    {
+      int element = EL_CUSTOM_START + i;
+
+      chunk_size = SaveLevel_CUSX(NULL, level, element);
+      if (chunk_size > LEVEL_CHUNK_CUSX_UNCHANGED)     /* save if changed */
+      {
+       putFileChunkBE(file, "CUSX", chunk_size);
+       SaveLevel_CUSX(file, level, element);
+      }
+    }
+
+    for (i = 0; i < NUM_GROUP_ELEMENTS; i++)
+    {
+      int element = EL_GROUP_START + i;
+
+      chunk_size = SaveLevel_GRPX(NULL, level, element);
+      if (chunk_size > LEVEL_CHUNK_GRPX_UNCHANGED)     /* save if changed */
+      {
+       putFileChunkBE(file, "GRPX", chunk_size);
+       SaveLevel_GRPX(file, level, element);
+      }
+    }
+  }
+#endif
 
   fclose(file);
 
@@ -3572,8 +6229,12 @@ void DumpLevel(struct LevelInfo *level)
   printf("\n");
   printf("Amoeba speed: %d\n", level->amoeba_speed);
   printf("\n");
+
+#if 0
   printf("Initial gravity:             %s\n", (level->initial_gravity ? "yes" : "no"));
-  printf("Double speed movement:       %s\n", (level->double_speed ? "yes" : "no"));
+  printf("Initial player stepsize:     %d\n", level->initial_player_stepsize);
+#endif
+
   printf("EM style slippery gems:      %s\n", (level->em_slippery_gems ? "yes" : "no"));
   printf("Player blocks last field:    %s\n", (level->block_last_field ? "yes" : "no"));
   printf("SP player blocks last field: %s\n", (level->sp_block_last_field ? "yes" : "no"));
@@ -3649,7 +6310,7 @@ static int LoadTape_HEAD(FILE *file, int chunk_size, struct TapeInfo *tape)
       }
     }
 
-    ReadUnusedBytesFromFile(file, TAPE_HEADER_UNUSED);
+    ReadUnusedBytesFromFile(file, TAPE_CHUNK_HEAD_UNUSED);
 
     engine_version = getFileVersion(file);
     if (engine_version > 0)
@@ -3700,7 +6361,7 @@ static int LoadTape_BODY(FILE *file, int chunk_size, struct TapeInfo *tape)
 
     for (j = 0; j < MAX_PLAYERS; j++)
     {
-      tape->pos[i].action[j] = MV_NO_MOVING;
+      tape->pos[i].action[j] = MV_NONE;
 
       if (tape->player_participates[j])
        tape->pos[i].action[j] = getFile8Bit(file);
@@ -3747,7 +6408,7 @@ static int LoadTape_BODY(FILE *file, int chunk_size, struct TapeInfo *tape)
 
        /* delay part */
        for (j = 0; j < MAX_PLAYERS; j++)
-         tape->pos[i].action[j] = MV_NO_MOVING;
+         tape->pos[i].action[j] = MV_NONE;
        tape->pos[i].delay--;
 
        i++;
@@ -3779,20 +6440,16 @@ void LoadTapeFromFilename(char *filename)
   {
     tape.no_valid_file = TRUE;
 
-#if 0
-    Error(ERR_WARN, "cannot read tape '%s' -- using empty tape", filename);
-#endif
-
     return;
   }
 
   getFileChunkBE(file, chunk_name, NULL);
-  if (strcmp(chunk_name, "RND1") == 0)
+  if (strEqual(chunk_name, "RND1"))
   {
     getFile32BitBE(file);              /* not used */
 
     getFileChunkBE(file, chunk_name, NULL);
-    if (strcmp(chunk_name, "TAPE") != 0)
+    if (!strEqual(chunk_name, "TAPE"))
     {
       tape.no_valid_file = TRUE;
 
@@ -3833,8 +6490,8 @@ void LoadTapeFromFilename(char *filename)
   if (tape.file_version < FILE_VERSION_1_2)
   {
     /* tape files from versions before 1.2.0 without chunk structure */
-    LoadTape_HEAD(file, TAPE_HEADER_SIZE, &tape);
-    LoadTape_BODY(file, 2 * tape.length,  &tape);
+    LoadTape_HEAD(file, TAPE_CHUNK_HEAD_SIZE, &tape);
+    LoadTape_BODY(file, 2 * tape.length,      &tape);
   }
   else
   {
@@ -3846,8 +6503,8 @@ void LoadTapeFromFilename(char *filename)
     }
     chunk_info[] =
     {
-      { "VERS", FILE_VERS_CHUNK_SIZE,  LoadTape_VERS },
-      { "HEAD", TAPE_HEADER_SIZE,      LoadTape_HEAD },
+      { "VERS", TAPE_CHUNK_VERS_SIZE,  LoadTape_VERS },
+      { "HEAD", TAPE_CHUNK_HEAD_SIZE,  LoadTape_HEAD },
       { "INFO", -1,                    LoadTape_INFO },
       { "BODY", -1,                    LoadTape_BODY },
       {  NULL,  0,                     NULL }
@@ -3858,7 +6515,7 @@ void LoadTapeFromFilename(char *filename)
       int i = 0;
 
       while (chunk_info[i].name != NULL &&
-            strcmp(chunk_name, chunk_info[i].name) != 0)
+            !strEqual(chunk_name, chunk_info[i].name))
        i++;
 
       if (chunk_info[i].name == NULL)
@@ -3897,6 +6554,7 @@ void LoadTapeFromFilename(char *filename)
   tape.length_seconds = GetTapeLength();
 
 #if 0
+  printf("::: tape file version: %d\n", tape.file_version);
   printf("::: tape game version: %d\n", tape.game_version);
   printf("::: tape engine version: %d\n", tape.engine_version);
 #endif
@@ -3939,7 +6597,7 @@ static void SaveTape_HEAD(FILE *file, struct TapeInfo *tape)
   putFile8Bit(file, store_participating_players);
 
   /* unused bytes not at the end here for 4-byte alignment of engine_version */
-  WriteUnusedBytesToFile(file, TAPE_HEADER_UNUSED);
+  WriteUnusedBytesToFile(file, TAPE_CHUNK_HEAD_UNUSED);
 
   putFileVersion(file, tape->engine_version);
 }
@@ -4011,10 +6669,10 @@ void SaveTape(int nr)
   putFileChunkBE(file, "RND1", CHUNK_SIZE_UNDEFINED);
   putFileChunkBE(file, "TAPE", CHUNK_SIZE_NONE);
 
-  putFileChunkBE(file, "VERS", FILE_VERS_CHUNK_SIZE);
+  putFileChunkBE(file, "VERS", TAPE_CHUNK_VERS_SIZE);
   SaveTape_VERS(file, &tape);
 
-  putFileChunkBE(file, "HEAD", TAPE_HEADER_SIZE);
+  putFileChunkBE(file, "HEAD", TAPE_CHUNK_HEAD_SIZE);
   SaveTape_HEAD(file, &tape);
 
   putFileChunkBE(file, "INFO", info_chunk_size);
@@ -4035,23 +6693,15 @@ void SaveTape(int nr)
 
 void DumpTape(struct TapeInfo *tape)
 {
+  int tape_frame_counter;
   int i, j;
 
-#if 1
   if (tape->no_valid_file)
   {
     Error(ERR_WARN, "cannot dump -- no valid tape file found");
 
     return;
   }
-#else
-  if (TAPE_IS_EMPTY(*tape))
-  {
-    Error(ERR_WARN, "no tape available for level %d", tape->level_nr);
-
-    return;
-  }
-#endif
 
   printf_line("-", 79);
   printf("Tape of Level %03d (file version %08d, game version %08d)\n",
@@ -4061,12 +6711,14 @@ void DumpTape(struct TapeInfo *tape)
   printf("Level series identifier: '%s'\n", tape->level_identifier);
   printf_line("-", 79);
 
+  tape_frame_counter = 0;
+
   for (i = 0; i < tape->length; i++)
   {
     if (i >= MAX_TAPE_LEN)
       break;
 
-    printf("%03d: ", i);
+    printf("%04d: ", i);
 
     for (j = 0; j < MAX_PLAYERS; j++)
     {
@@ -4085,7 +6737,10 @@ void DumpTape(struct TapeInfo *tape)
       }
     }
 
-    printf("(%03d)\n", tape->pos[i].delay);
+    printf("(%03d) ", tape->pos[i].delay);
+    printf("[%05d]\n", tape_frame_counter);
+
+    tape_frame_counter += tape->pos[i].delay;
   }
 
   printf_line("-", 79);
@@ -4191,21 +6846,26 @@ void SaveScore(int nr)
 #define SETUP_TOKEN_SOFT_SCROLLING             7
 #define SETUP_TOKEN_FADING                     8
 #define SETUP_TOKEN_AUTORECORD                 9
-#define SETUP_TOKEN_QUICK_DOORS                        10
-#define SETUP_TOKEN_TEAM_MODE                  11
-#define SETUP_TOKEN_HANDICAP                   12
-#define SETUP_TOKEN_SKIP_LEVELS                        13
-#define SETUP_TOKEN_TIME_LIMIT                 14
-#define SETUP_TOKEN_FULLSCREEN                 15
-#define SETUP_TOKEN_ASK_ON_ESCAPE              16
-#define SETUP_TOKEN_GRAPHICS_SET               17
-#define SETUP_TOKEN_SOUNDS_SET                 18
-#define SETUP_TOKEN_MUSIC_SET                  19
-#define SETUP_TOKEN_OVERRIDE_LEVEL_GRAPHICS    20
-#define SETUP_TOKEN_OVERRIDE_LEVEL_SOUNDS      21
-#define SETUP_TOKEN_OVERRIDE_LEVEL_MUSIC       22
-
-#define NUM_GLOBAL_SETUP_TOKENS                        23
+#define SETUP_TOKEN_SHOW_TITLESCREEN           10
+#define SETUP_TOKEN_QUICK_DOORS                        11
+#define SETUP_TOKEN_TEAM_MODE                  12
+#define SETUP_TOKEN_HANDICAP                   13
+#define SETUP_TOKEN_SKIP_LEVELS                        14
+#define SETUP_TOKEN_TIME_LIMIT                 15
+#define SETUP_TOKEN_FULLSCREEN                 16
+#define SETUP_TOKEN_ASK_ON_ESCAPE              17
+#define SETUP_TOKEN_ASK_ON_ESCAPE_EDITOR       18
+#define SETUP_TOKEN_QUICK_SWITCH               19
+#define SETUP_TOKEN_INPUT_ON_FOCUS             20
+#define SETUP_TOKEN_PREFER_AGA_GRAPHICS                21
+#define SETUP_TOKEN_GRAPHICS_SET               22
+#define SETUP_TOKEN_SOUNDS_SET                 23
+#define SETUP_TOKEN_MUSIC_SET                  24
+#define SETUP_TOKEN_OVERRIDE_LEVEL_GRAPHICS    25
+#define SETUP_TOKEN_OVERRIDE_LEVEL_SOUNDS      26
+#define SETUP_TOKEN_OVERRIDE_LEVEL_MUSIC       27
+
+#define NUM_GLOBAL_SETUP_TOKENS                        28
 
 /* editor setup */
 #define SETUP_TOKEN_EDITOR_EL_BOULDERDASH      0
@@ -4218,18 +6878,44 @@ void SaveScore(int nr)
 #define SETUP_TOKEN_EDITOR_EL_DX_BOULDERDASH   7
 #define SETUP_TOKEN_EDITOR_EL_CHARS            8
 #define SETUP_TOKEN_EDITOR_EL_CUSTOM           9
-#define SETUP_TOKEN_EDITOR_EL_CUSTOM_MORE      10
-#define SETUP_TOKEN_EDITOR_EL_HEADLINES                11
-#define SETUP_TOKEN_EDITOR_EL_USER_DEFINED     12
-
-#define NUM_EDITOR_SETUP_TOKENS                        13
+#define SETUP_TOKEN_EDITOR_EL_HEADLINES                10
+#define SETUP_TOKEN_EDITOR_EL_USER_DEFINED     11
+#define SETUP_TOKEN_EDITOR_EL_DYNAMIC          12
+#define SETUP_TOKEN_EDITOR_EL_BY_GAME          13
+#define SETUP_TOKEN_EDITOR_EL_BY_TYPE          14
+#define SETUP_TOKEN_EDITOR_SHOW_ELEMENT_TOKEN  15
+
+#define NUM_EDITOR_SETUP_TOKENS                        16
+
+/* editor cascade setup */
+#define SETUP_TOKEN_EDITOR_CASCADE_BD          0
+#define SETUP_TOKEN_EDITOR_CASCADE_EM          1
+#define SETUP_TOKEN_EDITOR_CASCADE_EMC         2
+#define SETUP_TOKEN_EDITOR_CASCADE_RND         3
+#define SETUP_TOKEN_EDITOR_CASCADE_SB          4
+#define SETUP_TOKEN_EDITOR_CASCADE_SP          5
+#define SETUP_TOKEN_EDITOR_CASCADE_DC          6
+#define SETUP_TOKEN_EDITOR_CASCADE_DX          7
+#define SETUP_TOKEN_EDITOR_CASCADE_TEXT                8
+#define SETUP_TOKEN_EDITOR_CASCADE_CE          9
+#define SETUP_TOKEN_EDITOR_CASCADE_GE          10
+#define SETUP_TOKEN_EDITOR_CASCADE_REF         11
+#define SETUP_TOKEN_EDITOR_CASCADE_USER                12
+#define SETUP_TOKEN_EDITOR_CASCADE_DYNAMIC     13
+
+#define NUM_EDITOR_CASCADE_SETUP_TOKENS                14
 
 /* shortcut setup */
 #define SETUP_TOKEN_SHORTCUT_SAVE_GAME         0
 #define SETUP_TOKEN_SHORTCUT_LOAD_GAME         1
 #define SETUP_TOKEN_SHORTCUT_TOGGLE_PAUSE      2
+#define SETUP_TOKEN_SHORTCUT_FOCUS_PLAYER_1    3
+#define SETUP_TOKEN_SHORTCUT_FOCUS_PLAYER_2    4
+#define SETUP_TOKEN_SHORTCUT_FOCUS_PLAYER_3    5
+#define SETUP_TOKEN_SHORTCUT_FOCUS_PLAYER_4    6
+#define SETUP_TOKEN_SHORTCUT_FOCUS_PLAYER_ALL  7
 
-#define NUM_SHORTCUT_SETUP_TOKENS              3
+#define NUM_SHORTCUT_SETUP_TOKENS              8
 
 /* player setup */
 #define SETUP_TOKEN_PLAYER_USE_JOYSTICK                0
@@ -4265,6 +6951,7 @@ void SaveScore(int nr)
 
 static struct SetupInfo si;
 static struct SetupEditorInfo sei;
+static struct SetupEditorCascadeInfo seci;
 static struct SetupShortcutInfo ssi;
 static struct SetupInputInfo sii;
 static struct SetupSystemInfo syi;
@@ -4282,6 +6969,7 @@ static struct TokenInfo global_setup_tokens[] =
   { TYPE_SWITCH, &si.soft_scrolling,   "soft_scrolling"                },
   { TYPE_SWITCH, &si.fading,           "screen_fading"                 },
   { TYPE_SWITCH, &si.autorecord,       "automatic_tape_recording"      },
+  { TYPE_SWITCH, &si.show_titlescreen, "show_titlescreen"              },
   { TYPE_SWITCH, &si.quick_doors,      "quick_doors"                   },
   { TYPE_SWITCH, &si.team_mode,                "team_mode"                     },
   { TYPE_SWITCH, &si.handicap,         "handicap"                      },
@@ -4289,6 +6977,10 @@ static struct TokenInfo global_setup_tokens[] =
   { TYPE_SWITCH, &si.time_limit,       "time_limit"                    },
   { TYPE_SWITCH, &si.fullscreen,       "fullscreen"                    },
   { TYPE_SWITCH, &si.ask_on_escape,    "ask_on_escape"                 },
+  { TYPE_SWITCH, &si.ask_on_escape_editor, "ask_on_escape_editor"      },
+  { TYPE_SWITCH, &si.quick_switch,     "quick_player_switch"           },
+  { TYPE_SWITCH, &si.input_on_focus,   "input_on_focus"                },
+  { TYPE_SWITCH, &si.prefer_aga_graphics, "prefer_aga_graphics"                },
   { TYPE_STRING, &si.graphics_set,     "graphics_set"                  },
   { TYPE_STRING, &si.sounds_set,       "sounds_set"                    },
   { TYPE_STRING, &si.music_set,                "music_set"                     },
@@ -4297,8 +6989,19 @@ static struct TokenInfo global_setup_tokens[] =
   { TYPE_SWITCH, &si.override_level_music,    "override_level_music"   },
 };
 
+static boolean not_used = FALSE;
 static struct TokenInfo editor_setup_tokens[] =
 {
+#if 1
+  { TYPE_SWITCH, &not_used,            "editor.el_boulderdash"         },
+  { TYPE_SWITCH, &not_used,            "editor.el_emerald_mine"        },
+  { TYPE_SWITCH, &not_used,            "editor.el_emerald_mine_club"   },
+  { TYPE_SWITCH, &not_used,            "editor.el_more"                },
+  { TYPE_SWITCH, &not_used,            "editor.el_sokoban"             },
+  { TYPE_SWITCH, &not_used,            "editor.el_supaplex"            },
+  { TYPE_SWITCH, &not_used,            "editor.el_diamond_caves"       },
+  { TYPE_SWITCH, &not_used,            "editor.el_dx_boulderdash"      },
+#else
   { TYPE_SWITCH, &sei.el_boulderdash,  "editor.el_boulderdash"         },
   { TYPE_SWITCH, &sei.el_emerald_mine, "editor.el_emerald_mine"        },
   { TYPE_SWITCH, &sei.el_emerald_mine_club,"editor.el_emerald_mine_club"},
@@ -4307,18 +7010,49 @@ static struct TokenInfo editor_setup_tokens[] =
   { 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"     },
+#endif
   { TYPE_SWITCH, &sei.el_chars,                "editor.el_chars"               },
   { TYPE_SWITCH, &sei.el_custom,       "editor.el_custom"              },
-  { TYPE_SWITCH, &sei.el_custom_more,  "editor.el_custom_more"         },
+#if 1
+  { TYPE_SWITCH, &not_used,            "editor.el_headlines"           },
+#else
   { TYPE_SWITCH, &sei.el_headlines,    "editor.el_headlines"           },
+#endif
   { TYPE_SWITCH, &sei.el_user_defined, "editor.el_user_defined"        },
+  { TYPE_SWITCH, &sei.el_dynamic,      "editor.el_dynamic"             },
+  { TYPE_SWITCH, &sei.el_by_game,      "editor.el_by_game"             },
+  { TYPE_SWITCH, &sei.el_by_type,      "editor.el_by_type"             },
+  { TYPE_SWITCH, &sei.show_element_token,"editor.show_element_token"   },
+};
+
+static struct TokenInfo editor_cascade_setup_tokens[] =
+{
+  { TYPE_SWITCH, &seci.el_bd,          "editor.cascade.el_bd"          },
+  { TYPE_SWITCH, &seci.el_em,          "editor.cascade.el_em"          },
+  { TYPE_SWITCH, &seci.el_emc,         "editor.cascade.el_emc"         },
+  { TYPE_SWITCH, &seci.el_rnd,         "editor.cascade.el_rnd"         },
+  { TYPE_SWITCH, &seci.el_sb,          "editor.cascade.el_sb"          },
+  { TYPE_SWITCH, &seci.el_sp,          "editor.cascade.el_sp"          },
+  { TYPE_SWITCH, &seci.el_dc,          "editor.cascade.el_dc"          },
+  { TYPE_SWITCH, &seci.el_dx,          "editor.cascade.el_dx"          },
+  { TYPE_SWITCH, &seci.el_chars,       "editor.cascade.el_chars"       },
+  { TYPE_SWITCH, &seci.el_ce,          "editor.cascade.el_ce"          },
+  { TYPE_SWITCH, &seci.el_ge,          "editor.cascade.el_ge"          },
+  { TYPE_SWITCH, &seci.el_ref,         "editor.cascade.el_ref"         },
+  { TYPE_SWITCH, &seci.el_user,                "editor.cascade.el_user"        },
+  { TYPE_SWITCH, &seci.el_dynamic,     "editor.cascade.el_dynamic"     },
 };
 
 static struct TokenInfo shortcut_setup_tokens[] =
 {
   { 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"         }
+  { TYPE_KEY_X11, &ssi.toggle_pause,   "shortcut.toggle_pause"         },
+  { TYPE_KEY_X11, &ssi.focus_player[0],        "shortcut.focus_player_1"       },
+  { TYPE_KEY_X11, &ssi.focus_player[1],        "shortcut.focus_player_2"       },
+  { TYPE_KEY_X11, &ssi.focus_player[2],        "shortcut.focus_player_3"       },
+  { TYPE_KEY_X11, &ssi.focus_player[3],        "shortcut.focus_player_4"       },
+  { TYPE_KEY_X11, &ssi.focus_player_all,"shortcut.focus_player_all"    },
 };
 
 static struct TokenInfo player_setup_tokens[] =
@@ -4338,18 +7072,18 @@ static struct TokenInfo player_setup_tokens[] =
   { TYPE_KEY_X11, &sii.key.up,         ".key.move_up"                  },
   { TYPE_KEY_X11, &sii.key.down,       ".key.move_down"                },
   { TYPE_KEY_X11, &sii.key.snap,       ".key.snap_field"               },
-  { TYPE_KEY_X11, &sii.key.drop,       ".key.place_bomb"               }
+  { TYPE_KEY_X11, &sii.key.drop,       ".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"        }
+  { TYPE_INTEGER, &syi.audio_fragment_size,"system.audio_fragment_size"        },
 };
 
 static struct TokenInfo options_setup_tokens[] =
 {
-  { TYPE_BOOLEAN, &soi.verbose,                "options.verbose"               }
+  { TYPE_BOOLEAN, &soi.verbose,                "options.verbose"               },
 };
 
 static char *get_corrected_login_name(char *login_name)
@@ -4384,6 +7118,7 @@ static void setSetupInfoToDefaults(struct SetupInfo *si)
   si->soft_scrolling = TRUE;
   si->fading = FALSE;
   si->autorecord = TRUE;
+  si->show_titlescreen = TRUE;
   si->quick_doors = FALSE;
   si->team_mode = FALSE;
   si->handicap = TRUE;
@@ -4391,6 +7126,10 @@ static void setSetupInfoToDefaults(struct SetupInfo *si)
   si->time_limit = TRUE;
   si->fullscreen = FALSE;
   si->ask_on_escape = TRUE;
+  si->ask_on_escape_editor = TRUE;
+  si->quick_switch = FALSE;
+  si->input_on_focus = FALSE;
+  si->prefer_aga_graphics = TRUE;
 
   si->graphics_set = getStringCopy(GFX_CLASSIC_SUBDIR);
   si->sounds_set = getStringCopy(SND_CLASSIC_SUBDIR);
@@ -4409,15 +7148,23 @@ static void setSetupInfoToDefaults(struct SetupInfo *si)
   si->editor.el_dx_boulderdash    = TRUE;
   si->editor.el_chars             = TRUE;
   si->editor.el_custom            = TRUE;
-  si->editor.el_custom_more       = FALSE;
 
   si->editor.el_headlines = TRUE;
   si->editor.el_user_defined = FALSE;
+  si->editor.el_dynamic = TRUE;
+
+  si->editor.show_element_token = FALSE;
 
   si->shortcut.save_game = DEFAULT_KEY_SAVE_GAME;
   si->shortcut.load_game = DEFAULT_KEY_LOAD_GAME;
   si->shortcut.toggle_pause = DEFAULT_KEY_TOGGLE_PAUSE;
 
+  si->shortcut.focus_player[0] = DEFAULT_KEY_FOCUS_PLAYER_1;
+  si->shortcut.focus_player[1] = DEFAULT_KEY_FOCUS_PLAYER_2;
+  si->shortcut.focus_player[2] = DEFAULT_KEY_FOCUS_PLAYER_3;
+  si->shortcut.focus_player[3] = DEFAULT_KEY_FOCUS_PLAYER_4;
+  si->shortcut.focus_player_all = DEFAULT_KEY_FOCUS_PLAYER_ALL;
+
   for (i = 0; i < MAX_PLAYERS; i++)
   {
     si->input[i].use_joystick = FALSE;
@@ -4444,6 +7191,25 @@ static void setSetupInfoToDefaults(struct SetupInfo *si)
   si->options.verbose = FALSE;
 }
 
+static void setSetupInfoToDefaults_EditorCascade(struct SetupInfo *si)
+{
+  si->editor_cascade.el_bd     = TRUE;
+  si->editor_cascade.el_em     = TRUE;
+  si->editor_cascade.el_emc    = TRUE;
+  si->editor_cascade.el_rnd    = TRUE;
+  si->editor_cascade.el_sb     = TRUE;
+  si->editor_cascade.el_sp     = TRUE;
+  si->editor_cascade.el_dc     = TRUE;
+  si->editor_cascade.el_dx     = TRUE;
+
+  si->editor_cascade.el_chars  = FALSE;
+  si->editor_cascade.el_ce     = FALSE;
+  si->editor_cascade.el_ge     = FALSE;
+  si->editor_cascade.el_ref    = FALSE;
+  si->editor_cascade.el_user   = FALSE;
+  si->editor_cascade.el_dynamic        = FALSE;
+}
+
 static void decodeSetupFileHash(SetupFileHash *setup_file_hash)
 {
   int i, pnr;
@@ -4506,6 +7272,22 @@ static void decodeSetupFileHash(SetupFileHash *setup_file_hash)
   setup.options = soi;
 }
 
+static void decodeSetupFileHash_EditorCascade(SetupFileHash *setup_file_hash)
+{
+  int i;
+
+  if (!setup_file_hash)
+    return;
+
+  /* editor cascade setup */
+  seci = setup.editor_cascade;
+  for (i = 0; i < NUM_EDITOR_CASCADE_SETUP_TOKENS; i++)
+    setSetupInfo(editor_cascade_setup_tokens, i,
+                getHashEntry(setup_file_hash,
+                             editor_cascade_setup_tokens[i].text));
+  setup.editor_cascade = seci;
+}
+
 void LoadSetup()
 {
   char *filename = getSetupFilename();
@@ -4520,7 +7302,7 @@ void LoadSetup()
   {
     char *player_name_new;
 
-    checkSetupFileHashIdentifier(setup_file_hash, getCookie("SETUP"));
+    checkSetupFileHashIdentifier(setup_file_hash, filename,getCookie("SETUP"));
     decodeSetupFileHash(setup_file_hash);
 
     setup.direct_draw = !setup.double_buffering;
@@ -4536,6 +7318,27 @@ void LoadSetup()
     Error(ERR_WARN, "using default setup values");
 }
 
+void LoadSetup_EditorCascade()
+{
+  char *filename = getPath2(getSetupDir(), EDITORCASCADE_FILENAME);
+  SetupFileHash *setup_file_hash = NULL;
+
+  /* always start with reliable default values */
+  setSetupInfoToDefaults_EditorCascade(&setup);
+
+  setup_file_hash = loadSetupFileHash(filename);
+
+  if (setup_file_hash)
+  {
+    checkSetupFileHashIdentifier(setup_file_hash, filename,getCookie("SETUP"));
+    decodeSetupFileHash_EditorCascade(setup_file_hash);
+
+    freeSetupFileHash(setup_file_hash);
+  }
+
+  free(filename);
+}
+
 void SaveSetup()
 {
   char *filename = getSetupFilename();
@@ -4608,6 +7411,37 @@ void SaveSetup()
   SetFilePermissions(filename, PERMS_PRIVATE);
 }
 
+void SaveSetup_EditorCascade()
+{
+  char *filename = getPath2(getSetupDir(), EDITORCASCADE_FILENAME);
+  FILE *file;
+  int i;
+
+  InitUserDataDirectory();
+
+  if (!(file = fopen(filename, MODE_WRITE)))
+  {
+    Error(ERR_WARN, "cannot write editor cascade state file '%s'", filename);
+    free(filename);
+    return;
+  }
+
+  fprintf(file, "%s\n", getFormattedSetupEntry(TOKEN_STR_FILE_IDENTIFIER,
+                                              getCookie("SETUP")));
+  fprintf(file, "\n");
+
+  seci = setup.editor_cascade;
+  fprintf(file, "\n");
+  for (i = 0; i < NUM_EDITOR_CASCADE_SETUP_TOKENS; i++)
+    fprintf(file, "%s\n", getSetupLine(editor_cascade_setup_tokens, "", i));
+
+  fclose(file);
+
+  SetFilePermissions(filename, PERMS_PRIVATE);
+
+  free(filename);
+}
+
 void LoadCustomElementDescriptions()
 {
   char *filename = getCustomArtworkConfigFilename(ARTWORK_TYPE_GRAPHICS);
@@ -4640,19 +7474,14 @@ void LoadCustomElementDescriptions()
   freeSetupFileHash(setup_file_hash);
 }
 
-void LoadSpecialMenuDesignSettings()
+static void LoadSpecialMenuDesignSettingsFromFilename(char *filename)
 {
-  char *filename = getCustomArtworkConfigFilename(ARTWORK_TYPE_GRAPHICS);
   SetupFileHash *setup_file_hash;
-  int i, j;
+  int i;
 
-  /* 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_auto_parameter_value(image_config_vars[i].token,
-                                  image_config[j].value);
+#if 0
+  printf("LoadSpecialMenuDesignSettings from file '%s' ...\n", filename);
+#endif
 
   if ((setup_file_hash = loadSetupFileHash(filename)) == NULL)
     return;
@@ -4685,6 +7514,42 @@ void LoadSpecialMenuDesignSettings()
   freeSetupFileHash(setup_file_hash);
 }
 
+void LoadSpecialMenuDesignSettings()
+{
+  char *filename_base = UNDEFINED_FILENAME, *filename_local;
+  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 (strEqual(image_config_vars[i].token, image_config[j].token))
+       *image_config_vars[i].value =
+         get_auto_parameter_value(image_config_vars[i].token,
+                                  image_config[j].value);
+
+#if 1
+  if (!SETUP_OVERRIDE_ARTWORK(setup, ARTWORK_TYPE_GRAPHICS))
+  {
+    /* first look for special settings configured in level series config */
+    filename_base = getCustomArtworkLevelConfigFilename(ARTWORK_TYPE_GRAPHICS);
+
+    if (fileExists(filename_base))
+      LoadSpecialMenuDesignSettingsFromFilename(filename_base);
+  }
+
+  filename_local = getCustomArtworkConfigFilename(ARTWORK_TYPE_GRAPHICS);
+
+  if (filename_local != NULL && !strEqual(filename_base, filename_local))
+    LoadSpecialMenuDesignSettingsFromFilename(filename_local);
+
+#else
+
+  filename_local = getCustomArtworkConfigFilename(ARTWORK_TYPE_GRAPHICS);
+
+  LoadSpecialMenuDesignSettingsFromFilename(filename_local);
+#endif
+}
+
 void LoadUserDefinedEditorElementList(int **elements, int *num_elements)
 {
   char *filename = getEditorSetupFilename();
@@ -4709,6 +7574,10 @@ void LoadUserDefinedEditorElementList(int **elements, int *num_elements)
   /* add space for up to 3 more elements for padding that may be needed */
   *num_elements += 3;
 
+  /* free memory for old list of elements, if needed */
+  checked_free(*elements);
+
+  /* allocate memory for new list of elements */
   *elements = checked_malloc(*num_elements * sizeof(int));
 
   *num_elements = 0;
@@ -4757,7 +7626,6 @@ void LoadUserDefinedEditorElementList(int **elements, int *num_elements)
   freeSetupFileHash(element_hash);
 
 #if 0
-  /* TEST-ONLY */
   for (i = 0; i < *num_elements; i++)
     printf("editor: element '%s' [%d]\n",
           element_info[(*elements)[i]].token_name, (*elements)[i]);
@@ -4871,7 +7739,7 @@ static boolean music_info_listed_ext(struct MusicFileInfo *list,
                                     char *basename, boolean is_sound)
 {
   for (; list != NULL; list = list->next)
-    if (list->is_sound == is_sound && strcmp(list->basename, basename) == 0)
+    if (list->is_sound == is_sound && strEqual(list->basename, basename))
       return TRUE;
 
   return FALSE;
@@ -4922,22 +7790,14 @@ void LoadMusicInfo()
 
   new = &music_file_info;
 
-#if 0
-  printf("::: num_music == %d\n", num_music);
-#endif
-
   for (i = 0; i < num_music; i++)
   {
     music = getMusicListEntry(i);
 
-#if 0
-    printf("::: %d [%08x]\n", i, music->filename);
-#endif
-
     if (music->filename == NULL)
       continue;
 
-    if (strcmp(music->filename, UNDEFINED_FILENAME) == 0)
+    if (strEqual(music->filename, UNDEFINED_FILENAME))
       continue;
 
     /* a configured file may be not recognized as music */
@@ -4976,7 +7836,7 @@ void LoadMusicInfo()
       if (music->filename == NULL)
        continue;
 
-      if (strcmp(basename, music->filename) == 0)
+      if (strEqual(basename, music->filename))
       {
        music_already_used = TRUE;
        break;
@@ -5012,7 +7872,7 @@ void LoadMusicInfo()
     if (sound->filename == NULL)
       continue;
 
-    if (strcmp(sound->filename, UNDEFINED_FILENAME) == 0)
+    if (strEqual(sound->filename, UNDEFINED_FILENAME))
       continue;
 
     /* a configured file may be not recognized as sound */
@@ -5032,7 +7892,6 @@ void LoadMusicInfo()
   }
 
 #if 0
-  /* TEST-ONLY */
   for (next = music_file_info; next != NULL; next = next->next)
     printf("::: title == '%s'\n", next->title);
 #endif
@@ -5112,7 +7971,7 @@ void LoadHelpAnimInfo()
                 i_to_a(element_action_info[i].value));
 
   /* do not store direction index (bit) here, but direction value! */
-  for (i = 0; i < NUM_DIRECTIONS; i++)
+  for (i = 0; i < NUM_DIRECTIONS_FULL; i++)
     setHashEntry(direction_hash, element_direction_info[i].suffix,
                 i_to_a(1 << element_direction_info[i].value));
 
@@ -5122,7 +7981,7 @@ void LoadHelpAnimInfo()
     char *element_value, *action_value, *direction_value;
     int delay = atoi(list->value);
 
-    if (strcmp(list->token, "end") == 0)
+    if (strEqual(list->token, "end"))
     {
       add_helpanim_entry(HELPANIM_LIST_NEXT, -1, -1, -1, &num_list_entries);
 
@@ -5273,9 +8132,9 @@ void LoadHelpAnimInfo()
   freeSetupFileHash(direction_hash);
 
 #if 0
-  /* TEST ONLY */
   for (i = 0; i < num_list_entries; i++)
-    printf("::: %d, %d, %d => %d\n",
+    printf("::: '%s': %d, %d, %d => %d\n",
+          EL_NAME(helpanim_info[i].element),
           helpanim_info[i].element,
           helpanim_info[i].action,
           helpanim_info[i].direction,
@@ -5309,7 +8168,6 @@ void LoadHelpTextInfo()
   }
 
 #if 0
-  /* TEST ONLY */
   BEGIN_HASH_ITERATION(helptext_info, itr)
   {
     printf("::: '%s' => '%s'\n",
index 9a0cf0ff04b476086d101b065db3ffcc7d830de0..1eadf1eb0420592d40e4fa6112560c600488f59e 100644 (file)
@@ -29,6 +29,7 @@
 
 void setElementChangePages(struct ElementInfo *, int);
 void setElementChangeInfoToDefaults(struct ElementChangeInfo *);
+void copyElementInfo(struct ElementInfo *, struct ElementInfo *);
 
 char *getDefaultLevelFilename(int);
 
@@ -54,6 +55,9 @@ void SaveScore(int);
 void LoadSetup();
 void SaveSetup();
 
+void LoadSetup_EditorCascade();
+void SaveSetup_EditorCascade();
+
 void LoadCustomElementDescriptions();
 void LoadSpecialMenuDesignSettings();
 void LoadUserDefinedEditorElementList(int **, int *);
index b0d7ec6bfd1a670820bce99d0111fd67b8c7db58..f06c86d855c06673b6c050100ba3bb9aafc7947c 100644 (file)
 #include "tape.h"
 #include "network.h"
 
-/* this switch controls how rocks move horizontally */
-#define OLD_GAME_BEHAVIOUR     FALSE
-
 /* EXPERIMENTAL STUFF */
 #define USE_NEW_AMOEBA_CODE    FALSE
 
 /* EXPERIMENTAL STUFF */
-#define USE_NEW_STUFF                  (TRUE                           * 1)
-
-#define USE_NEW_MOVE_STYLE             (TRUE   * USE_NEW_STUFF         * 1)
-#define USE_NEW_MOVE_DELAY             (TRUE   * USE_NEW_STUFF         * 1)
-#define USE_NEW_PUSH_DELAY             (TRUE   * USE_NEW_STUFF         * 1)
-#define USE_NEW_BLOCK_STYLE            (TRUE   * USE_NEW_STUFF         * 1)
-#define USE_NEW_SP_SLIPPERY            (TRUE   * USE_NEW_STUFF         * 1)
-#define USE_NEW_RANDOMIZE              (TRUE   * USE_NEW_STUFF         * 1)
-
-#define USE_CAN_MOVE_NOT_MOVING                (TRUE   * USE_NEW_STUFF         * 1)
-#define USE_PREVIOUS_MOVE_DIR          (TRUE   * USE_NEW_STUFF         * 1)
-
-#define USE_PUSH_BUGFIX                        (TRUE   * USE_NEW_STUFF         * 1)
-#if 0
-#define USE_BLOCK_DELAY_BUGFIX         (TRUE   * USE_NEW_STUFF         * 1)
-#endif
-#define USE_GRAVITY_BUGFIX_NEW         (TRUE   * USE_NEW_STUFF         * 1)
-#define USE_GRAVITY_BUGFIX_OLD         (TRUE   * USE_NEW_STUFF         * 0)
-
-#define USE_PENGUIN_COLLECT_BUGFIX     (TRUE   * USE_NEW_STUFF         * 1)
-
-#define USE_IMPACT_BUGFIX              (TRUE   * USE_NEW_STUFF         * 1)
-
-#define USE_HITTING_SOMETHING_BUGFIX   (TRUE   * USE_NEW_STUFF         * 1)
-#define USE_HIT_BY_SOMETHING_BUGFIX    (TRUE   * USE_NEW_STUFF         * 1)
-
-#define USE_DROP_BUGFIX                        (TRUE   * USE_NEW_STUFF         * 1)
-
-#define USE_CHANGE_TO_TRIGGERED                (TRUE   * USE_NEW_STUFF         * 1)
-
+#define USE_NEW_STUFF                  (                         1)
+
+#define USE_NEW_SP_SLIPPERY            (USE_NEW_STUFF          * 1)
+#define USE_NEW_CUSTOM_VALUE           (USE_NEW_STUFF          * 1)
+#define USE_NEW_PLAYER_ANIM            (USE_NEW_STUFF          * 1)
+#define USE_NEW_ALL_SLIPPERY           (USE_NEW_STUFF          * 1)
+#define USE_NEW_PLAYER_SPEED           (USE_NEW_STUFF          * 1)
+#define USE_NEW_DELAYED_ACTION         (USE_NEW_STUFF          * 1)
+#define USE_NEW_SNAP_DELAY             (USE_NEW_STUFF          * 1)
+#define USE_ONLY_ONE_CHANGE_PER_FRAME  (USE_NEW_STUFF          * 1)
+#define USE_ONE_MORE_CHANGE_PER_FRAME  (USE_NEW_STUFF          * 1)
+#define USE_FIXED_DONT_RUN_INTO                (USE_NEW_STUFF          * 1)
+#define USE_NEW_SPRING_BUMPER          (USE_NEW_STUFF          * 1)
+#define USE_STOP_CHANGED_ELEMENTS      (USE_NEW_STUFF          * 1)
+#define USE_ELEMENT_TOUCHING_BUGFIX    (USE_NEW_STUFF          * 1)
+#define USE_NEW_CONTINUOUS_SNAPPING    (USE_NEW_STUFF          * 1)
+#define USE_GFX_RESET_GFX_ANIMATION    (USE_NEW_STUFF          * 1)
+#define USE_BOTH_SWITCHGATE_SWITCHES   (USE_NEW_STUFF          * 1)
+#define USE_PLAYER_GRAVITY             (USE_NEW_STUFF          * 1)
+#define USE_FIXED_BORDER_RUNNING_GFX   (USE_NEW_STUFF          * 1)
+#define USE_QUICKSAND_BD_ROCK_BUGFIX   (USE_NEW_STUFF          * 0)
+
+#define USE_QUICKSAND_IMPACT_BUGFIX    (USE_NEW_STUFF          * 0)
 
 /* for DigField() */
 #define DF_NO_PUSH             0
 #define DF_SNAP                        2
 
 /* for MovePlayer() */
-#define MF_NO_ACTION           0
-#define MF_MOVING              1
-#define MF_ACTION              2
+#define MP_NO_ACTION           0
+#define MP_MOVING              1
+#define MP_ACTION              2
+#define MP_DONT_RUN_INTO       (MP_MOVING | MP_ACTION)
 
 /* for ScrollPlayer() */
 #define SCROLL_INIT            0
 #define SCROLL_GO_ON           1
 
-/* for Explode() */
+/* for Bang()/Explode() */
 #define EX_PHASE_START         0
 #define EX_TYPE_NONE           0
 #define EX_TYPE_NORMAL         (1 << 0)
 #define EX_TYPE_CENTER         (1 << 1)
 #define EX_TYPE_BORDER         (1 << 2)
 #define EX_TYPE_CROSS          (1 << 3)
+#define EX_TYPE_DYNA           (1 << 4)
 #define EX_TYPE_SINGLE_TILE    (EX_TYPE_CENTER | EX_TYPE_BORDER)
 
 /* special positions in the game control window (relative to control window) */
 #define DX_TIME2               (DX + XX_TIME2)
 #define DY_TIME                        (DY + YY_TIME)
 
+/* values for delayed check of falling and moving elements and for collision */
+#define CHECK_DELAY_MOVING     3
+#define CHECK_DELAY_FALLING    3
+#define CHECK_DELAY_COLLISION  2
+
 /* values for initial player move delay (initial delay counter value) */
 #define INITIAL_MOVE_DELAY_OFF -1
 #define INITIAL_MOVE_DELAY_ON  0
 
 /* values for player movement speed (which is in fact a delay value) */
+#define MOVE_DELAY_MIN_SPEED   32
 #define MOVE_DELAY_NORMAL_SPEED        8
 #define MOVE_DELAY_HIGH_SPEED  4
+#define MOVE_DELAY_MAX_SPEED   1
 
+#if 0
 #define DOUBLE_MOVE_DELAY(x)   (x = (x <= MOVE_DELAY_HIGH_SPEED ? x * 2 : x))
 #define HALVE_MOVE_DELAY(x)    (x = (x >= MOVE_DELAY_HIGH_SPEED ? x / 2 : x))
+#else
+#define DOUBLE_MOVE_DELAY(x)   (x = (x < MOVE_DELAY_MIN_SPEED ? x * 2 : x))
+#define HALVE_MOVE_DELAY(x)    (x = (x > MOVE_DELAY_MAX_SPEED ? x / 2 : x))
+#endif
 #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 MOVE_STEPSIZE_MIN      (1)
+#define MOVE_STEPSIZE_MAX      (TILEX)
 
 #define GET_DX_FROM_DIR(d)     ((d) == MV_LEFT ? -1 : (d) == MV_RIGHT ? 1 : 0)
 #define GET_DY_FROM_DIR(d)     ((d) == MV_UP   ? -1 : (d) == MV_DOWN  ? 1 : 0)
                                 RND(element_info[e].move_delay_random))
 #define GET_MAX_MOVE_DELAY(e)  (   (element_info[e].move_delay_fixed) + \
                                    (element_info[e].move_delay_random))
+#define GET_NEW_CE_VALUE(e)    (   (element_info[e].ce_value_fixed_initial) +\
+                                RND(element_info[e].ce_value_random_initial))
+#define GET_CE_SCORE(e)                (   (element_info[e].collect_score))
+#define GET_CHANGE_DELAY(c)    (   ((c)->delay_fixed  * (c)->delay_frames) + \
+                                RND((c)->delay_random * (c)->delay_frames))
+#define GET_CE_DELAY_VALUE(c)  (   ((c)->delay_fixed) + \
+                                RND((c)->delay_random))
 
-#define GET_TARGET_ELEMENT(e, ch)                                      \
-       ((e) == EL_TRIGGER_ELEMENT ? (ch)->actual_trigger_element :     \
-        (e) == EL_TRIGGER_PLAYER  ? (ch)->actual_trigger_player : (e))
 
-#define GET_VALID_PLAYER_ELEMENT(e)                                    \
-       ((e) >= EL_PLAYER_1 && (e) <= EL_PLAYER_4 ? (e) : EL_PLAYER_1)
+#if 1
+#define GET_VALID_RUNTIME_ELEMENT(e)                                   \
+        ((e) >= NUM_RUNTIME_ELEMENTS ? EL_UNKNOWN : (e))
+#else
+#define GET_VALID_FILE_ELEMENT(e)                                      \
+       ((e) >= NUM_FILE_ELEMENTS ? EL_UNKNOWN : (e))
+#endif
+
+#define GET_TARGET_ELEMENT(e, ch, cv, cs)                              \
+       ((e) == EL_TRIGGER_PLAYER   ? (ch)->actual_trigger_player    :  \
+        (e) == EL_TRIGGER_ELEMENT  ? (ch)->actual_trigger_element   :  \
+        (e) == EL_TRIGGER_CE_VALUE ? (ch)->actual_trigger_ce_value  :  \
+        (e) == EL_TRIGGER_CE_SCORE ? (ch)->actual_trigger_ce_score  :  \
+        (e) == EL_CURRENT_CE_VALUE ? (cv) :                            \
+        (e) == EL_CURRENT_CE_SCORE ? (cs) : (e))
 
 #define CAN_GROW_INTO(e)                                               \
        ((e) == EL_SAND || (IS_DIGGABLE(e) && level.grow_into_diggable))
                                         IS_PLAYER(x, y) &&             \
                                         !PLAYER_ENEMY_PROTECTED(x, y))))
 
-#if 0
-#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_PLAYER(x, y) &&             \
-                                        !PLAYER_ENEMY_PROTECTED(x, y))))
-#endif
-
 #define ELEMENT_CAN_ENTER_FIELD(e, x, y)                               \
        ELEMENT_CAN_ENTER_FIELD_BASE_4(e, x, y, 0)
 
-#if 1
 #define SATELLITE_CAN_ENTER_FIELD(x, y)                                        \
        ELEMENT_CAN_ENTER_FIELD_BASE_2(EL_SATELLITE, x, y, 0)
-#else
-#define SATELLITE_CAN_ENTER_FIELD(x, y)                                        \
-       ELEMENT_CAN_ENTER_FIELD_BASE_X(x, y, Feld[x][y] == EL_ACID)
-#endif
 
-#if 0
-#define ENEMY_CAN_ENTER_FIELD(e, x, y) (IN_LEV_FIELD(x, y) && IS_FREE(x, y))
-#endif
+#define ANDROID_CAN_ENTER_FIELD(e, x, y)                               \
+       ELEMENT_CAN_ENTER_FIELD_BASE_2(e, x, y, Feld[x][y] == EL_EMC_PLANT)
+
+#define ANDROID_CAN_CLONE_FIELD(x, y)                                  \
+       (IN_LEV_FIELD(x, y) && (CAN_BE_CLONED_BY_ANDROID(Feld[x][y]) || \
+                               CAN_BE_CLONED_BY_ANDROID(EL_TRIGGER_ELEMENT)))
 
 #define ENEMY_CAN_ENTER_FIELD(e, x, y)                                 \
        ELEMENT_CAN_ENTER_FIELD_BASE_2(e, x, y, 0)
 
-#if 1
-
 #define YAMYAM_CAN_ENTER_FIELD(e, x, y)                                        \
        ELEMENT_CAN_ENTER_FIELD_BASE_3(e, x, y, Feld[x][y] == EL_DIAMOND)
 
 #define SPRING_CAN_ENTER_FIELD(e, x, y)                                        \
        ELEMENT_CAN_ENTER_FIELD_BASE_2(e, x, y, 0)
 
-#else
-
-#define YAMYAM_CAN_ENTER_FIELD(e, x, y)                                        \
-               (IN_LEV_FIELD(x, y) && (IS_FREE_OR_PLAYER(x, y) ||      \
-                                       (CAN_MOVE_INTO_ACID(e) &&       \
-                                        Feld[x][y] == EL_ACID) ||      \
-                                       Feld[x][y] == EL_DIAMOND))
-
-#define DARK_YAMYAM_CAN_ENTER_FIELD(e, x, y)                           \
-               (IN_LEV_FIELD(x, y) && (IS_FREE_OR_PLAYER(x, y) ||      \
-                                       (CAN_MOVE_INTO_ACID(e) &&       \
-                                        Feld[x][y] == EL_ACID) ||      \
-                                       IS_FOOD_DARK_YAMYAM(Feld[x][y])))
-
-#define PACMAN_CAN_ENTER_FIELD(e, x, y)                                        \
-               (IN_LEV_FIELD(x, y) && (IS_FREE_OR_PLAYER(x, y) ||      \
-                                       (CAN_MOVE_INTO_ACID(e) &&       \
-                                        Feld[x][y] == EL_ACID) ||      \
-                                       IS_AMOEBOID(Feld[x][y])))
-
-#define PIG_CAN_ENTER_FIELD(e, x, y)                                   \
-               (IN_LEV_FIELD(x, y) && (IS_FREE(x, y) ||                \
-                                       (CAN_MOVE_INTO_ACID(e) &&       \
-                                        Feld[x][y] == EL_ACID) ||      \
-                                       IS_FOOD_PIG(Feld[x][y])))
-
-#define PENGUIN_CAN_ENTER_FIELD(e, x, y)                               \
-               (IN_LEV_FIELD(x, y) && (IS_FREE(x, y) ||                \
-                                       (CAN_MOVE_INTO_ACID(e) &&       \
-                                        Feld[x][y] == EL_ACID) ||      \
-                                       IS_FOOD_PENGUIN(Feld[x][y]) ||  \
-                                       Feld[x][y] == EL_EXIT_OPEN))
-
-#define DRAGON_CAN_ENTER_FIELD(e, x, y)                                        \
-               (IN_LEV_FIELD(x, y) && (IS_FREE(x, y) ||                \
-                                       (CAN_MOVE_INTO_ACID(e) &&       \
-                                        Feld[x][y] == EL_ACID)))
-
-#define MOLE_CAN_ENTER_FIELD(e, x, y, condition)                       \
-               (IN_LEV_FIELD(x, y) && (IS_FREE(x, y) ||                \
-                                       (CAN_MOVE_INTO_ACID(e) &&       \
-                                        Feld[x][y] == EL_ACID) ||      \
-                                       (condition)))
-
-#define SPRING_CAN_ENTER_FIELD(e, x, y)                                        \
-               (IN_LEV_FIELD(x, y) && (IS_FREE(x, y) ||                \
-                                       (CAN_MOVE_INTO_ACID(e) &&       \
-                                        Feld[x][y] == EL_ACID)))
-
-#endif
+#define SPRING_CAN_BUMP_FROM_FIELD(x, y)                               \
+       (IN_LEV_FIELD(x, y) && (Feld[x][y] == EL_EMC_SPRING_BUMPER ||   \
+                               Feld[x][y] == EL_EMC_SPRING_BUMPER_ACTIVE))
 
+#if 0
 #define GROUP_NR(e)            ((e) - EL_GROUP_START)
-#define MOVE_ENTER_EL(e)       (element_info[e].move_enter_element)
 #define IS_IN_GROUP(e, nr)     (element_info[e].in_group[nr] == TRUE)
 #define IS_IN_GROUP_EL(e, ge)  (IS_IN_GROUP(e, (ge) - EL_GROUP_START))
 
 #define IS_EQUAL_OR_IN_GROUP(e, ge)                                    \
        (IS_GROUP_ELEMENT(ge) ? IS_IN_GROUP(e, GROUP_NR(ge)) : (e) == (ge))
+#endif
+
+#define MOVE_ENTER_EL(e)       (element_info[e].move_enter_element)
 
-#if 0
-#define CE_ENTER_FIELD_COND(e, x, y)                                   \
-               (!IS_PLAYER(x, y) &&                                    \
-                (Feld[x][y] == EL_ACID ||                              \
-                 IS_EQUAL_OR_IN_GROUP(Feld[x][y], MOVE_ENTER_EL(e))))
-#else
 #define CE_ENTER_FIELD_COND(e, x, y)                                   \
                (!IS_PLAYER(x, y) &&                                    \
                 IS_EQUAL_OR_IN_GROUP(Feld[x][y], MOVE_ENTER_EL(e)))
-#endif
 
 #define CUSTOM_ELEMENT_CAN_ENTER_FIELD(e, x, y)                                \
        ELEMENT_CAN_ENTER_FIELD_BASE_4(e, x, y, CE_ENTER_FIELD_COND(e, x, y))
 
 /* forward declaration for internal use */
 
+static void CreateField(int, int, int);
+
+static void SetPlayerWaiting(struct PlayerInfo *, boolean);
 static void AdvanceFrameAndPlayerCounters(int);
 
 static boolean MovePlayerOneStep(struct PlayerInfo *, int, int, int, int);
@@ -337,8 +299,8 @@ static void InitBeltMovement(void);
 static void CloseAllOpenTimegates(void);
 static void CheckGravityMovement(struct PlayerInfo *);
 static void CheckGravityMovementWhenNotMoving(struct PlayerInfo *);
-static void KillHeroUnlessEnemyProtected(int, int);
-static void KillHeroUnlessExplosionProtected(int, int);
+static void KillPlayerUnlessEnemyProtected(int, int);
+static void KillPlayerUnlessExplosionProtected(int, int);
 
 static void TestIfPlayerTouchesCustomElement(int, int);
 static void TestIfElementTouchesCustomElement(int, int);
@@ -347,29 +309,27 @@ static void TestIfElementHitsCustomElement(int, int, int);
 static void TestIfElementSmashesCustomElement(int, int, int);
 #endif
 
-static void ChangeElement(int, int, int);
+static void HandleElementChange(int, int, int);
+static void ExecuteCustomElementAction(int, int, int, int);
+static boolean ChangeElement(int, int, int, int);
 
 static boolean CheckTriggeredElementChangeExt(int, int, int, int, int,int,int);
 #define CheckTriggeredElementChange(x, y, e, ev)                       \
-       CheckTriggeredElementChangeExt(x, y, e, ev, CH_PLAYER_ANY,      \
-                                      CH_SIDE_ANY, -1)
+       CheckTriggeredElementChangeExt(x,y,e,ev, CH_PLAYER_ANY,CH_SIDE_ANY, -1)
 #define CheckTriggeredElementChangeByPlayer(x, y, e, ev, p, s)         \
        CheckTriggeredElementChangeExt(x, y, e, ev, p, s, -1)
 #define CheckTriggeredElementChangeBySide(x, y, e, ev, s)              \
        CheckTriggeredElementChangeExt(x, y, e, ev, CH_PLAYER_ANY, s, -1)
 #define CheckTriggeredElementChangeByPage(x, y, e, ev, p)              \
-       CheckTriggeredElementChangeExt(x, y, e, ev, CH_PLAYER_ANY,      \
-                                      CH_SIDE_ANY, p)
+       CheckTriggeredElementChangeExt(x,y,e,ev, CH_PLAYER_ANY, CH_SIDE_ANY, p)
 
-static boolean CheckElementChangeExt(int, int, int, int, int, int, int, int);
+static boolean CheckElementChangeExt(int, int, int, int, int, int, int);
 #define CheckElementChange(x, y, e, te, ev)                            \
-       CheckElementChangeExt(x, y, e, te, ev, CH_PLAYER_ANY, CH_SIDE_ANY, -1)
+       CheckElementChangeExt(x, y, e, te, ev, CH_PLAYER_ANY, CH_SIDE_ANY)
 #define CheckElementChangeByPlayer(x, y, e, ev, p, s)                  \
-       CheckElementChangeExt(x, y, e, EL_EMPTY, ev, p, s, CH_PAGE_ANY)
+       CheckElementChangeExt(x, y, e, EL_EMPTY, ev, p, s)
 #define CheckElementChangeBySide(x, y, e, te, ev, s)                   \
-       CheckElementChangeExt(x, y, e, te, ev, CH_PLAYER_ANY, s, CH_PAGE_ANY)
-#define CheckElementChangeByPage(x, y, e, te, ev, p)                   \
-       CheckElementChangeExt(x, y, e, te, ev, CH_PLAYER_ANY, CH_SIDE_ANY, p)
+       CheckElementChangeExt(x, y, e, te, ev, CH_PLAYER_ANY, s)
 
 static void PlayLevelSound(int, int, int);
 static void PlayLevelSoundNearest(int, int, int);
@@ -383,6 +343,34 @@ static void PlayLevelMusic();
 static void MapGameButtons();
 static void HandleGameButtons(struct GadgetInfo *);
 
+int AmoebeNachbarNr(int, int);
+void AmoebeUmwandeln(int, int);
+void ContinueMoving(int, int);
+void Bang(int, int);
+void InitMovDir(int, int);
+void InitAmoebaNr(int, int);
+int NewHiScore(void);
+
+void TestIfGoodThingHitsBadThing(int, int, int);
+void TestIfBadThingHitsGoodThing(int, int, int);
+void TestIfPlayerTouchesBadThing(int, int);
+void TestIfPlayerRunsIntoBadThing(int, int, int);
+void TestIfBadThingTouchesPlayer(int, int);
+void TestIfBadThingRunsIntoPlayer(int, int, int);
+void TestIfFriendTouchesBadThing(int, int);
+void TestIfBadThingTouchesFriend(int, int);
+void TestIfBadThingTouchesOtherBadThing(int, int);
+
+void KillPlayer(struct PlayerInfo *);
+void BuryPlayer(struct PlayerInfo *);
+void RemovePlayer(struct PlayerInfo *);
+
+boolean SnapField(struct PlayerInfo *, int, int);
+boolean DropElement(struct PlayerInfo *);
+
+static int getInvisibleActiveFromInvisibleElement(int);
+static int getInvisibleFromInvisibleActiveElement(int);
+
 static struct GadgetInfo *game_gadget[NUM_GAME_BUTTONS];
 
 
@@ -392,19 +380,24 @@ static struct GadgetInfo *game_gadget[NUM_GAME_BUTTONS];
 /* ------------------------------------------------------------------------- */
 
 /* forward declaration for changer functions */
-static void InitBuggyBase(int x, int y);
-static void WarnBuggyBase(int x, int y);
+static void InitBuggyBase(int, int);
+static void WarnBuggyBase(int, int);
+
+static void InitTrap(int, int);
+static void ActivateTrap(int, int);
+static void ChangeActiveTrap(int, int);
 
-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, int);
+static void RunRobotWheel(int, int);
+static void StopRobotWheel(int, int);
 
-static void InitRobotWheel(int x, int y);
-static void RunRobotWheel(int x, int y);
-static void StopRobotWheel(int x, int y);
+static void InitTimegateWheel(int, int);
+static void RunTimegateWheel(int, int);
 
-static void InitTimegateWheel(int x, int y);
-static void RunTimegateWheel(int x, int y);
+static void InitMagicBallDelay(int, int);
+static void ActivateMagicBall(int, int);
+
+static void InitDiagonalMovingElement(int, int);
 
 struct ChangingElementInfo
 {
@@ -571,6 +564,38 @@ static struct ChangingElementInfo change_delay_list[] =
     RunTimegateWheel,
     NULL
   },
+  {
+    EL_EMC_MAGIC_BALL_ACTIVE,
+    EL_EMC_MAGIC_BALL_ACTIVE,
+    0,
+    InitMagicBallDelay,
+    NULL,
+    ActivateMagicBall
+  },
+  {
+    EL_EMC_SPRING_BUMPER_ACTIVE,
+    EL_EMC_SPRING_BUMPER,
+    8,
+    NULL,
+    NULL,
+    NULL
+  },
+  {
+    EL_DIAGONAL_SHRINKING,
+    EL_UNDEFINED,
+    0,
+    NULL,
+    NULL,
+    NULL
+  },
+  {
+    EL_DIAGONAL_GROWING,
+    EL_UNDEFINED,
+    0,
+    NULL,
+    NULL,
+    InitDiagonalMovingElement
+  },
 
   {
     EL_UNDEFINED,
@@ -678,7 +703,7 @@ access_direction_list[] =
   { EL_SP_GRAVITY_OFF_PORT_UP,                                      MV_DOWN },
   { EL_SP_GRAVITY_OFF_PORT_DOWN,                            MV_UP           },
 
-  { EL_UNDEFINED,                      MV_NO_MOVING                         }
+  { EL_UNDEFINED,                      MV_NONE                              }
 };
 
 static boolean trigger_events[MAX_NUM_ELEMENTS][NUM_CHANGE_EVENTS];
@@ -690,6 +715,93 @@ static boolean trigger_events[MAX_NUM_ELEMENTS][NUM_CHANGE_EVENTS];
 
 #define CE_PAGE(e, ce)         (element_info[e].event_page[ce])
 
+/* static variables for playfield scan mode (scanning forward or backward) */
+static int playfield_scan_start_x = 0;
+static int playfield_scan_start_y = 0;
+static int playfield_scan_delta_x = 1;
+static int playfield_scan_delta_y = 1;
+
+#define SCAN_PLAYFIELD(x, y)   for ((y) = playfield_scan_start_y;      \
+                                    (y) >= 0 && (y) <= lev_fieldy - 1; \
+                                    (y) += playfield_scan_delta_y)     \
+                               for ((x) = playfield_scan_start_x;      \
+                                    (x) >= 0 && (x) <= lev_fieldx - 1; \
+                                    (x) += playfield_scan_delta_x)     \
+
+#ifdef DEBUG
+void DEBUG_SetMaximumDynamite()
+{
+  int i;
+
+  for (i = 0; i < MAX_INVENTORY_SIZE; i++)
+    if (local_player->inventory_size < MAX_INVENTORY_SIZE)
+      local_player->inventory_element[local_player->inventory_size++] =
+       EL_DYNAMITE;
+}
+#endif
+
+static void InitPlayfieldScanModeVars()
+{
+  if (game.use_reverse_scan_direction)
+  {
+    playfield_scan_start_x = lev_fieldx - 1;
+    playfield_scan_start_y = lev_fieldy - 1;
+
+    playfield_scan_delta_x = -1;
+    playfield_scan_delta_y = -1;
+  }
+  else
+  {
+    playfield_scan_start_x = 0;
+    playfield_scan_start_y = 0;
+
+    playfield_scan_delta_x = 1;
+    playfield_scan_delta_y = 1;
+  }
+}
+
+static void InitPlayfieldScanMode(int mode)
+{
+  game.use_reverse_scan_direction =
+    (mode == CA_ARG_SCAN_MODE_REVERSE ? TRUE : FALSE);
+
+  InitPlayfieldScanModeVars();
+}
+
+static int get_move_delay_from_stepsize(int move_stepsize)
+{
+  move_stepsize =
+    MIN(MAX(MOVE_STEPSIZE_MIN, move_stepsize), MOVE_STEPSIZE_MAX);
+
+  /* make sure that stepsize value is always a power of 2 */
+  move_stepsize = (1 << log_2(move_stepsize));
+
+  return TILEX / move_stepsize;
+}
+
+static void SetPlayerMoveSpeed(struct PlayerInfo *player, int move_stepsize,
+                              boolean init_game)
+{
+  int player_nr = player->index_nr;
+  int move_delay = get_move_delay_from_stepsize(move_stepsize);
+  boolean cannot_move = (move_stepsize == STEPSIZE_NOT_MOVING ? TRUE : FALSE);
+
+  /* do no immediately change move delay -- the player might just be moving */
+  player->move_delay_value_next = move_delay;
+
+  /* information if player can move must be set separately */
+  player->cannot_move = cannot_move;
+
+  if (init_game)
+  {
+    player->move_delay       = game.initial_move_delay[player_nr];
+    player->move_delay_value = game.initial_move_delay_value[player_nr];
+
+    player->move_delay_value_next = -1;
+
+    player->move_delay_reset_counter = 0;
+  }
+}
 
 void GetPlayerConfig()
 {
@@ -753,7 +865,7 @@ static int getBeltDirFromBeltSwitchElement(int element)
   static int belt_move_dir[3] =
   {
     MV_LEFT,
-    MV_NO_MOVING,
+    MV_NONE,
     MV_RIGHT
   };
 
@@ -762,6 +874,32 @@ static int getBeltDirFromBeltSwitchElement(int element)
   return belt_move_dir[belt_dir_nr];
 }
 
+static int get_element_from_group_element(int element)
+{
+  if (IS_GROUP_ELEMENT(element))
+  {
+    struct ElementGroupInfo *group = element_info[element].group;
+    int last_anim_random_frame = gfx.anim_random_frame;
+    int element_pos;
+
+    if (group->choice_mode == ANIM_RANDOM)
+      gfx.anim_random_frame = RND(group->num_elements_resolved);
+
+    element_pos = getAnimationFrame(group->num_elements_resolved, 1,
+                                   group->choice_mode, 0,
+                                   group->choice_pos);
+
+    if (group->choice_mode == ANIM_RANDOM)
+      gfx.anim_random_frame = last_anim_random_frame;
+
+    group->choice_pos++;
+
+    element = group->element_resolved[element_pos];
+  }
+
+  return element;
+}
+
 static void InitPlayerField(int x, int y, int element, boolean init_game)
 {
   if (element == EL_SP_MURPHY)
@@ -776,7 +914,10 @@ static void InitPlayerField(int x, int y, int element, boolean init_game)
       }
       else
       {
-       stored_player[0].use_murphy_graphic = TRUE;
+       stored_player[0].use_murphy = TRUE;
+
+       if (!level.use_artwork_element[0])
+         stored_player[0].artwork_element = EL_SP_MURPHY;
       }
 
       Feld[x][y] = EL_PLAYER_1;
@@ -794,9 +935,6 @@ static void InitPlayerField(int x, int y, int element, boolean init_game)
                                level.sp_block_last_field :
                                level.block_last_field);
 
-#if USE_NEW_BLOCK_STYLE
-#if 1
-
     /* ---------- initialize player's last field block delay --------------- */
 
     /* always start with reliable default value (no adjustment needed) */
@@ -810,49 +948,6 @@ static void InitPlayerField(int x, int y, int element, boolean init_game)
     if (game.use_block_last_field_bug)
       player->block_delay_adjustment = (player->block_last_field ? -1 : 1);
 
-#if 0
-    /* blocking the last field when moving was corrected in version 3.1.1 */
-    if (game.use_block_last_field_bug)
-    {
-      /* even "not blocking" was blocking the last field for one frame */
-      level.block_delay    = (level.block_last_field    ? 7 : 1);
-      level.sp_block_delay = (level.sp_block_last_field ? 7 : 1);
-
-      level.block_last_field = TRUE;
-      level.sp_block_last_field = TRUE;
-    }
-#endif
-
-#if 0  /* !!! THIS IS NOT A LEVEL SETTING => REMOVED !!! */
-    level.block_delay = 8;             /* when blocking, block 8 frames */
-    level.sp_block_delay = 9;          /* SP indeed blocks 9 frames, not 8 */
-#endif
-
-#if 0
-    printf("::: %d, %d\n", level.block_delay, level.sp_block_delay);
-#endif
-
-#else
-
-#if 1
-    player->block_delay = (player->block_last_field ?
-                          (element == EL_SP_MURPHY ?
-                           level.sp_block_delay :
-                           level.block_delay) : 0);
-#else
-    player->block_delay = (element == EL_SP_MURPHY ?
-                          (player->block_last_field ? 7 : 1) :
-                          (player->block_last_field ? 7 : 1));
-#endif
-
-#endif
-
-#if 0
-    printf("::: block_last_field == %d, block_delay = %d\n",
-          player->block_last_field, player->block_delay);
-#endif
-#endif
-
     if (!options.network || player->connected)
     {
       player->active = TRUE;
@@ -918,41 +1013,45 @@ static void InitField(int x, int y, boolean init_game)
        Feld[x][y] = EL_ACID_POOL_BOTTOMRIGHT;
       break;
 
+    case EL_BUG:
     case EL_BUG_RIGHT:
     case EL_BUG_UP:
     case EL_BUG_LEFT:
     case EL_BUG_DOWN:
-    case EL_BUG:
+    case EL_SPACESHIP:
     case EL_SPACESHIP_RIGHT:
     case EL_SPACESHIP_UP:
     case EL_SPACESHIP_LEFT:
     case EL_SPACESHIP_DOWN:
-    case EL_SPACESHIP:
+    case EL_BD_BUTTERFLY:
     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:
     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_YAMYAM:
+    case EL_YAMYAM_LEFT:
+    case EL_YAMYAM_RIGHT:
+    case EL_YAMYAM_UP:
+    case EL_YAMYAM_DOWN:
     case EL_DARK_YAMYAM:
     case EL_ROBOT:
     case EL_PACMAN:
     case EL_SP_SNIKSNAK:
     case EL_SP_ELECTRON:
+    case EL_MOLE:
     case EL_MOLE_LEFT:
     case EL_MOLE_RIGHT:
     case EL_MOLE_UP:
     case EL_MOLE_DOWN:
-    case EL_MOLE:
       InitMovDir(x, y);
       break;
 
@@ -978,6 +1077,10 @@ static void InitField(int x, int y, boolean init_game)
       MovDelay[x][y] = 96;
       break;
 
+    case EL_EM_DYNAMITE_ACTIVE:
+      MovDelay[x][y] = 32;
+      break;
+
     case EL_LAMP:
       local_player->lights_still_needed++;
       break;
@@ -991,27 +1094,6 @@ static void InitField(int x, int y, boolean init_game)
       GfxDir[x][y] = MovDir[x][y] = 1 << RND(4);
       break;
 
-#if 0
-    case EL_SP_EMPTY:
-      Feld[x][y] = EL_EMPTY;
-      break;
-#endif
-
-#if 0
-    case EL_EM_KEY_1_FILE:
-      Feld[x][y] = EL_EM_KEY_1;
-      break;
-    case EL_EM_KEY_2_FILE:
-      Feld[x][y] = EL_EM_KEY_2;
-      break;
-    case EL_EM_KEY_3_FILE:
-      Feld[x][y] = EL_EM_KEY_3;
-      break;
-    case EL_EM_KEY_4_FILE:
-      Feld[x][y] = EL_EM_KEY_4;
-      break;
-#endif
-
     case EL_CONVEYOR_BELT_1_SWITCH_LEFT:
     case EL_CONVEYOR_BELT_1_SWITCH_MIDDLE:
     case EL_CONVEYOR_BELT_1_SWITCH_RIGHT:
@@ -1042,21 +1124,59 @@ static void InitField(int x, int y, boolean init_game)
       }
       break;
 
+#if !USE_BOTH_SWITCHGATE_SWITCHES
     case EL_SWITCHGATE_SWITCH_DOWN:    /* always start with same switch pos */
       if (init_game)
        Feld[x][y] = EL_SWITCHGATE_SWITCH_UP;
       break;
+#endif
 
     case EL_LIGHT_SWITCH_ACTIVE:
       if (init_game)
        game.light_time_left = level.time_light * FRAMES_PER_SECOND;
       break;
 
+    case EL_INVISIBLE_STEELWALL:
+    case EL_INVISIBLE_WALL:
+    case EL_INVISIBLE_SAND:
+      if (game.light_time_left > 0 ||
+         game.lenses_time_left > 0)
+        Feld[x][y] = getInvisibleActiveFromInvisibleElement(element);
+      break;
+
+    case EL_EMC_MAGIC_BALL:
+      if (game.ball_state)
+       Feld[x][y] = EL_EMC_MAGIC_BALL_ACTIVE;
+      break;
+
+    case EL_EMC_MAGIC_BALL_SWITCH:
+      if (game.ball_state)
+       Feld[x][y] = EL_EMC_MAGIC_BALL_SWITCH_ACTIVE;
+      break;
+
     default:
+#if 1
+      if (IS_CUSTOM_ELEMENT(element))
+      {
+       if (CAN_MOVE(element))
+         InitMovDir(x, y);
+
+#if USE_NEW_CUSTOM_VALUE
+       if (!element_info[element].use_last_ce_value || init_game)
+         CustomValue[x][y] = GET_NEW_CE_VALUE(Feld[x][y]);
+#endif
+      }
+#else
       if (IS_CUSTOM_ELEMENT(element) && CAN_MOVE(element))
        InitMovDir(x, y);
+#endif
       else if (IS_GROUP_ELEMENT(element))
       {
+#if 1
+       Feld[x][y] = get_element_from_group_element(element);
+
+       InitField(x, y, init_game);
+#else
        struct ElementGroupInfo *group = element_info[element].group;
        int last_anim_random_frame = gfx.anim_random_frame;
        int element_pos;
@@ -1076,9 +1196,29 @@ static void InitField(int x, int y, boolean init_game)
        Feld[x][y] = group->element_resolved[element_pos];
 
        InitField(x, y, init_game);
+#endif
       }
       break;
   }
+
+#if 1
+  if (!init_game)
+    CheckTriggeredElementChange(x, y, element, CE_CREATION_OF_X);
+#endif
+
+#if 0
+
+#if USE_NEW_CUSTOM_VALUE
+
+#if 1
+  CustomValue[x][y] = GET_NEW_CE_VALUE(Feld[x][y]);
+#else
+  CustomValue[x][y] = element_info[Feld[x][y]].custom_value_initial;
+#endif
+
+#endif
+
+#endif
 }
 
 static inline void InitField_WithBug1(int x, int y, boolean init_game)
@@ -1114,36 +1254,59 @@ static inline void InitField_WithBug2(int x, int y, boolean init_game)
 
 inline void DrawGameValue_Emeralds(int value)
 {
-  DrawText(DX_EMERALDS, DY_EMERALDS, int2str(value, 3), FONT_TEXT_2);
+  int xpos = (3 * 14 - 3 * getFontWidth(FONT_TEXT_2)) / 2;
+
+  DrawText(DX_EMERALDS + xpos, DY_EMERALDS, int2str(value, 3), FONT_TEXT_2);
 }
 
 inline void DrawGameValue_Dynamite(int value)
 {
-  DrawText(DX_DYNAMITE, DY_DYNAMITE, int2str(value, 3), FONT_TEXT_2);
+  int xpos = (3 * 14 - 3 * getFontWidth(FONT_TEXT_2)) / 2;
+
+  DrawText(DX_DYNAMITE + xpos, DY_DYNAMITE, int2str(value, 3), FONT_TEXT_2);
 }
 
 inline void DrawGameValue_Keys(int key[MAX_NUM_KEYS])
 {
+  int base_key_graphic = EL_KEY_1;
   int i;
 
+  if (level.game_engine_type == GAME_ENGINE_TYPE_EM)
+    base_key_graphic = EL_EM_KEY_1;
+
   /* currently only 4 of 8 possible keys are displayed */
   for (i = 0; i < STD_NUM_KEYS; i++)
+  {
     if (key[i])
       DrawMiniGraphicExt(drawto, DX_KEYS + i * MINI_TILEX, DY_KEYS,
-                        el2edimg(EL_KEY_1 + i));
+                        el2edimg(base_key_graphic + i));
+    else
+      BlitBitmap(graphic_info[IMG_GLOBAL_DOOR].bitmap, drawto,
+                DOOR_GFX_PAGEX5 + XX_KEYS + i * MINI_TILEX, YY_KEYS,
+                MINI_TILEX, MINI_TILEY, DX_KEYS + i * MINI_TILEX, DY_KEYS);
+  }
 }
 
 inline void DrawGameValue_Score(int value)
 {
-  DrawText(DX_SCORE, DY_SCORE, int2str(value, 5), FONT_TEXT_2);
+  int xpos = (5 * 14 - 5 * getFontWidth(FONT_TEXT_2)) / 2;
+
+  DrawText(DX_SCORE + xpos, DY_SCORE, int2str(value, 5), FONT_TEXT_2);
 }
 
 inline void DrawGameValue_Time(int value)
 {
+  int xpos3 = (3 * 14 - 3 * getFontWidth(FONT_TEXT_2)) / 2;
+  int xpos4 = (4 * 10 - 4 * getFontWidth(FONT_LEVEL_NUMBER)) / 2;
+
+  /* clear background if value just changed its size */
+  if (value == 999 || value == 1000)
+    ClearRectangle(drawto, DX_TIME1, DY_TIME, 14 * 3, 14);
+
   if (value < 1000)
-    DrawText(DX_TIME1, DY_TIME, int2str(value, 3), FONT_TEXT_2);
+    DrawText(DX_TIME1 + xpos3, DY_TIME, int2str(value, 3), FONT_TEXT_2);
   else
-    DrawText(DX_TIME2, DY_TIME, int2str(value, 4), FONT_LEVEL_NUMBER);
+    DrawText(DX_TIME2 + xpos4, DY_TIME, int2str(value, 4), FONT_LEVEL_NUMBER);
 }
 
 inline void DrawGameValue_Level(int value)
@@ -1191,7 +1354,9 @@ void DrawAllGameValues(int emeralds, int dynamite, int score, int time,
 
 void DrawGameDoorValues()
 {
-  int i;
+  int dynamite_state = 0;
+  int key_bits = 0;
+  int i, j;
 
   if (level.game_engine_type == GAME_ENGINE_TYPE_EM)
   {
@@ -1200,6 +1365,7 @@ void DrawGameDoorValues()
     return;
   }
 
+#if 0
   DrawGameValue_Level(level_nr);
 
   DrawGameValue_Emeralds(local_player->gems_still_needed);
@@ -1207,10 +1373,40 @@ void DrawGameDoorValues()
   DrawGameValue_Score(local_player->score);
   DrawGameValue_Time(TimeLeft);
 
-  for (i = 0; i < MAX_PLAYERS; i++)
+#else
+
+  if (game.centered_player_nr == -1)
+  {
+    for (i = 0; i < MAX_PLAYERS; i++)
+    {
+      for (j = 0; j < MAX_NUM_KEYS; j++)
+       if (stored_player[i].key[j])
+         key_bits |= (1 << j);
+
+      dynamite_state += stored_player[i].inventory_size;
+    }
+
+#if 0
     DrawGameValue_Keys(stored_player[i].key);
+#endif
+  }
+  else
+  {
+    int player_nr = game.centered_player_nr;
+
+    for (i = 0; i < MAX_NUM_KEYS; i++)
+      if (stored_player[player_nr].key[i])
+       key_bits |= (1 << i);
+
+    dynamite_state = stored_player[player_nr].inventory_size;
+  }
+
+  DrawAllGameValues(local_player->gems_still_needed, dynamite_state,
+                   local_player->score, TimeLeft, key_bits);
+#endif
 }
 
+#if 0
 static void resolve_group_element(int group_element, int recursion_depth)
 {
   static int group_nr;
@@ -1253,19 +1449,8 @@ static void resolve_group_element(int group_element, int recursion_depth)
       element_info[element].in_group[group_nr] = TRUE;
     }
   }
-
-#if 0
-  if (recursion_depth == 0 && group_element <= EL_GROUP_4)
-  {
-    printf("::: group %d: %d resolved elements\n",
-          group_element - EL_GROUP_START, group->num_elements_resolved);
-    for (i = 0; i < group->num_elements_resolved; i++)
-      printf("::: - %d ['%s']\n", group->element_resolved[i],
-            element_info[group->element_resolved[i]].token_name);
-  }
-#endif
 }
-
+#endif
 
 /*
   =============================================================================
@@ -1277,7 +1462,7 @@ static void resolve_group_element(int group_element, int recursion_depth)
 
 static void InitGameEngine()
 {
-  int i, j, k, l;
+  int i, j, k, l, x, y;
 
   /* set game engine from tape file when re-playing, else from level file */
   game.engine_version = (tape.playing ? tape.engine_version :
@@ -1349,8 +1534,43 @@ static void InitGameEngine()
   game.use_block_last_field_bug =
     (game.engine_version < VERSION_IDENT(3,1,1,0));
 
+  /*
+    Summary of bugfix/change:
+    Changed behaviour of CE changes with multiple changes per single frame.
+
+    Fixed/changed in version:
+    3.2.0-6
+
+    Description:
+    Before 3.2.0-6, only one single CE change was allowed in each engine frame.
+    This resulted in race conditions where CEs seem to behave strange in some
+    situations (where triggered CE changes were just skipped because there was
+    already a CE change on that tile in the playfield in that engine frame).
+    Since 3.2.0-6, this was changed to allow up to MAX_NUM_CHANGES_PER_FRAME.
+    (The number of changes per frame must be limited in any case, because else
+    it is easily possible to define CE changes that would result in an infinite
+    loop, causing the whole game to freeze. The MAX_NUM_CHANGES_PER_FRAME value
+    should be set large enough so that it would only be reached in cases where
+    the corresponding CE change conditions run into a loop. Therefore, it seems
+    to be reasonable to set MAX_NUM_CHANGES_PER_FRAME to the same value as the
+    maximal number of change pages for custom elements.)
+
+    Affected levels/tapes:
+    Probably many.
+  */
+
+#if USE_ONLY_ONE_CHANGE_PER_FRAME
+  game.max_num_changes_per_frame = 1;
+#else
+  game.max_num_changes_per_frame =
+    (game.engine_version < VERSION_IDENT(3,2,0,6) ? 1 : 32);
+#endif
+
   /* ---------------------------------------------------------------------- */
 
+  /* default scan direction: scan playfield from top/left to bottom/right */
+  InitPlayfieldScanMode(CA_ARG_SCAN_MODE_NORMAL);
+
   /* dynamically adjust element properties according to game engine version */
   InitElementPropertiesEngine(game.engine_version);
 
@@ -1362,6 +1582,7 @@ static void InitGameEngine()
   printf("       => game.engine_version == %06d\n", game.engine_version);
 #endif
 
+#if 0
   /* ---------- recursively resolve group elements ------------------------- */
 
   for (i = 0; i < MAX_NUM_ELEMENTS; i++)
@@ -1370,28 +1591,27 @@ static void InitGameEngine()
 
   for (i = 0; i < NUM_GROUP_ELEMENTS; i++)
     resolve_group_element(EL_GROUP_START + i, 0);
+#endif
 
   /* ---------- initialize player's initial move delay --------------------- */
 
-#if USE_NEW_MOVE_DELAY
+#if 1
   /* dynamically adjust player properties according to level information */
-  game.initial_move_delay_value =
-    (level.double_speed ? MOVE_DELAY_HIGH_SPEED : MOVE_DELAY_NORMAL_SPEED);
-
-  /* dynamically adjust player properties according to game engine version */
-  game.initial_move_delay = (game.engine_version <= VERSION_IDENT(2,0,1,0) ?
-                            game.initial_move_delay_value : 0);
+  for (i = 0; i < MAX_PLAYERS; i++)
+    game.initial_move_delay_value[i] =
+      get_move_delay_from_stepsize(level.initial_player_stepsize[i]);
 #else
-  /* dynamically adjust player properties according to game engine version */
-  game.initial_move_delay =
-    (game.engine_version <= VERSION_IDENT(2,0,1,0) ? INITIAL_MOVE_DELAY_ON :
-     INITIAL_MOVE_DELAY_OFF);
-
   /* dynamically adjust player properties according to level information */
   game.initial_move_delay_value =
     (level.double_speed ? MOVE_DELAY_HIGH_SPEED : MOVE_DELAY_NORMAL_SPEED);
 #endif
 
+  /* dynamically adjust player properties according to game engine version */
+  for (i = 0; i < MAX_PLAYERS; i++)
+    game.initial_move_delay[i] =
+      (game.engine_version <= VERSION_IDENT(2,0,1,0) ?
+       game.initial_move_delay_value[i] : 0);
+
   /* ---------- initialize player's initial push delay --------------------- */
 
   /* dynamically adjust player properties according to game engine version */
@@ -1438,14 +1658,29 @@ static void InitGameEngine()
     ei->change->change_function      = ch_delay->change_function;
     ei->change->post_change_function = ch_delay->post_change_function;
 
+    ei->change->can_change = TRUE;
+    ei->change->can_change_or_has_action = TRUE;
+
     ei->has_change_event[CE_DELAY] = TRUE;
 
-#if 1
     SET_PROPERTY(ch_delay->element, EP_CAN_CHANGE, TRUE);
-#endif
+    SET_PROPERTY(ch_delay->element, EP_CAN_CHANGE_OR_HAS_ACTION, TRUE);
+  }
+
+  /* ---------- initialize internal run-time variables ------------- */
+
+  for (i = 0; i < NUM_CUSTOM_ELEMENTS; i++)
+  {
+    struct ElementInfo *ei = &element_info[EL_CUSTOM_START + i];
+
+    for (j = 0; j < ei->num_change_pages; j++)
+    {
+      ei->change_page[j].can_change_or_has_action =
+       (ei->change_page[j].can_change |
+        ei->change_page[j].has_action);
+    }
   }
 
-#if 1
   /* add change events from custom element configuration */
   for (i = 0; i < NUM_CUSTOM_ELEMENTS; i++)
   {
@@ -1453,7 +1688,7 @@ static void InitGameEngine()
 
     for (j = 0; j < ei->num_change_pages; j++)
     {
-      if (!ei->change_page[j].can_change)
+      if (!ei->change_page[j].can_change_or_has_action)
        continue;
 
       for (k = 0; k < NUM_CHANGE_EVENTS; k++)
@@ -1470,19 +1705,6 @@ static void InitGameEngine()
     }
   }
 
-#else
-
-  /* add change events from custom element configuration */
-  for (i = 0; i < NUM_CUSTOM_ELEMENTS; i++)
-  {
-    int element = EL_CUSTOM_START + i;
-
-    /* only add custom elements that change after fixed/random frame delay */
-    if (CAN_CHANGE(element) && HAS_CHANGE_EVENT(element, CE_DELAY))
-      element_info[element].has_change_event[CE_DELAY] = TRUE;
-  }
-#endif
-
   /* ---------- initialize run-time trigger player and element ------------- */
 
   for (i = 0; i < NUM_CUSTOM_ELEMENTS; i++)
@@ -1493,6 +1715,9 @@ static void InitGameEngine()
     {
       ei->change_page[j].actual_trigger_element = EL_EMPTY;
       ei->change_page[j].actual_trigger_player = EL_PLAYER_1;
+      ei->change_page[j].actual_trigger_side = CH_SIDE_NONE;
+      ei->change_page[j].actual_trigger_ce_value = 0;
+      ei->change_page[j].actual_trigger_ce_score = 0;
     }
   }
 
@@ -1503,7 +1728,6 @@ static void InitGameEngine()
     for (j = 0; j < NUM_CHANGE_EVENTS; j++)
       trigger_events[i][j] = FALSE;
 
-#if 1
   /* add trigger events from element change event properties */
   for (i = 0; i < MAX_NUM_ELEMENTS; i++)
   {
@@ -1511,7 +1735,7 @@ static void InitGameEngine()
 
     for (j = 0; j < ei->num_change_pages; j++)
     {
-      if (!ei->change_page[j].can_change)
+      if (!ei->change_page[j].can_change_or_has_action)
        continue;
 
       if (ei->change_page[j].has_event[CE_BY_OTHER_ACTION])
@@ -1537,14 +1761,6 @@ static void InitGameEngine()
       }
     }
   }
-#else
-  /* add trigger events from element change event properties */
-  for (i = 0; i < MAX_NUM_ELEMENTS; i++)
-    if (HAS_CHANGE_EVENT(i, CE_BY_OTHER_ACTION))
-      for (j = 0; j < NUM_CHANGE_EVENTS; j++)
-       if (element_info[i].change->has_event[j])
-         trigger_events[element_info[i].change->trigger_element][j] = TRUE;
-#endif
 
   /* ---------- initialize push delay -------------------------------------- */
 
@@ -1553,8 +1769,22 @@ static void InitGameEngine()
   {
     if (!IS_CUSTOM_ELEMENT(i))
     {
+#if 1
+      /* set default push delay values (corrected since version 3.0.7-1) */
+      if (game.engine_version < VERSION_IDENT(3,0,7,1))
+      {
+       element_info[i].push_delay_fixed = 2;
+       element_info[i].push_delay_random = 8;
+      }
+      else
+      {
+       element_info[i].push_delay_fixed = 8;
+       element_info[i].push_delay_random = 8;
+      }
+#else
       element_info[i].push_delay_fixed  = game.default_push_delay_fixed;
       element_info[i].push_delay_random = game.default_push_delay_random;
+#endif
     }
   }
 
@@ -1574,16 +1804,11 @@ static void InitGameEngine()
     {
       if (IS_SP_ELEMENT(i))
       {
-#if USE_NEW_MOVE_STYLE
        /* set SP push delay to just enough to push under a falling zonk */
        int delay = (game.engine_version >= VERSION_IDENT(3,1,1,0) ? 8 : 6);
 
        element_info[i].push_delay_fixed  = delay;
        element_info[i].push_delay_random = 0;
-#else
-       element_info[i].push_delay_fixed  = 6;  /* just enough to escape ... */
-       element_info[i].push_delay_random = 0;  /* ... from falling zonk     */
-#endif
       }
     }
   }
@@ -1603,26 +1828,23 @@ static void InitGameEngine()
     element_info[e].move_stepsize = move_stepsize_list[i].move_stepsize;
   }
 
-#if 0
-  /* ---------- initialize move dig/leave ---------------------------------- */
+  /* ---------- initialize collect score ----------------------------------- */
 
+  /* initialize collect score values for custom elements from initial value */
   for (i = 0; i < MAX_NUM_ELEMENTS; i++)
-  {
-    element_info[i].can_leave_element = FALSE;
-    element_info[i].can_leave_element_last = FALSE;
-  }
-#endif
+    if (IS_CUSTOM_ELEMENT(i))
+      element_info[i].collect_score = element_info[i].collect_score_initial;
 
-  /* ---------- initialize gem count --------------------------------------- */
+  /* ---------- initialize collect count ----------------------------------- */
 
-  /* initialize gem count values for each element */
+  /* initialize collect count values for non-custom elements */
   for (i = 0; i < MAX_NUM_ELEMENTS; i++)
     if (!IS_CUSTOM_ELEMENT(i))
-      element_info[i].collect_count = 0;
+      element_info[i].collect_count_initial = 0;
 
-  /* add gem count values for all elements from pre-defined list */
+  /* add collect count values for all elements from pre-defined list */
   for (i = 0; collect_count_list[i].element != EL_UNDEFINED; i++)
-    element_info[collect_count_list[i].element].collect_count =
+    element_info[collect_count_list[i].element].collect_count_initial =
       collect_count_list[i].count;
 
   /* ---------- initialize access direction -------------------------------- */
@@ -1636,8 +1858,67 @@ static void InitGameEngine()
   for (i = 0; access_direction_list[i].element != EL_UNDEFINED; i++)
     element_info[access_direction_list[i].element].access_direction =
       access_direction_list[i].direction;
+
+  /* ---------- initialize explosion content ------------------------------- */
+  for (i = 0; i < MAX_NUM_ELEMENTS; i++)
+  {
+    if (IS_CUSTOM_ELEMENT(i))
+      continue;
+
+    for (y = 0; y < 3; y++) for (x = 0; x < 3; x++)
+    {
+      /* (content for EL_YAMYAM set at run-time with game.yamyam_content_nr) */
+
+      element_info[i].content.e[x][y] =
+       (i == EL_PLAYER_1 ? EL_EMERALD_YELLOW :
+        i == EL_PLAYER_2 ? EL_EMERALD_RED :
+        i == EL_PLAYER_3 ? EL_EMERALD :
+        i == EL_PLAYER_4 ? EL_EMERALD_PURPLE :
+        i == EL_MOLE ? EL_EMERALD_RED :
+        i == EL_PENGUIN ? EL_EMERALD_PURPLE :
+        i == EL_BUG ? (x == 1 && y == 1 ? EL_DIAMOND : EL_EMERALD) :
+        i == EL_BD_BUTTERFLY ? EL_BD_DIAMOND :
+        i == EL_SP_ELECTRON ? EL_SP_INFOTRON :
+        i == EL_AMOEBA_TO_DIAMOND ? level.amoeba_content :
+        i == EL_WALL_EMERALD ? EL_EMERALD :
+        i == EL_WALL_DIAMOND ? EL_DIAMOND :
+        i == EL_WALL_BD_DIAMOND ? EL_BD_DIAMOND :
+        i == EL_WALL_EMERALD_YELLOW ? EL_EMERALD_YELLOW :
+        i == EL_WALL_EMERALD_RED ? EL_EMERALD_RED :
+        i == EL_WALL_EMERALD_PURPLE ? EL_EMERALD_PURPLE :
+        i == EL_WALL_PEARL ? EL_PEARL :
+        i == EL_WALL_CRYSTAL ? EL_CRYSTAL :
+        EL_EMPTY);
+    }
+  }
 }
 
+int get_num_special_action(int element, int action_first, int action_last)
+{
+  int num_special_action = 0;
+  int i, j;
+
+  for (i = action_first; i <= action_last; i++)
+  {
+    boolean found = FALSE;
+
+    for (j = 0; j < NUM_DIRECTIONS; j++)
+      if (el_act_dir2img(element, i, j) !=
+         el_act_dir2img(element, ACTION_DEFAULT, j))
+       found = TRUE;
+
+    if (found)
+      num_special_action++;
+    else
+      break;
+  }
+
+#if 0
+  printf("::: %d->%d: %d\n", action_first, action_last, num_special_action);
+#endif
+
+  return num_special_action;
+}
 
 /*
   =============================================================================
@@ -1652,20 +1933,10 @@ void InitGame()
   boolean emulate_bd = TRUE;   /* unless non-BOULDERDASH elements found */
   boolean emulate_sb = TRUE;   /* unless non-SOKOBAN     elements found */
   boolean emulate_sp = TRUE;   /* unless non-SUPAPLEX    elements found */
-  int i, j, k, x, y;
+  int i, j, x, y;
 
   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 */
   network_playing = (options.network && !tape.playing);
 
@@ -1698,26 +1969,33 @@ void InitGame()
     player->dynabombs_left = 0;
     player->dynabomb_xl = FALSE;
 
-    player->MovDir = MV_NO_MOVING;
+    player->MovDir = MV_NONE;
     player->MovPos = 0;
     player->GfxPos = 0;
-    player->GfxDir = MV_NO_MOVING;
+    player->GfxDir = MV_NONE;
     player->GfxAction = ACTION_DEFAULT;
     player->Frame = 0;
     player->StepFrame = 0;
 
-    player->use_murphy_graphic = FALSE;
+    player->use_murphy = FALSE;
+    player->artwork_element =
+      (level.use_artwork_element[i] ? level.artwork_element[i] :
+       player->element_nr);
 
     player->block_last_field = FALSE;  /* initialized in InitPlayerField() */
     player->block_delay_adjustment = 0;        /* initialized in InitPlayerField() */
 
+    player->gravity = level.initial_player_gravity[i];
+
     player->can_fall_into_acid = CAN_MOVE_INTO_ACID(player->element_nr);
 
     player->actual_frame_counter = 0;
 
     player->step_counter = 0;
 
-    player->last_move_dir = MV_NO_MOVING;
+    player->last_move_dir = MV_NONE;
+
+    player->is_active = FALSE;
 
     player->is_waiting = FALSE;
     player->is_moving = FALSE;
@@ -1728,6 +2006,7 @@ void InitGame()
     player->is_pushing = FALSE;
     player->is_switching = FALSE;
     player->is_dropping = FALSE;
+    player->is_dropping_pressed = FALSE;
 
     player->is_bored = FALSE;
     player->is_sleeping = FALSE;
@@ -1738,68 +2017,50 @@ void InitGame()
     player->anim_delay_counter = 0;
     player->post_delay_counter = 0;
 
+    player->dir_waiting = MV_NONE;
     player->action_waiting = ACTION_DEFAULT;
     player->last_action_waiting = ACTION_DEFAULT;
     player->special_action_bored = ACTION_DEFAULT;
     player->special_action_sleeping = ACTION_DEFAULT;
 
-    player->num_special_action_bored = 0;
-    player->num_special_action_sleeping = 0;
-
-    /* determine number of special actions for bored and sleeping animation */
-    for (j = ACTION_BORING_1; j <= ACTION_BORING_LAST; j++)
-    {
-      boolean found = FALSE;
-
-      for (k = 0; k < NUM_DIRECTIONS; k++)
-       if (el_act_dir2img(player->element_nr, j, k) !=
-           el_act_dir2img(player->element_nr, ACTION_DEFAULT, k))
-         found = TRUE;
-
-      if (found)
-       player->num_special_action_bored++;
-      else
-       break;
-    }
-    for (j = ACTION_SLEEPING_1; j <= ACTION_SLEEPING_LAST; j++)
-    {
-      boolean found = FALSE;
-
-      for (k = 0; k < NUM_DIRECTIONS; k++)
-       if (el_act_dir2img(player->element_nr, j, k) !=
-           el_act_dir2img(player->element_nr, ACTION_DEFAULT, k))
-         found = TRUE;
-
-      if (found)
-       player->num_special_action_sleeping++;
-      else
-       break;
-    }
+#if 1
+    /* cannot be set here -- could be modified in Init[Player]Field() below */
+#else
+    /* set number of special actions for bored and sleeping animation */
+    player->num_special_action_bored =
+      get_num_special_action(player->artwork_element,
+                            ACTION_BORING_1, ACTION_BORING_LAST);
+    player->num_special_action_sleeping =
+      get_num_special_action(player->artwork_element,
+                            ACTION_SLEEPING_1, ACTION_SLEEPING_LAST);
+#endif
 
     player->switch_x = -1;
     player->switch_y = -1;
 
-#if USE_DROP_BUGFIX
     player->drop_x = -1;
     player->drop_y = -1;
-#endif
 
     player->show_envelope = 0;
 
+#if 1
+    SetPlayerMoveSpeed(player, level.initial_player_stepsize[i], TRUE);
+#else
     player->move_delay       = game.initial_move_delay;
     player->move_delay_value = game.initial_move_delay_value;
 
+    player->move_delay_value_next = -1;
+
     player->move_delay_reset_counter = 0;
 
-#if USE_NEW_PUSH_DELAY
+    player->cannot_move = FALSE;
+#endif
+
     player->push_delay       = -1;     /* initialized when pushing starts */
     player->push_delay_value = game.initial_push_delay_value;
-#else
-    player->push_delay       = 0;
-    player->push_delay_value = game.initial_push_delay_value;
-#endif
 
     player->drop_delay = 0;
+    player->drop_pressed_delay = 0;
 
     player->last_jx = player->last_jy = 0;
     player->jx = player->jy = 0;
@@ -1822,7 +2083,7 @@ void InitGame()
 #if defined(NETWORK_AVALIABLE)
   /* initial null action */
   if (network_playing)
-    SendToServer_MovePlayer(MV_NO_MOVING);
+    SendToServer_MovePlayer(MV_NONE);
 #endif
 
   ZX = ZY = -1;
@@ -1834,7 +2095,7 @@ void InitGame()
   TimeLeft = level.time;
   TapeTime = 0;
 
-  ScreenMovDir = MV_NO_MOVING;
+  ScreenMovDir = MV_NONE;
   ScreenMovPos = 0;
   ScreenGfxPos = 0;
 
@@ -1848,76 +2109,147 @@ void InitGame()
   game.light_time_left = 0;
   game.timegate_time_left = 0;
   game.switchgate_pos = 0;
-  game.balloon_dir = MV_NO_MOVING;
+  game.wind_direction = level.wind_direction_initial;
+
+#if !USE_PLAYER_GRAVITY
+#if 1
+  game.gravity = FALSE;
+#else
   game.gravity = level.initial_gravity;
+#endif
   game.explosions_delayed = TRUE;
+#endif
+
+  game.lenses_time_left = 0;
+  game.magnify_time_left = 0;
+
+  game.ball_state = level.ball_state_initial;
+  game.ball_content_nr = 0;
 
   game.envelope_active = FALSE;
 
+  /* set focus to local player for network games, else to all players */
+  game.centered_player_nr = (network_playing ? local_player->index_nr : -1);
+  game.centered_player_nr_next = game.centered_player_nr;
+  game.set_centered_player = FALSE;
+
+  if (network_playing && tape.recording)
+  {
+    /* store client dependent player focus when recording network games */
+    tape.centered_player_nr_next = game.centered_player_nr_next;
+    tape.set_centered_player = TRUE;
+  }
+
+#if 0
+  printf("::: focus set to player %d [%d]\n",
+        game.centered_player_nr, local_player->index_nr);
+#endif
+
   for (i = 0; i < NUM_BELTS; i++)
   {
-    game.belt_dir[i] = MV_NO_MOVING;
+    game.belt_dir[i] = MV_NONE;
     game.belt_dir_nr[i] = 3;           /* not moving, next moving left */
   }
 
   for (i = 0; i < MAX_NUM_AMOEBA; i++)
     AmoebaCnt[i] = AmoebaCnt2[i] = 0;
 
-  for (x = 0; x < lev_fieldx; x++)
+#if 1
+  SCAN_PLAYFIELD(x, y)
+#else
+  for (x = 0; x < lev_fieldx; x++) for (y = 0; y < lev_fieldy; y++)
+#endif
   {
-    for (y = 0; y < lev_fieldy; y++)
-    {
-      Feld[x][y] = level.field[x][y];
-      MovPos[x][y] = MovDir[x][y] = MovDelay[x][y] = 0;
-      ChangeDelay[x][y] = 0;
-      ChangePage[x][y] = -1;
-      Store[x][y] = Store2[x][y] = StorePlayer[x][y] = Back[x][y] = 0;
-      AmoebaNr[x][y] = 0;
-      WasJustMoving[x][y] = 0;
-      WasJustFalling[x][y] = 0;
-      CheckCollision[x][y] = 0;
-      Stop[x][y] = FALSE;
-      Pushed[x][y] = FALSE;
+    Feld[x][y] = level.field[x][y];
+    MovPos[x][y] = MovDir[x][y] = MovDelay[x][y] = 0;
+    ChangeDelay[x][y] = 0;
+    ChangePage[x][y] = -1;
+#if USE_NEW_CUSTOM_VALUE
+    CustomValue[x][y] = 0;             /* initialized in InitField() */
+#endif
+    Store[x][y] = Store2[x][y] = StorePlayer[x][y] = Back[x][y] = 0;
+    AmoebaNr[x][y] = 0;
+    WasJustMoving[x][y] = 0;
+    WasJustFalling[x][y] = 0;
+    CheckCollision[x][y] = 0;
+    Stop[x][y] = FALSE;
+    Pushed[x][y] = FALSE;
 
-      Changed[x][y] = FALSE;
-      ChangeEvent[x][y] = -1;
+    ChangeCount[x][y] = 0;
+    ChangeEvent[x][y] = -1;
 
-      ExplodePhase[x][y] = 0;
-      ExplodeDelay[x][y] = 0;
-      ExplodeField[x][y] = EX_TYPE_NONE;
+    ExplodePhase[x][y] = 0;
+    ExplodeDelay[x][y] = 0;
+    ExplodeField[x][y] = EX_TYPE_NONE;
 
-      RunnerVisit[x][y] = 0;
-      PlayerVisit[x][y] = 0;
+    RunnerVisit[x][y] = 0;
+    PlayerVisit[x][y] = 0;
 
-      GfxFrame[x][y] = 0;
-      GfxRandom[x][y] = INIT_GFX_RANDOM();
-      GfxElement[x][y] = EL_UNDEFINED;
-      GfxAction[x][y] = ACTION_DEFAULT;
-      GfxDir[x][y] = MV_NO_MOVING;
-    }
+    GfxFrame[x][y] = 0;
+    GfxRandom[x][y] = INIT_GFX_RANDOM();
+    GfxElement[x][y] = EL_UNDEFINED;
+    GfxAction[x][y] = ACTION_DEFAULT;
+    GfxDir[x][y] = MV_NONE;
   }
 
-  for (y = 0; y < lev_fieldy; y++)
+#if 1
+  SCAN_PLAYFIELD(x, y)
+#else
+  for (y = 0; y < lev_fieldy; y++) for (x = 0; x < lev_fieldx; x++)
+#endif
   {
-    for (x = 0; x < lev_fieldx; x++)
-    {
-      if (emulate_bd && !IS_BD_ELEMENT(Feld[x][y]))
-       emulate_bd = FALSE;
-      if (emulate_sb && !IS_SB_ELEMENT(Feld[x][y]))
-       emulate_sb = FALSE;
-      if (emulate_sp && !IS_SP_ELEMENT(Feld[x][y]))
-       emulate_sp = FALSE;
+    if (emulate_bd && !IS_BD_ELEMENT(Feld[x][y]))
+      emulate_bd = FALSE;
+    if (emulate_sb && !IS_SB_ELEMENT(Feld[x][y]))
+      emulate_sb = FALSE;
+    if (emulate_sp && !IS_SP_ELEMENT(Feld[x][y]))
+      emulate_sp = FALSE;
 
-      InitField(x, y, TRUE);
-    }
+    InitField(x, y, TRUE);
   }
 
   InitBeltMovement();
 
+  for (i = 0; i < MAX_PLAYERS; i++)
+  {
+    struct PlayerInfo *player = &stored_player[i];
+
+#if 1
+    /* set number of special actions for bored and sleeping animation */
+    player->num_special_action_bored =
+      get_num_special_action(player->artwork_element,
+                            ACTION_BORING_1, ACTION_BORING_LAST);
+    player->num_special_action_sleeping =
+      get_num_special_action(player->artwork_element,
+                            ACTION_SLEEPING_1, ACTION_SLEEPING_LAST);
+#endif
+
+  }
+
   game.emulation = (emulate_bd ? EMU_BOULDERDASH :
                    emulate_sb ? EMU_SOKOBAN :
                    emulate_sp ? EMU_SUPAPLEX : EMU_NONE);
 
+#if USE_NEW_ALL_SLIPPERY
+  /* initialize type of slippery elements */
+  for (i = 0; i < MAX_NUM_ELEMENTS; i++)
+  {
+    if (!IS_CUSTOM_ELEMENT(i))
+    {
+      /* default: elements slip down either to the left or right randomly */
+      element_info[i].slippery_type = SLIPPERY_ANY_RANDOM;
+
+      /* SP style elements prefer to slip down on the left side */
+      if (game.engine_version >= VERSION_IDENT(3,1,1,0) && IS_SP_ELEMENT(i))
+       element_info[i].slippery_type = SLIPPERY_ANY_LEFT_RIGHT;
+
+      /* BD style elements prefer to slip down on the left side */
+      if (game.emulation == EMU_BOULDERDASH)
+       element_info[i].slippery_type = SLIPPERY_ANY_LEFT_RIGHT;
+    }
+  }
+#endif
+
   /* initialize explosion and ignition delay */
   for (i = 0; i < MAX_NUM_ELEMENTS; i++)
   {
@@ -1933,13 +2265,8 @@ void InitGame()
       element_info[i].explosion_delay = last_phase - 1;
       element_info[i].ignition_delay = half_phase;
 
-#if 0
-      if (i == EL_BLACK_ORB)
-       element_info[i].ignition_delay = 0;
-#else
       if (i == EL_BLACK_ORB)
        element_info[i].ignition_delay = 1;
-#endif
     }
 
 #if 0
@@ -1953,7 +2280,7 @@ void InitGame()
 
   /* correct non-moving belts to start moving left */
   for (i = 0; i < NUM_BELTS; i++)
-    if (game.belt_dir[i] == MV_NO_MOVING)
+    if (game.belt_dir[i] == MV_NONE)
       game.belt_dir_nr[i] = 3;         /* not moving, next moving left */
 
   /* check if any connected player was not found in playfield */
@@ -1981,10 +2308,10 @@ void InitGame()
          player->element_nr = some_player->element_nr;
 #endif
 
-#if USE_NEW_BLOCK_STYLE
+         player->artwork_element = some_player->artwork_element;
+
          player->block_last_field       = some_player->block_last_field;
          player->block_delay_adjustment = some_player->block_delay_adjustment;
-#endif
 
          StorePlayer[jx][jy] = player->element_nr;
          player->jx = player->last_jx = jx;
@@ -1998,7 +2325,7 @@ void InitGame()
 
   if (tape.playing)
   {
-    /* when playing a tape, eliminate all players which do not participate */
+    /* when playing a tape, eliminate all players who do not participate */
 
     for (i = 0; i < MAX_PLAYERS; i++)
     {
@@ -2091,14 +2418,30 @@ void InitGame()
     int start_x = 0, start_y = 0;
     int found_rating = 0;
     int found_element = EL_UNDEFINED;
+    int player_nr = local_player->index_nr;
 
+#if 1
+    SCAN_PLAYFIELD(x, y)
+#else
     for (y = 0; y < lev_fieldy; y++) for (x = 0; x < lev_fieldx; x++)
+#endif
     {
       int element = Feld[x][y];
       int content;
       int xx, yy;
       boolean is_player;
 
+      if (level.use_start_element[player_nr] &&
+         level.start_element[player_nr] == element &&
+         found_rating < 4)
+      {
+       start_x = x;
+       start_y = y;
+
+       found_rating = 4;
+       found_element = element;
+      }
+
       if (!IS_CUSTOM_ELEMENT(element))
        continue;
 
@@ -2106,6 +2449,7 @@ void InitGame()
       {
        for (i = 0; i < element_info[element].num_change_pages; i++)
        {
+         /* check for player created from custom element as single target */
          content = element_info[element].change_page[i].target_element;
          is_player = ELEM_IS_PLAYER(content);
 
@@ -2122,7 +2466,8 @@ void InitGame()
 
       for (yy = 0; yy < 3; yy++) for (xx = 0; xx < 3; xx++)
       {
-       content = element_info[element].content[xx][yy];
+       /* check for player created from custom element as explosion content */
+       content = element_info[element].content.e[xx][yy];
        is_player = ELEM_IS_PLAYER(content);
 
        if (is_player && (found_rating < 2 || element < found_element))
@@ -2139,7 +2484,10 @@ void InitGame()
 
        for (i = 0; i < element_info[element].num_change_pages; i++)
        {
-         content= element_info[element].change_page[i].target_content[xx][yy];
+         /* check for player created from custom element as extended target */
+         content =
+           element_info[element].change_page[i].target_content.e[xx][yy];
+
          is_player = ELEM_IS_PLAYER(content);
 
          if (is_player && (found_rating < 1 || element < found_element))
@@ -2164,7 +2512,6 @@ void InitGame()
   }
   else
   {
-#if 1
     scroll_x = (local_player->jx < SBX_Left  + MIDPOSX ? SBX_Left :
                local_player->jx > SBX_Right + MIDPOSX ? SBX_Right :
                local_player->jx - MIDPOSX);
@@ -2172,21 +2519,10 @@ void InitGame()
     scroll_y = (local_player->jy < SBY_Upper + MIDPOSY ? SBY_Upper :
                local_player->jy > SBY_Lower + MIDPOSY ? SBY_Lower :
                local_player->jy - MIDPOSY);
-#else
-    scroll_x = SBX_Left;
-    scroll_y = SBY_Upper;
-    if (local_player->jx >= SBX_Left + MIDPOSX)
-      scroll_x = (local_player->jx <= SBX_Right + MIDPOSX ?
-                 local_player->jx - MIDPOSX :
-                 SBX_Right);
-    if (local_player->jy >= SBY_Upper + MIDPOSY)
-      scroll_y = (local_player->jy <= SBY_Lower + MIDPOSY ?
-                 local_player->jy - MIDPOSY :
-                 SBY_Lower);
-#endif
   }
 
-  CloseDoor(DOOR_CLOSE_1);
+  if (!game.restart_level)
+    CloseDoor(DOOR_CLOSE_1);
 
   /* !!! FIX THIS (START) !!! */
   if (level.game_engine_type == GAME_ENGINE_TYPE_EM)
@@ -2210,43 +2546,47 @@ void InitGame()
   }
   /* !!! FIX THIS (END) !!! */
 
-  /* copy default game door content to main double buffer */
-  BlitBitmap(graphic_info[IMG_GLOBAL_DOOR].bitmap, drawto,
-            DOOR_GFX_PAGEX5, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE, DX, DY);
+  if (!game.restart_level)
+  {
+    /* copy default game door content to main double buffer */
+    BlitBitmap(graphic_info[IMG_GLOBAL_DOOR].bitmap, drawto,
+              DOOR_GFX_PAGEX5, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE, DX, DY);
+  }
 
   DrawGameDoorValues();
 
-  UnmapGameButtons();
-  UnmapTapeButtons();
-  game_gadget[SOUND_CTRL_ID_MUSIC]->checked = setup.sound_music;
-  game_gadget[SOUND_CTRL_ID_LOOPS]->checked = setup.sound_loops;
-  game_gadget[SOUND_CTRL_ID_SIMPLE]->checked = setup.sound_simple;
-  MapGameButtons();
-  MapTapeButtons();
+  if (!game.restart_level)
+  {
+    UnmapGameButtons();
+    UnmapTapeButtons();
+    game_gadget[SOUND_CTRL_ID_MUSIC]->checked = setup.sound_music;
+    game_gadget[SOUND_CTRL_ID_LOOPS]->checked = setup.sound_loops;
+    game_gadget[SOUND_CTRL_ID_SIMPLE]->checked = setup.sound_simple;
+    MapGameButtons();
+    MapTapeButtons();
 
-  /* copy actual game door content to door double buffer for OpenDoor() */
-  BlitBitmap(drawto, bitmap_db_door,
-            DX, DY, DXSIZE, DYSIZE, DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
+    /* copy actual game 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_ALL);
+    OpenDoor(DOOR_OPEN_ALL);
 
-  PlaySoundStereo(SND_GAME_STARTING, SOUND_MIDDLE);
+    PlaySoundStereo(SND_GAME_STARTING, SOUND_MIDDLE);
 
-  if (setup.sound_music)
-    PlayLevelMusic();
+    if (setup.sound_music)
+      PlayLevelMusic();
 
-  KeyboardAutoRepeatOffUnlessAutoplay();
+    KeyboardAutoRepeatOffUnlessAutoplay();
 
-  if (options.debug)
-  {
-    for (i = 0; i < MAX_PLAYERS; i++)
-      printf("Player %d %sactive.\n",
-            i + 1, (stored_player[i].active ? "" : "not "));
+    if (options.debug)
+    {
+      for (i = 0; i < MAX_PLAYERS; i++)
+       printf("Player %d %sactive.\n",
+              i + 1, (stored_player[i].active ? "" : "not "));
+    }
   }
 
-#if 0
-  printf("::: starting game [%d]\n", FrameCounter);
-#endif
+  game.restart_level = FALSE;
 }
 
 void UpdateEngineValues(int actual_scroll_x, int actual_scroll_y)
@@ -2317,6 +2657,14 @@ void InitMovDir(int x, int y)
       MovDir[x][y] = direction[0][element - EL_PACMAN_RIGHT];
       break;
 
+    case EL_YAMYAM_LEFT:
+    case EL_YAMYAM_RIGHT:
+    case EL_YAMYAM_UP:
+    case EL_YAMYAM_DOWN:
+      Feld[x][y] = EL_YAMYAM;
+      MovDir[x][y] = direction[2][element - EL_YAMYAM_LEFT];
+      break;
+
     case EL_SP_SNIKSNAK:
       MovDir[x][y] = MV_UP;
       break;
@@ -2342,7 +2690,7 @@ void InitMovDir(int x, int y)
 
        if (move_direction_initial == MV_START_PREVIOUS)
        {
-         if (MovDir[x][y] != MV_NO_MOVING)
+         if (MovDir[x][y] != MV_NONE)
            return;
 
          move_direction_initial = MV_START_AUTOMATIC;
@@ -2368,11 +2716,9 @@ void InitMovDir(int x, int y)
        else if (move_pattern == MV_ALONG_LEFT_SIDE ||
                 move_pattern == MV_ALONG_RIGHT_SIDE)
        {
-#if 1
          /* use random direction as default start direction */
          if (game.engine_version >= VERSION_IDENT(3,1,0,0))
            MovDir[x][y] = 1 << RND(4);
-#endif
 
          for (i = 0; i < NUM_DIRECTIONS; i++)
          {
@@ -2458,13 +2804,8 @@ void GameWon()
   if (local_player->MovPos)
     return;
 
-#if 1
   if (tape.auto_play)          /* tape might already be stopped here */
     tape.auto_play_level_solved = TRUE;
-#else
-  if (tape.playing && tape.auto_play)
-    tape.auto_play_level_solved = TRUE;
-#endif
 
   local_player->LevelSolved = FALSE;
 
@@ -2480,12 +2821,17 @@ void GameWon()
     {
       if (!tape.playing && !setup.sound_loops)
        PlaySoundStereo(SND_GAME_LEVELTIME_BONUS, SOUND_MIDDLE);
-      if (TimeLeft > 0 && !(TimeLeft % 10))
-       RaiseScore(level.score[SC_TIME_BONUS]);
-      if (TimeLeft > 100 && !(TimeLeft % 10))
+
+      if (TimeLeft > 100 && TimeLeft % 10 == 0)
+      {
        TimeLeft -= 10;
+       RaiseScore(level.score[SC_TIME_BONUS] * 10);
+      }
       else
+      {
        TimeLeft--;
+       RaiseScore(level.score[SC_TIME_BONUS]);
+      }
 
       DrawGameValue_Time(TimeLeft);
 
@@ -2508,12 +2854,17 @@ void GameWon()
     {
       if (!tape.playing && !setup.sound_loops)
        PlaySoundStereo(SND_GAME_LEVELTIME_BONUS, SOUND_MIDDLE);
-      if (TimePlayed < 999 && !(TimePlayed % 10))
-       RaiseScore(level.score[SC_TIME_BONUS]);
-      if (TimePlayed < 900 && !(TimePlayed % 10))
+
+      if (TimePlayed < 900 && TimePlayed % 10 == 0)
+      {
        TimePlayed += 10;
+       RaiseScore(level.score[SC_TIME_BONUS] * 10);
+      }
       else
+      {
        TimePlayed++;
+       RaiseScore(level.score[SC_TIME_BONUS]);
+      }
 
       DrawGameValue_Time(TimePlayed);
 
@@ -2540,12 +2891,19 @@ void GameWon()
     PlayLevelSoundElementAction(ExitX, ExitY, element, ACTION_CLOSING);
   }
 
-  /* Hero disappears */
+  /* player disappears */
   if (ExitX >= 0 && ExitY >= 0)
     DrawLevelField(ExitX, ExitY);
 
   BackToFront();
 
+#if 0
+  if (tape.playing)
+    printf("::: TAPE PLAYING -> DO NOT SAVE SCORE\n");
+  else
+    printf("::: NO TAPE PLAYING -> SAVING SCORE\n");
+#endif
+
   if (tape.playing)
     return;
 
@@ -2599,7 +2957,7 @@ int NewHiScore()
 
   LoadScore(level_nr);
 
-  if (strcmp(setup.player_name, EMPTY_PLAYER_NAME) == 0 ||
+  if (strEqual(setup.player_name, EMPTY_PLAYER_NAME) ||
       local_player->score < highscore[MAX_SCORE_ENTRIES - 1].Score) 
     return -1;
 
@@ -2615,7 +2973,7 @@ int NewHiScore()
 
 #ifdef ONE_PER_NAME
        for (l = k; l < MAX_SCORE_ENTRIES; l++)
-         if (!strcmp(setup.player_name, highscore[l].Name))
+         if (strEqual(setup.player_name, highscore[l].Name))
            m = l;
        if (m == k)     /* player's new highscore overwrites his old one */
          goto put_into_list;
@@ -2699,21 +3057,67 @@ void InitPlayerGfxAnimation(struct PlayerInfo *player, int action, int dir)
   }
 }
 
-static void ResetRandomAnimationValue(int x, int y)
+#if USE_GFX_RESET_GFX_ANIMATION
+static void ResetGfxFrame(int x, int y, boolean redraw)
 {
-  GfxRandom[x][y] = INIT_GFX_RANDOM();
+  int element = Feld[x][y];
+  int graphic = el_act_dir2img(element, GfxAction[x][y], GfxDir[x][y]);
+  int last_gfx_frame = GfxFrame[x][y];
+
+  if (graphic_info[graphic].anim_global_sync)
+    GfxFrame[x][y] = FrameCounter;
+  else if (ANIM_MODE(graphic) == ANIM_CE_VALUE)
+    GfxFrame[x][y] = CustomValue[x][y];
+  else if (ANIM_MODE(graphic) == ANIM_CE_SCORE)
+    GfxFrame[x][y] = element_info[element].collect_score;
+  else if (ANIM_MODE(graphic) == ANIM_CE_DELAY)
+    GfxFrame[x][y] = ChangeDelay[x][y];
+
+  if (redraw && GfxFrame[x][y] != last_gfx_frame)
+    DrawLevelGraphicAnimation(x, y, graphic);
 }
+#endif
 
 static void ResetGfxAnimation(int x, int y)
 {
-  GfxFrame[x][y] = 0;
+#if 0
+  int element, graphic;
+#endif
+
   GfxAction[x][y] = ACTION_DEFAULT;
   GfxDir[x][y] = MovDir[x][y];
+  GfxFrame[x][y] = 0;
+
+#if 0
+  element = Feld[x][y];
+  graphic = el_act_dir2img(element, GfxAction[x][y], GfxDir[x][y]);
+
+  if (graphic_info[graphic].anim_global_sync)
+    GfxFrame[x][y] = FrameCounter;
+  else if (ANIM_MODE(graphic) == ANIM_CE_VALUE)
+    GfxFrame[x][y] = CustomValue[x][y];
+  else if (ANIM_MODE(graphic) == ANIM_CE_SCORE)
+    GfxFrame[x][y] = element_info[element].collect_score;
+  else if (ANIM_MODE(graphic) == ANIM_CE_DELAY)
+    GfxFrame[x][y] = ChangeDelay[x][y];
+#endif
+
+#if USE_GFX_RESET_GFX_ANIMATION
+  ResetGfxFrame(x, y, FALSE);
+#endif
+}
+
+static void ResetRandomAnimationValue(int x, int y)
+{
+  GfxRandom[x][y] = INIT_GFX_RANDOM();
 }
 
 void InitMovingField(int x, int y, int direction)
 {
   int element = Feld[x][y];
+#if 0
+  int graphic;
+#endif
   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;
@@ -2722,50 +3126,54 @@ void InitMovingField(int x, int y, int direction)
   if (!WasJustMoving[x][y] || direction != MovDir[x][y])
     ResetGfxAnimation(x, y);
 
-#if USE_CAN_MOVE_NOT_MOVING
-
   MovDir[x][y] = direction;
   GfxDir[x][y] = direction;
   GfxAction[x][y] = (direction == MV_DOWN && CAN_FALL(element) ?
                     ACTION_FALLING : ACTION_MOVING);
 
+#if 0
+  graphic = el_act_dir2img(element, GfxAction[x][y], GfxDir[x][y]);
+
+  if (graphic_info[graphic].anim_global_sync)
+    GfxFrame[x][y] = FrameCounter;
+  else if (ANIM_MODE(graphic) == ANIM_CE_VALUE)
+    GfxFrame[x][y] = CustomValue[x][y];
+  else if (ANIM_MODE(graphic) == ANIM_CE_SCORE)
+    GfxFrame[x][y] = element_info[element].collect_score;
+  else if (ANIM_MODE(graphic) == ANIM_CE_DELAY)
+    GfxFrame[x][y] = ChangeDelay[x][y];
+#endif
+
+  /* this is needed for CEs with property "can move" / "not moving" */
+
   if (getElementMoveStepsize(x, y) != 0)       /* moving or being moved */
   {
     if (Feld[newx][newy] == EL_EMPTY)
       Feld[newx][newy] = EL_BLOCKED;
 
     MovDir[newx][newy] = MovDir[x][y];
+
+#if USE_NEW_CUSTOM_VALUE
+    CustomValue[newx][newy] = CustomValue[x][y];
+#endif
+
     GfxFrame[newx][newy] = GfxFrame[x][y];
     GfxRandom[newx][newy] = GfxRandom[x][y];
     GfxAction[newx][newy] = GfxAction[x][y];
     GfxDir[newx][newy] = GfxDir[x][y];
   }
-
-#else
-
-  MovDir[newx][newy] = MovDir[x][y] = direction;
-  GfxDir[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];
-  GfxRandom[newx][newy] = GfxRandom[x][y];
-  GfxAction[newx][newy] = GfxAction[x][y];
-  GfxDir[newx][newy] = GfxDir[x][y];
-#endif
 }
 
 void Moving2Blocked(int x, int y, int *goes_to_x, int *goes_to_y)
 {
   int direction = MovDir[x][y];
+#if 1
+  int newx = x + (direction & MV_LEFT ? -1 : direction & MV_RIGHT ? +1 : 0);
+  int newy = y + (direction & MV_UP   ? -1 : direction & MV_DOWN  ? +1 : 0);
+#else
   int newx = x + (direction == MV_LEFT ? -1 : direction == MV_RIGHT ? +1 : 0);
   int newy = y + (direction == MV_UP   ? -1 : direction == MV_DOWN  ? +1 : 0);
+#endif
 
   *goes_to_x = newx;
   *goes_to_y = newy;
@@ -2835,6 +3243,10 @@ static void RemoveField(int x, int y)
   MovDir[x][y] = 0;
   MovDelay[x][y] = 0;
 
+#if USE_NEW_CUSTOM_VALUE
+  CustomValue[x][y] = 0;
+#endif
+
   AmoebaNr[x][y] = 0;
   ChangeDelay[x][y] = 0;
   ChangePage[x][y] = -1;
@@ -2846,7 +3258,7 @@ static void RemoveField(int x, int y)
 
   GfxElement[x][y] = EL_UNDEFINED;
   GfxAction[x][y] = ACTION_DEFAULT;
-  GfxDir[x][y] = MV_NO_MOVING;
+  GfxDir[x][y] = MV_NONE;
 }
 
 void RemoveMovingField(int x, int y)
@@ -2861,10 +3273,7 @@ void RemoveMovingField(int x, int y)
   if (IS_MOVING(x, y))
   {
     Moving2Blocked(x, y, &newx, &newy);
-#if 0
-    if (Feld[newx][newy] != EL_BLOCKED)
-      return;
-#else
+
     if (Feld[newx][newy] != EL_BLOCKED)
     {
       /* element is moving, but target field is not free (blocked), but
@@ -2879,7 +3288,6 @@ void RemoveMovingField(int x, int y)
 
       return;
     }
-#endif
   }
   else if (element == EL_BLOCKED)
   {
@@ -2926,19 +3334,10 @@ void DrawDynamite(int x, int y)
 
   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, IMG_SP_DISK_RED, frame);
-  else if (Store[x][y])
-    DrawGraphicThruMask(sx, sy, graphic, frame);
-  else
-    DrawGraphic(sx, sy, graphic, frame);
-#endif
 }
 
 void CheckDynamite(int x, int y)
@@ -2956,52 +3355,126 @@ void CheckDynamite(int x, int y)
     }
   }
 
-#if 1
   StopLevelSoundActionIfLoop(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_ACTIVE);
-#endif
 
   Bang(x, y);
 }
 
-void DrawRelocatePlayer(struct PlayerInfo *player)
+#if 1
+
+static void setMinimalPlayerBoundaries(int *sx1, int *sy1, int *sx2, int *sy2)
+{
+  boolean num_checked_players = 0;
+  int i;
+
+  for (i = 0; i < MAX_PLAYERS; i++)
+  {
+    if (stored_player[i].active)
+    {
+      int sx = stored_player[i].jx;
+      int sy = stored_player[i].jy;
+
+      if (num_checked_players == 0)
+      {
+       *sx1 = *sx2 = sx;
+       *sy1 = *sy2 = sy;
+      }
+      else
+      {
+       *sx1 = MIN(*sx1, sx);
+       *sy1 = MIN(*sy1, sy);
+       *sx2 = MAX(*sx2, sx);
+       *sy2 = MAX(*sy2, sy);
+      }
+
+      num_checked_players++;
+    }
+  }
+}
+
+static boolean checkIfAllPlayersFitToScreen_RND()
+{
+  int sx1 = 0, sy1 = 0, sx2 = 0, sy2 = 0;
+
+  setMinimalPlayerBoundaries(&sx1, &sy1, &sx2, &sy2);
+
+  return (sx2 - sx1 < SCR_FIELDX &&
+         sy2 - sy1 < SCR_FIELDY);
+}
+
+static void setScreenCenteredToAllPlayers(int *sx, int *sy)
+{
+  int sx1 = scroll_x, sy1 = scroll_y, sx2 = scroll_x, sy2 = scroll_y;
+
+  setMinimalPlayerBoundaries(&sx1, &sy1, &sx2, &sy2);
+
+  *sx = (sx1 + sx2) / 2;
+  *sy = (sy1 + sy2) / 2;
+}
+
+#if 0
+static void setMaxCenterDistanceForAllPlayers(int *max_dx, int *max_dy,
+                                             int center_x, int center_y)
+{
+  int sx1 = center_x, sy1 = center_y, sx2 = center_x, sy2 = center_y;
+
+  setMinimalPlayerBoundaries(&sx1, &sy1, &sx2, &sy2);
+
+  *max_dx = MAX(ABS(sx1 - center_x), ABS(sx2 - center_x));
+  *max_dy = MAX(ABS(sy1 - center_y), ABS(sy2 - center_y));
+}
+
+static boolean checkIfAllPlayersAreVisible(int center_x, int center_y)
+{
+  int max_dx, max_dy;
+
+  setMaxCenterDistanceForAllPlayers(&max_dx, &max_dy, center_x, center_y);
+
+  return (max_dx <= SCR_FIELDX / 2 &&
+         max_dy <= SCR_FIELDY / 2);
+}
+#endif
+
+#endif
+
+#if 1
+
+void DrawRelocateScreen(int x, int y, int move_dir, boolean center_screen,
+                       boolean quick_relocation)
 {
   boolean ffwd_delay = (tape.playing && tape.fast_forward);
   boolean no_delay = (tape.warp_forward);
   int frame_delay_value = (ffwd_delay ? FfwdFrameDelay : GameFrameDelay);
   int wait_delay_value = (no_delay ? 0 : frame_delay_value);
-  int jx = player->jx;
-  int jy = player->jy;
 
-  if (level.instant_relocation)
+  if (quick_relocation)
   {
-#if 1
     int offset = (setup.scroll_delay ? 3 : 0);
 
-    if (!IN_VIS_FIELD(SCREENX(jx), SCREENY(jy)))
+#if 0
+    if (center_screen)
+      offset = 0;
+#endif
+
+    if (!IN_VIS_FIELD(SCREENX(x), SCREENY(y)) || center_screen)
     {
-      scroll_x = (local_player->jx < SBX_Left  + MIDPOSX ? SBX_Left :
-                 local_player->jx > SBX_Right + MIDPOSX ? SBX_Right :
-                 local_player->jx - MIDPOSX);
+      scroll_x = (x < SBX_Left  + MIDPOSX ? SBX_Left :
+                 x > SBX_Right + MIDPOSX ? SBX_Right :
+                 x - MIDPOSX);
 
-      scroll_y = (local_player->jy < SBY_Upper + MIDPOSY ? SBY_Upper :
-                 local_player->jy > SBY_Lower + MIDPOSY ? SBY_Lower :
-                 local_player->jy - MIDPOSY);
+      scroll_y = (y < SBY_Upper + MIDPOSY ? SBY_Upper :
+                 y > SBY_Lower + MIDPOSY ? SBY_Lower :
+                 y - MIDPOSY);
     }
     else
     {
-      if ((player->MovDir == MV_LEFT  && scroll_x > jx - MIDPOSX + offset) ||
-         (player->MovDir == MV_RIGHT && scroll_x < jx - MIDPOSX - offset))
-       scroll_x = jx - MIDPOSX + (scroll_x < jx-MIDPOSX ? -offset : +offset);
+      if ((move_dir == MV_LEFT  && scroll_x > x - MIDPOSX + offset) ||
+         (move_dir == MV_RIGHT && scroll_x < x - MIDPOSX - offset))
+       scroll_x = x - MIDPOSX + (scroll_x < x - MIDPOSX ? -offset : +offset);
 
-      if ((player->MovDir == MV_UP  && scroll_y > jy - MIDPOSY + offset) ||
-         (player->MovDir == MV_DOWN && scroll_y < jy - MIDPOSY - offset))
-       scroll_y = jy - MIDPOSY + (scroll_y < jy-MIDPOSY ? -offset : +offset);
+      if ((move_dir == MV_UP   && scroll_y > y - MIDPOSY + offset) ||
+         (move_dir == MV_DOWN && scroll_y < y - MIDPOSY - offset))
+       scroll_y = y - MIDPOSY + (scroll_y < y - MIDPOSY ? -offset : +offset);
 
       /* don't scroll over playfield boundaries */
       if (scroll_x < SBX_Left || scroll_x > SBX_Right)
@@ -3011,54 +3484,31 @@ void DrawRelocatePlayer(struct PlayerInfo *player)
       if (scroll_y < SBY_Upper || scroll_y > SBY_Lower)
        scroll_y = (scroll_y < SBY_Upper ? SBY_Upper : SBY_Lower);
     }
-#else
-    scroll_x += (local_player->jx - old_jx);
-    scroll_y += (local_player->jy - old_jy);
-
-    /* don't scroll over playfield boundaries */
-    if (scroll_x < SBX_Left || scroll_x > SBX_Right)
-      scroll_x = (scroll_x < SBX_Left ? SBX_Left : SBX_Right);
-
-    /* don't scroll over playfield boundaries */
-    if (scroll_y < SBY_Upper || scroll_y > SBY_Lower)
-      scroll_y = (scroll_y < SBY_Upper ? SBY_Upper : SBY_Lower);
-#endif
 
     RedrawPlayfield(TRUE, 0,0,0,0);
   }
   else
   {
-#if 1
-#if 0
-    int offset = (setup.scroll_delay ? 3 : 0);
-#endif
-    int scroll_xx = -999, scroll_yy = -999;
+    int scroll_xx = (x < SBX_Left  + MIDPOSX ? SBX_Left :
+                    x > SBX_Right + MIDPOSX ? SBX_Right :
+                    x - MIDPOSX);
+
+    int scroll_yy = (y < SBY_Upper + MIDPOSY ? SBY_Upper :
+                    y > SBY_Lower + MIDPOSY ? SBY_Lower :
+                    y - MIDPOSY);
 
     ScrollScreen(NULL, SCROLL_GO_ON);  /* scroll last frame to full tile */
 
-    while (scroll_xx != scroll_x || scroll_yy != scroll_y)
+    while (scroll_x != scroll_xx || scroll_y != scroll_yy)
     {
       int dx = 0, dy = 0;
       int fx = FX, fy = FY;
 
-      scroll_xx = (local_player->jx < SBX_Left  + MIDPOSX ? SBX_Left :
-                  local_player->jx > SBX_Right + MIDPOSX ? SBX_Right :
-                  local_player->jx - MIDPOSX);
-
-      scroll_yy = (local_player->jy < SBY_Upper + MIDPOSY ? SBY_Upper :
-                  local_player->jy > SBY_Lower + MIDPOSY ? SBY_Lower :
-                  local_player->jy - MIDPOSY);
-
       dx = (scroll_xx < scroll_x ? +1 : scroll_xx > scroll_x ? -1 : 0);
       dy = (scroll_yy < scroll_y ? +1 : scroll_yy > scroll_y ? -1 : 0);
 
-#if 1
       if (dx == 0 && dy == 0)          /* no scrolling needed at all */
        break;
-#else
-      if (scroll_xx == scroll_x && scroll_yy == scroll_y)
-       break;
-#endif
 
       scroll_x -= dx;
       scroll_y -= dy;
@@ -3078,34 +3528,81 @@ void DrawRelocatePlayer(struct PlayerInfo *player)
       BackToFront();
       Delay(wait_delay_value);
     }
+
+    DrawAllPlayers();
+    BackToFront();
+    Delay(wait_delay_value);
+  }
+}
+
 #else
-    int scroll_xx = -999, scroll_yy = -999;
+
+void DrawRelocatePlayer(struct PlayerInfo *player, boolean quick_relocation)
+{
+  boolean ffwd_delay = (tape.playing && tape.fast_forward);
+  boolean no_delay = (tape.warp_forward);
+  int frame_delay_value = (ffwd_delay ? FfwdFrameDelay : GameFrameDelay);
+  int wait_delay_value = (no_delay ? 0 : frame_delay_value);
+  int jx = player->jx;
+  int jy = player->jy;
+
+  if (quick_relocation)
+  {
+    int offset = (setup.scroll_delay ? 3 : 0);
+
+    if (!IN_VIS_FIELD(SCREENX(jx), SCREENY(jy)))
+    {
+      scroll_x = (player->jx < SBX_Left  + MIDPOSX ? SBX_Left :
+                 player->jx > SBX_Right + MIDPOSX ? SBX_Right :
+                 player->jx - MIDPOSX);
+
+      scroll_y = (player->jy < SBY_Upper + MIDPOSY ? SBY_Upper :
+                 player->jy > SBY_Lower + MIDPOSY ? SBY_Lower :
+                 player->jy - MIDPOSY);
+    }
+    else
+    {
+      if ((player->MovDir == MV_LEFT  && scroll_x > jx - MIDPOSX + offset) ||
+         (player->MovDir == MV_RIGHT && scroll_x < jx - MIDPOSX - offset))
+       scroll_x = jx - MIDPOSX + (scroll_x < jx-MIDPOSX ? -offset : +offset);
+
+      if ((player->MovDir == MV_UP  && scroll_y > jy - MIDPOSY + offset) ||
+         (player->MovDir == MV_DOWN && scroll_y < jy - MIDPOSY - offset))
+       scroll_y = jy - MIDPOSY + (scroll_y < jy-MIDPOSY ? -offset : +offset);
+
+      /* don't scroll over playfield boundaries */
+      if (scroll_x < SBX_Left || scroll_x > SBX_Right)
+       scroll_x = (scroll_x < SBX_Left ? SBX_Left : SBX_Right);
+
+      /* don't scroll over playfield boundaries */
+      if (scroll_y < SBY_Upper || scroll_y > SBY_Lower)
+       scroll_y = (scroll_y < SBY_Upper ? SBY_Upper : SBY_Lower);
+    }
+
+    RedrawPlayfield(TRUE, 0,0,0,0);
+  }
+  else
+  {
+    int scroll_xx = (player->jx < SBX_Left  + MIDPOSX ? SBX_Left :
+                    player->jx > SBX_Right + MIDPOSX ? SBX_Right :
+                    player->jx - MIDPOSX);
+
+    int scroll_yy = (player->jy < SBY_Upper + MIDPOSY ? SBY_Upper :
+                    player->jy > SBY_Lower + MIDPOSY ? SBY_Lower :
+                    player->jy - MIDPOSY);
 
     ScrollScreen(NULL, SCROLL_GO_ON);  /* scroll last frame to full tile */
 
-    while (scroll_xx != scroll_x || scroll_yy != scroll_y)
+    while (scroll_x != scroll_xx || scroll_y != scroll_yy)
     {
       int dx = 0, dy = 0;
       int fx = FX, fy = FY;
 
-      scroll_xx = (local_player->jx < SBX_Left  + MIDPOSX ? SBX_Left :
-                  local_player->jx > SBX_Right + MIDPOSX ? SBX_Right :
-                  local_player->jx - MIDPOSX);
-
-      scroll_yy = (local_player->jy < SBY_Upper + MIDPOSY ? SBY_Upper :
-                  local_player->jy > SBY_Lower + MIDPOSY ? SBY_Lower :
-                  local_player->jy - MIDPOSY);
-
       dx = (scroll_xx < scroll_x ? +1 : scroll_xx > scroll_x ? -1 : 0);
       dy = (scroll_yy < scroll_y ? +1 : scroll_yy > scroll_y ? -1 : 0);
 
-#if 1
       if (dx == 0 && dy == 0)          /* no scrolling needed at all */
        break;
-#else
-      if (scroll_xx == scroll_x && scroll_yy == scroll_y)
-       break;
-#endif
 
       scroll_x -= dx;
       scroll_y -= dy;
@@ -3125,7 +3622,6 @@ void DrawRelocatePlayer(struct PlayerInfo *player)
       BackToFront();
       Delay(wait_delay_value);
     }
-#endif
 
     DrawPlayer(player);
     BackToFront();
@@ -3133,14 +3629,13 @@ void DrawRelocatePlayer(struct PlayerInfo *player)
   }
 }
 
+#endif
+
 void RelocatePlayer(int jx, int jy, int el_player_raw)
 {
-#if 1
-  int el_player = GET_VALID_PLAYER_ELEMENT(el_player_raw);
-#else
-  int el_player = (el_player_raw == EL_SP_MURPHY ? EL_PLAYER_1 :el_player_raw);
-#endif
-  struct PlayerInfo *player = &stored_player[el_player - EL_PLAYER_1];
+  int el_player = GET_PLAYER_ELEMENT(el_player_raw);
+  int player_nr = GET_PLAYER_NR(el_player);
+  struct PlayerInfo *player = &stored_player[player_nr];
   boolean ffwd_delay = (tape.playing && tape.fast_forward);
   boolean no_delay = (tape.warp_forward);
   int frame_delay_value = (ffwd_delay ? FfwdFrameDelay : GameFrameDelay);
@@ -3153,25 +3648,10 @@ void RelocatePlayer(int jx, int jy, int el_player_raw)
 
   int move_dir_horiz = (jx < old_jx ? MV_LEFT : jx > old_jx ? MV_RIGHT : 0);
   int move_dir_vert  = (jy < old_jy ? MV_UP   : jy > old_jy ? MV_DOWN  : 0);
-#if 1
   int enter_side_horiz = MV_DIR_OPPOSITE(move_dir_horiz);
   int enter_side_vert  = MV_DIR_OPPOSITE(move_dir_vert);
   int leave_side_horiz = move_dir_horiz;
   int leave_side_vert  = move_dir_vert;
-#else
-  static int trigger_sides[4][2] =
-  {
-    /* enter side               leave side */
-    { CH_SIDE_RIGHT,           CH_SIDE_LEFT    },      /* moving left  */
-    { CH_SIDE_LEFT,            CH_SIDE_RIGHT   },      /* moving right */
-    { CH_SIDE_BOTTOM,          CH_SIDE_TOP     },      /* moving up    */
-    { CH_SIDE_TOP,             CH_SIDE_BOTTOM  }       /* moving down  */
-  };
-  int enter_side_horiz = trigger_sides[MV_DIR_BIT(move_dir_horiz)][0];
-  int enter_side_vert  = trigger_sides[MV_DIR_BIT(move_dir_vert)][0];
-  int leave_side_horiz = trigger_sides[MV_DIR_BIT(move_dir_horiz)][1];
-  int leave_side_vert  = trigger_sides[MV_DIR_BIT(move_dir_vert)][1];
-#endif
   int enter_side = enter_side_horiz | enter_side_vert;
   int leave_side = leave_side_horiz | leave_side_vert;
 
@@ -3194,11 +3674,7 @@ void RelocatePlayer(int jx, int jy, int el_player_raw)
       ScrollPlayer(player, SCROLL_GO_ON);
       ScrollScreen(NULL, SCROLL_GO_ON);
 
-#if USE_NEW_MOVE_DELAY
       AdvanceFrameAndPlayerCounters(player->index_nr);
-#else
-      FrameCounter++;
-#endif
 
       DrawPlayer(player);
 
@@ -3212,7 +3688,6 @@ void RelocatePlayer(int jx, int jy, int el_player_raw)
     player->is_moving = FALSE;
   }
 
-#if 1
   if (IS_CUSTOM_ELEMENT(old_element))
     CheckElementChangeByPlayer(old_jx, old_jy, old_element,
                               CE_LEFT_BY_PLAYER,
@@ -3221,7 +3696,6 @@ void RelocatePlayer(int jx, int jy, int el_player_raw)
   CheckTriggeredElementChangeByPlayer(old_jx, old_jy, old_element,
                                      CE_PLAYER_LEAVES_X,
                                      player->index_bit, leave_side);
-#endif
 
   Feld[jx][jy] = el_player;
   InitPlayerField(jx, jy, el_player, TRUE);
@@ -3233,68 +3707,39 @@ void RelocatePlayer(int jx, int jy, int el_player_raw)
   }
 
 #if 1
-  if (player == local_player)  /* only visually relocate local player */
-    DrawRelocatePlayer(player);
-#endif
-
+  /* only visually relocate centered player */
 #if 1
-  TestIfHeroTouchesBadThing(jx, jy);
-  TestIfPlayerTouchesCustomElement(jx, jy);
-#endif
-
-#if 0
-  printf("::: %d,%d: %d\n", jx, jy-1, Changed[jx][jy-1]);
-#endif
-
-#if 0
-#if 0
-  /* needed to allow change of walkable custom element by entering player */
-  if (!(Changed[jx][jy] & CH_EVENT_BIT(CE_ENTERED_BY_PLAYER)))
-    Changed[jx][jy] = 0;       /* allow another change (but prevent loop) */
+  DrawRelocateScreen(player->jx, player->jy, player->MovDir, FALSE,
+                    level.instant_relocation);
 #else
-  /* needed to allow change of walkable custom element by entering player */
-  Changed[jx][jy] = 0;         /* allow another change */
+  if (player->index_nr == game.centered_player_nr)
+    DrawRelocatePlayer(player, level.instant_relocation);
 #endif
+#else
+  if (player == local_player)  /* only visually relocate local player */
+    DrawRelocatePlayer(player, level.instant_relocation);
 #endif
 
-#if 0
-  printf("::: player entering %d, %d from %s ...\n", jx, jy,
-        enter_side == MV_LEFT  ? "left" :
-        enter_side == MV_RIGHT ? "right" :
-        enter_side == MV_UP    ? "top" :
-        enter_side == MV_DOWN  ? "bottom" : "oops! no idea!");
-#endif
+  TestIfPlayerTouchesBadThing(jx, jy);
+  TestIfPlayerTouchesCustomElement(jx, jy);
 
-#if 1
   if (IS_CUSTOM_ELEMENT(element))
     CheckElementChangeByPlayer(jx, jy, element, CE_ENTERED_BY_PLAYER,
                               player->index_bit, enter_side);
 
-  CheckTriggeredElementChangeByPlayer(jx, jy, element,
-                                     CE_PLAYER_ENTERS_X,
+  CheckTriggeredElementChangeByPlayer(jx, jy, element, CE_PLAYER_ENTERS_X,
                                      player->index_bit, enter_side);
-#endif
 }
 
 void Explode(int ex, int ey, int phase, int mode)
 {
   int x, y;
-#if 0
-  int num_phase = 9;
-#endif
+  int last_phase;
+  int border_element;
 
   /* !!! eliminate this variable !!! */
   int delay = (game.emulation == EMU_SUPAPLEX ? 3 : 2);
 
-#if 1
-  int last_phase;
-#else
-  int last_phase = num_phase * delay;
-  int half_phase = (num_phase / 2) * delay;
-  int first_phase_after_start = EX_PHASE_START + 1;
-#endif
-  int border_element;
-
   if (game.explosions_delayed)
   {
     ExplodeField[ex][ey] = mode;
@@ -3304,10 +3749,7 @@ void Explode(int ex, int ey, int phase, int mode)
   if (phase == EX_PHASE_START)         /* initialize 'Store[][]' field */
   {
     int center_element = Feld[ex][ey];
-
-#if 0
-    printf("::: start explosion %d,%d [%d]\n", ex, ey, FrameCounter);
-#endif
+    int artwork_element, explosion_element;    /* set these values later */
 
 #if 0
     /* --- This is only really needed (and now handled) in "Impact()". --- */
@@ -3318,14 +3760,12 @@ void Explode(int ex, int ey, int phase, int mode)
       return;
 #endif
 
-#if 1
+#if 0
+    /* !!! at this place, the center element may be EL_BLOCKED !!! */
     if (mode == EX_TYPE_NORMAL ||
        mode == EX_TYPE_CENTER ||
        mode == EX_TYPE_CROSS)
-      PlayLevelSoundAction(ex, ey, ACTION_EXPLODING);
-#else
-    if (mode == EX_TYPE_NORMAL || mode == EX_TYPE_CENTER)
-      PlayLevelSoundAction(ex, ey, ACTION_EXPLODING);
+      PlayLevelSoundElementAction(ex, ey, artwork_element, ACTION_EXPLODING);
 #endif
 
     /* remove things displayed in background while burning dynamite */
@@ -3340,17 +3780,34 @@ void Explode(int ex, int ey, int phase, int mode)
       Feld[ex][ey] = center_element;
     }
 
-#if 1
+    /* now "center_element" is finally determined -- set related values now */
+    artwork_element = center_element;          /* for custom player artwork */
+    explosion_element = center_element;                /* for custom player artwork */
+
+    if (IS_PLAYER(ex, ey))
+    {
+      int player_nr = GET_PLAYER_NR(StorePlayer[ex][ey]);
+
+      artwork_element = stored_player[player_nr].artwork_element;
+
+      if (level.use_explosion_element[player_nr])
+      {
+       explosion_element = level.explosion_element[player_nr];
+       artwork_element = explosion_element;
+      }
+    }
 
 #if 1
-    last_phase = element_info[center_element].explosion_delay + 1;
-#else
-    last_phase = element_info[center_element].explosion_delay;
+    if (mode == EX_TYPE_NORMAL ||
+       mode == EX_TYPE_CENTER ||
+       mode == EX_TYPE_CROSS)
+      PlayLevelSoundElementAction(ex, ey, artwork_element, ACTION_EXPLODING);
 #endif
 
-#if 0
-    printf("::: %d -> %d\n", center_element, last_phase);
-#endif
+#if 1
+    last_phase = element_info[explosion_element].explosion_delay + 1;
+#else
+    last_phase = element_info[center_element].explosion_delay + 1;
 #endif
 
     for (y = ey - 1; y <= ey + 1; y++) for (x = ex - 1; x <= ex + 1; x++)
@@ -3359,24 +3816,10 @@ void Explode(int ex, int ey, int phase, int mode)
       int yy = y - ey + 1;
       int element;
 
-#if 1
-#if 1
       if (!IN_LEV_FIELD(x, y) ||
          (mode & EX_TYPE_SINGLE_TILE && (x != ex || y != ey)) ||
          (mode == EX_TYPE_CROSS      && (x != ex && y != ey)))
        continue;
-#else
-      if (!IN_LEV_FIELD(x, y) ||
-         (mode != EX_TYPE_NORMAL && (x != ex || y != ey)))
-       continue;
-#endif
-#else
-      if (!IN_LEV_FIELD(x, y) ||
-         ((mode != EX_TYPE_NORMAL ||
-           center_element == EL_AMOEBA_TO_DIAMOND) &&
-          (x != ex || y != ey)))
-       continue;
-#endif
 
       element = Feld[x][y];
 
@@ -3388,32 +3831,11 @@ void Explode(int ex, int ey, int phase, int mode)
          RemoveMovingField(x, y);
       }
 
-#if 1
-
-#if 0
-      if (IS_EXPLOSION_PROOF(element))
-       continue;
-#else
       /* indestructible elements can only explode in center (but not flames) */
-#if 1
       if ((IS_EXPLOSION_PROOF(element) && (x != ex || y != ey ||
                                           mode == EX_TYPE_BORDER)) ||
          element == EL_FLAMES)
        continue;
-#else
-      if ((IS_EXPLOSION_PROOF(element) && (x != ex || y != ey)) ||
-         element == EL_FLAMES)
-       continue;
-#endif
-#endif
-
-#else
-      if ((IS_INDESTRUCTIBLE(element) &&
-          (game.engine_version < VERSION_IDENT(2,2,0,0) ||
-           (!IS_WALKABLE_OVER(element) && !IS_WALKABLE_UNDER(element)))) ||
-         element == EL_FLAMES)
-       continue;
-#endif
 
       /* no idea why this was changed from 3.0.8 to 3.1.0 -- this causes buggy
         behaviour, for example when touching a yamyam that explodes to rocks
@@ -3430,50 +3852,22 @@ void Explode(int ex, int ey, int phase, int mode)
        if (IS_ACTIVE_BOMB(element))
        {
          /* re-activate things under the bomb like gate or penguin */
-#if 1
          Feld[x][y] = (Back[x][y] ? Back[x][y] : EL_EMPTY);
          Back[x][y] = 0;
-#else
-         Feld[x][y] = (Store[x][y] ? Store[x][y] : EL_EMPTY);
-         Store[x][y] = 0;
-#endif
-
-#if 0
-       printf("::: %d,%d: %d %s [%d, %d]\n", x, y, Feld[x][y],
-              element_info[Feld[x][y]].token_name,
-              Store[x][y], Store2[x][y]);
-#endif
        }
 
        continue;
       }
 
       /* save walkable background elements while explosion on same tile */
-#if 0
-      if (IS_INDESTRUCTIBLE(element))
-       Back[x][y] = element;
-#else
-#if 1
-#if 1
       if (IS_WALKABLE(element) && IS_INDESTRUCTIBLE(element) &&
          (x != ex || y != ey || mode == EX_TYPE_BORDER))
        Back[x][y] = element;
-#else
-      if (IS_WALKABLE(element) && IS_INDESTRUCTIBLE(element) &&
-         (x != ex || y != ey))
-       Back[x][y] = element;
-#endif
-#else
-      if (IS_WALKABLE(element) && IS_INDESTRUCTIBLE(element))
-       Back[x][y] = element;
-#endif
-#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 ||
@@ -3484,10 +3878,14 @@ void Explode(int ex, int ey, int phase, int mode)
       }
 
       RemoveField(x, y);
-#endif
 
       if (IS_PLAYER(ex, ey) && !PLAYER_EXPLOSION_PROTECTED(ex, ey))
       {
+#if 1
+       int player_nr = StorePlayer[ex][ey] - EL_PLAYER_1;
+
+       Store[x][y] = EL_PLAYER_IS_EXPLODING_1 + player_nr;
+#else
        switch(StorePlayer[ex][ey])
        {
          case EL_PLAYER_2:
@@ -3504,15 +3902,33 @@ void Explode(int ex, int ey, int phase, int mode)
            Store[x][y] = EL_PLAYER_IS_EXPLODING_1;
            break;
        }
+#endif
 
-#if 1
-       if (PLAYERINFO(ex, ey)->use_murphy_graphic)
+       if (PLAYERINFO(ex, ey)->use_murphy)
          Store[x][y] = EL_EMPTY;
+      }
+#if 1
+      /* !!! check this case -- currently needed for rnd_rado_negundo_v,
+        !!! levels 015 018 019 020 021 022 023 026 027 028 !!! */
+      else if (ELEM_IS_PLAYER(center_element))
+       Store[x][y] = EL_EMPTY;
+      else if (center_element == EL_YAMYAM)
+       Store[x][y] = level.yamyam_content[game.yamyam_content_nr].e[xx][yy];
+      else if (element_info[center_element].content.e[xx][yy] != EL_EMPTY)
+       Store[x][y] = element_info[center_element].content.e[xx][yy];
+#if 1
+      /* needed because EL_BD_BUTTERFLY is not defined as "CAN_EXPLODE"
+        (killing EL_BD_BUTTERFLY with dynamite would result in BD diamond
+        otherwise) -- FIX THIS !!! */
+      else if (!CAN_EXPLODE(element) && element != EL_BD_BUTTERFLY)
+       Store[x][y] = element_info[element].content.e[1][1];
 #else
-       if (game.emulation == EMU_SUPAPLEX)
-         Store[x][y] = EL_EMPTY;
+      else if (!CAN_EXPLODE(element))
+       Store[x][y] = element_info[element].content.e[1][1];
 #endif
-      }
+      else
+       Store[x][y] = EL_EMPTY;
+#else
       else if (center_element == EL_MOLE)
        Store[x][y] = EL_EMERALD_RED;
       else if (center_element == EL_PENGUIN)
@@ -3526,10 +3942,10 @@ void Explode(int ex, int ey, int phase, int mode)
       else if (center_element == EL_AMOEBA_TO_DIAMOND)
        Store[x][y] = level.amoeba_content;
       else if (center_element == EL_YAMYAM)
-       Store[x][y] = level.yamyam_content[game.yamyam_content_nr][xx][yy];
+       Store[x][y] = level.yamyam_content[game.yamyam_content_nr].e[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];
+              element_info[center_element].content.e[xx][yy] != EL_EMPTY)
+       Store[x][y] = element_info[center_element].content.e[xx][yy];
       else if (element == EL_WALL_EMERALD)
        Store[x][y] = EL_EMERALD;
       else if (element == EL_WALL_DIAMOND)
@@ -3547,57 +3963,25 @@ void Explode(int ex, int ey, int phase, int mode)
       else if (element == EL_WALL_CRYSTAL)
        Store[x][y] = EL_CRYSTAL;
       else if (IS_CUSTOM_ELEMENT(element) && !CAN_EXPLODE(element))
-       Store[x][y] = element_info[element].content[1][1];
+       Store[x][y] = element_info[element].content.e[1][1];
       else
        Store[x][y] = EL_EMPTY;
+#endif
 
       if (x != ex || y != ey || mode == EX_TYPE_BORDER ||
          center_element == EL_AMOEBA_TO_DIAMOND)
        Store2[x][y] = element;
 
-#if 0
-      printf("::: %d,%d: %d %s\n", x, y, Store2[x][y],
-            element_info[Store2[x][y]].token_name);
-#endif
+      Feld[x][y] = EL_EXPLOSION;
+      GfxElement[x][y] = artwork_element;
 
 #if 0
-      if (AmoebaNr[x][y] &&
-         (element == EL_AMOEBA_FULL ||
-          element == EL_BD_AMOEBA ||
-          element == EL_AMOEBA_GROWING))
-      {
-       AmoebaCnt[AmoebaNr[x][y]]--;
-       AmoebaCnt2[AmoebaNr[x][y]]--;
-      }
-
-#if 1
-      RemoveField(x, y);
-#else
-      MovDir[x][y] = MovPos[x][y] = 0;
-      GfxDir[x][y] = MovDir[x][y];
-      AmoebaNr[x][y] = 0;
-#endif
-#endif
-
-      Feld[x][y] = EL_EXPLOSION;
-#if 1
-      GfxElement[x][y] = center_element;
-#else
-      GfxElement[x][y] = EL_UNDEFINED;
+      printf(":: setting gfx(%d,%d) to %d ['%s']\n",
+            x, y, artwork_element, EL_NAME(artwork_element));
 #endif
 
       ExplodePhase[x][y] = 1;
-#if 1
       ExplodeDelay[x][y] = last_phase;
-#endif
-
-#if 0
-#if 1
-      GfxFrame[x][y] = 0;      /* animation does not start until next frame */
-#else
-      GfxFrame[x][y] = -1;     /* animation does not start until next frame */
-#endif
-#endif
 
       Stop[x][y] = TRUE;
     }
@@ -3606,11 +3990,6 @@ void Explode(int ex, int ey, int phase, int mode)
       game.yamyam_content_nr =
        (game.yamyam_content_nr + 1) % level.num_yamyam_contents;
 
-#if 0
-  printf("::: %d,%d: %d %s [%d]\n", ex + 1, ey, Feld[ex + 1][ey],
-        element_info[Feld[ex + 1][ey]].token_name, Store2[ex + 1][ey]);
-#endif
-
     return;
   }
 
@@ -3620,18 +3999,10 @@ void Explode(int ex, int ey, int phase, int mode)
   x = ex;
   y = ey;
 
-#if 1
   if (phase == 1)
     GfxFrame[x][y] = 0;                /* restart explosion animation */
-#endif
 
-#if 0
-  printf(":X: phase == %d [%d]\n", phase, GfxFrame[x][y]);
-#endif
-
-#if 1
   last_phase = ExplodeDelay[x][y];
-#endif
 
   ExplodePhase[x][y] = (phase < last_phase ? phase + 1 : 0);
 
@@ -3639,9 +4010,15 @@ void Explode(int ex, int ey, int phase, int mode)
 
   /* activate this even in non-DEBUG version until cause for crash in
      getGraphicAnimationFrame() (see below) is found and eliminated */
+
 #endif
 #if 1
 
+#if 1
+  /* this can happen if the player leaves an explosion just in time */
+  if (GfxElement[x][y] == EL_UNDEFINED)
+    GfxElement[x][y] = EL_EMPTY;
+#else
   if (GfxElement[x][y] == EL_UNDEFINED)
   {
     printf("\n\n");
@@ -3653,133 +4030,48 @@ void Explode(int ex, int ey, int phase, int mode)
   }
 #endif
 
-#if 1
+#endif
 
   border_element = Store2[x][y];
-#if 1
   if (IS_PLAYER(x, y) && !PLAYER_EXPLOSION_PROTECTED(x, y))
     border_element = StorePlayer[x][y];
-#else
-  if (IS_PLAYER(x, y))
-    border_element = StorePlayer[x][y];
-#endif
-
-#if 0
-  printf("::: %d,%d: %d %s [%d]\n", x, y, border_element,
-        element_info[border_element].token_name, Store2[x][y]);
-#endif
-
-#if 0
-  printf("::: phase == %d\n", phase);
-#endif
 
   if (phase == element_info[border_element].ignition_delay ||
       phase == last_phase)
   {
     boolean border_explosion = FALSE;
 
-#if 1
-#if 1
     if (IS_PLAYER(x, y) && PLAYERINFO(x, y)->present &&
        !PLAYER_EXPLOSION_PROTECTED(x, y))
-#else
-    if (IS_PLAYER(x, y) && PLAYERINFO(x, y)->present)
-#endif
-#else
-    if (IS_PLAYER(x, y))
-#endif
     {
-      KillHeroUnlessExplosionProtected(x, y);
+      KillPlayerUnlessExplosionProtected(x, y);
       border_explosion = TRUE;
-
-#if 0
-      if (phase == last_phase)
-       printf("::: IS_PLAYER\n");
-#endif
     }
     else if (CAN_EXPLODE_BY_EXPLOSION(border_element))
     {
-#if 0
-      printf("::: %d,%d: %d %s\n", x, y, border_element,
-            element_info[border_element].token_name);
-#endif
-
       Feld[x][y] = Store2[x][y];
       Store2[x][y] = 0;
       Bang(x, y);
       border_explosion = TRUE;
-
-#if 0
-      if (phase == last_phase)
-       printf("::: CAN_EXPLODE_BY_EXPLOSION\n");
-#endif
     }
     else if (border_element == EL_AMOEBA_TO_DIAMOND)
     {
       AmoebeUmwandeln(x, y);
       Store2[x][y] = 0;
       border_explosion = TRUE;
-
-#if 0
-      if (phase == last_phase)
-       printf("::: EL_AMOEBA_TO_DIAMOND [%d, %d] [%d]\n",
-              element_info[border_element].explosion_delay,
-              element_info[border_element].ignition_delay,
-              phase);
-#endif
     }
 
-#if 1
     /* if an element just explodes due to another explosion (chain-reaction),
        do not immediately end the new explosion when it was the last frame of
        the explosion (as it would be done in the following "if"-statement!) */
     if (border_explosion && phase == last_phase)
       return;
-#endif
-  }
-
-#else
-
-  if (phase == first_phase_after_start)
-  {
-    int element = Store2[x][y];
-
-    if (element == EL_BLACK_ORB)
-    {
-      Feld[x][y] = Store2[x][y];
-      Store2[x][y] = 0;
-      Bang(x, y);
-    }
-  }
-  else if (phase == half_phase)
-  {
-    int element = Store2[x][y];
-
-    if (IS_PLAYER(x, y))
-      KillHeroUnlessExplosionProtected(x, y);
-    else if (CAN_EXPLODE_BY_EXPLOSION(element))
-    {
-      Feld[x][y] = Store2[x][y];
-      Store2[x][y] = 0;
-      Bang(x, y);
-    }
-    else if (element == EL_AMOEBA_TO_DIAMOND)
-      AmoebeUmwandeln(x, y);
   }
-#endif
 
   if (phase == last_phase)
   {
     int element;
 
-#if 0
-  printf("::: done: phase == %d\n", phase);
-#endif
-
-#if 0
-    printf("::: explosion %d,%d done [%d]\n", x, y, FrameCounter);
-#endif
-
     element = Feld[x][y] = Store[x][y];
     Store[x][y] = Store2[x][y] = 0;
     GfxElement[x][y] = EL_UNDEFINED;
@@ -3787,12 +4079,18 @@ void Explode(int ex, int ey, int phase, int mode)
     /* player can escape from explosions and might therefore be still alive */
     if (element >= EL_PLAYER_IS_EXPLODING_1 &&
        element <= EL_PLAYER_IS_EXPLODING_4)
-      Feld[x][y] = (stored_player[element - EL_PLAYER_IS_EXPLODING_1].active ?
-                   EL_EMPTY :
-                   element == EL_PLAYER_IS_EXPLODING_1 ? EL_EMERALD_YELLOW :
-                   element == EL_PLAYER_IS_EXPLODING_2 ? EL_EMERALD_RED :
-                   element == EL_PLAYER_IS_EXPLODING_3 ? EL_EMERALD :
-                   EL_EMERALD_PURPLE);
+    {
+      int player_nr = element - EL_PLAYER_IS_EXPLODING_1;
+      int explosion_element = EL_PLAYER_1 + player_nr;
+      int xx = MIN(MAX(0, x - stored_player[player_nr].jx + 1), 2);
+      int yy = MIN(MAX(0, y - stored_player[player_nr].jy + 1), 2);
+
+      if (level.use_explosion_element[player_nr])
+       explosion_element = level.explosion_element[player_nr];
+
+      Feld[x][y] = (stored_player[player_nr].active ? EL_EMPTY :
+                   element_info[explosion_element].content.e[xx][yy]);
+    }
 
     /* restore probably existing indestructible background element */
     if (Back[x][y] && IS_INDESTRUCTIBLE(Back[x][y]))
@@ -3800,26 +4098,16 @@ void Explode(int ex, int ey, int phase, int mode)
     Back[x][y] = 0;
 
     MovDir[x][y] = MovPos[x][y] = MovDelay[x][y] = 0;
-    GfxDir[x][y] = MV_NO_MOVING;
+    GfxDir[x][y] = MV_NONE;
     ChangeDelay[x][y] = 0;
     ChangePage[x][y] = -1;
 
-#if 1
-    InitField_WithBug2(x, y, FALSE);
-#else
-    InitField(x, y, FALSE);
-#if 1
-    /* !!! not needed !!! */
-#if 1
-    if (game.engine_version < VERSION_IDENT(3,1,0,0) &&
-       CAN_MOVE(Feld[x][y]) && Feld[x][y] != EL_MOLE)
-      InitMovDir(x, y);
-#else
-    if (CAN_MOVE(element))
-      InitMovDir(x, y);
-#endif
-#endif
+#if USE_NEW_CUSTOM_VALUE
+    CustomValue[x][y] = 0;
 #endif
+
+    InitField_WithBug2(x, y, FALSE);
+
     DrawLevelField(x, y);
 
     TestIfElementTouchesCustomElement(x, y);
@@ -3833,40 +4121,10 @@ void Explode(int ex, int ey, int phase, int mode)
     if (ELEM_IS_PLAYER(element))
       RelocatePlayer(x, y, element);
   }
-#if 1
   else if (IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
-#else
-  else if (phase >= delay && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
-#endif
   {
-#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
-#if 1
     int frame = getGraphicAnimationFrame(graphic, GfxFrame[x][y]);
-#else
-    int frame = getGraphicAnimationFrame(graphic, phase - delay);
-#endif
-
-#if 0
-  printf("::: phase == %d [%d]\n", phase, GfxFrame[x][y]);
-#endif
-
-#if 0
-    printf("::: %d / %d [%d - %d]\n",
-          GfxFrame[x][y], phase - delay, phase, delay);
-#endif
-
-#if 0
-    printf("::: %d ['%s'] -> %d\n", GfxElement[x][y],
-          element_info[GfxElement[x][y]].token_name,
-          graphic);
-#endif
 
     if (phase == delay)
       DrawLevelFieldCrumbledSand(x, y);
@@ -3930,61 +4188,35 @@ void DynaExplode(int ex, int ey)
 
       Explode(x, y, EX_PHASE_START, EX_TYPE_BORDER);
 
-#if 1
-#if 1
       if (element != EL_EMPTY && element != EL_EXPLOSION &&
          !IS_DIGGABLE(element) && !dynabomb_xl)
        break;
-#else
-      if (element != EL_EMPTY && element != EL_EXPLOSION &&
-         !CAN_GROW_INTO(element) && !dynabomb_xl)
-       break;
-#endif
-#else
-      /* !!! extend EL_SAND to anything diggable (but maybe not SP_BASE) !!! */
-      if (element != EL_EMPTY && element != EL_EXPLOSION &&
-         element != EL_SAND && !dynabomb_xl)
-       break;
-#endif
     }
   }
 }
 
 void Bang(int x, int y)
 {
-#if 1
   int element = MovingOrBlocked2Element(x, y);
-#else
-  int element = Feld[x][y];
-#endif
+  int explosion_type = EX_TYPE_NORMAL;
 
-#if 1
   if (IS_PLAYER(x, y) && !PLAYER_EXPLOSION_PROTECTED(x, y))
-#else
-  if (IS_PLAYER(x, y))
-#endif
   {
     struct PlayerInfo *player = PLAYERINFO(x, y);
 
-    element = Feld[x][y] = (player->use_murphy_graphic ? EL_SP_MURPHY :
+    element = Feld[x][y] = (player->use_murphy ? EL_SP_MURPHY :
                            player->element_nr);
-  }
 
-#if 0
-#if 1
-  PlayLevelSoundAction(x, y, ACTION_EXPLODING);
-#else
-  if (game.emulation == EMU_SUPAPLEX)
-    PlayLevelSound(x, y, SND_SP_ELEMENT_EXPLODING);
-  else
-    PlayLevelSound(x, y, SND_ELEMENT_EXPLODING);
-#endif
-#endif
+    if (level.use_explosion_element[player->index_nr])
+    {
+      int explosion_element = level.explosion_element[player->index_nr];
 
-#if 0
-  if (IS_PLAYER(x, y)) /* remove objects that might cause smaller explosion */
-    element = EL_EMPTY;
-#endif
+      if (element_info[explosion_element].explosion_type == EXPLODES_CROSS)
+       explosion_type = EX_TYPE_CROSS;
+      else if (element_info[explosion_element].explosion_type == EXPLODES_1X1)
+       explosion_type = EX_TYPE_CENTER;
+    }
+  }
 
   switch(element)
   {
@@ -3998,8 +4230,8 @@ void Bang(int x, int y)
     case EL_PACMAN:
     case EL_MOLE:
       RaiseScoreElement(element);
-      Explode(x, y, EX_PHASE_START, EX_TYPE_NORMAL);
       break;
+
     case EL_DYNABOMB_PLAYER_1_ACTIVE:
     case EL_DYNABOMB_PLAYER_2_ACTIVE:
     case EL_DYNABOMB_PLAYER_3_ACTIVE:
@@ -4007,47 +4239,35 @@ void Bang(int x, int y)
     case EL_DYNABOMB_INCREASE_NUMBER:
     case EL_DYNABOMB_INCREASE_SIZE:
     case EL_DYNABOMB_INCREASE_POWER:
-      DynaExplode(x, y);
+      explosion_type = EX_TYPE_DYNA;
       break;
+
     case EL_PENGUIN:
     case EL_LAMP:
     case EL_LAMP_ACTIVE:
-#if 1
     case EL_AMOEBA_TO_DIAMOND:
-#endif
-      if (IS_PLAYER(x, y))
-       Explode(x, y, EX_PHASE_START, EX_TYPE_NORMAL);
-      else
-       Explode(x, y, EX_PHASE_START, EX_TYPE_CENTER);
+      if (!IS_PLAYER(x, y))    /* penguin and player may be at same field */
+       explosion_type = EX_TYPE_CENTER;
       break;
+
     default:
-#if 1
       if (element_info[element].explosion_type == EXPLODES_CROSS)
-#else
-      if (CAN_EXPLODE_CROSS(element))
-#endif
-#if 1
-       Explode(x, y, EX_PHASE_START, EX_TYPE_CROSS);
-#else
-       DynaExplode(x, y);
-#endif
-#if 1
+       explosion_type = EX_TYPE_CROSS;
       else if (element_info[element].explosion_type == EXPLODES_1X1)
-#else
-      else if (CAN_EXPLODE_1X1(element))
-#endif
-       Explode(x, y, EX_PHASE_START, EX_TYPE_CENTER);
-      else
-       Explode(x, y, EX_PHASE_START, EX_TYPE_NORMAL);
+       explosion_type = EX_TYPE_CENTER;
       break;
   }
 
+  if (explosion_type == EX_TYPE_DYNA)
+    DynaExplode(x, y);
+  else
+    Explode(x, y, EX_PHASE_START, explosion_type);
+
   CheckTriggeredElementChange(x, y, element, CE_EXPLOSION_OF_X);
 }
 
 void SplashAcid(int x, int y)
 {
-#if 1
   if (IN_LEV_FIELD(x - 1, y - 1) && IS_FREE(x - 1, y - 1) &&
       (!IN_LEV_FIELD(x - 1, y - 2) ||
        !CAN_FALL(MovingOrBlocked2Element(x - 1, y - 2))))
@@ -4059,30 +4279,6 @@ void SplashAcid(int x, int y)
     Feld[x + 1][y - 1] = EL_ACID_SPLASH_RIGHT;
 
   PlayLevelSound(x, y, SND_ACID_SPLASHING);
-#else
-  /* input: position of element entering acid (obsolete) */
-
-  int element = Feld[x][y];
-
-  if (!IN_LEV_FIELD(x, y + 1) || Feld[x][y + 1] != EL_ACID)
-    return;
-
-  if (element != EL_ACID_SPLASH_LEFT &&
-      element != EL_ACID_SPLASH_RIGHT)
-  {
-    PlayLevelSound(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_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_ACID_SPLASH_RIGHT;
-  }
-#endif
 }
 
 static void InitBeltMovement()
@@ -4121,25 +4317,26 @@ static void InitBeltMovement()
     }
   }
 
-  for (y = 0; y < lev_fieldy; y++)
+#if 1
+  SCAN_PLAYFIELD(x, y)
+#else
+  for (y = 0; y < lev_fieldy; y++) for (x = 0; x < lev_fieldx; x++)
+#endif
   {
-    for (x = 0; x < lev_fieldx; x++)
-    {
-      int element = Feld[x][y];
+    int element = Feld[x][y];
 
-      for (i = 0; i < NUM_BELTS; i++)
+    for (i = 0; i < NUM_BELTS; i++)
+    {
+      if (IS_BELT(element) && game.belt_dir[i] != MV_NONE)
       {
-       if (IS_BELT(element) && game.belt_dir[i] != MV_NO_MOVING)
-       {
-         int e_belt_nr = getBeltNrFromBeltElement(element);
-         int belt_nr = i;
+       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];
+       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;
-         }
+         Feld[x][y] = belt_base_active_element[belt_nr] + belt_part;
        }
       }
     }
@@ -4172,9 +4369,9 @@ static void ToggleBeltSwitch(int x, int y)
   static int belt_move_dir[4] =
   {
     MV_LEFT,
-    MV_NO_MOVING,
+    MV_NONE,
     MV_RIGHT,
-    MV_NO_MOVING,
+    MV_NONE,
   };
 
   int element = Feld[x][y];
@@ -4204,45 +4401,46 @@ static void ToggleBeltSwitch(int x, int y)
       graphic_info[graphic].anim_mode |=  ANIM_REVERSE;
   }
 
-  for (yy = 0; yy < lev_fieldy; yy++)
+#if 1
+  SCAN_PLAYFIELD(xx, yy)
+#else
+  for (yy = 0; yy < lev_fieldy; yy++) for (xx = 0; xx < lev_fieldx; xx++)
+#endif
   {
-    for (xx = 0; xx < lev_fieldx; xx++)
+    int element = Feld[xx][yy];
+
+    if (IS_BELT_SWITCH(element))
     {
-      int element = Feld[xx][yy];
+      int e_belt_nr = getBeltNrFromBeltSwitchElement(element);
 
-      if (IS_BELT_SWITCH(element))
+      if (e_belt_nr == belt_nr)
       {
-       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);
-       }
+       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);
+    }
+    else if (IS_BELT(element) && belt_dir != MV_NONE)
+    {
+      int e_belt_nr = getBeltNrFromBeltElement(element);
 
-       if (e_belt_nr == belt_nr)
-       {
-         int belt_part = Feld[xx][yy] - belt_base_element[belt_nr];
+      if (e_belt_nr == belt_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);
-       }
+       Feld[xx][yy] = belt_base_active_element[belt_nr] + belt_part;
+       DrawLevelField(xx, yy);
       }
-      else if (IS_BELT_ACTIVE(element) && belt_dir == MV_NO_MOVING)
-      {
-       int e_belt_nr = getBeltNrFromBeltActiveElement(element);
+    }
+    else if (IS_BELT_ACTIVE(element) && belt_dir == MV_NONE)
+    {
+      int e_belt_nr = getBeltNrFromBeltActiveElement(element);
 
-       if (e_belt_nr == belt_nr)
-       {
-         int belt_part = Feld[xx][yy] - belt_base_active_element[belt_nr];
+      if (e_belt_nr == belt_nr)
+      {
+       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);
-       }
+       Feld[xx][yy] = belt_base_element[belt_nr] + belt_part;
+       DrawLevelField(xx, yy);
       }
     }
   }
@@ -4254,38 +4452,46 @@ static void ToggleSwitchgateSwitch(int x, int y)
 
   game.switchgate_pos = !game.switchgate_pos;
 
-  for (yy = 0; yy < lev_fieldy; yy++)
-  {
-    for (xx = 0; xx < lev_fieldx; xx++)
-    {
-      int element = Feld[xx][yy];
-
-      if (element == EL_SWITCHGATE_SWITCH_UP ||
-         element == EL_SWITCHGATE_SWITCH_DOWN)
-      {
-       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
-       PlayLevelSoundAction(xx, yy, ACTION_CLOSING);
+  SCAN_PLAYFIELD(xx, yy)
 #else
-       PlayLevelSound(xx, yy, SND_SWITCHGATE_CLOSING);
+  for (yy = 0; yy < lev_fieldy; yy++) for (xx = 0; xx < lev_fieldx; xx++)
 #endif
-      }
-      else if (element == EL_SWITCHGATE_CLOSED ||
-              element == EL_SWITCHGATE_CLOSING)
-      {
-       Feld[xx][yy] = EL_SWITCHGATE_OPENING;
-#if 1
-       PlayLevelSoundAction(xx, yy, ACTION_OPENING);
+  {
+    int element = Feld[xx][yy];
+
+#if !USE_BOTH_SWITCHGATE_SWITCHES
+    if (element == EL_SWITCHGATE_SWITCH_UP ||
+       element == EL_SWITCHGATE_SWITCH_DOWN)
+    {
+      Feld[xx][yy] = EL_SWITCHGATE_SWITCH_UP + game.switchgate_pos;
+      DrawLevelField(xx, yy);
+    }
 #else
-       PlayLevelSound(xx, yy, SND_SWITCHGATE_OPENING);
+    if (element == EL_SWITCHGATE_SWITCH_UP)
+    {
+      Feld[xx][yy] = EL_SWITCHGATE_SWITCH_DOWN;
+      DrawLevelField(xx, yy);
+    }
+    else if (element == EL_SWITCHGATE_SWITCH_DOWN)
+    {
+      Feld[xx][yy] = EL_SWITCHGATE_SWITCH_UP;
+      DrawLevelField(xx, yy);
+    }
 #endif
-      }
+    else if (element == EL_SWITCHGATE_OPEN ||
+            element == EL_SWITCHGATE_OPENING)
+    {
+      Feld[xx][yy] = EL_SWITCHGATE_CLOSING;
+
+      PlayLevelSoundAction(xx, yy, ACTION_CLOSING);
+    }
+    else if (element == EL_SWITCHGATE_CLOSED ||
+            element == EL_SWITCHGATE_CLOSING)
+    {
+      Feld[xx][yy] = EL_SWITCHGATE_OPENING;
+
+      PlayLevelSoundAction(xx, yy, ACTION_OPENING);
     }
   }
 }
@@ -4310,50 +4516,167 @@ static void RedrawAllLightSwitchesAndInvisibleElements()
 {
   int x, y;
 
-  for (y = 0; y < lev_fieldy; y++)
+#if 1
+  SCAN_PLAYFIELD(x, y)
+#else
+  for (y = 0; y < lev_fieldy; y++) for (x = 0; x < lev_fieldx; x++)
+#endif
   {
-    for (x = 0; x < lev_fieldx; x++)
+    int element = Feld[x][y];
+
+    if (element == EL_LIGHT_SWITCH &&
+       game.light_time_left > 0)
     {
-      int element = Feld[x][y];
+      Feld[x][y] = EL_LIGHT_SWITCH_ACTIVE;
+      DrawLevelField(x, y);
+    }
+    else if (element == EL_LIGHT_SWITCH_ACTIVE &&
+            game.light_time_left == 0)
+    {
+      Feld[x][y] = EL_LIGHT_SWITCH;
+      DrawLevelField(x, y);
+    }
+    else if (element == EL_EMC_DRIPPER &&
+            game.light_time_left > 0)
+    {
+      Feld[x][y] = EL_EMC_DRIPPER_ACTIVE;
+      DrawLevelField(x, y);
+    }
+    else if (element == EL_EMC_DRIPPER_ACTIVE &&
+            game.light_time_left == 0)
+    {
+      Feld[x][y] = EL_EMC_DRIPPER;
+      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);
 
-      if (element == EL_LIGHT_SWITCH &&
-         game.light_time_left > 0)
-      {
-       Feld[x][y] = EL_LIGHT_SWITCH_ACTIVE;
-       DrawLevelField(x, y);
-      }
-      else if (element == EL_LIGHT_SWITCH_ACTIVE &&
-              game.light_time_left == 0)
-      {
-       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);
 
-       DrawLevelField(x, y);
+      /* uncrumble neighbour fields, if needed */
+      if (element == EL_INVISIBLE_SAND)
+       DrawLevelFieldCrumbledSandNeighbours(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);
 
-       /* uncrumble neighbour fields, if needed */
-       if (element == EL_INVISIBLE_SAND)
-         DrawLevelFieldCrumbledSandNeighbours(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);
+      DrawLevelField(x, y);
 
-       DrawLevelField(x, y);
+      /* re-crumble neighbour fields, if needed */
+      if (element == EL_INVISIBLE_SAND)
+       DrawLevelFieldCrumbledSandNeighbours(x, y);
+    }
+  }
+}
 
-       /* re-crumble neighbour fields, if needed */
-       if (element == EL_INVISIBLE_SAND)
-         DrawLevelFieldCrumbledSandNeighbours(x, y);
-      }
+static void RedrawAllInvisibleElementsForLenses()
+{
+  int x, y;
+
+#if 1
+  SCAN_PLAYFIELD(x, y)
+#else
+  for (y = 0; y < lev_fieldy; y++) for (x = 0; x < lev_fieldx; x++)
+#endif
+  {
+    int element = Feld[x][y];
+
+    if (element == EL_EMC_DRIPPER &&
+       game.lenses_time_left > 0)
+    {
+      Feld[x][y] = EL_EMC_DRIPPER_ACTIVE;
+      DrawLevelField(x, y);
+    }
+    else if (element == EL_EMC_DRIPPER_ACTIVE &&
+            game.lenses_time_left == 0)
+    {
+      Feld[x][y] = EL_EMC_DRIPPER;
+      DrawLevelField(x, y);
+    }
+    else if (element == EL_INVISIBLE_STEELWALL ||
+            element == EL_INVISIBLE_WALL ||
+            element == EL_INVISIBLE_SAND)
+    {
+      if (game.lenses_time_left > 0)
+       Feld[x][y] = getInvisibleActiveFromInvisibleElement(element);
+
+      DrawLevelField(x, y);
+
+      /* uncrumble neighbour fields, if needed */
+      if (element == EL_INVISIBLE_SAND)
+       DrawLevelFieldCrumbledSandNeighbours(x, y);
+    }
+    else if (element == EL_INVISIBLE_STEELWALL_ACTIVE ||
+            element == EL_INVISIBLE_WALL_ACTIVE ||
+            element == EL_INVISIBLE_SAND_ACTIVE)
+    {
+      if (game.lenses_time_left == 0)
+       Feld[x][y] = getInvisibleFromInvisibleActiveElement(element);
+
+      DrawLevelField(x, y);
+
+      /* re-crumble neighbour fields, if needed */
+      if (element == EL_INVISIBLE_SAND)
+       DrawLevelFieldCrumbledSandNeighbours(x, y);
+    }
+  }
+}
+
+static void RedrawAllInvisibleElementsForMagnifier()
+{
+  int x, y;
+
+#if 1
+  SCAN_PLAYFIELD(x, y)
+#else
+  for (y = 0; y < lev_fieldy; y++) for (x = 0; x < lev_fieldx; x++)
+#endif
+  {
+    int element = Feld[x][y];
+
+    if (element == EL_EMC_FAKE_GRASS &&
+       game.magnify_time_left > 0)
+    {
+      Feld[x][y] = EL_EMC_FAKE_GRASS_ACTIVE;
+      DrawLevelField(x, y);
+    }
+    else if (element == EL_EMC_FAKE_GRASS_ACTIVE &&
+            game.magnify_time_left == 0)
+    {
+      Feld[x][y] = EL_EMC_FAKE_GRASS;
+      DrawLevelField(x, y);
+    }
+    else if (IS_GATE_GRAY(element) &&
+            game.magnify_time_left > 0)
+    {
+      Feld[x][y] = (IS_RND_GATE_GRAY(element) ?
+                   element - EL_GATE_1_GRAY + EL_GATE_1_GRAY_ACTIVE :
+                   IS_EM_GATE_GRAY(element) ?
+                   element - EL_EM_GATE_1_GRAY + EL_EM_GATE_1_GRAY_ACTIVE :
+                   IS_EMC_GATE_GRAY(element) ?
+                   element - EL_EMC_GATE_5_GRAY + EL_EMC_GATE_5_GRAY_ACTIVE :
+                   element);
+      DrawLevelField(x, y);
+    }
+    else if (IS_GATE_GRAY_ACTIVE(element) &&
+            game.magnify_time_left == 0)
+    {
+      Feld[x][y] = (IS_RND_GATE_GRAY_ACTIVE(element) ?
+                   element - EL_GATE_1_GRAY_ACTIVE + EL_GATE_1_GRAY :
+                   IS_EM_GATE_GRAY_ACTIVE(element) ?
+                   element - EL_EM_GATE_1_GRAY_ACTIVE + EL_EM_GATE_1_GRAY :
+                   IS_EMC_GATE_GRAY_ACTIVE(element) ?
+                   element - EL_EMC_GATE_5_GRAY_ACTIVE + EL_EMC_GATE_5_GRAY :
+                   element);
+      DrawLevelField(x, y);
     }
   }
 }
@@ -4375,28 +4698,29 @@ static void ActivateTimegateSwitch(int x, int y)
 
   game.timegate_time_left = level.time_timegate * FRAMES_PER_SECOND;
 
-  for (yy = 0; yy < lev_fieldy; yy++)
+#if 1
+  SCAN_PLAYFIELD(xx, yy)
+#else
+  for (yy = 0; yy < lev_fieldy; yy++) for (xx = 0; xx < lev_fieldx; xx++)
+#endif
   {
-    for (xx = 0; xx < lev_fieldx; xx++)
-    {
-      int element = Feld[xx][yy];
-
-      if (element == EL_TIMEGATE_CLOSED ||
-         element == EL_TIMEGATE_CLOSING)
-      {
-       Feld[xx][yy] = EL_TIMEGATE_OPENING;
-       PlayLevelSound(xx, yy, SND_TIMEGATE_OPENING);
-      }
+    int element = Feld[xx][yy];
 
-      /*
-      else if (element == EL_TIMEGATE_SWITCH_ACTIVE)
-      {
-       Feld[xx][yy] = EL_TIMEGATE_SWITCH;
-       DrawLevelField(xx, yy);
-      }
-      */
+    if (element == EL_TIMEGATE_CLOSED ||
+       element == EL_TIMEGATE_CLOSING)
+    {
+      Feld[xx][yy] = EL_TIMEGATE_OPENING;
+      PlayLevelSound(xx, yy, SND_TIMEGATE_OPENING);
+    }
 
+    /*
+    else if (element == EL_TIMEGATE_SWITCH_ACTIVE)
+    {
+      Feld[xx][yy] = EL_TIMEGATE_SWITCH;
+      DrawLevelField(xx, yy);
     }
+    */
+
   }
 
   Feld[x][y] = EL_TIMEGATE_SWITCH_ACTIVE;
@@ -4410,10 +4734,6 @@ void Impact(int x, int y)
   int element = Feld[x][y];
   int smashed = EL_STEELWALL;
 
-#if 0
-  printf("IMPACT!\n");
-#endif
-
   if (!last_line)      /* check if element below was hit */
   {
     if (Feld[x][y + 1] == EL_PLAYER_IS_LEAVING)
@@ -4423,15 +4743,23 @@ void Impact(int x, int y)
                                         MovDir[x][y + 1] != MV_DOWN ||
                                         MovPos[x][y + 1] <= TILEY / 2));
 
-#if 0
-    object_hit = !IS_FREE(x, y + 1);
-#endif
-
     /* do not smash moving elements that left the smashed field in time */
     if (game.engine_version >= VERSION_IDENT(2,2,0,7) && IS_MOVING(x, y + 1) &&
        ABS(MovPos[x][y + 1] + getElementMoveStepsize(x, y + 1)) >= TILEX)
       object_hit = FALSE;
 
+#if USE_QUICKSAND_IMPACT_BUGFIX
+    if (Feld[x][y + 1] == EL_QUICKSAND_EMPTYING && object_hit == FALSE)
+    {
+      RemoveMovingField(x, y + 1);
+      Feld[x][y + 1] = EL_QUICKSAND_EMPTY;
+      Feld[x][y + 2] = EL_ROCK;
+      DrawLevelField(x, y + 2);
+
+      object_hit = TRUE;
+    }
+#endif
+
     if (object_hit)
       smashed = MovingOrBlocked2Element(x, y + 1);
 
@@ -4476,7 +4804,7 @@ void Impact(int x, int y)
   if (impact && element == EL_AMOEBA_DROP)
   {
     if (object_hit && IS_PLAYER(x, y + 1))
-      KillHeroUnlessEnemyProtected(x, y + 1);
+      KillPlayerUnlessEnemyProtected(x, y + 1);
     else if (object_hit && smashed == EL_PENGUIN)
       Bang(x, y + 1);
     else
@@ -4501,10 +4829,13 @@ void Impact(int x, int y)
         EL_BD_MAGIC_WALL_ACTIVE);
 
       /* activate magic wall / mill */
-      for (yy = 0; yy < lev_fieldy; yy++)
-       for (xx = 0; xx < lev_fieldx; xx++)
-         if (Feld[xx][yy] == smashed)
-           Feld[xx][yy] = activated_magic_wall;
+#if 1
+      SCAN_PLAYFIELD(xx, yy)
+#else
+      for (yy = 0; yy < lev_fieldy; yy++) for (xx = 0; xx < lev_fieldx; xx++)
+#endif
+       if (Feld[xx][yy] == smashed)
+         Feld[xx][yy] = activated_magic_wall;
 
       game.magic_wall_time_left = level.time_magic_wall * FRAMES_PER_SECOND;
       game.magic_wall_active = TRUE;
@@ -4518,7 +4849,7 @@ void Impact(int x, int y)
     {
       if (CAN_SMASH_PLAYER(element))
       {
-       KillHeroUnlessEnemyProtected(x, y + 1);
+       KillPlayerUnlessEnemyProtected(x, y + 1);
        return;
       }
     }
@@ -4549,13 +4880,6 @@ void Impact(int x, int y)
       Bang(x, y + 1);
       return;
     }
-#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_CLASSIC_ENEMY(smashed) ||
@@ -4615,18 +4939,10 @@ void Impact(int x, int y)
 
          CheckElementChange(x, y + 1, smashed, element, CE_SMASHED);
 
-#if 1
-         /* !!! TEST ONLY !!! */
-         CheckElementChangeBySide(x, y + 1, smashed, element,
-                                  CE_SWITCHED, CH_SIDE_TOP);
-         CheckTriggeredElementChangeBySide(x, y + 1, smashed,
-                                           CE_SWITCH_OF_X, CH_SIDE_TOP);
-#else
-         CheckTriggeredElementChangeBySide(x, y + 1, smashed,
-                                           CE_SWITCH_OF_X, CH_SIDE_TOP);
          CheckElementChangeBySide(x, y + 1, smashed, element,
                                   CE_SWITCHED, CH_SIDE_TOP);
-#endif
+         CheckTriggeredElementChangeBySide(x, y + 1, smashed, CE_SWITCH_OF_X,
+                                           CH_SIDE_TOP);
        }
       }
       else
@@ -4658,7 +4974,7 @@ inline static void TurnRoundExt(int x, int y)
 {
   static struct
   {
-    int x, y;
+    int dx, dy;
   } move_xy[] =
   {
     {  0,  0 },
@@ -4693,10 +5009,10 @@ inline static void TurnRoundExt(int x, int y)
   int right_dir = turn[old_move_dir].right;
   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].dx,     left_dy  = move_xy[left_dir].dy;
+  int right_dx = move_xy[right_dir].dx,    right_dy = move_xy[right_dir].dy;
+  int move_dx  = move_xy[old_move_dir].dx, move_dy  = move_xy[old_move_dir].dy;
+  int back_dx  = move_xy[back_dir].dx,     back_dy  = move_xy[back_dir].dy;
 
   int left_x  = x + left_dx,  left_y  = y + left_dy;
   int right_x = x + right_dx, right_y = y + right_dy;
@@ -4718,26 +5034,6 @@ inline static void TurnRoundExt(int x, int y)
     else if (element == EL_BD_BUTTERFLY)     /* && MovDir[x][y] == left_dir) */
       MovDelay[x][y] = 1;
   }
-#if 0
-  else if (element == EL_SPACESHIP || element == EL_BD_FIREFLY ||
-          element == EL_SP_SNIKSNAK || element == EL_SP_ELECTRON)
-  {
-    TestIfBadThingTouchesOtherBadThing(x, y);
-
-    if (ENEMY_CAN_ENTER_FIELD(element, left_x, left_y))
-      MovDir[x][y] = left_dir;
-    else if (!ENEMY_CAN_ENTER_FIELD(element, move_x, move_y))
-      MovDir[x][y] = right_dir;
-
-    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_BD_FIREFLY)     /* && MovDir[x][y] == right_dir) */
-      MovDelay[x][y] = 1;
-  }
-#else
   else if (element == EL_SPACESHIP || element == EL_BD_FIREFLY)
   {
     TestIfBadThingTouchesOtherBadThing(x, y);
@@ -4764,7 +5060,6 @@ inline static void TurnRoundExt(int x, int y)
     if (MovDir[x][y] != old_move_dir)
       MovDelay[x][y] = 9;
   }
-#endif
   else if (element == EL_YAMYAM)
   {
     boolean can_turn_left  = YAMYAM_CAN_ENTER_FIELD(element, left_x, left_y);
@@ -4870,18 +5165,12 @@ inline static void TurnRoundExt(int x, int y)
     else
       MovDir[x][y] = back_dir;
 
-    xx = x + move_xy[MovDir[x][y]].x;
-    yy = y + move_xy[MovDir[x][y]].y;
+    xx = x + move_xy[MovDir[x][y]].dx;
+    yy = y + move_xy[MovDir[x][y]].dy;
 
-#if 1
-    /* !!! this bugfix breaks at least BD2K3, level 010 !!! [re-recorded] */
     if (!IN_LEV_FIELD(xx, yy) ||
         (!IS_FREE(xx, yy) && !IS_FOOD_PIG(Feld[xx][yy])))
       MovDir[x][y] = old_move_dir;
-#else
-    if (!IS_FREE(xx, yy) && !IS_FOOD_PIG(Feld[xx][yy]))
-      MovDir[x][y] = old_move_dir;
-#endif
 
     MovDelay[x][y] = 0;
   }
@@ -4893,11 +5182,6 @@ inline static void TurnRoundExt(int x, int y)
     int rnd_value = 24;
     int rnd = RND(rnd_value);
 
-#if 0
-    if (FrameCounter < 1 && x == 0 && y == 29)
-      printf(":2: %d/%d: %d [%d]\n", x, y, MovDir[x][y], FrameCounter);
-#endif
-
     if (can_move_on && rnd > rnd_value / 8)
       MovDir[x][y] = old_move_dir;
     else if (can_turn_left && can_turn_right)
@@ -4909,28 +5193,11 @@ inline static void TurnRoundExt(int x, int y)
     else
       MovDir[x][y] = back_dir;
 
-    xx = x + move_xy[MovDir[x][y]].x;
-    yy = y + move_xy[MovDir[x][y]].y;
+    xx = x + move_xy[MovDir[x][y]].dx;
+    yy = y + move_xy[MovDir[x][y]].dy;
 
-#if 0
-    if (FrameCounter < 1 && x == 0 && y == 29)
-      printf(":3: %d/%d: %d (%d/%d: %d) [%d]\n", x, y, MovDir[x][y],
-            xx, yy, Feld[xx][yy],
-            FrameCounter);
-#endif
-
-#if 1
     if (!IN_LEV_FIELD_AND_IS_FREE(xx, yy))
       MovDir[x][y] = old_move_dir;
-#else
-    if (!IS_FREE(xx, yy))
-      MovDir[x][y] = old_move_dir;
-#endif
-
-#if 0
-    if (FrameCounter < 1 && x == 0 && y == 29)
-      printf(":4: %d/%d: %d [%d]\n", x, y, MovDir[x][y], FrameCounter);
-#endif
 
     MovDelay[x][y] = 0;
   }
@@ -4963,27 +5230,40 @@ inline static void TurnRoundExt(int x, int y)
   }
   else if (element == EL_BALLOON)
   {
-    MovDir[x][y] = game.balloon_dir;
+    MovDir[x][y] = game.wind_direction;
     MovDelay[x][y] = 0;
   }
   else if (element == EL_SPRING)
   {
-#if 0
-    if (MovDir[x][y] & MV_HORIZONTAL &&
-       !SPRING_CAN_ENTER_FIELD(element, move_x, move_y))
-      MovDir[x][y] = MV_NO_MOVING;
+#if USE_NEW_SPRING_BUMPER
+    if (MovDir[x][y] & MV_HORIZONTAL)
+    {
+      if (SPRING_CAN_BUMP_FROM_FIELD(move_x, move_y) &&
+         !SPRING_CAN_ENTER_FIELD(element, x, y + 1))
+      {
+       Feld[move_x][move_y] = EL_EMC_SPRING_BUMPER_ACTIVE;
+       ResetGfxAnimation(move_x, move_y);
+       DrawLevelField(move_x, move_y);
+
+       MovDir[x][y] = back_dir;
+      }
+      else if (!SPRING_CAN_ENTER_FIELD(element, move_x, move_y) ||
+              SPRING_CAN_ENTER_FIELD(element, x, y + 1))
+       MovDir[x][y] = MV_NONE;
+    }
 #else
     if (MovDir[x][y] & MV_HORIZONTAL &&
        (!SPRING_CAN_ENTER_FIELD(element, move_x, move_y) ||
         SPRING_CAN_ENTER_FIELD(element, x, y + 1)))
-      MovDir[x][y] = MV_NO_MOVING;
+      MovDir[x][y] = MV_NONE;
 #endif
 
     MovDelay[x][y] = 0;
   }
   else if (element == EL_ROBOT ||
           element == EL_SATELLITE ||
-          element == EL_PENGUIN)
+          element == EL_PENGUIN ||
+          element == EL_EMC_ANDROID)
   {
     int attr_x = -1, attr_y = -1;
 
@@ -5013,13 +5293,9 @@ inline static void TurnRoundExt(int x, int y)
       }
     }
 
-#if 1
     if (element == EL_ROBOT && ZX >= 0 && ZY >= 0 &&
        (Feld[ZX][ZY] == EL_ROBOT_WHEEL_ACTIVE ||
         game.engine_version < VERSION_IDENT(3,1,0,0)))
-#else
-    if (element == EL_ROBOT && ZX >= 0 && ZY >= 0)
-#endif
     {
       attr_x = ZX;
       attr_y = ZY;
@@ -5050,7 +5326,7 @@ inline static void TurnRoundExt(int x, int y)
       }
     }
 
-    MovDir[x][y] = MV_NO_MOVING;
+    MovDir[x][y] = MV_NONE;
     if (attr_x < x)
       MovDir[x][y] |= (AllPlayersGone ? MV_RIGHT : MV_LEFT);
     else if (attr_x > x)
@@ -5088,21 +5364,21 @@ inline static void TurnRoundExt(int x, int y)
          new_move_dir & (first_horiz ? MV_HORIZONTAL : MV_VERTICAL);
        Moving2Blocked(x, y, &newx, &newy);
 
-       if (PENGUIN_CAN_ENTER_FIELD(EL_PENGUIN, newx, newy))
+       if (PENGUIN_CAN_ENTER_FIELD(element, newx, newy))
          return;
 
        MovDir[x][y] =
          new_move_dir & (!first_horiz ? MV_HORIZONTAL : MV_VERTICAL);
        Moving2Blocked(x, y, &newx, &newy);
 
-       if (PENGUIN_CAN_ENTER_FIELD(EL_PENGUIN, newx, newy))
+       if (PENGUIN_CAN_ENTER_FIELD(element, newx, newy))
          return;
 
        MovDir[x][y] = old_move_dir;
        return;
       }
     }
-    else       /* (element == EL_SATELLITE) */
+    else if (element == EL_SATELLITE)
     {
       int newx, newy;
 
@@ -5131,6 +5407,144 @@ inline static void TurnRoundExt(int x, int y)
        return;
       }
     }
+    else if (element == EL_EMC_ANDROID)
+    {
+      static int check_pos[16] =
+      {
+       -1,             /*  0 => (invalid)          */
+       7,              /*  1 => MV_LEFT            */
+       3,              /*  2 => MV_RIGHT           */
+       -1,             /*  3 => (invalid)          */
+       1,              /*  4 =>            MV_UP   */
+       0,              /*  5 => MV_LEFT  | MV_UP   */
+       2,              /*  6 => MV_RIGHT | MV_UP   */
+       -1,             /*  7 => (invalid)          */
+       5,              /*  8 =>            MV_DOWN */
+       6,              /*  9 => MV_LEFT  | MV_DOWN */
+       4,              /* 10 => MV_RIGHT | MV_DOWN */
+       -1,             /* 11 => (invalid)          */
+       -1,             /* 12 => (invalid)          */
+       -1,             /* 13 => (invalid)          */
+       -1,             /* 14 => (invalid)          */
+       -1,             /* 15 => (invalid)          */
+      };
+      static struct
+      {
+       int dx, dy;
+       int dir;
+      } check_xy[8] =
+      {
+        { -1, -1,      MV_LEFT  | MV_UP   },
+               {  0, -1,                  MV_UP   },
+       { +1, -1,       MV_RIGHT | MV_UP   },
+       { +1,  0,       MV_RIGHT           },
+       { +1, +1,       MV_RIGHT | MV_DOWN },
+       {  0, +1,                  MV_DOWN },
+       { -1, +1,       MV_LEFT  | MV_DOWN },
+       { -1,  0,       MV_LEFT            },
+      };
+      int start_pos, check_order;
+      boolean can_clone = FALSE;
+      int i;
+
+      /* check if there is any free field around current position */
+      for (i = 0; i < 8; i++)
+      {
+       int newx = x + check_xy[i].dx;
+       int newy = y + check_xy[i].dy;
+
+       if (IN_LEV_FIELD_AND_IS_FREE(newx, newy))
+       {
+         can_clone = TRUE;
+
+         break;
+       }
+      }
+
+      if (can_clone)           /* randomly find an element to clone */
+      {
+       can_clone = FALSE;
+
+       start_pos = check_pos[RND(8)];
+       check_order = (RND(2) ? -1 : +1);
+
+       for (i = 0; i < 8; i++)
+       {
+         int pos_raw = start_pos + i * check_order;
+         int pos = (pos_raw + 8) % 8;
+         int newx = x + check_xy[pos].dx;
+         int newy = y + check_xy[pos].dy;
+
+         if (ANDROID_CAN_CLONE_FIELD(newx, newy))
+         {
+           element_info[element].move_leave_type = LEAVE_TYPE_LIMITED;
+           element_info[element].move_leave_element = EL_TRIGGER_ELEMENT;
+
+           Store[x][y] = Feld[newx][newy];
+
+           can_clone = TRUE;
+
+           break;
+         }
+       }
+      }
+
+      if (can_clone)           /* randomly find a direction to move */
+      {
+       can_clone = FALSE;
+
+       start_pos = check_pos[RND(8)];
+       check_order = (RND(2) ? -1 : +1);
+
+       for (i = 0; i < 8; i++)
+       {
+         int pos_raw = start_pos + i * check_order;
+         int pos = (pos_raw + 8) % 8;
+         int newx = x + check_xy[pos].dx;
+         int newy = y + check_xy[pos].dy;
+         int new_move_dir = check_xy[pos].dir;
+
+         if (IN_LEV_FIELD_AND_IS_FREE(newx, newy))
+         {
+           MovDir[x][y] = new_move_dir;
+           MovDelay[x][y] = level.android_clone_time * 8 + 1;
+
+           can_clone = TRUE;
+
+           break;
+         }
+       }
+      }
+
+      if (can_clone)           /* cloning and moving successful */
+       return;
+
+      /* cannot clone -- try to move towards player */
+
+      start_pos = check_pos[MovDir[x][y] & 0x0f];
+      check_order = (RND(2) ? -1 : +1);
+
+      for (i = 0; i < 3; i++)
+      {
+       /* first check start_pos, then previous/next or (next/previous) pos */
+       int pos_raw = start_pos + (i < 2 ? i : -1) * check_order;
+       int pos = (pos_raw + 8) % 8;
+       int newx = x + check_xy[pos].dx;
+       int newy = y + check_xy[pos].dy;
+       int new_move_dir = check_xy[pos].dir;
+
+       if (IS_PLAYER(newx, newy))
+         break;
+
+       if (ANDROID_CAN_ENTER_FIELD(element, newx, newy))
+       {
+         MovDir[x][y] = new_move_dir;
+         MovDelay[x][y] = level.android_move_time * 8 + 1;
+
+         break;
+       }
+      }
+    }
   }
   else if (move_pattern == MV_TURNING_LEFT ||
           move_pattern == MV_TURNING_RIGHT ||
@@ -5144,10 +5558,8 @@ inline static void TurnRoundExt(int x, int y)
     boolean can_turn_right =
       CUSTOM_ELEMENT_CAN_ENTER_FIELD(element, right_x,right_y);
 
-#if USE_CAN_MOVE_NOT_MOVING
-    if (element_info[element].move_stepsize == 0)      /* not moving */
+    if (element_info[element].move_stepsize == 0)      /* "not moving" */
       return;
-#endif
 
     if (move_pattern == MV_TURNING_LEFT)
       MovDir[x][y] = left_dir;
@@ -5189,6 +5601,11 @@ inline static void TurnRoundExt(int x, int y)
     MovDir[x][y] = move_pattern;
     MovDelay[x][y] = GET_NEW_MOVE_DELAY(element);
   }
+  else if (move_pattern & MV_WIND_DIRECTION)
+  {
+    MovDir[x][y] = game.wind_direction;
+    MovDelay[x][y] = GET_NEW_MOVE_DELAY(element);
+  }
   else if (move_pattern == MV_ALONG_LEFT_SIDE)
   {
     if (CUSTOM_ELEMENT_CAN_ENTER_FIELD(element, left_x, left_y))
@@ -5242,7 +5659,7 @@ inline static void TurnRoundExt(int x, int y)
       }
     }
 
-    MovDir[x][y] = MV_NO_MOVING;
+    MovDir[x][y] = MV_NONE;
     if (attr_x < x)
       MovDir[x][y] |= (move_away ? MV_RIGHT : MV_LEFT);
     else if (attr_x > x)
@@ -5259,15 +5676,13 @@ inline static void TurnRoundExt(int x, int y)
       boolean first_horiz = RND(2);
       int new_move_dir = MovDir[x][y];
 
-#if USE_CAN_MOVE_NOT_MOVING
-      if (element_info[element].move_stepsize == 0)    /* not moving */
+      if (element_info[element].move_stepsize == 0)    /* "not moving" */
       {
        first_horiz = (ABS(attr_x - x) >= ABS(attr_y - y));
        MovDir[x][y] &= (first_horiz ? MV_HORIZONTAL : MV_VERTICAL);
 
        return;
       }
-#endif
 
       MovDir[x][y] =
        new_move_dir & (first_horiz ? MV_HORIZONTAL : MV_VERTICAL);
@@ -5290,7 +5705,7 @@ inline static void TurnRoundExt(int x, int y)
           move_pattern == MV_WHEN_DROPPED)
   {
     if (!CUSTOM_ELEMENT_CAN_ENTER_FIELD(element, move_x, move_y))
-      MovDir[x][y] = MV_NO_MOVING;
+      MovDir[x][y] = MV_NONE;
 
     MovDelay[x][y] = 0;
   }
@@ -5318,7 +5733,7 @@ inline static void TurnRoundExt(int x, int y)
     };
     boolean hunter_mode = (move_pattern == MV_MAZE_HUNTER);
     int move_preference = -1000000;    /* start with very low preference */
-    int new_move_dir = MV_NO_MOVING;
+    int new_move_dir = MV_NONE;
     int start_test = RND(4);
     int i;
 
@@ -5362,39 +5777,41 @@ inline static void TurnRoundExt(int x, int y)
 
     MovDir[x][y] = new_move_dir;
     if (old_move_dir != new_move_dir)
-    {
-#if 1
       MovDelay[x][y] = GET_NEW_MOVE_DELAY(element);
-#else
-      MovDelay[x][y] = 9;
-#endif
-    }
   }
 }
 
 static void TurnRound(int x, int y)
 {
   int direction = MovDir[x][y];
-
 #if 0
-  GfxDir[x][y] = MovDir[x][y];
+  int element, graphic;
 #endif
 
   TurnRoundExt(x, y);
 
-#if 1
   GfxDir[x][y] = MovDir[x][y];
-#endif
 
   if (direction != MovDir[x][y])
     GfxFrame[x][y] = 0;
 
-#if 1
   if (MovDelay[x][y])
-    GfxAction[x][y] = ACTION_TURNING_FROM_LEFT + MV_DIR_BIT(direction);
+    GfxAction[x][y] = ACTION_TURNING_FROM_LEFT + MV_DIR_TO_BIT(direction);
+
+#if 1
+  ResetGfxFrame(x, y, FALSE);
 #else
-  if (MovDelay[x][y])
-    GfxAction[x][y] = ACTION_WAITING;
+  element = Feld[x][y];
+  graphic = el_act_dir2img(element, GfxAction[x][y], GfxDir[x][y]);
+
+  if (graphic_info[graphic].anim_global_sync)
+    GfxFrame[x][y] = FrameCounter;
+  else if (ANIM_MODE(graphic) == ANIM_CE_VALUE)
+    GfxFrame[x][y] = CustomValue[x][y];
+  else if (ANIM_MODE(graphic) == ANIM_CE_SCORE)
+    GfxFrame[x][y] = element_info[element].collect_score;
+  else if (ANIM_MODE(graphic) == ANIM_CE_DELAY)
+    GfxFrame[x][y] = ChangeDelay[x][y];
 #endif
 }
 
@@ -5421,23 +5838,14 @@ static boolean JustBeingPushed(int x, int y)
 
 void StartMoving(int x, int y)
 {
-#if 0
-  boolean use_spring_bug = (game.engine_version < VERSION_IDENT(2,2,0,0));
-#endif
   boolean started_moving = FALSE;      /* some elements can fall _and_ move */
   int element = Feld[x][y];
 
   if (Stop[x][y])
     return;
 
-#if 1
   if (MovDelay[x][y] == 0)
     GfxAction[x][y] = ACTION_DEFAULT;
-#else
-  /* !!! this should be handled more generic (not only for mole) !!! */
-  if (element != EL_MOLE && GfxAction[x][y] != ACTION_DIGGING)
-    GfxAction[x][y] = ACTION_DEFAULT;
-#endif
 
   if (CAN_FALL(element) && y < lev_fieldy - 1)
   {
@@ -5454,12 +5862,14 @@ void StartMoving(int x, int y)
        started_moving = TRUE;
 
        Feld[x][y] = EL_QUICKSAND_EMPTYING;
-       Store[x][y] = EL_ROCK;
-#if 1
-       PlayLevelSoundAction(x, y, ACTION_EMPTYING);
+#if USE_QUICKSAND_BD_ROCK_BUGFIX
+       if (Store[x][y] != EL_ROCK && Store[x][y] != EL_BD_ROCK)
+         Store[x][y] = EL_ROCK;
 #else
-       PlayLevelSound(x, y, SND_QUICKSAND_EMPTYING);
+       Store[x][y] = EL_ROCK;
 #endif
+
+       PlayLevelSoundAction(x, y, ACTION_EMPTYING);
       }
       else if (Feld[x][y + 1] == EL_QUICKSAND_EMPTY)
       {
@@ -5477,11 +5887,8 @@ void StartMoving(int x, int y)
        Feld[x][y + 1] = EL_QUICKSAND_FULL;
        Store[x][y + 1] = Store[x][y];
        Store[x][y] = 0;
-#if 1
+
        PlayLevelSoundAction(x, y, ACTION_FILLING);
-#else
-       PlayLevelSound(x, y, SND_QUICKSAND_FILLING);
-#endif
       }
     }
     else if ((element == EL_ROCK || element == EL_BD_ROCK) &&
@@ -5492,11 +5899,8 @@ void StartMoving(int x, int y)
 
       Feld[x][y] = EL_QUICKSAND_FILLING;
       Store[x][y] = element;
-#if 1
+
       PlayLevelSoundAction(x, y, ACTION_FILLING);
-#else
-      PlayLevelSound(x, y, SND_QUICKSAND_FILLING);
-#endif
     }
     else if (element == EL_MAGIC_WALL_FULL)
     {
@@ -5566,11 +5970,7 @@ void StartMoving(int x, int y)
         EL_BD_MAGIC_WALL_FILLING);
       Store[x][y] = element;
     }
-#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
     {
       SplashAcid(x, y + 1);
 
@@ -5578,16 +5978,10 @@ void StartMoving(int x, int y)
       started_moving = TRUE;
 
       Store[x][y] = EL_ACID;
-#if 0
-      /* !!! TEST !!! better use "_FALLING" etc. !!! */
-      GfxAction[x][y + 1] = ACTION_ACTIVE;
-#endif
     }
-#if 1
     else if ((game.engine_version >= VERSION_IDENT(3,1,0,0) &&
              CheckCollision[x][y] && !IS_FREE(x, y + 1)) ||
 
-#if USE_IMPACT_BUGFIX
             (game.engine_version >= VERSION_IDENT(3,0,7,0) &&
              CAN_FALL(element) && WasJustFalling[x][y] &&
              (Feld[x][y + 1] == EL_BLOCKED || IS_PLAYER(x, y + 1))) ||
@@ -5595,27 +5989,6 @@ void StartMoving(int x, int y)
             (game.engine_version < VERSION_IDENT(2,2,0,7) &&
              CAN_FALL(element) && WasJustMoving[x][y] && !Pushed[x][y + 1] &&
              (Feld[x][y + 1] == EL_BLOCKED)))
-#else
-            (game.engine_version >= VERSION_IDENT(3,0,7,0) &&
-             CAN_SMASH(element) && WasJustFalling[x][y] &&
-             (Feld[x][y + 1] == EL_BLOCKED || IS_PLAYER(x, y + 1))) ||
-
-            (game.engine_version < VERSION_IDENT(2,2,0,7) &&
-             CAN_SMASH(element) && WasJustMoving[x][y] && !Pushed[x][y + 1] &&
-             (Feld[x][y + 1] == EL_BLOCKED)))
-#endif
-
-#else
-#if 1
-    else if (game.engine_version < VERSION_IDENT(2,2,0,7) &&
-            CAN_SMASH(element) && Feld[x][y + 1] == EL_BLOCKED &&
-            WasJustMoving[x][y] && !Pushed[x][y + 1])
-#else
-    else if (CAN_SMASH(element) && Feld[x][y + 1] == EL_BLOCKED &&
-            WasJustMoving[x][y])
-#endif
-#endif
-
     {
       /* this is needed for a special case not covered by calling "Impact()"
         from "ContinueMoving()": if an element moves to a tile directly below
@@ -5627,23 +6000,13 @@ void StartMoving(int x, int y)
         element; also, the case of the player being the element to smash was
         simply not covered here... :-/ ) */
 
-#if 0
-      WasJustMoving[x][y] = 0;
-      WasJustFalling[x][y] = 0;
-#endif
-
       CheckCollision[x][y] = 0;
 
-#if 0
-      if (IS_PLAYER(x, y + 1))
-       printf("::: we ARE now killing the player [%d]\n", FrameCounter);
-#endif
-
       Impact(x, y);
     }
     else if (IS_FREE(x, y + 1) && element == EL_SPRING && level.use_spring_bug)
     {
-      if (MovDir[x][y] == MV_NO_MOVING)
+      if (MovDir[x][y] == MV_NONE)
       {
        InitMovingField(x, y, MV_DOWN);
        started_moving = TRUE;
@@ -5662,23 +6025,10 @@ void StartMoving(int x, int y)
       Feld[x][y] = EL_AMOEBA_GROWING;
       Store[x][y] = EL_AMOEBA_WET;
     }
-    /* 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
-    else if (IS_SLIPPERY(Feld[x][y + 1]) && !Store[x][y + 1] &&
-            !IS_FALLING(x, y + 1) && !WasJustMoving[x][y + 1] &&
-            element != EL_DX_SUPABOMB)
-#endif
-#else
     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) && !WasJustMoving[x][y + 1] &&
             element != EL_DX_SUPABOMB && element != EL_SP_DISK_ORANGE)
-#endif
     {
       boolean can_fall_left  = (x > 0 && IS_FREE(x - 1, y) &&
                                (IS_FREE(x - 1, y + 1) ||
@@ -5688,11 +6038,26 @@ void StartMoving(int x, int y)
                                 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);
+      int slippery_type = element_info[Feld[x][y + 1]].slippery_type;
 
-      if (can_fall_any && IS_CUSTOM_ELEMENT(Feld[x][y + 1]))
+#if USE_NEW_ALL_SLIPPERY
+      if (can_fall_any && slippery_type != SLIPPERY_ANY_RANDOM)
       {
-       int slippery_type = element_info[Feld[x][y + 1]].slippery_type;
+       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;
+       else if (slippery_type == SLIPPERY_ONLY_LEFT)
+         can_fall_right = FALSE;
+       else if (slippery_type == SLIPPERY_ONLY_RIGHT)
+         can_fall_left = FALSE;
 
+       can_fall_any  = (can_fall_left || can_fall_right);
+       can_fall_both = FALSE;
+      }
+#else
+      if (can_fall_any && IS_CUSTOM_ELEMENT(Feld[x][y + 1]))
+      {
        if (slippery_type == SLIPPERY_ONLY_LEFT)
          can_fall_right = FALSE;
        else if (slippery_type == SLIPPERY_ONLY_RIGHT)
@@ -5705,7 +6070,10 @@ void StartMoving(int x, int y)
        can_fall_any  = (can_fall_left || can_fall_right);
        can_fall_both = (can_fall_left && can_fall_right);
       }
+#endif
 
+#if USE_NEW_ALL_SLIPPERY
+#else
 #if USE_NEW_SP_SLIPPERY
       /* !!! better use the same properties as for custom elements here !!! */
       else if (game.engine_version >= VERSION_IDENT(3,1,1,0) &&
@@ -5715,8 +6083,19 @@ void StartMoving(int x, int y)
        can_fall_both = FALSE;
       }
 #endif
+#endif
 
-#if 1
+#if USE_NEW_ALL_SLIPPERY
+      if (can_fall_both)
+      {
+       if (element == EL_BD_ROCK || element == EL_BD_DIAMOND)
+         can_fall_right = FALSE;       /* slip down on left side */
+       else
+         can_fall_left = !(can_fall_right = RND(2));
+
+       can_fall_both = FALSE;
+      }
+#else
       if (can_fall_both)
       {
        if (game.emulation == EMU_BOULDERDASH ||
@@ -5731,13 +6110,6 @@ void StartMoving(int x, int y)
 
       if (can_fall_any)
       {
-#if 0
-       if (can_fall_both &&
-           (game.emulation != EMU_BOULDERDASH &&
-            element != EL_BD_ROCK && element != EL_BD_DIAMOND))
-         can_fall_left = !(can_fall_right = RND(2));
-#endif
-
        /* if not determined otherwise, prefer left side for slipping down */
        InitMovingField(x, y, can_fall_left ? MV_LEFT : MV_RIGHT);
        started_moving = TRUE;
@@ -5757,17 +6129,13 @@ void StartMoving(int x, int y)
       if ((belt_dir == MV_LEFT  && left_is_free) ||
          (belt_dir == MV_RIGHT && right_is_free))
       {
-#if 1
        int nextx = (belt_dir == MV_LEFT ? x - 1 : x + 1);
-#endif
 
        InitMovingField(x, y, belt_dir);
        started_moving = TRUE;
 
-#if 1
        Pushed[x][y] = TRUE;
        Pushed[nextx][y] = TRUE;
-#endif
 
        GfxAction[x][y] = ACTION_DEFAULT;
       }
@@ -5780,7 +6148,7 @@ void StartMoving(int x, int y)
 
   /* not "else if" because of elements that can fall and move (EL_SPRING) */
 #if 0
-  if (CAN_MOVE(element) && !started_moving && MovDir[x][y] != MV_NO_MOVING)
+  if (CAN_MOVE(element) && !started_moving && MovDir[x][y] != MV_NONE)
 #else
   if (CAN_MOVE(element) && !started_moving)
 #endif
@@ -5790,7 +6158,7 @@ void StartMoving(int x, int y)
 
 #if 0
 #if DEBUG
-    if (MovDir[x][y] == MV_NO_MOVING)
+    if (MovDir[x][y] == MV_NONE)
     {
       printf("StartMoving(): %d,%d: element %d ['%s'] not moving\n",
             x, y, element, element_info[element].token_name);
@@ -5801,80 +6169,20 @@ void StartMoving(int x, int y)
 
     Moving2Blocked(x, y, &newx, &newy);
 
-#if 1
     if (IS_PUSHABLE(element) && JustBeingPushed(x, y))
       return;
-#else
-    if ((element == EL_SATELLITE ||
-        element == EL_BALLOON ||
-        element == EL_SPRING)
-       && JustBeingPushed(x, y))
-      return;
-#endif
-
-#if 1
 
-#if 1
     if (game.engine_version >= VERSION_IDENT(3,1,0,0) &&
        CheckCollision[x][y] && !IN_LEV_FIELD_AND_IS_FREE(newx, newy))
-#else
-    if (game.engine_version >= VERSION_IDENT(3,1,0,0) &&
-       WasJustMoving[x][y] && IN_LEV_FIELD(newx, newy) &&
-       (Feld[newx][newy] == EL_BLOCKED || IS_PLAYER(newx, newy)))
-#endif
     {
-#if 0
-      printf("::: element %d '%s' WasJustMoving %d [%d, %d, %d, %d]\n",
-            element, element_info[element].token_name,
-            WasJustMoving[x][y],
-            HAS_ANY_CHANGE_EVENT(element, CE_HITTING_SOMETHING),
-            HAS_ANY_CHANGE_EVENT(element, CE_HIT_BY_SOMETHING),
-            HAS_ANY_CHANGE_EVENT(element, CE_HITTING_X),
-            HAS_ANY_CHANGE_EVENT(element, CE_HIT_BY_X));
-#endif
-
-#if 1
       WasJustMoving[x][y] = 0;
-#endif
-
       CheckCollision[x][y] = 0;
 
       TestIfElementHitsCustomElement(x, y, MovDir[x][y]);
 
-#if 0
-      if (Feld[x][y] != element)       /* element has changed */
-      {
-       element = Feld[x][y];
-       move_pattern = element_info[element].move_pattern;
-
-       if (!CAN_MOVE(element))
-         return;
-      }
-#else
       if (Feld[x][y] != element)       /* element has changed */
        return;
-#endif
-    }
-#endif
-
-#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 0
-    if (FrameCounter < 1 && x == 0 && y == 29)
-      printf(":1: %d/%d: %d [%d]\n", x, y, MovDir[x][y], FrameCounter);
-#endif
 
     if (!MovDelay[x][y])       /* start new movement phase */
     {
@@ -5893,11 +6201,6 @@ void StartMoving(int x, int y)
       {
        TurnRound(x, y);
 
-#if 0
-       if (FrameCounter < 1 && x == 0 && y == 29)
-         printf(":9: %d: %d [%d]\n", y, MovDir[x][y], FrameCounter);
-#endif
-
        if (MovDelay[x][y] && (element == EL_BUG ||
                               element == EL_SPACESHIP ||
                               element == EL_SP_SNIKSNAK ||
@@ -5911,42 +6214,11 @@ void StartMoving(int x, int y)
     {
       MovDelay[x][y]--;
 
-#if 0
-      if (element == EL_YAMYAM)
-      {
-       printf("::: %d\n",
-              el_act_dir2img(EL_YAMYAM, ACTION_WAITING, MV_LEFT));
-       DrawLevelElementAnimation(x, y, element);
-      }
-#endif
-
-      if (MovDelay[x][y])      /* element still has to wait some time */
-      {
-#if 0
-       /* !!! PLACE THIS SOMEWHERE AFTER "TurnRound()" !!! */
-       ResetGfxAnimation(x, y);
-#endif
-
-#if 0
-       if (GfxAction[x][y] != ACTION_WAITING)
-         printf("::: %d: %d != ACTION_WAITING\n", element, GfxAction[x][y]);
-
-       GfxAction[x][y] = ACTION_WAITING;
-#endif
-      }
-
       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
        PlayLevelSoundAction(x, y, ACTION_WAITING);
       }
       else if (element == EL_SP_ELECTRON)
@@ -5963,10 +6235,6 @@ void StartMoving(int x, int y)
                       dir == MV_DOWN   ? IMG_FLAMES_1_DOWN : IMG_EMPTY);
        int frame = getGraphicAnimationFrame(graphic, GfxFrame[x][y]);
 
-#if 0
-       printf("::: %d, %d\n", GfxAction[x][y], GfxFrame[x][y]);
-#endif
-
        GfxAction[x][y] = ACTION_ATTACKING;
 
        if (IS_PLAYER(x, y))
@@ -6006,16 +6274,10 @@ void StartMoving(int x, int y)
              RemoveMovingField(xx, yy);
 #endif
 
-#if 0
-           if (ChangeDelay[xx][yy])
-             printf("::: !!! [%d]\n", (IS_MOVING(xx, yy) ||
-                                       Feld[xx][yy] == EL_BLOCKED));
-#endif
-
-#if 1
            ChangeDelay[xx][yy] = 0;
-#endif
+
            Feld[xx][yy] = EL_FLAMES;
+
            if (IN_SCR_FIELD(sx, sy))
            {
              DrawLevelFieldCrumbledSand(xx, yy);
@@ -6037,13 +6299,6 @@ void StartMoving(int x, int y)
 
        return;
       }
-
-#if 0
-      /* 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;
-#endif
     }
 
     /* now make next step */
@@ -6054,38 +6309,16 @@ void StartMoving(int x, int y)
        IN_LEV_FIELD(newx, newy) && IS_PLAYER(newx, newy) &&
        !PLAYER_ENEMY_PROTECTED(newx, newy))
     {
-#if 1
-      TestIfBadThingRunsIntoHero(x, y, MovDir[x][y]);
+      TestIfBadThingRunsIntoPlayer(x, y, MovDir[x][y]);
 
       return;
-#else
-      /* player killed by element which is deadly when colliding with */
-      MovDir[x][y] = 0;
-      KillHero(PLAYERINFO(newx, newy));
-      return;
-#endif
-
     }
-#if 1
-#if 1
+
     else if (CAN_MOVE_INTO_ACID(element) &&
             IN_LEV_FIELD(newx, newy) && Feld[newx][newy] == EL_ACID &&
+            !IS_MV_DIAGONAL(MovDir[x][y]) &&
             (MovDir[x][y] == MV_DOWN ||
              game.engine_version >= VERSION_IDENT(3,1,0,0)))
-#else
-    else if (CAN_MOVE_INTO_ACID(element) && MovDir[x][y] == MV_DOWN &&
-            IN_LEV_FIELD(newx, newy) && Feld[newx][newy] == EL_ACID)
-#endif
-#else
-
-    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_ACID)
-#endif
     {
       SplashAcid(newx, newy);
       Store[x][y] = EL_ACID;
@@ -6094,13 +6327,8 @@ void StartMoving(int x, int y)
     {
       if (Feld[newx][newy] == EL_EXIT_OPEN)
       {
-#if 1
        RemoveField(x, y);
        DrawLevelField(x, y);
-#else
-       Feld[x][y] = EL_EMPTY;
-       DrawLevelField(x, y);
-#endif
 
        PlayLevelSound(newx, newy, SND_PENGUIN_PASSING);
        if (IN_SCR_FIELD(SCREENX(newx), SCREENY(newy)))
@@ -6115,10 +6343,10 @@ void StartMoving(int x, int y)
       }
       else if (IS_FOOD_PENGUIN(Feld[newx][newy]))
       {
-       if (DigField(local_player, x, y, newx, newy, 0,0, DF_DIG) == MF_MOVING)
+       if (DigField(local_player, x, y, newx, newy, 0,0, DF_DIG) == MP_MOVING)
          DrawLevelField(newx, newy);
        else
-         GfxDir[x][y] = MovDir[x][y] = MV_NO_MOVING;
+         GfxDir[x][y] = MovDir[x][y] = MV_NONE;
       }
       else if (!IS_FREE(newx, newy))
       {
@@ -6156,32 +6384,102 @@ void StartMoving(int x, int y)
        return;
       }
     }
+    else if (element == EL_EMC_ANDROID && IN_LEV_FIELD(newx, newy))
+    {
+      if (Store[x][y] != EL_EMPTY)
+      {
+       boolean can_clone = FALSE;
+       int xx, yy;
 
-#if 1
+       /* check if element to clone is still there */
+       for (yy = y - 1; yy <= y + 1; yy++) for (xx = x - 1; xx <= x + 1; xx++)
+       {
+         if (IN_LEV_FIELD(xx, yy) && Feld[xx][yy] == Store[x][y])
+         {
+           can_clone = TRUE;
 
-    /*
-    else if (move_pattern & MV_MAZE_RUNNER_STYLE && IN_LEV_FIELD(newx, newy))
-    */
+           break;
+         }
+       }
 
-    else if (IS_CUSTOM_ELEMENT(element) &&
-            CUSTOM_ELEMENT_CAN_ENTER_FIELD(element, newx, newy)
+       /* cannot clone or target field not free anymore -- do not clone */
+       if (!can_clone || !ANDROID_CAN_ENTER_FIELD(element, newx, newy))
+         Store[x][y] = EL_EMPTY;
+      }
+
+      if (ANDROID_CAN_ENTER_FIELD(element, newx, newy))
+      {
+       if (IS_MV_DIAGONAL(MovDir[x][y]))
+       {
+         int diagonal_move_dir = MovDir[x][y];
+         int stored = Store[x][y];
+         int change_delay = 8;
+         int graphic;
 
+         /* android is moving diagonally */
+
+         CreateField(x, y, EL_DIAGONAL_SHRINKING);
+
+         Store[x][y] = (stored == EL_ACID ? EL_EMPTY : stored);
+         GfxElement[x][y] = EL_EMC_ANDROID;
+         GfxAction[x][y] = ACTION_SHRINKING;
+         GfxDir[x][y] = diagonal_move_dir;
+         ChangeDelay[x][y] = change_delay;
+
+         graphic = el_act_dir2img(GfxElement[x][y], GfxAction[x][y],
+                                  GfxDir[x][y]);
+
+         DrawLevelGraphicAnimation(x, y, graphic);
+         PlayLevelSoundAction(x, y, ACTION_SHRINKING);
+
+         if (Feld[newx][newy] == EL_ACID)
+         {
+           SplashAcid(newx, newy);
+
+           return;
+         }
+
+         CreateField(newx, newy, EL_DIAGONAL_GROWING);
+
+         Store[newx][newy] = EL_EMC_ANDROID;
+         GfxElement[newx][newy] = EL_EMC_ANDROID;
+         GfxAction[newx][newy] = ACTION_GROWING;
+         GfxDir[newx][newy] = diagonal_move_dir;
+         ChangeDelay[newx][newy] = change_delay;
+
+         graphic = el_act_dir2img(GfxElement[newx][newy],
+                                  GfxAction[newx][newy], GfxDir[newx][newy]);
+
+         DrawLevelGraphicAnimation(newx, newy, graphic);
+         PlayLevelSoundAction(newx, newy, ACTION_GROWING);
+
+         return;
+       }
+       else
+       {
+         Feld[newx][newy] = EL_EMPTY;
+         DrawLevelField(newx, newy);
+
+         PlayLevelSoundAction(x, y, ACTION_DIGGING);
+       }
+      }
+      else if (!IS_FREE(newx, newy))
+      {
 #if 0
- &&
-            !IS_FREE(newx, newy)
+       if (IS_PLAYER(x, y))
+         DrawPlayerField(x, y);
+       else
+         DrawLevelField(x, y);
 #endif
 
-)
+       return;
+      }
+    }
+    else if (IS_CUSTOM_ELEMENT(element) &&
+            CUSTOM_ELEMENT_CAN_ENTER_FIELD(element, newx, newy))
     {
       int new_element = Feld[newx][newy];
 
-#if 0
-      printf("::: '%s' digs '%s' [%d]\n",
-            element_info[element].token_name,
-            element_info[Feld[newx][newy]].token_name,
-            StorePlayer[newx][newy]);
-#endif
-
       if (!IS_FREE(newx, newy))
       {
        int action = (IS_DIGGABLE(new_element) ? ACTION_DIGGING :
@@ -6217,29 +6515,20 @@ void StartMoving(int x, int y)
        PlayLevelSoundAction(x, y, action);
       }
 
-#if 1
-#if 1
       Store[newx][newy] = EL_EMPTY;
+#if 1
+      /* this makes it possible to leave the removed element again */
+      if (IS_EQUAL_OR_IN_GROUP(new_element, MOVE_ENTER_EL(element)))
+       Store[newx][newy] = new_element;
+#else
       if (IS_EQUAL_OR_IN_GROUP(new_element, MOVE_ENTER_EL(element)))
       {
-#if USE_CHANGE_TO_TRIGGERED
        int move_leave_element = element_info[element].move_leave_element;
 
+       /* this makes it possible to leave the removed element again */
        Store[newx][newy] = (move_leave_element == EL_TRIGGER_ELEMENT ?
                             new_element : move_leave_element);
-#else
-       Store[newx][newy] = element_info[element].move_leave_element;
-#endif
       }
-#else
-      Store[newx][newy] = EL_EMPTY;
-      if (IS_EQUAL_OR_IN_GROUP(new_element, MOVE_ENTER_EL(element)) ||
-         element_info[element].move_leave_type == LEAVE_TYPE_UNLIMITED)
-       Store[newx][newy] = element_info[element].move_leave_element;
-#endif
-#else
-      if (IS_EQUAL_OR_IN_GROUP(new_element, MOVE_ENTER_EL(element)))
-       element_info[element].can_leave_element = TRUE;
 #endif
 
       if (move_pattern & MV_MAZE_RUNNER_STYLE)
@@ -6248,9 +6537,6 @@ void StartMoving(int x, int y)
        PlayerVisit[x][y] /= 8;         /* expire player visit path */
       }
     }
-
-#endif
-
     else if (element == EL_DRAGON && IN_LEV_FIELD(newx, newy))
     {
       if (!IS_FREE(newx, newy))
@@ -6279,10 +6565,8 @@ void StartMoving(int x, int y)
            element1 != EL_DRAGON && element2 != EL_DRAGON &&
            element1 != EL_FLAMES && element2 != EL_FLAMES)
        {
-#if 1
          ResetGfxAnimation(x, y);
          GfxAction[x][y] = ACTION_ATTACKING;
-#endif
 
          if (IS_PLAYER(x, y))
            DrawPlayerField(x, y);
@@ -6344,12 +6628,15 @@ void StartMoving(int x, int y)
 #if 0
       /* !!! test !!! */
       if (IS_MOVING(newx, newy) || IS_BLOCKED(newx, newy))
+      {
+       RemoveMovingField(newx, newy);
+      }
 #else
       if (IS_MOVING(newx, newy))
-#endif
       {
        RemoveMovingField(newx, newy);
       }
+#endif
       else
       {
        Feld[newx][newy] = EL_EMPTY;
@@ -6403,19 +6690,13 @@ void StartMoving(int x, int y)
       TurnRound(x, y);
 
 #if 0
+      /* !!! NEW "CE_BLOCKED" STUFF !!! -- DOES NOT WORK YET... !!! */
       if (move_pattern & MV_ANY_DIRECTION &&
          move_pattern == MovDir[x][y])
       {
        int blocking_element =
          (IN_LEV_FIELD(newx, newy) ? Feld[newx][newy] : BorderElement);
 
-#if 0
-       printf("::: '%s' is blocked by '%s'! [%d,%d -> %d,%d]\n",
-              element_info[element].token_name,
-              element_info[blocking_element].token_name,
-              x, y, newx, newy);
-#endif
-
        CheckElementChangeBySide(x, y, element, blocking_element, CE_BLOCKED,
                                 MovDir[x][y]);
 
@@ -6423,31 +6704,11 @@ void StartMoving(int x, int y)
       }
 #endif
 
-#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_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)
-       DrawLevelElementAnimationIfNeeded(x, y, element);
-#endif
 
       if (DONT_TOUCH(element))
-       TestIfBadThingTouchesHero(x, y);
-
-#if 0
-      PlayLevelSoundAction(x, y, ACTION_WAITING);
-#endif
+       TestIfBadThingTouchesPlayer(x, y);
 
       return;
     }
@@ -6461,42 +6722,24 @@ void StartMoving(int x, int y)
     ContinueMoving(x, y);
 }
 
-void dummy()
-{
-}
-
 void ContinueMoving(int x, int y)
 {
   int element = Feld[x][y];
-  int stored = Store[x][y];
   struct ElementInfo *ei = &element_info[element];
   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 newx = x + dx, newy = y + dy;
-#if 0
-  int nextx = newx + dx, nexty = newy + dy;
-#endif
-#if 1
+  int stored = Store[x][y];
+  int stored_new = Store[newx][newy];
   boolean pushed_by_player   = (Pushed[x][y] && IS_PLAYER(x, y));
   boolean pushed_by_conveyor = (Pushed[x][y] && !IS_PLAYER(x, y));
-#else
-  boolean pushed_by_player = Pushed[x][y];
-#endif
   boolean last_line = (newy == lev_fieldy - 1);
 
   MovPos[x][y] += getElementMoveStepsize(x, y);
 
-#if 0
-  if (pushed_by_player && IS_PLAYER(x, y))
-  {
-    /* special case: moving object pushed by player */
-    MovPos[x][y] = SIGN(MovPos[x][y]) * (TILEX - ABS(PLAYERINFO(x,y)->MovPos));
-  }
-#else
   if (pushed_by_player)        /* special case: moving object pushed by player */
     MovPos[x][y] = SIGN(MovPos[x][y]) * (TILEX - ABS(PLAYERINFO(x,y)->MovPos));
-#endif
 
   if (ABS(MovPos[x][y]) < TILEX)
   {
@@ -6511,12 +6754,10 @@ void ContinueMoving(int x, int y)
   Feld[newx][newy] = element;
   MovPos[x][y] = 0;    /* force "not moving" for "crumbled sand" */
 
-#if 1
   if (Store[x][y] == EL_ACID)  /* element is moving into acid pool */
   {
     element = Feld[newx][newy] = EL_ACID;
   }
-#endif
   else if (element == EL_MOLE)
   {
     Feld[x][y] = EL_SAND;
@@ -6546,6 +6787,10 @@ void ContinueMoving(int x, int y)
     if (!game.magic_wall_active)
       Feld[x][y] = EL_MAGIC_WALL_DEAD;
     element = Feld[newx][newy] = Store[x][y];
+
+#if USE_NEW_CUSTOM_VALUE
+    InitField(newx, newy, FALSE);
+#endif
   }
   else if (element == EL_BD_MAGIC_WALL_FILLING)
   {
@@ -6560,6 +6805,10 @@ void ContinueMoving(int x, int y)
     if (!game.magic_wall_active)
       Feld[x][y] = EL_BD_MAGIC_WALL_DEAD;
     element = Feld[newx][newy] = Store[x][y];
+
+#if USE_NEW_CUSTOM_VALUE
+    InitField(newx, newy, FALSE);
+#endif
   }
   else if (element == EL_AMOEBA_DROPPING)
   {
@@ -6576,48 +6825,48 @@ void ContinueMoving(int x, int y)
 
     Back[x][y] = Back[newx][newy] = 0;
   }
-#if 0
-  else if (Store[x][y] == EL_ACID)
-  {
-    element = Feld[newx][newy] = EL_ACID;
-  }
-#endif
-#if 0
-  else if (IS_CUSTOM_ELEMENT(element) && !IS_PLAYER(x, y) &&
-          ei->move_leave_element != EL_EMPTY &&
-          (ei->move_leave_type == LEAVE_TYPE_UNLIMITED ||
-           Store[x][y] != EL_EMPTY))
-  {
-    /* some elements can leave other elements behind after moving */
-
-    Feld[x][y] = ei->move_leave_element;
-    InitField(x, y, FALSE);
-
-    if (GFX_CRUMBLED(Feld[x][y]))
-      DrawLevelFieldCrumbledSandNeighbours(x, y);
-  }
-#endif
 
   Store[x][y] = EL_EMPTY;
   MovPos[x][y] = 0;
   MovDir[x][y] = 0;
   MovDelay[x][y] = 0;
+
   MovDelay[newx][newy] = 0;
 
+#if 1
+  if (CAN_CHANGE_OR_HAS_ACTION(element))
+#else
   if (CAN_CHANGE(element))
+#endif
   {
     /* copy element change control values to new field */
     ChangeDelay[newx][newy] = ChangeDelay[x][y];
     ChangePage[newx][newy]  = ChangePage[x][y];
-    Changed[newx][newy]     = Changed[x][y];
+    ChangeCount[newx][newy] = ChangeCount[x][y];
     ChangeEvent[newx][newy] = ChangeEvent[x][y];
+
+#if 0
+#if USE_NEW_CUSTOM_VALUE
+    CustomValue[newx][newy] = CustomValue[x][y];
+#endif
+#endif
   }
 
+#if 1
+#if USE_NEW_CUSTOM_VALUE
+    CustomValue[newx][newy] = CustomValue[x][y];
+#endif
+#endif
+
   ChangeDelay[x][y] = 0;
   ChangePage[x][y] = -1;
-  Changed[x][y] = FALSE;
+  ChangeCount[x][y] = 0;
   ChangeEvent[x][y] = -1;
 
+#if USE_NEW_CUSTOM_VALUE
+  CustomValue[x][y] = 0;
+#endif
+
   /* copy animation control values to new field */
   GfxFrame[newx][newy]  = GfxFrame[x][y];
   GfxRandom[newx][newy] = GfxRandom[x][y];     /* keep same random value */
@@ -6626,26 +6875,31 @@ void ContinueMoving(int x, int y)
 
   Pushed[x][y] = Pushed[newx][newy] = FALSE;
 
-#if 0
-  /* do this after checking for left-behind element */
-  ResetGfxAnimation(x, y);     /* reset animation values for old field */
-#endif
-
-#if 1
   /* some elements can leave other elements behind after moving */
 #if 1
-  if (IS_CUSTOM_ELEMENT(element) && ei->move_leave_element != EL_EMPTY &&
+  if (ei->move_leave_element != EL_EMPTY &&
       (ei->move_leave_type == LEAVE_TYPE_UNLIMITED || stored != EL_EMPTY) &&
       (!IS_PLAYER(x, y) || IS_WALKABLE(ei->move_leave_element)))
 #else
   if (IS_CUSTOM_ELEMENT(element) && ei->move_leave_element != EL_EMPTY &&
       (ei->move_leave_type == LEAVE_TYPE_UNLIMITED || stored != EL_EMPTY) &&
-      !IS_PLAYER(x, y))
+      (!IS_PLAYER(x, y) || IS_WALKABLE(ei->move_leave_element)))
 #endif
   {
     int move_leave_element = ei->move_leave_element;
 
-#if USE_CHANGE_TO_TRIGGERED
+#if 1
+#if 1
+    /* this makes it possible to leave the removed element again */
+    if (ei->move_leave_element == EL_TRIGGER_ELEMENT)
+      move_leave_element = (stored == EL_ACID ? EL_EMPTY : stored);
+#else
+    /* this makes it possible to leave the removed element again */
+    if (ei->move_leave_element == EL_TRIGGER_ELEMENT)
+      move_leave_element = stored;
+#endif
+#else
+    /* this makes it possible to leave the removed element again */
     if (ei->move_leave_type == LEAVE_TYPE_LIMITED &&
         ei->move_leave_element == EL_TRIGGER_ELEMENT)
       move_leave_element = stored;
@@ -6653,10 +6907,8 @@ void ContinueMoving(int x, int y)
 
     Feld[x][y] = move_leave_element;
 
-#if USE_PREVIOUS_MOVE_DIR
     if (element_info[Feld[x][y]].move_direction_initial == MV_START_PREVIOUS)
       MovDir[x][y] = direction;
-#endif
 
     InitField(x, y, FALSE);
 
@@ -6666,63 +6918,16 @@ void ContinueMoving(int x, int y)
     if (ELEM_IS_PLAYER(move_leave_element))
       RelocatePlayer(x, y, move_leave_element);
   }
-#endif
-
-#if 0
-  /* some elements can leave other elements behind after moving */
-  if (IS_CUSTOM_ELEMENT(element) && !IS_PLAYER(x, y) &&
-      ei->move_leave_element != EL_EMPTY &&
-      (ei->move_leave_type == LEAVE_TYPE_UNLIMITED ||
-       ei->can_leave_element_last))
-  {
-    Feld[x][y] = ei->move_leave_element;
-    InitField(x, y, FALSE);
-
-    if (GFX_CRUMBLED(Feld[x][y]))
-      DrawLevelFieldCrumbledSandNeighbours(x, y);
-  }
 
-  ei->can_leave_element_last = ei->can_leave_element;
-  ei->can_leave_element = FALSE;
-#endif
-
-#if 1
   /* do this after checking for left-behind element */
   ResetGfxAnimation(x, y);     /* reset animation values for old field */
-#endif
-
-#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 0
-  if (!CAN_MOVE(element) ||
-      (CAN_FALL(element) && direction == MV_DOWN))
-    GfxDir[x][y] = MovDir[newx][newy] = 0;
-#else
   if (!CAN_MOVE(element) ||
       (CAN_FALL(element) && direction == MV_DOWN &&
        (element == EL_SPRING ||
        element_info[element].move_pattern == MV_WHEN_PUSHED ||
        element_info[element].move_pattern == MV_WHEN_DROPPED)))
     GfxDir[x][y] = MovDir[newx][newy] = 0;
-#endif
-
-#endif
-#endif
 
   DrawLevelField(x, y);
   DrawLevelField(newx, newy);
@@ -6735,39 +6940,28 @@ void ContinueMoving(int x, int y)
       !(element_info[element].move_pattern & direction))
     TurnRound(newx, newy);
 
-#if 1
   /* prevent elements on conveyor belt from moving on in last direction */
   if (pushed_by_conveyor && CAN_FALL(element) &&
       direction & MV_HORIZONTAL)
-  {
-#if 0
-    if (CAN_MOVE(element))
-      InitMovDir(newx, newy);
-    else
-      MovDir[newx][newy] = 0;
-#else
     MovDir[newx][newy] = 0;
-#endif
-  }
-#endif
 
   if (!pushed_by_player)
   {
     int nextx = newx + dx, nexty = newy + dy;
     boolean check_collision_again = IN_LEV_FIELD_AND_IS_FREE(nextx, nexty);
 
-    WasJustMoving[newx][newy] = 3;
+    WasJustMoving[newx][newy] = CHECK_DELAY_MOVING;
 
     if (CAN_FALL(element) && direction == MV_DOWN)
-      WasJustFalling[newx][newy] = 3;
+      WasJustFalling[newx][newy] = CHECK_DELAY_FALLING;
 
     if ((!CAN_FALL(element) || direction == MV_DOWN) && check_collision_again)
-      CheckCollision[newx][newy] = 2;
+      CheckCollision[newx][newy] = CHECK_DELAY_COLLISION;
   }
 
   if (DONT_TOUCH(element))     /* object may be nasty to player or others */
   {
-    TestIfBadThingTouchesHero(newx, newy);
+    TestIfBadThingTouchesPlayer(newx, newy);
     TestIfBadThingTouchesFriend(newx, newy);
 
     if (!IS_CUSTOM_ELEMENT(element))
@@ -6776,147 +6970,63 @@ void ContinueMoving(int x, int y)
   else if (element == EL_PENGUIN)
     TestIfFriendTouchesBadThing(newx, newy);
 
-#if USE_NEW_MOVE_STYLE
-#if 0
-  if (CAN_FALL(element) && direction == MV_DOWN &&
-      !last_line && IS_PLAYER(x, newy + 1))
-    printf("::: we would now kill the player [%d]\n", FrameCounter);
-#endif
-
   /* give the player one last chance (one more frame) to move away */
   if (CAN_FALL(element) && direction == MV_DOWN &&
       (last_line || (!IS_FREE(x, newy + 1) &&
                     (!IS_PLAYER(x, newy + 1) ||
                      game.engine_version < VERSION_IDENT(3,1,1,0)))))
     Impact(x, newy);
-#else
-  if (CAN_FALL(element) && direction == MV_DOWN &&
-      (last_line || !IS_FREE(x, newy + 1)))
-    Impact(x, newy);
-#endif
 
-#if 1
-
-#if USE_PUSH_BUGFIX
-#if 1
   if (pushed_by_player && !game.use_change_when_pushing_bug)
-#else
-  if (pushed_by_player && game.engine_version >= VERSION_IDENT(3,1,0,0))
-#endif
-#else
-  if (pushed_by_player)
-#endif
-
   {
-#if 1
-    int dig_side = MV_DIR_OPPOSITE(direction);
-#else
-    static int trigger_sides[4] =
-    {
-      CH_SIDE_RIGHT,   /* moving left  */
-      CH_SIDE_LEFT,    /* moving right */
-      CH_SIDE_BOTTOM,  /* moving up    */
-      CH_SIDE_TOP,     /* moving down  */
-    };
-    int dig_side = trigger_sides[MV_DIR_BIT(direction)];
-#endif
+    int push_side = MV_DIR_OPPOSITE(direction);
     struct PlayerInfo *player = PLAYERINFO(x, y);
 
     CheckElementChangeByPlayer(newx, newy, element, CE_PUSHED_BY_PLAYER,
-                              player->index_bit, dig_side);
+                              player->index_bit, push_side);
     CheckTriggeredElementChangeByPlayer(newx,newy, element, CE_PLAYER_PUSHES_X,
-                                       player->index_bit, dig_side);
+                                       player->index_bit, push_side);
   }
-#endif
-
-#if 1
-  TestIfElementTouchesCustomElement(x, y);     /* empty or new element */
-#endif
 
-#if 0
-  if (ChangePage[newx][newy] != -1)                    /* delayed change */
-    ChangeElement(newx, newy, ChangePage[newx][newy]);
-#endif
-
-#if 1
+  if (element == EL_EMC_ANDROID && pushed_by_player)   /* make another move */
+    MovDelay[newx][newy] = 1;
 
-  TestIfElementHitsCustomElement(newx, newy, direction);
+  CheckTriggeredElementChangeBySide(x, y, element, CE_MOVE_OF_X, direction);
 
-#else
+  TestIfElementTouchesCustomElement(x, y);     /* empty or new element */
 
-  if (!IN_LEV_FIELD(nextx, nexty) || !IS_FREE(nextx, nexty))
+#if 0
+  if (ChangePage[newx][newy] != -1)            /* delayed change */
   {
-    int hitting_element = Feld[newx][newy];
+    int page = ChangePage[newx][newy];
+    struct ElementChangeInfo *change = &ei->change_page[page];
 
-    /* !!! fix side (direction) orientation here and elsewhere !!! */
-    CheckElementChangeBySide(newx, newy, hitting_element, CE_HITTING_SOMETHING,
-                            direction);
+    ChangePage[newx][newy] = -1;
 
-#if 0
-    if (IN_LEV_FIELD(nextx, nexty))
+    if (change->can_change)
     {
-      int opposite_direction = MV_DIR_OPPOSITE(direction);
-      int hitting_side = direction;
-      int touched_side = opposite_direction;
-      int touched_element = MovingOrBlocked2Element(nextx, nexty);
-      boolean object_hit = (!IS_MOVING(nextx, nexty) ||
-                           MovDir[nextx][nexty] != direction ||
-                           ABS(MovPos[nextx][nexty]) <= TILEY / 2);
-
-      if (object_hit)
+      if (ChangeElement(newx, newy, element, page))
       {
-       int i;
+        if (change->post_change_function)
+          change->post_change_function(newx, newy);
+      }
+    }
 
-       CheckElementChangeBySide(nextx, nexty, touched_element,
-                                CE_HIT_BY_SOMETHING, opposite_direction);
-
-       if (IS_CUSTOM_ELEMENT(hitting_element) &&
-           HAS_ANY_CHANGE_EVENT(hitting_element, CE_HITTING_X))
-       {
-         for (i = 0; i < element_info[hitting_element].num_change_pages; i++)
-         {
-           struct ElementChangeInfo *change =
-             &element_info[hitting_element].change_page[i];
-
-           if (change->can_change &&
-               change->has_event[CE_HITTING_X] &&
-               change->trigger_side & touched_side &&
-               change->trigger_element == touched_element)
-           {
-             CheckElementChangeByPage(newx, newy, hitting_element,
-                                      touched_element, CE_HITTING_X, i);
-             break;
-           }
-         }
-       }
-
-       if (IS_CUSTOM_ELEMENT(touched_element) &&
-           HAS_ANY_CHANGE_EVENT(touched_element, CE_HIT_BY_X))
-       {
-         for (i = 0; i < element_info[touched_element].num_change_pages; i++)
-         {
-           struct ElementChangeInfo *change =
-             &element_info[touched_element].change_page[i];
-
-           if (change->can_change &&
-               change->has_event[CE_HIT_BY_X] &&
-               change->trigger_side & hitting_side &&
-               change->trigger_element == hitting_element)
-           {
-             CheckElementChangeByPage(nextx, nexty, touched_element,
-                                      hitting_element, CE_HIT_BY_X,i);
-             break;
-           }
-         }
-       }
-      }
-    }
-#endif
-  }
-#endif
+    if (change->has_action)
+      ExecuteCustomElementAction(newx, newy, element, page);
+  }
+#endif
 
+  TestIfElementHitsCustomElement(newx, newy, direction);
   TestIfPlayerTouchesCustomElement(newx, newy);
   TestIfElementTouchesCustomElement(newx, newy);
+
+#if 1
+  if (IS_CUSTOM_ELEMENT(element) && ei->move_enter_element != EL_EMPTY &&
+      IS_EQUAL_OR_IN_GROUP(stored_new, ei->move_enter_element))
+    CheckElementChangeBySide(newx, newy, element, stored_new, CE_DIGGING_X,
+                                     MV_DIR_OPPOSITE(direction));
+#endif
 }
 
 int AmoebeNachbarNr(int ax, int ay)
@@ -6985,13 +7095,14 @@ void AmoebenVereinigen(int ax, int ay)
       AmoebaCnt2[new_group_nr] += AmoebaCnt2[old_group_nr];
       AmoebaCnt2[old_group_nr] = 0;
 
-      for (yy = 0; yy < lev_fieldy; yy++)
+#if 1
+      SCAN_PLAYFIELD(xx, yy)
+#else
+      for (yy = 0; yy < lev_fieldy; yy++) for (xx = 0; xx < lev_fieldx; xx++)
+#endif
       {
-       for (xx = 0; xx < lev_fieldx; xx++)
-       {
-         if (AmoebaNr[xx][yy] == old_group_nr)
-           AmoebaNr[xx][yy] = new_group_nr;
-       }
+       if (AmoebaNr[xx][yy] == old_group_nr)
+         AmoebaNr[xx][yy] = new_group_nr;
       }
     }
   }
@@ -7014,17 +7125,19 @@ void AmoebeUmwandeln(int ax, int ay)
     }
 #endif
 
-    for (y = 0; y < lev_fieldy; y++)
+#if 1
+    SCAN_PLAYFIELD(x, y)
+#else
+    for (y = 0; y < lev_fieldy; y++) for (x = 0; x < lev_fieldx; x++)
+#endif
     {
-      for (x = 0; x < lev_fieldx; x++)
+      if (Feld[x][y] == EL_AMOEBA_DEAD && 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_AMOEBA_TO_DIAMOND;
-       }
+       AmoebaNr[x][y] = 0;
+       Feld[x][y] = EL_AMOEBA_TO_DIAMOND;
       }
     }
+
     PlayLevelSound(ax, ay, (IS_GEM(level.amoeba_content) ?
                            SND_AMOEBA_TURNING_TO_GEM :
                            SND_AMOEBA_TURNING_TO_ROCK));
@@ -7074,21 +7187,22 @@ void AmoebeUmwandelnBD(int ax, int ay, int new_element)
   }
 #endif
 
-  for (y = 0; y < lev_fieldy; y++)
+#if 1
+  SCAN_PLAYFIELD(x, y)
+#else
+  for (y = 0; y < lev_fieldy; y++) for (x = 0; x < lev_fieldx; x++)
+#endif
   {
-    for (x = 0; x < lev_fieldx; x++)
+    if (AmoebaNr[x][y] == group_nr &&
+       (Feld[x][y] == EL_AMOEBA_DEAD ||
+        Feld[x][y] == EL_BD_AMOEBA ||
+        Feld[x][y] == EL_AMOEBA_GROWING))
     {
-      if (AmoebaNr[x][y] == group_nr &&
-         (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;
-       InitField(x, y, FALSE);
-       DrawLevelField(x, y);
-       done = TRUE;
-      }
+      AmoebaNr[x][y] = 0;
+      Feld[x][y] = new_element;
+      InitField(x, y, FALSE);
+      DrawLevelField(x, y);
+      done = TRUE;
     }
   }
 
@@ -7109,14 +7223,7 @@ void AmoebeWaechst(int x, int y)
 
     if (DelayReached(&sound_delay, sound_delay_value))
     {
-#if 1
       PlayLevelSoundElementAction(x, y, Store[x][y], ACTION_GROWING);
-#else
-      if (Store[x][y] == EL_BD_AMOEBA)
-       PlayLevelSound(x, y, SND_BD_AMOEBA_GROWING);
-      else
-       PlayLevelSound(x, y, SND_AMOEBA_GROWING);
-#endif
       sound_delay_value = 30;
     }
   }
@@ -7183,6 +7290,7 @@ void AmoebeAbleger(int ax, int ay)
   int element = Feld[ax][ay];
   int graphic = el2img(element);
   int newax = ax, neway = ay;
+  boolean can_drop = (element == EL_AMOEBA_WET || element == EL_EMC_DRIPPER);
   static int xy[4][2] =
   {
     { 0, -1 },
@@ -7191,7 +7299,7 @@ void AmoebeAbleger(int ax, int ay)
     { 0, +1 }
   };
 
-  if (!level.amoeba_speed)
+  if (!level.amoeba_speed && element != EL_EMC_DRIPPER)
   {
     Feld[ax][ay] = EL_AMOEBA_DEAD;
     DrawLevelField(ax, ay);
@@ -7211,7 +7319,7 @@ void AmoebeAbleger(int ax, int ay)
       return;
   }
 
-  if (element == EL_AMOEBA_WET)        /* object is an acid / amoeba drop */
+  if (can_drop)                        /* EL_AMOEBA_WET or EL_EMC_DRIPPER */
   {
     int start = RND(4);
     int x = ax + xy[start][0];
@@ -7220,7 +7328,6 @@ void AmoebeAbleger(int ax, int ay)
     if (!IN_LEV_FIELD(x, y))
       return;
 
-#if 1
     if (IS_FREE(x, y) ||
        CAN_GROW_INTO(Feld[x][y]) ||
        Feld[x][y] == EL_QUICKSAND_EMPTY)
@@ -7228,15 +7335,6 @@ void AmoebeAbleger(int ax, int ay)
       newax = x;
       neway = y;
     }
-#else
-    /* !!! extend EL_SAND to anything diggable (but maybe not SP_BASE) !!! */
-    if (IS_FREE(x, y) ||
-       Feld[x][y] == EL_SAND || Feld[x][y] == EL_QUICKSAND_EMPTY)
-    {
-      newax = x;
-      neway = y;
-    }
-#endif
 
     if (newax == ax && neway == ay)
       return;
@@ -7255,7 +7353,6 @@ void AmoebeAbleger(int ax, int ay)
       if (!IN_LEV_FIELD(x, y))
        continue;
 
-#if 1
       if (IS_FREE(x, y) ||
          CAN_GROW_INTO(Feld[x][y]) ||
          Feld[x][y] == EL_QUICKSAND_EMPTY)
@@ -7264,27 +7361,13 @@ void AmoebeAbleger(int ax, int ay)
        neway = y;
        break;
       }
-#else
-      /* !!! extend EL_SAND to anything diggable (but maybe not SP_BASE) !!! */
-      if (IS_FREE(x, y) ||
-         Feld[x][y] == EL_SAND || Feld[x][y] == EL_QUICKSAND_EMPTY)
-      {
-       newax = x;
-       neway = y;
-       break;
-      }
-#endif
       else if (IS_PLAYER(x, y))
        waiting_for_player = TRUE;
     }
 
     if (newax == ax && neway == ay)            /* amoeba cannot grow */
     {
-#if 1
       if (i == 4 && (!waiting_for_player || element == EL_BD_AMOEBA))
-#else
-      if (i == 4 && (!waiting_for_player || game.emulation == EMU_BOULDERDASH))
-#endif
       {
        Feld[ax][ay] = EL_AMOEBA_DEAD;
        DrawLevelField(ax, ay);
@@ -7330,20 +7413,17 @@ void AmoebeAbleger(int ax, int ay)
     }
   }
 
-  if (element != EL_AMOEBA_WET || neway < ay || !IS_FREE(newax, neway) ||
+  if (!can_drop || neway < ay || !IS_FREE(newax, neway) ||
       (neway == lev_fieldy - 1 && newax != ax))
   {
     Feld[newax][neway] = EL_AMOEBA_GROWING;    /* creation of new amoeba */
     Store[newax][neway] = element;
   }
-  else if (neway == ay)
+  else if (neway == ay || element == EL_EMC_DRIPPER)
   {
     Feld[newax][neway] = EL_AMOEBA_DROP;       /* drop left/right of amoeba */
-#if 1
+
     PlayLevelSoundAction(newax, neway, ACTION_GROWING);
-#else
-    PlayLevelSound(newax, neway, SND_AMOEBA_GROWING);
-#endif
   }
   else
   {
@@ -7360,10 +7440,14 @@ void AmoebeAbleger(int ax, int ay)
 void Life(int ax, int ay)
 {
   int x1, y1, x2, y2;
+#if 0
   static int life[4] = { 2, 3, 3, 3 }; /* parameters for "game of life" */
+#endif
   int life_time = 40;
   int element = Feld[ax][ay];
   int graphic = el2img(element);
+  int *life_parameter = (element == EL_GAME_OF_LIFE ? level.game_of_life :
+                        level.biomaze);
   boolean changed = FALSE;
 
   if (IS_ANIMATED(graphic))
@@ -7406,7 +7490,8 @@ void Life(int ax, int ay)
 
     if (xx == ax && yy == ay)          /* field in the middle */
     {
-      if (nachbarn < life[0] || nachbarn > life[1])
+      if (nachbarn < life_parameter[0] ||
+         nachbarn > life_parameter[1])
       {
        Feld[xx][yy] = EL_EMPTY;
        if (!Stop[xx][yy])
@@ -7415,24 +7500,10 @@ void Life(int ax, int ay)
        changed = TRUE;
       }
     }
-#if 1
     else if (IS_FREE(xx, yy) || CAN_GROW_INTO(Feld[xx][yy]))
     {                                  /* free border field */
-      if (nachbarn >= life[2] && nachbarn <= life[3])
-      {
-       Feld[xx][yy] = element;
-       MovDelay[xx][yy] = (element == EL_GAME_OF_LIFE ? 0 : life_time-1);
-       if (!Stop[xx][yy])
-         DrawLevelField(xx, yy);
-       Stop[xx][yy] = TRUE;
-       changed = TRUE;
-      }
-    }
-#else
-    /* !!! 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])
+      if (nachbarn >= life_parameter[2] &&
+         nachbarn <= life_parameter[3])
       {
        Feld[xx][yy] = element;
        MovDelay[xx][yy] = (element == EL_GAME_OF_LIFE ? 0 : life_time-1);
@@ -7442,7 +7513,6 @@ void Life(int ax, int ay)
        changed = TRUE;
       }
     }
-#endif
   }
 
   if (changed)
@@ -7468,12 +7538,7 @@ static void StopRobotWheel(int x, int y)
 
 static void InitTimegateWheel(int x, int y)
 {
-#if 1
   ChangeDelay[x][y] = level.time_timegate * FRAMES_PER_SECOND;
-#else
-  /* another brainless, "type style" bug ... :-( */
-  ChangeDelay[x][y] = level.time_wheel * FRAMES_PER_SECOND;
-#endif
 }
 
 static void RunTimegateWheel(int x, int y)
@@ -7481,6 +7546,54 @@ static void RunTimegateWheel(int x, int y)
   PlayLevelSound(x, y, SND_TIMEGATE_SWITCH_ACTIVE);
 }
 
+static void InitMagicBallDelay(int x, int y)
+{
+#if 1
+  ChangeDelay[x][y] = (level.ball_time + 1) * 8 + 1;
+#else
+  ChangeDelay[x][y] = level.ball_time * FRAMES_PER_SECOND + 1;
+#endif
+}
+
+static void ActivateMagicBall(int bx, int by)
+{
+  int x, y;
+
+  if (level.ball_random)
+  {
+    int pos_border = RND(8);   /* select one of the eight border elements */
+    int pos_content = (pos_border > 3 ? pos_border + 1 : pos_border);
+    int xx = pos_content % 3;
+    int yy = pos_content / 3;
+
+    x = bx - 1 + xx;
+    y = by - 1 + yy;
+
+    if (IN_LEV_FIELD(x, y) && Feld[x][y] == EL_EMPTY)
+      CreateField(x, y, level.ball_content[game.ball_content_nr].e[xx][yy]);
+  }
+  else
+  {
+    for (y = by - 1; y <= by + 1; y++) for (x = bx - 1; x <= bx + 1; x++)
+    {
+      int xx = x - bx + 1;
+      int yy = y - by + 1;
+
+      if (IN_LEV_FIELD(x, y) && Feld[x][y] == EL_EMPTY)
+       CreateField(x, y, level.ball_content[game.ball_content_nr].e[xx][yy]);
+    }
+  }
+
+  game.ball_content_nr = (game.ball_content_nr + 1) % level.num_ball_contents;
+}
+
+static void InitDiagonalMovingElement(int x, int y)
+{
+#if 0
+  MovDelay[x][y] = level.android_move_time;
+#endif
+}
+
 void CheckExit(int x, int y)
 {
   if (local_player->gems_still_needed > 0 ||
@@ -7529,21 +7642,19 @@ static void CloseAllOpenTimegates()
 {
   int x, y;
 
-  for (y = 0; y < lev_fieldy; y++)
-  {
-    for (x = 0; x < lev_fieldx; x++)
-    {
-      int element = Feld[x][y];
-
-      if (element == EL_TIMEGATE_OPEN || element == EL_TIMEGATE_OPENING)
-      {
-       Feld[x][y] = EL_TIMEGATE_CLOSING;
 #if 1
-       PlayLevelSoundAction(x, y, ACTION_CLOSING);
+  SCAN_PLAYFIELD(x, y)
 #else
-       PlayLevelSound(x, y, SND_TIMEGATE_CLOSING);
+  for (y = 0; y < lev_fieldy; y++) for (x = 0; x < lev_fieldx; x++)
 #endif
-      }
+  {
+    int element = Feld[x][y];
+
+    if (element == EL_TIMEGATE_OPEN || element == EL_TIMEGATE_OPENING)
+    {
+      Feld[x][y] = EL_TIMEGATE_CLOSING;
+
+      PlayLevelSoundAction(x, y, ACTION_CLOSING);
     }
   }
 }
@@ -7634,7 +7745,7 @@ void MauerWaechst(int x, int y)
 
       Feld[x][y] = Store[x][y];
       Store[x][y] = 0;
-      GfxDir[x][y] = MovDir[x][y] = MV_NO_MOVING;
+      GfxDir[x][y] = MovDir[x][y] = MV_NONE;
       DrawLevelField(x, y);
     }
   }
@@ -7699,7 +7810,8 @@ void MauerAbleger(int ax, int ay)
 
   if (element == EL_EXPANDABLE_WALL_HORIZONTAL ||
       element == EL_EXPANDABLE_WALL_ANY ||
-      element == EL_EXPANDABLE_WALL)
+      element == EL_EXPANDABLE_WALL ||
+      element == EL_BD_EXPANDABLE_WALL)
   {
     if (links_frei)
     {
@@ -7744,11 +7856,7 @@ void MauerAbleger(int ax, int ay)
     Feld[ax][ay] = EL_WALL;
 
   if (new_wall)
-#if 1
     PlayLevelSoundAction(ax, ay, ACTION_GROWING);
-#else
-    PlayLevelSound(ax, ay, SND_EXPANDABLE_WALL_GROWING);
-#endif
 }
 
 void CheckForDragon(int x, int y)
@@ -7827,9 +7935,10 @@ static void WarnBuggyBase(int x, int y)
 
   for (i = 0; i < NUM_DIRECTIONS; i++)
   {
-    int xx = x + xy[i][0], yy = y + xy[i][1];
+    int xx = x + xy[i][0];
+    int yy = y + xy[i][1];
 
-    if (IS_PLAYER(xx, yy))
+    if (IN_LEV_FIELD(xx, yy) && IS_PLAYER(xx, yy))
     {
       PlayLevelSound(x, y, SND_SP_BUGGY_BASE_ACTIVE);
 
@@ -7857,457 +7966,1034 @@ static void ChangeActiveTrap(int x, int y)
     DrawLevelFieldCrumbledSand(x, y);
 }
 
-static void ChangeElementNowExt(int x, int y, int target_element)
+static int getSpecialActionElement(int element, int number, int base_element)
 {
-  int previous_move_direction = MovDir[x][y];
-#if 1
-  boolean add_player = (ELEM_IS_PLAYER(target_element) &&
-                       IS_WALKABLE(Feld[x][y]));
-#else
-  boolean add_player = (ELEM_IS_PLAYER(target_element) &&
-                       IS_WALKABLE(Feld[x][y]) &&
-                       !IS_MOVING(x, y));
-#endif
+  return (element != EL_EMPTY ? element :
+         number != -1 ? base_element + number - 1 :
+         EL_EMPTY);
+}
 
-  /* check if element under player changes from accessible to unaccessible
-     (needed for special case of dropping element which then changes) */
-  if (IS_PLAYER(x, y) && !PLAYER_EXPLOSION_PROTECTED(x, y) &&
-      IS_ACCESSIBLE(Feld[x][y]) && !IS_ACCESSIBLE(target_element))
-  {
-#if 0
-    printf("::: BOOOM! [%d, '%s']\n", target_element,
-          element_info[target_element].token_name);
-#endif
+static int getModifiedActionNumber(int value_old, int operator, int operand,
+                                  int value_min, int value_max)
+{
+  int value_new = (operator == CA_MODE_SET      ? operand :
+                  operator == CA_MODE_ADD      ? value_old + operand :
+                  operator == CA_MODE_SUBTRACT ? value_old - operand :
+                  operator == CA_MODE_MULTIPLY ? value_old * operand :
+                  operator == CA_MODE_DIVIDE   ? value_old / MAX(1, operand) :
+                  operator == CA_MODE_MODULO   ? value_old % MAX(1, operand) :
+                  value_old);
 
-    Bang(x, y);
+  return (value_new < value_min ? value_min :
+         value_new > value_max ? value_max :
+         value_new);
+}
+
+static void ExecuteCustomElementAction(int x, int y, int element, int page)
+{
+  struct ElementInfo *ei = &element_info[element];
+  struct ElementChangeInfo *change = &ei->change_page[page];
+  int target_element = change->target_element;
+  int action_type = change->action_type;
+  int action_mode = change->action_mode;
+  int action_arg = change->action_arg;
+  int i;
+
+  if (!change->has_action)
     return;
-  }
 
-#if 1
-  if (!add_player)
-#endif
-  {
-#if 1
-    if (IS_MOVING(x, y) || IS_BLOCKED(x, y))
-      RemoveMovingField(x, y);
-    else
-      RemoveField(x, y);
+  /* ---------- determine action paramater values -------------------------- */
+
+  int level_time_value =
+    (level.time > 0 ? TimeLeft :
+     TimePlayed);
+
+  int action_arg_element =
+    (action_arg == CA_ARG_PLAYER_TRIGGER  ? change->actual_trigger_player :
+     action_arg == CA_ARG_ELEMENT_TRIGGER ? change->actual_trigger_element :
+     action_arg == CA_ARG_ELEMENT_TARGET  ? change->target_element :
+     EL_EMPTY);
+
+  int action_arg_direction =
+    (action_arg >= CA_ARG_DIRECTION_LEFT &&
+     action_arg <= CA_ARG_DIRECTION_DOWN ? action_arg - CA_ARG_DIRECTION :
+     action_arg == CA_ARG_DIRECTION_TRIGGER ?
+     change->actual_trigger_side :
+     action_arg == CA_ARG_DIRECTION_TRIGGER_BACK ?
+     MV_DIR_OPPOSITE(change->actual_trigger_side) :
+     MV_NONE);
+
+  int action_arg_number_min =
+    (action_type == CA_SET_PLAYER_SPEED ? STEPSIZE_NOT_MOVING :
+     CA_ARG_MIN);
+
+  int action_arg_number_max =
+    (action_type == CA_SET_PLAYER_SPEED ? STEPSIZE_EVEN_FASTER :
+     action_type == CA_SET_LEVEL_GEMS ? 999 :
+     action_type == CA_SET_LEVEL_TIME ? 9999 :
+     action_type == CA_SET_LEVEL_SCORE ? 99999 :
+     action_type == CA_SET_CE_VALUE ? 9999 :
+     action_type == CA_SET_CE_SCORE ? 9999 :
+     CA_ARG_MAX);
+
+  int action_arg_number_reset =
+    (action_type == CA_SET_PLAYER_SPEED ? level.initial_player_stepsize[0] :
+     action_type == CA_SET_LEVEL_GEMS ? level.gems_needed :
+     action_type == CA_SET_LEVEL_TIME ? level.time :
+     action_type == CA_SET_LEVEL_SCORE ? 0 :
+#if 1
+     action_type == CA_SET_CE_VALUE ? GET_NEW_CE_VALUE(element) :
+#else
+     action_type == CA_SET_CE_VALUE ? ei->custom_value_initial :
+#endif
+     action_type == CA_SET_CE_SCORE ? 0 :
+     0);
+
+  int action_arg_number =
+    (action_arg <= CA_ARG_MAX ? action_arg :
+     action_arg >= CA_ARG_SPEED_NOT_MOVING &&
+     action_arg <= CA_ARG_SPEED_EVEN_FASTER ? (action_arg - CA_ARG_SPEED) :
+     action_arg == CA_ARG_SPEED_RESET ? action_arg_number_reset :
+     action_arg == CA_ARG_NUMBER_MIN ? action_arg_number_min :
+     action_arg == CA_ARG_NUMBER_MAX ? action_arg_number_max :
+     action_arg == CA_ARG_NUMBER_RESET ? action_arg_number_reset :
+#if USE_NEW_CUSTOM_VALUE
+     action_arg == CA_ARG_NUMBER_CE_VALUE ? CustomValue[x][y] :
+#else
+     action_arg == CA_ARG_NUMBER_CE_VALUE ? ei->custom_value_initial :
+#endif
+     action_arg == CA_ARG_NUMBER_CE_SCORE ? ei->collect_score :
+     action_arg == CA_ARG_NUMBER_CE_DELAY ? GET_CE_DELAY_VALUE(change) :
+     action_arg == CA_ARG_NUMBER_LEVEL_TIME ? level_time_value :
+     action_arg == CA_ARG_NUMBER_LEVEL_GEMS ? local_player->gems_still_needed :
+     action_arg == CA_ARG_NUMBER_LEVEL_SCORE ? local_player->score :
+     action_arg == CA_ARG_ELEMENT_CV_TARGET ? GET_NEW_CE_VALUE(target_element):
+     action_arg == CA_ARG_ELEMENT_CV_TRIGGER ? change->actual_trigger_ce_value:
+     action_arg == CA_ARG_ELEMENT_CS_TARGET ? GET_CE_SCORE(target_element) :
+     action_arg == CA_ARG_ELEMENT_CS_TRIGGER ? change->actual_trigger_ce_score:
+     action_arg == CA_ARG_ELEMENT_NR_TARGET  ? change->target_element :
+     action_arg == CA_ARG_ELEMENT_NR_TRIGGER ? change->actual_trigger_element :
+     -1);
+
+  int action_arg_number_old =
+    (action_type == CA_SET_LEVEL_GEMS ? local_player->gems_still_needed :
+     action_type == CA_SET_LEVEL_TIME ? TimeLeft :
+     action_type == CA_SET_LEVEL_SCORE ? local_player->score :
+     action_type == CA_SET_CE_VALUE ? CustomValue[x][y] :
+     action_type == CA_SET_CE_SCORE ? ei->collect_score :
+     0);
+
+  int action_arg_number_new =
+    getModifiedActionNumber(action_arg_number_old,
+                           action_mode, action_arg_number,
+                           action_arg_number_min, action_arg_number_max);
+
+  int trigger_player_bits =
+    (change->actual_trigger_player >= EL_PLAYER_1 &&
+     change->actual_trigger_player <= EL_PLAYER_4 ?
+     (1 << (change->actual_trigger_player - EL_PLAYER_1)) :
+     PLAYER_BITS_ANY);
+
+  int action_arg_player_bits =
+    (action_arg >= CA_ARG_PLAYER_1 &&
+     action_arg <= CA_ARG_PLAYER_4 ? action_arg - CA_ARG_PLAYER :
+     action_arg == CA_ARG_PLAYER_TRIGGER ? trigger_player_bits :
+     PLAYER_BITS_ANY);
+
+  /* ---------- execute action  -------------------------------------------- */
+
+  switch(action_type)
+  {
+    case CA_NO_ACTION:
+    {
+      return;
+    }
 
-    Feld[x][y] = target_element;
-#else
-    RemoveField(x, y);
-    Feld[x][y] = target_element;
-#endif
+    /* ---------- level actions  ------------------------------------------- */
 
-    ResetGfxAnimation(x, y);
-    ResetRandomAnimationValue(x, y);
+    case CA_RESTART_LEVEL:
+    {
+      game.restart_level = TRUE;
 
-    if (element_info[Feld[x][y]].move_direction_initial == MV_START_PREVIOUS)
-      MovDir[x][y] = previous_move_direction;
+      break;
+    }
 
-#if 1
-    InitField_WithBug1(x, y, FALSE);
-#else
-    InitField(x, y, FALSE);
-    if (CAN_MOVE(Feld[x][y]))
-      InitMovDir(x, y);
-#endif
+    case CA_SHOW_ENVELOPE:
+    {
+      int element = getSpecialActionElement(action_arg_element,
+                                           action_arg_number, EL_ENVELOPE_1);
 
-    DrawLevelField(x, y);
+      if (IS_ENVELOPE(element))
+       local_player->show_envelope = element;
 
-    if (GFX_CRUMBLED(Feld[x][y]))
-      DrawLevelFieldCrumbledSandNeighbours(x, y);
-  }
+      break;
+    }
 
-#if 0
-  Changed[x][y] |= ChangeEvent[x][y];  /* ignore same changes in this frame */
-#endif
+    case CA_SET_LEVEL_TIME:
+    {
+      if (level.time > 0)      /* only modify limited time value */
+      {
+       TimeLeft = action_arg_number_new;
 
-#if 0
-  TestIfBadThingTouchesHero(x, y);
-  TestIfPlayerTouchesCustomElement(x, y);
-  TestIfElementTouchesCustomElement(x, y);
-#endif
+       DrawGameValue_Time(TimeLeft);
 
-  /* "Changed[][]" not set yet to allow "entered by player" change one time */
-  if (ELEM_IS_PLAYER(target_element))
-    RelocatePlayer(x, y, target_element);
+       if (!TimeLeft && setup.time_limit)
+         for (i = 0; i < MAX_PLAYERS; i++)
+           KillPlayer(&stored_player[i]);
+      }
 
-#if 1
-  Changed[x][y] = TRUE;                /* ignore all further changes in this frame */
-#else
-  Changed[x][y] |= ChangeEvent[x][y];  /* ignore same changes in this frame */
-#endif
+      break;
+    }
 
-#if 1
-  TestIfBadThingTouchesHero(x, y);
-  TestIfPlayerTouchesCustomElement(x, y);
-  TestIfElementTouchesCustomElement(x, y);
-#endif
-}
+    case CA_SET_LEVEL_SCORE:
+    {
+      local_player->score = action_arg_number_new;
 
-static boolean ChangeElementNow(int x, int y, int element, int page)
-{
-  struct ElementChangeInfo *change = &element_info[element].change_page[page];
-  int target_element;
-  int old_element = Feld[x][y];
+      DrawGameValue_Score(local_player->score);
 
-  /* always use default change event to prevent running into a loop */
-  if (ChangeEvent[x][y] == -1)
-    ChangeEvent[x][y] = CE_DELAY;
+      break;
+    }
 
-  if (ChangeEvent[x][y] == CE_DELAY)
-  {
-    /* reset actual trigger element and player */
-    change->actual_trigger_element = EL_EMPTY;
-    change->actual_trigger_player = EL_PLAYER_1;
-  }
+    case CA_SET_LEVEL_GEMS:
+    {
+      local_player->gems_still_needed = action_arg_number_new;
 
-#if 1
-  /* do not change any elements that have already changed in this frame */
-  if (Changed[x][y])
-    return FALSE;
-#else
-  /* do not change already changed elements with same change event */
-  if (Changed[x][y] & ChangeEvent[x][y])
-    return FALSE;
-#endif
+      DrawGameValue_Emeralds(local_player->gems_still_needed);
 
-#if 1
-  Changed[x][y] = TRUE;                /* ignore all further changes in this frame */
-#else
-  Changed[x][y] |= ChangeEvent[x][y];  /* ignore same changes in this frame */
-#endif
+      break;
+    }
 
-#if 0
-  /* !!! indirect change before direct change !!! */
-  CheckTriggeredElementChangeByPage(x, y, Feld[x][y], CE_CHANGE_OF_X, page);
+#if !USE_PLAYER_GRAVITY
+    case CA_SET_LEVEL_GRAVITY:
+    {
+      game.gravity = (action_arg == CA_ARG_GRAVITY_OFF    ? FALSE         :
+                     action_arg == CA_ARG_GRAVITY_ON     ? TRUE          :
+                     action_arg == CA_ARG_GRAVITY_TOGGLE ? !game.gravity :
+                     game.gravity);
+      break;
+    }
 #endif
 
-  if (change->explode)
-  {
-    Bang(x, y);
+    case CA_SET_LEVEL_WIND:
+    {
+      game.wind_direction = action_arg_direction;
 
-    return TRUE;
-  }
+      break;
+    }
 
-  if (change->use_target_content)
-  {
-    boolean complete_replace = TRUE;
-    boolean can_replace[3][3];
-    int xx, yy;
+    /* ---------- player actions  ------------------------------------------ */
 
-    for (yy = 0; yy < 3; yy++) for (xx = 0; xx < 3 ; xx++)
+    case CA_MOVE_PLAYER:
     {
-      boolean is_empty;
-      boolean is_walkable;
-      boolean is_diggable;
-      boolean is_collectible;
-      boolean is_removable;
-      boolean is_destructible;
-      int ex = x + xx - 1;
-      int ey = y + yy - 1;
-      int content_element = change->target_content[xx][yy];
-      int e;
+      /* automatically move to the next field in specified direction */
+      for (i = 0; i < MAX_PLAYERS; i++)
+       if (trigger_player_bits & (1 << i))
+         stored_player[i].programmed_action = action_arg_direction;
 
-      can_replace[xx][yy] = TRUE;
+      break;
+    }
 
-      if (ex == x && ey == y)  /* do not check changing element itself */
-       continue;
+    case CA_EXIT_PLAYER:
+    {
+      for (i = 0; i < MAX_PLAYERS; i++)
+       if (action_arg_player_bits & (1 << i))
+         stored_player[i].LevelSolved = stored_player[i].GameOver = TRUE;
 
-      if (content_element == EL_EMPTY_SPACE)
-      {
-       can_replace[xx][yy] = FALSE;    /* do not replace border with space */
+      break;
+    }
 
-       continue;
-      }
+    case CA_KILL_PLAYER:
+    {
+      for (i = 0; i < MAX_PLAYERS; i++)
+       if (action_arg_player_bits & (1 << i))
+         KillPlayer(&stored_player[i]);
 
-      if (!IN_LEV_FIELD(ex, ey))
-      {
-       can_replace[xx][yy] = FALSE;
-       complete_replace = FALSE;
+      break;
+    }
 
-       continue;
-      }
+    case CA_SET_PLAYER_KEYS:
+    {
+      int key_state = (action_mode == CA_MODE_ADD ? TRUE : FALSE);
+      int element = getSpecialActionElement(action_arg_element,
+                                           action_arg_number, EL_KEY_1);
 
-#if 0
-      if (Changed[ex][ey])     /* do not change already changed elements */
+      if (IS_KEY(element))
       {
-       can_replace[xx][yy] = FALSE;
-       complete_replace = FALSE;
-
-       continue;
-      }
-#endif
-
-      e = Feld[ex][ey];
-
-      if (IS_MOVING(ex, ey) || IS_BLOCKED(ex, ey))
-       e = MovingOrBlocked2Element(ex, ey);
+       for (i = 0; i < MAX_PLAYERS; i++)
+       {
+         if (trigger_player_bits & (1 << i))
+         {
+           stored_player[i].key[KEY_NR(element)] = key_state;
 
 #if 1
-
-#if 0
-      is_empty = (IS_FREE(ex, ey) ||
-                 (IS_PLAYER(ex, ey) && IS_WALKABLE(content_element)) ||
-                 (IS_WALKABLE(e) && ELEM_IS_PLAYER(content_element) &&
-                  !IS_MOVING(ex, ey) && !IS_BLOCKED(ex, ey)));
+           DrawGameDoorValues();
 #else
-
-#if 0
-      is_empty = (IS_FREE(ex, ey) ||
-                 (IS_PLAYER(ex, ey) && IS_WALKABLE(content_element)));
-#else
-      is_empty = (IS_FREE(ex, ey) ||
-                 (IS_FREE_OR_PLAYER(ex, ey) && IS_WALKABLE(content_element)));
+           DrawGameValue_Keys(stored_player[i].key);
 #endif
 
-#endif
+           redraw_mask |= REDRAW_DOOR_1;
+         }
+       }
+      }
 
-      is_walkable     = (is_empty || IS_WALKABLE(e));
-      is_diggable     = (is_empty || IS_DIGGABLE(e));
-      is_collectible  = (is_empty || IS_COLLECTIBLE(e));
-      is_destructible = (is_empty || !IS_INDESTRUCTIBLE(e));
-      is_removable    = (is_diggable || is_collectible);
+      break;
+    }
 
-      can_replace[xx][yy] =
-       (((change->replace_when == CP_WHEN_EMPTY        && is_empty) ||
-         (change->replace_when == CP_WHEN_WALKABLE     && is_walkable) ||
-         (change->replace_when == CP_WHEN_DIGGABLE     && is_diggable) ||
-         (change->replace_when == CP_WHEN_COLLECTIBLE  && is_collectible) ||
-         (change->replace_when == CP_WHEN_REMOVABLE    && is_removable) ||
-         (change->replace_when == CP_WHEN_DESTRUCTIBLE && is_destructible)) &&
-        !(IS_PLAYER(ex, ey) && ELEM_IS_PLAYER(content_element)));
+    case CA_SET_PLAYER_SPEED:
+    {
+      for (i = 0; i < MAX_PLAYERS; i++)
+      {
+       if (trigger_player_bits & (1 << i))
+       {
+         int move_stepsize = TILEX / stored_player[i].move_delay_value;
+
+         if (action_arg == CA_ARG_SPEED_FASTER &&
+             stored_player[i].cannot_move)
+         {
+           action_arg_number = STEPSIZE_VERY_SLOW;
+         }
+         else if (action_arg == CA_ARG_SPEED_SLOWER ||
+                  action_arg == CA_ARG_SPEED_FASTER)
+         {
+           action_arg_number = 2;
+           action_mode = (action_arg == CA_ARG_SPEED_SLOWER ? CA_MODE_DIVIDE :
+                          CA_MODE_MULTIPLY);
+         }
+         else if (action_arg == CA_ARG_NUMBER_RESET)
+         {
+           action_arg_number = level.initial_player_stepsize[i];
+         }
+
+         move_stepsize =
+           getModifiedActionNumber(move_stepsize,
+                                   action_mode,
+                                   action_arg_number,
+                                   action_arg_number_min,
+                                   action_arg_number_max);
 
-      if (!can_replace[xx][yy])
-       complete_replace = FALSE;
-#else
-      empty_for_element = (IS_FREE(ex, ey) || (IS_FREE_OR_PLAYER(ex, ey) &&
-                                              IS_WALKABLE(content_element)));
 #if 1
-      half_destructible = (empty_for_element || IS_DIGGABLE(e));
+         SetPlayerMoveSpeed(&stored_player[i], move_stepsize, FALSE);
 #else
-      half_destructible = (IS_FREE(ex, ey) || IS_DIGGABLE(e));
+         /* make sure that value is power of 2 */
+         move_stepsize = (1 << log_2(move_stepsize));
+
+         /* do no immediately change -- the player might just be moving */
+         stored_player[i].move_delay_value_next = TILEX / move_stepsize;
+
+         stored_player[i].cannot_move =
+           (action_arg == CA_ARG_SPEED_NOT_MOVING ? TRUE : FALSE);
 #endif
+       }
+      }
 
-      if ((change->replace_when <= CP_WHEN_EMPTY  && !empty_for_element) ||
-         (change->replace_when <= CP_WHEN_DIGGABLE && !half_destructible) ||
-         (change->replace_when <= CP_WHEN_DESTRUCTIBLE && IS_INDESTRUCTIBLE(e)))
+      break;
+    }
+
+    case CA_SET_PLAYER_SHIELD:
+    {
+      for (i = 0; i < MAX_PLAYERS; i++)
       {
-       can_replace[xx][yy] = FALSE;
-       complete_replace = FALSE;
+       if (trigger_player_bits & (1 << i))
+       {
+         if (action_arg == CA_ARG_SHIELD_OFF)
+         {
+           stored_player[i].shield_normal_time_left = 0;
+           stored_player[i].shield_deadly_time_left = 0;
+         }
+         else if (action_arg == CA_ARG_SHIELD_NORMAL)
+         {
+           stored_player[i].shield_normal_time_left = 999999;
+         }
+         else if (action_arg == CA_ARG_SHIELD_DEADLY)
+         {
+           stored_player[i].shield_normal_time_left = 999999;
+           stored_player[i].shield_deadly_time_left = 999999;
+         }
+       }
       }
-#endif
+
+      break;
     }
 
-    if (!change->only_if_complete || complete_replace)
+#if USE_PLAYER_GRAVITY
+    case CA_SET_PLAYER_GRAVITY:
     {
-      boolean something_has_changed = FALSE;
+      for (i = 0; i < MAX_PLAYERS; i++)
+      {
+       if (trigger_player_bits & (1 << i))
+       {
+         stored_player[i].gravity =
+           (action_arg == CA_ARG_GRAVITY_OFF    ? FALSE                     :
+            action_arg == CA_ARG_GRAVITY_ON     ? TRUE                      :
+            action_arg == CA_ARG_GRAVITY_TOGGLE ? !stored_player[i].gravity :
+            stored_player[i].gravity);
+       }
+      }
 
-      if (change->only_if_complete && change->use_random_replace &&
-         RND(100) < change->random_percentage)
-       return FALSE;
+      break;
+    }
+#endif
 
-      for (yy = 0; yy < 3; yy++) for (xx = 0; xx < 3 ; xx++)
+    case CA_SET_PLAYER_ARTWORK:
+    {
+      for (i = 0; i < MAX_PLAYERS; i++)
       {
-       int ex = x + xx - 1;
-       int ey = y + yy - 1;
-       int content_element;
-
-       if (can_replace[xx][yy] && (!change->use_random_replace ||
-                                   RND(100) < change->random_percentage))
+       if (trigger_player_bits & (1 << i))
        {
-         if (IS_MOVING(ex, ey) || IS_BLOCKED(ex, ey))
-           RemoveMovingField(ex, ey);
-
-         ChangeEvent[ex][ey] = ChangeEvent[x][y];
+         int artwork_element = action_arg_element;
 
-         content_element = change->target_content[xx][yy];
-         target_element = GET_TARGET_ELEMENT(content_element, change);
+         if (action_arg == CA_ARG_ELEMENT_RESET)
+           artwork_element =
+             (level.use_artwork_element[i] ? level.artwork_element[i] :
+              stored_player[i].element_nr);
 
-         ChangeElementNowExt(ex, ey, target_element);
+         stored_player[i].artwork_element = artwork_element;
 
-         something_has_changed = TRUE;
+         SetPlayerWaiting(&stored_player[i], FALSE);
 
-         /* for symmetry reasons, freeze newly created border elements */
-         if (ex != x || ey != y)
-           Stop[ex][ey] = TRUE;        /* no more moving in this frame */
+         /* set number of special actions for bored and sleeping animation */
+         stored_player[i].num_special_action_bored =
+           get_num_special_action(artwork_element,
+                                  ACTION_BORING_1, ACTION_BORING_LAST);
+         stored_player[i].num_special_action_sleeping =
+           get_num_special_action(artwork_element,
+                                  ACTION_SLEEPING_1, ACTION_SLEEPING_LAST);
        }
       }
 
-      if (something_has_changed)
-       PlayLevelSoundElementAction(x, y, element, ACTION_CHANGING);
+      break;
     }
-  }
-  else
-  {
-    target_element = GET_TARGET_ELEMENT(change->target_element, change);
 
-    ChangeElementNowExt(x, y, target_element);
+    /* ---------- CE actions  ---------------------------------------------- */
 
-    PlayLevelSoundElementAction(x, y, element, ACTION_CHANGING);
-  }
+    case CA_SET_CE_VALUE:
+    {
+#if USE_NEW_CUSTOM_VALUE
+      int last_ce_value = CustomValue[x][y];
 
-#if 1
-  /* this uses direct change before indirect change */
-  CheckTriggeredElementChangeByPage(x, y, old_element, CE_CHANGE_OF_X, page);
-#endif
+      CustomValue[x][y] = action_arg_number_new;
 
-  return TRUE;
-}
+#if 0
+      printf("::: CE value == %d\n", CustomValue[x][y]);
+#endif
 
-static void ChangeElement(int x, int y, int page)
-{
-  int element = MovingOrBlocked2Element(x, y);
-  struct ElementInfo *ei = &element_info[element];
-  struct ElementChangeInfo *change = &ei->change_page[page];
+      if (CustomValue[x][y] != last_ce_value)
+      {
+       CheckElementChange(x, y, element, EL_UNDEFINED, CE_VALUE_CHANGES);
+       CheckTriggeredElementChange(x, y, element, CE_VALUE_CHANGES_OF_X);
 
-#ifdef DEBUG
-  if (!CAN_CHANGE(element) && !CAN_CHANGE(Back[x][y]))
-  {
-    printf("\n\n");
-    printf("ChangeElement(): %d,%d: element = %d ('%s')\n",
-          x, y, element, element_info[element].token_name);
-    printf("ChangeElement(): This should never happen!\n");
-    printf("\n\n");
-  }
+       if (CustomValue[x][y] == 0)
+       {
+#if 0
+         printf("::: CE_VALUE_GETS_ZERO\n");
 #endif
 
-  /* this can happen with classic bombs on walkable, changing elements */
-  if (!CAN_CHANGE(element))
-  {
+         CheckElementChange(x, y, element, EL_UNDEFINED, CE_VALUE_GETS_ZERO);
+         CheckTriggeredElementChange(x, y, element, CE_VALUE_GETS_ZERO_OF_X);
+
 #if 0
-    if (!CAN_CHANGE(Back[x][y]))       /* prevent permanent repetition */
-      ChangeDelay[x][y] = 0;
+         printf("::: RESULT: %d, %d\n", Feld[x][y], ChangePage[x][y]);
 #endif
+       }
+      }
 
-    return;
-  }
-
-  if (ChangeDelay[x][y] == 0)          /* initialize element change */
-  {
-    ChangeDelay[x][y] = (    change->delay_fixed  * change->delay_frames +
-                        RND(change->delay_random * change->delay_frames)) + 1;
+#endif
 
-    ResetGfxAnimation(x, y);
-    ResetRandomAnimationValue(x, y);
+      break;
+    }
 
-    if (change->pre_change_function)
-      change->pre_change_function(x, y);
-  }
+    case CA_SET_CE_SCORE:
+    {
+#if USE_NEW_CUSTOM_VALUE
+      int last_ce_score = ei->collect_score;
 
-  ChangeDelay[x][y]--;
+      ei->collect_score = action_arg_number_new;
 
-  if (ChangeDelay[x][y] != 0)          /* continue element change */
-  {
-    int graphic = el_act_dir2img(element, GfxAction[x][y], GfxDir[x][y]);
+#if 0
+      printf("::: CE score == %d\n", ei->collect_score);
+#endif
 
-    if (IS_ANIMATED(graphic))
-      DrawLevelGraphicAnimationIfNeeded(x, y, graphic);
+      if (ei->collect_score != last_ce_score)
+      {
+       CheckElementChange(x, y, element, EL_UNDEFINED, CE_SCORE_CHANGES);
+       CheckTriggeredElementChange(x, y, element, CE_SCORE_CHANGES_OF_X);
 
-    if (change->change_function)
-      change->change_function(x, y);
-  }
-  else                                 /* finish element change */
-  {
-    if (ChangePage[x][y] != -1)                /* remember page from delayed change */
-    {
-      page = ChangePage[x][y];
-      ChangePage[x][y] = -1;
+       if (ei->collect_score == 0)
+       {
+#if 0
+         printf("::: CE_SCORE_GETS_ZERO\n");
+#endif
 
-      change = &ei->change_page[page];
-    }
+         CheckElementChange(x, y, element, EL_UNDEFINED, CE_SCORE_GETS_ZERO);
+         CheckTriggeredElementChange(x, y, element, CE_SCORE_GETS_ZERO_OF_X);
 
 #if 0
-    if (IS_MOVING(x, y) && !change->explode)
-#else
-    if (IS_MOVING(x, y))               /* never change a running system ;-) */
+         printf("::: RESULT: %d, %d\n", Feld[x][y], ChangePage[x][y]);
 #endif
-    {
-      ChangeDelay[x][y] = 1;           /* try change after next move step */
-      ChangePage[x][y] = page;         /* remember page to use for change */
+       }
+      }
 
-      return;
+#endif
+
+      break;
     }
 
-    if (ChangeElementNow(x, y, element, page))
+    /* ---------- engine actions  ------------------------------------------ */
+
+    case CA_SET_ENGINE_SCAN_MODE:
     {
-      if (change->post_change_function)
-       change->post_change_function(x, y);
+      InitPlayfieldScanMode(action_arg);
+
+      break;
     }
+
+    default:
+      break;
   }
 }
 
-static boolean CheckTriggeredElementChangeExt(int lx, int ly,
-                                             int trigger_element,
-                                             int trigger_event,
-                                             int trigger_player,
-                                             int trigger_side,
-                                             int trigger_page)
+static void CreateFieldExt(int x, int y, int element, boolean is_change)
 {
-  int i, j, x, y;
-  int trigger_page_bits = (trigger_page < 0 ? CH_PAGE_ANY : 1 << trigger_page);
-
-  if (!(trigger_events[trigger_element][trigger_event]))
-    return FALSE;
+  int old_element = Feld[x][y];
+  int new_element = get_element_from_group_element(element);
+  int previous_move_direction = MovDir[x][y];
+#if USE_NEW_CUSTOM_VALUE
+  int last_ce_value = CustomValue[x][y];
+#endif
+  boolean new_element_is_player = ELEM_IS_PLAYER(new_element);
+  boolean add_player_onto_element = (new_element_is_player &&
+                                    new_element != EL_SOKOBAN_FIELD_PLAYER &&
+                                    IS_WALKABLE(old_element));
+
+#if 0
+  /* check if element under the player changes from accessible to unaccessible
+     (needed for special case of dropping element which then changes) */
+  if (IS_PLAYER(x, y) && !PLAYER_EXPLOSION_PROTECTED(x, y) &&
+      IS_ACCESSIBLE(old_element) && !IS_ACCESSIBLE(new_element))
+  {
+    Bang(x, y);
+
+    return;
+  }
+#endif
+
+  if (!add_player_onto_element)
+  {
+    if (IS_MOVING(x, y) || IS_BLOCKED(x, y))
+      RemoveMovingField(x, y);
+    else
+      RemoveField(x, y);
+
+    Feld[x][y] = new_element;
+
+#if !USE_GFX_RESET_GFX_ANIMATION
+    ResetGfxAnimation(x, y);
+    ResetRandomAnimationValue(x, y);
+#endif
+
+    if (element_info[new_element].move_direction_initial == MV_START_PREVIOUS)
+      MovDir[x][y] = previous_move_direction;
+
+#if USE_NEW_CUSTOM_VALUE
+    if (element_info[new_element].use_last_ce_value)
+      CustomValue[x][y] = last_ce_value;
+#endif
+
+    InitField_WithBug1(x, y, FALSE);
+
+    new_element = Feld[x][y];  /* element may have changed */
+
+#if USE_GFX_RESET_GFX_ANIMATION
+    ResetGfxAnimation(x, y);
+    ResetRandomAnimationValue(x, y);
+#endif
+
+    DrawLevelField(x, y);
+
+    if (GFX_CRUMBLED(new_element))
+      DrawLevelFieldCrumbledSandNeighbours(x, y);
+  }
+
+#if 1
+  /* check if element under the player changes from accessible to unaccessible
+     (needed for special case of dropping element which then changes) */
+  /* (must be checked after creating new element for walkable group elements) */
+  if (IS_PLAYER(x, y) && !PLAYER_EXPLOSION_PROTECTED(x, y) &&
+      IS_ACCESSIBLE(old_element) && !IS_ACCESSIBLE(new_element))
+  {
+    Bang(x, y);
+
+    return;
+  }
+#endif
+
+  /* "ChangeCount" not set yet to allow "entered by player" change one time */
+  if (new_element_is_player)
+    RelocatePlayer(x, y, new_element);
+
+  if (is_change)
+    ChangeCount[x][y]++;       /* count number of changes in the same frame */
+
+  TestIfBadThingTouchesPlayer(x, y);
+  TestIfPlayerTouchesCustomElement(x, y);
+  TestIfElementTouchesCustomElement(x, y);
+}
+
+static void CreateField(int x, int y, int element)
+{
+  CreateFieldExt(x, y, element, FALSE);
+}
+
+static void CreateElementFromChange(int x, int y, int element)
+{
+  element = GET_VALID_RUNTIME_ELEMENT(element);
+
+#if USE_STOP_CHANGED_ELEMENTS
+  if (game.engine_version >= VERSION_IDENT(3,2,0,7))
+  {
+    int old_element = Feld[x][y];
+
+    /* prevent changed element from moving in same engine frame
+       unless both old and new element can either fall or move */
+    if ((!CAN_FALL(old_element) || !CAN_FALL(element)) &&
+       (!CAN_MOVE(old_element) || !CAN_MOVE(element)))
+      Stop[x][y] = TRUE;
+  }
+#endif
+
+  CreateFieldExt(x, y, element, TRUE);
+}
+
+static boolean ChangeElement(int x, int y, int element, int page)
+{
+  struct ElementInfo *ei = &element_info[element];
+  struct ElementChangeInfo *change = &ei->change_page[page];
+  int ce_value = CustomValue[x][y];
+  int ce_score = ei->collect_score;
+  int target_element;
+  int old_element = Feld[x][y];
+
+  /* always use default change event to prevent running into a loop */
+  if (ChangeEvent[x][y] == -1)
+    ChangeEvent[x][y] = CE_DELAY;
+
+  if (ChangeEvent[x][y] == CE_DELAY)
+  {
+    /* reset actual trigger element, trigger player and action element */
+    change->actual_trigger_element = EL_EMPTY;
+    change->actual_trigger_player = EL_PLAYER_1;
+    change->actual_trigger_side = CH_SIDE_NONE;
+    change->actual_trigger_ce_value = 0;
+    change->actual_trigger_ce_score = 0;
+  }
+
+  /* do not change elements more than a specified maximum number of changes */
+  if (ChangeCount[x][y] >= game.max_num_changes_per_frame)
+    return FALSE;
+
+  ChangeCount[x][y]++;         /* count number of changes in the same frame */
+
+  if (change->explode)
+  {
+    Bang(x, y);
+
+    return TRUE;
+  }
+
+  if (change->use_target_content)
+  {
+    boolean complete_replace = TRUE;
+    boolean can_replace[3][3];
+    int xx, yy;
+
+    for (yy = 0; yy < 3; yy++) for (xx = 0; xx < 3 ; xx++)
+    {
+      boolean is_empty;
+      boolean is_walkable;
+      boolean is_diggable;
+      boolean is_collectible;
+      boolean is_removable;
+      boolean is_destructible;
+      int ex = x + xx - 1;
+      int ey = y + yy - 1;
+      int content_element = change->target_content.e[xx][yy];
+      int e;
+
+      can_replace[xx][yy] = TRUE;
+
+      if (ex == x && ey == y)  /* do not check changing element itself */
+       continue;
+
+      if (content_element == EL_EMPTY_SPACE)
+      {
+       can_replace[xx][yy] = FALSE;    /* do not replace border with space */
+
+       continue;
+      }
+
+      if (!IN_LEV_FIELD(ex, ey))
+      {
+       can_replace[xx][yy] = FALSE;
+       complete_replace = FALSE;
+
+       continue;
+      }
+
+      e = Feld[ex][ey];
+
+      if (IS_MOVING(ex, ey) || IS_BLOCKED(ex, ey))
+       e = MovingOrBlocked2Element(ex, ey);
+
+      is_empty = (IS_FREE(ex, ey) ||
+                 (IS_FREE_OR_PLAYER(ex, ey) && IS_WALKABLE(content_element)));
+
+      is_walkable     = (is_empty || IS_WALKABLE(e));
+      is_diggable     = (is_empty || IS_DIGGABLE(e));
+      is_collectible  = (is_empty || IS_COLLECTIBLE(e));
+      is_destructible = (is_empty || !IS_INDESTRUCTIBLE(e));
+      is_removable    = (is_diggable || is_collectible);
+
+      can_replace[xx][yy] =
+       (((change->replace_when == CP_WHEN_EMPTY        && is_empty) ||
+         (change->replace_when == CP_WHEN_WALKABLE     && is_walkable) ||
+         (change->replace_when == CP_WHEN_DIGGABLE     && is_diggable) ||
+         (change->replace_when == CP_WHEN_COLLECTIBLE  && is_collectible) ||
+         (change->replace_when == CP_WHEN_REMOVABLE    && is_removable) ||
+         (change->replace_when == CP_WHEN_DESTRUCTIBLE && is_destructible)) &&
+        !(IS_PLAYER(ex, ey) && ELEM_IS_PLAYER(content_element)));
+
+      if (!can_replace[xx][yy])
+       complete_replace = FALSE;
+    }
+
+    if (!change->only_if_complete || complete_replace)
+    {
+      boolean something_has_changed = FALSE;
+
+      if (change->only_if_complete && change->use_random_replace &&
+         RND(100) < change->random_percentage)
+       return FALSE;
+
+      for (yy = 0; yy < 3; yy++) for (xx = 0; xx < 3 ; xx++)
+      {
+       int ex = x + xx - 1;
+       int ey = y + yy - 1;
+       int content_element;
+
+       if (can_replace[xx][yy] && (!change->use_random_replace ||
+                                   RND(100) < change->random_percentage))
+       {
+         if (IS_MOVING(ex, ey) || IS_BLOCKED(ex, ey))
+           RemoveMovingField(ex, ey);
+
+         ChangeEvent[ex][ey] = ChangeEvent[x][y];
+
+         content_element = change->target_content.e[xx][yy];
+         target_element = GET_TARGET_ELEMENT(content_element, change,
+                                             ce_value, ce_score);
+
+         CreateElementFromChange(ex, ey, target_element);
+
+         something_has_changed = TRUE;
+
+         /* for symmetry reasons, freeze newly created border elements */
+         if (ex != x || ey != y)
+           Stop[ex][ey] = TRUE;        /* no more moving in this frame */
+       }
+      }
+
+      if (something_has_changed)
+      {
+       PlayLevelSoundElementAction(x, y, element, ACTION_CHANGING);
+       PlayLevelSoundElementAction(x, y, element, ACTION_PAGE_1 + page);
+      }
+    }
+  }
+  else
+  {
+    target_element = GET_TARGET_ELEMENT(change->target_element, change,
+                                       ce_value, ce_score);
+
+    if (element == EL_DIAGONAL_GROWING ||
+       element == EL_DIAGONAL_SHRINKING)
+    {
+      target_element = Store[x][y];
+
+      Store[x][y] = EL_EMPTY;
+    }
+
+    CreateElementFromChange(x, y, target_element);
+
+    PlayLevelSoundElementAction(x, y, element, ACTION_CHANGING);
+    PlayLevelSoundElementAction(x, y, element, ACTION_PAGE_1 + page);
+  }
+
+  /* this uses direct change before indirect change */
+  CheckTriggeredElementChangeByPage(x, y, old_element, CE_CHANGE_OF_X, page);
+
+  return TRUE;
+}
+
+#if USE_NEW_DELAYED_ACTION
+
+static void HandleElementChange(int x, int y, int page)
+{
+  int element = MovingOrBlocked2Element(x, y);
+  struct ElementInfo *ei = &element_info[element];
+  struct ElementChangeInfo *change = &ei->change_page[page];
+
+#ifdef DEBUG
+  if (!CAN_CHANGE_OR_HAS_ACTION(element) &&
+      !CAN_CHANGE_OR_HAS_ACTION(Back[x][y]))
+  {
+    printf("\n\n");
+    printf("HandleElementChange(): %d,%d: element = %d ('%s')\n",
+          x, y, element, element_info[element].token_name);
+    printf("HandleElementChange(): This should never happen!\n");
+    printf("\n\n");
+  }
+#endif
+
+  /* this can happen with classic bombs on walkable, changing elements */
+  if (!CAN_CHANGE_OR_HAS_ACTION(element))
+  {
+#if 0
+    if (!CAN_CHANGE(Back[x][y]))       /* prevent permanent repetition */
+      ChangeDelay[x][y] = 0;
+#endif
+
+    return;
+  }
+
+  if (ChangeDelay[x][y] == 0)          /* initialize element change */
+  {
+    ChangeDelay[x][y] = GET_CHANGE_DELAY(change) + 1;
+
+    if (change->can_change)
+    {
+      ResetGfxAnimation(x, y);
+      ResetRandomAnimationValue(x, y);
+
+      if (change->pre_change_function)
+       change->pre_change_function(x, y);
+    }
+  }
+
+  ChangeDelay[x][y]--;
+
+  if (ChangeDelay[x][y] != 0)          /* continue element change */
+  {
+    if (change->can_change)
+    {
+      int graphic = el_act_dir2img(element, GfxAction[x][y], GfxDir[x][y]);
+
+      if (IS_ANIMATED(graphic))
+       DrawLevelGraphicAnimationIfNeeded(x, y, graphic);
+
+      if (change->change_function)
+       change->change_function(x, y);
+    }
+  }
+  else                                 /* finish element change */
+  {
+    if (ChangePage[x][y] != -1)                /* remember page from delayed change */
+    {
+      page = ChangePage[x][y];
+      ChangePage[x][y] = -1;
+
+      change = &ei->change_page[page];
+    }
+
+    if (IS_MOVING(x, y))               /* never change a running system ;-) */
+    {
+      ChangeDelay[x][y] = 1;           /* try change after next move step */
+      ChangePage[x][y] = page;         /* remember page to use for change */
+
+      return;
+    }
+
+    if (change->can_change)
+    {
+      if (ChangeElement(x, y, element, page))
+      {
+       if (change->post_change_function)
+         change->post_change_function(x, y);
+      }
+    }
+
+    if (change->has_action)
+      ExecuteCustomElementAction(x, y, element, page);
+  }
+}
+
+#else
+
+static void HandleElementChange(int x, int y, int page)
+{
+  int element = MovingOrBlocked2Element(x, y);
+  struct ElementInfo *ei = &element_info[element];
+  struct ElementChangeInfo *change = &ei->change_page[page];
+
+#ifdef DEBUG
+  if (!CAN_CHANGE(element) && !CAN_CHANGE(Back[x][y]))
+  {
+    printf("\n\n");
+    printf("HandleElementChange(): %d,%d: element = %d ('%s')\n",
+          x, y, element, element_info[element].token_name);
+    printf("HandleElementChange(): This should never happen!\n");
+    printf("\n\n");
+  }
+#endif
+
+  /* this can happen with classic bombs on walkable, changing elements */
+  if (!CAN_CHANGE(element))
+  {
+#if 0
+    if (!CAN_CHANGE(Back[x][y]))       /* prevent permanent repetition */
+      ChangeDelay[x][y] = 0;
+#endif
+
+    return;
+  }
+
+  if (ChangeDelay[x][y] == 0)          /* initialize element change */
+  {
+    ChangeDelay[x][y] = GET_CHANGE_DELAY(change) + 1;
+
+    ResetGfxAnimation(x, y);
+    ResetRandomAnimationValue(x, y);
+
+    if (change->pre_change_function)
+      change->pre_change_function(x, y);
+  }
+
+  ChangeDelay[x][y]--;
+
+  if (ChangeDelay[x][y] != 0)          /* continue element change */
+  {
+    int graphic = el_act_dir2img(element, GfxAction[x][y], GfxDir[x][y]);
+
+    if (IS_ANIMATED(graphic))
+      DrawLevelGraphicAnimationIfNeeded(x, y, graphic);
+
+    if (change->change_function)
+      change->change_function(x, y);
+  }
+  else                                 /* finish element change */
+  {
+    if (ChangePage[x][y] != -1)                /* remember page from delayed change */
+    {
+      page = ChangePage[x][y];
+      ChangePage[x][y] = -1;
+
+      change = &ei->change_page[page];
+    }
+
+    if (IS_MOVING(x, y))               /* never change a running system ;-) */
+    {
+      ChangeDelay[x][y] = 1;           /* try change after next move step */
+      ChangePage[x][y] = page;         /* remember page to use for change */
+
+      return;
+    }
+
+    if (ChangeElement(x, y, element, page))
+    {
+      if (change->post_change_function)
+       change->post_change_function(x, y);
+    }
+  }
+}
+
+#endif
+
+static boolean CheckTriggeredElementChangeExt(int trigger_x, int trigger_y,
+                                             int trigger_element,
+                                             int trigger_event,
+                                             int trigger_player,
+                                             int trigger_side,
+                                             int trigger_page)
+{
+  boolean change_done_any = FALSE;
+  int trigger_page_bits = (trigger_page < 0 ? CH_PAGE_ANY : 1 << trigger_page);
+  int i;
+
+  if (!(trigger_events[trigger_element][trigger_event]))
+    return FALSE;
 
   for (i = 0; i < NUM_CUSTOM_ELEMENTS; i++)
   {
     int element = EL_CUSTOM_START + i;
+    boolean change_done = FALSE;
+    int p;
 
-    boolean change_element = FALSE;
-    int page = 0;
-
-    if (!CAN_CHANGE(element) || !HAS_ANY_CHANGE_EVENT(element, trigger_event))
+    if (!CAN_CHANGE_OR_HAS_ACTION(element) ||
+       !HAS_ANY_CHANGE_EVENT(element, trigger_event))
       continue;
 
-    for (j = 0; j < element_info[element].num_change_pages; j++)
+    for (p = 0; p < element_info[element].num_change_pages; p++)
     {
-      struct ElementChangeInfo *change = &element_info[element].change_page[j];
+      struct ElementChangeInfo *change = &element_info[element].change_page[p];
 
-      if (change->can_change &&
+      if (change->can_change_or_has_action &&
          change->has_event[trigger_event] &&
          change->trigger_side & trigger_side &&
          change->trigger_player & trigger_player &&
          change->trigger_page & trigger_page_bits &&
          IS_EQUAL_OR_IN_GROUP(trigger_element, change->trigger_element))
       {
-#if 0
-       if (!(change->has_event[trigger_event]))
-         printf("::: !!! %d triggers %d: using wrong page %d [event %d]\n",
-                trigger_element-EL_CUSTOM_START+1, i+1, j, trigger_event);
-#endif
-
-       change_element = TRUE;
-       page = j;
-
        change->actual_trigger_element = trigger_element;
        change->actual_trigger_player = EL_PLAYER_1 + log_2(trigger_player);
+       change->actual_trigger_side = trigger_side;
+       change->actual_trigger_ce_value = CustomValue[trigger_x][trigger_y];
+       change->actual_trigger_ce_score = GET_CE_SCORE(trigger_element);
 
-       break;
-      }
-    }
-
-    if (!change_element)
-      continue;
+       if ((change->can_change && !change_done) || change->has_action)
+       {
+         int x, y;
 
-    for (y = 0; y < lev_fieldy; y++) for (x = 0; x < lev_fieldx; x++)
-    {
-#if 0
-      if (x == lx && y == ly)  /* do not change trigger element itself */
-       continue;
+#if 1
+         SCAN_PLAYFIELD(x, y)
+#else
+         for (y = 0; y < lev_fieldy; y++) for (x = 0; x < lev_fieldx; x++)
+#endif
+         {
+           if (Feld[x][y] == element)
+           {
+             if (change->can_change && !change_done)
+             {
+               ChangeDelay[x][y] = 1;
+               ChangeEvent[x][y] = trigger_event;
+
+               HandleElementChange(x, y, p);
+             }
+#if USE_NEW_DELAYED_ACTION
+             else if (change->has_action)
+             {
+               ExecuteCustomElementAction(x, y, element, p);
+               PlayLevelSoundElementAction(x, y, element, ACTION_PAGE_1 + p);
+             }
+#else
+             if (change->has_action)
+             {
+               ExecuteCustomElementAction(x, y, element, p);
+               PlayLevelSoundElementAction(x, y, element, ACTION_PAGE_1 + p);
+             }
 #endif
+           }
+         }
 
-      if (Feld[x][y] == element)
-      {
-       ChangeDelay[x][y] = 1;
-       ChangeEvent[x][y] = trigger_event;
-       ChangeElement(x, y, page);
+         if (change->can_change)
+         {
+           change_done = TRUE;
+           change_done_any = TRUE;
+         }
+       }
       }
     }
   }
 
-  return TRUE;
+  return change_done_any;
 }
 
 static boolean CheckElementChangeExt(int x, int y,
@@ -8315,10 +9001,13 @@ static boolean CheckElementChangeExt(int x, int y,
                                     int trigger_element,
                                     int trigger_event,
                                     int trigger_player,
-                                    int trigger_side,
-                                    int trigger_page)
+                                    int trigger_side)
 {
-  if (!CAN_CHANGE(element) || !HAS_ANY_CHANGE_EVENT(element, trigger_event))
+  boolean change_done = FALSE;
+  int p;
+
+  if (!CAN_CHANGE_OR_HAS_ACTION(element) ||
+      !HAS_ANY_CHANGE_EVENT(element, trigger_event))
     return FALSE;
 
   if (Feld[x][y] == EL_BLOCKED)
@@ -8327,96 +9016,116 @@ static boolean CheckElementChangeExt(int x, int y,
     element = Feld[x][y];
   }
 
-#if 1
-  if (Feld[x][y] != element)   /* check if element has already changed */
-  {
 #if 0
-    printf("::: %d ('%s') != %d ('%s') [%d]\n",
-          Feld[x][y], element_info[Feld[x][y]].token_name,
-          element, element_info[element].token_name,
-          trigger_event);
-#endif
+  /* check if element has already changed */
+  if (Feld[x][y] != element)
+    return FALSE;
+#else
+  /* check if element has already changed or is about to change after moving */
+  if ((game.engine_version < VERSION_IDENT(3,2,0,7) &&
+       Feld[x][y] != element) ||
 
+      (game.engine_version >= VERSION_IDENT(3,2,0,7) &&
+       (ChangeCount[x][y] >= game.max_num_changes_per_frame ||
+       ChangePage[x][y] != -1)))
     return FALSE;
-  }
 #endif
 
-#if 1
-  if (trigger_page < 0)
+  for (p = 0; p < element_info[element].num_change_pages; p++)
   {
-    boolean change_element = FALSE;
-    int i;
+    struct ElementChangeInfo *change = &element_info[element].change_page[p];
 
-    for (i = 0; i < element_info[element].num_change_pages; i++)
+    boolean check_trigger_element =
+      (trigger_event == CE_TOUCHING_X ||
+       trigger_event == CE_HITTING_X ||
+       trigger_event == CE_HIT_BY_X);
+
+    if (change->can_change_or_has_action &&
+       change->has_event[trigger_event] &&
+       change->trigger_side & trigger_side &&
+       change->trigger_player & trigger_player &&
+       (!check_trigger_element ||
+        IS_EQUAL_OR_IN_GROUP(trigger_element, change->trigger_element)))
     {
-      struct ElementChangeInfo *change = &element_info[element].change_page[i];
+      change->actual_trigger_element = trigger_element;
+      change->actual_trigger_player = EL_PLAYER_1 + log_2(trigger_player);
+      change->actual_trigger_side = trigger_side;
+      change->actual_trigger_ce_value = CustomValue[x][y];
+      change->actual_trigger_ce_score = GET_CE_SCORE(trigger_element);
 
-      if (change->can_change &&
-         change->has_event[trigger_event] &&
-         change->trigger_side & trigger_side &&
-         change->trigger_player & trigger_player)
+      /* special case: trigger element not at (x,y) position for some events */
+      if (check_trigger_element)
       {
-       change_element = TRUE;
-       trigger_page = i;
+       static struct
+       {
+         int dx, dy;
+       } move_xy[] =
+         {
+           {  0,  0 },
+           { -1,  0 },
+           { +1,  0 },
+           {  0,  0 },
+           {  0, -1 },
+           {  0,  0 }, { 0, 0 }, { 0, 0 },
+           {  0, +1 }
+         };
 
-       change->actual_trigger_element = trigger_element;
-       change->actual_trigger_player = EL_PLAYER_1 + log_2(trigger_player);
+       int xx = x + move_xy[MV_DIR_OPPOSITE(trigger_side)].dx;
+       int yy = y + move_xy[MV_DIR_OPPOSITE(trigger_side)].dy;
 
-       break;
+       change->actual_trigger_ce_value = CustomValue[xx][yy];
+       change->actual_trigger_ce_score = GET_CE_SCORE(trigger_element);
       }
-    }
 
-    if (!change_element)
-      return FALSE;
-  }
-  else
-  {
-    struct ElementInfo *ei = &element_info[element];
-    struct ElementChangeInfo *change = &ei->change_page[trigger_page];
+      if (change->can_change && !change_done)
+      {
+       ChangeDelay[x][y] = 1;
+       ChangeEvent[x][y] = trigger_event;
 
-    change->actual_trigger_element = trigger_element;
-    change->actual_trigger_player = EL_PLAYER_1;       /* unused */
-  }
+       HandleElementChange(x, y, p);
 
+       change_done = TRUE;
+      }
+#if USE_NEW_DELAYED_ACTION
+      else if (change->has_action)
+      {
+       ExecuteCustomElementAction(x, y, element, p);
+       PlayLevelSoundElementAction(x, y, element, ACTION_PAGE_1 + p);
+      }
 #else
-
-  /* !!! this check misses pages with same event, but different side !!! */
-
-  if (trigger_page < 0)
-    trigger_page = element_info[element].event_page_nr[trigger_event];
-
-  if (!(element_info[element].change_page[trigger_page].trigger_side & trigger_side))
-    return FALSE;
+      if (change->has_action)
+      {
+       ExecuteCustomElementAction(x, y, element, p);
+       PlayLevelSoundElementAction(x, y, element, ACTION_PAGE_1 + p);
+      }
 #endif
+    }
+  }
 
-  ChangeDelay[x][y] = 1;
-  ChangeEvent[x][y] = trigger_event;
-  ChangeElement(x, y, trigger_page);
-
-  return TRUE;
+  return change_done;
 }
 
 static void PlayPlayerSound(struct PlayerInfo *player)
 {
   int jx = player->jx, jy = player->jy;
-  int element = player->element_nr;
+  int sound_element = player->artwork_element;
   int last_action = player->last_action_waiting;
   int action = player->action_waiting;
 
   if (player->is_waiting)
   {
     if (action != last_action)
-      PlayLevelSoundElementAction(jx, jy, element, action);
+      PlayLevelSoundElementAction(jx, jy, sound_element, action);
     else
-      PlayLevelSoundElementActionIfLoop(jx, jy, element, action);
+      PlayLevelSoundElementActionIfLoop(jx, jy, sound_element, action);
   }
   else
   {
     if (action != last_action)
-      StopSound(element_info[element].sound[last_action]);
+      StopSound(element_info[sound_element].sound[last_action]);
 
     if (last_action == ACTION_SLEEPING)
-      PlayLevelSoundElementAction(jx, jy, element, ACTION_AWAKENING);
+      PlayLevelSoundElementAction(jx, jy, sound_element, ACTION_AWAKENING);
   }
 }
 
@@ -8434,6 +9143,7 @@ static void SetPlayerWaiting(struct PlayerInfo *player, boolean is_waiting)
   boolean last_waiting = player->is_waiting;
   int move_dir = player->MovDir;
 
+  player->dir_waiting = move_dir;
   player->last_action_waiting = player->action_waiting;
 
   if (is_waiting)
@@ -8451,7 +9161,11 @@ static void SetPlayerWaiting(struct PlayerInfo *player, boolean is_waiting)
        game.player_sleeping_delay_fixed +
        SimpleRND(game.player_sleeping_delay_random);
 
+#if 1
+      InitPlayerGfxAnimation(player, ACTION_WAITING, move_dir);
+#else
       InitPlayerGfxAnimation(player, ACTION_WAITING, player->MovDir);
+#endif
     }
 
     if (game.player_sleeping_delay_fixed +
@@ -8469,6 +9183,26 @@ static void SetPlayerWaiting(struct PlayerInfo *player, boolean is_waiting)
                              player->is_bored ? ACTION_BORING :
                              ACTION_WAITING);
 
+#if 1
+    if (player->is_sleeping && player->use_murphy)
+    {
+      /* special case for sleeping Murphy when leaning against non-free tile */
+
+      if (!IN_LEV_FIELD(player->jx - 1, player->jy) ||
+         (Feld[player->jx - 1][player->jy] != EL_EMPTY &&
+          !IS_MOVING(player->jx - 1, player->jy)))
+       move_dir = MV_LEFT;
+      else if (!IN_LEV_FIELD(player->jx + 1, player->jy) ||
+              (Feld[player->jx + 1][player->jy] != EL_EMPTY &&
+               !IS_MOVING(player->jx + 1, player->jy)))
+       move_dir = MV_RIGHT;
+      else
+       player->is_sleeping = FALSE;
+
+      player->dir_waiting = move_dir;
+    }
+#endif
+
     if (player->is_sleeping)
     {
       if (player->num_special_action_sleeping > 0)
@@ -8483,7 +9217,7 @@ static void SetPlayerWaiting(struct PlayerInfo *player, boolean is_waiting)
             last_special_action < ACTION_SLEEPING_1 + num_special_action - 1 ?
             last_special_action + 1 : ACTION_SLEEPING);
          int special_graphic =
-           el_act_dir2img(player->element_nr, special_action, move_dir);
+           el_act_dir2img(player->artwork_element, special_action, move_dir);
 
          player->anim_delay_counter =
            graphic_info[special_graphic].anim_delay_fixed +
@@ -8515,7 +9249,7 @@ static void SetPlayerWaiting(struct PlayerInfo *player, boolean is_waiting)
          int special_action =
            ACTION_BORING_1 + SimpleRND(player->num_special_action_bored);
          int special_graphic =
-           el_act_dir2img(player->element_nr, special_action, move_dir);
+           el_act_dir2img(player->artwork_element, special_action, move_dir);
 
          player->anim_delay_counter =
            graphic_info[special_graphic].anim_delay_fixed +
@@ -8551,6 +9285,7 @@ static void SetPlayerWaiting(struct PlayerInfo *player, boolean is_waiting)
     player->anim_delay_counter = 0;
     player->post_delay_counter = 0;
 
+    player->dir_waiting = player->MovDir;
     player->action_waiting = ACTION_DEFAULT;
 
     player->special_action_bored = ACTION_DEFAULT;
@@ -8558,13 +9293,8 @@ static void SetPlayerWaiting(struct PlayerInfo *player, boolean is_waiting)
   }
 }
 
-#if 1
 static byte PlayerActions(struct PlayerInfo *player, byte player_action)
 {
-#if 0
-  static byte stored_player_action[MAX_PLAYERS];
-  static int num_stored_actions = 0;
-#endif
   boolean moved = FALSE, snapped = FALSE, dropped = FALSE;
   int left     = player_action & JOY_LEFT;
   int right    = player_action & JOY_RIGHT;
@@ -8572,37 +9302,14 @@ static byte PlayerActions(struct PlayerInfo *player, byte player_action)
   int down     = player_action & JOY_DOWN;
   int button1  = player_action & JOY_BUTTON_1;
   int button2  = player_action & JOY_BUTTON_2;
-  int dx       = (left ? -1    : right ? 1     : 0);
-  int dy       = (up   ? -1    : down  ? 1     : 0);
-
-#if 0
-  stored_player_action[player->index_nr] = 0;
-  num_stored_actions++;
-#endif
-
-#if 0
-  printf("::: player %d [%d]\n", player->index_nr, FrameCounter);
-#endif
+  int dx       = (left ? -1 : right ? 1 : 0);
+  int dy       = (up   ? -1 : down  ? 1 : 0);
 
   if (!player->active || tape.pausing)
     return 0;
 
-#if 0
-  printf("::: [%d %d %d %d] [%d %d]\n",
-        left, right, up, down, button1, button2);
-#endif
-
   if (player_action)
   {
-#if 0
-    printf("::: player %d acts [%d]\n", player->index_nr, FrameCounter);
-#endif
-
-#if 0
-    /* !!! TEST !!! */
-    if (player->MovPos == 0)
-      CheckGravityMovement(player);
-#endif
     if (button1)
       snapped = SnapField(player, dx, dy);
     else
@@ -8624,18 +9331,10 @@ static byte PlayerActions(struct PlayerInfo *player, byte player_action)
 
     SetPlayerWaiting(player, FALSE);
 
-#if 1
     return player_action;
-#else
-    stored_player_action[player->index_nr] = player_action;
-#endif
   }
   else
   {
-#if 0
-    printf("::: player %d waits [%d]\n", player->index_nr, FrameCounter);
-#endif
-
     /* no actions for this player (no input at player's configured device) */
 
     DigField(player, 0, 0, 0, 0, 0, 0, DF_NO_PUSH);
@@ -8649,101 +9348,95 @@ static byte PlayerActions(struct PlayerInfo *player, byte player_action)
       player->is_moving = FALSE;
 
     player->is_dropping = FALSE;
+    player->is_dropping_pressed = FALSE;
+    player->drop_pressed_delay = 0;
 
     return 0;
   }
-
-#if 0
-  if (tape.recording && num_stored_actions >= MAX_PLAYERS)
-  {
-    printf("::: player %d recorded [%d]\n", player->index_nr, FrameCounter);
-
-    TapeRecordAction(stored_player_action);
-    num_stored_actions = 0;
-  }
-#endif
 }
 
-#else
-
-static void PlayerActions(struct PlayerInfo *player, byte player_action)
+static void CheckLevelTime()
 {
-  static byte stored_player_action[MAX_PLAYERS];
-  static int num_stored_actions = 0;
-  boolean moved = FALSE, snapped = FALSE, dropped = FALSE;
-  int left     = player_action & JOY_LEFT;
-  int right    = player_action & JOY_RIGHT;
-  int up       = player_action & JOY_UP;
-  int down     = player_action & JOY_DOWN;
-  int button1  = player_action & JOY_BUTTON_1;
-  int button2  = player_action & JOY_BUTTON_2;
-  int dx       = (left ? -1    : right ? 1     : 0);
-  int dy       = (up   ? -1    : down  ? 1     : 0);
+  int i;
 
-  stored_player_action[player->index_nr] = 0;
-  num_stored_actions++;
+  if (level.game_engine_type == GAME_ENGINE_TYPE_EM)
+  {
+    if (level.native_em_level->lev->home == 0) /* all players at home */
+    {
+      local_player->LevelSolved = TRUE;
+      AllPlayersGone = TRUE;
 
-  printf("::: player %d [%d]\n", player->index_nr, FrameCounter);
+      level.native_em_level->lev->home = -1;
+    }
 
-  if (!player->active || tape.pausing)
-    return;
+    if (level.native_em_level->ply[0]->alive == 0 &&
+       level.native_em_level->ply[1]->alive == 0 &&
+       level.native_em_level->ply[2]->alive == 0 &&
+       level.native_em_level->ply[3]->alive == 0)      /* all dead */
+      AllPlayersGone = TRUE;
+  }
 
-  if (player_action)
+  if (TimeFrames >= FRAMES_PER_SECOND)
   {
-    printf("::: player %d acts [%d]\n", player->index_nr, FrameCounter);
+    TimeFrames = 0;
+    TapeTime++;
 
-    if (button1)
-      snapped = SnapField(player, dx, dy);
-    else
+    for (i = 0; i < MAX_PLAYERS; i++)
     {
-      if (button2)
-       dropped = DropElement(player);
-
-      moved = MovePlayer(player, dx, dy);
-    }
+      struct PlayerInfo *player = &stored_player[i];
 
-    if (tape.single_step && tape.recording && !tape.pausing)
-    {
-      if (button1 || (dropped && !moved))
+      if (SHIELD_ON(player))
       {
-       TapeTogglePause(TAPE_TOGGLE_AUTOMATIC);
-       SnapField(player, 0, 0);                /* stop snapping */
+       player->shield_normal_time_left--;
+
+       if (player->shield_deadly_time_left > 0)
+         player->shield_deadly_time_left--;
       }
     }
 
-    stored_player_action[player->index_nr] = player_action;
-  }
-  else
-  {
-    printf("::: player %d waits [%d]\n", player->index_nr, FrameCounter);
+    if (!level.use_step_counter)
+    {
+      TimePlayed++;
 
-    /* no actions for this player (no input at player's configured device) */
+      if (TimeLeft > 0)
+      {
+       TimeLeft--;
 
-    DigField(player, 0, 0, 0, 0, 0, 0, DF_NO_PUSH);
-    SnapField(player, 0, 0);
-    CheckGravityMovementWhenNotMoving(player);
+       if (TimeLeft <= 10 && setup.time_limit)
+         PlaySoundStereo(SND_GAME_RUNNING_OUT_OF_TIME, SOUND_MIDDLE);
 
-    if (player->MovPos == 0)
-      InitPlayerGfxAnimation(player, ACTION_DEFAULT, player->MovDir);
+       DrawGameValue_Time(TimeLeft);
 
-    if (player->MovPos == 0)   /* needed for tape.playing */
-      player->is_moving = FALSE;
-  }
+       if (!TimeLeft && setup.time_limit)
+       {
+         if (level.game_engine_type == GAME_ENGINE_TYPE_EM)
+           level.native_em_level->lev->killed_out_of_time = TRUE;
+         else
+           for (i = 0; i < MAX_PLAYERS; i++)
+             KillPlayer(&stored_player[i]);
+       }
+      }
+      else if (level.time == 0 && !AllPlayersGone) /* level w/o time limit */
+       DrawGameValue_Time(TimePlayed);
 
-  if (tape.recording && num_stored_actions >= MAX_PLAYERS)
-  {
-    printf("::: player %d recorded [%d]\n", player->index_nr, FrameCounter);
+      level.native_em_level->lev->time =
+       (level.time == 0 ? TimePlayed : TimeLeft);
+    }
 
-    TapeRecordAction(stored_player_action);
-    num_stored_actions = 0;
+    if (tape.recording || tape.playing)
+      DrawVideoDisplay(VIDEO_STATE_TIME_ON, TapeTime);
   }
 }
-#endif
 
 void AdvanceFrameAndPlayerCounters(int player_nr)
 {
   int i;
 
+#if 0
+  Error(ERR_NETWORK_CLIENT, "advancing frame counter from %d to %d",
+       FrameCounter, FrameCounter + 1);
+#endif
+
   /* advance frame counters (global frame counter and time frame counter) */
   FrameCounter++;
   TimeFrames++;
@@ -8752,46 +9445,105 @@ void AdvanceFrameAndPlayerCounters(int player_nr)
   for (i = 0; i < MAX_PLAYERS; i++)
   {
     boolean advance_player_counters = (player_nr == -1 || player_nr == i);
-    int move_frames =
-      MOVE_DELAY_NORMAL_SPEED /  stored_player[i].move_delay_value;
+    int move_delay_value = stored_player[i].move_delay_value;
+    int move_frames = MOVE_DELAY_NORMAL_SPEED / move_delay_value;
 
     if (!advance_player_counters)      /* not all players may be affected */
       continue;
 
+#if USE_NEW_PLAYER_ANIM
+    if (move_frames == 0)      /* less than one move per game frame */
+    {
+      int stepsize = TILEX / move_delay_value;
+      int delay = move_delay_value / MOVE_DELAY_NORMAL_SPEED;
+      int count = (stored_player[i].is_moving ?
+                  ABS(stored_player[i].MovPos) / stepsize : FrameCounter);
+
+      if (count % delay == 0)
+       move_frames = 1;
+    }
+#endif
+
     stored_player[i].Frame += move_frames;
 
     if (stored_player[i].MovPos != 0)
       stored_player[i].StepFrame += move_frames;
 
-#if USE_NEW_MOVE_DELAY
     if (stored_player[i].move_delay > 0)
       stored_player[i].move_delay--;
-#endif
 
-#if USE_NEW_PUSH_DELAY
     /* due to bugs in previous versions, counter must count up, not down */
     if (stored_player[i].push_delay != -1)
       stored_player[i].push_delay++;
-#endif
 
     if (stored_player[i].drop_delay > 0)
       stored_player[i].drop_delay--;
+
+    if (stored_player[i].is_dropping_pressed)
+      stored_player[i].drop_pressed_delay++;
+  }
+}
+
+void StartGameActions(boolean init_network_game, boolean record_tape,
+                     long random_seed)
+{
+  unsigned long new_random_seed = InitRND(random_seed);
+
+  if (record_tape)
+    TapeStartRecording(new_random_seed);
+
+#if defined(NETWORK_AVALIABLE)
+  if (init_network_game)
+  {
+    SendToServer_StartPlaying();
+
+    return;
   }
+#endif
+
+  StopAnimation();
+
+  game_status = GAME_MODE_PLAYING;
+
+  InitGame();
 }
 
 void GameActions()
 {
   static unsigned long game_frame_delay = 0;
   unsigned long game_frame_delay_value;
-  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 1
   byte tape_action[MAX_PLAYERS];
-#endif
+  int i;
 
-  if (game_status != GAME_MODE_PLAYING)
+  if (game.restart_level)
+    StartGameActions(options.network, setup.autorecord, NEW_RANDOMIZE);
+
+  if (level.game_engine_type == GAME_ENGINE_TYPE_EM)
+  {
+    if (level.native_em_level->lev->home == 0) /* all players at home */
+    {
+      local_player->LevelSolved = TRUE;
+      AllPlayersGone = TRUE;
+
+      level.native_em_level->lev->home = -1;
+    }
+
+    if (level.native_em_level->ply[0]->alive == 0 &&
+       level.native_em_level->ply[1]->alive == 0 &&
+       level.native_em_level->ply[2]->alive == 0 &&
+       level.native_em_level->ply[3]->alive == 0)      /* all dead */
+      AllPlayersGone = TRUE;
+  }
+
+  if (local_player->LevelSolved)
+    GameWon();
+
+  if (AllPlayersGone && !TAPE_IS_STOPPED(tape))
+    TapeStop();
+
+  if (game_status != GAME_MODE_PLAYING)                /* status might have changed */
     return;
 
   game_frame_delay_value =
@@ -8806,55 +9558,39 @@ void GameActions()
 
   if (network_playing && !network_player_action_received)
   {
-    /*
-#ifdef DEBUG
-    printf("DEBUG: try to get network player actions in time\n");
-#endif
-    */
+    /* try to get network player actions in time */
 
 #if defined(NETWORK_AVALIABLE)
     /* last chance to get network player actions without main loop delay */
     HandleNetworking();
 #endif
 
+    /* game was quit by network peer */
     if (game_status != GAME_MODE_PLAYING)
       return;
 
     if (!network_player_action_received)
-    {
-      /*
-#ifdef DEBUG
-      printf("DEBUG: failed to get network player actions in time\n");
-#endif
-      */
-      return;
-    }
+      return;          /* failed to get network player actions in time */
+
+    /* do not yet reset "network_player_action_received" (for tape.pausing) */
   }
 
   if (tape.pausing)
     return;
 
-#if 0
-  printf("::: getting new tape action [%d]\n", FrameCounter);
-#endif
-
-  recorded_player_action = (tape.playing ? TapePlayAction() : NULL);
+  /* at this point we know that we really continue executing the game */
 
 #if 1
-  /* !!! CHECK THIS (tape.pausing is always FALSE here!) !!! */
-  if (recorded_player_action == NULL && tape.pausing)
-    return;
+  network_player_action_received = FALSE;
 #endif
 
-#if 0
-  printf("::: %d\n", stored_player[0].action);
-#endif
+  recorded_player_action = (tape.playing ? TapePlayAction() : NULL);
 
-#if 0
-  if (recorded_player_action != NULL)
-    for (i = 0; i < MAX_PLAYERS; i++)
-      stored_player[i].action = recorded_player_action[i];
-#endif
+  if (tape.set_centered_player)
+  {
+    game.centered_player_nr_next = tape.centered_player_nr_next;
+    game.set_centered_player = TRUE;
+  }
 
   for (i = 0; i < MAX_PLAYERS; i++)
   {
@@ -8872,24 +9608,116 @@ void GameActions()
   if (!options.network && !setup.team_mode)
     local_player->effective_action = summarized_player_action;
 
-#if 1
+  if (setup.team_mode && setup.input_on_focus && game.centered_player_nr != -1)
+  {
+    for (i = 0; i < MAX_PLAYERS; i++)
+      stored_player[i].effective_action =
+       (i == game.centered_player_nr ? summarized_player_action : 0);
+  }
+
   if (recorded_player_action != NULL)
     for (i = 0; i < MAX_PLAYERS; i++)
       stored_player[i].effective_action = recorded_player_action[i];
-#endif
 
-#if 1
   for (i = 0; i < MAX_PLAYERS; i++)
   {
     tape_action[i] = stored_player[i].effective_action;
 
+    /* (this can only happen in the R'n'D game engine) */
     if (tape.recording && tape_action[i] && !tape.player_participates[i])
       tape.player_participates[i] = TRUE;    /* player just appeared from CE */
   }
 
-  /* only save actions from input devices, but not programmed actions */
+  /* only record actions from input devices, but not programmed actions */
   if (tape.recording)
     TapeRecordAction(tape_action);
+
+  if (level.game_engine_type == GAME_ENGINE_TYPE_EM)
+  {
+    GameActions_EM_Main();
+  }
+  else
+  {
+    GameActions_RND();
+  }
+}
+
+void GameActions_EM_Main()
+{
+  byte effective_action[MAX_PLAYERS];
+  boolean warp_mode = (tape.playing && tape.warp_forward && !tape.pausing);
+  int i;
+
+  for (i = 0; i < MAX_PLAYERS; i++)
+    effective_action[i] = stored_player[i].effective_action;
+
+  GameActions_EM(effective_action, warp_mode);
+
+  CheckLevelTime();
+
+  AdvanceFrameAndPlayerCounters(-1);   /* advance counters for all players */
+}
+
+void GameActions_RND()
+{
+  int magic_wall_x = 0, magic_wall_y = 0;
+  int i, x, y, element, graphic;
+
+  InitPlayfieldScanModeVars();
+
+#if USE_ONE_MORE_CHANGE_PER_FRAME
+  if (game.engine_version >= VERSION_IDENT(3,2,0,7))
+  {
+    SCAN_PLAYFIELD(x, y)
+    {
+      ChangeCount[x][y] = 0;
+      ChangeEvent[x][y] = -1;
+    }
+  }
+#endif
+
+#if 1
+  if (game.set_centered_player)
+  {
+    boolean all_players_fit_to_screen = checkIfAllPlayersFitToScreen_RND();
+
+    /* switching to "all players" only possible if all players fit to screen */
+    if (game.centered_player_nr_next == -1 && !all_players_fit_to_screen)
+    {
+      game.centered_player_nr_next = game.centered_player_nr;
+      game.set_centered_player = FALSE;
+    }
+
+    /* do not switch focus to non-existing (or non-active) player */
+    if (game.centered_player_nr_next >= 0 &&
+       !stored_player[game.centered_player_nr_next].active)
+    {
+      game.centered_player_nr_next = game.centered_player_nr;
+      game.set_centered_player = FALSE;
+    }
+  }
+
+  if (game.set_centered_player &&
+      ScreenMovPos == 0)       /* screen currently aligned at tile position */
+  {
+    int sx, sy;
+
+    if (game.centered_player_nr_next == -1)
+    {
+      setScreenCenteredToAllPlayers(&sx, &sy);
+    }
+    else
+    {
+      sx = stored_player[game.centered_player_nr_next].jx;
+      sy = stored_player[game.centered_player_nr_next].jy;
+    }
+
+    game.centered_player_nr = game.centered_player_nr_next;
+    game.set_centered_player = FALSE;
+
+    DrawRelocateScreen(sx, sy, MV_NONE, TRUE, setup.quick_switch);
+    DrawGameDoorValues();
+  }
 #endif
 
   for (i = 0; i < MAX_PLAYERS; i++)
@@ -8907,42 +9735,9 @@ void GameActions()
       CheckGravityMovement(&stored_player[i]);
 #endif
 
-#if 1
     /* overwrite programmed action with tape action */
     if (stored_player[i].programmed_action)
       actual_player_action = stored_player[i].programmed_action;
-#endif
-
-#if 0
-    if (stored_player[i].programmed_action)
-      printf("::: %d\n", stored_player[i].programmed_action);
-#endif
-
-    if (recorded_player_action)
-    {
-#if 0
-      if (stored_player[i].programmed_action &&
-         stored_player[i].programmed_action != recorded_player_action[i])
-       printf("::: %d: %d <-> %d\n", i,
-              stored_player[i].programmed_action, recorded_player_action[i]);
-#endif
-
-#if 0
-      actual_player_action = recorded_player_action[i];
-#endif
-    }
-
-#if 0
-    /* overwrite tape action with programmed action */
-    if (stored_player[i].programmed_action)
-      actual_player_action = stored_player[i].programmed_action;
-#endif
-
-#if 0
-    if (i == 0)
-      printf("::: action: %d: %x [%d]\n",
-            stored_player[i].MovPos, actual_player_action, FrameCounter);
-#endif
 
 #if 1
     PlayerActions(&stored_player[i], actual_player_action);
@@ -8957,23 +9752,11 @@ void GameActions()
   }
 
 #if 0
-  if (tape.recording)
-    TapeRecordAction(tape_action);
-#endif
-
   network_player_action_received = FALSE;
+#endif
 
   ScrollScreen(NULL, SCROLL_GO_ON);
 
-#if 0
-  FrameCounter++;
-  TimeFrames++;
-
-  for (i = 0; i < MAX_PLAYERS; i++)
-    stored_player[i].Frame++;
-#endif
-
-#if 1
   /* for backwards compatibility, the following code emulates a fixed bug that
      occured when pushing elements (causing elements that just made their last
      pushing step to already (if possible) make their first falling step in the
@@ -8982,11 +9765,7 @@ void GameActions()
      used also in newer levels, but in this case the buggy pushing code is only
      affecting the "spring" element and no other elements */
 
-#if 1
   if (game.engine_version < VERSION_IDENT(2,2,0,7) || level.use_spring_bug)
-#else
-  if (game.engine_version < VERSION_IDENT(2,2,0,7))
-#endif
   {
     for (i = 0; i < MAX_PLAYERS; i++)
     {
@@ -8994,15 +9773,10 @@ void GameActions()
       int x = player->jx;
       int y = player->jy;
 
-#if 1
       if (player->active && player->is_pushing && player->is_moving &&
          IS_MOVING(x, y) &&
          (game.engine_version < VERSION_IDENT(2,2,0,7) ||
           Feld[x][y] == EL_SPRING))
-#else
-      if (player->active && player->is_pushing && player->is_moving &&
-         IS_MOVING(x, y))
-#endif
       {
        ContinueMoving(x, y);
 
@@ -9014,14 +9788,16 @@ void GameActions()
       }
     }
   }
-#endif
 
+#if 1
+  SCAN_PLAYFIELD(x, y)
+#else
   for (y = 0; y < lev_fieldy; y++) for (x = 0; x < lev_fieldx; x++)
+#endif
   {
-    Changed[x][y] = FALSE;
+    ChangeCount[x][y] = 0;
     ChangeEvent[x][y] = -1;
 
-#if USE_NEW_BLOCK_STYLE
     /* this must be handled before main playfield loop */
     if (Feld[x][y] == EL_PLAYER_IS_LEAVING)
     {
@@ -9029,6 +9805,19 @@ void GameActions()
       if (MovDelay[x][y] <= 0)
        RemoveField(x, y);
     }
+
+#if USE_NEW_SNAP_DELAY
+    if (Feld[x][y] == EL_ELEMENT_SNAPPING)
+    {
+      MovDelay[x][y]--;
+      if (MovDelay[x][y] <= 0)
+      {
+       RemoveField(x, y);
+       DrawLevelField(x, y);
+
+       TestIfElementTouchesCustomElement(x, y);        /* for empty space */
+      }
+    }
 #endif
 
 #if DEBUG
@@ -9051,15 +9840,13 @@ void GameActions()
 
     GfxFrame[x][y]++;
 
-#if 1
     /* reset finished pushing action (not done in ContinueMoving() to allow
-       continous pushing animation for elements with zero push delay) */
+       continuous pushing animation for elements with zero 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))
@@ -9078,26 +9865,61 @@ void GameActions()
 #endif
   }
 
+#if 1
+  SCAN_PLAYFIELD(x, y)
+#else
   for (y = 0; y < lev_fieldy; y++) for (x = 0; x < lev_fieldx; x++)
+#endif
   {
     element = Feld[x][y];
-#if 1
     graphic = el_act_dir2img(element, GfxAction[x][y], GfxDir[x][y]);
-#else
-    graphic = el2img(element);
-#endif
 
 #if 0
-    if (element == -1)
-    {
-      printf("::: %d,%d: %d [%d]\n", x, y, element, FrameCounter);
+    printf("::: %d,%d\n", x, y);
 
-      element = graphic = 0;
-    }
+    if (element == EL_ROCK)
+      printf("::: Yo man! Rocks can fall!\n");
 #endif
 
+#if 1
+    ResetGfxFrame(x, y, TRUE);
+#else
     if (graphic_info[graphic].anim_global_sync)
       GfxFrame[x][y] = FrameCounter;
+    else if (ANIM_MODE(graphic) == ANIM_CE_VALUE)
+    {
+      int old_gfx_frame = GfxFrame[x][y];
+
+      GfxFrame[x][y] = CustomValue[x][y];
+
+#if 1
+      if (GfxFrame[x][y] != old_gfx_frame)
+#endif
+       DrawLevelGraphicAnimation(x, y, graphic);
+    }
+    else if (ANIM_MODE(graphic) == ANIM_CE_SCORE)
+    {
+      int old_gfx_frame = GfxFrame[x][y];
+
+      GfxFrame[x][y] = element_info[element].collect_score;
+
+#if 1
+      if (GfxFrame[x][y] != old_gfx_frame)
+#endif
+       DrawLevelGraphicAnimation(x, y, graphic);
+    }
+    else if (ANIM_MODE(graphic) == ANIM_CE_DELAY)
+    {
+      int old_gfx_frame = GfxFrame[x][y];
+
+      GfxFrame[x][y] = ChangeDelay[x][y];
+
+#if 1
+      if (GfxFrame[x][y] != old_gfx_frame)
+#endif
+       DrawLevelGraphicAnimation(x, y, graphic);
+    }
+#endif
 
     if (ANIM_MODE(graphic) == ANIM_RANDOM &&
        IS_NEXT_FRAME(GfxFrame[x][y], graphic))
@@ -9105,9 +9927,7 @@ void GameActions()
 
     SetRandomAnimationValue(x, y);
 
-#if 1
     PlayLevelSoundActionIfLoop(x, y, GfxAction[x][y]);
-#endif
 
     if (IS_INACTIVE(element))
     {
@@ -9117,64 +9937,52 @@ void GameActions()
       continue;
     }
 
-#if 1
     /* this may take place after moving, so 'element' may have changed */
-#if 0
-    if (IS_CHANGING(x, y))
-#else
     if (IS_CHANGING(x, y) &&
        (game.engine_version < VERSION_IDENT(3,0,7,1) || !Stop[x][y]))
-#endif
     {
+      int page = element_info[element].event_page_nr[CE_DELAY];
+#if 0
+      HandleElementChange(x, y, ChangePage[x][y] != -1 ? ChangePage[x][y] : page);
+#else
+
+#if 0
+      printf("::: ChangeDelay == %d\n", ChangeDelay[x][y]);
+#endif
+
 #if 0
-      ChangeElement(x, y, ChangePage[x][y] != -1 ? ChangePage[x][y] :
-                   element_info[element].event_page_nr[CE_DELAY]);
+      if (element == EL_CUSTOM_255)
+       printf("::: ChangeDelay == %d\n", ChangeDelay[x][y]);
+#endif
+
+#if 1
+      HandleElementChange(x, y, page);
 #else
-      ChangeElement(x, y, element_info[element].event_page_nr[CE_DELAY]);
+      if (CAN_CHANGE(element))
+       HandleElementChange(x, y, page);
+
+      if (HAS_ACTION(element))
+       ExecuteCustomElementAction(x, y, element, page);
+#endif
+
 #endif
 
       element = Feld[x][y];
       graphic = el_act_dir2img(element, GfxAction[x][y], GfxDir[x][y]);
     }
-#endif
 
     if (!IS_MOVING(x, y) && (CAN_FALL(element) || CAN_MOVE(element)))
     {
       StartMoving(x, y);
 
-#if 1
       element = Feld[x][y];
       graphic = el_act_dir2img(element, GfxAction[x][y], GfxDir[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_BUG)
-         printf("::: %d, %d\n", graphic, GfxFrame[x][y]);
-#endif
-
-#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);
     }
@@ -9192,10 +10000,6 @@ void GameActions()
       ContinueMoving(x, y);
     else if (IS_ACTIVE_BOMB(element))
       CheckDynamite(x, y);
-#if 0
-    else if (element == EL_EXPLOSION && !game.explosions_delayed)
-      Explode(x, y, ExplodePhase[x][y], EX_TYPE_NORMAL);
-#endif
     else if (element == EL_AMOEBA_GROWING)
       AmoebeWaechst(x, y);
     else if (element == EL_AMOEBA_SHRINKING)
@@ -9217,23 +10021,30 @@ void GameActions()
     else if (element == EL_EXPANDABLE_WALL ||
             element == EL_EXPANDABLE_WALL_HORIZONTAL ||
             element == EL_EXPANDABLE_WALL_VERTICAL ||
-            element == EL_EXPANDABLE_WALL_ANY)
+            element == EL_EXPANDABLE_WALL_ANY ||
+            element == EL_BD_EXPANDABLE_WALL)
       MauerAbleger(x, y);
     else if (element == EL_FLAMES)
       CheckForDragon(x, y);
-#if 0
-    else if (IS_AUTO_CHANGING(element))
-      ChangeElement(x, y);
-#endif
     else if (element == EL_EXPLOSION)
       ;        /* drawing of correct explosion animation is handled separately */
+    else if (element == EL_ELEMENT_SNAPPING ||
+            element == EL_DIAGONAL_SHRINKING ||
+            element == EL_DIAGONAL_GROWING)
+    {
+#if 1
+      graphic = el_act_dir2img(GfxElement[x][y], GfxAction[x][y],GfxDir[x][y]);
+
+      DrawLevelGraphicAnimationIfNeeded(x, y, graphic);
+#endif
+    }
     else if (IS_ANIMATED(graphic) && !IS_CHANGING(x, y))
       DrawLevelGraphicAnimationIfNeeded(x, y, graphic);
 
 #if 0
-    /* this may take place after moving, so 'element' may have changed */
-    if (IS_AUTO_CHANGING(Feld[x][y]))
-      ChangeElement(x, y);
+    if (element == EL_CUSTOM_255 ||
+       element == EL_CUSTOM_256)
+      DrawLevelGraphicAnimation(x, y, graphic);
 #endif
 
     if (IS_BELT_ACTIVE(element))
@@ -9260,24 +10071,16 @@ void GameActions()
 
 #if USE_NEW_AMOEBA_CODE
   /* new experimental amoeba growth stuff */
-#if 1
   if (!(FrameCounter % 8))
-#endif
   {
     static unsigned long random = 1684108901;
 
     for (i = 0; i < level.amoeba_speed * 28 / 8; i++)
     {
-#if 0
-      x = (random >> 10) % lev_fieldx;
-      y = (random >> 20) % lev_fieldy;
-#else
       x = RND(lev_fieldx);
       y = RND(lev_fieldy);
-#endif
       element = Feld[x][y];
 
-#if 1
       if (!IS_PLAYER(x,y) &&
          (element == EL_EMPTY ||
           CAN_GROW_INTO(element) ||
@@ -9291,22 +10094,6 @@ void GameActions()
            (IN_LEV_FIELD(x, y+1) && Feld[x][y+1] == EL_AMOEBA_WET))
          Feld[x][y] = EL_AMOEBA_DROP;
       }
-#else
-      /* !!! extend EL_SAND to anything diggable (but maybe not SP_BASE) !!! */
-      if (!IS_PLAYER(x,y) &&
-         (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_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;
-      }
-#endif
 
       random = random * 129 + 1;
     }
@@ -9319,7 +10106,11 @@ void GameActions()
   {
     game.explosions_delayed = FALSE;
 
+#if 1
+    SCAN_PLAYFIELD(x, y)
+#else
     for (y = 0; y < lev_fieldy; y++) for (x = 0; x < lev_fieldx; x++)
+#endif
     {
       element = Feld[x][y];
 
@@ -9353,7 +10144,11 @@ void GameActions()
       game.magic_wall_time_left--;
       if (!game.magic_wall_time_left)
       {
+#if 1
+       SCAN_PLAYFIELD(x, y)
+#else
        for (y = 0; y < lev_fieldy; y++) for (x = 0; x < lev_fieldx; x++)
+#endif
        {
          element = Feld[x][y];
 
@@ -9392,6 +10187,22 @@ void GameActions()
       CloseAllOpenTimegates();
   }
 
+  if (game.lenses_time_left > 0)
+  {
+    game.lenses_time_left--;
+
+    if (game.lenses_time_left == 0)
+      RedrawAllInvisibleElementsForLenses();
+  }
+
+  if (game.magnify_time_left > 0)
+  {
+    game.magnify_time_left--;
+
+    if (game.magnify_time_left == 0)
+      RedrawAllInvisibleElementsForMagnifier();
+  }
+
   for (i = 0; i < MAX_PLAYERS; i++)
   {
     struct PlayerInfo *player = &stored_player[i];
@@ -9405,48 +10216,7 @@ void GameActions()
     }
   }
 
-  if (TimeFrames >= FRAMES_PER_SECOND)
-  {
-    TimeFrames = 0;
-    TapeTime++;
-
-    for (i = 0; i < MAX_PLAYERS; i++)
-    {
-      struct PlayerInfo *player = &stored_player[i];
-
-      if (SHIELD_ON(player))
-      {
-       player->shield_normal_time_left--;
-
-       if (player->shield_deadly_time_left > 0)
-         player->shield_deadly_time_left--;
-      }
-    }
-
-    if (!level.use_step_counter)
-    {
-      TimePlayed++;
-
-      if (TimeLeft > 0)
-      {
-       TimeLeft--;
-
-       if (TimeLeft <= 10 && setup.time_limit)
-         PlaySoundStereo(SND_GAME_RUNNING_OUT_OF_TIME, SOUND_MIDDLE);
-
-       DrawGameValue_Time(TimeLeft);
-
-       if (!TimeLeft && setup.time_limit)
-         for (i = 0; i < MAX_PLAYERS; i++)
-           KillHero(&stored_player[i]);
-      }
-      else if (level.time == 0 && !AllPlayersGone) /* level w/o time limit */
-       DrawGameValue_Time(TimePlayed);
-    }
-
-    if (tape.recording || tape.playing)
-      DrawVideoDisplay(VIDEO_STATE_TIME_ON, TapeTime);
-  }
+  CheckLevelTime();
 
   DrawAllPlayers();
   PlayAllPlayersSound();
@@ -9470,57 +10240,18 @@ 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 USE_NEW_MOVE_DELAY
   AdvanceFrameAndPlayerCounters(-1);   /* advance counters for all players */
-#else
-  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;
-
-#if USE_NEW_MOVE_DELAY
-    if (stored_player[i].move_delay > 0)
-      stored_player[i].move_delay--;
-#endif
-
-    if (stored_player[i].drop_delay > 0)
-      stored_player[i].drop_delay--;
-  }
-#endif
-
-#if 1
   if (local_player->show_envelope != 0 && local_player->MovPos == 0)
   {
     ShowEnvelope(local_player->show_envelope - EL_ENVELOPE_1);
 
     local_player->show_envelope = 0;
   }
-#endif
 
-#if USE_NEW_RANDOMIZE
   /* use random number generator in every frame to make it less predictable */
   if (game.engine_version >= VERSION_IDENT(3,1,1,0))
     RND(1);
-#endif
 }
 
 static boolean AllPlayersInSight(struct PlayerInfo *player, int x, int y)
@@ -9592,51 +10323,12 @@ void ScrollLevel(int dx, int dy)
   redraw_mask |= REDRAW_FIELD;
 }
 
-#if 0
-static boolean canEnterSupaplexPort(int x, int y, int dx, int dy)
-{
-  int nextx = x + dx, nexty = y + dy;
-  int element = Feld[x][y];
-
-  if ((dx == -1 &&
-       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_PORT_RIGHT &&
-       element != EL_SP_GRAVITY_PORT_RIGHT &&
-       element != EL_SP_PORT_HORIZONTAL &&
-       element != EL_SP_PORT_ANY) ||
-      (dy == -1 &&
-       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_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 FALSE;
-
-  return TRUE;
-}
-#endif
-
 static boolean canFallDown(struct PlayerInfo *player)
 {
   int jx = player->jx, jy = player->jy;
 
   return (IN_LEV_FIELD(jx, jy + 1) &&
          (IS_FREE(jx, jy + 1) ||
-#if USE_NEW_BLOCK_STYLE
-#if USE_GRAVITY_BUGFIX_OLD
-          Feld[jx][jy + 1] == EL_PLAYER_IS_LEAVING ||
-#endif
-#endif
           (Feld[jx][jy + 1] == EL_ACID && player->can_fall_into_acid)) &&
          IS_WALKABLE_FROM(Feld[jx][jy], MV_DOWN) &&
          !IS_WALKABLE_INSIDE(Feld[jx][jy]));
@@ -9665,168 +10357,47 @@ static boolean canMoveToValidFieldWithGravity(int x, int y, int move_dir)
   int dy = (move_dir & MV_UP   ? -1 : move_dir & MV_DOWN  ? +1 : 0);
   int newx = x + dx;
   int newy = y + dy;
-#if 0
-  int nextx = newx + dx;
-  int nexty = newy + dy;
-#endif
 
-#if 1
-  return (IN_LEV_FIELD(newx, newy) && !IS_FREE_OR_PLAYER(newx, newy) &&
-         IS_GRAVITY_REACHABLE(Feld[newx][newy]) &&
-#if 0
-         (!IS_SP_PORT(Feld[newx][newy]) || move_dir == MV_UP) &&
-#endif
-         (IS_DIGGABLE(Feld[newx][newy]) ||
-          IS_WALKABLE_FROM(Feld[newx][newy], opposite_dir) ||
-          canPassField(newx, newy, move_dir)));
-#else
-#if 1
   return (IN_LEV_FIELD(newx, newy) && !IS_FREE_OR_PLAYER(newx, newy) &&
          IS_GRAVITY_REACHABLE(Feld[newx][newy]) &&
          (IS_DIGGABLE(Feld[newx][newy]) ||
           IS_WALKABLE_FROM(Feld[newx][newy], opposite_dir) ||
           canPassField(newx, newy, move_dir)));
-#else
-#if 1
-  return (IN_LEV_FIELD(newx, newy) && !IS_FREE_OR_PLAYER(newx, newy) &&
-         (IS_DIGGABLE_WITH_GRAVITY(Feld[newx][newy]) ||
-          IS_WALKABLE_FROM(Feld[newx][newy], opposite_dir) ||
-          canPassField(newx, newy, move_dir)));
-#else
-  return (IN_LEV_FIELD(newx, newy) && !IS_FREE_OR_PLAYER(newx, newy) &&
-         (IS_DIGGABLE(Feld[newx][newy]) ||
-          IS_WALKABLE_FROM(Feld[newx][newy], opposite_dir) ||
-          (IS_PASSABLE_FROM(Feld[newx][newy], opposite_dir) &&
-           !CAN_MOVE(Feld[newx][newy]) &&
-           IN_LEV_FIELD(nextx, nexty) && !IS_PLAYER(nextx, nexty) &&
-           IS_WALKABLE_FROM(Feld[nextx][nexty], move_dir) &&
-           (level.can_pass_to_walkable || IS_FREE(nextx, nexty)))));
-#endif
-#endif
-#endif
 }
 
 static void CheckGravityMovement(struct PlayerInfo *player)
 {
+#if USE_PLAYER_GRAVITY
+  if (player->gravity && !player->programmed_action)
+#else
   if (game.gravity && !player->programmed_action)
+#endif
   {
-#if 1
     int move_dir_horizontal = player->effective_action & MV_HORIZONTAL;
     int move_dir_vertical   = player->effective_action & MV_VERTICAL;
-#else
-    int move_dir_horizontal = player->action & MV_HORIZONTAL;
-    int move_dir_vertical   = player->action & MV_VERTICAL;
-#endif
-
-#if 1
     boolean player_is_snapping = player->effective_action & JOY_BUTTON_1;
-#else
-    boolean player_is_snapping = player->action & JOY_BUTTON_1;
-#endif
-
     int jx = player->jx, jy = player->jy;
-
     boolean player_is_moving_to_valid_field =
       (!player_is_snapping &&
        (canMoveToValidFieldWithGravity(jx, jy, move_dir_horizontal) ||
        canMoveToValidFieldWithGravity(jx, jy, move_dir_vertical)));
-
-#if 0
-    int move_dir =
-      (player->last_move_dir & MV_HORIZONTAL ?
-       (move_dir_vertical ? move_dir_vertical : move_dir_horizontal) :
-       (move_dir_horizontal ? move_dir_horizontal : move_dir_vertical));
-#endif
-
-#if 0
-    int opposite_dir = MV_DIR_OPPOSITE(move_dir);
-    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 new_jx = jx + dx, new_jy = jy + dy;
-    int nextx = new_jx + dx, nexty = new_jy + dy;
-#endif
-
-#if 1
-
-#if 1
     boolean player_can_fall_down = canFallDown(player);
-#else
-    boolean player_can_fall_down =
-      (IN_LEV_FIELD(jx, jy + 1) &&
-       (IS_FREE(jx, jy + 1) ||
-       (Feld[jx][jy + 1] == EL_ACID && player->can_fall_into_acid)));
-#endif
-
-#else
-    boolean player_can_fall_down =
-      (IN_LEV_FIELD(jx, jy + 1) &&
-       (IS_FREE(jx, jy + 1)));
-#endif
-
-#if 0
-    boolean player_is_moving_to_valid_field =
-      (
-#if 1
-       !player_is_snapping &&
-#endif
-
-#if 1
-       IN_LEV_FIELD(new_jx, new_jy) &&
-       (IS_DIGGABLE(Feld[new_jx][new_jy]) ||
-       (IS_SP_PORT(Feld[new_jx][new_jy]) &&
-        element_info[Feld[new_jx][new_jy]].access_direction & opposite_dir &&
-        IN_LEV_FIELD(nextx, nexty) &&
-        element_info[Feld[nextx][nexty]].access_direction & move_dir))
-#else
-       IN_LEV_FIELD(new_jx, new_jy) &&
-       (Feld[new_jx][new_jy] == EL_SP_BASE ||
-       Feld[new_jx][new_jy] == EL_SAND ||
-       (IS_SP_PORT(Feld[new_jx][new_jy]) &&
-        canEnterSupaplexPort(new_jx, new_jy, dx, dy)))
-    /* !!! extend EL_SAND to anything diggable !!! */
-#endif
-       );
-#endif
-
-#if 0
-    boolean player_is_standing_on_valid_field =
-      (IS_WALKABLE_INSIDE(Feld[jx][jy]) ||
-       (IS_WALKABLE(Feld[jx][jy]) && !ACCESS_FROM(Feld[jx][jy], MV_DOWN)));
-#endif
-
-#if 0
-    printf("::: checking gravity NOW [%d, %d, %d] [%d] [%d / %d] ...\n",
-          player_can_fall_down,
-          player_is_standing_on_valid_field,
-          player_is_moving_to_valid_field,
-          (player_is_moving_to_valid_field ? Feld[new_jx][new_jy] : -1),
-          player->effective_action,
-          player->can_fall_into_acid);
-#endif
 
     if (player_can_fall_down &&
-#if 0
-       !player_is_standing_on_valid_field &&
-#endif
        !player_is_moving_to_valid_field)
-    {
-#if 0
-      printf("::: setting programmed_action to MV_DOWN [%d,%d - %d] ...\n",
-            jx, jy, FrameCounter);
-#endif
-
       player->programmed_action = MV_DOWN;
-    }
   }
 }
 
 static void CheckGravityMovementWhenNotMoving(struct PlayerInfo *player)
 {
-#if 1
   return CheckGravityMovement(player);
-#endif
 
+#if USE_PLAYER_GRAVITY
+  if (player->gravity && !player->programmed_action)
+#else
   if (game.gravity && !player->programmed_action)
+#endif
   {
     int jx = player->jx, jy = player->jy;
     boolean field_under_player_is_free =
@@ -9851,48 +10422,60 @@ static void CheckGravityMovementWhenNotMoving(struct PlayerInfo *player)
 boolean MovePlayerOneStep(struct PlayerInfo *player,
                          int dx, int dy, int real_dx, int real_dy)
 {
-#if 0
-  static int trigger_sides[4][2] =
-  {
-    /* enter side        leave side */
-    { CH_SIDE_RIGHT,   CH_SIDE_LEFT    },      /* moving left  */
-    { CH_SIDE_LEFT,    CH_SIDE_RIGHT   },      /* moving right */
-    { CH_SIDE_BOTTOM,  CH_SIDE_TOP     },      /* moving up    */
-    { CH_SIDE_TOP,     CH_SIDE_BOTTOM  }       /* moving down  */
-  };
-  int move_direction = (dx == -1 ? MV_LEFT :
-                       dx == +1 ? MV_RIGHT :
-                       dy == -1 ? MV_UP :
-                       dy == +1 ? MV_DOWN : MV_NO_MOVING);
-  int enter_side = trigger_sides[MV_DIR_BIT(move_direction)][0];
-  int leave_side = trigger_sides[MV_DIR_BIT(move_direction)][1];
-#endif
   int jx = player->jx, jy = player->jy;
   int new_jx = jx + dx, new_jy = jy + dy;
+#if !USE_FIXED_DONT_RUN_INTO
   int element;
+#endif
   int can_move;
+  boolean player_can_move = !player->cannot_move;
 
   if (!player->active || (!dx && !dy))
-    return MF_NO_ACTION;
+    return MP_NO_ACTION;
 
   player->MovDir = (dx < 0 ? MV_LEFT :
                    dx > 0 ? MV_RIGHT :
                    dy < 0 ? MV_UP :
-                   dy > 0 ? MV_DOWN :  MV_NO_MOVING);
+                   dy > 0 ? MV_DOWN :  MV_NONE);
 
   if (!IN_LEV_FIELD(new_jx, new_jy))
-    return MF_NO_ACTION;
+    return MP_NO_ACTION;
 
-  if (!options.network && !AllPlayersInSight(player, new_jx, new_jy))
-    return MF_NO_ACTION;
+  if (!player_can_move)
+  {
+#if 1
+    if (player->MovPos == 0)
+    {
+      player->is_moving = FALSE;
+      player->is_digging = FALSE;
+      player->is_collecting = FALSE;
+      player->is_snapping = FALSE;
+      player->is_pushing = FALSE;
+    }
+#else
+    DigField(player, 0, 0, 0, 0, 0, 0, DF_NO_PUSH);
+    SnapField(player, 0, 0);
+#endif
 
 #if 0
-  element = MovingOrBlocked2Element(new_jx, new_jy);
+    return MP_NO_ACTION;
+#endif
+  }
+
+#if 1
+  if (!options.network && game.centered_player_nr == -1 &&
+      !AllPlayersInSight(player, new_jx, new_jy))
+    return MP_NO_ACTION;
 #else
-  element = MovingOrBlocked2ElementIfNotLeaving(new_jx, new_jy);
+  if (!options.network && !AllPlayersInSight(player, new_jx, new_jy))
+    return MP_NO_ACTION;
 #endif
 
-  if (DONT_RUN_INTO(element))
+#if !USE_FIXED_DONT_RUN_INTO
+  element = MovingOrBlocked2ElementIfNotLeaving(new_jx, new_jy);
+
+  /* (moved to DigField()) */
+  if (player_can_move && DONT_RUN_INTO(element))
   {
     if (element == EL_ACID && dx == 0 && dy == 1)
     {
@@ -9901,21 +10484,31 @@ boolean MovePlayerOneStep(struct PlayerInfo *player,
       InitMovingField(jx, jy, MV_DOWN);
       Store[jx][jy] = EL_ACID;
       ContinueMoving(jx, jy);
-      BuryHero(player);
+      BuryPlayer(player);
     }
     else
-      TestIfHeroRunsIntoBadThing(jx, jy, player->MovDir);
+      TestIfPlayerRunsIntoBadThing(jx, jy, player->MovDir);
 
-    return MF_MOVING;
+    return MP_MOVING;
   }
+#endif
 
   can_move = DigField(player, jx, jy, new_jx, new_jy, real_dx,real_dy, DF_DIG);
-  if (can_move != MF_MOVING)
+#if 0
+#if USE_FIXED_DONT_RUN_INTO
+  if (can_move == MP_DONT_RUN_INTO)
+    return MP_MOVING;
+#endif
+#endif
+  if (can_move != MP_MOVING)
     return can_move;
 
+#if USE_FIXED_DONT_RUN_INTO
+#endif
+
   /* check if DigField() has caused relocation of the player */
   if (player->jx != jx || player->jy != jy)
-    return MF_NO_ACTION;       /* <-- !!! CHECK THIS [-> MF_ACTION ?] !!! */
+    return MP_NO_ACTION;       /* <-- !!! CHECK THIS [-> MP_ACTION ?] !!! */
 
   StorePlayer[jx][jy] = 0;
   player->last_jx = jx;
@@ -9924,46 +10517,30 @@ boolean MovePlayerOneStep(struct PlayerInfo *player,
   player->jy = new_jy;
   StorePlayer[new_jx][new_jy] = player->element_nr;
 
+  if (player->move_delay_value_next != -1)
+  {
+    player->move_delay_value = player->move_delay_value_next;
+    player->move_delay_value_next = -1;
+  }
+
   player->MovPos =
     (dx > 0 || dy > 0 ? -1 : 1) * (TILEX - TILEX / player->move_delay_value);
 
   player->step_counter++;
 
-#if 0
-  player->drop_delay = 0;
-#endif
-
   PlayerVisit[jx][jy] = FrameCounter;
 
   ScrollPlayer(player, SCROLL_INIT);
 
-#if 0
-  if (IS_CUSTOM_ELEMENT(Feld[jx][jy]))
-  {
-    CheckTriggeredElementChangeBySide(jx, jy, Feld[jx][jy], CE_PLAYER_LEAVES_X,
-                                     leave_side);
-    CheckElementChangeBySide(jx,jy, Feld[jx][jy],CE_LEFT_BY_PLAYER,leave_side);
-  }
-
-  if (IS_CUSTOM_ELEMENT(Feld[new_jx][new_jy]))
-  {
-    CheckTriggeredElementChangeBySide(new_jx, new_jy, Feld[new_jx][new_jy],
-                                     CE_PLAYER_ENTERS_X, enter_side);
-    CheckElementChangeBySide(new_jx, new_jy, Feld[new_jx][new_jy],
-                            CE_ENTERED_BY_PLAYER, enter_side);
-  }
-#endif
-
-  return MF_MOVING;
+  return MP_MOVING;
 }
 
 boolean MovePlayer(struct PlayerInfo *player, int dx, int dy)
 {
   int jx = player->jx, jy = player->jy;
   int old_jx = jx, old_jy = jy;
-  int moved = MF_NO_ACTION;
+  int moved = MP_NO_ACTION;
 
-#if 1
   if (!player->active)
     return FALSE;
 
@@ -9980,54 +10557,14 @@ boolean MovePlayer(struct PlayerInfo *player, int dx, int dy)
 
     return FALSE;
   }
-#else
-  if (!player->active || (!dx && !dy))
-    return FALSE;
-#endif
-
-#if 0
-  if (!FrameReached(&player->move_delay, player->move_delay_value) &&
-      !tape.playing)
-    return FALSE;
-#else
 
-#if 1
-
-#if 0
-  printf("::: %d <= %d < %d ?\n", player->move_delay, FrameCounter,
-        player->move_delay + player->move_delay_value);
-#endif
-
-#if USE_NEW_MOVE_DELAY
   if (player->move_delay > 0)
-#else
-  if (!FrameReached(&player->move_delay, player->move_delay_value))
-#endif
-  {
-#if 0
-    printf("::: can NOT move\n");
-#endif
-
-    return FALSE;
-  }
-#else
-  if (!FrameReached(&player->move_delay, player->move_delay_value) &&
-      !(tape.playing && tape.file_version < FILE_VERSION_2_0))
     return FALSE;
-#endif
-
-#endif
-
-#if 0
-  printf("::: COULD move now\n");
-#endif
 
-#if USE_NEW_MOVE_DELAY
   player->move_delay = -1;             /* set to "uninitialized" value */
-#endif
 
   /* store if player is automatically moved to next field */
-  player->is_auto_moving = (player->programmed_action != MV_NO_MOVING);
+  player->is_auto_moving = (player->programmed_action != MV_NONE);
 
   /* remove the last programmed player action */
   player->programmed_action = 0;
@@ -10052,11 +10589,7 @@ boolean MovePlayer(struct PlayerInfo *player, int dx, int dy)
       ScrollPlayer(player, SCROLL_GO_ON);
       ScrollScreen(NULL, SCROLL_GO_ON);
 
-#if USE_NEW_MOVE_DELAY
-      AdvanceFrameAndPlayerCounters(player->index_nr);
-#else
-      FrameCounter++;
-#endif
+      AdvanceFrameAndPlayerCounters(player->index_nr);
 
       DrawAllPlayers();
       BackToFront();
@@ -10065,6 +10598,8 @@ boolean MovePlayer(struct PlayerInfo *player, int dx, int dy)
     player->move_delay_value = original_move_delay_value;
   }
 
+  player->is_active = FALSE;
+
   if (player->last_move_dir & MV_HORIZONTAL)
   {
     if (!(moved |= MovePlayerOneStep(player, 0, dy, dx, dy)))
@@ -10076,11 +10611,28 @@ boolean MovePlayer(struct PlayerInfo *player, int dx, int dy)
       moved |= MovePlayerOneStep(player, 0, dy, dx, dy);
   }
 
+#if USE_FIXED_BORDER_RUNNING_GFX
+  if (!moved && !player->is_active)
+  {
+    player->is_moving = FALSE;
+    player->is_digging = FALSE;
+    player->is_collecting = FALSE;
+    player->is_snapping = FALSE;
+    player->is_pushing = FALSE;
+  }
+#endif
+
   jx = player->jx;
   jy = player->jy;
 
-  if (moved & MF_MOVING && !ScreenMovPos &&
+#if 1
+  if (moved & MP_MOVING && !ScreenMovPos &&
+      (player->index_nr == game.centered_player_nr ||
+       game.centered_player_nr == -1))
+#else
+  if (moved & MP_MOVING && !ScreenMovPos &&
       (player == local_player || !options.network))
+#endif
   {
     int old_scroll_x = scroll_x, old_scroll_y = scroll_y;
     int offset = (setup.scroll_delay ? 3 : 0);
@@ -10135,12 +10687,22 @@ boolean MovePlayer(struct PlayerInfo *player, int dx, int dy)
 
     if (scroll_x != old_scroll_x || scroll_y != old_scroll_y)
     {
+#if 1
+      if (!options.network && game.centered_player_nr == -1 &&
+         !AllPlayersInVisibleScreen())
+      {
+       scroll_x = old_scroll_x;
+       scroll_y = old_scroll_y;
+      }
+      else
+#else
       if (!options.network && !AllPlayersInVisibleScreen())
       {
        scroll_x = old_scroll_x;
        scroll_y = old_scroll_y;
       }
       else
+#endif
       {
        ScrollScreen(player, SCROLL_INIT);
        ScrollLevel(old_scroll_x - scroll_x, old_scroll_y - scroll_y);
@@ -10148,23 +10710,10 @@ boolean MovePlayer(struct PlayerInfo *player, int dx, int dy)
     }
   }
 
-#if 0
-#if 1
-  InitPlayerGfxAnimation(player, ACTION_DEFAULT);
-#else
-  if (!(moved & MF_MOVING) && !player->is_pushing)
-    player->Frame = 0;
-#endif
-#endif
-
   player->StepFrame = 0;
 
-  if (moved & MF_MOVING)
+  if (moved & MP_MOVING)
   {
-#if 0
-    printf("::: REALLY moves now\n");
-#endif
-
     if (old_jx != jx && old_jy == jy)
       player->MovDir = (old_jx < jx ? MV_RIGHT : MV_LEFT);
     else if (old_jx == jx && old_jy != jy)
@@ -10174,101 +10723,38 @@ boolean MovePlayer(struct PlayerInfo *player, int dx, int dy)
 
     player->last_move_dir = player->MovDir;
     player->is_moving = TRUE;
-#if 1
     player->is_snapping = FALSE;
-#endif
-
-#if 1
     player->is_switching = FALSE;
-#endif
-
     player->is_dropping = FALSE;
-
-
-#if 0
-    /* !!! ENABLE THIS FOR OLD VERSIONS !!! */
-
-#if 1
-    if (game.engine_version < VERSION_IDENT(3,1,0,0))
-#endif
-    {
-      int move_direction = player->MovDir;
-#if 1
-      int enter_side = MV_DIR_OPPOSITE(move_direction);
-      int leave_side = move_direction;
-#else
-      static int trigger_sides[4][2] =
-      {
-       /* enter side           leave side */
-       { CH_SIDE_RIGHT,        CH_SIDE_LEFT    },      /* moving left  */
-       { CH_SIDE_LEFT,         CH_SIDE_RIGHT   },      /* moving right */
-       { CH_SIDE_BOTTOM,       CH_SIDE_TOP     },      /* moving up    */
-       { CH_SIDE_TOP,          CH_SIDE_BOTTOM  }       /* moving down  */
-      };
-      int enter_side = trigger_sides[MV_DIR_BIT(move_direction)][0];
-      int leave_side = trigger_sides[MV_DIR_BIT(move_direction)][1];
-#endif
-      int old_element = Feld[old_jx][old_jy];
-      int new_element = Feld[jx][jy];
-
-#if 1
-      /* !!! TEST ONLY !!! */
-      if (IS_CUSTOM_ELEMENT(old_element))
-       CheckElementChangeByPlayer(old_jx, old_jy, old_element,
-                                  CE_LEFT_BY_PLAYER,
-                                  player->index_bit, leave_side);
-
-      CheckTriggeredElementChangeByPlayer(old_jx, old_jy, old_element,
-                                         CE_PLAYER_LEAVES_X,
-                                         player->index_bit, leave_side);
-
-      if (IS_CUSTOM_ELEMENT(new_element))
-       CheckElementChangeByPlayer(jx, jy, new_element, CE_ENTERED_BY_PLAYER,
-                                  player->index_bit, enter_side);
-
-      CheckTriggeredElementChangeByPlayer(jx, jy, new_element,
-                                         CE_PLAYER_ENTERS_X,
-                                         player->index_bit, enter_side);
-#endif
-
-    }
-#endif
-
-
+    player->is_dropping_pressed = FALSE;
+    player->drop_pressed_delay = 0;
   }
   else
   {
     CheckGravityMovementWhenNotMoving(player);
 
-    /*
-    player->last_move_dir = MV_NO_MOVING;
-    */
     player->is_moving = FALSE;
 
-#if USE_NEW_MOVE_STYLE
-    /* player is ALLOWED to move, but CANNOT move (something blocks his way) */
-    /* ensure that the player is also allowed to move in the next frame */
-    /* (currently, the player is forced to wait eight frames before he can try
-       again!!!) */
+    /* at this point, the player is allowed to move, but cannot move right now
+       (e.g. because of something blocking the way) -- ensure that the player
+       is also allowed to move in the next frame (in old versions before 3.1.1,
+       the player was forced to wait again for eight frames before next try) */
 
     if (game.engine_version >= VERSION_IDENT(3,1,1,0))
       player->move_delay = 0;  /* allow direct movement in the next frame */
-#endif
   }
 
-#if USE_NEW_MOVE_DELAY
   if (player->move_delay == -1)                /* not yet initialized by DigField() */
     player->move_delay = player->move_delay_value;
-#endif
 
   if (game.engine_version < VERSION_IDENT(3,0,7,0))
   {
-    TestIfHeroTouchesBadThing(jx, jy);
+    TestIfPlayerTouchesBadThing(jx, jy);
     TestIfPlayerTouchesCustomElement(jx, jy);
   }
 
   if (!player->active)
-    RemoveHero(player);
+    RemovePlayer(player);
 
   return moved;
 }
@@ -10279,28 +10765,22 @@ void ScrollPlayer(struct PlayerInfo *player, int mode)
   int last_jx = player->last_jx, last_jy = player->last_jy;
   int move_stepsize = TILEX / player->move_delay_value;
 
-  if (!player->active || !player->MovPos)
+#if USE_NEW_PLAYER_SPEED
+  if (!player->active)
+    return;
+
+  if (player->MovPos == 0 && mode == SCROLL_GO_ON)     /* player not moving */
+    return;
+#else
+  if (!player->active || player->MovPos == 0)
     return;
+#endif
 
   if (mode == SCROLL_INIT)
   {
     player->actual_frame_counter = FrameCounter;
     player->GfxPos = move_stepsize * (player->MovPos / move_stepsize);
 
-#if 0
-    printf("::: %06d: %d,%d: %d (%d) [%d]\n",
-          FrameCounter,
-          last_jx, last_jy, Feld[last_jx][last_jy], EL_EXPLOSION,
-          player->block_delay);
-#endif
-
-#if USE_NEW_BLOCK_STYLE
-
-#if 0
-    if (player->block_delay <= 0)
-      printf("::: ALERT! block_delay == %d\n", player->block_delay);
-#endif
-
     if ((player->block_last_field || player->block_delay_adjustment > 0) &&
        Feld[last_jx][last_jy] == EL_EMPTY)
     {
@@ -10312,8 +10792,11 @@ void ScrollPlayer(struct PlayerInfo *player, int mode)
       {
        last_field_block_delay += player->move_delay_value;
 
-#if USE_GRAVITY_BUGFIX_NEW
        /* when blocking enabled, prevent moving up despite gravity */
+#if USE_PLAYER_GRAVITY
+       if (player->gravity && player->MovDir == MV_UP)
+         block_delay_adjustment = -1;
+#else
        if (game.gravity && player->MovDir == MV_UP)
          block_delay_adjustment = -1;
 #endif
@@ -10322,74 +10805,51 @@ void ScrollPlayer(struct PlayerInfo *player, int mode)
       /* add block delay adjustment (also possible when not blocking) */
       last_field_block_delay += block_delay_adjustment;
 
-#if 0
-#if USE_BLOCK_DELAY_BUGFIX
-      /* when blocking enabled, correct block delay for fast movement */
-      if (player->block_last_field &&
-         player->move_delay_value < MOVE_DELAY_NORMAL_SPEED)
-       last_field_block_delay =
-         player->move_delay_value + player->block_delay_adjustment;
-#endif
-#endif
-
-#if 0
-#if USE_GRAVITY_BUGFIX_NEW
-      /* when blocking enabled, correct block delay for gravity movement */
-      if (player->block_last_field &&
-         game.gravity && player->MovDir == MV_UP)
-       last_field_block_delay = player->move_delay_value - 1;
-#endif
-#endif
-
       Feld[last_jx][last_jy] = EL_PLAYER_IS_LEAVING;
       MovDelay[last_jx][last_jy] = last_field_block_delay + 1;
     }
+
+#if USE_NEW_PLAYER_SPEED
+    if (player->MovPos != 0)   /* player has not yet reached destination */
+      return;
 #else
-#if USE_NEW_MOVE_STYLE
-    if ((game.engine_version < VERSION_IDENT(3,1,1,0) ||
-        player->block_last_field) &&
-       Feld[last_jx][last_jy] == EL_EMPTY)
-      Feld[last_jx][last_jy] = EL_PLAYER_IS_LEAVING;
-#else
-    if (Feld[last_jx][last_jy] == EL_EMPTY)
-      Feld[last_jx][last_jy] = EL_PLAYER_IS_LEAVING;
-#endif
+    return;
 #endif
+  }
+  else if (!FrameReached(&player->actual_frame_counter, 1))
+    return;
 
 #if 0
-    DrawPlayer(player);
+  printf("::: player->MovPos: %d -> %d\n",
+        player->MovPos,
+        player->MovPos + (player->MovPos > 0 ? -1 : 1) * move_stepsize);
 #endif
 
-    return;
-  }
-  else if (!FrameReached(&player->actual_frame_counter, 1))
-    return;
+#if USE_NEW_PLAYER_SPEED
+  if (player->MovPos != 0)
+  {
+    player->MovPos += (player->MovPos > 0 ? -1 : 1) * move_stepsize;
+    player->GfxPos = move_stepsize * (player->MovPos / move_stepsize);
 
+    /* before DrawPlayer() to draw correct player graphic for this case */
+    if (player->MovPos == 0)
+      CheckGravityMovement(player);
+  }
+#else
   player->MovPos += (player->MovPos > 0 ? -1 : 1) * move_stepsize;
   player->GfxPos = move_stepsize * (player->MovPos / move_stepsize);
 
-#if USE_NEW_BLOCK_STYLE
-#else
-  if (!player->block_last_field &&
-      Feld[last_jx][last_jy] == EL_PLAYER_IS_LEAVING)
-#if 1
-    RemoveField(last_jx, last_jy);
-#else
-    Feld[last_jx][last_jy] = EL_EMPTY;
-#endif
-#endif
-
   /* before DrawPlayer() to draw correct player graphic for this case */
   if (player->MovPos == 0)
     CheckGravityMovement(player);
-
-#if 0
-  DrawPlayer(player);  /* needed here only to cleanup last field */
 #endif
 
   if (player->MovPos == 0)     /* player reached destination field */
   {
-#if 1
+#if 0
+    printf("::: player reached destination field\n");
+#endif
+
     if (player->move_delay_reset_counter > 0)
     {
       player->move_delay_reset_counter--;
@@ -10403,27 +10863,6 @@ void ScrollPlayer(struct PlayerInfo *player, int mode)
        player->move_delay = 0;
       }
     }
-#else
-    if (IS_PASSABLE(Feld[last_jx][last_jy]))
-    {
-      /* continue with normal speed after quickly moving through gate */
-      HALVE_PLAYER_SPEED(player);
-
-      /* be able to make the next move without delay */
-      player->move_delay = 0;
-    }
-#endif
-
-#if USE_NEW_BLOCK_STYLE
-#else
-    if (player->block_last_field &&
-       Feld[last_jx][last_jy] == EL_PLAYER_IS_LEAVING)
-#if 1
-      RemoveField(last_jx, last_jy);
-#else
-      Feld[last_jx][last_jy] = EL_EMPTY;
-#endif
-#endif
 
     player->last_jx = jx;
     player->last_jy = jy;
@@ -10433,43 +10872,23 @@ void ScrollPlayer(struct PlayerInfo *player, int mode)
        Feld[jx][jy] == EL_SP_EXIT_OPENING)     /* <-- special case */
     {
       DrawPlayer(player);      /* needed here only to cleanup last field */
-      RemoveHero(player);
+      RemovePlayer(player);
 
       if (local_player->friends_still_needed == 0 ||
          IS_SP_ELEMENT(Feld[jx][jy]))
        player->LevelSolved = player->GameOver = TRUE;
     }
 
-#if 1
-    /* !!! ENABLE THIS FOR NEW VERSIONS !!! */
     /* this breaks one level: "machine", level 000 */
-#if 0
-    if (game.engine_version >= VERSION_IDENT(3,1,0,0))
-#endif
     {
       int move_direction = player->MovDir;
-#if 1
       int enter_side = MV_DIR_OPPOSITE(move_direction);
       int leave_side = move_direction;
-#else
-      static int trigger_sides[4][2] =
-      {
-       /* enter side           leave side */
-       { CH_SIDE_RIGHT,        CH_SIDE_LEFT    },      /* moving left  */
-       { CH_SIDE_LEFT,         CH_SIDE_RIGHT   },      /* moving right */
-       { CH_SIDE_BOTTOM,       CH_SIDE_TOP     },      /* moving up    */
-       { CH_SIDE_TOP,          CH_SIDE_BOTTOM  }       /* moving down  */
-      };
-      int enter_side = trigger_sides[MV_DIR_BIT(move_direction)][0];
-      int leave_side = trigger_sides[MV_DIR_BIT(move_direction)][1];
-#endif
       int old_jx = last_jx;
       int old_jy = last_jy;
       int old_element = Feld[old_jx][old_jy];
       int new_element = Feld[jx][jy];
 
-#if 1
-      /* !!! TEST ONLY !!! */
       if (IS_CUSTOM_ELEMENT(old_element))
        CheckElementChangeByPlayer(old_jx, old_jy, old_element,
                                   CE_LEFT_BY_PLAYER,
@@ -10486,26 +10905,23 @@ void ScrollPlayer(struct PlayerInfo *player, int mode)
       CheckTriggeredElementChangeByPlayer(jx, jy, new_element,
                                          CE_PLAYER_ENTERS_X,
                                          player->index_bit, enter_side);
-#endif
 
+      CheckTriggeredElementChangeBySide(jx, jy, player->element_nr,
+                                       CE_MOVE_OF_X, move_direction);
     }
-#endif
 
     if (game.engine_version >= VERSION_IDENT(3,0,7,0))
     {
-      TestIfHeroTouchesBadThing(jx, jy);
+      TestIfPlayerTouchesBadThing(jx, jy);
       TestIfPlayerTouchesCustomElement(jx, jy);
-#if 1
-#if 1
+
       /* needed because pushed element has not yet reached its destination,
         so it would trigger a change event at its previous field location */
       if (!player->is_pushing)
-#endif
        TestIfElementTouchesCustomElement(jx, jy);      /* for empty space */
-#endif
 
       if (!player->active)
-       RemoveHero(player);
+       RemovePlayer(player);
     }
 
     if (level.use_step_counter)
@@ -10525,7 +10941,7 @@ void ScrollPlayer(struct PlayerInfo *player, int mode)
 
        if (!TimeLeft && setup.time_limit)
          for (i = 0; i < MAX_PLAYERS; i++)
-           KillHero(&stored_player[i]);
+           KillPlayer(&stored_player[i]);
       }
       else if (level.time == 0 && !AllPlayersGone) /* level w/o time limit */
        DrawGameValue_Time(TimePlayed);
@@ -10562,7 +10978,7 @@ void ScrollScreen(struct PlayerInfo *player, int mode)
     redraw_mask |= REDRAW_FIELD;
   }
   else
-    ScreenMovDir = MV_NO_MOVING;
+    ScreenMovDir = MV_NONE;
 }
 
 void TestIfPlayerTouchesCustomElement(int x, int y)
@@ -10616,20 +11032,11 @@ void TestIfPlayerTouchesCustomElement(int x, int y)
       else
        continue;               /* center and border element do not touch */
 
-#if 1
-      /* !!! TEST ONLY !!! */
       CheckElementChangeByPlayer(xx, yy, border_element, CE_TOUCHED_BY_PLAYER,
                                 player->index_bit, border_side);
       CheckTriggeredElementChangeByPlayer(xx, yy, border_element,
                                          CE_PLAYER_TOUCHES_X,
                                          player->index_bit, border_side);
-#else
-      CheckTriggeredElementChangeByPlayer(xx, yy, border_element,
-                                         CE_PLAYER_TOUCHES_X,
-                                         player->index_bit, border_side);
-      CheckElementChangeByPlayer(xx, yy, border_element, CE_TOUCHED_BY_PLAYER,
-                                player->index_bit, border_side);
-#endif
     }
     else if (IS_PLAYER(xx, yy))
     {
@@ -10641,27 +11048,104 @@ void TestIfPlayerTouchesCustomElement(int x, int y)
          continue;             /* center and border element do not touch */
       }
 
-#if 1
-      /* !!! TEST ONLY !!! */
       CheckElementChangeByPlayer(x, y, center_element, CE_TOUCHED_BY_PLAYER,
                                 player->index_bit, center_side);
       CheckTriggeredElementChangeByPlayer(x, y, center_element,
                                          CE_PLAYER_TOUCHES_X,
                                          player->index_bit, center_side);
-#else
-      CheckTriggeredElementChangeByPlayer(x, y, center_element,
-                                         CE_PLAYER_TOUCHES_X,
-                                         player->index_bit, center_side);
-      CheckElementChangeByPlayer(x, y, center_element, CE_TOUCHED_BY_PLAYER,
-                                player->index_bit, center_side);
-#endif
+      break;
+    }
+  }
+}
+
+#if USE_ELEMENT_TOUCHING_BUGFIX
+
+void TestIfElementTouchesCustomElement(int x, int y)
+{
+  static int xy[4][2] =
+  {
+    { 0, -1 },
+    { -1, 0 },
+    { +1, 0 },
+    { 0, +1 }
+  };
+  static int trigger_sides[4][2] =
+  {
+    /* center side     border side */
+    { CH_SIDE_TOP,     CH_SIDE_BOTTOM  },      /* check top    */
+    { CH_SIDE_LEFT,    CH_SIDE_RIGHT   },      /* check left   */
+    { CH_SIDE_RIGHT,   CH_SIDE_LEFT    },      /* check right  */
+    { CH_SIDE_BOTTOM,  CH_SIDE_TOP     }       /* check bottom */
+  };
+  static int touch_dir[4] =
+  {
+    MV_LEFT | MV_RIGHT,
+    MV_UP   | MV_DOWN,
+    MV_UP   | MV_DOWN,
+    MV_LEFT | MV_RIGHT
+  };
+  boolean change_center_element = FALSE;
+  int center_element = Feld[x][y];     /* should always be non-moving! */
+  int border_element_old[NUM_DIRECTIONS];
+  int i;
+
+  for (i = 0; i < NUM_DIRECTIONS; i++)
+  {
+    int xx = x + xy[i][0];
+    int yy = y + xy[i][1];
+    int border_element;
+
+    border_element_old[i] = -1;
+
+    if (!IN_LEV_FIELD(xx, yy))
+      continue;
+
+    if (game.engine_version < VERSION_IDENT(3,0,7,0))
+      border_element = Feld[xx][yy];   /* may be moving! */
+    else if (!IS_MOVING(xx, yy) && !IS_BLOCKED(xx, yy))
+      border_element = Feld[xx][yy];
+    else if (MovDir[xx][yy] & touch_dir[i])    /* elements are touching */
+      border_element = MovingOrBlocked2Element(xx, yy);
+    else
+      continue;                        /* center and border element do not touch */
+
+    border_element_old[i] = border_element;
+  }
+
+  for (i = 0; i < NUM_DIRECTIONS; i++)
+  {
+    int xx = x + xy[i][0];
+    int yy = y + xy[i][1];
+    int center_side = trigger_sides[i][0];
+    int border_element = border_element_old[i];
+
+    if (border_element == -1)
+      continue;
+
+    /* check for change of border element */
+    CheckElementChangeBySide(xx, yy, border_element, center_element,
+                            CE_TOUCHING_X, center_side);
+  }
+
+  for (i = 0; i < NUM_DIRECTIONS; i++)
+  {
+    int border_side = trigger_sides[i][1];
+    int border_element = border_element_old[i];
+
+    if (border_element == -1)
+      continue;
 
-      break;
-    }
+    /* check for change of center element (but change it only once) */
+    if (!change_center_element)
+      change_center_element =
+       CheckElementChangeBySide(x, y, center_element, border_element,
+                                CE_TOUCHING_X, border_side);
   }
 }
 
-void TestIfElementTouchesCustomElement(int x, int y)
+#else
+
+void TestIfElementTouchesCustomElement_OLD(int x, int y)
 {
   static int xy[4][2] =
   {
@@ -10686,10 +11170,8 @@ void TestIfElementTouchesCustomElement(int x, int y)
     MV_LEFT | MV_RIGHT
   };
   boolean change_center_element = FALSE;
-  int center_element_change_page = 0;
   int center_element = Feld[x][y];     /* should always be non-moving! */
-  int border_trigger_element = EL_UNDEFINED;
-  int i, j;
+  int i;
 
   for (i = 0; i < NUM_DIRECTIONS; i++)
   {
@@ -10712,76 +11194,19 @@ void TestIfElementTouchesCustomElement(int x, int y)
       continue;                        /* center and border element do not touch */
 
     /* check for change of center element (but change it only once) */
-    if (IS_CUSTOM_ELEMENT(center_element) &&
-       HAS_ANY_CHANGE_EVENT(center_element, CE_TOUCHING_X) &&
-       !change_center_element)
-    {
-      for (j = 0; j < element_info[center_element].num_change_pages; j++)
-      {
-       struct ElementChangeInfo *change =
-         &element_info[center_element].change_page[j];
-
-       if (change->can_change &&
-           change->has_event[CE_TOUCHING_X] &&
-           change->trigger_side & border_side &&
-#if 1
-           IS_EQUAL_OR_IN_GROUP(border_element, change->trigger_element)
-#else
-           change->trigger_element == border_element
-#endif
-           )
-       {
-         change_center_element = TRUE;
-         center_element_change_page = j;
-         border_trigger_element = border_element;
-
-         break;
-       }
-      }
-    }
+    if (!change_center_element)
+      change_center_element =
+       CheckElementChangeBySide(x, y, center_element, border_element,
+                                CE_TOUCHING_X, border_side);
 
     /* check for change of border element */
-    if (IS_CUSTOM_ELEMENT(border_element) &&
-       HAS_ANY_CHANGE_EVENT(border_element, CE_TOUCHING_X))
-    {
-      for (j = 0; j < element_info[border_element].num_change_pages; j++)
-      {
-       struct ElementChangeInfo *change =
-         &element_info[border_element].change_page[j];
-
-       if (change->can_change &&
-           change->has_event[CE_TOUCHING_X] &&
-           change->trigger_side & center_side &&
-#if 1
-           IS_EQUAL_OR_IN_GROUP(center_element, change->trigger_element)
-#else
-           change->trigger_element == center_element
-#endif
-           )
-       {
-#if 0
-         printf("::: border_element %d, %d\n", x, y);
-#endif
-
-         CheckElementChangeByPage(xx, yy, border_element, center_element,
-                                  CE_TOUCHING_X, j);
-         break;
-       }
-      }
-    }
+    CheckElementChangeBySide(xx, yy, border_element, center_element,
+                            CE_TOUCHING_X, center_side);
   }
+}
 
-  if (change_center_element)
-  {
-#if 0
-    printf("::: center_element %d, %d\n", x, y);
 #endif
 
-    CheckElementChangeByPage(x, y, center_element, border_trigger_element,
-                            CE_TOUCHING_X, center_element_change_page);
-  }
-}
-
 void TestIfElementHitsCustomElement(int x, int y, int direction)
 {
   int dx = (direction == MV_LEFT ? -1 : direction == MV_RIGHT ? +1 : 0);
@@ -10789,119 +11214,40 @@ void TestIfElementHitsCustomElement(int x, int y, int direction)
   int hitx = x + dx, hity = y + dy;
   int hitting_element = Feld[x][y];
   int touched_element;
-#if 0
-  boolean object_hit = (IN_LEV_FIELD(hitx, hity) &&
-                       !IS_FREE(hitx, hity) &&
-                       (!IS_MOVING(hitx, hity) ||
-                        MovDir[hitx][hity] != direction ||
-                        ABS(MovPos[hitx][hity]) <= TILEY / 2));
-#endif
 
   if (IN_LEV_FIELD(hitx, hity) && IS_FREE(hitx, hity))
     return;
 
-#if 0
-  if (IN_LEV_FIELD(hitx, hity) && !object_hit)
-    return;
-#endif
-
   touched_element = (IN_LEV_FIELD(hitx, hity) ?
                     MovingOrBlocked2Element(hitx, hity) : EL_STEELWALL);
 
-#if !USE_HITTING_SOMETHING_BUGFIX
-  /* "hitting something" is also true when hitting the playfield border */
-  CheckElementChangeBySide(x, y, hitting_element, touched_element,
-                          CE_HITTING_SOMETHING, direction);
-#endif
-
   if (IN_LEV_FIELD(hitx, hity))
   {
     int opposite_direction = MV_DIR_OPPOSITE(direction);
     int hitting_side = direction;
     int touched_side = opposite_direction;
-#if 0
-    int touched_element = MovingOrBlocked2Element(hitx, hity);
-#endif
-#if 1
     boolean object_hit = (!IS_MOVING(hitx, hity) ||
                          MovDir[hitx][hity] != direction ||
                          ABS(MovPos[hitx][hity]) <= TILEY / 2);
 
     object_hit = TRUE;
-#endif
 
     if (object_hit)
     {
-      int i;
-
-#if !USE_HIT_BY_SOMETHING_BUGFIX
-      CheckElementChangeBySide(hitx, hity, touched_element, hitting_element,
-                              CE_HIT_BY_SOMETHING, opposite_direction);
-#endif
-
-      if (IS_CUSTOM_ELEMENT(hitting_element) &&
-         HAS_ANY_CHANGE_EVENT(hitting_element, CE_HITTING_X))
-      {
-       for (i = 0; i < element_info[hitting_element].num_change_pages; i++)
-       {
-         struct ElementChangeInfo *change =
-           &element_info[hitting_element].change_page[i];
-
-         if (change->can_change &&
-             change->has_event[CE_HITTING_X] &&
-             change->trigger_side & touched_side &&
-         
-#if 1
-             IS_EQUAL_OR_IN_GROUP(touched_element, change->trigger_element)
-#else
-             change->trigger_element == touched_element
-#endif
-             )
-         {
-           CheckElementChangeByPage(x, y, hitting_element, touched_element,
-                                    CE_HITTING_X, i);
-           break;
-         }
-       }
-      }
-
-      if (IS_CUSTOM_ELEMENT(touched_element) &&
-         HAS_ANY_CHANGE_EVENT(touched_element, CE_HIT_BY_X))
-      {
-       for (i = 0; i < element_info[touched_element].num_change_pages; i++)
-       {
-         struct ElementChangeInfo *change =
-           &element_info[touched_element].change_page[i];
+      CheckElementChangeBySide(x, y, hitting_element, touched_element,
+                              CE_HITTING_X, touched_side);
 
-         if (change->can_change &&
-             change->has_event[CE_HIT_BY_X] &&
-             change->trigger_side & hitting_side &&
-#if 1
-             IS_EQUAL_OR_IN_GROUP(hitting_element, change->trigger_element)
-#else
-             change->trigger_element == hitting_element
-#endif
-             )
-         {
-           CheckElementChangeByPage(hitx, hity, touched_element,
-                                    hitting_element, CE_HIT_BY_X, i);
-           break;
-         }
-       }
-      }
+      CheckElementChangeBySide(hitx, hity, touched_element,
+                              hitting_element, CE_HIT_BY_X, hitting_side);
 
-#if USE_HIT_BY_SOMETHING_BUGFIX
       CheckElementChangeBySide(hitx, hity, touched_element, hitting_element,
                               CE_HIT_BY_SOMETHING, opposite_direction);
-#endif
     }
   }
 
-#if USE_HITTING_SOMETHING_BUGFIX
   /* "hitting something" is also true when hitting the playfield border */
   CheckElementChangeBySide(x, y, hitting_element, touched_element,
                           CE_HITTING_SOMETHING, direction);
-#endif
 }
 
 #if 0
@@ -10957,56 +11303,11 @@ void TestIfElementSmashesCustomElement(int x, int y, int direction)
       CheckElementChangeBySide(hitx, hity, touched_element, hitting_element,
                               CE_SMASHED_BY_SOMETHING, opposite_direction);
 
-      if (IS_CUSTOM_ELEMENT(hitting_element) &&
-         HAS_ANY_CHANGE_EVENT(hitting_element, CE_OTHER_IS_SMASHING))
-      {
-       for (i = 0; i < element_info[hitting_element].num_change_pages; i++)
-       {
-         struct ElementChangeInfo *change =
-           &element_info[hitting_element].change_page[i];
-
-         if (change->can_change &&
-             change->has_event[CE_OTHER_IS_SMASHING] &&
-             change->trigger_side & touched_side &&
-         
-#if 1
-             IS_EQUAL_OR_IN_GROUP(touched_element, change->trigger_element)
-#else
-             change->trigger_element == touched_element
-#endif
-             )
-         {
-           CheckElementChangeByPage(x, y, hitting_element, touched_element,
-                                    CE_OTHER_IS_SMASHING, i);
-           break;
-         }
-       }
-      }
-
-      if (IS_CUSTOM_ELEMENT(touched_element) &&
-         HAS_ANY_CHANGE_EVENT(touched_element, CE_OTHER_GETS_SMASHED))
-      {
-       for (i = 0; i < element_info[touched_element].num_change_pages; i++)
-       {
-         struct ElementChangeInfo *change =
-           &element_info[touched_element].change_page[i];
+      CheckElementChangeBySide(x, y, hitting_element, touched_element,
+                              CE_OTHER_IS_SMASHING, touched_side);
 
-         if (change->can_change &&
-             change->has_event[CE_OTHER_GETS_SMASHED] &&
-             change->trigger_side & hitting_side &&
-#if 1
-             IS_EQUAL_OR_IN_GROUP(hitting_element, change->trigger_element)
-#else
-             change->trigger_element == hitting_element
-#endif
-             )
-         {
-           CheckElementChangeByPage(hitx, hity, touched_element,
-                                    hitting_element, CE_OTHER_GETS_SMASHED,i);
-           break;
-         }
-       }
-      }
+      CheckElementChangeBySide(hitx, hity, touched_element, hitting_element,
+                              CE_OTHER_GETS_SMASHED, hitting_side);
     }
   }
 }
@@ -11015,6 +11316,7 @@ void TestIfElementSmashesCustomElement(int x, int y, int direction)
 void TestIfGoodThingHitsBadThing(int good_x, int good_y, int good_move_dir)
 {
   int i, kill_x = -1, kill_y = -1;
+
   int bad_element = -1;
   static int test_xy[4][2] =
   {
@@ -11042,13 +11344,9 @@ void TestIfGoodThingHitsBadThing(int good_x, int good_y, int good_move_dir)
       continue;
 
     test_move_dir =
-      (IS_MOVING(test_x, test_y) ? MovDir[test_x][test_y] : MV_NO_MOVING);
+      (IS_MOVING(test_x, test_y) ? MovDir[test_x][test_y] : MV_NONE);
 
-#if 0
-    test_element = Feld[test_x][test_y];
-#else
     test_element = MovingOrBlocked2ElementIfNotLeaving(test_x, test_y);
-#endif
 
     /* 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
@@ -11070,18 +11368,11 @@ void TestIfGoodThingHitsBadThing(int good_x, int good_y, int good_move_dir)
     {
       struct PlayerInfo *player = PLAYERINFO(good_x, good_y);
 
-#if 1
       if (player->shield_deadly_time_left > 0 &&
          !IS_INDESTRUCTIBLE(bad_element))
        Bang(kill_x, kill_y);
       else if (!PLAYER_ENEMY_PROTECTED(good_x, good_y))
-       KillHero(player);
-#else
-      if (player->shield_deadly_time_left > 0)
-       Bang(kill_x, kill_y);
-      else if (!PLAYER_ENEMY_PROTECTED(good_x, good_y))
-       KillHero(player);
-#endif
+       KillPlayer(player);
     }
     else
       Bang(good_x, good_y);
@@ -11127,7 +11418,7 @@ void TestIfBadThingHitsGoodThing(int bad_x, int bad_y, int bad_move_dir)
       continue;
 
     test_move_dir =
-      (IS_MOVING(test_x, test_y) ? MovDir[test_x][test_y] : MV_NO_MOVING);
+      (IS_MOVING(test_x, test_y) ? MovDir[test_x][test_y] : MV_NONE);
 
     test_element = Feld[test_x][test_y];
 
@@ -11170,52 +11461,45 @@ void TestIfBadThingHitsGoodThing(int bad_x, int bad_y, int bad_move_dir)
     {
       struct PlayerInfo *player = PLAYERINFO(kill_x, kill_y);
 
-#if 1
       if (player->shield_deadly_time_left > 0 &&
          !IS_INDESTRUCTIBLE(bad_element))
        Bang(bad_x, bad_y);
       else if (!PLAYER_ENEMY_PROTECTED(kill_x, kill_y))
-       KillHero(player);
-#else
-      if (player->shield_deadly_time_left > 0)
-       Bang(bad_x, bad_y);
-      else if (!PLAYER_ENEMY_PROTECTED(kill_x, kill_y))
-       KillHero(player);
-#endif
+       KillPlayer(player);
     }
     else
       Bang(kill_x, kill_y);
   }
 }
 
-void TestIfHeroTouchesBadThing(int x, int y)
+void TestIfPlayerTouchesBadThing(int x, int y)
 {
-  TestIfGoodThingHitsBadThing(x, y, MV_NO_MOVING);
+  TestIfGoodThingHitsBadThing(x, y, MV_NONE);
 }
 
-void TestIfHeroRunsIntoBadThing(int x, int y, int move_dir)
+void TestIfPlayerRunsIntoBadThing(int x, int y, int move_dir)
 {
   TestIfGoodThingHitsBadThing(x, y, move_dir);
 }
 
-void TestIfBadThingTouchesHero(int x, int y)
+void TestIfBadThingTouchesPlayer(int x, int y)
 {
-  TestIfBadThingHitsGoodThing(x, y, MV_NO_MOVING);
+  TestIfBadThingHitsGoodThing(x, y, MV_NONE);
 }
 
-void TestIfBadThingRunsIntoHero(int x, int y, int move_dir)
+void TestIfBadThingRunsIntoPlayer(int x, int y, int move_dir)
 {
   TestIfBadThingHitsGoodThing(x, y, move_dir);
 }
 
 void TestIfFriendTouchesBadThing(int x, int y)
 {
-  TestIfGoodThingHitsBadThing(x, y, MV_NO_MOVING);
+  TestIfGoodThingHitsBadThing(x, y, MV_NONE);
 }
 
 void TestIfBadThingTouchesFriend(int x, int y)
 {
-  TestIfBadThingHitsGoodThing(x, y, MV_NO_MOVING);
+  TestIfBadThingHitsGoodThing(x, y, MV_NONE);
 }
 
 void TestIfBadThingTouchesOtherBadThing(int bad_x, int bad_y)
@@ -11252,7 +11536,7 @@ void TestIfBadThingTouchesOtherBadThing(int bad_x, int bad_y)
     Bang(bad_x, bad_y);
 }
 
-void KillHero(struct PlayerInfo *player)
+void KillPlayer(struct PlayerInfo *player)
 {
   int jx = player->jx, jy = player->jy;
 
@@ -11267,40 +11551,36 @@ void KillHero(struct PlayerInfo *player)
   player->shield_deadly_time_left = 0;
 
   Bang(jx, jy);
-  BuryHero(player);
+  BuryPlayer(player);
 }
 
-static void KillHeroUnlessEnemyProtected(int x, int y)
+static void KillPlayerUnlessEnemyProtected(int x, int y)
 {
   if (!PLAYER_ENEMY_PROTECTED(x, y))
-    KillHero(PLAYERINFO(x, y));
+    KillPlayer(PLAYERINFO(x, y));
 }
 
-static void KillHeroUnlessExplosionProtected(int x, int y)
+static void KillPlayerUnlessExplosionProtected(int x, int y)
 {
   if (!PLAYER_EXPLOSION_PROTECTED(x, y))
-    KillHero(PLAYERINFO(x, y));
+    KillPlayer(PLAYERINFO(x, y));
 }
 
-void BuryHero(struct PlayerInfo *player)
+void BuryPlayer(struct PlayerInfo *player)
 {
   int jx = player->jx, jy = player->jy;
 
   if (!player->active)
     return;
 
-#if 1
-  PlayLevelSoundElementAction(jx, jy, player->element_nr, ACTION_DYING);
-#else
-  PlayLevelSound(jx, jy, SND_CLASS_PLAYER_DYING);
-#endif
+  PlayLevelSoundElementAction(jx, jy, player->artwork_element, ACTION_DYING);
   PlayLevelSound(jx, jy, SND_GAME_LOSING);
 
   player->GameOver = TRUE;
-  RemoveHero(player);
+  RemovePlayer(player);
 }
 
-void RemoveHero(struct PlayerInfo *player)
+void RemovePlayer(struct PlayerInfo *player)
 {
   int jx = player->jx, jy = player->jy;
   int i, found = FALSE;
@@ -11311,6 +11591,9 @@ void RemoveHero(struct PlayerInfo *player)
   if (!ExplodeField[jx][jy])
     StorePlayer[jx][jy] = 0;
 
+  if (player->is_moving)
+    DrawLevelField(player->last_jx, player->last_jy);
+
   for (i = 0; i < MAX_PLAYERS; i++)
     if (stored_player[i].active)
       found = TRUE;
@@ -11322,6 +11605,27 @@ void RemoveHero(struct PlayerInfo *player)
   ExitY = ZY = jy;
 }
 
+#if USE_NEW_SNAP_DELAY
+static void setFieldForSnapping(int x, int y, int element, int direction)
+{
+  struct ElementInfo *ei = &element_info[element];
+  int direction_bit = MV_DIR_TO_BIT(direction);
+  int graphic_snapping = ei->direction_graphic[ACTION_SNAPPING][direction_bit];
+  int action = (graphic_snapping != IMG_EMPTY_SPACE ? ACTION_SNAPPING :
+               IS_DIGGABLE(element) ? ACTION_DIGGING : ACTION_COLLECTING);
+
+  Feld[x][y] = EL_ELEMENT_SNAPPING;
+  MovDelay[x][y] = MOVE_DELAY_NORMAL_SPEED + 1 - 1;
+
+  ResetGfxAnimation(x, y);
+
+  GfxElement[x][y] = element;
+  GfxAction[x][y] = action;
+  GfxDir[x][y] = direction;
+  GfxFrame[x][y] = -1;
+}
+#endif
+
 /*
   =============================================================================
   checkDiagonalPushing()
@@ -11363,33 +11667,26 @@ int DigField(struct PlayerInfo *player,
             int oldx, int oldy, int x, int y,
             int real_dx, int real_dy, int mode)
 {
-#if 0
-  boolean use_spring_bug = (game.engine_version < VERSION_IDENT(2,2,0,0));
-#endif
   boolean is_player = (IS_PLAYER(oldx, oldy) || mode != DF_DIG);
   boolean player_was_pushing = player->is_pushing;
+  boolean player_can_move = (!player->cannot_move && mode != DF_SNAP);
+  boolean player_can_move_or_snap = (!player->cannot_move || mode == DF_SNAP);
   int jx = oldx, jy = oldy;
   int dx = x - jx, dy = y - jy;
   int nextx = x + dx, nexty = y + dy;
-  int move_direction = (dx == -1 ? MV_LEFT :
+  int move_direction = (dx == -1 ? MV_LEFT  :
                        dx == +1 ? MV_RIGHT :
-                       dy == -1 ? MV_UP :
-                       dy == +1 ? MV_DOWN : MV_NO_MOVING);
+                       dy == -1 ? MV_UP    :
+                       dy == +1 ? MV_DOWN  : MV_NONE);
   int opposite_direction = MV_DIR_OPPOSITE(move_direction);
-#if 1
   int dig_side = MV_DIR_OPPOSITE(move_direction);
-#else
-  static int trigger_sides[4] =
-  {
-    CH_SIDE_RIGHT,     /* moving left  */
-    CH_SIDE_LEFT,      /* moving right */
-    CH_SIDE_BOTTOM,    /* moving up    */
-    CH_SIDE_TOP,       /* moving down  */
-  };
-  int dig_side = trigger_sides[MV_DIR_BIT(move_direction)];
-#endif
   int old_element = Feld[jx][jy];
+#if USE_FIXED_DONT_RUN_INTO
+  int element = MovingOrBlocked2ElementIfNotLeaving(x, y);
+#else
   int element;
+#endif
+  int collect_count;
 
   if (is_player)               /* function can also be called by EL_PENGUIN */
   {
@@ -11405,897 +11702,785 @@ int DigField(struct PlayerInfo *player,
     if (mode == DF_NO_PUSH)    /* player just stopped pushing */
     {
       player->is_switching = FALSE;
-#if USE_NEW_PUSH_DELAY
       player->push_delay = -1;
-#else
-      player->push_delay = 0;
-#endif
 
-      return MF_NO_ACTION;
+      return MP_NO_ACTION;
     }
   }
 
+#if !USE_FIXED_DONT_RUN_INTO
   if (IS_MOVING(x, y) || IS_PLAYER(x, y))
-    return MF_NO_ACTION;
-
-#if 0
-
-#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,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_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] != tube_element)
-    {
-      i++;
-      if (tube_leave_directions[i][0] == -1)   /* should not happen */
-       break;
-    }
-
-    if (!(tube_leave_directions[i][1] & move_direction))
-      return MF_NO_ACTION;     /* tube has no opening in this direction */
-  }
-
-#else
+    return MP_NO_ACTION;
+#endif
 
   if (IS_TUBE(Back[jx][jy]) && game.engine_version >= VERSION_IDENT(2,2,0,0))
     old_element = Back[jx][jy];
 
-#endif
-
-  if (IS_WALKABLE(old_element) && !ACCESS_FROM(old_element, move_direction))
-    return MF_NO_ACTION;       /* field has no opening in this direction */
-
-  if (IS_PASSABLE(old_element) && !ACCESS_FROM(old_element,opposite_direction))
-    return MF_NO_ACTION;       /* field has no opening in this direction */
-
-  element = Feld[x][y];
-
-  if (!is_player && !IS_COLLECTIBLE(element))  /* penguin cannot collect it */
-    return MF_NO_ACTION;
-
-  if (mode == DF_SNAP && !IS_SNAPPABLE(element) &&
-      game.engine_version >= VERSION_IDENT(2,2,0,0))
-    return MF_NO_ACTION;
-
-#if 1
-  if (game.gravity && is_player && !player->is_auto_moving &&
-      canFallDown(player) && move_direction != MV_DOWN &&
-      !canMoveToValidFieldWithGravity(jx, jy, move_direction))
-    return MF_NO_ACTION;       /* player cannot walk here due to gravity */
-#endif
+  /* in case of element dropped at player position, check background */
+  else if (Back[jx][jy] != EL_EMPTY &&
+          game.engine_version >= VERSION_IDENT(2,2,0,0))
+    old_element = Back[jx][jy];
 
+  /* checking here causes player to move into acid even if the current field
+     cannot be left to that direction */
 #if 0
-  if (element == EL_EMPTY_SPACE &&
-      game.gravity && !player->is_auto_moving &&
-      canFallDown(player) && move_direction != MV_DOWN)
-    return MF_NO_ACTION;       /* player cannot walk here due to gravity */
-#endif
-
-  switch (element)
+#if USE_FIXED_DONT_RUN_INTO
+  if (player_can_move && DONT_RUN_INTO(element))
   {
-#if 0
-    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 1
-      if (!canEnterSupaplexPort(x, y, dx, dy))
-       return MF_NO_ACTION;
-#else
-      if ((dx == -1 &&
-          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_PORT_RIGHT &&
-          element != EL_SP_GRAVITY_PORT_RIGHT &&
-          element != EL_SP_PORT_HORIZONTAL &&
-          element != EL_SP_PORT_ANY) ||
-         (dy == -1 &&
-          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_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;
-#endif
-
-      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)
-       game.gravity = !game.gravity;
-
-      /* automatically move to the next field with double speed */
-      player->programmed_action = move_direction;
-#if 1
-      if (player->move_delay_reset_counter == 0)
-      {
-       player->move_delay_reset_counter = 2;   /* two double speed steps */
-
-       DOUBLE_PLAYER_SPEED(player);
-      }
-#else
-      player->move_delay_reset_counter = 2;
-
-      DOUBLE_PLAYER_SPEED(player);
-#endif
-
-#if 0
-      printf("::: passing port %d,%d [%d]\n", x, y, FrameCounter);
-#endif
-
-      PlayLevelSound(x, y, SND_CLASS_SP_PORT_PASSING);
-      break;
-#endif
-
-#if 0
-    case EL_TUBE_ANY:
-    case EL_TUBE_VERTICAL:
-    case EL_TUBE_HORIZONTAL:
-    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:
-    case EL_TUBE_RIGHT_DOWN:
-      {
-       int i = 0;
-       int tube_enter_directions[][2] =
-       {
-         { 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)
-       {
-         i++;
-         if (tube_enter_directions[i][0] == -1)        /* should not happen */
-           break;
-       }
-
-       if (!(tube_enter_directions[i][1] & move_direction))
-         return MF_NO_ACTION;  /* tube has no opening in this direction */
-
-       PlayLevelSound(x, y, SND_CLASS_TUBE_WALKING);
-      }
-      break;
-#endif
-
-    default:
+    if (element == EL_ACID && dx == 0 && dy == 1)
+    {
+      SplashAcid(x, y);
+      Feld[jx][jy] = EL_PLAYER_1;
+      InitMovingField(jx, jy, MV_DOWN);
+      Store[jx][jy] = EL_ACID;
+      ContinueMoving(jx, jy);
+      BuryPlayer(player);
+    }
+    else
+      TestIfPlayerRunsIntoBadThing(jx, jy, player->MovDir);
 
-#if 1
-      if (IS_WALKABLE(element) && ACCESS_FROM(element, opposite_direction))
-#else
-      if (IS_WALKABLE(element))
+    return MP_DONT_RUN_INTO;
+  }
 #endif
-      {
-       int sound_element = SND_ELEMENT(element);
-       int sound_action = ACTION_WALKING;
-
-#if 0
-       if (!ACCESS_FROM(element, opposite_direction))
-         return MF_NO_ACTION;  /* field not accessible from this direction */
 #endif
 
-#if 0
-       if (element == EL_EMPTY_SPACE &&
-           game.gravity && !player->is_auto_moving &&
-           canFallDown(player) && move_direction != MV_DOWN)
-         return MF_NO_ACTION;  /* player cannot walk here due to gravity */
-#endif
+#if 1  /* ------------------------------ NEW ------------------------------ */
 
-       if (IS_RND_GATE(element))
-       {
-         if (!player->key[RND_GATE_NR(element)])
-           return MF_NO_ACTION;
-       }
-       else if (IS_RND_GATE_GRAY(element))
-       {
-         if (!player->key[RND_GATE_GRAY_NR(element)])
-           return MF_NO_ACTION;
-       }
-       else if (element == EL_EXIT_OPEN ||
-                element == EL_SP_EXIT_OPEN ||
-                element == EL_SP_EXIT_OPENING)
-       {
-         sound_action = ACTION_PASSING;        /* player is passing exit */
-       }
-       else if (element == EL_EMPTY)
-       {
-         sound_action = ACTION_MOVING;         /* nothing to walk on */
-       }
+  if (IS_WALKABLE(old_element) && !ACCESS_FROM(old_element, move_direction))
+    return MP_NO_ACTION;       /* field has no opening in this direction */
 
-       /* play sound from background or player, whatever is available */
-       if (element_info[sound_element].sound[sound_action] != SND_UNDEFINED)
-         PlayLevelSoundElementAction(x, y, sound_element, sound_action);
-       else
-         PlayLevelSoundElementAction(x, y, player->element_nr, sound_action);
+  if (IS_PASSABLE(old_element) && !ACCESS_FROM(old_element,opposite_direction))
+    return MP_NO_ACTION;       /* field has no opening in this direction */
 
-       break;
-      }
+#if USE_FIXED_DONT_RUN_INTO
+  if (player_can_move && element == EL_ACID && move_direction == MV_DOWN)
+  {
+    SplashAcid(x, y);
 #if 1
-      else if (IS_PASSABLE(element) && canPassField(x, y, move_direction))
+    Feld[jx][jy] = player->artwork_element;
 #else
-      else if (IS_PASSABLE(element))
+    Feld[jx][jy] = EL_PLAYER_1;
 #endif
-      {
-#if 0
-       if (!canPassField(x, y, move_direction))
-         return MF_NO_ACTION;
-#else
+    InitMovingField(jx, jy, MV_DOWN);
+    Store[jx][jy] = EL_ACID;
+    ContinueMoving(jx, jy);
+    BuryPlayer(player);
 
-#if 0
-#if 1
-       if (!IN_LEV_FIELD(nextx, nexty) || IS_PLAYER(nextx, nexty) ||
-           !IS_WALKABLE_FROM(Feld[nextx][nexty], move_direction) ||
-           (!level.can_pass_to_walkable && !IS_FREE(nextx, nexty)))
-         return MF_NO_ACTION;
-#else
-       if (!IN_LEV_FIELD(nextx, nexty) || !IS_FREE(nextx, nexty))
-         return MF_NO_ACTION;
+    return MP_DONT_RUN_INTO;
+  }
 #endif
+
+#if USE_FIXED_DONT_RUN_INTO
+  if (player_can_move && DONT_RUN_INTO(element))
+  {
+    TestIfPlayerRunsIntoBadThing(jx, jy, player->MovDir);
+
+    return MP_DONT_RUN_INTO;
+  }
 #endif
 
+#else  /* ------------------------------ OLD ------------------------------ */
+
 #if 1
-       if (!ACCESS_FROM(element, opposite_direction))
-         return MF_NO_ACTION;  /* field not accessible from this direction */
-#else
-       if (IS_CUSTOM_ELEMENT(element) &&
-           !ACCESS_FROM(element, opposite_direction))
-         return MF_NO_ACTION;  /* field not accessible from this direction */
+#if USE_FIXED_DONT_RUN_INTO
+  if (player_can_move && DONT_RUN_INTO(element))
+  {
+    TestIfPlayerRunsIntoBadThing(jx, jy, player->MovDir);
+
+    return MP_DONT_RUN_INTO;
+  }
 #endif
+#endif
+
+  if (IS_WALKABLE(old_element) && !ACCESS_FROM(old_element, move_direction))
+    return MP_NO_ACTION;       /* field has no opening in this direction */
+
+  if (IS_PASSABLE(old_element) && !ACCESS_FROM(old_element,opposite_direction))
+    return MP_NO_ACTION;       /* field has no opening in this direction */
 
+  /* checking here causes player to explode when moving into acid */
 #if 1
-       if (CAN_MOVE(element))  /* only fixed elements can be passed! */
-         return MF_NO_ACTION;
-#endif
+#if USE_FIXED_DONT_RUN_INTO
+  if (player_can_move && element == EL_ACID && move_direction == MV_DOWN)
+  {
+    SplashAcid(x, y);
+    Feld[jx][jy] = EL_PLAYER_1;
+    InitMovingField(jx, jy, MV_DOWN);
+    Store[jx][jy] = EL_ACID;
+    ContinueMoving(jx, jy);
+    BuryPlayer(player);
 
+    return MP_DONT_RUN_INTO;
+  }
+#endif
 #endif
 
-       if (IS_EM_GATE(element))
-       {
-         if (!player->key[EM_GATE_NR(element)])
-           return MF_NO_ACTION;
-       }
-       else if (IS_EM_GATE_GRAY(element))
-       {
-         if (!player->key[EM_GATE_GRAY_NR(element)])
-           return MF_NO_ACTION;
-       }
-       else if (IS_SP_PORT(element))
-       {
-         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)
-           game.gravity = !game.gravity;
-         else if (element == EL_SP_GRAVITY_ON_PORT_LEFT ||
-                  element == EL_SP_GRAVITY_ON_PORT_RIGHT ||
-                  element == EL_SP_GRAVITY_ON_PORT_UP ||
-                  element == EL_SP_GRAVITY_ON_PORT_DOWN)
-           game.gravity = TRUE;
-         else if (element == EL_SP_GRAVITY_OFF_PORT_LEFT ||
-                  element == EL_SP_GRAVITY_OFF_PORT_RIGHT ||
-                  element == EL_SP_GRAVITY_OFF_PORT_UP ||
-                  element == EL_SP_GRAVITY_OFF_PORT_DOWN)
-           game.gravity = FALSE;
-       }
+#endif /* ------------------------------ END ------------------------------ */
 
-       /* automatically move to the next field with double speed */
-       player->programmed_action = move_direction;
-#if 1
-       if (player->move_delay_reset_counter == 0)
-       {
-         player->move_delay_reset_counter = 2; /* two double speed steps */
+#if 0
+#if USE_FIXED_DONT_RUN_INTO
+  if (player_can_move && DONT_RUN_INTO(element))
+  {
+    if (element == EL_ACID && dx == 0 && dy == 1)
+    {
+      SplashAcid(x, y);
+      Feld[jx][jy] = EL_PLAYER_1;
+      InitMovingField(jx, jy, MV_DOWN);
+      Store[jx][jy] = EL_ACID;
+      ContinueMoving(jx, jy);
+      BuryPlayer(player);
+    }
+    else
+      TestIfPlayerRunsIntoBadThing(jx, jy, player->MovDir);
 
-         DOUBLE_PLAYER_SPEED(player);
-       }
-#else
-       player->move_delay_reset_counter = 2;
+    return MP_DONT_RUN_INTO;
+  }
+#endif
+#endif
 
-       DOUBLE_PLAYER_SPEED(player);
+#if USE_FIXED_DONT_RUN_INTO
+  if (IS_MOVING(x, y) || IS_PLAYER(x, y))
+    return MP_NO_ACTION;
 #endif
 
-       PlayLevelSoundAction(x, y, ACTION_PASSING);
+#if !USE_FIXED_DONT_RUN_INTO
+  element = Feld[x][y];
+#endif
 
-       break;
-      }
-      else if (IS_DIGGABLE(element))
-      {
-       RemoveField(x, y);
+  collect_count = element_info[element].collect_count_initial;
 
-       if (mode != DF_SNAP)
-       {
-#if 1
-         GfxElement[x][y] = GFX_ELEMENT(element);
-#else
-         GfxElement[x][y] =
-           (GFX_CRUMBLED(element) ? EL_SAND : GFX_ELEMENT(element));
-#endif
-         player->is_digging = TRUE;
-       }
+  if (!is_player && !IS_COLLECTIBLE(element))  /* penguin cannot collect it */
+    return MP_NO_ACTION;
 
-       PlayLevelSoundElementAction(x, y, element, ACTION_DIGGING);
+  if (game.engine_version < VERSION_IDENT(2,2,0,0))
+    player_can_move = player_can_move_or_snap;
 
-       CheckTriggeredElementChangeByPlayer(x, y, element, CE_PLAYER_DIGS_X,
-                                           player->index_bit, dig_side);
+  if (mode == DF_SNAP && !IS_SNAPPABLE(element) &&
+      game.engine_version >= VERSION_IDENT(2,2,0,0))
+  {
+    CheckElementChangeByPlayer(x, y, element, CE_SNAPPED_BY_PLAYER,
+                              player->index_bit, dig_side);
+    CheckTriggeredElementChangeByPlayer(x, y, element, CE_PLAYER_SNAPS_X,
+                                       player->index_bit, dig_side);
 
-#if 1
-       if (mode == DF_SNAP)
-         TestIfElementTouchesCustomElement(x, y);      /* for empty space */
-#endif
+    if (Feld[x][y] != element)         /* field changed by snapping */
+      return MP_ACTION;
 
-       break;
-      }
-      else if (IS_COLLECTIBLE(element))
-      {
-       RemoveField(x, y);
+    return MP_NO_ACTION;
+  }
 
-       if (is_player && mode != DF_SNAP)
-       {
-         GfxElement[x][y] = element;
-         player->is_collecting = TRUE;
-       }
+#if USE_PLAYER_GRAVITY
+  if (player->gravity && is_player && !player->is_auto_moving &&
+      canFallDown(player) && move_direction != MV_DOWN &&
+      !canMoveToValidFieldWithGravity(jx, jy, move_direction))
+    return MP_NO_ACTION;       /* player cannot walk here due to gravity */
+#else
+  if (game.gravity && is_player && !player->is_auto_moving &&
+      canFallDown(player) && move_direction != MV_DOWN &&
+      !canMoveToValidFieldWithGravity(jx, jy, move_direction))
+    return MP_NO_ACTION;       /* player cannot walk here due to gravity */
+#endif
 
-       if (element == EL_SPEED_PILL)
-         player->move_delay_value = MOVE_DELAY_HIGH_SPEED;
-       else if (element == EL_EXTRA_TIME && level.time > 0)
-       {
-         TimeLeft += 10;
-         DrawGameValue_Time(TimeLeft);
-       }
-       else if (element == EL_SHIELD_NORMAL || element == EL_SHIELD_DEADLY)
-       {
-         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)
-       {
-         if (player->inventory_size < MAX_INVENTORY_SIZE)
-           player->inventory_element[player->inventory_size++] = element;
+  if (player_can_move &&
+      IS_WALKABLE(element) && ACCESS_FROM(element, opposite_direction))
+  {
+    int sound_element = SND_ELEMENT(element);
+    int sound_action = ACTION_WALKING;
 
-         DrawGameValue_Dynamite(local_player->inventory_size);
-       }
-       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 (IS_KEY(element))
-       {
-         player->key[KEY_NR(element)] = TRUE;
+    if (IS_RND_GATE(element))
+    {
+      if (!player->key[RND_GATE_NR(element)])
+       return MP_NO_ACTION;
+    }
+    else if (IS_RND_GATE_GRAY(element))
+    {
+      if (!player->key[RND_GATE_GRAY_NR(element)])
+       return MP_NO_ACTION;
+    }
+    else if (IS_RND_GATE_GRAY_ACTIVE(element))
+    {
+      if (!player->key[RND_GATE_GRAY_ACTIVE_NR(element)])
+       return MP_NO_ACTION;
+    }
+    else if (element == EL_EXIT_OPEN ||
+            element == EL_SP_EXIT_OPEN ||
+            element == EL_SP_EXIT_OPENING)
+    {
+      sound_action = ACTION_PASSING;   /* player is passing exit */
+    }
+    else if (element == EL_EMPTY)
+    {
+      sound_action = ACTION_MOVING;            /* nothing to walk on */
+    }
 
-         DrawGameValue_Keys(player->key);
+    /* play sound from background or player, whatever is available */
+    if (element_info[sound_element].sound[sound_action] != SND_UNDEFINED)
+      PlayLevelSoundElementAction(x, y, sound_element, sound_action);
+    else
+      PlayLevelSoundElementAction(x, y, player->artwork_element, sound_action);
+  }
+  else if (player_can_move &&
+          IS_PASSABLE(element) && canPassField(x, y, move_direction))
+  {
+    if (!ACCESS_FROM(element, opposite_direction))
+      return MP_NO_ACTION;     /* field not accessible from this direction */
 
-         redraw_mask |= REDRAW_DOOR_1;
-       }
-       else if (IS_ENVELOPE(element))
-       {
-#if 1
-         player->show_envelope = element;
+    if (CAN_MOVE(element))     /* only fixed elements can be passed! */
+      return MP_NO_ACTION;
+
+    if (IS_EM_GATE(element))
+    {
+      if (!player->key[EM_GATE_NR(element)])
+       return MP_NO_ACTION;
+    }
+    else if (IS_EM_GATE_GRAY(element))
+    {
+      if (!player->key[EM_GATE_GRAY_NR(element)])
+       return MP_NO_ACTION;
+    }
+    else if (IS_EM_GATE_GRAY_ACTIVE(element))
+    {
+      if (!player->key[EM_GATE_GRAY_ACTIVE_NR(element)])
+       return MP_NO_ACTION;
+    }
+    else if (IS_EMC_GATE(element))
+    {
+      if (!player->key[EMC_GATE_NR(element)])
+       return MP_NO_ACTION;
+    }
+    else if (IS_EMC_GATE_GRAY(element))
+    {
+      if (!player->key[EMC_GATE_GRAY_NR(element)])
+       return MP_NO_ACTION;
+    }
+    else if (IS_EMC_GATE_GRAY_ACTIVE(element))
+    {
+      if (!player->key[EMC_GATE_GRAY_ACTIVE_NR(element)])
+       return MP_NO_ACTION;
+    }
+    else if (IS_SP_PORT(element))
+    {
+      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)
+#if USE_PLAYER_GRAVITY
+       player->gravity = !player->gravity;
 #else
-         ShowEnvelope(element - EL_ENVELOPE_1);
+       game.gravity = !game.gravity;
 #endif
-       }
-       else if (IS_DROPPABLE(element) ||
-                IS_THROWABLE(element)) /* can be collected and dropped */
-       {
-         int i;
+      else if (element == EL_SP_GRAVITY_ON_PORT_LEFT ||
+              element == EL_SP_GRAVITY_ON_PORT_RIGHT ||
+              element == EL_SP_GRAVITY_ON_PORT_UP ||
+              element == EL_SP_GRAVITY_ON_PORT_DOWN)
+#if USE_PLAYER_GRAVITY
+       player->gravity = TRUE;
+#else
+       game.gravity = TRUE;
+#endif
+      else if (element == EL_SP_GRAVITY_OFF_PORT_LEFT ||
+              element == EL_SP_GRAVITY_OFF_PORT_RIGHT ||
+              element == EL_SP_GRAVITY_OFF_PORT_UP ||
+              element == EL_SP_GRAVITY_OFF_PORT_DOWN)
+#if USE_PLAYER_GRAVITY
+       player->gravity = FALSE;
+#else
+       game.gravity = FALSE;
+#endif
+    }
 
-         if (element_info[element].collect_count == 0)
-           player->inventory_infinite_element = element;
-         else
-           for (i = 0; i < element_info[element].collect_count; i++)
-             if (player->inventory_size < MAX_INVENTORY_SIZE)
-               player->inventory_element[player->inventory_size++] = element;
+    /* automatically move to the next field with double speed */
+    player->programmed_action = move_direction;
 
-         DrawGameValue_Dynamite(local_player->inventory_size);
-       }
-       else if (element_info[element].collect_count > 0)
-       {
-         local_player->gems_still_needed -=
-           element_info[element].collect_count;
-         if (local_player->gems_still_needed < 0)
-           local_player->gems_still_needed = 0;
+    if (player->move_delay_reset_counter == 0)
+    {
+      player->move_delay_reset_counter = 2;    /* two double speed steps */
 
-         DrawGameValue_Emeralds(local_player->gems_still_needed);
-       }
+      DOUBLE_PLAYER_SPEED(player);
+    }
+
+    PlayLevelSoundAction(x, y, ACTION_PASSING);
+  }
+  else if (player_can_move_or_snap && IS_DIGGABLE(element))
+  {
+    RemoveField(x, y);
 
-       RaiseScoreElement(element);
-       PlayLevelSoundElementAction(x, y, element, ACTION_COLLECTING);
+    if (mode != DF_SNAP)
+    {
+      GfxElement[x][y] = GFX_ELEMENT(element);
+      player->is_digging = TRUE;
+    }
 
-       if (is_player)
-         CheckTriggeredElementChangeByPlayer(x, y, element,
-                                             CE_PLAYER_COLLECTS_X,
-                                             player->index_bit, dig_side);
+    PlayLevelSoundElementAction(x, y, element, ACTION_DIGGING);
 
-#if 1
-       if (mode == DF_SNAP)
-         TestIfElementTouchesCustomElement(x, y);      /* for empty space */
+    CheckTriggeredElementChangeByPlayer(x, y, element, CE_PLAYER_DIGS_X,
+                                       player->index_bit, dig_side);
+
+    if (mode == DF_SNAP)
+    {
+#if USE_NEW_SNAP_DELAY
+      if (level.block_snap_field)
+       setFieldForSnapping(x, y, element, move_direction);
+      else
+       TestIfElementTouchesCustomElement(x, y);        /* for empty space */
+#else
+      TestIfElementTouchesCustomElement(x, y);         /* for empty space */
 #endif
 
-       break;
-      }
-      else if (IS_PUSHABLE(element))
-      {
-       if (mode == DF_SNAP && element != EL_BD_ROCK)
-         return MF_NO_ACTION;
+      CheckTriggeredElementChangeByPlayer(x, y, element, CE_PLAYER_SNAPS_X,
+                                         player->index_bit, dig_side);
+    }
+  }
+  else if (player_can_move_or_snap && IS_COLLECTIBLE(element))
+  {
+    RemoveField(x, y);
 
-       if (CAN_FALL(element) && dy)
-         return MF_NO_ACTION;
+    if (is_player && mode != DF_SNAP)
+    {
+      GfxElement[x][y] = element;
+      player->is_collecting = TRUE;
+    }
 
-       if (CAN_FALL(element) && IN_LEV_FIELD(x, y + 1) && IS_FREE(x, y + 1) &&
-           !(element == EL_SPRING && level.use_spring_bug))
-         return MF_NO_ACTION;
+    if (element == EL_SPEED_PILL)
+    {
+      player->move_delay_value = MOVE_DELAY_HIGH_SPEED;
+    }
+    else if (element == EL_EXTRA_TIME && level.time > 0)
+    {
+      TimeLeft += level.extra_time;
+      DrawGameValue_Time(TimeLeft);
+    }
+    else if (element == EL_SHIELD_NORMAL || element == EL_SHIELD_DEADLY)
+    {
+      player->shield_normal_time_left += level.shield_normal_time;
+      if (element == EL_SHIELD_DEADLY)
+       player->shield_deadly_time_left += level.shield_deadly_time;
+    }
+    else if (element == EL_DYNAMITE ||
+            element == EL_EM_DYNAMITE ||
+            element == EL_SP_DISK_RED)
+    {
+      if (player->inventory_size < MAX_INVENTORY_SIZE)
+       player->inventory_element[player->inventory_size++] = element;
 
 #if 1
-       if (CAN_MOVE(element) && GET_MAX_MOVE_DELAY(element) == 0 &&
-           ((move_direction & MV_VERTICAL &&
-             ((element_info[element].move_pattern & MV_LEFT &&
-               IN_LEV_FIELD(x - 1, y) && IS_FREE(x - 1, y)) ||
-              (element_info[element].move_pattern & MV_RIGHT &&
-               IN_LEV_FIELD(x + 1, y) && IS_FREE(x + 1, y)))) ||
-            (move_direction & MV_HORIZONTAL &&
-             ((element_info[element].move_pattern & MV_UP &&
-               IN_LEV_FIELD(x, y - 1) && IS_FREE(x, y - 1)) ||
-              (element_info[element].move_pattern & MV_DOWN &&
-               IN_LEV_FIELD(x, y + 1) && IS_FREE(x, y + 1))))))
-         return MF_NO_ACTION;
+      DrawGameDoorValues();
+#else
+      DrawGameValue_Dynamite(local_player->inventory_size);
 #endif
+    }
+    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 (IS_KEY(element))
+    {
+      player->key[KEY_NR(element)] = TRUE;
 
 #if 1
-       /* do not push elements already moving away faster than player */
-       if (CAN_MOVE(element) && MovDir[x][y] == move_direction &&
-           ABS(getElementMoveStepsize(x, y)) > MOVE_STEPSIZE_NORMAL)
-         return MF_NO_ACTION;
+      DrawGameDoorValues();
 #else
-       if (element == EL_SPRING && MovDir[x][y] != MV_NO_MOVING)
-         return MF_NO_ACTION;
+      DrawGameValue_Keys(player->key);
 #endif
 
-#if 1
+      redraw_mask |= REDRAW_DOOR_1;
+    }
+    else if (IS_ENVELOPE(element))
+    {
+      player->show_envelope = element;
+    }
+    else if (element == EL_EMC_LENSES)
+    {
+      game.lenses_time_left = level.lenses_time * FRAMES_PER_SECOND;
+
+      RedrawAllInvisibleElementsForLenses();
+    }
+    else if (element == EL_EMC_MAGNIFIER)
+    {
+      game.magnify_time_left = level.magnify_time * FRAMES_PER_SECOND;
+
+      RedrawAllInvisibleElementsForMagnifier();
+    }
+    else if (IS_DROPPABLE(element) ||
+            IS_THROWABLE(element))     /* can be collected and dropped */
+    {
+      int i;
+
+      if (collect_count == 0)
+       player->inventory_infinite_element = element;
+      else
+       for (i = 0; i < collect_count; i++)
+         if (player->inventory_size < MAX_INVENTORY_SIZE)
+           player->inventory_element[player->inventory_size++] = element;
 
 #if 1
-       if (game.engine_version >= VERSION_IDENT(3,1,0,0))
-       {
-         if (player->push_delay_value == -1 || !player_was_pushing)
-           player->push_delay_value = GET_NEW_PUSH_DELAY(element);
-       }
-       else if (game.engine_version >= VERSION_IDENT(3,0,7,1))
-       {
-         if (player->push_delay_value == -1)
-           player->push_delay_value = GET_NEW_PUSH_DELAY(element);
-       }
+      DrawGameDoorValues();
 #else
-       if (game.engine_version >= VERSION_IDENT(3,0,7,1))
-       {
-         if (player->push_delay_value == -1 || !player_was_pushing)
-           player->push_delay_value = GET_NEW_PUSH_DELAY(element);
-       }
+      DrawGameValue_Dynamite(local_player->inventory_size);
 #endif
-       else if (game.engine_version >= VERSION_IDENT(2,2,0,7))
-       {
-         if (!player->is_pushing)
-           player->push_delay_value = GET_NEW_PUSH_DELAY(element);
-       }
+    }
+    else if (collect_count > 0)
+    {
+      local_player->gems_still_needed -= collect_count;
+      if (local_player->gems_still_needed < 0)
+       local_player->gems_still_needed = 0;
+
+      DrawGameValue_Emeralds(local_player->gems_still_needed);
+    }
+
+    RaiseScoreElement(element);
+    PlayLevelSoundElementAction(x, y, element, ACTION_COLLECTING);
 
-       /*
-       if (game.engine_version >= VERSION_IDENT(2,2,0,7) &&
-           (game.engine_version < VERSION_IDENT(3,0,7,1) ||
-            !player_is_pushing))
-         player->push_delay_value = GET_NEW_PUSH_DELAY(element);
-       */
+    if (is_player)
+      CheckTriggeredElementChangeByPlayer(x, y, element, CE_PLAYER_COLLECTS_X,
+                                         player->index_bit, dig_side);
+
+    if (mode == DF_SNAP)
+    {
+#if USE_NEW_SNAP_DELAY
+      if (level.block_snap_field)
+       setFieldForSnapping(x, y, element, move_direction);
+      else
+       TestIfElementTouchesCustomElement(x, y);        /* for empty space */
 #else
-       if (!player->is_pushing &&
-           game.engine_version >= VERSION_IDENT(2,2,0,7))
-         player->push_delay_value = GET_NEW_PUSH_DELAY(element);
+      TestIfElementTouchesCustomElement(x, y);         /* for empty space */
 #endif
 
-#if 0
-       printf("::: push delay: %ld -> %ld [%d, %d] [%d / %d] [%d '%s': %d]\n",
-              player->push_delay, player->push_delay_value,
-              FrameCounter, game.engine_version,
-              player_was_pushing, player->is_pushing,
-              element, element_info[element].token_name,
-              GET_NEW_PUSH_DELAY(element));
-#endif
+      CheckTriggeredElementChangeByPlayer(x, y, element, CE_PLAYER_SNAPS_X,
+                                         player->index_bit, dig_side);
+    }
+  }
+  else if (player_can_move_or_snap && IS_PUSHABLE(element))
+  {
+    if (mode == DF_SNAP && element != EL_BD_ROCK)
+      return MP_NO_ACTION;
 
-       player->is_pushing = TRUE;
+    if (CAN_FALL(element) && dy)
+      return MP_NO_ACTION;
 
-       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 (CAN_FALL(element) && IN_LEV_FIELD(x, y + 1) && IS_FREE(x, y + 1) &&
+       !(element == EL_SPRING && level.use_spring_bug))
+      return MP_NO_ACTION;
 
-       if (!checkDiagonalPushing(player, x, y, real_dx, real_dy))
-         return MF_NO_ACTION;
+    if (CAN_MOVE(element) && GET_MAX_MOVE_DELAY(element) == 0 &&
+       ((move_direction & MV_VERTICAL &&
+         ((element_info[element].move_pattern & MV_LEFT &&
+           IN_LEV_FIELD(x - 1, y) && IS_FREE(x - 1, y)) ||
+          (element_info[element].move_pattern & MV_RIGHT &&
+           IN_LEV_FIELD(x + 1, y) && IS_FREE(x + 1, y)))) ||
+        (move_direction & MV_HORIZONTAL &&
+         ((element_info[element].move_pattern & MV_UP &&
+           IN_LEV_FIELD(x, y - 1) && IS_FREE(x, y - 1)) ||
+          (element_info[element].move_pattern & MV_DOWN &&
+           IN_LEV_FIELD(x, y + 1) && IS_FREE(x, y + 1))))))
+      return MP_NO_ACTION;
 
-#if USE_NEW_PUSH_DELAY
+    /* do not push elements already moving away faster than player */
+    if (CAN_MOVE(element) && MovDir[x][y] == move_direction &&
+       ABS(getElementMoveStepsize(x, y)) > MOVE_STEPSIZE_NORMAL)
+      return MP_NO_ACTION;
 
-#if 0
-       if ( (player->push_delay == -1) != (player->push_delay2 == 0) )
-         printf("::: ALERT: %d, %d [%d / %d]\n",
-                player->push_delay, player->push_delay2,
-                FrameCounter, FrameCounter / 50);
-#endif
+    if (game.engine_version >= VERSION_IDENT(3,1,0,0))
+    {
+      if (player->push_delay_value == -1 || !player_was_pushing)
+       player->push_delay_value = GET_NEW_PUSH_DELAY(element);
+    }
+    else if (game.engine_version >= VERSION_IDENT(3,0,7,1))
+    {
+      if (player->push_delay_value == -1)
+       player->push_delay_value = GET_NEW_PUSH_DELAY(element);
+    }
+    else if (game.engine_version >= VERSION_IDENT(2,2,0,7))
+    {
+      if (!player->is_pushing)
+       player->push_delay_value = GET_NEW_PUSH_DELAY(element);
+    }
 
-       if (player->push_delay == -1)   /* new pushing; restart delay */
-         player->push_delay = 0;
-#else
-       if (player->push_delay == 0)    /* new pushing; restart delay */
-         player->push_delay = FrameCounter;
-#endif
+    player->is_pushing = TRUE;
+    player->is_active = TRUE;
 
-#if USE_NEW_PUSH_DELAY
-#if 0
-       if ( (player->push_delay > 0) != (!xxx_fr) )
-         printf("::: PUSH BUG! %d, (%d -> %d) %d [%d / %d]\n",
-                player->push_delay,
-                xxx_pdv2, player->push_delay2, player->push_delay_value,
-                FrameCounter, FrameCounter / 50);
-#endif
+    if (!(IN_LEV_FIELD(nextx, nexty) &&
+         (IS_FREE(nextx, nexty) ||
+          (Feld[nextx][nexty] == EL_SOKOBAN_FIELD_EMPTY &&
+           IS_SB_ELEMENT(element)))))
+      return MP_NO_ACTION;
 
-#if 0
-       if (player->push_delay > 0 &&
-           !(tape.playing && tape.file_version < FILE_VERSION_2_0) &&
-           element != EL_SPRING && element != EL_BALLOON)
-#else
-       /* !!! */
-       if (player->push_delay < player->push_delay_value &&
-           !(tape.playing && tape.file_version < FILE_VERSION_2_0) &&
-           element != EL_SPRING && element != EL_BALLOON)
-#endif
+    if (!checkDiagonalPushing(player, x, y, real_dx, real_dy))
+      return MP_NO_ACTION;
 
-#else
-       if (!FrameReached(&player->push_delay, player->push_delay_value) &&
-           !(tape.playing && tape.file_version < FILE_VERSION_2_0) &&
-           element != EL_SPRING && element != EL_BALLOON)
-#endif
-       {
-         /* make sure that there is no move delay before next try to push */
-#if USE_NEW_MOVE_DELAY
-         if (game.engine_version >= VERSION_IDENT(3,0,7,1))
-           player->move_delay = 0;
-#else
-         if (game.engine_version >= VERSION_IDENT(3,0,7,1))
-           player->move_delay = INITIAL_MOVE_DELAY_OFF;
-#endif
+    if (player->push_delay == -1)      /* new pushing; restart delay */
+      player->push_delay = 0;
+
+    if (player->push_delay < player->push_delay_value &&
+       !(tape.playing && tape.file_version < FILE_VERSION_2_0) &&
+       element != EL_SPRING && element != EL_BALLOON)
+    {
+      /* make sure that there is no move delay before next try to push */
+      if (game.engine_version >= VERSION_IDENT(3,0,7,1))
+       player->move_delay = 0;
 
-         return MF_NO_ACTION;
-       }
+      return MP_NO_ACTION;
+    }
 
-#if 0
-       printf("::: NOW PUSHING... [%d]\n", FrameCounter);
-#endif
+    if (IS_SB_ELEMENT(element))
+    {
+      if (element == EL_SOKOBAN_FIELD_FULL)
+      {
+       Back[x][y] = EL_SOKOBAN_FIELD_EMPTY;
+       local_player->sokobanfields_still_needed++;
+      }
 
-       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--;
+      }
 
-         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;
 
-         Feld[x][y] = EL_SOKOBAN_OBJECT;
+      if (Back[x][y] == Back[nextx][nexty])
+       PlayLevelSoundAction(x, y, ACTION_PUSHING);
+      else if (Back[x][y] != 0)
+       PlayLevelSoundElementAction(x, y, EL_SOKOBAN_FIELD_FULL,
+                                   ACTION_EMPTYING);
+      else
+       PlayLevelSoundElementAction(nextx, nexty, EL_SOKOBAN_FIELD_EMPTY,
+                                   ACTION_FILLING);
 
-         if (Back[x][y] == Back[nextx][nexty])
-           PlayLevelSoundAction(x, y, ACTION_PUSHING);
-         else if (Back[x][y] != 0)
-           PlayLevelSoundElementAction(x, y, EL_SOKOBAN_FIELD_FULL,
-                                       ACTION_EMPTYING);
-         else
-           PlayLevelSoundElementAction(nextx, nexty, EL_SOKOBAN_FIELD_EMPTY,
-                                       ACTION_FILLING);
+      if (local_player->sokobanfields_still_needed == 0 &&
+         game.emulation == EMU_SOKOBAN)
+      {
+       player->LevelSolved = player->GameOver = TRUE;
+       PlayLevelSound(x, y, SND_GAME_SOKOBAN_SOLVING);
+      }
+    }
+    else
+      PlayLevelSoundElementAction(x, y, element, ACTION_PUSHING);
 
-         if (local_player->sokobanfields_still_needed == 0 &&
-             game.emulation == EMU_SOKOBAN)
-         {
-           player->LevelSolved = player->GameOver = TRUE;
-           PlayLevelSound(x, y, SND_GAME_SOKOBAN_SOLVING);
-         }
-       }
-       else
-         PlayLevelSoundElementAction(x, y, element, ACTION_PUSHING);
+    InitMovingField(x, y, move_direction);
+    GfxAction[x][y] = 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);
 
-       if (mode == DF_SNAP)
-         ContinueMoving(x, y);
-       else
-         MovPos[x][y] = (dx != 0 ? dx : dy);
+    Pushed[x][y] = TRUE;
+    Pushed[nextx][nexty] = TRUE;
 
-       Pushed[x][y] = TRUE;
-       Pushed[nextx][nexty] = TRUE;
+    if (game.engine_version < VERSION_IDENT(2,2,0,7))
+      player->push_delay_value = GET_NEW_PUSH_DELAY(element);
+    else
+      player->push_delay_value = -1;   /* get new value later */
 
-       if (game.engine_version < VERSION_IDENT(2,2,0,7))
-         player->push_delay_value = GET_NEW_PUSH_DELAY(element);
-       else
-         player->push_delay_value = -1;        /* get new value later */
+    /* check for element change _after_ element has been pushed */
+    if (game.use_change_when_pushing_bug)
+    {
+      CheckElementChangeByPlayer(x, y, element, CE_PUSHED_BY_PLAYER,
+                                player->index_bit, dig_side);
+      CheckTriggeredElementChangeByPlayer(x, y, element, CE_PLAYER_PUSHES_X,
+                                         player->index_bit, dig_side);
+    }
+  }
+  else if (IS_SWITCHABLE(element))
+  {
+    if (PLAYER_SWITCHING(player, x, y))
+    {
+      CheckTriggeredElementChangeByPlayer(x, y, element, CE_PLAYER_PRESSES_X,
+                                         player->index_bit, dig_side);
 
-#if USE_PUSH_BUGFIX
-       /* now: check for element change _after_ element has been pushed! */
-#if 1
-       if (game.use_change_when_pushing_bug)
-#else
-       if (game.engine_version < VERSION_IDENT(3,1,0,0))
-#endif
-       {
-         CheckElementChangeByPlayer(x, y, element, CE_PUSHED_BY_PLAYER,
-                                    player->index_bit, dig_side);
-         CheckTriggeredElementChangeByPlayer(x,y, element, CE_PLAYER_PUSHES_X,
-                                             player->index_bit, dig_side);
-       }
+      return MP_ACTION;
+    }
 
-#else
+    player->is_switching = TRUE;
+    player->switch_x = x;
+    player->switch_y = y;
 
-#if 1
-       /* check for element change _after_ element has been pushed! */
-#else
+    PlayLevelSoundElementAction(x, y, element, ACTION_ACTIVATING);
+
+    if (element == EL_ROBOT_WHEEL)
+    {
+      Feld[x][y] = EL_ROBOT_WHEEL_ACTIVE;
+      ZX = x;
+      ZY = y;
+
+      DrawLevelField(x, y);
+    }
+    else if (element == EL_SP_TERMINAL)
+    {
+      int xx, yy;
 
 #if 1
-       /* !!! TEST ONLY !!! */
-       CheckElementChangeByPlayer(x, y, element, CE_PUSHED_BY_PLAYER,
-                                  player->index_bit, dig_side);
-       CheckTriggeredElementChangeByPlayer(x, y, element, CE_PLAYER_PUSHES_X,
-                                           player->index_bit, dig_side);
+      SCAN_PLAYFIELD(xx, yy)
 #else
-       CheckTriggeredElementChangeByPlayer(x, y, element, CE_PLAYER_PUSHES_X,
-                                           player->index_bit, dig_side);
-       CheckElementChangeByPlayer(x, y, element, CE_PUSHED_BY_PLAYER,
-                                  player->index_bit, dig_side);
-#endif
-#endif
-
+      for (yy = 0; yy < lev_fieldy; yy++) for (xx = 0; xx < lev_fieldx; xx++)
 #endif
-
-       break;
-      }
-      else if (IS_SWITCHABLE(element))
       {
-       if (PLAYER_SWITCHING(player, x, y))
-       {
-         CheckTriggeredElementChangeByPlayer(x,y, element,
-                                             CE_PLAYER_PRESSES_X,
-                                             player->index_bit, dig_side);
-
-         return MF_ACTION;
-       }
-
-       player->is_switching = TRUE;
-       player->switch_x = x;
-       player->switch_y = y;
+       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;
+      }
+    }
+    else if (IS_BELT_SWITCH(element))
+    {
+      ToggleBeltSwitch(x, y);
+    }
+    else if (element == EL_SWITCHGATE_SWITCH_UP ||
+            element == EL_SWITCHGATE_SWITCH_DOWN)
+    {
+      ToggleSwitchgateSwitch(x, y);
+    }
+    else if (element == EL_LIGHT_SWITCH ||
+            element == EL_LIGHT_SWITCH_ACTIVE)
+    {
+      ToggleLightSwitch(x, y);
+    }
+    else if (element == EL_TIMEGATE_SWITCH)
+    {
+      ActivateTimegateSwitch(x, y);
+    }
+    else if (element == EL_BALLOON_SWITCH_LEFT  ||
+            element == EL_BALLOON_SWITCH_RIGHT ||
+            element == EL_BALLOON_SWITCH_UP    ||
+            element == EL_BALLOON_SWITCH_DOWN  ||
+            element == EL_BALLOON_SWITCH_NONE  ||
+            element == EL_BALLOON_SWITCH_ANY)
+    {
+      game.wind_direction = (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  :
+                            element == EL_BALLOON_SWITCH_NONE  ? MV_NONE  :
+                            move_direction);
+    }
+    else if (element == EL_LAMP)
+    {
+      Feld[x][y] = EL_LAMP_ACTIVE;
+      local_player->lights_still_needed--;
 
-       PlayLevelSoundElementAction(x, y, element, ACTION_ACTIVATING);
+      ResetGfxAnimation(x, y);
+      DrawLevelField(x, y);
+    }
+    else if (element == EL_TIME_ORB_FULL)
+    {
+      Feld[x][y] = EL_TIME_ORB_EMPTY;
 
-       if (element == EL_ROBOT_WHEEL)
-       {
-         Feld[x][y] = EL_ROBOT_WHEEL_ACTIVE;
-         ZX = x;
-         ZY = y;
+      if (level.time > 0 || level.use_time_orb_bug)
+      {
+       TimeLeft += level.time_orb_time;
+       DrawGameValue_Time(TimeLeft);
+      }
 
-         DrawLevelField(x, y);
-       }
-       else if (element == EL_SP_TERMINAL)
-       {
-         int xx, yy;
+      ResetGfxAnimation(x, y);
+      DrawLevelField(x, y);
+    }
+    else if (element == EL_EMC_MAGIC_BALL_SWITCH ||
+            element == EL_EMC_MAGIC_BALL_SWITCH_ACTIVE)
+    {
+      int xx, yy;
 
-         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;
-         }
-       }
-       else if (IS_BELT_SWITCH(element))
-       {
-         ToggleBeltSwitch(x, y);
-       }
-       else if (element == EL_SWITCHGATE_SWITCH_UP ||
-                element == EL_SWITCHGATE_SWITCH_DOWN)
-       {
-         ToggleSwitchgateSwitch(x, y);
-       }
-       else if (element == EL_LIGHT_SWITCH ||
-                element == EL_LIGHT_SWITCH_ACTIVE)
-       {
-         ToggleLightSwitch(x, y);
+      game.ball_state = !game.ball_state;
 
-#if 0
-         PlayLevelSound(x, y, element == EL_LIGHT_SWITCH ?
-                        SND_LIGHT_SWITCH_ACTIVATING :
-                        SND_LIGHT_SWITCH_DEACTIVATING);
+#if 1
+      SCAN_PLAYFIELD(xx, yy)
+#else
+      for (yy = 0; yy < lev_fieldy; yy++) for (xx = 0; xx < lev_fieldx; xx++)
 #endif
-       }
-       else if (element == EL_TIMEGATE_SWITCH)
-       {
-         ActivateTimegateSwitch(x, y);
-       }
-       else if (element == EL_BALLOON_SWITCH_LEFT ||
-                element == EL_BALLOON_SWITCH_RIGHT ||
-                element == EL_BALLOON_SWITCH_UP ||
-                element == EL_BALLOON_SWITCH_DOWN ||
-                element == EL_BALLOON_SWITCH_ANY)
+      {
+       int e = Feld[xx][yy];
+
+       if (game.ball_state)
        {
-         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);
+         if (e == EL_EMC_MAGIC_BALL)
+           CreateField(xx, yy, EL_EMC_MAGIC_BALL_ACTIVE);
+         else if (e == EL_EMC_MAGIC_BALL_SWITCH)
+           CreateField(xx, yy, EL_EMC_MAGIC_BALL_SWITCH_ACTIVE);
        }
-       else if (element == EL_LAMP)
+       else
        {
-         Feld[x][y] = EL_LAMP_ACTIVE;
-         local_player->lights_still_needed--;
-
-         ResetGfxAnimation(x, y);
-         DrawLevelField(x, y);
+         if (e == EL_EMC_MAGIC_BALL_ACTIVE)
+           CreateField(xx, yy, EL_EMC_MAGIC_BALL);
+         else if (e == EL_EMC_MAGIC_BALL_SWITCH_ACTIVE)
+           CreateField(xx, yy, EL_EMC_MAGIC_BALL_SWITCH);
        }
-       else if (element == EL_TIME_ORB_FULL)
-       {
-         Feld[x][y] = EL_TIME_ORB_EMPTY;
-         TimeLeft += 10;
-         DrawGameValue_Time(TimeLeft);
+      }
+    }
 
-         ResetGfxAnimation(x, y);
-         DrawLevelField(x, y);
+    CheckTriggeredElementChangeByPlayer(x, y, element, CE_SWITCH_OF_X,
+                                       player->index_bit, dig_side);
 
-#if 0
-         PlaySoundStereo(SND_TIME_ORB_FULL_COLLECTING, SOUND_MIDDLE);
-#endif
-       }
+    CheckTriggeredElementChangeByPlayer(x, y, element, CE_PLAYER_SWITCHES_X,
+                                       player->index_bit, dig_side);
 
-       CheckTriggeredElementChangeByPlayer(x, y, element,
-                                           CE_SWITCH_OF_X,
-                                           player->index_bit, dig_side);
+    CheckTriggeredElementChangeByPlayer(x, y, element, CE_PLAYER_PRESSES_X,
+                                       player->index_bit, dig_side);
 
-       CheckTriggeredElementChangeByPlayer(x, y, element, CE_PLAYER_PRESSES_X,
-                                           player->index_bit, dig_side);
+    return MP_ACTION;
+  }
+  else
+  {
+    if (!PLAYER_SWITCHING(player, x, y))
+    {
+      player->is_switching = TRUE;
+      player->switch_x = x;
+      player->switch_y = y;
 
-       return MF_ACTION;
-      }
-      else
-      {
-       if (!PLAYER_SWITCHING(player, x, y))
-       {
-         player->is_switching = TRUE;
-         player->switch_x = x;
-         player->switch_y = y;
+      CheckElementChangeByPlayer(x, y, element, CE_SWITCHED,
+                                player->index_bit, dig_side);
+      CheckTriggeredElementChangeByPlayer(x, y, element, CE_SWITCH_OF_X,
+                                         player->index_bit, dig_side);
 
-#if 1
-         /* !!! TEST ONLY !!! */
-         CheckElementChangeByPlayer(x, y, element, CE_SWITCHED,
-                                    player->index_bit, dig_side);
-         CheckTriggeredElementChangeByPlayer(x, y, element,
-                                             CE_SWITCH_OF_X,
-                                             player->index_bit, dig_side);
-#else
-         CheckTriggeredElementChangeByPlayer(x, y, element,
-                                             CE_SWITCH_OF_X,
-                                             player->index_bit, dig_side);
-         CheckElementChangeByPlayer(x, y, element, CE_SWITCHED,
-                                    player->index_bit, dig_side);
-#endif
-       }
+      CheckElementChangeByPlayer(x, y, element, CE_SWITCHED_BY_PLAYER,
+                                player->index_bit, dig_side);
+      CheckTriggeredElementChangeByPlayer(x, y, element, CE_PLAYER_SWITCHES_X,
+                                         player->index_bit, dig_side);
+    }
 
-#if 1
-       /* !!! TEST ONLY !!! (this breaks "machine", level 000) */
-       CheckElementChangeByPlayer(x, y, element, CE_PRESSED_BY_PLAYER,
-                                  player->index_bit, dig_side);
-       CheckTriggeredElementChangeByPlayer(x, y, element, CE_PLAYER_PRESSES_X,
-                                           player->index_bit, dig_side);
-#else
-       CheckTriggeredElementChangeByPlayer(x, y, element, CE_PLAYER_PRESSES_X,
-                                           player->index_bit, dig_side);
-       CheckElementChangeByPlayer(x, y, element, CE_PRESSED_BY_PLAYER,
-                                  player->index_bit, dig_side);
-#endif
-      }
+    CheckElementChangeByPlayer(x, y, element, CE_PRESSED_BY_PLAYER,
+                              player->index_bit, dig_side);
+    CheckTriggeredElementChangeByPlayer(x, y, element, CE_PLAYER_PRESSES_X,
+                                       player->index_bit, dig_side);
 
-      return MF_NO_ACTION;
+    return MP_NO_ACTION;
   }
 
-#if USE_NEW_PUSH_DELAY
   player->push_delay = -1;
-#else
-  player->push_delay = 0;
-#endif
 
-#if USE_PENGUIN_COLLECT_BUGFIX
   if (is_player)               /* function can also be called by EL_PENGUIN */
-#endif
   {
     if (Feld[x][y] != element)         /* really digged/collected something */
+    {
       player->is_collecting = !player->is_digging;
+      player->is_active = TRUE;
+    }
   }
 
-  return MF_MOVING;
+  return MP_MOVING;
 }
 
 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 :
+  int snap_direction = (dx == -1 ? MV_LEFT  :
                        dx == +1 ? MV_RIGHT :
-                       dy == -1 ? MV_UP :
-                       dy == +1 ? MV_DOWN : MV_NO_MOVING);
+                       dy == -1 ? MV_UP    :
+                       dy == +1 ? MV_DOWN  : MV_NONE);
+  boolean can_continue_snapping = (level.continuous_snapping &&
+                                  WasJustFalling[x][y] < CHECK_DELAY_FALLING);
 
-#if 0
-  if (player->MovPos != 0)
-    return FALSE;
-#else
   if (player->MovPos != 0 && game.engine_version >= VERSION_IDENT(2,2,0,0))
     return FALSE;
-#endif
 
   if (!player->active || !IN_LEV_FIELD(x, y))
     return FALSE;
@@ -12320,14 +12505,18 @@ boolean SnapField(struct PlayerInfo *player, int dx, int dy)
     return FALSE;
   }
 
+#if USE_NEW_CONTINUOUS_SNAPPING
+  /* prevent snapping with already pressed snap key when not allowed */
+  if (player->is_snapping && !can_continue_snapping)
+    return FALSE;
+#else
   if (player->is_snapping)
     return FALSE;
+#endif
 
   player->MovDir = snap_direction;
 
-#if 1
   if (player->MovPos == 0)
-#endif
   {
     player->is_moving = FALSE;
     player->is_digging = FALSE;
@@ -12335,32 +12524,27 @@ boolean SnapField(struct PlayerInfo *player, int dx, int dy)
   }
 
   player->is_dropping = FALSE;
+  player->is_dropping_pressed = FALSE;
+  player->drop_pressed_delay = 0;
 
-  if (DigField(player, jx, jy, x, y, 0, 0, DF_SNAP) == MF_NO_ACTION)
+  if (DigField(player, jx, jy, x, y, 0, 0, DF_SNAP) == MP_NO_ACTION)
     return FALSE;
 
   player->is_snapping = TRUE;
+  player->is_active = TRUE;
 
-#if 1
   if (player->MovPos == 0)
-#endif
   {
     player->is_moving = FALSE;
     player->is_digging = FALSE;
     player->is_collecting = FALSE;
   }
 
-#if 1
   if (player->MovPos != 0)     /* prevent graphic bugs in versions < 2.2.0 */
     DrawLevelField(player->last_jx, player->last_jy);
-#endif
 
   DrawLevelField(x, y);
 
-#if 0
-  BackToFront();
-#endif
-
   return TRUE;
 }
 
@@ -12369,18 +12553,7 @@ boolean DropElement(struct PlayerInfo *player)
   int old_element, new_element;
   int dropx = player->jx, dropy = player->jy;
   int drop_direction = player->MovDir;
-#if 1
   int drop_side = drop_direction;
-#else
-  static int trigger_sides[4] =
-  {
-    CH_SIDE_LEFT,      /* dropping left  */
-    CH_SIDE_RIGHT,     /* dropping right */
-    CH_SIDE_TOP,       /* dropping up    */
-    CH_SIDE_BOTTOM,    /* dropping down  */
-  };
-  int drop_side = trigger_sides[MV_DIR_BIT(drop_direction)];
-#endif
   int drop_element = (player->inventory_size > 0 ?
                      player->inventory_element[player->inventory_size - 1] :
                      player->inventory_infinite_element != EL_UNDEFINED ?
@@ -12389,14 +12562,14 @@ boolean DropElement(struct PlayerInfo *player)
                      EL_DYNABOMB_PLAYER_1_ACTIVE + player->index_nr :
                      EL_UNDEFINED);
 
-#if USE_DROP_BUGFIX
+  player->is_dropping_pressed = TRUE;
+
   /* do not drop an element on top of another element; when holding drop key
      pressed without moving, dropped element must move away before the next
      element can be dropped (this is especially important if the next element
      is dynamite, which can be placed on background for historical reasons) */
   if (PLAYER_DROPPING(player, dropx, dropy) && Feld[dropx][dropy] != EL_EMPTY)
-    return MF_ACTION;
-#endif
+    return MP_ACTION;
 
   if (IS_THROWABLE(drop_element))
   {
@@ -12415,30 +12588,20 @@ boolean DropElement(struct PlayerInfo *player)
     return FALSE;
 
   /* check if player has anything that can be dropped */
-#if 1
   if (new_element == EL_UNDEFINED)
     return FALSE;
-#else
-  if (player->inventory_size == 0 &&
-      player->inventory_infinite_element == EL_UNDEFINED &&
-      player->dynabombs_left == 0)
+
+  /* check if drop key was pressed long enough for EM style dynamite */
+  if (new_element == EL_EM_DYNAMITE && player->drop_pressed_delay < 40)
     return FALSE;
-#endif
 
   /* check if anything can be dropped at the current position */
   if (IS_ACTIVE_BOMB(old_element) || old_element == EL_EXPLOSION)
     return FALSE;
 
   /* collected custom elements can only be dropped on empty fields */
-#if 1
   if (IS_CUSTOM_ELEMENT(new_element) && old_element != EL_EMPTY)
     return FALSE;
-#else
-  if (player->inventory_size > 0 &&
-      IS_CUSTOM_ELEMENT(player->inventory_element[player->inventory_size - 1])
-      && old_element != EL_EMPTY)
-    return FALSE;
-#endif
 
   if (old_element != EL_EMPTY)
     Back[dropx][dropy] = old_element;  /* store old element on this field */
@@ -12453,14 +12616,16 @@ boolean DropElement(struct PlayerInfo *player)
     {
       player->inventory_size--;
 
-#if 0
-      new_element = player->inventory_element[player->inventory_size];
-#endif
-
+#if 1
+      DrawGameDoorValues();
+#else
       DrawGameValue_Dynamite(local_player->inventory_size);
+#endif
 
       if (new_element == EL_DYNAMITE)
        new_element = EL_DYNAMITE_ACTIVE;
+      else if (new_element == EL_EM_DYNAMITE)
+       new_element = EL_EM_DYNAMITE_ACTIVE;
       else if (new_element == EL_SP_DISK_RED)
        new_element = EL_SP_DISK_RED_ACTIVE;
     }
@@ -12473,25 +12638,14 @@ boolean DropElement(struct PlayerInfo *player)
 
     PlayLevelSoundAction(dropx, dropy, ACTION_DROPPING);
 
-#if 1
     /* needed if previous element just changed to "empty" in the last frame */
-    Changed[dropx][dropy] = FALSE;             /* allow another change */
-#endif
+    ChangeCount[dropx][dropy] = 0;     /* allow at least one more change */
 
-#if 1
-    /* !!! TEST ONLY !!! */
     CheckElementChangeByPlayer(dropx, dropy, new_element, CE_DROPPED_BY_PLAYER,
                               player->index_bit, drop_side);
     CheckTriggeredElementChangeByPlayer(dropx, dropy, new_element,
                                        CE_PLAYER_DROPS_X,
                                        player->index_bit, drop_side);
-#else
-    CheckTriggeredElementChangeByPlayer(dropx, dropy, new_element,
-                                       CE_PLAYER_DROPS_X,
-                                       player->index_bit, drop_side);
-    CheckElementChangeByPlayer(dropx, dropy, new_element, CE_DROPPED_BY_PLAYER,
-                              player->index_bit, drop_side);
-#endif
 
     TestIfElementTouchesCustomElement(dropx, dropy);
   }
@@ -12499,10 +12653,6 @@ boolean DropElement(struct PlayerInfo *player)
   {
     player->dynabombs_left--;
 
-#if 0
-    new_element = EL_DYNABOMB_PLAYER_1_ACTIVE + player->index_nr;
-#endif
-
     Feld[dropx][dropy] = new_element;
 
     if (IN_SCR_FIELD(SCREENX(dropx), SCREENY(dropy)))
@@ -12512,29 +12662,14 @@ boolean DropElement(struct PlayerInfo *player)
     PlayLevelSoundAction(dropx, dropy, ACTION_DROPPING);
   }
 
-
-
-#if 1
-
   if (Feld[dropx][dropy] == new_element) /* uninitialized unless CE change */
-  {
-#if 1
     InitField_WithBug1(dropx, dropy, FALSE);
-#else
-    InitField(dropx, dropy, FALSE);
-    if (CAN_MOVE(Feld[dropx][dropy]))
-      InitMovDir(dropx, dropy);
-#endif
-  }
 
   new_element = Feld[dropx][dropy];    /* element might have changed */
 
   if (IS_CUSTOM_ELEMENT(new_element) && CAN_MOVE(new_element) &&
       element_info[new_element].move_pattern == MV_WHEN_DROPPED)
   {
-#if 0
-    int move_stepsize = element_info[new_element].move_stepsize;
-#endif
     int move_direction, nextx, nexty;
 
     if (element_info[new_element].move_direction_initial == MV_START_AUTOMATIC)
@@ -12544,60 +12679,18 @@ boolean DropElement(struct PlayerInfo *player)
     nextx = dropx + GET_DX_FROM_DIR(move_direction);
     nexty = dropy + GET_DY_FROM_DIR(move_direction);
 
-#if 1
-    Changed[dropx][dropy] = FALSE;             /* allow another change */
-    CheckCollision[dropx][dropy] = 2;
-#else
-
-    if (IN_LEV_FIELD_AND_IS_FREE(nextx, nexty))
-    {
-#if 0
-      WasJustMoving[dropx][dropy] = 3;
-#else
-#if 1
-      InitMovingField(dropx, dropy, move_direction);
-      ContinueMoving(dropx, dropy);
-#endif
-#endif
-    }
-#if 0
-    /* !!! commented out from 3.1.0-4 to 3.1.0-5 !!! */
-    else
-    {
-      Changed[dropx][dropy] = FALSE;   /* allow another change */
-
-#if 1
-      TestIfElementHitsCustomElement(dropx, dropy, move_direction);
-#else
-      CheckElementChangeBySide(dropx, dropy, new_element, touched_element,
-                              CE_HITTING_SOMETHING, move_direction);
-#endif
-    }
-#endif
-
-#endif
-
-#if 0
-    player->drop_delay = 2 * TILEX / move_stepsize + 1;
-#endif
+    ChangeCount[dropx][dropy] = 0;     /* allow at least one more change */
+    CheckCollision[dropx][dropy] = CHECK_DELAY_COLLISION;
   }
 
-#if 0
-  player->drop_delay = 8 + 8 + 8;
-#endif
-
-#if 1
   player->drop_delay = GET_NEW_DROP_DELAY(drop_element);
-#endif
-
-#endif
-
   player->is_dropping = TRUE;
 
-#if USE_DROP_BUGFIX
+  player->drop_pressed_delay = 0;
+  player->is_dropping_pressed = FALSE;
+
   player->drop_x = dropx;
   player->drop_y = dropy;
-#endif
 
   return TRUE;
 }
@@ -12724,11 +12817,6 @@ void PlayLevelSound_EM(int x, int y, int element_em, int sample)
 {
   int element = (element_em > -1 ? map_element_EM_to_RND(element_em) : 0);
 
-#if 0
-  if (sample == SAMPLE_bug)
-    printf("::: PlayLevelSound_EM: %d, %d: %d\n", x, y, sample);
-#endif
-
   switch (sample)
   {
     case SAMPLE_blank:
@@ -12772,7 +12860,7 @@ void PlayLevelSound_EM(int x, int y, int element_em, int sample)
       break;
 
     case SAMPLE_slurp:
-      PlayLevelSoundElementAction(x, y, element, ACTION_SLURPED_BY_SPRING);
+      PlayLevelSoundElementAction(x, y, element, ACTION_EATING);
       break;
 
     case SAMPLE_eater:
@@ -12934,6 +13022,7 @@ void RaiseScoreElement(int element)
       RaiseScore(level.score[SC_NUT]);
       break;
     case EL_DYNAMITE:
+    case EL_EM_DYNAMITE:
     case EL_SP_DISK_RED:
     case EL_DYNABOMB_INCREASE_NUMBER:
     case EL_DYNABOMB_INCREASE_SIZE:
@@ -12945,7 +13034,7 @@ void RaiseScoreElement(int element)
       RaiseScore(level.score[SC_SHIELD]);
       break;
     case EL_EXTRA_TIME:
-      RaiseScore(level.score[SC_TIME_BONUS]);
+      RaiseScore(level.extra_time_score);
       break;
     case EL_KEY_1:
     case EL_KEY_2:
@@ -12977,7 +13066,7 @@ void RequestQuitGame(boolean ask_if_really_quit)
   {
 #if defined(NETWORK_AVALIABLE)
     if (options.network)
-      SendToServer_StopPlaying();
+      SendToServer_StopPlaying(NETWORK_STOP_BY_PLAYER);
     else
 #endif
     {
@@ -12987,19 +13076,13 @@ void RequestQuitGame(boolean ask_if_really_quit)
   }
   else
   {
-
-#if 1
     if (tape.playing && tape.deactivate_display)
       TapeDeactivateDisplayOff(TRUE);
-#endif
 
     OpenDoor(DOOR_OPEN_1 | DOOR_COPY_BACK);
 
-#if 1
     if (tape.playing && tape.deactivate_display)
       TapeDeactivateDisplayOn();
-#endif
-
   }
 }
 
@@ -13160,7 +13243,10 @@ static void HandleGameButtons(struct GadgetInfo *gi)
   switch (id)
   {
     case GAME_CTRL_ID_STOP:
-      RequestQuitGame(TRUE);
+      if (tape.playing)
+       TapeStop();
+      else
+       RequestQuitGame(TRUE);
       break;
 
     case GAME_CTRL_ID_PAUSE:
@@ -13187,7 +13273,7 @@ static void HandleGameButtons(struct GadgetInfo *gi)
 #endif
        {
          tape.pausing = FALSE;
-         DrawVideoDisplay(VIDEO_STATE_PAUSE_OFF,0);
+         DrawVideoDisplay(VIDEO_STATE_PAUSE_OFF, 0);
        }
       }
       break;
index 4bca9fd69f8253151c8dc6194e2e4cc3256f9f7f..71ad7a0a3b8084c0296b9464c340b8522f15613d 100644 (file)
 #ifndef GAME_H
 #define GAME_H
 
-#include "main.h"
+
+#define MAX_INVENTORY_SIZE     1000
+#define STD_NUM_KEYS           4
+#define MAX_NUM_KEYS           8
+
+
+struct GameInfo
+{
+  /* values for engine initialization */
+  int default_push_delay_fixed;
+  int default_push_delay_random;
+
+  /* constant within running game */
+  int engine_version;
+  int emulation;
+  int initial_move_delay[MAX_PLAYERS];
+  int initial_move_delay_value[MAX_PLAYERS];
+  int initial_push_delay_value;
+
+  /* flags to handle bugs in and changes between different engine versions */
+  /* (for the latest engine version, these flags should always be "FALSE") */
+  boolean use_change_when_pushing_bug;
+  boolean use_block_last_field_bug;
+  boolean max_num_changes_per_frame;
+  boolean use_reverse_scan_direction;
+
+  /* variable within running game */
+  int yamyam_content_nr;
+  boolean magic_wall_active;
+  int magic_wall_time_left;
+  int light_time_left;
+  int timegate_time_left;
+  int belt_dir[4];
+  int belt_dir_nr[4];
+  int switchgate_pos;
+  int wind_direction;
+  boolean gravity;
+  boolean explosions_delayed;
+  boolean envelope_active;
+
+#if 1
+  /* values for the new EMC elements */
+  int lenses_time_left;
+  int magnify_time_left;
+  boolean ball_state;
+  int ball_content_nr;
+#endif
+
+  /* values for player idle animation (no effect on engine) */
+  int player_boring_delay_fixed;
+  int player_boring_delay_random;
+  int player_sleeping_delay_fixed;
+  int player_sleeping_delay_random;
+
+  /* values for special game initialization control */
+  boolean restart_level;
+
+  /* values for special game control */
+  int centered_player_nr;
+  int centered_player_nr_next;
+  boolean set_centered_player;
+};
+
+struct PlayerInfo
+{
+  boolean present;             /* player present in level playfield */
+  boolean connected;           /* player connected (locally or via network) */
+  boolean active;              /* player present and connected */
+
+  int index_nr;                        /* player number (0 to 3) */
+  int index_bit;               /* player number bit (1 << 0 to 1 << 3) */
+  int element_nr;              /* element (EL_PLAYER_1 to EL_PLAYER_4) */
+  int client_nr;               /* network client identifier */
+
+  byte action;                 /* action from local input device */
+  byte effective_action;       /* action acknowledged from network server
+                                  or summarized over all configured input
+                                  devices when in single player mode */
+  byte programmed_action;      /* action forced by game itself (like moving
+                                  through doors); overrides other actions */
+
+  int jx, jy, last_jx, last_jy;
+  int MovDir, MovPos, GfxDir, GfxPos;
+  int Frame, StepFrame;
+
+  int GfxAction;
+
+  boolean use_murphy;
+  int artwork_element;
+
+  boolean block_last_field;
+  int block_delay_adjustment;  /* needed for different engine versions */
+
+  boolean can_fall_into_acid;
+
+  boolean gravity;
+
+  boolean LevelSolved, GameOver;
+
+  int last_move_dir;
+
+  boolean is_active;
+
+  boolean is_waiting;
+  boolean is_moving;
+  boolean is_auto_moving;
+  boolean is_digging;
+  boolean is_snapping;
+  boolean is_collecting;
+  boolean is_pushing;
+  boolean is_switching;
+  boolean is_dropping;
+  boolean is_dropping_pressed;
+
+  boolean is_bored;
+  boolean is_sleeping;
+
+  boolean cannot_move;
+
+  int frame_counter_bored;
+  int frame_counter_sleeping;
+
+  int anim_delay_counter;
+  int post_delay_counter;
+
+  int dir_waiting;
+  int action_waiting, last_action_waiting;
+  int special_action_bored;
+  int special_action_sleeping;
+
+  int num_special_action_bored;
+  int num_special_action_sleeping;
+
+  int switch_x, switch_y;
+  int drop_x, drop_y;
+
+  int show_envelope;
+
+  int move_delay;
+  int move_delay_value;
+  int move_delay_value_next;
+  int move_delay_reset_counter;
+
+  int push_delay;
+  int push_delay_value;
+
+  unsigned long actual_frame_counter;
+
+  int drop_delay;
+  int drop_pressed_delay;
+
+  int step_counter;
+
+  int score;
+  int gems_still_needed;
+  int sokobanfields_still_needed;
+  int lights_still_needed;
+  int friends_still_needed;
+  int key[MAX_NUM_KEYS];
+  int dynabomb_count, dynabomb_size, dynabombs_left, dynabomb_xl;
+  int shield_normal_time_left;
+  int shield_deadly_time_left;
+
+  int inventory_element[MAX_INVENTORY_SIZE];
+  int inventory_infinite_element;
+  int inventory_size;
+};
+
+
+extern struct GameInfo         game;
+extern struct PlayerInfo       stored_player[], *local_player;
+
+
+#ifdef DEBUG
+void DEBUG_SetMaximumDynamite();
+#endif
 
 void GetPlayerConfig(void);
 
@@ -25,61 +200,20 @@ void InitGameSound();
 void InitGame(void);
 
 void UpdateEngineValues(int, int);
-
-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 *);
-int MovingOrBlocked2Element(int, int);
-void RemoveMovingField(int, int);
 void DrawDynamite(int, int);
-void CheckDynamite(int, int);
-void Explode(int, int, int, int);
-void DynaExplode(int, int);
-void Bang(int, int);
-void Blurb(int, int);
-void Impact(int, int);
-void StartMoving(int, int);
-void ContinueMoving(int, int);
-int AmoebeNachbarNr(int, int);
-void AmoebeUmwandeln(int, int);
-void AmoebeUmwandelnBD(int, int, int);
-void AmoebeWaechst(int, int);
-void AmoebeAbleger(int, int);
-void Life(int, int);
-void Ablenk(int, int);
-void Blubber(int, int);
-void NussKnacken(int, int);
-void SiebAktivieren(int, int, int);
-void AusgangstuerPruefen(int, int);
-void AusgangstuerOeffnen(int, int);
-void AusgangstuerBlinken(int, int);
-void EdelsteinFunkeln(int, int);
-void MauerWaechst(int, int);
-void MauerAbleger(int, int);
+
+void StartGameActions(boolean, boolean, long);
 
 void GameActions(void);
-void ScrollLevel(int, int);
+void GameActions_EM_Main();
+void GameActions_RND();
 
-void TestIfGoodThingHitsBadThing(int, int, int);
-void TestIfBadThingHitsGoodThing(int, int, int);
-void TestIfHeroTouchesBadThing(int, int);
-void TestIfHeroRunsIntoBadThing(int, int, int);
-void TestIfBadThingTouchesHero(int, int);
-void TestIfBadThingRunsIntoHero(int, int, int);
-void TestIfFriendTouchesBadThing(int, int);
-void TestIfBadThingTouchesFriend(int, int);
-void TestIfBadThingTouchesOtherBadThing(int, int);
-void KillHero(struct PlayerInfo *);
-void BuryHero(struct PlayerInfo *);
-void RemoveHero(struct PlayerInfo *);
-boolean SnapField(struct PlayerInfo *, int, int);
-boolean DropElement(struct PlayerInfo *);
+void ScrollLevel(int, int);
 
 void InitPlayLevelSound();
 void PlayLevelSound_EM(int, int, int, int);
index 22ea317e33d146044806760c8389bef81ab38586..ab8e5c346fa76cba403bac73d3f45c7dd877f164 100644 (file)
@@ -3,9 +3,7 @@
  * cave data structures
  */
 
-#include "global.h"
-#include "tile.h"
-#include "level.h"
+#include "main_em.h"
 
 
 struct LevelInfo_EM native_em_level;
@@ -17,17 +15,17 @@ void setLevelInfoToDefaults_EM(void)
   native_em_level.file_version = FILE_VERSION_EM_ACTUAL;
 
   native_em_level.lev = &lev;
-  native_em_level.ply1 = &ply1;
-  native_em_level.ply2 = &ply2;
+  for (i = 0; i < MAX_PLAYERS; i++)
+    native_em_level.ply[i] = &ply[i];
 
   lev.width = 64;
   lev.height = 32;
 
-  ply1.x_initial = 0;
-  ply1.y_initial = 0;
-
-  ply2.x_initial = 0;
-  ply2.y_initial = 0;
+  for (i = 0; i < MAX_PLAYERS; i++)
+  {
+    ply[i].x_initial = 0;
+    ply[i].y_initial = 0;
+  }
 
   lev.lenses_cnt_initial = 0;
   lev.magnify_cnt_initial = 0;
@@ -42,13 +40,30 @@ void setLevelInfoToDefaults_EM(void)
   lev.wonderwall_state_initial = 0;
   lev.wonderwall_time_initial = 0;
 
+  lev.num_ball_arrays = 8;
+
   for (i = 0; i < TILE_MAX; i++)
     lev.android_array[i] = Xblank;
 
-  lev.home_initial = 1;                /* initial number of players in this level */
+#if 1
+  /* initial number of players in this level */
+  lev.home_initial = 0;
 
-  ply1.alive_initial = (lev.home_initial >= 1);
-  ply2.alive_initial = (lev.home_initial >= 2);
+  for (i = 0; i < MAX_PLAYERS; i++)
+  {
+    ply[i].exists = 0;
+    ply[i].alive_initial = FALSE;
+  }
+#else
+  /* initial number of players in this level */
+  lev.home_initial = (setup.team_mode ? 2 : 1);
+
+  for (i = 0; i < MAX_PLAYERS; i++)
+  {
+    ply[i].exists = 0;
+    ply[i].alive_initial = (lev.home_initial > i ? TRUE : FALSE);
+  }
+#endif
 }
 
 
index 6287eea207642bdf86973d686e789c984bee2f25..8a44053cabfa187cfe24cff148c6729a8b160d69 100644 (file)
@@ -8,11 +8,11 @@
  * inconsequential, but no doubt it will break some caves.
  */
 
-#include "global.h"
-#include "tile.h"
-#include "level.h"
+#include "main_em.h"
 
 
+#define ALLOW_ROLLING_SPRING
+
 static unsigned char remap_v6[256] =
 {
   /* filter crap for v6 */
@@ -22,7 +22,11 @@ static unsigned char remap_v6[256] =
   0,16,2,18,       36,37,37,37,     40,41,42,43,     44,45,128,128,
   128,148,148,     148,45,45,45,    148,0,57,58,     59,60,61,62,63,
 
+#ifdef ALLOW_ROLLING_SPRING
+  64,65,66,67,     68,69,69,71,     72,73,74,75,     118,75,75,75,
+#else
   64,65,66,67,     68,69,69,69,     69,73,74,75,     118,75,75,75,
+#endif
   75,75,75,75,     75,153,153,153,  153,153,153,153, 153,153,153,153,
   153,153,153,99,  100,68,68,68,    68,68,68,68,     68,118,118,118,
   118,118,114,115, 131,118,118,119, 120,121,122,118, 118,118,118,118,
@@ -151,7 +155,7 @@ int cleanup_em_level(unsigned char *src, int length)
     for (i = 2112; i < 2148; i++) src[i] = src[i - 64];
   }
   else if (length >= 2106 &&
-          src[0] == 241 &&
+          src[0] == 241 &&     /* <-- Emerald Mine I levels */
           src[1983] == 27)
   {
     unsigned char j = 94;
@@ -171,7 +175,7 @@ int cleanup_em_level(unsigned char *src, int length)
   }
 #if 1
   else if (length >= 2106 &&
-          src[0] == 245 &&
+          src[0] == 245 &&     /* <-- Emerald Mine II levels */
           src[1983] == 27)
   {
     unsigned char j = 94;
@@ -181,6 +185,7 @@ int cleanup_em_level(unsigned char *src, int length)
 
     for (i = 0; i < 2106; i++)
       src[i] = (src[i] ^ (j += 7)) - 0x11;
+    src[0] = 131;              /* needed for Emerald Mine II levels */
     src[1] = 131;
     for (i = 0; i < 2048; i++)
       src[i] = remap_v4[src[i]];
@@ -188,13 +193,18 @@ int cleanup_em_level(unsigned char *src, int length)
       src[i] = remap_v4eater[src[i] >= 28 ? 0 : src[i]];
     for (i = 2112; i < 2148; i++)
       src[i] = src[i - 64];
+
+    /* fix copyright sign in Emerald Mine II levels */
+    for (i = 0; i < 2048; i++)
+      if (src[i] == 241)
+       src[i] = 254;           /* replace 'Xdecor_1' with 'Xalpha_copyr' */
   }
 #endif
   else
   {
     /* ---------- this cave has unknown file format ---------- */
 
-#if 1
+#if 0
     printf("::: %d, %d\n", src[0], src[1983]);
 #endif
 
@@ -436,6 +446,11 @@ int cleanup_em_level(unsigned char *src, int length)
  * - rolling spring is now turned into regular spring. it appears the emc
  *   editor only uses the force code for initially moving spring. i will
  *   follow this in my editor.
+ *
+ * 2006-04-02
+ * - introduced ALLOW_ROLLING_SPRING; if defined, do NOT turn rolling spring
+ *   into regular spring, because this breaks at least E.M.C. Mine 3, level 79
+ *   (see comment directly above)
  */
 
 static unsigned short remap_emerald[256] =
@@ -460,10 +475,17 @@ static unsigned short remap_emerald[256] =
   Xstone,              Xgrow_ew,       Xgrow_ns,       Xdynamite_1,
   Xdynamite_2,         Xdynamite_3,    Xdynamite_4,    Xacid_s,
 
+#ifdef ALLOW_ROLLING_SPRING
+  Xexit_1,             Xexit_2,        Xexit_3,        Xballoon,
+  Xplant,              Xspring,        Xspring_fall,   Xspring_w,
+  Xspring_e,           Xball_1,        Xball_2,        Xandroid,
+  Xblank,              Xandroid,       Xandroid,       Xandroid,
+#else
   Xexit_1,             Xexit_2,        Xexit_3,        Xballoon,
   Xplant,              Xspring,        Xspring,        Xspring,
   Xspring,             Xball_1,        Xball_2,        Xandroid,
   Xblank,              Xandroid,       Xandroid,       Xandroid,
+#endif
 
   Xandroid,            Xandroid,       Xandroid,       Xandroid,
   Xandroid,            Xblank,         Xblank,         Xblank,
@@ -538,17 +560,31 @@ static unsigned short remap_emerald[256] =
   Xblank,              Xblank,         Xblank,         Xblank,
 #else
   /* special elements added to solve compatibility problems */
-  Xblank,              Xblank,         Xblank,         Xfake_acid_1
+  Xblank,              Xblank,         Xalpha_copyr,   Xfake_acid_1
 #endif
 };
 
+static int get_em_element(unsigned short em_element_raw, int file_version)
+{
+  int em_element = remap_emerald[em_element_raw];
+
+  if (file_version <= FILE_VERSION_EM_V4)
+  {
+    /* versions up to V4 had no grass, but only sand/dirt */
+    if (em_element == Xgrass)
+      em_element = Xdirt;
+  }
+
+  return em_element;
+}
+
 void convert_em_level(unsigned char *src, int file_version)
 {
   static int eater_offset[8] =
   {
     0x800, 0x809, 0x812, 0x81B, 0x840, 0x849, 0x852, 0x85B
   };
-  unsigned int i, x, y, temp;
+  int i, x, y, temp;
 
 #if 1
   lev.time_seconds = src[0x83E] << 8 | src[0x83F];
@@ -563,12 +599,12 @@ void convert_em_level(unsigned char *src, int file_version)
 
   lev.required_initial = src[0x82F];
 
-  temp = src[0x830] << 8 | src[0x831];
-  ply1.x_initial = (temp & 63) + 1;
-  ply1.y_initial = (temp >> 6 & 31) + 1;
-  temp = src[0x832] << 8 | src[0x833];
-  ply2.x_initial = (temp & 63) + 1;
-  ply2.y_initial = (temp >> 6 & 31) + 1;
+  for (i = 0; i < 2; i++)
+  {
+    temp = src[0x830 + i * 2] << 8 | src[0x831 + i * 2];
+    ply[i].x_initial = (temp & 63) + 1;
+    ply[i].y_initial = (temp >> 6 & 31) + 1;
+  }
 
   temp = (src[0x834] << 8 | src[0x835]) * 28;
   if (temp > 9999)
@@ -611,9 +647,10 @@ void convert_em_level(unsigned char *src, int file_version)
 
   for (i = 0; i < 8; i++)
     for (x = 0; x < 9; x++)
-      lev.eater_array[i][x] = remap_emerald[src[eater_offset[i] + x]];
+      lev.eater_array[i][x] =
+       get_em_element(src[eater_offset[i] + x], file_version);
 
-  temp = remap_emerald[src[0x86F]];
+  temp = get_em_element(src[0x86F], file_version);
   for (y = 0; y < 8; y++)
   {
     if (src[0x872] & 1)
@@ -638,163 +675,173 @@ void convert_em_level(unsigned char *src, int file_version)
 
   if (temp & 1)
   {
-    lev.android_array[Xemerald] =
-      lev.android_array[Xemerald_pause] =
-      lev.android_array[Xemerald_fall] =
-      lev.android_array[Yemerald_sB] =
-      lev.android_array[Yemerald_eB] =
-      lev.android_array[Yemerald_wB] = Xemerald;
+    lev.android_array[Xemerald]                = Xemerald;
+    lev.android_array[Xemerald_pause]  = Xemerald;
+    lev.android_array[Xemerald_fall]   = Xemerald;
+    lev.android_array[Yemerald_sB]     = Xemerald;
+    lev.android_array[Yemerald_eB]     = Xemerald;
+    lev.android_array[Yemerald_wB]     = Xemerald;
   }
 
   if (temp & 2)
   {
-    lev.android_array[Xdiamond] =
-      lev.android_array[Xdiamond_pause] =
-      lev.android_array[Xdiamond_fall] =
-      lev.android_array[Ydiamond_sB] =
-      lev.android_array[Ydiamond_eB] =
-      lev.android_array[Ydiamond_wB] = Xdiamond;
+    lev.android_array[Xdiamond]                = Xdiamond;
+    lev.android_array[Xdiamond_pause]  = Xdiamond;
+    lev.android_array[Xdiamond_fall]   = Xdiamond;
+    lev.android_array[Ydiamond_sB]     = Xdiamond;
+    lev.android_array[Ydiamond_eB]     = Xdiamond;
+    lev.android_array[Ydiamond_wB]     = Xdiamond;
   }
 
   if (temp & 4)
   {
-    lev.android_array[Xstone] =
-      lev.android_array[Xstone_pause] =
-      lev.android_array[Xstone_fall] =
-      lev.android_array[Ystone_sB] =
-      lev.android_array[Ystone_eB] =
-      lev.android_array[Ystone_wB] = Xstone;
+    lev.android_array[Xstone]          = Xstone;
+    lev.android_array[Xstone_pause]    = Xstone;
+    lev.android_array[Xstone_fall]     = Xstone;
+    lev.android_array[Ystone_sB]       = Xstone;
+    lev.android_array[Ystone_eB]       = Xstone;
+    lev.android_array[Ystone_wB]       = Xstone;
   }
 
   if (temp & 8)
   {
-    lev.android_array[Xbomb] =
-      lev.android_array[Xbomb_pause] =
-      lev.android_array[Xbomb_fall] =
-      lev.android_array[Ybomb_sB] =
-      lev.android_array[Ybomb_eB] =
-      lev.android_array[Ybomb_wB] = Xbomb;
+    lev.android_array[Xbomb]           = Xbomb;
+    lev.android_array[Xbomb_pause]     = Xbomb;
+    lev.android_array[Xbomb_fall]      = Xbomb;
+    lev.android_array[Ybomb_sB]                = Xbomb;
+    lev.android_array[Ybomb_eB]                = Xbomb;
+    lev.android_array[Ybomb_wB]                = Xbomb;
   }
 
   if (temp & 16)
   {
-    lev.android_array[Xnut] =
-      lev.android_array[Xnut_pause] =
-      lev.android_array[Xnut_fall] =
-      lev.android_array[Ynut_sB] =
-      lev.android_array[Ynut_eB] =
-      lev.android_array[Ynut_wB] = Xnut;
+    lev.android_array[Xnut]            = Xnut;
+    lev.android_array[Xnut_pause]      = Xnut;
+    lev.android_array[Xnut_fall]       = Xnut;
+    lev.android_array[Ynut_sB]         = Xnut;
+    lev.android_array[Ynut_eB]         = Xnut;
+    lev.android_array[Ynut_wB]         = Xnut;
   }
 
   if (temp & 32)
   {
-    lev.android_array[Xtank_n] =
-      lev.android_array[Xtank_gon] =
-      lev.android_array[Ytank_nB] =
-      lev.android_array[Ytank_n_e] =
-      lev.android_array[Ytank_n_w] = Xtank_n;
-
-    lev.android_array[Xtank_e] =
-      lev.android_array[Xtank_goe] =
-      lev.android_array[Ytank_eB] =
-      lev.android_array[Ytank_e_s] =
-      lev.android_array[Ytank_e_n] = Xtank_e;
-
-    lev.android_array[Xtank_s] =
-      lev.android_array[Xtank_gos] =
-      lev.android_array[Ytank_sB] =
-      lev.android_array[Ytank_s_w] =
-      lev.android_array[Ytank_s_e] = Xtank_s;
-
-    lev.android_array[Xtank_w] =
-      lev.android_array[Xtank_gow] =
-      lev.android_array[Ytank_wB] =
-      lev.android_array[Ytank_w_n] =
-      lev.android_array[Ytank_w_s] = Xtank_w;
+    lev.android_array[Xtank_n]         = Xtank_n;
+    lev.android_array[Xtank_gon]       = Xtank_n;
+    lev.android_array[Ytank_nB]                = Xtank_n;
+    lev.android_array[Ytank_n_e]       = Xtank_n;
+    lev.android_array[Ytank_n_w]       = Xtank_n;
+
+    lev.android_array[Xtank_e]         = Xtank_e;
+    lev.android_array[Xtank_goe]       = Xtank_e;
+    lev.android_array[Ytank_eB]                = Xtank_e;
+    lev.android_array[Ytank_e_s]       = Xtank_e;
+    lev.android_array[Ytank_e_n]       = Xtank_e;
+
+    lev.android_array[Xtank_s]         = Xtank_s;
+    lev.android_array[Xtank_gos]       = Xtank_s;
+    lev.android_array[Ytank_sB]                = Xtank_s;
+    lev.android_array[Ytank_s_w]       = Xtank_s;
+    lev.android_array[Ytank_s_e]       = Xtank_s;
+
+    lev.android_array[Xtank_w]         = Xtank_w;
+    lev.android_array[Xtank_gow]       = Xtank_w;
+    lev.android_array[Ytank_wB]                = Xtank_w;
+    lev.android_array[Ytank_w_n]       = Xtank_w;
+    lev.android_array[Ytank_w_s]       = Xtank_w;
   }
 
   if (temp & 64)
   {
-    lev.android_array[Xeater_n] = lev.android_array[Yeater_nB] = Xeater_n;
-    lev.android_array[Xeater_e] = lev.android_array[Yeater_eB] = Xeater_e;
-    lev.android_array[Xeater_s] = lev.android_array[Yeater_sB] = Xeater_s;
-    lev.android_array[Xeater_w] = lev.android_array[Yeater_wB] = Xeater_w;
-  }
+    lev.android_array[Xeater_n]                = Xeater_n;
+    lev.android_array[Yeater_nB]       = Xeater_n;
 
-  if (temp & 128)
-  {
-    lev.android_array[Xbug_n] =
-      lev.android_array[Xbug_gon] =
-      lev.android_array[Ybug_nB] =
-      lev.android_array[Ybug_n_e] =
-      lev.android_array[Ybug_n_w] = Xbug_gon;
+    lev.android_array[Xeater_e]                = Xeater_e;
+    lev.android_array[Yeater_eB]       = Xeater_e;
 
-    lev.android_array[Xbug_e] =
-      lev.android_array[Xbug_goe] =
-      lev.android_array[Ybug_eB] =
-      lev.android_array[Ybug_e_s] =
-      lev.android_array[Ybug_e_n] = Xbug_goe;
+    lev.android_array[Xeater_s]                = Xeater_s;
+    lev.android_array[Yeater_sB]       = Xeater_s;
 
-    lev.android_array[Xbug_s] =
-      lev.android_array[Xbug_gos] =
-      lev.android_array[Ybug_sB] =
-      lev.android_array[Ybug_s_w] =
-      lev.android_array[Ybug_s_e] = Xbug_gos;
+    lev.android_array[Xeater_w]                = Xeater_w;
+    lev.android_array[Yeater_wB]       = Xeater_w;
+  }
 
-    lev.android_array[Xbug_w] =
-      lev.android_array[Xbug_gow] =
-      lev.android_array[Ybug_wB] =
-      lev.android_array[Ybug_w_n] =
-      lev.android_array[Ybug_w_s] = Xbug_gow;
+  if (temp & 128)
+  {
+    lev.android_array[Xbug_n]          = Xbug_gon;
+    lev.android_array[Xbug_gon]                = Xbug_gon;
+    lev.android_array[Ybug_nB]         = Xbug_gon;
+    lev.android_array[Ybug_n_e]                = Xbug_gon;
+    lev.android_array[Ybug_n_w]                = Xbug_gon;
+
+    lev.android_array[Xbug_e]          = Xbug_goe;
+    lev.android_array[Xbug_goe]                = Xbug_goe;
+    lev.android_array[Ybug_eB]         = Xbug_goe;
+    lev.android_array[Ybug_e_s]                = Xbug_goe;
+    lev.android_array[Ybug_e_n]                = Xbug_goe;
+
+    lev.android_array[Xbug_s]          = Xbug_gos;
+    lev.android_array[Xbug_gos]                = Xbug_gos;
+    lev.android_array[Ybug_sB]         = Xbug_gos;
+    lev.android_array[Ybug_s_w]                = Xbug_gos;
+    lev.android_array[Ybug_s_e]                = Xbug_gos;
+
+    lev.android_array[Xbug_w]          = Xbug_gow;
+    lev.android_array[Xbug_gow]                = Xbug_gow;
+    lev.android_array[Ybug_wB]         = Xbug_gow;
+    lev.android_array[Ybug_w_n]                = Xbug_gow;
+    lev.android_array[Ybug_w_s]                = Xbug_gow;
   }
 
   if (temp & 256)
   {
-    lev.android_array[Xalien] = lev.android_array[Xalien_pause] =
-      lev.android_array[Yalien_nB] = lev.android_array[Yalien_eB] =
-      lev.android_array[Yalien_sB] = lev.android_array[Yalien_wB] = Xalien;
+    lev.android_array[Xalien]          = Xalien;
+    lev.android_array[Xalien_pause]    = Xalien;
+    lev.android_array[Yalien_nB]       = Xalien;
+    lev.android_array[Yalien_eB]       = Xalien;
+    lev.android_array[Yalien_sB]       = Xalien;
+    lev.android_array[Yalien_wB]       = Xalien;
   }
 
   if (temp & 512)
   {
-    lev.android_array[Xspring] =
-      lev.android_array[Xspring_pause] =
-      lev.android_array[Xspring_e] =
-      lev.android_array[Yspring_eB] =
-      lev.android_array[Yspring_kill_eB] =
-      lev.android_array[Xspring_w] =
-      lev.android_array[Yspring_wB] =
-      lev.android_array[Yspring_kill_wB] =
-      lev.android_array[Xspring_fall] =
-      lev.android_array[Yspring_sB] = Xspring;
+    lev.android_array[Xspring]         = Xspring;
+    lev.android_array[Xspring_pause]   = Xspring;
+    lev.android_array[Xspring_e]       = Xspring;
+    lev.android_array[Yspring_eB]      = Xspring;
+    lev.android_array[Yspring_kill_eB] = Xspring;
+    lev.android_array[Xspring_w]       = Xspring;
+    lev.android_array[Yspring_wB]      = Xspring;
+    lev.android_array[Yspring_kill_wB] = Xspring;
+    lev.android_array[Xspring_fall]    = Xspring;
+    lev.android_array[Yspring_sB]      = Xspring;
   }
 
   if (temp & 1024)
   {
-    lev.android_array[Yballoon_nB] =
-      lev.android_array[Yballoon_eB] =
-      lev.android_array[Yballoon_sB] =
-      lev.android_array[Yballoon_wB] =
-      lev.android_array[Xballoon] = Xballoon;
+    lev.android_array[Yballoon_nB]     = Xballoon;
+    lev.android_array[Yballoon_eB]     = Xballoon;
+    lev.android_array[Yballoon_sB]     = Xballoon;
+    lev.android_array[Yballoon_wB]     = Xballoon;
+    lev.android_array[Xballoon]                = Xballoon;
   }
 
   if (temp & 2048)
   {
-    lev.android_array[Xdripper] =
-      lev.android_array[XdripperB] =
-      lev.android_array[Xamoeba_1] =
-      lev.android_array[Xamoeba_2] =
-      lev.android_array[Xamoeba_3] =
-      lev.android_array[Xamoeba_4] =
-      lev.android_array[Xamoeba_5] =
-      lev.android_array[Xamoeba_6] =
-      lev.android_array[Xamoeba_7] =
-      lev.android_array[Xamoeba_8] = Xdrip_eat;
+    lev.android_array[Xdripper]                = Xdrip_eat;
+    lev.android_array[XdripperB]       = Xdrip_eat;
+    lev.android_array[Xamoeba_1]       = Xdrip_eat;
+    lev.android_array[Xamoeba_2]       = Xdrip_eat;
+    lev.android_array[Xamoeba_3]       = Xdrip_eat;
+    lev.android_array[Xamoeba_4]       = Xdrip_eat;
+    lev.android_array[Xamoeba_5]       = Xdrip_eat;
+    lev.android_array[Xamoeba_6]       = Xdrip_eat;
+    lev.android_array[Xamoeba_7]       = Xdrip_eat;
+    lev.android_array[Xamoeba_8]       = Xdrip_eat;
   }
 
   if (temp & 4096)
   {
-    lev.android_array[Xdynamite] = Xdynamite;
+    lev.android_array[Xdynamite]       = Xdynamite;
   }
 
   for (temp = 1; temp < 2047; temp++)
@@ -873,20 +920,28 @@ void convert_em_level(unsigned char *src, int file_version)
   temp = 0;
   for (y = 0; y < lev.height; y++)
     for (x = 0; x < lev.width; x++)
-      native_em_level.cave[x + 1][y + 1] = remap_emerald[src[temp++]];
+      native_em_level.cave[x + 1][y + 1] =
+       get_em_element(src[temp++], file_version);
 
   /* at last, set the two players at their positions in the playfield */
-  if (ply1.alive_initial)
-    native_em_level.cave[ply1.x_initial][ply1.y_initial] = Zplayer;
-  if (ply2.alive_initial)
-    native_em_level.cave[ply2.x_initial][ply2.y_initial] = Zplayer;
+  /* (native EM[C] levels always have exactly two players in a level) */
+#if 1
+  for (i = 0; i < 2; i++)
+    native_em_level.cave[ply[i].x_initial][ply[i].y_initial] = Zplayer;
+#else
+  for (i = 0; i < 2; i++)
+    if (ply[i].alive_initial)
+      native_em_level.cave[ply[i].x_initial][ply[i].y_initial] = Zplayer;
+#endif
 
   native_em_level.file_version = file_version;
 }
 
 void prepare_em_level(void)
 {
-  unsigned int x, y;
+  int i, x, y;
+  int players_left;
+  int num_tape_players;
 
   /* reset all runtime variables to their initial values */
 
@@ -929,39 +984,85 @@ void prepare_em_level(void)
   lev.wheel_x   = lev.wheel_x_initial;
   lev.wheel_y   = lev.wheel_y_initial;
 
-  lev.wind_cnt       = lev.wind_cnt_initial;
   lev.wind_direction = lev.wind_direction_initial;
+  lev.wind_cnt       = lev.wind_cnt_initial;
 
   lev.wonderwall_state = lev.wonderwall_state_initial;
   lev.wonderwall_time  = lev.wonderwall_time_initial;
 
+  lev.killed_out_of_time = FALSE;
+
+  /* determine number of players in this level */
+  lev.home_initial = 0;
+
+  for (i = 0; i < MAX_PLAYERS; i++)
+  {
+    ply[i].exists = 0;
+    ply[i].alive_initial = FALSE;
+
+    if (ply[i].x_initial > 0 && ply[i].y_initial > 0)
+    {
+      ply[i].exists = 1;
+
+      lev.home_initial++;
+    }
+  }
+
+  num_tape_players = getNumActivePlayers_EM();
+
+  if (num_tape_players != -1)
+    lev.home_initial = MIN(lev.home_initial, num_tape_players);
+  else if (!setup.team_mode)
+    lev.home_initial = MIN(lev.home_initial, 1);
+
   lev.home = lev.home_initial;
+  players_left = lev.home_initial;
 
-  lev.killed_out_of_time = FALSE;
+  for (i = 0; i < MAX_PLAYERS; i++)
+  {
+    if (ply[i].exists)
+    {
+      if (players_left)
+      {
+       ply[i].alive_initial = TRUE;
+       players_left--;
+      }
+      else
+      {
+       int x = ply[i].x_initial;
+       int y = ply[i].y_initial;
+
+       native_em_level.cave[x][y] = Xblank;
+
+       Cave[y][x] = Next[y][x] = Draw[y][x] = Xblank;
+      }
+    }
+  }
+
+  for (i = 0; i < MAX_PLAYERS; i++)
+  {
+    ply[i].num = i;
+    ply[i].alive = ply[i].alive_initial;
+    ply[i].dynamite = 0;
+    ply[i].dynamite_cnt = 0;
+    ply[i].keys = 0;
+    ply[i].anim = 0;
+    ply[i].oldx = ply[i].x = ply[i].x_initial;
+    ply[i].oldy = ply[i].y = ply[i].y_initial;
+    ply[i].last_move_dir = MV_NONE;
+    ply[i].joy_n = ply[i].joy_e = ply[i].joy_s = ply[i].joy_w = 0;
+    ply[i].joy_snap  = ply[i].joy_drop = 0;
+    ply[i].joy_stick = ply[i].joy_spin = 0;
+
+#if 0
+    printf("player %d: x/y == %d/%d, alive == %d\n",
+          i, ply[i].x_initial, ply[i].y_initial, ply[i].alive);
+#endif
+  }
+
+  game_em.any_player_moving = FALSE;
+  game_em.last_moving_player = 0;      /* default: first player */
 
-  ply1.num = 0;
-  ply1.alive = ply1.alive_initial;
-  ply1.dynamite = 0;
-  ply1.dynamite_cnt = 0;
-  ply1.keys = 0;
-  ply1.anim = 0;
-  ply1.oldx = ply1.x = ply1.x_initial;
-  ply1.oldy = ply1.y = ply1.y_initial;
-  ply1.last_move_dir = MV_NO_MOVING;
-  ply1.joy_n = ply1.joy_e = ply1.joy_s = ply1.joy_w = 0;
-  ply1.joy_snap = ply1.joy_drop = 0;
-  ply1.joy_stick = ply1.joy_spin = 0;
-
-  ply2.num = 1;
-  ply2.alive = ply2.alive_initial;
-  ply2.dynamite = 0;
-  ply2.dynamite_cnt = 0;
-  ply2.keys = 0;
-  ply2.anim = 0;
-  ply2.oldx = ply2.x = ply2.x_initial;
-  ply2.oldy = ply2.y = ply2.y_initial;
-  ply2.last_move_dir = MV_NO_MOVING;
-  ply2.joy_n = ply2.joy_e = ply2.joy_s = ply2.joy_w = 0;
-  ply2.joy_snap = ply1.joy_drop = 0;
-  ply2.joy_stick = ply2.joy_spin = 0;
+  for (i = 0; i < MAX_PLAYERS; i++)
+    game_em.last_player_direction[i] = MV_NONE;
 }
diff --git a/src/game_em/display.h b/src/game_em/display.h
deleted file mode 100644 (file)
index f6a82af..0000000
+++ /dev/null
@@ -1,79 +0,0 @@
-#ifndef DISPLAY_H
-#define DISPLAY_H
-
-#include "main_em.h"
-
-#define ORIG_TILEX             16
-#define ORIG_TILEY             16
-#define ORIG_SCOREX            8
-#define ORIG_SCOREY            9
-#define ORIG_GFXMENUFONTX      14
-#define ORIG_GFXMENUFONTY      16
-#define ORIG_MENUFONTX         12
-#define ORIG_MENUFONTY         16
-
-#define ZOOM_FACTOR            2
-
-#define TILEX                  (ORIG_TILEX             * ZOOM_FACTOR)
-#define TILEY                  (ORIG_TILEY             * ZOOM_FACTOR)
-#define SCOREX                 (ORIG_SCOREX            * ZOOM_FACTOR)
-#define SCOREY                 (ORIG_SCOREY            * ZOOM_FACTOR)
-#define GFXMENUFONTX           (ORIG_GFXMENUFONTX      * ZOOM_FACTOR)
-#define GFXMENUFONTY           (ORIG_GFXMENUFONTY      * ZOOM_FACTOR)
-#define MENUFONTX              (ORIG_MENUFONTX         * ZOOM_FACTOR)
-#define MENUFONTY              (ORIG_MENUFONTY         * ZOOM_FACTOR)
-
-#define ORIG_SCR_MENUX         20
-#define ORIG_SCR_MENUY         12
-#define SCR_MENUX              17
-#define SCR_MENUY              12
-#define SCR_FIELDX             17
-#define SCR_FIELDY             17
-#define MAX_BUF_XSIZE          (SCR_FIELDX + 2)
-#define MAX_BUF_YSIZE          (SCR_FIELDY + 2)
-
-/* often used screen positions */
-#define ORIG_MENU_SX           ((ORIG_SCR_MENUX - SCR_MENUX) * TILEX / 2)
-#define ORIG_MENU_SY           0
-#define SY                     8
-#define SX                     8
-#define SY                     8
-#define SXSIZE                 (SCR_FIELDX * TILEX)
-#define SYSIZE                 (SCR_FIELDY * TILEY)
-
-#if 1
-#define FRAMES_PER_SECOND      50
-
-#define ROUNDED_DIVIDE(x, y)   (((x) + (y) - 1) / (y))
-
-#define SECONDS_TO_FRAMES(x)   ((x) * FRAMES_PER_SECOND)
-#define FRAMES_TO_SECONDS(x)   ((x) / FRAMES_PER_SECOND)
-
-#define SECONDS_TO_CYCLES(x)   ROUNDED_DIVIDE((x) * FRAMES_PER_SECOND, 8)
-#define CYCLES_TO_SECONDS(x)   ROUNDED_DIVIDE((x) * 8, FRAMES_PER_SECOND)
-
-#define DISPLAY_TIME(x)                ROUNDED_DIVIDE(x, FRAMES_PER_SECOND)
-
-#else
-
-#define DISPLAY_TIME(x)                (((x) * 8 + 49) / 50)
-#endif
-
-extern Bitmap *screenBitmap;
-extern Bitmap *scoreBitmap;
-
-extern Bitmap *objBitmap;
-extern Bitmap *sprBitmap;
-extern Bitmap *ttlBitmap;
-extern Bitmap *botBitmap;
-
-extern Pixmap screenPixmap;
-extern Pixmap scorePixmap;
-extern Pixmap spriteBitmap;
-
-extern Pixmap objmaskBitmap;
-extern Pixmap sprmaskBitmap;
-
-extern GC spriteGC;
-
-#endif
diff --git a/src/game_em/export.h b/src/game_em/export.h
new file mode 100644 (file)
index 0000000..9801d0c
--- /dev/null
@@ -0,0 +1,717 @@
+#ifndef EXPORT_H
+#define EXPORT_H
+
+/* ========================================================================= */
+/* functions and definitions exported from game_em to main program           */
+/* ========================================================================= */
+
+/* ------------------------------------------------------------------------- */
+/* constant definitions                                                      */
+/* ------------------------------------------------------------------------- */
+
+/* define these for backwards compatibility */
+#define EM_ENGINE_BAD_ROLL
+#define EM_ENGINE_BAD_SPRING
+
+/* define these to use additional elements */
+#define EM_ENGINE_USE_ADDITIONAL_ELEMENTS
+
+/* internal definitions for EM engine */
+#ifdef EM_ENGINE_BAD_ROLL
+#define BAD_ROLL
+#endif
+
+#ifdef EM_ENGINE_BAD_SPRING
+#define BAD_SPRING
+#endif
+
+/* one border for ZBORDER elements, one border for steelwall, if needed */
+#define EM_MAX_CAVE_WIDTH              (MAX_PLAYFIELD_WIDTH  + 2 + 2)
+#define EM_MAX_CAVE_HEIGHT             (MAX_PLAYFIELD_HEIGHT + 2 + 2)
+
+/*
+  -----------------------------------------------------------------------------
+  definition of elements used in the Emerald Mine Club engine;
+  the element names have the following properties:
+  - elements that start with 'X' can be stored in a level file
+  - elements that start with 'Y' indicate moving elements
+  - elements that end with 'B' are the "backside" of moving elements
+  -----------------------------------------------------------------------------
+*/
+
+enum
+{
+  Xblank = 0,          /* still */
+  Yacid_splash_eB,     /* hmm */
+  Yacid_splash_wB,     /* hmm */
+
+#ifdef EM_ENGINE_BAD_ROLL
+  Xstone_force_e,      /* only use these in eater */
+  Xstone_force_w,
+  Xnut_force_e,
+  Xnut_force_w,
+  Xspring_force_e,
+  Xspring_force_w,
+  Xemerald_force_e,
+  Xemerald_force_w,
+  Xdiamond_force_e,
+  Xdiamond_force_w,
+  Xbomb_force_e,
+  Xbomb_force_w,
+#endif
+
+  Xstone,
+  Xstone_pause,
+  Xstone_fall,
+  Ystone_s,
+  Ystone_sB,
+  Ystone_e,
+  Ystone_eB,
+  Ystone_w,
+  Ystone_wB,
+  Xnut,
+  Xnut_pause,
+  Xnut_fall,
+  Ynut_s,
+  Ynut_sB,
+  Ynut_e,
+  Ynut_eB,
+  Ynut_w,
+  Ynut_wB,
+  Xbug_n,
+  Xbug_e,
+  Xbug_s,
+  Xbug_w,
+  Xbug_gon,
+  Xbug_goe,
+  Xbug_gos,
+  Xbug_gow,
+  Ybug_n,
+  Ybug_nB,
+  Ybug_e,
+  Ybug_eB,
+  Ybug_s,
+  Ybug_sB,
+  Ybug_w,
+  Ybug_wB,
+  Ybug_w_n,
+  Ybug_n_e,
+  Ybug_e_s,
+  Ybug_s_w,
+  Ybug_e_n,
+  Ybug_s_e,
+  Ybug_w_s,
+  Ybug_n_w,
+  Ybug_stone,
+  Ybug_spring,
+  Xtank_n,
+  Xtank_e,
+  Xtank_s,
+  Xtank_w,
+  Xtank_gon,
+  Xtank_goe,
+  Xtank_gos,
+  Xtank_gow,
+  Ytank_n,
+  Ytank_nB,
+  Ytank_e,
+  Ytank_eB,
+  Ytank_s,
+  Ytank_sB,
+  Ytank_w,
+  Ytank_wB,
+  Ytank_w_n,
+  Ytank_n_e,
+  Ytank_e_s,
+  Ytank_s_w,
+  Ytank_e_n,
+  Ytank_s_e,
+  Ytank_w_s,
+  Ytank_n_w,
+  Ytank_stone,
+  Ytank_spring,
+  Xandroid,
+  Xandroid_1_n,
+  Xandroid_2_n,
+  Xandroid_1_e,
+  Xandroid_2_e,
+  Xandroid_1_w,
+  Xandroid_2_w,
+  Xandroid_1_s,
+  Xandroid_2_s,
+  Yandroid_n,
+  Yandroid_nB,
+  Yandroid_ne,
+  Yandroid_neB,
+  Yandroid_e,
+  Yandroid_eB,
+  Yandroid_se,
+  Yandroid_seB,
+  Yandroid_s,
+  Yandroid_sB,
+  Yandroid_sw,
+  Yandroid_swB,
+  Yandroid_w,
+  Yandroid_wB,
+  Yandroid_nw,
+  Yandroid_nwB,
+  Xspring,
+  Xspring_pause,
+  Xspring_e,
+  Xspring_w,
+  Xspring_fall,
+  Yspring_s,
+  Yspring_sB,
+  Yspring_e,
+  Yspring_eB,
+  Yspring_w,
+  Yspring_wB,
+  Yspring_kill_e,
+  Yspring_kill_eB,
+  Yspring_kill_w,
+  Yspring_kill_wB,
+  Xeater_n,
+  Xeater_e,
+  Xeater_w,
+  Xeater_s,
+  Yeater_n,
+  Yeater_nB,
+  Yeater_e,
+  Yeater_eB,
+  Yeater_s,
+  Yeater_sB,
+  Yeater_w,
+  Yeater_wB,
+  Yeater_stone,
+  Yeater_spring,
+  Xalien,
+  Xalien_pause,
+  Yalien_n,
+  Yalien_nB,
+  Yalien_e,
+  Yalien_eB,
+  Yalien_s,
+  Yalien_sB,
+  Yalien_w,
+  Yalien_wB,
+  Yalien_stone,
+  Yalien_spring,
+  Xemerald,
+  Xemerald_pause,
+  Xemerald_fall,
+  Xemerald_shine,
+  Yemerald_s,
+  Yemerald_sB,
+  Yemerald_e,
+  Yemerald_eB,
+  Yemerald_w,
+  Yemerald_wB,
+  Yemerald_eat,
+  Yemerald_stone,
+  Xdiamond,
+  Xdiamond_pause,
+  Xdiamond_fall,
+  Xdiamond_shine,
+  Ydiamond_s,
+  Ydiamond_sB,
+  Ydiamond_e,
+  Ydiamond_eB,
+  Ydiamond_w,
+  Ydiamond_wB,
+  Ydiamond_eat,
+  Ydiamond_stone,
+  Xdrip_fall,
+  Xdrip_stretch,
+  Xdrip_stretchB,
+  Xdrip_eat,
+  Ydrip_s1,
+  Ydrip_s1B,
+  Ydrip_s2,
+  Ydrip_s2B,
+  Xbomb,
+  Xbomb_pause,
+  Xbomb_fall,
+  Ybomb_s,
+  Ybomb_sB,
+  Ybomb_e,
+  Ybomb_eB,
+  Ybomb_w,
+  Ybomb_wB,
+  Ybomb_eat,
+  Xballoon,
+  Yballoon_n,
+  Yballoon_nB,
+  Yballoon_e,
+  Yballoon_eB,
+  Yballoon_s,
+  Yballoon_sB,
+  Yballoon_w,
+  Yballoon_wB,
+  Xgrass,
+  Ygrass_nB,
+  Ygrass_eB,
+  Ygrass_sB,
+  Ygrass_wB,
+  Xdirt,
+  Ydirt_nB,
+  Ydirt_eB,
+  Ydirt_sB,
+  Ydirt_wB,
+  Xacid_ne,
+  Xacid_se,
+  Xacid_s,
+  Xacid_sw,
+  Xacid_nw,
+  Xacid_1,
+  Xacid_2,
+  Xacid_3,
+  Xacid_4,
+  Xacid_5,
+  Xacid_6,
+  Xacid_7,
+  Xacid_8,
+  Xball_1,
+  Xball_1B,
+  Xball_2,
+  Xball_2B,
+  Yball_eat,
+
+#ifdef EM_ENGINE_USE_ADDITIONAL_ELEMENTS
+  Ykey_1_eat,
+  Ykey_2_eat,
+  Ykey_3_eat,
+  Ykey_4_eat,
+  Ykey_5_eat,
+  Ykey_6_eat,
+  Ykey_7_eat,
+  Ykey_8_eat,
+  Ylenses_eat,
+  Ymagnify_eat,
+  Ygrass_eat,
+  Ydirt_eat,
+#endif
+
+  Xgrow_ns,
+  Ygrow_ns_eat,
+  Xgrow_ew,
+  Ygrow_ew_eat,
+  Xwonderwall,
+  XwonderwallB,
+  Xamoeba_1,
+  Xamoeba_2,
+  Xamoeba_3,
+  Xamoeba_4,
+  Xamoeba_5,
+  Xamoeba_6,
+  Xamoeba_7,
+  Xamoeba_8,
+  Xdoor_1,
+  Xdoor_2,
+  Xdoor_3,
+  Xdoor_4,
+  Xdoor_5,
+  Xdoor_6,
+  Xdoor_7,
+  Xdoor_8,
+  Xkey_1,
+  Xkey_2,
+  Xkey_3,
+  Xkey_4,
+  Xkey_5,
+  Xkey_6,
+  Xkey_7,
+  Xkey_8,
+  Xwind_n,
+  Xwind_e,
+  Xwind_s,
+  Xwind_w,
+  Xwind_nesw,
+  Xwind_stop,
+  Xexit,
+  Xexit_1,
+  Xexit_2,
+  Xexit_3,
+  Xdynamite,
+  Ydynamite_eat,
+  Xdynamite_1,
+  Xdynamite_2,
+  Xdynamite_3,
+  Xdynamite_4,
+  Xbumper,
+  XbumperB,
+  Xwheel,
+  XwheelB,
+  Xswitch,
+  XswitchB,
+  Xsand,
+  Xsand_stone,
+  Xsand_stonein_1,
+  Xsand_stonein_2,
+  Xsand_stonein_3,
+  Xsand_stonein_4,
+  Xsand_stonesand_1,
+  Xsand_stonesand_2,
+  Xsand_stonesand_3,
+  Xsand_stonesand_4,
+  Xsand_stoneout_1,
+  Xsand_stoneout_2,
+  Xsand_sandstone_1,
+  Xsand_sandstone_2,
+  Xsand_sandstone_3,
+  Xsand_sandstone_4,
+  Xplant,
+  Yplant,
+  Xlenses,
+  Xmagnify,
+  Xdripper,
+  XdripperB,
+  Xfake_blank,
+  Xfake_blankB,
+  Xfake_grass,
+  Xfake_grassB,
+  Xfake_door_1,
+  Xfake_door_2,
+  Xfake_door_3,
+  Xfake_door_4,
+  Xfake_door_5,
+  Xfake_door_6,
+  Xfake_door_7,
+  Xfake_door_8,
+
+#ifdef EM_ENGINE_USE_ADDITIONAL_ELEMENTS
+  Xfake_acid_1,
+  Xfake_acid_2,
+  Xfake_acid_3,
+  Xfake_acid_4,
+  Xfake_acid_5,
+  Xfake_acid_6,
+  Xfake_acid_7,
+  Xfake_acid_8,
+#endif
+
+  Xsteel_1,
+  Xsteel_2,
+  Xsteel_3,
+  Xsteel_4,
+  Xwall_1,
+  Xwall_2,
+  Xwall_3,
+  Xwall_4,
+  Xround_wall_1,
+  Xround_wall_2,
+  Xround_wall_3,
+  Xround_wall_4,
+  Xdecor_1,
+  Xdecor_2,
+  Xdecor_3,
+  Xdecor_4,
+  Xdecor_5,
+  Xdecor_6,
+  Xdecor_7,
+  Xdecor_8,
+  Xdecor_9,
+  Xdecor_10,
+  Xdecor_11,
+  Xdecor_12,
+  Xalpha_0,
+  Xalpha_1,
+  Xalpha_2,
+  Xalpha_3,
+  Xalpha_4,
+  Xalpha_5,
+  Xalpha_6,
+  Xalpha_7,
+  Xalpha_8,
+  Xalpha_9,
+  Xalpha_excla,
+  Xalpha_quote,
+  Xalpha_comma,
+  Xalpha_minus,
+  Xalpha_perio,
+  Xalpha_colon,
+  Xalpha_quest,
+  Xalpha_a,
+  Xalpha_b,
+  Xalpha_c,
+  Xalpha_d,
+  Xalpha_e,
+  Xalpha_f,
+  Xalpha_g,
+  Xalpha_h,
+  Xalpha_i,
+  Xalpha_j,
+  Xalpha_k,
+  Xalpha_l,
+  Xalpha_m,
+  Xalpha_n,
+  Xalpha_o,
+  Xalpha_p,
+  Xalpha_q,
+  Xalpha_r,
+  Xalpha_s,
+  Xalpha_t,
+  Xalpha_u,
+  Xalpha_v,
+  Xalpha_w,
+  Xalpha_x,
+  Xalpha_y,
+  Xalpha_z,
+  Xalpha_arrow_e,
+  Xalpha_arrow_w,
+  Xalpha_copyr,
+
+  Xboom_bug,           /* passed from explode to synchro (linked explosion);
+                          transition to explode_normal */
+  Xboom_bomb,          /* passed from explode to synchro (linked explosion);
+                          transition to explode_normal */
+  Xboom_android,       /* passed from explode to synchro;
+                          transition to boom_2 */
+  Xboom_1,             /* passed from explode to synchro;
+                          transition to boom_2 */
+  Xboom_2,             /* transition to boom[] */
+
+  Znormal,             /* passed from synchro to explode, only in next[];
+                          no picture */
+  Zdynamite,           /* passed from synchro to explode, only in next[];
+                          no picture */
+  Zplayer,             /* special code to indicate player;
+                          no picture */
+  ZBORDER,             /* special code to indicate border;
+                          no picture */
+
+  TILE_MAX
+};
+
+/* other definitions */
+
+enum
+{
+  SPR_still = 0,
+  SPR_walk  = 1,
+  SPR_push  = 5,
+  SPR_spray = 9,
+
+  SPR_MAX   = 13
+};
+
+enum
+{
+  SAMPLE_blank = 0,    /* player walks on blank */
+  SAMPLE_roll,         /* player pushes stone/bomb/nut/spring */
+  SAMPLE_stone,                /* stone hits ground */
+  SAMPLE_nut,          /* nut hits ground */
+  SAMPLE_crack,                /* stone hits nut */
+  SAMPLE_bug,          /* bug moves */
+  SAMPLE_tank,         /* tank moves */
+  SAMPLE_android_clone,        /* android places something */
+  SAMPLE_android_move, /* android moves */
+  SAMPLE_spring,       /* spring hits ground/wall/bumper, stone hits spring */
+  SAMPLE_slurp,                /* spring kills alien */
+  SAMPLE_eater,                /* eater sits */
+  SAMPLE_eater_eat,    /* eater eats diamond */
+  SAMPLE_alien,                /* alien moves */
+  SAMPLE_collect,      /* player collects object */
+  SAMPLE_diamond,      /* diamond/emerald hits ground */
+  SAMPLE_squash,       /* stone squashes diamond */
+  SAMPLE_wonderfall,   /* object falls thru wonderwall */
+  SAMPLE_drip,         /* drip hits ground */
+  SAMPLE_push,         /* player pushes balloon/android */
+  SAMPLE_dirt,         /* player walks on dirt */
+  SAMPLE_acid,         /* acid splashes */
+  SAMPLE_ball,         /* ball places something */
+  SAMPLE_grow,         /* growing wall grows */
+  SAMPLE_wonder,       /* wonderwall is active */
+  SAMPLE_door,         /* player goes thru door (gate) */
+  SAMPLE_exit_open,    /* exit opens */
+  SAMPLE_exit_leave,   /* player goes into exit */
+  SAMPLE_dynamite,     /* player places dynamite */
+  SAMPLE_tick,         /* dynamite ticks */
+  SAMPLE_press,                /* player presses wheel/wind/switch */
+  SAMPLE_wheel,                /* wheel moves */
+  SAMPLE_boom,         /* explosion */
+  SAMPLE_time,         /* time runs out */
+  SAMPLE_die,          /* player dies */
+
+  SAMPLE_MAX
+};
+
+
+/* ------------------------------------------------------------------------- */
+/* data structure definitions                                                */
+/* ------------------------------------------------------------------------- */
+
+struct LEVEL
+{
+  int home_initial;            /* number of players (initial) */
+  int home;                    /* number of players not yet at home */
+                               /* 0 == all players at home */
+
+  int width;                   /* playfield width */
+  int height;                  /* playfield height */
+
+  int time_seconds;            /* available time (seconds) */
+  int time_initial;            /* available time (initial) */
+  int time;                    /* time remaining (runtime) */
+
+  boolean killed_out_of_time;  /* kill player due to time out */
+
+  int required_initial;                /* emeralds needed (initial) */
+  int required;                        /* emeralds needed (runtime) */
+
+  int score;                   /* score */
+
+  /* all below entries must be filled every time a level is read */
+
+  int alien_score;             /* score for killing alien */
+  int amoeba_time;             /* amoeba speed */
+  int android_move_cnt_initial;        /* android move counter (initial) */
+  int android_move_cnt;                /* android move counter */
+  int android_move_time;       /* android move reset time */
+  int android_clone_cnt_initial;/* android clone counter (initial) */
+  int android_clone_cnt;       /* android clone counter */
+  int android_clone_time;      /* android clone reset time */
+  int ball_cnt;                        /* ball counter */
+  int ball_pos;                        /* ball array pos counter */
+  int ball_random;             /* ball is random flag */
+  int ball_state_initial;      /* ball active flag (initial) */
+  int ball_state;              /* ball active flag */
+  int ball_time;               /* ball reset time */
+  int bug_score;               /* score for killing bug */
+  int diamond_score;           /* score for collecting diamond */
+  int dynamite_score;          /* score for collecting dynamite */
+  int eater_pos;               /* eater array pos */
+  int eater_score;             /* score for killing eater */
+  int emerald_score;           /* score for collecting emerald */
+  int exit_score;              /* score for entering exit */
+  int key_score;               /* score for colleting key */
+  int lenses_cnt_initial;      /* lenses counter (initial) */
+  int lenses_cnt;              /* lenses counter */
+  int lenses_score;            /* score for collecting lenses */
+  int lenses_time;             /* lenses reset time */
+  int magnify_cnt_initial;     /* magnify counter (initial) */
+  int magnify_cnt;             /* magnify counter */
+  int magnify_score;           /* score for collecting magnifier */
+  int magnify_time;            /* magnify reset time */
+  int nut_score;               /* score for cracking nut */
+  int shine_cnt;               /* shine counter for emerald/diamond */
+  int slurp_score;             /* score for slurping alien */
+  int tank_score;              /* score for killing tank */
+  int wheel_cnt_initial;       /* wheel counter (initial) */
+  int wheel_cnt;               /* wheel counter */
+  int wheel_x_initial;         /* wheel x pos (initial) */
+  int wheel_x;                 /* wheel x pos */
+  int wheel_y_initial;         /* wheel y pos (initial) */
+  int wheel_y;                 /* wheel y pos */
+  int wheel_time;              /* wheel reset time */
+  int wind_cnt_initial;                /* wind counter (initial) */
+  int wind_cnt;                        /* wind time counter */
+  int wind_direction_initial;  /* wind direction (initial) */
+  int wind_direction;          /* wind direction */
+  int wind_time;               /* wind reset time */
+  int wonderwall_state_initial;        /* wonderwall active flag (initial) */
+  int wonderwall_state;                /* wonderwall active flag */
+  int wonderwall_time_initial; /* wonderwall time (initial) */
+  int wonderwall_time;         /* wonderwall time */
+  short eater_array[8][9];     /* eater data */
+  short ball_array[8][8];      /* ball data */
+  short android_array[TILE_MAX];/* android clone table */
+  int num_ball_arrays;         /* number of ball data arrays used */
+};
+
+struct PLAYER
+{
+  int num;
+  int exists;
+  int alive_initial;
+  int alive;
+
+  int dynamite;
+  int dynamite_cnt;
+  int keys;
+  int anim;
+
+  int x_initial;
+  int y_initial;
+  int x;
+  int y;
+  int oldx;
+  int oldy;
+
+  int last_move_dir;
+
+  int joy_n:1;
+  int joy_e:1;
+  int joy_s:1;
+  int joy_w:1;
+  int joy_snap:1;
+  int joy_drop:1;
+  int joy_stick:1;
+  int joy_spin:1;
+};
+
+struct GlobalInfo_EM
+{
+  Bitmap *screenbuffer;
+};
+
+struct GameInfo_EM
+{
+  boolean any_player_moving;
+  int last_moving_player;
+  int last_player_direction[MAX_PLAYERS];
+};
+
+struct LevelInfo_EM
+{
+  int file_version;
+
+  short cave[EM_MAX_CAVE_WIDTH][EM_MAX_CAVE_HEIGHT];
+
+  struct LEVEL *lev;
+  struct PLAYER *ply[MAX_PLAYERS];
+};
+
+struct GraphicInfo_EM
+{
+  Bitmap *bitmap;
+  int src_x, src_y;
+  int src_offset_x, src_offset_y;
+  int dst_offset_x, dst_offset_y;
+  int width, height;
+
+  Bitmap *crumbled_bitmap;
+  int crumbled_src_x, crumbled_src_y;
+  int crumbled_border_size;
+
+  boolean has_crumbled_graphics;
+  boolean preserve_background;
+
+  int unique_identifier;       /* used to identify needed screen updates */
+};
+
+
+/* ------------------------------------------------------------------------- */
+/* exported functions                                                        */
+/* ------------------------------------------------------------------------- */
+
+extern struct GlobalInfo_EM global_em_info;
+extern struct LevelInfo_EM native_em_level;
+extern struct GraphicInfo_EM graphic_info_em_object[TILE_MAX][8];
+extern struct GraphicInfo_EM graphic_info_em_player[MAX_PLAYERS][SPR_MAX][8];
+
+extern void em_open_all();
+extern void em_close_all();
+
+extern void InitGameEngine_EM();
+extern void GameActions_EM(byte *, boolean);
+
+extern unsigned int InitEngineRND_EM(long);
+
+extern void setLevelInfoToDefaults_EM();
+extern boolean LoadNativeLevel_EM(char *);
+
+extern void BlitScreenToBitmap_EM(Bitmap *);
+extern void RedrawPlayfield_EM(boolean);
+extern void DrawGameDoorValues_EM();
+
+#endif /* EXPORT_H */
index 820d7aa6a7e3ec3ace41fb3a8a7aa87f20b686dc..0407fa5ca699ebaec4e4e585bd8c6180bf4ccd81 100644 (file)
 
 #define GAME_EM_VERSION_1_0_0
 
-
-/* ========================================================================= */
-/* functions and definitions exported from game_em to main program           */
-/* ========================================================================= */
-
-#include "main_em.h"
-
-extern struct GlobalInfo_EM global_em_info;
-extern struct LevelInfo_EM native_em_level;
-extern struct GraphicInfo_EM graphic_info_em_object[TILE_MAX][8];
-extern struct GraphicInfo_EM graphic_info_em_player[2][SPR_MAX][8];
-
-extern void em_open_all();
-extern void em_close_all();
-
-extern void InitGameEngine_EM();
-extern void GameActions_EM(byte);
-
-extern unsigned int InitEngineRND_EM(long);
-
-extern void setLevelInfoToDefaults_EM();
-extern boolean LoadNativeLevel_EM(char *);
-
-extern void BlitScreenToBitmap_EM(Bitmap *);
-extern void RedrawPlayfield_EM();
-extern void DrawGameDoorValues_EM();
+#include "export.h"
 
 #endif /* GAME_EM_H */
index 2d30f24ecc522297252bfab894fb4241d6685cef..2f062e512625d78d5b3412ba2fe44c50154af41a 100644 (file)
@@ -14,7 +14,7 @@ extern int debug;
 extern char *progname;
 extern char *arg_basedir;
 
-extern unsigned int frame;
+extern int frame;
 
 extern short ulaw_to_linear[256];
 extern unsigned char linear_to_ulaw[65536];
@@ -24,7 +24,11 @@ extern unsigned char linear_to_ulaw[65536];
 int open_all(void);
 void close_all(void);
 
+#if 1
+void readjoy(byte, struct PLAYER *);
+#else
 void readjoy(byte);
+#endif
 void input_eventloop(void);
 
 void blitscreen(void);
index 06f974a2e935777387583b68373e7897e55b2ff6..deee45a380a905e09b93cb2f02609659b33edfa2 100644 (file)
@@ -3,29 +3,55 @@
  * graphics manipulation crap
  */
 
-#include "global.h"
-#include "display.h"
-#include "level.h"
+#include "main_em.h"
 
+#define MIN_SCREEN_XPOS                1
+#define MIN_SCREEN_YPOS                1
+#define MAX_SCREEN_XPOS                MAX(1, lev.width  - (SCR_FIELDX - 1))
+#define MAX_SCREEN_YPOS                MAX(1, lev.height - (SCR_FIELDY - 1))
 
-unsigned int frame;            /* current screen frame */
-unsigned int screen_x;         /* current scroll position */
-unsigned int screen_y;
+#define MIN_SCREEN_X           (MIN_SCREEN_XPOS * TILEX)
+#define MIN_SCREEN_Y           (MIN_SCREEN_YPOS * TILEY)
+#define MAX_SCREEN_X           (MAX_SCREEN_XPOS * TILEX)
+#define MAX_SCREEN_Y           (MAX_SCREEN_YPOS * TILEY)
+
+#define VALID_SCREEN_X(x)      ((x) < MIN_SCREEN_X ? MIN_SCREEN_X :    \
+                                (x) > MAX_SCREEN_X ? MAX_SCREEN_X : (x))
+#define VALID_SCREEN_Y(y)      ((y) < MIN_SCREEN_Y ? MIN_SCREEN_Y :    \
+                                (y) > MAX_SCREEN_Y ? MAX_SCREEN_Y : (y))
+
+#define PLAYER_SCREEN_X(p)     (((    frame) * ply[p].oldx +           \
+                                 (8 - frame) * ply[p].x) * TILEX / 8   \
+                                - ((SCR_FIELDX - 1) * TILEX) / 2)
+#define PLAYER_SCREEN_Y(p)     (((    frame) * ply[p].oldy +           \
+                                 (8 - frame) * ply[p].y) * TILEY / 8   \
+                                - ((SCR_FIELDY - 1) * TILEY) / 2)
+
+
+int frame;                     /* current screen frame */
+int screen_x;                  /* current scroll position */
+int screen_y;
 
 /* tiles currently on screen */
-static unsigned int screentiles[MAX_BUF_YSIZE][MAX_BUF_XSIZE];
-static unsigned int crumbled_state[MAX_BUF_YSIZE][MAX_BUF_XSIZE];
+static int screentiles[MAX_BUF_YSIZE][MAX_BUF_XSIZE];
+static int crumbled_state[MAX_BUF_YSIZE][MAX_BUF_XSIZE];
 
+static boolean redraw[MAX_BUF_XSIZE][MAX_BUF_YSIZE];
 
-/* copy the entire screen to the window at the scroll position
- *
- * perhaps use mit-shm to speed this up
- */
+#if 0
+#if 1
+int centered_player_nr;
+#else
+static int centered_player_nr;
+#endif
+#endif
+
+/* copy the entire screen to the window at the scroll position */
 
 void BlitScreenToBitmap_EM(Bitmap *target_bitmap)
 {
-  unsigned int x = screen_x % (MAX_BUF_XSIZE * TILEX);
-  unsigned int y = screen_y % (MAX_BUF_YSIZE * TILEY);
+  int x = screen_x % (MAX_BUF_XSIZE * TILEX);
+  int y = screen_y % (MAX_BUF_YSIZE * TILEY);
 
   if (x < 2 * TILEX && y < 2 * TILEY)
   {
@@ -69,7 +95,43 @@ void BlitScreenToBitmap_EM(Bitmap *target_bitmap)
 
 void blitscreen(void)
 {
-  BlitScreenToBitmap_EM(window);
+  static boolean scrolling_last = FALSE;
+  int left = screen_x / TILEX;
+  int top  = screen_y / TILEY;
+  boolean scrolling = (screen_x % TILEX != 0 || screen_y % TILEY != 0);
+  int x, y;
+
+  if (redraw_tiles > REDRAWTILES_THRESHOLD || scrolling || scrolling_last)
+  {
+    /* blit all (up to four) parts of the scroll buffer to the backbuffer */
+    BlitScreenToBitmap_EM(backbuffer);
+
+    /* blit the completely updated backbuffer to the window (in one blit) */
+    BlitBitmap(backbuffer, window, SX, SY, SXSIZE, SYSIZE, SX, SY);
+  }
+  else
+  {
+    for (x = 0; x < SCR_FIELDX; x++)
+    {
+      for (y = 0; y < SCR_FIELDY; y++)
+      {
+       int xx = (left + x) % MAX_BUF_XSIZE;
+       int yy = (top  + y) % MAX_BUF_YSIZE;
+
+       if (redraw[xx][yy])
+         BlitBitmap(screenBitmap, window,
+                    xx * TILEX, yy * TILEY, TILEX, TILEY,
+                    SX + x * TILEX, SY + y * TILEY);
+      }
+    }
+  }
+
+  for (x = 0; x < MAX_BUF_XSIZE; x++)
+    for (y = 0; y < MAX_BUF_YSIZE; y++)
+      redraw[x][y] = FALSE;
+  redraw_tiles = 0;
+
+  scrolling_last = scrolling;
 }
 
 static void DrawLevelField_EM(int x, int y, int sx, int sy,
@@ -83,6 +145,13 @@ static void DrawLevelField_EM(int x, int y, int sx, int sy,
   int dst_y = sy * TILEY + g->dst_offset_y;
   int width = g->width;
   int height = g->height;
+  int left = screen_x / TILEX;
+  int top  = screen_y / TILEY;
+
+  /* do not draw fields that are outside the visible screen area */
+  if (x < left || x >= left + MAX_BUF_XSIZE ||
+      y < top  || y >= top  + MAX_BUF_YSIZE)
+    return;
 
   if (draw_masked)
   {
@@ -110,7 +179,14 @@ static void DrawLevelFieldCrumbled_EM(int x, int y, int sx, int sy,
 {
   int tile = Draw[y][x];
   struct GraphicInfo_EM *g = &graphic_info_em_object[tile][frame];
-  unsigned int i;
+  int left = screen_x / TILEX;
+  int top  = screen_y / TILEY;
+  int i;
+
+  /* do not draw fields that are outside the visible screen area */
+  if (x < left || x >= left + MAX_BUF_XSIZE ||
+      y < top  || y >= top  + MAX_BUF_YSIZE)
+    return;
 
   if (crm == 0)                /* no crumbled edges for this tile */
     return;
@@ -166,6 +242,14 @@ static void DrawLevelPlayer_EM(int x1, int y1, int player_nr, int anim,
   int src_x = g->src_x, src_y = g->src_y;
   int dst_x, dst_y;
 
+  /* do not draw fields that are outside the visible screen area */
+  if (x1 < screen_x - TILEX || x1 >= screen_x + MAX_BUF_XSIZE * TILEX ||
+      y1 < screen_y - TILEY || y1 >= screen_y + MAX_BUF_YSIZE * TILEY)
+    return;
+
+  x1 %= MAX_BUF_XSIZE * TILEX;
+  y1 %= MAX_BUF_YSIZE * TILEY;
+
   if (draw_masked)
   {
     /* draw the player to current location */
@@ -217,15 +301,13 @@ static void DrawLevelPlayer_EM(int x1, int y1, int player_nr, int anim,
 /* draw differences between game tiles and screen tiles
  *
  * implicitly handles scrolling and restoring background under the sprites
- *
- * perhaps use mit-shm to speed this up
  */
 
 static void animscreen(void)
 {
-  unsigned int x, y, i;
-  unsigned int left = screen_x / TILEX;
-  unsigned int top = screen_y / TILEY;
+  int x, y, i;
+  int left = screen_x / TILEX;
+  int top  = screen_y / TILEY;
   static int xy[4][2] =
   {
     { 0, -1 },
@@ -242,8 +324,8 @@ static void animscreen(void)
       int sy = y % MAX_BUF_YSIZE;    
       int tile = Draw[y][x];
       struct GraphicInfo_EM *g = &graphic_info_em_object[tile][frame];
-      unsigned int obj = g->unique_identifier;
-      unsigned int crm = 0;
+      int obj = g->unique_identifier;
+      int crm = 0;
 
       /* re-calculate crumbled state of this tile */
       if (g->has_crumbled_graphics)
@@ -273,6 +355,9 @@ static void animscreen(void)
 
        screentiles[sy][sx] = obj;
        crumbled_state[sy][sx] = crm;
+
+       redraw[sx][sy] = TRUE;
+       redraw_tiles++;
       }
     }
   }
@@ -286,7 +371,7 @@ static void animscreen(void)
 
 static void blitplayer(struct PLAYER *ply)
 {
-  unsigned int x1, y1, x2, y2;
+  int x1, y1, x2, y2;
 
   if (!ply->alive)
     return;
@@ -297,8 +382,8 @@ static void blitplayer(struct PLAYER *ply)
   x2 = x1 + TILEX - 1;
   y2 = y1 + TILEY - 1;
 
-  if ((unsigned int)(x2 - screen_x) < ((MAX_BUF_XSIZE - 1) * TILEX - 1) &&
-      (unsigned int)(y2 - screen_y) < ((MAX_BUF_YSIZE - 1) * TILEY - 1))
+  if ((int)(x2 - screen_x) < ((MAX_BUF_XSIZE - 1) * TILEX - 1) &&
+      (int)(y2 - screen_y) < ((MAX_BUF_YSIZE - 1) * TILEY - 1))
   {
     /* some casts to "int" are needed because of negative calculation values */
     int dx = (int)ply->x - (int)ply->oldx;
@@ -319,10 +404,12 @@ static void blitplayer(struct PLAYER *ply)
     /* only diggable elements can be crumbled in the classic EM engine */
     boolean player_is_digging = (new_crm != 0);
 
+#if 0
     x1 %= MAX_BUF_XSIZE * TILEX;
     y1 %= MAX_BUF_YSIZE * TILEY;
     x2 %= MAX_BUF_XSIZE * TILEX;
     y2 %= MAX_BUF_YSIZE * TILEY;
+#endif
 
     if (player_is_digging)
     {
@@ -364,11 +451,21 @@ static void blitplayer(struct PLAYER *ply)
 
 void game_initscreen(void)
 {
-  unsigned int x,y;
+  int x,y;
+  int dynamite_state = ply[0].dynamite;                /* !!! ONLY PLAYER 1 !!! */
+  int all_keys_state = ply[0].keys | ply[1].keys | ply[2].keys | ply[3].keys;
+  int player_nr;
 
   frame = 6;
-  screen_x = 0;
-  screen_y = 0;
+
+#if 0
+  game.centered_player_nr = getCenteredPlayerNr_EM();
+#endif
+
+  player_nr = (game.centered_player_nr != -1 ? game.centered_player_nr : 0);
+
+  screen_x = VALID_SCREEN_X(PLAYER_SCREEN_X(player_nr));
+  screen_y = VALID_SCREEN_Y(PLAYER_SCREEN_Y(player_nr));
 
   for (y = 0; y < MAX_BUF_YSIZE; y++)
   {
@@ -379,40 +476,529 @@ void game_initscreen(void)
     }
   }
 
-#if 1
-  DrawAllGameValues(lev.required, ply1.dynamite, lev.score,
-                   lev.time, ply1.keys | ply2.keys);
-#else
-  DrawAllGameValues(lev.required, ply1.dynamite, lev.score,
-                   DISPLAY_TIME(lev.time + 4), ply1.keys | ply2.keys);
+  DrawAllGameValues(lev.required, dynamite_state, lev.score,
+                   lev.time, all_keys_state);
+}
+
+#if 0
+void DrawRelocatePlayer(struct PlayerInfo *player, boolean quick_relocation)
+{
+  boolean ffwd_delay = (tape.playing && tape.fast_forward);
+  boolean no_delay = (tape.warp_forward);
+  int frame_delay_value = (ffwd_delay ? FfwdFrameDelay : GameFrameDelay);
+  int wait_delay_value = (no_delay ? 0 : frame_delay_value);
+  int jx = player->jx;
+  int jy = player->jy;
+
+  if (quick_relocation)
+  {
+    int offset = (setup.scroll_delay ? 3 : 0);
+
+    if (!IN_VIS_FIELD(SCREENX(jx), SCREENY(jy)))
+    {
+      scroll_x = (player->jx < SBX_Left  + MIDPOSX ? SBX_Left :
+                 player->jx > SBX_Right + MIDPOSX ? SBX_Right :
+                 player->jx - MIDPOSX);
+
+      scroll_y = (player->jy < SBY_Upper + MIDPOSY ? SBY_Upper :
+                 player->jy > SBY_Lower + MIDPOSY ? SBY_Lower :
+                 player->jy - MIDPOSY);
+    }
+    else
+    {
+      if ((player->MovDir == MV_LEFT  && scroll_x > jx - MIDPOSX + offset) ||
+         (player->MovDir == MV_RIGHT && scroll_x < jx - MIDPOSX - offset))
+       scroll_x = jx - MIDPOSX + (scroll_x < jx-MIDPOSX ? -offset : +offset);
+
+      if ((player->MovDir == MV_UP  && scroll_y > jy - MIDPOSY + offset) ||
+         (player->MovDir == MV_DOWN && scroll_y < jy - MIDPOSY - offset))
+       scroll_y = jy - MIDPOSY + (scroll_y < jy-MIDPOSY ? -offset : +offset);
+
+      /* don't scroll over playfield boundaries */
+      if (scroll_x < SBX_Left || scroll_x > SBX_Right)
+       scroll_x = (scroll_x < SBX_Left ? SBX_Left : SBX_Right);
+
+      /* don't scroll over playfield boundaries */
+      if (scroll_y < SBY_Upper || scroll_y > SBY_Lower)
+       scroll_y = (scroll_y < SBY_Upper ? SBY_Upper : SBY_Lower);
+    }
+
+    RedrawPlayfield(TRUE, 0,0,0,0);
+  }
+  else
+  {
+    int scroll_xx = -999, scroll_yy = -999;
+
+    ScrollScreen(NULL, SCROLL_GO_ON);  /* scroll last frame to full tile */
+
+    while (scroll_xx != scroll_x || scroll_yy != scroll_y)
+    {
+      int dx = 0, dy = 0;
+      int fx = FX, fy = FY;
+
+      scroll_xx = (player->jx < SBX_Left  + MIDPOSX ? SBX_Left :
+                  player->jx > SBX_Right + MIDPOSX ? SBX_Right :
+                  player->jx - MIDPOSX);
+
+      scroll_yy = (player->jy < SBY_Upper + MIDPOSY ? SBY_Upper :
+                  player->jy > SBY_Lower + MIDPOSY ? SBY_Lower :
+                  player->jy - MIDPOSY);
+
+      dx = (scroll_xx < scroll_x ? +1 : scroll_xx > scroll_x ? -1 : 0);
+      dy = (scroll_yy < scroll_y ? +1 : scroll_yy > scroll_y ? -1 : 0);
+
+      if (dx == 0 && dy == 0)          /* no scrolling needed at all */
+       break;
+
+      scroll_x -= dx;
+      scroll_y -= dy;
+
+      fx += dx * TILEX / 2;
+      fy += dy * TILEY / 2;
+
+      ScrollLevel(dx, dy);
+      DrawAllPlayers();
+
+      /* scroll in two steps of half tile size to make things smoother */
+      BlitBitmap(drawto_field, window, fx, fy, SXSIZE, SYSIZE, SX, SY);
+      FlushDisplay();
+      Delay(wait_delay_value);
+
+      /* scroll second step to align at full tile size */
+      BackToFront();
+      Delay(wait_delay_value);
+    }
+
+    DrawPlayer(player);
+    BackToFront();
+    Delay(wait_delay_value);
+  }
+}
 #endif
+
+static int getMaxCenterDistancePlayerNr(int center_x, int center_y)
+{
+  int max_dx = 0, max_dy = 0;
+  int player_nr = game_em.last_moving_player;
+  int i;
+
+  for (i = 0; i < MAX_PLAYERS; i++)
+  {
+    if (ply[i].alive)
+    {
+      int sx = PLAYER_SCREEN_X(i);
+      int sy = PLAYER_SCREEN_Y(i);
+
+      if (game_em.last_player_direction[i] != MV_NONE &&
+         (ABS(sx - center_x) > max_dx ||
+          ABS(sy - center_y) > max_dy))
+      {
+       max_dx = MAX(max_dx, ABS(sx - center_x));
+       max_dy = MAX(max_dy, ABS(sy - center_y));
+
+       player_nr = i;
+      }
+    }
+  }
+
+  return player_nr;
+}
+
+static void setMinimalPlayerBoundaries(int *sx1, int *sy1, int *sx2, int *sy2)
+{
+  boolean num_checked_players = 0;
+  int i;
+
+  for (i = 0; i < MAX_PLAYERS; i++)
+  {
+    if (ply[i].alive)
+    {
+      int sx = PLAYER_SCREEN_X(i);
+      int sy = PLAYER_SCREEN_Y(i);
+
+      if (num_checked_players == 0)
+      {
+       *sx1 = *sx2 = sx;
+       *sy1 = *sy2 = sy;
+      }
+      else
+      {
+       *sx1 = MIN(*sx1, sx);
+       *sy1 = MIN(*sy1, sy);
+       *sx2 = MAX(*sx2, sx);
+       *sy2 = MAX(*sy2, sy);
+      }
+
+      num_checked_players++;
+    }
+  }
+}
+
+boolean checkIfAllPlayersFitToScreen()
+{
+  int sx1 = 0, sy1 = 0, sx2 = 0, sy2 = 0;
+
+  setMinimalPlayerBoundaries(&sx1, &sy1, &sx2, &sy2);
+
+  return (sx2 - sx1 <= SCR_FIELDX * TILEX &&
+         sy2 - sy1 <= SCR_FIELDY * TILEY);
+}
+
+static void setScreenCenteredToAllPlayers(int *sx, int *sy)
+{
+  int sx1 = screen_x, sy1 = screen_y, sx2 = screen_x, sy2 = screen_y;
+
+  setMinimalPlayerBoundaries(&sx1, &sy1, &sx2, &sy2);
+
+  *sx = (sx1 + sx2) / 2;
+  *sy = (sy1 + sy2) / 2;
 }
 
-void RedrawPlayfield_EM()
+static void setMaxCenterDistanceForAllPlayers(int *max_dx, int *max_dy,
+                                             int center_x, int center_y)
 {
-  unsigned int x,y;
+  int sx1 = center_x, sy1 = center_y, sx2 = center_x, sy2 = center_y;
+
+  setMinimalPlayerBoundaries(&sx1, &sy1, &sx2, &sy2);
+
+  *max_dx = MAX(ABS(sx1 - center_x), ABS(sx2 - center_x));
+  *max_dy = MAX(ABS(sy1 - center_y), ABS(sy2 - center_y));
+}
+
+static boolean checkIfAllPlayersAreVisible(int center_x, int center_y)
+{
+  int max_dx, max_dy;
+
+  setMaxCenterDistanceForAllPlayers(&max_dx, &max_dy, center_x, center_y);
+
+  return (max_dx <= SCR_FIELDX * TILEX / 2 &&
+         max_dy <= SCR_FIELDY * TILEY / 2);
+}
+
+void RedrawPlayfield_EM(boolean force_redraw)
+{
+#if 0
+  boolean all_players_visible = checkIfAllPlayersAreVisible();
+#endif
+  boolean draw_new_player_location = FALSE;
+  boolean quick_relocation = setup.quick_switch;
+#if 0
+  boolean scrolling = (screen_x % TILEX != 0 || screen_y % TILEY != 0);
+#endif
+#if 0
+  boolean game.set_centered_player = getSetCenteredPlayer_EM();
+  int game.centered_player_nr_next = getCenteredPlayerNr_EM();
+#endif
+#if 1
+  int max_center_distance_player_nr =
+    getMaxCenterDistancePlayerNr(screen_x, screen_y);
+#else
+  int player_nr = game_em.last_moving_player;
+#endif
+  int stepsize = TILEX / 8;
+  int offset = (setup.scroll_delay ? 3 : 0) * TILEX;
+  int offset_x = offset;
+  int offset_y = offset;
+  int screen_x_old = screen_x;
+  int screen_y_old = screen_y;
+  int x, y, sx, sy;
+  int i;
+
+  if (game.set_centered_player)
+  {
+    boolean all_players_fit_to_screen = checkIfAllPlayersFitToScreen();
+
+    /* switching to "all players" only possible if all players fit to screen */
+    if (game.centered_player_nr_next == -1 && !all_players_fit_to_screen)
+    {
+      game.centered_player_nr_next = game.centered_player_nr;
+      game.set_centered_player = FALSE;
+    }
+
+    /* do not switch focus to non-existing (or non-active) player */
+    if (game.centered_player_nr_next >= 0 &&
+       !ply[game.centered_player_nr_next].alive)
+    {
+      game.centered_player_nr_next = game.centered_player_nr;
+      game.set_centered_player = FALSE;
+    }
+  }
+
+#if 1
+  /* also allow focus switching when screen is scrolled to half tile */
+#else
+  if (!scrolling)      /* screen currently aligned at tile position */
+#endif
+  {
+#if 1
+    if (game.set_centered_player)
+#else
+    if (game.centered_player_nr != game.centered_player_nr_next)
+#endif
+    {
+      game.centered_player_nr = game.centered_player_nr_next;
+
+      draw_new_player_location = TRUE;
+      force_redraw = TRUE;
+
+      game.set_centered_player = FALSE;
+    }
+  }
+
+  if (game.centered_player_nr == -1)
+  {
+#if 1
+    if (draw_new_player_location || offset == 0)
+#else
+    if (draw_new_player_location)
+#endif
+    {
+      setScreenCenteredToAllPlayers(&sx, &sy);
+    }
+    else
+    {
+#if 1
+      sx = PLAYER_SCREEN_X(max_center_distance_player_nr);
+      sy = PLAYER_SCREEN_Y(max_center_distance_player_nr);
+#else
+      sx = PLAYER_SCREEN_X(game_em.last_moving_player);
+      sy = PLAYER_SCREEN_Y(game_em.last_moving_player);
+#endif
+    }
+  }
+  else
+  {
+    sx = PLAYER_SCREEN_X(game.centered_player_nr);
+    sy = PLAYER_SCREEN_Y(game.centered_player_nr);
+  }
+
+  if (draw_new_player_location && quick_relocation)
+  {
+    screen_x = VALID_SCREEN_X(sx);
+    screen_y = VALID_SCREEN_Y(sy);
+    screen_x_old = screen_x;
+    screen_y_old = screen_y;
+
+#if 0
+    offset_x = 0;
+    offset_y = 0;
+#endif
+  }
+
+  if (draw_new_player_location && !quick_relocation)
+  {
+#if 1
+    unsigned long game_frame_delay_value = getGameFrameDelay_EM(20);
+#else
+    unsigned long game_frame_delay_value = getGameFrameDelay_EM(25);
+#endif
+    int wait_delay_value = game_frame_delay_value;
+    int screen_xx = VALID_SCREEN_X(sx);
+    int screen_yy = VALID_SCREEN_Y(sy);
+
+    while (screen_x != screen_xx || screen_y != screen_yy)
+    {
+      int dx = (screen_xx < screen_x ? +1 : screen_xx > screen_x ? -1 : 0);
+      int dy = (screen_yy < screen_y ? +1 : screen_yy > screen_y ? -1 : 0);
+      int dxx = 0, dyy = 0;
+
+      if (dx == 0 && dy == 0)          /* no scrolling needed at all */
+       break;
+
+#if 1
+
+      if (ABS(screen_xx - screen_x) >= TILEX)
+      {
+       screen_x -= dx * TILEX;
+       dxx = dx * TILEX / 2;
+      }
+      else
+      {
+       screen_x = screen_xx;
+       dxx = 0;
+      }
+
+      if (ABS(screen_yy - screen_y) >= TILEY)
+      {
+       screen_y -= dy * TILEY;
+       dyy = dy * TILEY / 2;
+      }
+      else
+      {
+       screen_y = screen_yy;
+       dyy = 0;
+      }
+
+#else
+
+#if 1
+      if (ABS(screen_xx - screen_x) >= TILEX ||
+         ABS(screen_yy - screen_y) >= TILEY)
+      {
+       screen_x -= dx * TILEX;
+       screen_y -= dy * TILEY;
+
+       dxx = dx * TILEX / 2;
+       dyy = dy * TILEY / 2;
+      }
+      else
+      {
+       screen_x = screen_xx;
+       screen_y = screen_yy;
+
+       dxx = 0;
+       dyy = 0;
+      }
+#else
+      screen_x -= dx * TILEX;
+      screen_y -= dy * TILEY;
+
+      dxx += dx * TILEX / 2;
+      dyy += dy * TILEY / 2;
+#endif
+
+#endif
+
+      /* scroll in two steps of half tile size to make things smoother */
+      screen_x += dxx;
+      screen_y += dyy;
 
-  x = (frame * ply1.oldx + (8 - frame) * ply1.x) * TILEX / 8
-    + ((SCR_FIELDX - 1) * TILEX) / 2;
-  y = (frame * ply1.oldy + (8 - frame) * ply1.y) * TILEY / 8
-    + ((SCR_FIELDY - 1) * TILEY) / 2;
+      animscreen();
 
-  if (x > lev.width * TILEX)
-    x = lev.width * TILEX;
-  if (y > lev.height * TILEY)
-    y = lev.height * TILEY;
+      for (i = 0; i < MAX_PLAYERS; i++)
+       blitplayer(&ply[i]);
 
-  if (x < SCR_FIELDX * TILEX)
-    x = SCR_FIELDX * TILEY;
-  if (y < SCR_FIELDY * TILEY)
-    y = SCR_FIELDY * TILEY;
+      blitscreen();
+      FlushDisplay();
+      Delay(wait_delay_value);
 
-  screen_x = x - (SCR_FIELDX - 1) * TILEX;
-  screen_y = y - (SCR_FIELDY - 1) * TILEY;
+      /* scroll second step to align at full tile size */
+      screen_x -= dxx;
+      screen_y -= dyy;
+
+      SyncDisplay();
+
+      animscreen();
+
+      for (i = 0; i < MAX_PLAYERS; i++)
+       blitplayer(&ply[i]);
+
+      blitscreen();
+      FlushDisplay();
+      Delay(wait_delay_value);
+    }
+
+    screen_x_old = screen_x;
+    screen_y_old = screen_y;
+  }
+
+  if (force_redraw)
+  {
+    for (y = 0; y < MAX_BUF_YSIZE; y++)
+    {
+      for (x = 0; x < MAX_BUF_XSIZE; x++)
+      {
+       screentiles[y][x] = -1;
+       crumbled_state[y][x] = 0;
+      }
+    }
+  }
+
+  /* calculate new screen scrolling position, with regard to scroll delay */
+  screen_x = VALID_SCREEN_X(sx + offset_x < screen_x ? sx + offset_x :
+                           sx - offset_x > screen_x ? sx - offset_x :
+                           screen_x);
+  screen_y = VALID_SCREEN_Y(sy + offset_y < screen_y ? sy + offset_y :
+                           sy - offset_y > screen_y ? sy - offset_y :
+                           screen_y);
+
+#if 1
+  /* prevent scrolling further than double player step size when scrolling */
+  if (ABS(screen_x - screen_x_old) > 2 * stepsize ||
+      ABS(screen_y - screen_y_old) > 2 * stepsize)
+  {
+    int dx = SIGN(screen_x - screen_x_old);
+    int dy = SIGN(screen_y - screen_y_old);
+
+    screen_x = screen_x_old + dx * 2 * stepsize;
+    screen_y = screen_y_old + dy * 2 * stepsize;
+  }
+#else
+  /* prevent scrolling further than player step size when scrolling */
+  if (ABS(screen_x - screen_x_old) > stepsize ||
+      ABS(screen_y - screen_y_old) > stepsize)
+  {
+    int dx = SIGN(screen_x - screen_x_old);
+    int dy = SIGN(screen_y - screen_y_old);
+
+    screen_x = screen_x_old + dx * stepsize;
+    screen_y = screen_y_old + dy * stepsize;
+  }
+#endif
+
+  /* prevent scrolling away from the other players when focus on all players */
+  if (game.centered_player_nr == -1)
+  {
+#if 1
+    /* check if all players are still visible with new scrolling position */
+    if (checkIfAllPlayersAreVisible(screen_x_old, screen_y_old) &&
+       !checkIfAllPlayersAreVisible(screen_x, screen_y))
+    {
+      /* reset horizontal scroll position to last value, if needed */
+      if (!checkIfAllPlayersAreVisible(screen_x, screen_y_old))
+       screen_x = screen_x_old;
+
+      /* reset vertical scroll position to last value, if needed */
+      if (!checkIfAllPlayersAreVisible(screen_x_old, screen_y))
+       screen_y = screen_y_old;
+    }
+#else
+    boolean all_players_visible = checkIfAllPlayersAreVisible();
+
+    if (!all_players_visible)
+    {
+      printf("::: not all players visible\n");
+
+      screen_x = screen_x_old;
+      screen_y = screen_y_old;
+    }
+#endif
+  }
+
+  /* prevent scrolling (for screen correcting) if no player is moving */
+  if (!game_em.any_player_moving)
+  {
+    screen_x = screen_x_old;
+    screen_y = screen_y_old;
+  }
+  else
+  {
+    /* prevent scrolling against the players move direction */
+#if 0
+    int player_nr = game_em.last_moving_player;
+#endif
+    int player_nr = (game.centered_player_nr == -1 ?
+                    max_center_distance_player_nr : game.centered_player_nr);
+    int player_move_dir = game_em.last_player_direction[player_nr];
+    int dx = SIGN(screen_x - screen_x_old);
+    int dy = SIGN(screen_y - screen_y_old);
+
+    if ((dx < 0 && player_move_dir != MV_LEFT) ||
+       (dx > 0 && player_move_dir != MV_RIGHT))
+      screen_x = screen_x_old;
+
+    if ((dy < 0 && player_move_dir != MV_UP) ||
+       (dy > 0 && player_move_dir != MV_DOWN))
+      screen_y = screen_y_old;
+  }
 
   animscreen();
-  blitplayer(&ply1);
-  blitplayer(&ply2);
+
+  for (i = 0; i < MAX_PLAYERS; i++)
+    blitplayer(&ply[i]);
+
+  SyncDisplay();
+
   blitscreen();
 
   FlushDisplay();
@@ -420,14 +1006,52 @@ void RedrawPlayfield_EM()
 
 void game_animscreen(void)
 {
-  RedrawPlayfield_EM();
+  RedrawPlayfield_EM(FALSE);
 }
 
 void DrawGameDoorValues_EM()
 {
 #if 1
-  DrawAllGameValues(lev.required, ply1.dynamite, lev.score,
-                   lev.time, ply1.keys | ply2.keys);
+  int dynamite_state;
+  int key_state;
+#else
+  int dynamite_state = ply[0].dynamite;                /* !!! ONLY PLAYER 1 !!! */
+  int key_state = ply[0].keys | ply[1].keys | ply[2].keys | ply[3].keys;
+#endif
+
+#if 1
+  if (game.centered_player_nr == -1)
+  {
+#if 1
+    int i;
+
+    dynamite_state = 0;
+    key_state = 0;
+
+    for (i = 0; i < MAX_PLAYERS; i++)
+    {
+      dynamite_state += ply[i].dynamite;
+      key_state |= ply[i].keys;
+    }
+
+#else
+
+    dynamite_state = ply[0].dynamite;          /* !!! ONLY PLAYER 1 !!! */
+    key_state = ply[0].keys | ply[1].keys | ply[2].keys | ply[3].keys;
+#endif
+  }
+  else
+  {
+    int player_nr = game.centered_player_nr;
+
+    dynamite_state = ply[player_nr].dynamite;
+    key_state = ply[player_nr].keys;
+  }
+#endif
+
+#if 1
+  DrawAllGameValues(lev.required, dynamite_state, lev.score,
+                   lev.time, key_state);
 #else
   DrawAllGameValues(lev.required, ply1.dynamite, lev.score,
                    DISPLAY_TIME(lev.time), ply1.keys | ply2.keys);
index 54759eefbe5a12ca785365e6fca8817e1a079f58..a756d24a1974aaf99b3353141f3704fc2f036622 100644 (file)
@@ -3,19 +3,15 @@
  * open X11 display and sound
  */
 
+#include "main_em.h"
+
+
 #include <signal.h>
 
 #if !defined(TARGET_SDL)
 #include <sys/wait.h>
 #endif
 
-#include "main_em.h"
-
-#include "global.h"
-#include "display.h"
-#include "sample.h"
-#include "level.h"
-
 
 Bitmap *objBitmap;
 Bitmap *sprBitmap;
@@ -44,6 +40,7 @@ int play_element[SAMPLE_MAX];
 static boolean use_native_em_sound = 0;
 
 struct GlobalInfo_EM global_em_info;
+struct GameInfo_EM game_em;
 
 #if defined(AUDIO_UNIX_NATIVE)
 static int sound_pid = -1;
@@ -299,18 +296,18 @@ void em_close_all(void)
 
 /* ---------------------------------------------------------------------- */
 
-extern unsigned int screen_x;
-extern unsigned int screen_y;
+extern int screen_x;
+extern int screen_y;
 
 void play_element_sound(int x, int y, int sample, int element)
 {
 #if 0
-  unsigned int left = screen_x / TILEX;
-  unsigned int top  = screen_y / TILEY;
+  int left = screen_x / TILEX;
+  int top  = screen_y / TILEY;
 
   if ((x == -1 && y == -1) ||  /* play sound in the middle of the screen */
-      ((unsigned int)(y - top)  <= SCR_FIELDY &&
-       (unsigned int)(x - left) <= SCR_FIELDX))
+      ((int)(y - top)  <= SCR_FIELDY &&
+       (int)(x - left) <= SCR_FIELDX))
 #endif
   {
 #if 1
index 7418f0b6a55547757d60334fb3a3089733dbd348..353b36eec71687f862d7a44fd7b2f7a0061c9b16 100644 (file)
@@ -3,27 +3,24 @@
  * handle input from x11 and keyboard and joystick
  */
 
-#include "global.h"
-#include "display.h"
-#include "level.h"
+#include "main_em.h"
 
 
 unsigned long RandomEM;
 
-struct PLAYER ply1;
-struct PLAYER ply2;
 struct LEVEL lev;
+struct PLAYER ply[MAX_PLAYERS];
 
-unsigned short **Boom;
-unsigned short **Cave;
-unsigned short **Next;
-unsigned short **Draw;
+short **Boom;
+short **Cave;
+short **Next;
+short **Draw;
 
-static unsigned short *Index[4][HEIGHT];
-static unsigned short Array[4][HEIGHT][WIDTH];
+static short *Index[4][HEIGHT];
+static short Array[4][HEIGHT][WIDTH];
 
-extern unsigned int screen_x;
-extern unsigned int screen_y;
+extern int screen_x;
+extern int screen_y;
 
 void game_init_vars(void)
 {
@@ -67,21 +64,9 @@ void InitGameEngine_EM()
   game_animscreen();
 }
 
-void GameActions_EM(byte action)
+void GameActions_EM(byte action[MAX_PLAYERS], boolean warp_mode)
 {
-  static unsigned long game_frame_delay = 0;
-#if 1
-  unsigned long game_frame_delay_value = getGameFrameDelay_EM(20);
-#else
-  unsigned long game_frame_delay_value = getGameFrameDelay_EM(25);
-#endif
-
-#if 0
-  /* this is done in screens.c/HandleGameActions() by calling BackToFront() */
-  XSync(display, False);       /* block until all graphics are drawn */
-#endif
-
-  WaitUntilDelayReached(&game_frame_delay, game_frame_delay_value);
+  int i;
 
   game_animscreen();
 
@@ -89,7 +74,8 @@ void GameActions_EM(byte action)
 
   frame = (frame - 1) & 7;
 
-  readjoy(action);
+  for (i = 0; i < MAX_PLAYERS; i++)
+    readjoy(action[i], &ply[i]);
 
   UpdateEngineValues(screen_x / TILEX, screen_y / TILEY);
 
@@ -104,31 +90,17 @@ void GameActions_EM(byte action)
     synchro_3();
     sound_play();
 
-    if (game_frame_delay_value > 0)    /* do not redraw values in warp mode */
+    if (!warp_mode)            /* do not redraw values in warp mode */
       DrawGameDoorValues_EM();
   }
-
-#if 0
-  if (lev.time_initial == 0)
-    lev.time++;
-  else if (lev.time > 0)
-    lev.time--;
-#endif
-
-#if 0
-  if (lev.time_initial > 0 &&
-      lev.time > 0 && lev.time <= 50 && lev.time % 5 == 0 && setup.time_limit)
-    play_sound(-1, -1, SAMPLE_time);
-#endif
 }
 
-
 /* read input device for players */
 
-void readjoy(byte action)
+void readjoy(byte action, struct PLAYER *ply)
 {
-  unsigned int north = 0, east = 0, south = 0, west = 0;
-  unsigned int snap = 0, drop = 0;
+  int north = 0, east = 0, south = 0, west = 0;
+  int snap = 0, drop = 0;
 
   if (action & JOY_LEFT)
     west = 1;
@@ -148,27 +120,14 @@ void readjoy(byte action)
   if (action & JOY_BUTTON_2)
     drop = 1;
 
-#if 1
-  ply1.joy_snap = snap;
-  ply1.joy_drop = drop;
-  if (ply1.joy_stick || (north | east | south | west))
-  {
-    ply1.joy_n = north;
-    ply1.joy_e = east;
-    ply1.joy_s = south;
-    ply1.joy_w = west;
-  }
-
-#else
+  ply->joy_snap = snap;
+  ply->joy_drop = drop;
 
-  ply2.joy_snap = snap;
-  ply2.joy_drop = drop;
-  if (ply2.joy_stick || (north | east | south | west))
+  if (ply->joy_stick || (north | east | south | west))
   {
-    ply2.joy_n = north;
-    ply2.joy_e = east;
-    ply2.joy_s = south;
-    ply2.joy_w = west;
+    ply->joy_n = north;
+    ply->joy_e = east;
+    ply->joy_s = south;
+    ply->joy_w = west;
   }
-#endif
 }
diff --git a/src/game_em/level.h b/src/game_em/level.h
deleted file mode 100644 (file)
index 46ba9e4..0000000
+++ /dev/null
@@ -1,107 +0,0 @@
-#ifndef LEVEL_H
-#define LEVEL_H
-
-#include "main_em.h"
-#include "tile.h"
-
-#define WIDTH          EM_MAX_CAVE_WIDTH
-#define HEIGHT         EM_MAX_CAVE_HEIGHT
-
-#if 0
-
-struct LEVEL
-{
-  unsigned int home;     /* number of players that have to go home */
-                         /* 0 == all players home */
-
-  unsigned int width;    /* world width */
-  unsigned int height;   /* world height */
-  unsigned int time;     /* time remaining */
-  unsigned int required; /* emeralds needed */
-  unsigned int score;    /* score */
-
-  /* fill in all below /every/ time you read a level */
-  unsigned int alien_score;           /* alien popped by stone/spring score */
-  unsigned int amoeba_time;           /* amoeba speed */
-  unsigned int android_move_cnt;      /* android move time counter */
-  unsigned int android_move_time;     /* android move reset time */
-  unsigned int android_clone_cnt;     /* android clone time counter */
-  unsigned int android_clone_time;    /* android clone reset time */
-  unsigned int ball_cnt;              /* ball time counter */
-  unsigned int ball_pos;              /* ball array pos counter */
-  unsigned int ball_random;           /* ball is random flag */
-  unsigned int ball_state;            /* ball currently on flag */
-  unsigned int ball_time;             /* ball reset time */
-  unsigned int bug_score;             /* bug popped by stone/spring score */
-  unsigned int diamond_score;         /* diamond collect score */
-  unsigned int dynamite_score;        /* dynamite collect scoer*/
-  unsigned int eater_pos;             /* eater array pos */
-  unsigned int eater_score;           /* eater popped by stone/spring score */
-  unsigned int emerald_score;         /* emerald collect score */
-  unsigned int exit_score;            /* exit score */
-  unsigned int key_score;             /* key collect score */
-  unsigned int lenses_cnt;            /* lenses time counter */
-  unsigned int lenses_score;          /* lenses collect score */
-  unsigned int lenses_time;           /* lenses reset time */
-  unsigned int magnify_cnt;           /* magnify time counter */
-  unsigned int magnify_score;         /* magnify collect score */
-  unsigned int magnify_time;          /* magnify reset time */
-  unsigned int nut_score;             /* nut crack score */
-  unsigned int shine_cnt;             /* shine counter for emerald/diamond */
-  unsigned int slurp_score;           /* slurp alien score */
-  unsigned int tank_score;            /* tank popped by stone/spring */
-  unsigned int wheel_cnt;             /* wheel time counter */
-  unsigned int wheel_x;               /* wheel x pos */
-  unsigned int wheel_y;               /* wheel y pos */
-  unsigned int wheel_time;            /* wheel reset time */
-  unsigned int wind_cnt;              /* wind time counter */
-  unsigned int wind_direction;        /* wind direction */
-  unsigned int wind_time;             /* wind reset time */
-  unsigned int wonderwall_state;      /* wonderwall currently on flag */
-  unsigned int wonderwall_time;       /* wonderwall time */
-  unsigned short eater_array[8][9];   /* eater data */
-  unsigned short ball_array[8][8];    /* ball data */
-  unsigned short android_array[TILE_MAX]; /* android clone table */
-};
-
-struct PLAYER
-{
-  unsigned int num;
-  unsigned int alive;
-  unsigned int dynamite;
-  unsigned int dynamite_cnt;
-  unsigned int keys;
-  unsigned int anim;
-  unsigned int x;
-  unsigned int y;
-  unsigned int oldx;
-  unsigned int oldy;
-
-  unsigned joy_n:1;
-  unsigned joy_e:1;
-  unsigned joy_s:1;
-  unsigned joy_w:1;
-  unsigned joy_snap:1;
-  unsigned joy_drop:1;
-  unsigned joy_stick:1;
-  unsigned joy_spin:1;
-};
-
-#endif
-
-extern unsigned long RandomEM;
-
-extern struct PLAYER ply1;
-extern struct PLAYER ply2;
-extern struct LEVEL lev;
-
-extern struct LevelInfo_EM native_em_level;
-extern struct GraphicInfo_EM graphic_info_em_object[TILE_MAX][8];
-extern struct GraphicInfo_EM graphic_info_em_player[2][SPR_MAX][8];
-
-extern unsigned short **Boom;
-extern unsigned short **Cave;
-extern unsigned short **Next;
-extern unsigned short **Draw;
-
-#endif
index 17cb9f73df67ebc4380f9b546301b18936068e1e..d6a768786ee70591cfd486bf88f397f52fd22bbb 100644 (file)
 #ifndef MAIN_EM_H
 #define MAIN_EM_H
 
+/* ========================================================================= */
+/* external functions and definitions imported from main program to game_em  */
+/* ========================================================================= */
+
 #include "../engines.h"
 
 
-/* 2000-07-30T11:06:03Z ---------------------------------------------------- */
-
-#define EM_MAX_CAVE_WIDTH              102
-#define EM_MAX_CAVE_HEIGHT             102
-
-/* define these for backwards compatibility */
-#define EM_ENGINE_BAD_ROLL
-#define EM_ENGINE_BAD_SPRING
-
-
-/*
-  -----------------------------------------------------------------------------
-  definition of elements used in the Emerald Mine Club engine;
-  the element names have the following properties:
-  - elements that start with an 'X' can be stored in a level file;
-  - elements that start with an 'Y' indicate moving elements;
-  - elements that end with a 'B' are the "backside" of a moving element.
-  -----------------------------------------------------------------------------
-*/
-
-enum
-{
-  Xblank = 0,          /* still */
-  Yacid_splash_eB,     /* hmm */
-  Yacid_splash_wB,     /* hmm */
-
-#ifdef EM_ENGINE_BAD_ROLL
-  Xstone_force_e,      /* only use these in eater */
-  Xstone_force_w,
-  Xnut_force_e,
-  Xnut_force_w,
-  Xspring_force_e,
-  Xspring_force_w,
-  Xemerald_force_e,
-  Xemerald_force_w,
-  Xdiamond_force_e,
-  Xdiamond_force_w,
-  Xbomb_force_e,
-  Xbomb_force_w,
-#endif
-
-  Xstone,
-  Xstone_pause,
-  Xstone_fall,
-  Ystone_s,
-  Ystone_sB,
-  Ystone_e,
-  Ystone_eB,
-  Ystone_w,
-  Ystone_wB,
-  Xnut,
-  Xnut_pause,
-  Xnut_fall,
-  Ynut_s,
-  Ynut_sB,
-  Ynut_e,
-  Ynut_eB,
-  Ynut_w,
-  Ynut_wB,
-  Xbug_n,
-  Xbug_e,
-  Xbug_s,
-  Xbug_w,
-  Xbug_gon,
-  Xbug_goe,
-  Xbug_gos,
-  Xbug_gow,
-  Ybug_n,
-  Ybug_nB,
-  Ybug_e,
-  Ybug_eB,
-  Ybug_s,
-  Ybug_sB,
-  Ybug_w,
-  Ybug_wB,
-  Ybug_w_n,
-  Ybug_n_e,
-  Ybug_e_s,
-  Ybug_s_w,
-  Ybug_e_n,
-  Ybug_s_e,
-  Ybug_w_s,
-  Ybug_n_w,
-  Ybug_stone,
-  Ybug_spring,
-  Xtank_n,
-  Xtank_e,
-  Xtank_s,
-  Xtank_w,
-  Xtank_gon,
-  Xtank_goe,
-  Xtank_gos,
-  Xtank_gow,
-  Ytank_n,
-  Ytank_nB,
-  Ytank_e,
-  Ytank_eB,
-  Ytank_s,
-  Ytank_sB,
-  Ytank_w,
-  Ytank_wB,
-  Ytank_w_n,
-  Ytank_n_e,
-  Ytank_e_s,
-  Ytank_s_w,
-  Ytank_e_n,
-  Ytank_s_e,
-  Ytank_w_s,
-  Ytank_n_w,
-  Ytank_stone,
-  Ytank_spring,
-  Xandroid,
-  Xandroid_1_n,
-  Xandroid_2_n,
-  Xandroid_1_e,
-  Xandroid_2_e,
-  Xandroid_1_w,
-  Xandroid_2_w,
-  Xandroid_1_s,
-  Xandroid_2_s,
-  Yandroid_n,
-  Yandroid_nB,
-  Yandroid_ne,
-  Yandroid_neB,
-  Yandroid_e,
-  Yandroid_eB,
-  Yandroid_se,
-  Yandroid_seB,
-  Yandroid_s,
-  Yandroid_sB,
-  Yandroid_sw,
-  Yandroid_swB,
-  Yandroid_w,
-  Yandroid_wB,
-  Yandroid_nw,
-  Yandroid_nwB,
-  Xspring,
-  Xspring_pause,
-  Xspring_e,
-  Xspring_w,
-  Xspring_fall,
-  Yspring_s,
-  Yspring_sB,
-  Yspring_e,
-  Yspring_eB,
-  Yspring_w,
-  Yspring_wB,
-  Yspring_kill_e,
-  Yspring_kill_eB,
-  Yspring_kill_w,
-  Yspring_kill_wB,
-  Xeater_n,
-  Xeater_e,
-  Xeater_w,
-  Xeater_s,
-  Yeater_n,
-  Yeater_nB,
-  Yeater_e,
-  Yeater_eB,
-  Yeater_s,
-  Yeater_sB,
-  Yeater_w,
-  Yeater_wB,
-  Yeater_stone,
-  Yeater_spring,
-  Xalien,
-  Xalien_pause,
-  Yalien_n,
-  Yalien_nB,
-  Yalien_e,
-  Yalien_eB,
-  Yalien_s,
-  Yalien_sB,
-  Yalien_w,
-  Yalien_wB,
-  Yalien_stone,
-  Yalien_spring,
-  Xemerald,
-  Xemerald_pause,
-  Xemerald_fall,
-  Xemerald_shine,
-  Yemerald_s,
-  Yemerald_sB,
-  Yemerald_e,
-  Yemerald_eB,
-  Yemerald_w,
-  Yemerald_wB,
-  Yemerald_eat,
-  Yemerald_stone,
-  Xdiamond,
-  Xdiamond_pause,
-  Xdiamond_fall,
-  Xdiamond_shine,
-  Ydiamond_s,
-  Ydiamond_sB,
-  Ydiamond_e,
-  Ydiamond_eB,
-  Ydiamond_w,
-  Ydiamond_wB,
-  Ydiamond_eat,
-  Ydiamond_stone,
-  Xdrip_fall,
-  Xdrip_stretch,
-  Xdrip_stretchB,
-  Xdrip_eat,
-  Ydrip_s1,
-  Ydrip_s1B,
-  Ydrip_s2,
-  Ydrip_s2B,
-  Xbomb,
-  Xbomb_pause,
-  Xbomb_fall,
-  Ybomb_s,
-  Ybomb_sB,
-  Ybomb_e,
-  Ybomb_eB,
-  Ybomb_w,
-  Ybomb_wB,
-  Ybomb_eat,
-  Xballoon,
-  Yballoon_n,
-  Yballoon_nB,
-  Yballoon_e,
-  Yballoon_eB,
-  Yballoon_s,
-  Yballoon_sB,
-  Yballoon_w,
-  Yballoon_wB,
-  Xgrass,
-  Ygrass_nB,
-  Ygrass_eB,
-  Ygrass_sB,
-  Ygrass_wB,
-  Xdirt,
-  Ydirt_nB,
-  Ydirt_eB,
-  Ydirt_sB,
-  Ydirt_wB,
-  Xacid_ne,
-  Xacid_se,
-  Xacid_s,
-  Xacid_sw,
-  Xacid_nw,
-  Xacid_1,
-  Xacid_2,
-  Xacid_3,
-  Xacid_4,
-  Xacid_5,
-  Xacid_6,
-  Xacid_7,
-  Xacid_8,
-  Xball_1,
-  Xball_1B,
-  Xball_2,
-  Xball_2B,
-  Yball_eat,
-
-#if 1
-  Ykey_1_eat,
-  Ykey_2_eat,
-  Ykey_3_eat,
-  Ykey_4_eat,
-  Ykey_5_eat,
-  Ykey_6_eat,
-  Ykey_7_eat,
-  Ykey_8_eat,
-  Ylenses_eat,
-  Ymagnify_eat,
-  Ygrass_eat,
-  Ydirt_eat,
-#endif
-
-  Xgrow_ns,
-  Ygrow_ns_eat,
-  Xgrow_ew,
-  Ygrow_ew_eat,
-  Xwonderwall,
-  XwonderwallB,
-  Xamoeba_1,
-  Xamoeba_2,
-  Xamoeba_3,
-  Xamoeba_4,
-  Xamoeba_5,
-  Xamoeba_6,
-  Xamoeba_7,
-  Xamoeba_8,
-  Xdoor_1,
-  Xdoor_2,
-  Xdoor_3,
-  Xdoor_4,
-  Xdoor_5,
-  Xdoor_6,
-  Xdoor_7,
-  Xdoor_8,
-  Xkey_1,
-  Xkey_2,
-  Xkey_3,
-  Xkey_4,
-  Xkey_5,
-  Xkey_6,
-  Xkey_7,
-  Xkey_8,
-  Xwind_n,
-  Xwind_e,
-  Xwind_s,
-  Xwind_w,
-  Xwind_nesw,
-  Xwind_stop,
-  Xexit,
-  Xexit_1,
-  Xexit_2,
-  Xexit_3,
-  Xdynamite,
-  Ydynamite_eat,
-  Xdynamite_1,
-  Xdynamite_2,
-  Xdynamite_3,
-  Xdynamite_4,
-  Xbumper,
-  XbumperB,
-  Xwheel,
-  XwheelB,
-  Xswitch,
-  XswitchB,
-  Xsand,
-  Xsand_stone,
-  Xsand_stonein_1,
-  Xsand_stonein_2,
-  Xsand_stonein_3,
-  Xsand_stonein_4,
-  Xsand_stonesand_1,
-  Xsand_stonesand_2,
-  Xsand_stonesand_3,
-  Xsand_stonesand_4,
-  Xsand_stoneout_1,
-  Xsand_stoneout_2,
-  Xsand_sandstone_1,
-  Xsand_sandstone_2,
-  Xsand_sandstone_3,
-  Xsand_sandstone_4,
-  Xplant,
-  Yplant,
-  Xlenses,
-  Xmagnify,
-  Xdripper,
-  XdripperB,
-  Xfake_blank,
-  Xfake_blankB,
-  Xfake_grass,
-  Xfake_grassB,
-  Xfake_door_1,
-  Xfake_door_2,
-  Xfake_door_3,
-  Xfake_door_4,
-  Xfake_door_5,
-  Xfake_door_6,
-  Xfake_door_7,
-  Xfake_door_8,
-
-#if 1
-  Xfake_acid_1,
-  Xfake_acid_2,
-  Xfake_acid_3,
-  Xfake_acid_4,
-  Xfake_acid_5,
-  Xfake_acid_6,
-  Xfake_acid_7,
-  Xfake_acid_8,
-#endif
-
-  Xsteel_1,
-  Xsteel_2,
-  Xsteel_3,
-  Xsteel_4,
-  Xwall_1,
-  Xwall_2,
-  Xwall_3,
-  Xwall_4,
-  Xround_wall_1,
-  Xround_wall_2,
-  Xround_wall_3,
-  Xround_wall_4,
-  Xdecor_1,
-  Xdecor_2,
-  Xdecor_3,
-  Xdecor_4,
-  Xdecor_5,
-  Xdecor_6,
-  Xdecor_7,
-  Xdecor_8,
-  Xdecor_9,
-  Xdecor_10,
-  Xdecor_11,
-  Xdecor_12,
-  Xalpha_0,
-  Xalpha_1,
-  Xalpha_2,
-  Xalpha_3,
-  Xalpha_4,
-  Xalpha_5,
-  Xalpha_6,
-  Xalpha_7,
-  Xalpha_8,
-  Xalpha_9,
-  Xalpha_excla,
-  Xalpha_quote,
-  Xalpha_comma,
-  Xalpha_minus,
-  Xalpha_perio,
-  Xalpha_colon,
-  Xalpha_quest,
-  Xalpha_a,
-  Xalpha_b,
-  Xalpha_c,
-  Xalpha_d,
-  Xalpha_e,
-  Xalpha_f,
-  Xalpha_g,
-  Xalpha_h,
-  Xalpha_i,
-  Xalpha_j,
-  Xalpha_k,
-  Xalpha_l,
-  Xalpha_m,
-  Xalpha_n,
-  Xalpha_o,
-  Xalpha_p,
-  Xalpha_q,
-  Xalpha_r,
-  Xalpha_s,
-  Xalpha_t,
-  Xalpha_u,
-  Xalpha_v,
-  Xalpha_w,
-  Xalpha_x,
-  Xalpha_y,
-  Xalpha_z,
-  Xalpha_arrow_e,
-  Xalpha_arrow_w,
-  Xalpha_copyr,
-
-  Xboom_bug,           /* passed from explode to synchro (linked explosion);
-                          transition to explode_normal */
-  Xboom_bomb,          /* passed from explode to synchro (linked explosion);
-                          transition to explode_normal */
-  Xboom_android,       /* passed from explode to synchro;
-                          transition to boom_2 */
-  Xboom_1,             /* passed from explode to synchro;
-                          transition to boom_2 */
-  Xboom_2,             /* transition to boom[] */
-
-  Znormal,             /* passed from synchro to explode, only in next[];
-                          no picture */
-  Zdynamite,           /* passed from synchro to explode, only in next[];
-                          no picture */
-  Zplayer,             /* special code to indicate player;
-                          no picture */
-  ZBORDER,             /* special code to indicate border;
-                          no picture */
-
-  TILE_MAX
-};
-
-enum
-{
-  SPR_still = 0,
-  SPR_walk  = 1,
-  SPR_push  = 5,
-  SPR_spray = 9,
-
-  SPR_MAX   = 13
-};
-
-enum
-{
-  SAMPLE_blank = 0,    /* player walks on blank */
-  SAMPLE_roll,         /* player pushes stone/bomb/nut/spring */
-  SAMPLE_stone,                /* stone hits ground */
-  SAMPLE_nut,          /* nut hits ground */
-  SAMPLE_crack,                /* stone hits nut */
-  SAMPLE_bug,          /* bug moves */
-  SAMPLE_tank,         /* tank moves */
-  SAMPLE_android_clone,        /* android places something */
-  SAMPLE_android_move, /* android moves */
-  SAMPLE_spring,       /* spring hits ground/wall/bumper, stone hits spring */
-  SAMPLE_slurp,                /* spring kills alien */
-  SAMPLE_eater,                /* eater sits */
-  SAMPLE_eater_eat,    /* eater eats diamond */
-  SAMPLE_alien,                /* alien moves */
-  SAMPLE_collect,      /* player collects object */
-  SAMPLE_diamond,      /* diamond/emerald hits ground */
-  SAMPLE_squash,       /* stone squashes diamond */
-  SAMPLE_wonderfall,   /* object falls thru wonderwall */
-  SAMPLE_drip,         /* drip hits ground */
-  SAMPLE_push,         /* player pushes balloon/android */
-  SAMPLE_dirt,         /* player walks on dirt */
-  SAMPLE_acid,         /* acid splashes */
-  SAMPLE_ball,         /* ball places something */
-  SAMPLE_grow,         /* growing wall grows */
-  SAMPLE_wonder,       /* wonderwall is active */
-  SAMPLE_door,         /* player goes thru door (gate) */
-  SAMPLE_exit_open,    /* exit opens */
-  SAMPLE_exit_leave,   /* player goes into exit */
-  SAMPLE_dynamite,     /* player places dynamite */
-  SAMPLE_tick,         /* dynamite ticks */
-  SAMPLE_press,                /* player presses wheel/wind/switch */
-  SAMPLE_wheel,                /* wheel moves */
-  SAMPLE_boom,         /* explosion */
-  SAMPLE_time,         /* time runs out */
-  SAMPLE_die,          /* player dies */
-
-  SAMPLE_MAX
-};
-
-struct LEVEL
-{
-  unsigned int home_initial;           /* number of players (initial) */
-  unsigned int home;                   /* number of players not yet at home */
-                                       /* 0 == all players at home */
-
-  unsigned int width;                  /* playfield width */
-  unsigned int height;                 /* playfield height */
-
-  unsigned int time_seconds;           /* available time (seconds) */
-  unsigned int time_initial;           /* available time (initial) */
-  unsigned int time;                   /* time remaining (runtime) */
-
-  boolean killed_out_of_time;          /* kill player due to time out */
-
-  unsigned int required_initial;       /* emeralds needed (initial) */
-  unsigned int required;               /* emeralds needed (runtime) */
-
-  unsigned int score;                  /* score */
-
-  /* all below entries must be filled every time a level is read */
-
-  unsigned int alien_score;            /* score for killing alien */
-  unsigned int amoeba_time;            /* amoeba speed */
-  unsigned int android_move_cnt_initial;/* android move counter (initial) */
-  unsigned int android_move_cnt;       /* android move counter */
-  unsigned int android_move_time;      /* android move reset time */
-  unsigned int android_clone_cnt_initial;/* android clone counter (initial) */
-  unsigned int android_clone_cnt;      /* android clone counter */
-  unsigned int android_clone_time;     /* android clone reset time */
-  unsigned int ball_cnt;               /* ball counter */
-  unsigned int ball_pos;               /* ball array pos counter */
-  unsigned int ball_random;            /* ball is random flag */
-  unsigned int ball_state_initial;     /* ball active flag (initial) */
-  unsigned int ball_state;             /* ball active flag */
-  unsigned int ball_time;              /* ball reset time */
-  unsigned int bug_score;              /* score for killing bug */
-  unsigned int diamond_score;          /* score for collecting diamond */
-  unsigned int dynamite_score;         /* score for collecting dynamite */
-  unsigned int eater_pos;              /* eater array pos */
-  unsigned int eater_score;            /* score for killing eater */
-  unsigned int emerald_score;          /* score for collecting emerald */
-  unsigned int exit_score;             /* score for entering exit */
-  unsigned int key_score;              /* score for colleting key */
-  unsigned int lenses_cnt_initial;     /* lenses counter (initial) */
-  unsigned int lenses_cnt;             /* lenses counter */
-  unsigned int lenses_score;           /* score for collecting lenses */
-  unsigned int lenses_time;            /* lenses reset time */
-  unsigned int magnify_cnt_initial;    /* magnify counter (initial) */
-  unsigned int magnify_cnt;            /* magnify counter */
-  unsigned int magnify_score;          /* score for collecting magnifier */
-  unsigned int magnify_time;           /* magnify reset time */
-  unsigned int nut_score;              /* score for cracking nut */
-  unsigned int shine_cnt;              /* shine counter for emerald/diamond */
-  unsigned int slurp_score;            /* score for slurping alien */
-  unsigned int tank_score;             /* score for killing tank */
-  unsigned int wheel_cnt_initial;      /* wheel counter (initial) */
-  unsigned int wheel_cnt;              /* wheel counter */
-  unsigned int wheel_x_initial;                /* wheel x pos (initial) */
-  unsigned int wheel_x;                        /* wheel x pos */
-  unsigned int wheel_y_initial;                /* wheel y pos (initial) */
-  unsigned int wheel_y;                        /* wheel y pos */
-  unsigned int wheel_time;             /* wheel reset time */
-  unsigned int wind_cnt_initial;       /* wind counter (initial) */
-  unsigned int wind_cnt;               /* wind time counter */
-  unsigned int wind_direction_initial; /* wind direction (initial) */
-  unsigned int wind_direction;         /* wind direction */
-  unsigned int wind_time;              /* wind reset time */
-  unsigned int wonderwall_state_initial;/* wonderwall active flag (initial) */
-  unsigned int wonderwall_state;       /* wonderwall active flag */
-  unsigned int wonderwall_time_initial;        /* wonderwall time (initial) */
-  unsigned int wonderwall_time;                /* wonderwall time */
-  unsigned short eater_array[8][9];    /* eater data */
-  unsigned short ball_array[8][8];     /* ball data */
-  unsigned short android_array[TILE_MAX];/* android clone table */
-};
-
-struct PLAYER
-{
-  unsigned int num;
-  unsigned int alive_initial;
-  unsigned int alive;
-
-  unsigned int dynamite;
-  unsigned int dynamite_cnt;
-  unsigned int keys;
-  unsigned int anim;
-
-  unsigned int x_initial;
-  unsigned int y_initial;
-  unsigned int x;
-  unsigned int y;
-  unsigned int oldx;
-  unsigned int oldy;
-
-  unsigned int last_move_dir;
-
-  unsigned joy_n:1;
-  unsigned joy_e:1;
-  unsigned joy_s:1;
-  unsigned joy_w:1;
-  unsigned joy_snap:1;
-  unsigned joy_drop:1;
-  unsigned joy_stick:1;
-  unsigned joy_spin:1;
-};
+/* ========================================================================= */
+/* functions and definitions that are exported from game_em to main program  */
+/* ========================================================================= */
+
+#include "export.h"
+
+
+/* ========================================================================= */
+/* internal functions and definitions that are not exported to main program  */
+/* ========================================================================= */
+
+#include "global.h"
+#include "sample.h"
 
 
 /* ------------------------------------------------------------------------- */
-/* definitions and structures for use by the main game functions             */
+/* constant definitions                                                      */
 /* ------------------------------------------------------------------------- */
 
 /* values for native Emerald Mine game version */
@@ -638,37 +35,122 @@ struct PLAYER
 
 #define FILE_VERSION_EM_ACTUAL FILE_VERSION_EM_V6
 
-struct GlobalInfo_EM
-{
-  Bitmap *screenbuffer;
-};
+/* level sizes and positions for EM engine */
+
+#define WIDTH                  EM_MAX_CAVE_WIDTH
+#define HEIGHT                 EM_MAX_CAVE_HEIGHT
+
+/* screen sizes and positions for EM engine */
+
+#define ORIG_TILEX             16
+#define ORIG_TILEY             16
+#define ORIG_SCOREX            8
+#define ORIG_SCOREY            9
+#define ORIG_GFXMENUFONTX      14
+#define ORIG_GFXMENUFONTY      16
+#define ORIG_MENUFONTX         12
+#define ORIG_MENUFONTY         16
+
+#define ZOOM_FACTOR            2
+
+#define TILEX                  (ORIG_TILEX             * ZOOM_FACTOR)
+#define TILEY                  (ORIG_TILEY             * ZOOM_FACTOR)
+#define SCOREX                 (ORIG_SCOREX            * ZOOM_FACTOR)
+#define SCOREY                 (ORIG_SCOREY            * ZOOM_FACTOR)
+#define GFXMENUFONTX           (ORIG_GFXMENUFONTX      * ZOOM_FACTOR)
+#define GFXMENUFONTY           (ORIG_GFXMENUFONTY      * ZOOM_FACTOR)
+#define MENUFONTX              (ORIG_MENUFONTX         * ZOOM_FACTOR)
+#define MENUFONTY              (ORIG_MENUFONTY         * ZOOM_FACTOR)
+
+#define ORIG_SCR_MENUX         20
+#define ORIG_SCR_MENUY         12
+#define SCR_MENUX              17
+#define SCR_MENUY              12
+#define SCR_FIELDX             17
+#define SCR_FIELDY             17
+#define MAX_BUF_XSIZE          (SCR_FIELDX + 2)
+#define MAX_BUF_YSIZE          (SCR_FIELDY + 2)
+
+/* often used screen positions */
+#define ORIG_MENU_SX           ((ORIG_SCR_MENUX - SCR_MENUX) * TILEX / 2)
+#define ORIG_MENU_SY           0
+#define SY                     8
+#define SX                     8
+#define SY                     8
+#define SXSIZE                 (SCR_FIELDX * TILEX)
+#define SYSIZE                 (SCR_FIELDY * TILEY)
+
 
-struct LevelInfo_EM
-{
-  int file_version;
+/* ------------------------------------------------------------------------- */
+/* macro function definitions                                                */
+/* ------------------------------------------------------------------------- */
 
-  unsigned short cave[EM_MAX_CAVE_WIDTH][EM_MAX_CAVE_HEIGHT];
+#define ROUNDED_DIVIDE(x, y)   (((x) + (y) - 1) / (y))
 
-  struct LEVEL *lev;
-  struct PLAYER *ply1, *ply2;
-};
+#define SECONDS_TO_FRAMES(x)   ((x) * FRAMES_PER_SECOND)
+#define FRAMES_TO_SECONDS(x)   ((x) / FRAMES_PER_SECOND)
 
-struct GraphicInfo_EM
-{
-  Bitmap *bitmap;
-  int src_x, src_y;
-  int src_offset_x, src_offset_y;
-  int dst_offset_x, dst_offset_y;
-  int width, height;
+#define SECONDS_TO_CYCLES(x)   ROUNDED_DIVIDE((x) * FRAMES_PER_SECOND, 8)
+#define CYCLES_TO_SECONDS(x)   ROUNDED_DIVIDE((x) * 8, FRAMES_PER_SECOND)
 
-  Bitmap *crumbled_bitmap;
-  int crumbled_src_x, crumbled_src_y;
-  int crumbled_border_size;
+#define DISPLAY_TIME(x)                ROUNDED_DIVIDE(x, FRAMES_PER_SECOND)
+
+
+/* ------------------------------------------------------------------------- */
+/* data structure definitions                                                */
+/* ------------------------------------------------------------------------- */
+
+/* ------------------------------------------------------------------------- */
+/* exported variables                                                        */
+/* ------------------------------------------------------------------------- */
 
-  boolean has_crumbled_graphics;
-  boolean preserve_background;
+extern unsigned long RandomEM;
 
-  int unique_identifier;       /* used to identify needed screen updates */
-};
+extern struct LEVEL lev;
+extern struct PLAYER ply[MAX_PLAYERS];
+
+extern struct LevelInfo_EM native_em_level;
+extern struct GraphicInfo_EM graphic_info_em_object[TILE_MAX][8];
+extern struct GraphicInfo_EM graphic_info_em_player[MAX_PLAYERS][SPR_MAX][8];
+
+extern short **Boom;
+extern short **Cave;
+extern short **Next;
+extern short **Draw;
+
+extern struct GameInfo_EM game_em;
+
+extern unsigned char tab_blank[TILE_MAX];
+extern unsigned char tab_acid[TILE_MAX];
+extern unsigned char tab_amoeba[TILE_MAX];
+extern unsigned char tab_android_move[TILE_MAX];
+extern unsigned short tab_explode_normal[TILE_MAX];
+extern unsigned short tab_explode_dynamite[TILE_MAX];
+
+extern unsigned short map_obj[8][TILE_MAX];
+extern unsigned short map_spr[2][8][SPR_MAX];
+extern unsigned short map_ttl[128];
+
+extern Bitmap *screenBitmap;
+extern Bitmap *scoreBitmap;
+
+extern Bitmap *objBitmap;
+extern Bitmap *sprBitmap;
+extern Bitmap *ttlBitmap;
+extern Bitmap *botBitmap;
+
+extern Pixmap screenPixmap;
+extern Pixmap scorePixmap;
+extern Pixmap spriteBitmap;
+
+extern Pixmap objmaskBitmap;
+extern Pixmap sprmaskBitmap;
+
+extern GC spriteGC;
+
+
+/* ------------------------------------------------------------------------- */
+/* exported functions                                                        */
+/* ------------------------------------------------------------------------- */
 
 #endif /* MAIN_EM_H */
index 90c45a9ba54e5bb95b0d7b858d9b3e12c96c6334..853b27d378ef6887576aa6f0ec2f9c2653cccfe5 100644 (file)
@@ -4,51 +4,6 @@
 #include "main_em.h"
 
 
-#if 0
-
-enum
-{
-  SAMPLE_blank = 0,    /* player walks on blank */
-  SAMPLE_roll,         /* player pushes stone/bomb/nut/spring */
-  SAMPLE_stone,                /* stone hits ground */
-  SAMPLE_nut,          /* nut hits ground */
-  SAMPLE_crack,                /* stone hits nut */
-  SAMPLE_bug,          /* bug moves */
-  SAMPLE_tank,         /* tank moves */
-  SAMPLE_android_clone,        /* android places something */
-  SAMPLE_android_move, /* android moves */
-  SAMPLE_spring,       /* spring hits ground/wall/bumper, stone hits spring */
-  SAMPLE_slurp,                /* spring kills alien */
-  SAMPLE_eater,                /* eater sits */
-  SAMPLE_eater_eat,    /* eater eats diamond */
-  SAMPLE_alien,                /* alien moves */
-  SAMPLE_collect,      /* player collects object */
-  SAMPLE_diamond,      /* diamond/emerald hits ground */
-  SAMPLE_squash,       /* stone squashes diamond */
-  SAMPLE_wonderfall,   /* object falls thru wonderwall */
-  SAMPLE_drip,         /* drip hits ground */
-  SAMPLE_push,         /* player pushes balloon/android */
-  SAMPLE_dirt,         /* player walks on dirt */
-  SAMPLE_acid,         /* acid splashes */
-  SAMPLE_ball,         /* ball places something */
-  SAMPLE_grow,         /* growing wall grows */
-  SAMPLE_wonder,       /* wonderwall moves (is active) */
-  SAMPLE_door,         /* player goes thru door */
-  SAMPLE_exit_open,    /* exit opens */
-  SAMPLE_exit_leave,   /* player goes into exit */
-  SAMPLE_dynamite,     /* player places dynamite */
-  SAMPLE_tick,         /* dynamite ticks */
-  SAMPLE_press,                /* player presses wheel/wind/switch */
-  SAMPLE_wheel,                /* wheel moves */
-  SAMPLE_boom,         /* explosion */
-  SAMPLE_time,         /* time runs out */
-  SAMPLE_die,          /* player dies */
-
-  SAMPLE_MAX
-};
-
-#endif
-
 extern void play_sound(int, int, int);
 extern void play_element_sound(int, int, int, int);
 
index 9bdd2be8745c027f07aebe83b3694bd2b0bf7db9..5aedabb35abb1cbf42faaa23b67b32e6502e6883 100644 (file)
@@ -20,9 +20,6 @@
 #include <soundcard.h>
 #endif
 
-#include "global.h"
-#include "sample.h"
-
 static char audioname[] = "/dev/audio";
 
 static const int sound_priority[SAMPLE_MAX] =
index 124751d0ad312087bbf805251937df00481ef4eb..5f0929875b67b59ca711d4c89839cfd2da4eec6d 100644 (file)
@@ -5,12 +5,17 @@
  * large switch statement for tiles the player interacts with.
  */
 
-#include "tile.h"
-#include "level.h"
-#include "sample.h"
-#include "display.h"
+#include "main_em.h"
 
 
+#if 0
+extern int centered_player_nr;
+#endif
+
+#define USE_CHANGED_ACID_STUFF         1
+
+extern boolean checkIfAllPlayersFitToScreen();
+
 static void check_player(struct PLAYER *);
 static void kill_player(struct PLAYER *);
 static boolean player_digfield(struct PLAYER *, int, int);
@@ -18,7 +23,26 @@ static boolean player_killed(struct PLAYER *);
 
 void synchro_1(void)
 {
- /* must test for death and actually kill separately */
+#if 1
+
+  int start_check_nr;
+  int i;
+
+  game_em.any_player_moving = FALSE;
+
+  /* must test for death and actually kill separately */
+
+  for (i = 0; i < MAX_PLAYERS; i++)
+  {
+    boolean ply_kill = player_killed(&ply[i]);
+
+    if (ply[i].alive && ply_kill)
+      kill_player(&ply[i]);
+  }
+
+#else
+
+  /* must test for death and actually kill separately */
   boolean ply1_kill = player_killed(&ply1);
   boolean ply2_kill = player_killed(&ply2);
 
@@ -27,10 +51,51 @@ void synchro_1(void)
   if (ply2.alive && ply2_kill)
     kill_player(&ply2);
 
+#endif
+
 #if 0
   ply1.alive = 1; /* debugging */
 #endif
 
+#if 1
+
+  for (i = 0; i < MAX_PLAYERS; i++)
+  {
+    ply[i].oldx = ply[i].x;
+    ply[i].oldy = ply[i].y;
+    ply[i].anim = SPR_still;
+  }
+
+  start_check_nr = (RandomEM & 128 ? 0 : 1) * 2 + (RandomEM & 256 ? 0 : 1);
+
+  for (i = 0; i < MAX_PLAYERS; i++)
+  {
+    int check_nr = (start_check_nr + i) % MAX_PLAYERS;
+
+    if (ply[check_nr].alive)
+      check_player(&ply[check_nr]);
+  }
+
+  for (i = 0; i < MAX_PLAYERS; i++)
+  {
+    if (!ply[i].alive)
+      continue;
+
+    if (Cave[ply[i].oldy][ply[i].oldx] == Zplayer)
+    {
+      Cave[ply[i].oldy][ply[i].oldx] = Xblank;
+      Next[ply[i].oldy][ply[i].oldx] = Xblank;
+    }
+
+    if (Cave[ply[i].y][ply[i].x] == Xblank)
+    {
+      Cave[ply[i].y][ply[i].x] = Zplayer;
+      Next[ply[i].y][ply[i].x] = Zplayer;
+    }
+  }
+
+#else
+
   ply1.oldx = ply1.x;
   ply1.oldy = ply1.y;
   ply1.anim = SPR_still;
@@ -78,12 +143,18 @@ void synchro_1(void)
       Next[ply2.y][ply2.x] = Zplayer;
     }
   }
+
+#endif
 }
 
 static boolean player_killed(struct PLAYER *ply)
 {
-  register unsigned int x = ply->x;
-  register unsigned int y = ply->y;
+  int x = ply->x;
+  int y = ply->y;
+
+#if 0
+  printf("::: %d: %d, %d\n", ply->num, x, y);
+#endif
 
   if (!ply->alive)
     return FALSE;
@@ -208,8 +279,8 @@ static boolean player_killed(struct PLAYER *ply)
 
 static void kill_player(struct PLAYER *ply)
 {
-  register unsigned int x = ply->x;
-  register unsigned int y = ply->y;
+  int x = ply->x;
+  int y = ply->y;
 
   ply->alive = 0;
 
@@ -352,7 +423,7 @@ static void kill_player(struct PLAYER *ply)
 
   switch(Cave[y][x])
   {
-#if 1
+#if USE_CHANGED_ACID_STUFF
     case Xacid_1:
     case Xacid_2:
     case Xacid_3:
@@ -373,13 +444,15 @@ static void kill_player(struct PLAYER *ply)
 
 static void check_player(struct PLAYER *ply)
 {
-  unsigned int oldx = ply->x;
-  unsigned int oldy = ply->y;
-  register unsigned int x = oldx;
-  register unsigned int y = oldy;
-  unsigned int anim = 0;
+  int oldx = ply->x;
+  int oldy = ply->y;
+  int x = oldx;
+  int y = oldy;
+  int anim = 0;
   int dx = 0, dy = 0;
 
+  game_em.last_player_direction[ply->num] = MV_NONE;
+
 #if 0
   printf("::: up == %d, down == %d, left == %d, right == %d, fire == %d [spin == %d, stick == %d]\n",
         ply->joy_n, ply->joy_s, ply->joy_w, ply->joy_e, ply->joy_fire,
@@ -471,6 +544,44 @@ static void check_player(struct PLAYER *ply)
   }
 #endif
 
+  if (dx || dy)
+  {
+    int oldx = ply->x;
+    int oldy = ply->y;
+    int x = oldx + dx;
+    int y = oldy + dy;
+    boolean players_visible_before_move;
+    boolean players_visible_after_move;
+    boolean can_move;
+
+    players_visible_before_move = checkIfAllPlayersFitToScreen();
+
+    ply->x = x;
+    ply->y = y;
+
+    players_visible_after_move = checkIfAllPlayersFitToScreen();
+
+    /*
+      player is allowed to move only in the following cases:
+      - it is not needed to display all players (not focussed to all players)
+      - all players are (still or again) visible after the move
+      - some players were already outside visible screen area before the move
+    */
+    can_move = (game.centered_player_nr != -1 ||
+               players_visible_after_move ||
+               !players_visible_before_move);
+
+    ply->x = oldx;
+    ply->y = oldy;
+
+    if (!can_move)
+    {
+      ply->joy_n = ply->joy_e = ply->joy_s = ply->joy_w = 0;
+
+      return;
+    }
+  }
+
   if (dx == 0 && dy == 0)
   {
     ply->joy_stick = 0;
@@ -496,7 +607,7 @@ static void check_player(struct PLAYER *ply)
 
   ply->joy_stick = 1;
   ply->joy_n = ply->joy_e = ply->joy_s = ply->joy_w = 0;
-  ply->dynamite_cnt = 0; /* reset dynamite timer if we move */
+  ply->dynamite_cnt = 0;       /* reset dynamite timer if we move */
   ply->joy_spin = !ply->joy_spin;
 
   if (ply->joy_snap == 0)              /* player wants to move */
@@ -520,6 +631,10 @@ static void check_player(struct PLAYER *ply)
        ply->last_move_dir = (dx < 0 ? MV_LEFT : MV_RIGHT);
       else if (oldy != ply->y)
        ply->last_move_dir = (dy < 0 ? MV_UP : MV_DOWN);
+
+      game_em.any_player_moving = TRUE;
+      game_em.last_moving_player = ply->num;
+      game_em.last_player_direction[ply->num] = ply->last_move_dir;
     }
   }
   else                                 /* player wants to snap */
@@ -531,10 +646,10 @@ static void check_player(struct PLAYER *ply)
 static boolean player_digfield(struct PLAYER *ply, int dx, int dy)
 {
   int anim = (dx < 0 ? 3 : dx > 0 ? 1 : dy < 0 ? 0 : dy > 0 ? 2 : 2);
-  unsigned int oldx = ply->x;
-  unsigned int oldy = ply->y;
-  register unsigned int x = oldx + dx;
-  register unsigned int y = oldy + dy;
+  int oldx = ply->x;
+  int oldy = ply->y;
+  int x = oldx + dx;
+  int y = oldy + dy;
   boolean result = TRUE;
 
   if (!dx && !dy)                      /* no direction specified */
@@ -571,7 +686,7 @@ static boolean player_digfield(struct PLAYER *ply, int dx, int dy)
        ply->y = y;
        break;
 
-#if 1
+#if USE_CHANGED_ACID_STUFF
       case Xacid_1:
       case Xacid_2:
       case Xacid_3:
@@ -580,12 +695,12 @@ static boolean player_digfield(struct PLAYER *ply, int dx, int dy)
       case Xacid_6:
       case Xacid_7:
       case Xacid_8:
-#endif
        if (Cave[y-1][x+1] == Xblank)
          Cave[y-1][x+1] = Yacid_splash_eB;
        if (Cave[y-1][x-1] == Xblank)
          Cave[y-1][x-1] = Yacid_splash_wB;
        play_element_sound(x, y, SAMPLE_acid, Xacid_1);
+#endif
 
       case Xboom_android:
       case Xboom_1:
@@ -605,7 +720,8 @@ static boolean player_digfield(struct PLAYER *ply, int dx, int dy)
       case Xtank_goe:
       case Xtank_gos:
       case Xtank_gow:
-#if 0
+
+#if !USE_CHANGED_ACID_STUFF
       case Xacid_1:
       case Xacid_2:
       case Xacid_3:
index 3dff9e62edd2445be9f9df73bdbe96d0e2d2a662..1ab59546bc14d613ef83c50f0916f547bb32707a 100644 (file)
@@ -8,25 +8,48 @@
  * compilers suck.
  */
 
-#include "display.h"
-#include "tile.h"
-#include "level.h"
-#include "sample.h"
+#include "main_em.h"
 
 
 #define RANDOM (random = random << 31 | random >> 1)
 
+static void set_nearest_player_xy(int x, int y, int *dx, int *dy)
+{
+  int distance, distance_shortest = EM_MAX_CAVE_WIDTH + EM_MAX_CAVE_HEIGHT;
+  int i;
+
+  /* default values if no players are alive anymore */
+  *dx = 0;
+  *dy = 0;
+
+  for (i = 0; i < MAX_PLAYERS; i++)
+  {
+    if (!ply[i].alive)
+      continue;
+
+    distance = ABS(ply[i].x - x) + ABS(ply[i].y - y);
+
+    if (distance < distance_shortest)
+    {
+      *dx = ply[i].x;
+      *dy = ply[i].y;
+
+      distance_shortest = distance;
+    }
+  }
+}
+
 void synchro_2(void)
 {
-  register unsigned int x = 0;
-  register unsigned int y = 1;
-  register unsigned long random = RandomEM;
-  register unsigned short *cave_cache = Cave[y]; /* might be a win */
-  unsigned long score = 0;
-
-  unsigned int temp = 0;       /* initialized to make compilers happy */
-  unsigned int dx; /* only needed to find closest player */
-  unsigned int dy;
+  int x = 0;
+  int y = 1;
+  unsigned long random = RandomEM;
+  short *cave_cache = Cave[y]; /* might be a win */
+  int score = 0;
+
+  int temp = 0;                        /* initialized to make compilers happy */
+  int dx;                      /* only needed to find closest player */
+  int dy;
   int element;
 
  loop:
@@ -1879,6 +1902,12 @@ void synchro_2(void)
            Cave[y+1][x+1] == Zplayer)
          goto android_still;
 
+#if 1
+
+       set_nearest_player_xy(x, y, &dx, &dy);
+
+#else
+
        if (ply1.alive && ply2.alive)
        {
          if ((ply1.x > x ? ply1.x - x : x - ply1.x) +
@@ -1911,6 +1940,8 @@ void synchro_2(void)
          dy = 0;
        }
 
+#endif
+
        Next[y][x] = Xblank;    /* assume we will move */
        temp = ((x < dx) + 1 - (x > dx)) + ((y < dy) + 1 - (y > dy)) * 3;
 
@@ -3205,6 +3236,21 @@ void synchro_2(void)
     /* --------------------------------------------------------------------- */
 
     case Xalien:
+
+#if 1
+
+      if (lev.wheel_cnt)
+      {
+       dx = lev.wheel_x;
+       dy = lev.wheel_y;
+      }
+      else
+      {
+       set_nearest_player_xy(x, y, &dx, &dy);
+      }
+
+#else
+
       if (lev.wheel_cnt)
       {
        dx = lev.wheel_x;
@@ -3242,6 +3288,8 @@ void synchro_2(void)
        dy = 0;
       }
 
+#endif
+
       if (RANDOM & 1)
       {
        if (y > dy)
@@ -4517,7 +4565,11 @@ void synchro_2(void)
        }
       }
 
+#if 1
+      lev.ball_pos = (lev.ball_pos + 1) % lev.num_ball_arrays;
+#else
       lev.ball_pos = (lev.ball_pos + 1) & 7;
+#endif
       goto loop;
 
     /* --------------------------------------------------------------------- */
@@ -4884,8 +4936,8 @@ void synchro_2(void)
 
  done:
 
-  if (ply1.alive || ply2.alive)
-    lev.score += score; /* only get a score if someone is alive */
+  if (ply[0].alive || ply[1].alive || ply[2].alive || ply[3].alive)
+    lev.score += score;                /* only add a score if someone is alive */
 
   RandomEM = random;
 
index 449ecab094649ad72c2104835294bd8cb11f4b32..bafc581f8f458d5174084b7bd7f0423f1b43a31c 100644 (file)
@@ -5,17 +5,15 @@
  * this should be spread over the frames for reduced cpu load.
  */
 
-#include "tile.h"
-#include "level.h"
-#include "sample.h"
+#include "main_em.h"
 
 
 void synchro_3(void)
 {
-  register unsigned int x;
-  register unsigned int y;
-  register unsigned int count;
-  register unsigned long random;
+  int x;
+  int y;
+  int count;
+  unsigned long random;
 
   /* update variables */
 
index 75c47b3795afc0345af4817394b0130b9e051ab8..8a3f731ad55ccf0549658b5d326fde7ba2796784 100644 (file)
  * modify.
  */
 
-#include "tile.h"
-#include "display.h"
+#include "main_em.h"
 
 
-/* ---------------------------------------------------------------------- */
+/* ------------------------------------------------------------------------- */
 
 /* 0=stop 1=blank */
 int tile_blank[] =
@@ -69,7 +68,8 @@ int tile_android_move[] =
   TILE_MAX
 };
 
-/* ---------------------------------------------------------------------- */
+
+/* ------------------------------------------------------------------------- */
 
 /* explosions: special format */
 /* everything is initially filled with Xboom_1 */
@@ -152,7 +152,8 @@ int tile_explode[] =
   TILE_MAX                     /* up until here are dynamite explosions */
 };
 
-/* ---------------------------------------------------------------------- */
+
+/* ------------------------------------------------------------------------- */
 
 /* map the graphics file to internal tiles and animations
  *
@@ -4435,7 +4436,7 @@ unsigned short map_ttl[128];
 struct GraphicInfo_EM graphic_info_em_object[TILE_MAX][8];
 
 /* map player number, frames and action to graphic info */
-struct GraphicInfo_EM graphic_info_em_player[2][SPR_MAX][8];
+struct GraphicInfo_EM graphic_info_em_player[MAX_PLAYERS][SPR_MAX][8];
 
 void create_tab(int *invert, unsigned char *array)
 {
@@ -4641,14 +4642,14 @@ void create_spr_graphics_info_em()
 {
   int i, j, k;
 
-  for (i = 0; i < 2; i++)
+  for (i = 0; i < MAX_PLAYERS; i++)
   {
     for (j = 0; j < SPR_MAX; j++)
     {
       for (k = 0; k < 8; k++)
       {
        struct GraphicInfo_EM *g = &graphic_info_em_player[i][j][k];
-       int spr = map_spr[i][k][j];
+       int spr = map_spr[i % 2][k][j];
 
        g->bitmap = sprBitmap;
        g->src_x = (spr / 8) * TILEX;
index 1f58073285447eaab1dac4f132d8be8288442f8c..c975ec616a5d194cf485ef238d3027fd15c7f362 100644 (file)
@@ -66,6 +66,11 @@ static int copy_properties[][5] =
     EL_PACMAN_LEFT,            EL_PACMAN_RIGHT,
     EL_PACMAN_UP,              EL_PACMAN_DOWN
   },
+  {
+    EL_YAMYAM,
+    EL_YAMYAM_LEFT,            EL_YAMYAM_RIGHT,
+    EL_YAMYAM_UP,              EL_YAMYAM_DOWN
+  },
   {
     EL_MOLE,
     EL_MOLE_LEFT,              EL_MOLE_RIGHT,
@@ -77,180 +82,6 @@ static int copy_properties[][5] =
   }
 };
 
-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
-  {
-    int start;
-    int count;
-  }
-  tile_needs_clipping[] =
-  {
-    { GFX_SPIELER1_UP, 4 },
-    { GFX_SPIELER1_DOWN, 4 },
-    { GFX_SPIELER1_LEFT, 4 },
-    { GFX_SPIELER1_RIGHT, 4 },
-    { GFX_SPIELER1_PUSH_LEFT, 4 },
-    { GFX_SPIELER1_PUSH_RIGHT, 4 },
-    { GFX_SPIELER2_UP, 4 },
-    { GFX_SPIELER2_DOWN, 4 },
-    { GFX_SPIELER2_LEFT, 4 },
-    { GFX_SPIELER2_RIGHT, 4 },
-    { GFX_SPIELER2_PUSH_LEFT, 4 },
-    { GFX_SPIELER2_PUSH_RIGHT, 4 },
-    { GFX_SPIELER3_UP, 4 },
-    { GFX_SPIELER3_DOWN, 4 },
-    { GFX_SPIELER3_LEFT, 4 },
-    { GFX_SPIELER3_RIGHT, 4 },
-    { GFX_SPIELER3_PUSH_LEFT, 4 },
-    { GFX_SPIELER3_PUSH_RIGHT, 4 },
-    { GFX_SPIELER4_UP, 4 },
-    { GFX_SPIELER4_DOWN, 4 },
-    { GFX_SPIELER4_LEFT, 4 },
-    { GFX_SPIELER4_RIGHT, 4 },
-    { GFX_SPIELER4_PUSH_LEFT, 4 },
-    { GFX_SPIELER4_PUSH_RIGHT, 4 },
-    { GFX_SP_MURPHY, 1 },
-    { GFX_MURPHY_GO_LEFT, 3 },
-    { GFX_MURPHY_GO_RIGHT, 3 },
-    { GFX_MURPHY_SNAP_UP, 1 },
-    { GFX_MURPHY_SNAP_DOWN, 1 },
-    { GFX_MURPHY_SNAP_RIGHT, 1 },
-    { GFX_MURPHY_SNAP_LEFT, 1 },
-    { GFX_MURPHY_PUSH_RIGHT, 1 },
-    { GFX_MURPHY_PUSH_LEFT, 1 },
-    { GFX_GEBLUBBER, 4 },
-    { GFX_DYNAMIT, 7 },
-    { GFX_DYNABOMB, 4 },
-    { GFX_EXPLOSION, 8 },
-    { GFX_SOKOBAN_OBJEKT, 1 },
-    { GFX_FUNKELN_BLAU, 3 },
-    { GFX_FUNKELN_WEISS, 3 },
-    { GFX2_SHIELD_PASSIVE, 3 },
-    { 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++)
-    tile_clipmask[i] = None;
-
-#if defined(TARGET_X11)
-  /* 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;
-  tile_clip_gc = XCreateGC(display, window->drawable,
-                          clip_gc_valuemask, &clip_gc_values);
-
-#if 0
-  for (i = 0; i < NUM_BITMAPS; i++)
-  {
-    if (pix[i]->clip_mask)
-    {
-      clip_gc_values.graphics_exposures = False;
-      clip_gc_values.clip_mask = pix[i]->clip_mask;
-      clip_gc_valuemask = GCGraphicsExposures | GCClipMask;
-      pix[i]->stored_clip_gc = XCreateGC(display, window->drawable,
-                                        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);
-
-  /* create only those clipping Pixmaps we really need */
-  for (i = 0; tile_needs_clipping[i].start >= 0; i++)
-  {
-    int 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;
-      Bitmap *src_bitmap;
-      Pixmap src_pixmap;
-
-      getGraphicSource(graphic, &src_bitmap, &src_x, &src_y);
-      src_pixmap = src_bitmap->clip_mask;
-
-      tile_clipmask[tile] = XCreatePixmap(display, window->drawable,
-                                         TILEX, TILEY, 1);
-
-      XCopyArea(display, src_pixmap, tile_clipmask[tile], copy_clipmask_gc,
-               src_x, src_y, TILEX, TILEY, 0, 0);
-    }
-  }
-
-  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++)
-  {
-    if (tile_clipmask[i] != None)
-    {
-      XFreePixmap(display, tile_clipmask[i]);
-      tile_clipmask[i] = None;
-    }
-  }
-
-  if (tile_clip_gc)
-    XFreeGC(display, tile_clip_gc);
-  tile_clip_gc = None;
-
-#if 0
-  for (i = 0; i < NUM_BITMAPS; i++)
-  {
-    if (pix[i] != NULL && pix[i]->stored_clip_gc)
-    {
-      XFreeGC(display, pix[i]->stored_clip_gc);
-      pix[i]->stored_clip_gc = None;
-    }
-  }
-#endif
-
-#endif /* TARGET_X11 */
-#endif
-}
-
 void FreeGadgets()
 {
   FreeLevelEditorGadgets();
@@ -283,6 +114,14 @@ inline void InitElementSmallImagesScaledUp(int graphic)
 
 void InitElementSmallImages()
 {
+  static int special_graphics[] =
+  {
+    IMG_EDITOR_ELEMENT_BORDER,
+    IMG_EDITOR_ELEMENT_BORDER_INPUT,
+    IMG_EDITOR_CASCADE_LIST,
+    IMG_EDITOR_CASCADE_LIST_ACTIVE,
+    -1
+  };
   struct PropertyMapping *property_mapping = getImageListPropertyMapping();
   int num_property_mappings = getImageListPropertyMappingSize();
   int i;
@@ -296,22 +135,21 @@ void InitElementSmallImages()
     InitElementSmallImagesScaledUp(element_to_special_graphic[i].graphic);
 
   /* initialize images from dynamic configuration (may be elements or other) */
-#if 1
   for (i = 0; i < num_property_mappings; i++)
     InitElementSmallImagesScaledUp(property_mapping[i].artwork_index);
-#else
-  /* !!! THIS DOES NOT WORK -- "artwork_index" is graphic, not element !!! */
-  /* !!! ALSO, non-element graphics might need scaling-up !!! */
-  for (i = 0; i < num_property_mappings; i++)
-    if (property_mapping[i].artwork_index < MAX_NUM_ELEMENTS)
-      InitElementSmallImagesScaledUp(property_mapping[i].artwork_index);
-#endif
 
-#if 0
-  /* !!! FIX THIS (CHANGE TO USING NORMAL ELEMENT GRAPHIC DEFINITIONS) !!! */
-  for (i = IMG_EMC_OBJECT; i <= IMG_EMC_SPRITE; i++)
-    InitElementSmallImagesScaledUp(i);
-#endif
+  /* initialize special images from above list (non-element images) */
+  for (i = 0; special_graphics[i] > -1; i++)
+    InitElementSmallImagesScaledUp(special_graphics[i]);
+}
+
+void InitScaledImages()
+{
+  int i;
+
+  /* scale normal images from static configuration, if not already scaled */
+  for (i = 0; i < NUM_IMAGE_FILES; i++)
+    ScaleImage(i, graphic_info[i].scale_up_factor);
 }
 
 #if 1
@@ -358,13 +196,8 @@ void InitFontGraphicInfo()
   /* ---------- initialize font graphic definitions ---------- */
 
   /* always start with reliable default values (normal font graphics) */
-#if 1
   for (i = 0; i < NUM_FONTS; i++)
     font_info[i].graphic = IMG_FONT_INITIAL_1;
-#else
-  for (i = 0; i < NUM_FONTS; i++)
-    font_info[i].graphic = FONT_INITIAL_1;
-#endif
 
   /* initialize normal font/graphic mapping from static configuration */
   for (i = 0; font_to_graphic[i].font_nr > -1; i++)
@@ -392,12 +225,25 @@ void InitFontGraphicInfo()
   /* initialize special 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;
+    int font_nr      = font_to_graphic[i].font_nr;
+    int special      = font_to_graphic[i].special;
+    int graphic      = font_to_graphic[i].graphic;
+    int base_graphic = font2baseimg(font_nr);
 
     if (special >= 0 && special < NUM_SPECIAL_GFX_ARGS)
     {
+      boolean base_redefined =
+       getImageListEntryFromImageID(base_graphic)->redefined;
+      boolean special_redefined =
+       getImageListEntryFromImageID(graphic)->redefined;
+
+      /* if the base font ("font.title_1", for example) has been redefined,
+        but not the special font ("font.title_1.LEVELS", for example), do not
+        use an existing (in this case considered obsolete) special font
+        anymore, but use the automatically determined default font */
+      if (base_redefined && !special_redefined)
+       continue;
+
       font_info[font_nr].special_graphic[special] = graphic;
       font_info[font_nr].special_bitmap_id[special] = num_font_bitmaps;
       num_font_bitmaps++;
@@ -458,8 +304,11 @@ void InitFontGraphicInfo()
       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].draw_xoffset =
+       graphic_info[graphic].draw_xoffset;
+      font_bitmap_info[font_bitmap_id].draw_yoffset =
+       graphic_info[graphic].draw_yoffset;
 
       font_bitmap_info[font_bitmap_id].num_chars =
        graphic_info[graphic].anim_frames;
@@ -488,7 +337,7 @@ void InitElementGraphicInfo()
       element_info[i].graphic[act] = -1;
       element_info[i].crumbled[act] = -1;
 
-      for (dir = 0; dir < NUM_DIRECTIONS; dir++)
+      for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
       {
        element_info[i].direction_graphic[act][dir] = -1;
        element_info[i].direction_crumbled[act][dir] = -1;
@@ -572,7 +421,7 @@ void InitElementGraphicInfo()
     if (crumbled)
     {
       if (direction < 0)
-       for (dir = 0; dir < NUM_DIRECTIONS; dir++)
+       for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
          element_info[element].direction_crumbled[action][dir] = -1;
 
       if (direction > -1)
@@ -583,7 +432,7 @@ void InitElementGraphicInfo()
     else
     {
       if (direction < 0)
-       for (dir = 0; dir < NUM_DIRECTIONS; dir++)
+       for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
          element_info[element].direction_graphic[action][dir] = -1;
 
       if (direction > -1)
@@ -611,7 +460,7 @@ void InitElementGraphicInfo()
        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++)
+       for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
          element_info[i].direction_crumbled[act][dir] =
            element_info[crumbled_like].direction_crumbled[act][dir];
     }
@@ -620,7 +469,7 @@ void InitElementGraphicInfo()
     {
       element_info[i].graphic[ACTION_DIGGING] =
        element_info[diggable_like].graphic[ACTION_DIGGING];
-      for (dir = 0; dir < NUM_DIRECTIONS; dir++)
+      for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
        element_info[i].direction_graphic[ACTION_DIGGING][dir] =
          element_info[diggable_like].direction_graphic[ACTION_DIGGING][dir];
     }
@@ -632,6 +481,16 @@ void InitElementGraphicInfo()
 #endif
 
 #if 1
+  /* set hardcoded definitions for some internal elements without graphic */
+  for (i = 0; i < MAX_NUM_ELEMENTS; i++)
+  {
+    if (IS_EDITOR_CASCADE_INACTIVE(i))
+      element_info[i].graphic[ACTION_DEFAULT] = IMG_EDITOR_CASCADE_LIST;
+    else if (IS_EDITOR_CASCADE_ACTIVE(i))
+      element_info[i].graphic[ACTION_DEFAULT] = IMG_EDITOR_CASCADE_LIST_ACTIVE;
+  }
+#endif
+
   /* now set all undefined/invalid graphics to -1 to set to default after it */
   for (i = 0; i < MAX_NUM_ELEMENTS; i++)
   {
@@ -647,7 +506,7 @@ void InitElementGraphicInfo()
       if (graphic > 0 && graphic_info[graphic].bitmap == NULL)
        element_info[i].crumbled[act] = -1;
 
-      for (dir = 0; dir < NUM_DIRECTIONS; dir++)
+      for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
       {
        graphic = element_info[i].direction_graphic[act][dir];
        if (graphic > 0 && graphic_info[graphic].bitmap == NULL)
@@ -659,16 +518,14 @@ void InitElementGraphicInfo()
       }
     }
   }
-#endif
 
-#if 1
   /* adjust graphics with 2nd tile for movement according to direction
      (do this before correcting '-1' values to minimize calculations) */
   for (i = 0; i < MAX_NUM_ELEMENTS; i++)
   {
     for (act = 0; act < NUM_ACTIONS; act++)
     {
-      for (dir = 0; dir < NUM_DIRECTIONS; dir++)
+      for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
       {
        int graphic = element_info[i].direction_graphic[act][dir];
        int move_dir = (act == ACTION_FALLING ? MV_BIT_DOWN : dir);
@@ -689,18 +546,6 @@ void InitElementGraphicInfo()
                                                   g->offset_y != 0);
          boolean front_is_left_or_upper = (src_x_front < src_x_back ||
                                            src_y_front < src_y_back);
-#if 0
-         boolean second_tile_is_back =
-           ((move_dir == MV_BIT_LEFT  && front_is_left_or_upper) ||
-            (move_dir == MV_BIT_UP    && front_is_left_or_upper));
-         boolean second_tile_is_front =
-           ((move_dir == MV_BIT_RIGHT && front_is_left_or_upper) ||
-            (move_dir == MV_BIT_DOWN  && front_is_left_or_upper));
-         boolean second_tile_should_be_front =
-           (g->second_tile_is_start == 0);
-         boolean second_tile_should_be_back =
-           (g->second_tile_is_start == 1);
-#endif
          boolean swap_movement_tiles_always = (g->swap_double_tiles == 1);
          boolean swap_movement_tiles_autodetected =
            (!frames_are_ordered_diagonally &&
@@ -710,17 +555,6 @@ void InitElementGraphicInfo()
              (move_dir == MV_BIT_DOWN  &&  front_is_left_or_upper)));
          Bitmap *dummy;
 
-#if 0
-         printf("::: CHECKING element %d ('%s'), '%s', dir %d [(%d -> %d, %d), %d => %d]\n",
-                i, element_info[i].token_name,
-                element_action_info[act].suffix, move_dir,
-                g->swap_double_tiles,
-                swap_movement_tiles_never,
-                swap_movement_tiles_always,
-                swap_movement_tiles_autodetected,
-                swap_movement_tiles);
-#endif
-
          /* swap frontside and backside graphic tile coordinates, if needed */
          if (swap_movement_tiles_always || swap_movement_tiles_autodetected)
          {
@@ -738,24 +572,19 @@ void InitElementGraphicInfo()
 
            /* do not swap front and backside tiles again after correction */
            g->swap_double_tiles = 0;
-
-#if 0
-           printf("    CORRECTED\n");
-#endif
          }
        }
       }
     }
   }
-#endif
 
   /* now set all '-1' values to element specific default values */
   for (i = 0; i < MAX_NUM_ELEMENTS; i++)
   {
     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];
+    int default_direction_graphic[NUM_DIRECTIONS_FULL];
+    int default_direction_crumbled[NUM_DIRECTIONS_FULL];
 
     if (default_graphic == -1)
       default_graphic = IMG_UNKNOWN;
@@ -768,7 +597,7 @@ void InitElementGraphicInfo()
       default_crumbled = IMG_EMPTY;
 #endif
 
-    for (dir = 0; dir < NUM_DIRECTIONS; dir++)
+    for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
     {
       default_direction_graphic[dir] =
        element_info[i].direction_graphic[ACTION_DEFAULT][dir];
@@ -841,7 +670,7 @@ void InitElementGraphicInfo()
        default_action_crumbled = default_crumbled;
 #endif
 
-      for (dir = 0; dir < NUM_DIRECTIONS; dir++)
+      for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
       {
        /* use action graphic as the default direction graphic, if undefined */
        int default_action_direction_graphic = element_info[i].graphic[act];
@@ -879,16 +708,6 @@ void InitElementGraphicInfo()
        if (element_info[i].direction_crumbled[act][dir] == -1)
          element_info[i].direction_crumbled[act][dir] =
            default_action_direction_crumbled;
-
-#if 0
-       if (i == EL_EMC_GRASS &&
-           act == ACTION_DIGGING &&
-           dir == MV_BIT_DOWN)
-         printf("::: direction_crumbled == %d, %d, %d\n",
-                element_info[i].direction_crumbled[act][dir],
-                default_action_direction_crumbled,
-                element_info[i].crumbled[act]);
-#endif
       }
 
       /* no graphic for this specific action -- use default action graphic */
@@ -910,7 +729,8 @@ void InitElementGraphicInfo()
     }
   }
 
-#if 1
+#if 0
+  /* !!! THIS ALSO CLEARS SPECIAL FLAGS (AND IS NOT NEEDED ANYWAY) !!! */
   /* set animation mode to "none" for each graphic with only 1 frame */
   for (i = 0; i < MAX_NUM_ELEMENTS; i++)
   {
@@ -924,7 +744,7 @@ void InitElementGraphicInfo()
       if (graphic_info[crumbled].anim_frames == 1)
        graphic_info[crumbled].anim_mode = ANIM_NONE;
 
-      for (dir = 0; dir < NUM_DIRECTIONS; dir++)
+      for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
       {
        graphic = element_info[i].direction_graphic[act][dir];
        crumbled = element_info[i].direction_crumbled[act][dir];
@@ -1000,24 +820,46 @@ void InitElementSpecialGraphicInfo()
       element_info[element].special_graphic[special] = graphic;
   }
 
-#if 1
   /* now set all undefined/invalid graphics to default */
   for (i = 0; i < MAX_NUM_ELEMENTS; i++)
     for (j = 0; j < NUM_SPECIAL_GFX_ARGS; j++)
       if (graphic_info[element_info[i].special_graphic[j]].bitmap == NULL)
        element_info[i].special_graphic[j] =
          element_info[i].graphic[ACTION_DEFAULT];
-#endif
 }
 
-static int get_element_from_token(char *token)
+static int get_graphic_parameter_value(char *value_raw, char *suffix, int type)
 {
   int i;
+  int x = 0;
+
+  if (type != TYPE_TOKEN)
+    return get_parameter_value(value_raw, suffix, type);
 
+  if (strEqual(value_raw, ARG_UNDEFINED))
+    return ARG_UNDEFINED_VALUE;
+
+  /* !!! OPTIMIZE THIS BY USING HASH !!! */
   for (i = 0; i < MAX_NUM_ELEMENTS; i++)
-    if (strcmp(element_info[i].token_name, token) == 0)
+    if (strEqual(element_info[i].token_name, value_raw))
       return i;
 
+  /* !!! OPTIMIZE THIS BY USING HASH !!! */
+  for (i = 0; image_config[i].token != NULL; i++)
+  {
+    int len_config_value = strlen(image_config[i].value);
+
+    if (!strEqual(&image_config[i].value[len_config_value - 4], ".pcx") &&
+       !strEqual(&image_config[i].value[len_config_value - 4], ".wav") &&
+       !strEqual(image_config[i].value, UNDEFINED_FILENAME))
+      continue;
+
+    if (strEqual(image_config[i].token, value_raw))
+      return x;
+
+    x++;
+  }
+
   return -1;
 }
 
@@ -1037,73 +879,31 @@ static int get_scaled_graphic_height(int graphic)
   return original_height * scale_up_factor;
 }
 
-static void set_graphic_parameters(int graphic, int graphic_copy_from)
+static void set_graphic_parameters(int graphic)
 {
-  struct FileInfo *image = getImageListEntryFromImageID(graphic_copy_from);
+  struct FileInfo *image = getImageListEntryFromImageID(graphic);
   char **parameter_raw = image->parameter;
-  Bitmap *src_bitmap = getBitmapFromImageID(graphic_copy_from);
+  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;
 
-#if 1
-#if 1
-
-  /* !!! NEW ARTWORK FALLBACK CODE !!! NEARLY UNTESTED !!! */
   /* if fallback to default artwork is done, also use the default parameters */
   if (image->fallback_to_default)
-  {
-#if 0
-    printf("::: FALLBACK for %d\n", graphic_copy_from);
-#endif
-
     parameter_raw = image->default_parameter;
-  }
-
-#else
-
-  /* !!! ARTWORK FALLBACK CODE !!! NEARLY UNTESTED !!! */
-  /* (better try to set a "fallback -> use default parameters" flag) */
-  if (src_bitmap)
-  {
-    int len_source_filename = strlen(src_bitmap->source_filename);
-    int len_default_filename = strlen(image->default_filename);
-    int pos_basename = len_source_filename - len_default_filename;
-    char *source_basename = &src_bitmap->source_filename[pos_basename];
-
-#if 0
-    printf("::: src_bitmap->source_filename -> '%s'\n",
-          src_bitmap->source_filename);
-    printf("::: image->default_filename     -> '%s'\n",
-          image->default_filename);
-    printf("::: image->filename             -> '%s'\n",
-          image->filename);
-#endif
-
-    /* check if there was a fallback to the default artwork file */
-    if (strcmp(image->filename, image->default_filename) != 0 &&
-       pos_basename >= 0 &&
-       strcmp(source_basename, image->default_filename) == 0)
-      parameter_raw = image->default_parameter;
-  }
-#endif
-#endif
 
   /* 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]);
-  }
+    parameter[i] = get_graphic_parameter_value(parameter_raw[i],
+                                              image_config_suffix[i].token,
+                                              image_config_suffix[i].type);
 
   graphic_info[graphic].bitmap = src_bitmap;
 
   /* start with reliable default values */
+  graphic_info[graphic].src_image_width = 0;
+  graphic_info[graphic].src_image_height = 0;
   graphic_info[graphic].src_x = 0;
   graphic_info[graphic].src_y = 0;
   graphic_info[graphic].width = TILEX;
@@ -1117,6 +917,7 @@ static void set_graphic_parameters(int graphic, int graphic_copy_from)
   graphic_info[graphic].diggable_like = -1;    /* do not use clone element */
   graphic_info[graphic].border_size = TILEX / 8;  /* "CRUMBLED" border size */
   graphic_info[graphic].scale_up_factor = 1;   /* default: no scaling up */
+  graphic_info[graphic].clone_from = -1;       /* do not use clone graphic */
   graphic_info[graphic].anim_delay_fixed = 0;
   graphic_info[graphic].anim_delay_random = 0;
   graphic_info[graphic].post_delay_fixed = 0;
@@ -1149,11 +950,14 @@ static void set_graphic_parameters(int graphic, int graphic_copy_from)
   if (src_bitmap)
   {
     /* get final bitmap size (with scaling, but without small images) */
-    int src_bitmap_width  = get_scaled_graphic_width(graphic);
-    int src_bitmap_height = get_scaled_graphic_height(graphic);
+    int src_image_width  = get_scaled_graphic_width(graphic);
+    int src_image_height = get_scaled_graphic_height(graphic);
 
-    anim_frames_per_row = src_bitmap_width  / graphic_info[graphic].width;
-    anim_frames_per_col = src_bitmap_height / graphic_info[graphic].height;
+    anim_frames_per_row = src_image_width  / graphic_info[graphic].width;
+    anim_frames_per_col = src_image_height / graphic_info[graphic].height;
+
+    graphic_info[graphic].src_image_width  = src_image_width;
+    graphic_info[graphic].src_image_height = src_image_height;
   }
 
   /* correct x or y offset dependent of vertical or horizontal frame order */
@@ -1214,6 +1018,9 @@ static void set_graphic_parameters(int graphic, int graphic_copy_from)
   else
     graphic_info[graphic].anim_frames = 1;
 
+  if (graphic_info[graphic].anim_frames == 0)  /* frames must be at least 1 */
+    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);
@@ -1271,11 +1078,54 @@ static void set_graphic_parameters(int graphic, int graphic_copy_from)
   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];
+  graphic_info[graphic].draw_xoffset = parameter[GFX_ARG_DRAW_XOFFSET];
+  graphic_info[graphic].draw_yoffset = parameter[GFX_ARG_DRAW_YOFFSET];
 
   /* this is only used for drawing envelope graphics */
   graphic_info[graphic].draw_masked = parameter[GFX_ARG_DRAW_MASKED];
+
+  /* optional graphic for cloning all graphics settings */
+  if (parameter[GFX_ARG_CLONE_FROM] != ARG_UNDEFINED_VALUE)
+    graphic_info[graphic].clone_from = parameter[GFX_ARG_CLONE_FROM];
+}
+
+static void set_cloned_graphic_parameters(int graphic)
+{
+  int fallback_graphic = IMG_CHAR_EXCLAM;
+  int max_num_images = getImageListSize();
+  int clone_graphic = graphic_info[graphic].clone_from;
+  int num_references_followed = 1;
+
+  while (graphic_info[clone_graphic].clone_from != -1 &&
+        num_references_followed < max_num_images)
+  {
+    clone_graphic = graphic_info[clone_graphic].clone_from;
+
+    num_references_followed++;
+  }
+
+  if (num_references_followed >= max_num_images)
+  {
+    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(graphic));
+    Error(ERR_RETURN, "error: loop discovered when resolving cloned graphics");
+    Error(ERR_RETURN, "custom graphic rejected for this element/action");
+
+    if (graphic == 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, "-");
+
+    graphic_info[graphic] = graphic_info[fallback_graphic];
+  }
+  else
+  {
+    graphic_info[graphic] = graphic_info[clone_graphic];
+    graphic_info[graphic].clone_from = clone_graphic;
+  }
 }
 
 static void InitGraphicInfo()
@@ -1296,10 +1146,6 @@ static void InitGraphicInfo()
 
   graphic_info = checked_calloc(num_images * sizeof(struct GraphicInfo));
 
-#if 0
-  printf("::: graphic_info: %d entries\n", num_images);
-#endif
-
 #if defined(TARGET_X11_NATIVE_PERFORMANCE_WORKAROUND)
   if (clipmasks_initialized)
   {
@@ -1316,6 +1162,15 @@ static void InitGraphicInfo()
   }
 #endif
 
+  /* first set all graphic paramaters ... */
+  for (i = 0; i < num_images; i++)
+    set_graphic_parameters(i);
+
+  /* ... then copy these parameters for cloned graphics */
+  for (i = 0; i < num_images; i++)
+    if (graphic_info[i].clone_from != -1)
+      set_cloned_graphic_parameters(i);
+
   for (i = 0; i < num_images; i++)
   {
     Bitmap *src_bitmap;
@@ -1323,76 +1178,60 @@ static void InitGraphicInfo()
     int first_frame, last_frame;
     int src_bitmap_width, src_bitmap_height;
 
-#if 0
-    printf("::: image: '%s' [%d]\n", image->token, i);
-#endif
-
-#if 0
-    printf("::: image # %d: '%s' ['%s']\n",
-          i, image->token,
-          getTokenFromImageID(i));
-#endif
-
-    set_graphic_parameters(i, i);
-
     /* 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 */
 
     /* get final bitmap size (with scaling, but without small images) */
-    src_bitmap_width  = get_scaled_graphic_width(i);
-    src_bitmap_height = get_scaled_graphic_height(i);
+    src_bitmap_width  = graphic_info[i].src_image_width;
+    src_bitmap_height = graphic_info[i].src_image_height;
+
+    /* check if first animation frame is inside specified bitmap */
 
     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, "- 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: first animation frame out of bounds (%d, %d) [%d, %d]",
+           src_x, src_y, src_bitmap_width, src_bitmap_height);
       Error(ERR_RETURN, "custom graphic rejected for this element/action");
 
-#if 0
-      Error(ERR_RETURN, "scale_up_factor == %d", scale_up_factor);
-#endif
-
       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_graphic);
+      graphic_info[i] = graphic_info[fallback_graphic];
     }
 
+    /* check if last animation frame is inside specified 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, "- 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: last animation frame (%d) out of bounds (%d, %d) [%d, %d]",
+           last_frame, src_x, src_y, src_bitmap_width, src_bitmap_height);
       Error(ERR_RETURN, "custom graphic rejected for this element/action");
 
       if (i == fallback_graphic)
@@ -1401,7 +1240,7 @@ static void InitGraphicInfo()
       Error(ERR_RETURN, "fallback done to 'char_exclam' for this graphic");
       Error(ERR_RETURN_LINE, "-");
 
-      set_graphic_parameters(i, fallback_graphic);
+      graphic_info[i] = graphic_info[fallback_graphic];
     }
 
 #if defined(TARGET_X11_NATIVE_PERFORMANCE_WORKAROUND)
@@ -1466,8 +1305,8 @@ static void InitElementSoundInfo()
       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)
+       if (strEqual(element_info[j].class_name,
+                    element_info[element].class_name))
          element_info[j].sound[action] = sound;
   }
 
@@ -1485,8 +1324,8 @@ static void InitElementSoundInfo()
       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)
+      if (strEqual(element_info[j].class_name,
+                  element_info[element_class].class_name))
        element_info[j].sound[action] = sound;
   }
 
@@ -1542,7 +1381,6 @@ static void InitElementSoundInfo()
     }
   }
 
-#if 1
   /* copy sound settings to some elements that are only stored in level file
      in native R'n'D levels, but are used by game engine in native EM levels */
   for (i = 0; copy_properties[i][0] != -1; i++)
@@ -1550,7 +1388,6 @@ static void InitElementSoundInfo()
       for (act = 0; act < NUM_ACTIONS; act++)
        element_info[copy_properties[i][j]].sound[act] =
          element_info[copy_properties[i][0]].sound[act];
-#endif
 }
 
 static void InitGameModeSoundInfo()
@@ -1579,7 +1416,6 @@ static void InitGameModeSoundInfo()
       menu.sound[i] = menu.sound[GAME_MODE_DEFAULT];
 
 #if 0
-  /* TEST ONLY */
   for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
     if (menu.sound[i] != -1)
       printf("::: menu.sound[%d] == %d\n", i, menu.sound[i]);
@@ -1594,7 +1430,8 @@ static void set_sound_parameters(int sound, char **parameter_raw)
   /* 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],
+      get_parameter_value(parameter_raw[i],
+                         sound_config_suffix[i].token,
                          sound_config_suffix[i].type);
 
   /* explicit loop mode setting in configuration overrides default value */
@@ -1610,10 +1447,6 @@ static void set_sound_parameters(int sound, char **parameter_raw)
 
 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;
@@ -1647,8 +1480,8 @@ static void InitSoundInfo()
       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)
+         strEqual(&sound->token[len_effect_text - len_action_text],
+                  element_action_info[j].suffix))
       {
        sound_effect_properties[i] = element_action_info[j].value;
        sound_info[i].loop = element_action_info[j].is_loop_sound;
@@ -1657,11 +1490,6 @@ static void InitSoundInfo()
       }
     }
 
-#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++)
@@ -1686,77 +1514,6 @@ static void InitSoundInfo()
   }
 
   free(sound_effect_properties);
-
-#if 0
-  /* !!! MOVED TO "InitElementSoundInfo()" !!! */
-  /* !!! everything defined here gets overwritten there !!! */
-
-  /* copy sound settings to some elements that are only stored in level file
-     in native R'n'D levels, but are used by game engine in native EM levels */
-  for (i = 0; i < NUM_ACTIONS; i++)
-    for (j = 0; copy_properties[j][0] != -1; j++)
-      for (k = 1; k <= 4; k++)
-       element_info[copy_properties[j][k]].sound[i] =
-         element_info[copy_properties[j][0]].sound[i];
-
-  printf("::: bug   -> %d\n", element_info[EL_BUG].sound[ACTION_MOVING]);
-  printf("::: bug_r -> %d\n", element_info[EL_BUG_RIGHT].sound[ACTION_MOVING]);
-#endif
-
-#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 InitGameModeMusicInfo()
@@ -1834,7 +1591,6 @@ static void InitGameModeMusicInfo()
       menu.music[i] = menu.music[GAME_MODE_DEFAULT];
 
 #if 0
-  /* TEST ONLY */
   for (i = 0; i < MAX_LEVELS; i++)
     if (levelset.music[i] != -1)
       printf("::: levelset.music[%d] == %d\n", i, levelset.music[i]);
@@ -1852,7 +1608,8 @@ static void set_music_parameters(int music, char **parameter_raw)
   /* get integer values from string parameters */
   for (i = 0; i < NUM_MUS_ARGS; i++)
     parameter[i] =
-      get_parameter_value(music_config_suffix[i].token, parameter_raw[i],
+      get_parameter_value(parameter_raw[i],
+                         music_config_suffix[i].token,
                          music_config_suffix[i].type);
 
   /* explicit loop mode setting in configuration overrides default value */
@@ -1902,7 +1659,8 @@ static void ReinitializeGraphics()
   InitElementGraphicInfo();            /* element game graphic mapping */
   InitElementSpecialGraphicInfo();     /* element special graphic mapping */
 
-  InitElementSmallImages();            /* scale images to all needed sizes */
+  InitElementSmallImages();            /* scale elements to all needed sizes */
+  InitScaledImages();                  /* scale all other images, if needed */
   InitFontGraphicInfo();               /* initialize text drawing functions */
 
   InitGraphicInfo_EM();                        /* graphic mapping for EM engine */
@@ -1947,7 +1705,7 @@ static int get_special_property_bit(int element, int property_bit_nr)
     { EL_SP_MURPHY,            0       },
     { EL_SOKOBAN_FIELD_PLAYER, 0       },
 
-    /* all element that can move may be able to also move into acid */
+    /* all elements that can move may be able to also move into acid */
     { EL_BUG,                  1       },
     { EL_BUG_LEFT,             1       },
     { EL_BUG_RIGHT,            1       },
@@ -1969,6 +1727,10 @@ static int get_special_property_bit(int element, int property_bit_nr)
     { EL_BD_FIREFLY_UP,                4       },
     { EL_BD_FIREFLY_DOWN,      4       },
     { EL_YAMYAM,               5       },
+    { EL_YAMYAM_LEFT,          5       },
+    { EL_YAMYAM_RIGHT,         5       },
+    { EL_YAMYAM_UP,            5       },
+    { EL_YAMYAM_DOWN,          5       },
     { EL_DARK_YAMYAM,          6       },
     { EL_ROBOT,                        7       },
     { EL_PACMAN,               8       },
@@ -1989,6 +1751,7 @@ static int get_special_property_bit(int element, int property_bit_nr)
     { EL_SP_ELECTRON,          15      },
     { EL_BALLOON,              16      },
     { EL_SPRING,               17      },
+    { EL_EMC_ANDROID,          18      },
 
     { -1,                      -1      },
   };
@@ -2030,7 +1793,6 @@ static int get_special_property_bit(int element, int property_bit_nr)
   return -1;
 }
 
-#if 1
 void setBitfieldProperty(int *bitfield, int property_bit_nr, int element,
                         boolean property_value)
 {
@@ -2055,29 +1817,52 @@ boolean getBitfieldProperty(int *bitfield, int property_bit_nr, int element)
   return FALSE;
 }
 
-#else
-
-void setMoveIntoAcidProperty(struct LevelInfo *level, int element, boolean set)
+#if 1
+static void resolve_group_element(int group_element, int recursion_depth)
 {
-  int bit_nr = get_special_property_bit(element, EP_CAN_MOVE_INTO_ACID);
+  static int group_nr;
+  static struct ElementGroupInfo *group;
+  struct ElementGroupInfo *actual_group = element_info[group_element].group;
+  int i;
 
-  if (bit_nr > -1)
+  if (actual_group == NULL)                    /* not yet initialized */
+    return;
+
+  if (recursion_depth > NUM_GROUP_ELEMENTS)    /* recursion too deep */
   {
-    level->can_move_into_acid_bits &= ~(1 << bit_nr);
+    Error(ERR_WARN, "recursion too deep when resolving group element %d",
+         group_element - EL_GROUP_START + 1);
 
-    if (set)
-      level->can_move_into_acid_bits |= (1 << bit_nr);
+    /* replace element which caused too deep recursion by question mark */
+    group->element_resolved[group->num_elements_resolved++] = EL_UNKNOWN;
+
+    return;
   }
-}
 
-boolean getMoveIntoAcidProperty(struct LevelInfo *level, int element)
-{
-  int bit_nr = get_special_property_bit(element, EP_CAN_MOVE_INTO_ACID);
+  if (recursion_depth == 0)                    /* initialization */
+  {
+    group = actual_group;
+    group_nr = group_element - EL_GROUP_START;
 
-  if (bit_nr > -1)
-    return ((level->can_move_into_acid_bits & (1 << bit_nr)) != 0);
+    group->num_elements_resolved = 0;
+    group->choice_pos = 0;
+  }
 
-  return FALSE;
+  for (i = 0; i < actual_group->num_elements; i++)
+  {
+    int element = actual_group->element[i];
+
+    if (group->num_elements_resolved == NUM_FILE_ELEMENTS)
+      break;
+
+    if (IS_GROUP_ELEMENT(element))
+      resolve_group_element(element, recursion_depth + 1);
+    else
+    {
+      group->element_resolved[group->num_elements_resolved++] = element;
+      element_info[element].in_group[group_nr] = TRUE;
+    }
+  }
 }
 #endif
 
@@ -2102,6 +1887,7 @@ void InitElementPropertiesStatic()
     EL_SP_BUGGY_BASE_ACTIVE,
     EL_EMC_PLANT,
 #endif
+
     -1
   };
 
@@ -2126,6 +1912,7 @@ void InitElementPropertiesStatic()
     EL_EMC_KEY_7,
     EL_EMC_KEY_8,
     EL_DYNAMITE,
+    EL_EM_DYNAMITE,
     EL_DYNABOMB_INCREASE_NUMBER,
     EL_DYNABOMB_INCREASE_SIZE,
     EL_DYNABOMB_INCREASE_POWER,
@@ -2144,6 +1931,7 @@ void InitElementPropertiesStatic()
     EL_SPEED_PILL,
     EL_EMC_LENSES,
     EL_EMC_MAGNIFIER,
+
     -1
   };
 
@@ -2174,6 +1962,7 @@ void InitElementPropertiesStatic()
     EL_SP_BUGGY_BASE_ACTIVE,
     EL_EMC_PLANT,
 #endif
+
     -1
   };
 
@@ -2192,6 +1981,7 @@ void InitElementPropertiesStatic()
     EL_PACMAN,
     EL_SP_SNIKSNAK,
     EL_SP_ELECTRON,
+
     -1
   };
 
@@ -2201,6 +1991,7 @@ void InitElementPropertiesStatic()
     EL_SPACESHIP,
     EL_BD_BUTTERFLY,
     EL_BD_FIREFLY,
+
     -1
   };
 
@@ -2266,6 +2057,10 @@ void InitElementPropertiesStatic()
     EL_GATE_2_GRAY,
     EL_GATE_3_GRAY,
     EL_GATE_4_GRAY,
+    EL_GATE_1_GRAY_ACTIVE,
+    EL_GATE_2_GRAY_ACTIVE,
+    EL_GATE_3_GRAY_ACTIVE,
+    EL_GATE_4_GRAY_ACTIVE,
     EL_EM_GATE_1,
     EL_EM_GATE_2,
     EL_EM_GATE_3,
@@ -2274,6 +2069,10 @@ void InitElementPropertiesStatic()
     EL_EM_GATE_2_GRAY,
     EL_EM_GATE_3_GRAY,
     EL_EM_GATE_4_GRAY,
+    EL_EM_GATE_1_GRAY_ACTIVE,
+    EL_EM_GATE_2_GRAY_ACTIVE,
+    EL_EM_GATE_3_GRAY_ACTIVE,
+    EL_EM_GATE_4_GRAY_ACTIVE,
     EL_EMC_GATE_5,
     EL_EMC_GATE_6,
     EL_EMC_GATE_7,
@@ -2282,6 +2081,10 @@ void InitElementPropertiesStatic()
     EL_EMC_GATE_6_GRAY,
     EL_EMC_GATE_7_GRAY,
     EL_EMC_GATE_8_GRAY,
+    EL_EMC_GATE_5_GRAY_ACTIVE,
+    EL_EMC_GATE_6_GRAY_ACTIVE,
+    EL_EMC_GATE_7_GRAY_ACTIVE,
+    EL_EMC_GATE_8_GRAY_ACTIVE,
     EL_SWITCHGATE_OPEN,
     EL_SWITCHGATE_OPENING,
     EL_SWITCHGATE_CLOSED,
@@ -2309,6 +2112,7 @@ void InitElementPropertiesStatic()
     EL_TUBE_LEFT_DOWN,
     EL_TUBE_RIGHT_UP,
     EL_TUBE_RIGHT_DOWN,
+
     -1
   };
 
@@ -2350,6 +2154,9 @@ void InitElementPropertiesStatic()
     EL_EMC_WALL_SLIPPERY_2,
     EL_EMC_WALL_SLIPPERY_3,
     EL_EMC_WALL_SLIPPERY_4,
+    EL_EMC_MAGIC_BALL,
+    EL_EMC_MAGIC_BALL_ACTIVE,
+
     -1
   };
 
@@ -2379,6 +2186,7 @@ void InitElementPropertiesStatic()
     EL_BALLOON,
     EL_SPRING,
     EL_EMC_ANDROID,
+
     -1
   };
 
@@ -2407,6 +2215,7 @@ void InitElementPropertiesStatic()
     EL_CRYSTAL,
     EL_SPRING,
     EL_DX_SUPABOMB,
+
     -1
   };
 
@@ -2432,6 +2241,7 @@ void InitElementPropertiesStatic()
     EL_CRYSTAL,
     EL_SPRING,
     EL_DX_SUPABOMB,
+
     -1
   };
 
@@ -2440,6 +2250,7 @@ void InitElementPropertiesStatic()
     EL_ROCK,
     EL_BD_ROCK,
     EL_SP_ZONK,
+
     -1
   };
 
@@ -2448,6 +2259,7 @@ void InitElementPropertiesStatic()
     EL_ROCK,
     EL_BD_ROCK,
     EL_SP_ZONK,
+
     -1
   };
 
@@ -2465,8 +2277,10 @@ void InitElementPropertiesStatic()
     EL_MOLE,
 
     /* new elements */
-    EL_DYNAMITE_ACTIVE,
     EL_DYNAMITE,
+    EL_DYNAMITE_ACTIVE,
+    EL_EM_DYNAMITE,
+    EL_EM_DYNAMITE_ACTIVE,
     EL_DYNABOMB_PLAYER_1_ACTIVE,
     EL_DYNABOMB_PLAYER_2_ACTIVE,
     EL_DYNABOMB_PLAYER_3_ACTIVE,
@@ -2484,6 +2298,7 @@ void InitElementPropertiesStatic()
 #if 0
     EL_BLACK_ORB,
 #endif
+
     -1
   };
 
@@ -2499,6 +2314,7 @@ void InitElementPropertiesStatic()
     EL_PIG,
     EL_DRAGON,
     EL_MOLE,
+
     -1
   };
 
@@ -2507,6 +2323,7 @@ void InitElementPropertiesStatic()
     EL_BOMB,
     EL_SP_DISK_ORANGE,
     EL_DX_SUPABOMB,
+
     -1
   };
 
@@ -2526,14 +2343,14 @@ void InitElementPropertiesStatic()
     EL_GATE_2_GRAY,
     EL_GATE_3_GRAY,
     EL_GATE_4_GRAY,
+    EL_GATE_1_GRAY_ACTIVE,
+    EL_GATE_2_GRAY_ACTIVE,
+    EL_GATE_3_GRAY_ACTIVE,
+    EL_GATE_4_GRAY_ACTIVE,
     EL_PENGUIN,
     EL_PIG,
     EL_DRAGON,
 
-#if 0  /* USE_GRAVITY_BUGFIX_OLD */
-    EL_PLAYER_IS_LEAVING,      /* needed for gravity + "block last field" */
-#endif
-
     -1
   };
 
@@ -2550,6 +2367,7 @@ void InitElementPropertiesStatic()
     EL_TUBE_LEFT_DOWN,
     EL_TUBE_RIGHT_UP,
     EL_TUBE_RIGHT_DOWN,
+
     -1
   };
 
@@ -2568,6 +2386,10 @@ void InitElementPropertiesStatic()
     EL_EM_GATE_2_GRAY,
     EL_EM_GATE_3_GRAY,
     EL_EM_GATE_4_GRAY,
+    EL_EM_GATE_1_GRAY_ACTIVE,
+    EL_EM_GATE_2_GRAY_ACTIVE,
+    EL_EM_GATE_3_GRAY_ACTIVE,
+    EL_EM_GATE_4_GRAY_ACTIVE,
     EL_EMC_GATE_5,
     EL_EMC_GATE_6,
     EL_EMC_GATE_7,
@@ -2576,8 +2398,13 @@ void InitElementPropertiesStatic()
     EL_EMC_GATE_6_GRAY,
     EL_EMC_GATE_7_GRAY,
     EL_EMC_GATE_8_GRAY,
+    EL_EMC_GATE_5_GRAY_ACTIVE,
+    EL_EMC_GATE_6_GRAY_ACTIVE,
+    EL_EMC_GATE_7_GRAY_ACTIVE,
+    EL_EMC_GATE_8_GRAY_ACTIVE,
     EL_SWITCHGATE_OPEN,
     EL_TIMEGATE_OPEN,
+
     -1
   };
 
@@ -2602,6 +2429,7 @@ void InitElementPropertiesStatic()
     EL_SP_GRAVITY_OFF_PORT_RIGHT,
     EL_SP_GRAVITY_OFF_PORT_UP,
     EL_SP_GRAVITY_OFF_PORT_DOWN,
+
     -1
   };
 
@@ -2637,6 +2465,7 @@ void InitElementPropertiesStatic()
     EL_SP_DISK_YELLOW,
     EL_BALLOON,
     EL_EMC_ANDROID,
+
     -1
   };
 
@@ -2669,6 +2498,10 @@ void InitElementPropertiesStatic()
     EL_EM_GATE_2_GRAY,
     EL_EM_GATE_3_GRAY,
     EL_EM_GATE_4_GRAY,
+    EL_EM_GATE_1_GRAY_ACTIVE,
+    EL_EM_GATE_2_GRAY_ACTIVE,
+    EL_EM_GATE_3_GRAY_ACTIVE,
+    EL_EM_GATE_4_GRAY_ACTIVE,
     EL_EMC_GATE_5,
     EL_EMC_GATE_6,
     EL_EMC_GATE_7,
@@ -2677,6 +2510,10 @@ void InitElementPropertiesStatic()
     EL_EMC_GATE_6_GRAY,
     EL_EMC_GATE_7_GRAY,
     EL_EMC_GATE_8_GRAY,
+    EL_EMC_GATE_5_GRAY_ACTIVE,
+    EL_EMC_GATE_6_GRAY_ACTIVE,
+    EL_EMC_GATE_7_GRAY_ACTIVE,
+    EL_EMC_GATE_8_GRAY_ACTIVE,
     EL_SWITCHGATE_OPEN,
     EL_TIMEGATE_OPEN,
 
@@ -2700,6 +2537,7 @@ void InitElementPropertiesStatic()
     EL_SP_GRAVITY_OFF_PORT_RIGHT,
     EL_SP_GRAVITY_OFF_PORT_UP,
     EL_SP_GRAVITY_OFF_PORT_DOWN,
+
     -1
   };
 
@@ -2722,8 +2560,10 @@ void InitElementPropertiesStatic()
     EL_MOLE,
 
     /* elements that can explode by explosion or by dragonfire */
-    EL_DYNAMITE_ACTIVE,
     EL_DYNAMITE,
+    EL_DYNAMITE_ACTIVE,
+    EL_EM_DYNAMITE,
+    EL_EM_DYNAMITE_ACTIVE,
     EL_DYNABOMB_PLAYER_1_ACTIVE,
     EL_DYNABOMB_PLAYER_2_ACTIVE,
     EL_DYNABOMB_PLAYER_3_ACTIVE,
@@ -2741,6 +2581,7 @@ void InitElementPropertiesStatic()
 
     /* elements that can explode only by explosion */
     EL_BLACK_ORB,
+
     -1
   };
 
@@ -2771,6 +2612,7 @@ void InitElementPropertiesStatic()
     EL_SP_GRAVITY_OFF_PORT_UP,
     EL_SP_GRAVITY_OFF_PORT_DOWN,
     EL_EMC_GRASS,
+
     -1
   };
 
@@ -2783,6 +2625,7 @@ void InitElementPropertiesStatic()
     EL_SP_MURPHY,
     EL_SOKOBAN_FIELD_PLAYER,
     EL_TRIGGER_PLAYER,
+
     -1
   };
 
@@ -2796,6 +2639,7 @@ void InitElementPropertiesStatic()
     EL_EMERALD_RED,
     EL_EMERALD_PURPLE,
     EL_DIAMOND,
+
     -1
   };
 
@@ -2825,9 +2669,12 @@ void InitElementPropertiesStatic()
     EL_BALLOON_SWITCH_UP,
     EL_BALLOON_SWITCH_DOWN,
     EL_BALLOON_SWITCH_ANY,
+    EL_BALLOON_SWITCH_NONE,
     EL_LAMP,
     EL_TIME_ORB_FULL,
     EL_EMC_MAGIC_BALL_SWITCH,
+    EL_EMC_MAGIC_BALL_SWITCH_ACTIVE,
+
     -1
   };
 
@@ -2861,6 +2708,7 @@ void InitElementPropertiesStatic()
     EL_BD_AMOEBA,
     EL_CHAR_QUESTION,
     EL_UNKNOWN,
+
     -1
   };
 
@@ -2935,6 +2783,7 @@ void InitElementPropertiesStatic()
     EL_SP_BUGGY_BASE_ACTIVE,
     EL_SP_EXIT_OPENING,
     EL_SP_EXIT_CLOSING,
+
     -1
   };
 
@@ -2951,6 +2800,7 @@ void InitElementPropertiesStatic()
     EL_PLAYER_3,
     EL_PLAYER_4,
     EL_INVISIBLE_STEELWALL,
+
     -1
   };
 
@@ -2962,6 +2812,7 @@ void InitElementPropertiesStatic()
     EL_EMERALD_RED,
     EL_EMERALD_PURPLE,
     EL_DIAMOND,
+
     -1
   };
 
@@ -2989,6 +2840,7 @@ void InitElementPropertiesStatic()
     EL_DIAMOND,
     EL_PEARL,
     EL_CRYSTAL,
+
     -1
   };
 
@@ -3002,6 +2854,7 @@ void InitElementPropertiesStatic()
     EL_DIAMOND,
     EL_PEARL,
     EL_CRYSTAL,
+
     -1
   };
 
@@ -3013,6 +2866,7 @@ void InitElementPropertiesStatic()
     EL_EMERALD_RED,
     EL_EMERALD_PURPLE,
     EL_DIAMOND,
+
     -1
   };
 
@@ -3027,6 +2881,10 @@ void InitElementPropertiesStatic()
     EL_GATE_2_GRAY,
     EL_GATE_3_GRAY,
     EL_GATE_4_GRAY,
+    EL_GATE_1_GRAY_ACTIVE,
+    EL_GATE_2_GRAY_ACTIVE,
+    EL_GATE_3_GRAY_ACTIVE,
+    EL_GATE_4_GRAY_ACTIVE,
     EL_EM_GATE_1,
     EL_EM_GATE_2,
     EL_EM_GATE_3,
@@ -3035,6 +2893,10 @@ void InitElementPropertiesStatic()
     EL_EM_GATE_2_GRAY,
     EL_EM_GATE_3_GRAY,
     EL_EM_GATE_4_GRAY,
+    EL_EM_GATE_1_GRAY_ACTIVE,
+    EL_EM_GATE_2_GRAY_ACTIVE,
+    EL_EM_GATE_3_GRAY_ACTIVE,
+    EL_EM_GATE_4_GRAY_ACTIVE,
     EL_EXIT_CLOSED,
     EL_EXIT_OPENING,
     EL_EXIT_OPEN,
@@ -3045,6 +2907,7 @@ void InitElementPropertiesStatic()
     EL_EXPANDABLE_WALL_VERTICAL,
     EL_EXPANDABLE_WALL_ANY,
     EL_EXPANDABLE_WALL_GROWING,
+    EL_BD_EXPANDABLE_WALL,
     EL_BD_WALL,
     EL_SP_CHIP_SINGLE,
     EL_SP_CHIP_LEFT,
@@ -3083,6 +2946,7 @@ void InitElementPropertiesStatic()
     EL_EMC_WALL_6,
     EL_EMC_WALL_7,
     EL_EMC_WALL_8,
+
     -1
   };
 
@@ -3093,6 +2957,7 @@ void InitElementPropertiesStatic()
     EL_EXPANDABLE_WALL_HORIZONTAL,
     EL_EXPANDABLE_WALL_VERTICAL,
     EL_EXPANDABLE_WALL_ANY,
+    EL_BD_EXPANDABLE_WALL,
     EL_BD_WALL,
     EL_WALL_SLIPPERY,
     EL_EXIT_CLOSED,
@@ -3211,6 +3076,10 @@ void InitElementPropertiesStatic()
     EL_GATE_2_GRAY,
     EL_GATE_3_GRAY,
     EL_GATE_4_GRAY,
+    EL_GATE_1_GRAY_ACTIVE,
+    EL_GATE_2_GRAY_ACTIVE,
+    EL_GATE_3_GRAY_ACTIVE,
+    EL_GATE_4_GRAY_ACTIVE,
     EL_EM_GATE_1,
     EL_EM_GATE_2,
     EL_EM_GATE_3,
@@ -3219,6 +3088,10 @@ void InitElementPropertiesStatic()
     EL_EM_GATE_2_GRAY,
     EL_EM_GATE_3_GRAY,
     EL_EM_GATE_4_GRAY,
+    EL_EM_GATE_1_GRAY_ACTIVE,
+    EL_EM_GATE_2_GRAY_ACTIVE,
+    EL_EM_GATE_3_GRAY_ACTIVE,
+    EL_EM_GATE_4_GRAY_ACTIVE,
     EL_SWITCHGATE_OPEN,
     EL_SWITCHGATE_OPENING,
     EL_SWITCHGATE_CLOSED,
@@ -3238,6 +3111,7 @@ void InitElementPropertiesStatic()
     EL_TUBE_LEFT_DOWN,
     EL_TUBE_RIGHT_UP,
     EL_TUBE_RIGHT_DOWN,
+
     -1
   };
 
@@ -3254,6 +3128,7 @@ void InitElementPropertiesStatic()
     EL_PACMAN,
     EL_SP_SNIKSNAK,
     EL_SP_ELECTRON,
+
     -1
   };
 
@@ -3271,6 +3146,7 @@ void InitElementPropertiesStatic()
     EL_CONVEYOR_BELT_4_LEFT,
     EL_CONVEYOR_BELT_4_MIDDLE,
     EL_CONVEYOR_BELT_4_RIGHT,
+
     -1
   };
 
@@ -3288,6 +3164,7 @@ void InitElementPropertiesStatic()
     EL_CONVEYOR_BELT_4_LEFT_ACTIVE,
     EL_CONVEYOR_BELT_4_MIDDLE_ACTIVE,
     EL_CONVEYOR_BELT_4_RIGHT_ACTIVE,
+
     -1
   };
 
@@ -3305,6 +3182,7 @@ void InitElementPropertiesStatic()
     EL_CONVEYOR_BELT_4_SWITCH_LEFT,
     EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
     EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
+
     -1
   };
 
@@ -3321,6 +3199,7 @@ void InitElementPropertiesStatic()
     EL_TUBE_VERTICAL_LEFT,
     EL_TUBE_VERTICAL_RIGHT,
     EL_TUBE_ANY,
+
     -1
   };
 
@@ -3334,6 +3213,10 @@ void InitElementPropertiesStatic()
     EL_GATE_2_GRAY,
     EL_GATE_3_GRAY,
     EL_GATE_4_GRAY,
+    EL_GATE_1_GRAY_ACTIVE,
+    EL_GATE_2_GRAY_ACTIVE,
+    EL_GATE_3_GRAY_ACTIVE,
+    EL_GATE_4_GRAY_ACTIVE,
     EL_EM_GATE_1,
     EL_EM_GATE_2,
     EL_EM_GATE_3,
@@ -3342,6 +3225,10 @@ void InitElementPropertiesStatic()
     EL_EM_GATE_2_GRAY,
     EL_EM_GATE_3_GRAY,
     EL_EM_GATE_4_GRAY,
+    EL_EM_GATE_1_GRAY_ACTIVE,
+    EL_EM_GATE_2_GRAY_ACTIVE,
+    EL_EM_GATE_3_GRAY_ACTIVE,
+    EL_EM_GATE_4_GRAY_ACTIVE,
     EL_EMC_GATE_5,
     EL_EMC_GATE_6,
     EL_EMC_GATE_7,
@@ -3350,6 +3237,11 @@ void InitElementPropertiesStatic()
     EL_EMC_GATE_6_GRAY,
     EL_EMC_GATE_7_GRAY,
     EL_EMC_GATE_8_GRAY,
+    EL_EMC_GATE_5_GRAY_ACTIVE,
+    EL_EMC_GATE_6_GRAY_ACTIVE,
+    EL_EMC_GATE_7_GRAY_ACTIVE,
+    EL_EMC_GATE_8_GRAY_ACTIVE,
+
     -1
   };
 
@@ -3360,6 +3252,8 @@ void InitElementPropertiesStatic()
     EL_AMOEBA_DRY,
     EL_AMOEBA_FULL,
     EL_BD_AMOEBA,
+    EL_EMC_DRIPPER,
+
     -1
   };
 
@@ -3369,16 +3263,30 @@ void InitElementPropertiesStatic()
     EL_AMOEBA_DRY,
     EL_AMOEBA_FULL,
     EL_BD_AMOEBA,
+    EL_EMC_DRIPPER,
+
     -1
   };
 
-  static int ep_has_content[] =
+  static int ep_has_editor_content[] =
   {
+    EL_PLAYER_1,
+    EL_PLAYER_2,
+    EL_PLAYER_3,
+    EL_PLAYER_4,
+    EL_SP_MURPHY,
     EL_YAMYAM,
+    EL_YAMYAM_LEFT,
+    EL_YAMYAM_RIGHT,
+    EL_YAMYAM_UP,
+    EL_YAMYAM_DOWN,
     EL_AMOEBA_WET,
     EL_AMOEBA_DRY,
     EL_AMOEBA_FULL,
     EL_BD_AMOEBA,
+    EL_EMC_MAGIC_BALL,
+    EL_EMC_ANDROID,
+
     -1
   };
 
@@ -3397,17 +3305,21 @@ void InitElementPropertiesStatic()
     EL_AMOEBA_FULL,
     EL_GAME_OF_LIFE,
     EL_BIOMAZE,
+    EL_EMC_DRIPPER,
+
     -1
   };
 
   static int ep_active_bomb[] =
   {
     EL_DYNAMITE_ACTIVE,
+    EL_EM_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
   };
 
@@ -3443,6 +3355,10 @@ void InitElementPropertiesStatic()
     EL_GATE_2_GRAY,
     EL_GATE_3_GRAY,
     EL_GATE_4_GRAY,
+    EL_GATE_1_GRAY_ACTIVE,
+    EL_GATE_2_GRAY_ACTIVE,
+    EL_GATE_3_GRAY_ACTIVE,
+    EL_GATE_4_GRAY_ACTIVE,
     EL_EM_GATE_1,
     EL_EM_GATE_2,
     EL_EM_GATE_3,
@@ -3451,6 +3367,10 @@ void InitElementPropertiesStatic()
     EL_EM_GATE_2_GRAY,
     EL_EM_GATE_3_GRAY,
     EL_EM_GATE_4_GRAY,
+    EL_EM_GATE_1_GRAY_ACTIVE,
+    EL_EM_GATE_2_GRAY_ACTIVE,
+    EL_EM_GATE_3_GRAY_ACTIVE,
+    EL_EM_GATE_4_GRAY_ACTIVE,
     EL_EMC_GATE_5,
     EL_EMC_GATE_6,
     EL_EMC_GATE_7,
@@ -3459,7 +3379,12 @@ void InitElementPropertiesStatic()
     EL_EMC_GATE_6_GRAY,
     EL_EMC_GATE_7_GRAY,
     EL_EMC_GATE_8_GRAY,
+    EL_EMC_GATE_5_GRAY_ACTIVE,
+    EL_EMC_GATE_6_GRAY_ACTIVE,
+    EL_EMC_GATE_7_GRAY_ACTIVE,
+    EL_EMC_GATE_8_GRAY_ACTIVE,
     EL_DYNAMITE,
+    EL_EM_DYNAMITE,
     EL_INVISIBLE_STEELWALL,
     EL_INVISIBLE_WALL,
     EL_INVISIBLE_SAND,
@@ -3580,6 +3505,7 @@ void InitElementPropertiesStatic()
     EL_EMC_WALL_14,
     EL_EMC_WALL_15,
     EL_EMC_WALL_16,
+
     -1
   };
 
@@ -3594,6 +3520,60 @@ void InitElementPropertiesStatic()
     EL_LANDMINE,
     EL_TRAP,
     EL_TRAP_ACTIVE,
+
+    -1
+  };
+
+  static int ep_editor_cascade_active[] =
+  {
+    EL_INTERNAL_CASCADE_BD_ACTIVE,
+    EL_INTERNAL_CASCADE_EM_ACTIVE,
+    EL_INTERNAL_CASCADE_EMC_ACTIVE,
+    EL_INTERNAL_CASCADE_RND_ACTIVE,
+    EL_INTERNAL_CASCADE_SB_ACTIVE,
+    EL_INTERNAL_CASCADE_SP_ACTIVE,
+    EL_INTERNAL_CASCADE_DC_ACTIVE,
+    EL_INTERNAL_CASCADE_DX_ACTIVE,
+    EL_INTERNAL_CASCADE_CHARS_ACTIVE,
+    EL_INTERNAL_CASCADE_CE_ACTIVE,
+    EL_INTERNAL_CASCADE_GE_ACTIVE,
+    EL_INTERNAL_CASCADE_REF_ACTIVE,
+    EL_INTERNAL_CASCADE_USER_ACTIVE,
+    EL_INTERNAL_CASCADE_DYNAMIC_ACTIVE,
+
+    -1
+  };
+
+  static int ep_editor_cascade_inactive[] =
+  {
+    EL_INTERNAL_CASCADE_BD,
+    EL_INTERNAL_CASCADE_EM,
+    EL_INTERNAL_CASCADE_EMC,
+    EL_INTERNAL_CASCADE_RND,
+    EL_INTERNAL_CASCADE_SB,
+    EL_INTERNAL_CASCADE_SP,
+    EL_INTERNAL_CASCADE_DC,
+    EL_INTERNAL_CASCADE_DX,
+    EL_INTERNAL_CASCADE_CHARS,
+    EL_INTERNAL_CASCADE_CE,
+    EL_INTERNAL_CASCADE_GE,
+    EL_INTERNAL_CASCADE_REF,
+    EL_INTERNAL_CASCADE_USER,
+    EL_INTERNAL_CASCADE_DYNAMIC,
+
+    -1
+  };
+
+  static int ep_obsolete[] =
+  {
+    EL_PLAYER_OBSOLETE,
+    EL_KEY_OBSOLETE,
+    EL_EM_KEY_1_FILE_OBSOLETE,
+    EL_EM_KEY_2_FILE_OBSOLETE,
+    EL_EM_KEY_3_FILE_OBSOLETE,
+    EL_EM_KEY_4_FILE_OBSOLETE,
+    EL_ENVELOPE_OBSOLETE,
+
     -1
   };
 
@@ -3603,68 +3583,73 @@ void InitElementPropertiesStatic()
     int property;
   } element_properties[] =
   {
-    { ep_diggable,             EP_DIGGABLE             },
-    { ep_collectible_only,     EP_COLLECTIBLE_ONLY     },
-    { 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_explodes_by_fire,     EP_EXPLODES_BY_FIRE     },
-    { ep_explodes_smashed,     EP_EXPLODES_SMASHED     },
-    { ep_explodes_impact,      EP_EXPLODES_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_droppable,            EP_DROPPABLE            },
-    { ep_explodes_1x1_old,     EP_EXPLODES_1X1_OLD     },
-    { ep_pushable,             EP_PUSHABLE             },
-    { ep_explodes_cross_old,   EP_EXPLODES_CROSS_OLD   },
-    { ep_protected,            EP_PROTECTED            },
-    { ep_throwable,            EP_THROWABLE            },
-    { ep_can_explode,          EP_CAN_EXPLODE          },
-    { ep_gravity_reachable,    EP_GRAVITY_REACHABLE    },
-
-    { 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_can_turn_each_move,   EP_CAN_TURN_EACH_MOVE   },
-    { ep_can_grow,             EP_CAN_GROW             },
-    { ep_active_bomb,          EP_ACTIVE_BOMB          },
-    { ep_inactive,             EP_INACTIVE             },
-
-    { ep_em_slippery_wall,     EP_EM_SLIPPERY_WALL     },
-
-    { ep_gfx_crumbled,         EP_GFX_CRUMBLED         },
-
-    { NULL,                    -1                      }
+    { ep_diggable,                     EP_DIGGABLE                     },
+    { ep_collectible_only,             EP_COLLECTIBLE_ONLY             },
+    { 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_explodes_by_fire,             EP_EXPLODES_BY_FIRE             },
+    { ep_explodes_smashed,             EP_EXPLODES_SMASHED             },
+    { ep_explodes_impact,              EP_EXPLODES_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_droppable,                    EP_DROPPABLE                    },
+    { ep_explodes_1x1_old,             EP_EXPLODES_1X1_OLD             },
+    { ep_pushable,                     EP_PUSHABLE                     },
+    { ep_explodes_cross_old,           EP_EXPLODES_CROSS_OLD           },
+    { ep_protected,                    EP_PROTECTED                    },
+    { ep_throwable,                    EP_THROWABLE                    },
+    { ep_can_explode,                  EP_CAN_EXPLODE                  },
+    { ep_gravity_reachable,            EP_GRAVITY_REACHABLE            },
+
+    { 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_editor_content,           EP_HAS_EDITOR_CONTENT           },
+    { ep_can_turn_each_move,           EP_CAN_TURN_EACH_MOVE           },
+    { ep_can_grow,                     EP_CAN_GROW                     },
+    { ep_active_bomb,                  EP_ACTIVE_BOMB                  },
+    { ep_inactive,                     EP_INACTIVE                     },
+
+    { ep_em_slippery_wall,             EP_EM_SLIPPERY_WALL             },
+
+    { ep_gfx_crumbled,                 EP_GFX_CRUMBLED                 },
+
+    { ep_editor_cascade_active,                EP_EDITOR_CASCADE_ACTIVE        },
+    { ep_editor_cascade_inactive,      EP_EDITOR_CASCADE_INACTIVE      },
+
+    { ep_obsolete,                     EP_OBSOLETE                     },
+
+    { NULL,                            -1                              }
   };
 
   int i, j, k;
@@ -3690,38 +3675,6 @@ void InitElementPropertiesStatic()
 
 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_EXPLODES_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,
-  };
-#endif
-
   static int no_wall_properties[] =
   {
     EP_DIGGABLE,
@@ -3753,24 +3706,26 @@ void InitElementPropertiesEngine(int engine_version)
 
   int i, j;
 
-#if 0
-  InitElementPropertiesStatic();
-#endif
-
   /* important: after initialization in InitElementPropertiesStatic(), the
      elements are not again initialized to a default value; therefore all
      changes have to make sure that they leave the element with a defined
      property (which means that conditional property changes must be set to
      a reliable default value before) */
 
-  /* set all special, combined or engine dependent element properties */
+#if 1
+  /* ---------- recursively resolve group elements ------------------------- */
+
   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);
+    for (j = 0; j < NUM_GROUP_ELEMENTS; j++)
+      element_info[i].in_group[j] = FALSE;
+
+  for (i = 0; i < NUM_GROUP_ELEMENTS; i++)
+    resolve_group_element(EL_GROUP_START + i, 0);
 #endif
 
+  /* set all special, combined or engine dependent element properties */
+  for (i = 0; i < MAX_NUM_ELEMENTS; i++)
+  {
     /* ---------- INACTIVE ------------------------------------------------- */
     SET_PROPERTY(i, EP_INACTIVE, (i >= EL_CHAR_START && i <= EL_CHAR_END));
 
@@ -3825,12 +3780,6 @@ void InitElementPropertiesEngine(int engine_version)
                                             !IS_DIGGABLE(i) &&
                                             !IS_COLLECTIBLE(i)));
 
-#if 0
-    /* ---------- PROTECTED ------------------------------------------------ */
-    if (IS_ACCESSIBLE_INSIDE(i))
-      SET_PROPERTY(i, EP_PROTECTED, TRUE);
-#endif
-
     /* ---------- DRAGONFIRE_PROOF ----------------------------------------- */
 
     if (IS_HISTORIC_SOLID(i) || i == EL_EXPLOSION)
@@ -3845,20 +3794,9 @@ void InitElementPropertiesEngine(int engine_version)
     else if (engine_version < VERSION_IDENT(2,2,0,0))
       SET_PROPERTY(i, EP_EXPLOSION_PROOF, IS_INDESTRUCTIBLE(i));
     else
-#if 1
       SET_PROPERTY(i, EP_EXPLOSION_PROOF, (IS_INDESTRUCTIBLE(i) &&
                                           (!IS_WALKABLE(i) ||
                                            IS_PROTECTED(i))));
-#else
-#if 1
-      SET_PROPERTY(i, EP_EXPLOSION_PROOF, (IS_INDESTRUCTIBLE(i) &&
-                                          !IS_WALKABLE_OVER(i) &&
-                                          !IS_WALKABLE_UNDER(i)));
-#else
-      SET_PROPERTY(i, EP_EXPLOSION_PROOF, (IS_INDESTRUCTIBLE(i) &&
-                                          IS_PROTECTED(i)));
-#endif
-#endif
 
     if (IS_CUSTOM_ELEMENT(i))
     {
@@ -3882,25 +3820,6 @@ void InitElementPropertiesEngine(int engine_version)
                                   CAN_SMASH_ENEMIES(i) ||
                                   CAN_SMASH_EVERYTHING(i)));
 
-#if 0
-    /* ---------- CAN_EXPLODE ---------------------------------------------- */
-    SET_PROPERTY(i, EP_CAN_EXPLODE, (CAN_EXPLODE_BY_FIRE(i) ||
-                                    CAN_EXPLODE_SMASHED(i) ||
-                                    CAN_EXPLODE_IMPACT(i)));
-#endif
-
-#if 0
-    /* ---------- CAN_EXPLODE_3X3 ------------------------------------------ */
-#if 0
-    SET_PROPERTY(i, EP_CAN_EXPLODE_3X3, (!CAN_EXPLODE_1X1(i) &&
-                                        !CAN_EXPLODE_CROSS(i)));
-#else
-    SET_PROPERTY(i, EP_CAN_EXPLODE_3X3, (CAN_EXPLODE(i) &&
-                                        !CAN_EXPLODE_1X1(i) &&
-                                        !CAN_EXPLODE_CROSS(i)));
-#endif
-#endif
-
     /* ---------- CAN_EXPLODE_BY_FIRE -------------------------------------- */
     SET_PROPERTY(i, EP_CAN_EXPLODE_BY_FIRE, (CAN_EXPLODE(i) &&
                                             EXPLODES_BY_FIRE(i)));
@@ -3943,12 +3862,28 @@ void InitElementPropertiesEngine(int engine_version)
     SET_PROPERTY(i, EP_SP_PORT, (IS_SP_ELEMENT(i) &&
                                 IS_PASSABLE_INSIDE(i)));
 
+    /* ---------- CAN_BE_CLONED_BY_ANDROID --------------------------------- */
+    for (j = 0; j < level.num_android_clone_elements; j++)
+      SET_PROPERTY(i, EP_CAN_BE_CLONED_BY_ANDROID,
+                  (i != EL_EMPTY &&
+                   IS_EQUAL_OR_IN_GROUP(i, level.android_clone_element[j])));
+
     /* ---------- CAN_CHANGE ----------------------------------------------- */
     SET_PROPERTY(i, EP_CAN_CHANGE, FALSE);     /* default: cannot change */
     for (j = 0; j < element_info[i].num_change_pages; j++)
       if (element_info[i].change_page[j].can_change)
        SET_PROPERTY(i, EP_CAN_CHANGE, TRUE);
 
+    /* ---------- HAS_ACTION ----------------------------------------------- */
+    SET_PROPERTY(i, EP_HAS_ACTION, FALSE);     /* default: has no action */
+    for (j = 0; j < element_info[i].num_change_pages; j++)
+      if (element_info[i].change_page[j].has_action)
+       SET_PROPERTY(i, EP_HAS_ACTION, TRUE);
+
+    /* ---------- CAN_CHANGE_OR_HAS_ACTION --------------------------------- */
+    SET_PROPERTY(i, EP_CAN_CHANGE_OR_HAS_ACTION, (CAN_CHANGE(i) ||
+                                                 HAS_ACTION(i)));
+
     /* ---------- GFX_CRUMBLED --------------------------------------------- */
 #if 1
     SET_PROPERTY(i, EP_GFX_CRUMBLED,
@@ -3959,26 +3894,11 @@ void InitElementPropertiesEngine(int engine_version)
     SET_PROPERTY(i, EP_GFX_CRUMBLED,
                 element_info[i].crumbled[ACTION_DEFAULT] != IMG_EMPTY);
 #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
+    /* ---------- EDITOR_CASCADE ------------------------------------------- */
+    SET_PROPERTY(i, EP_EDITOR_CASCADE, (IS_EDITOR_CASCADE_ACTIVE(i) ||
+                                       IS_EDITOR_CASCADE_INACTIVE(i)));
   }
-#endif
 
   /* dynamically adjust element properties according to game engine version */
   {
@@ -4004,7 +3924,7 @@ void InitElementPropertiesEngine(int engine_version)
                  engine_version > VERSION_IDENT(2,0,1,0)));
   }
 
-#if 1
+#if 0
   /* set default push delay values (corrected since version 3.0.7-1) */
   if (engine_version < VERSION_IDENT(3,0,7,1))
   {
@@ -4016,7 +3936,9 @@ void InitElementPropertiesEngine(int engine_version)
     game.default_push_delay_fixed = 8;
     game.default_push_delay_random = 8;
   }
+#endif
 
+#if 0
   /* set uninitialized push delay values of custom elements in older levels */
   for (i = 0; i < NUM_CUSTOM_ELEMENTS; i++)
   {
@@ -4027,7 +3949,9 @@ void InitElementPropertiesEngine(int engine_version)
     if (element_info[element].push_delay_random == -1)
       element_info[element].push_delay_random = game.default_push_delay_random;
   }
+#endif
 
+#if 0
   /* set some other uninitialized values of custom elements in older levels */
   if (engine_version < VERSION_IDENT(3,1,0,0))
   {
@@ -4041,6 +3965,7 @@ void InitElementPropertiesEngine(int engine_version)
       element_info[element].ignition_delay = 8;
     }
   }
+#endif
 
 #if 0
   /* set element properties that were handled incorrectly in older levels */
@@ -4049,8 +3974,6 @@ void InitElementPropertiesEngine(int engine_version)
     SET_PROPERTY(EL_SP_SNIKSNAK, EP_DONT_COLLIDE_WITH, FALSE);
     SET_PROPERTY(EL_SP_ELECTRON, EP_DONT_COLLIDE_WITH, FALSE);
   }
-#endif
-
 #endif
 
   /* this is needed because some graphics depend on element properties */
@@ -4058,6 +3981,54 @@ void InitElementPropertiesEngine(int engine_version)
     InitElementGraphicInfo();
 }
 
+void InitElementPropertiesAfterLoading(int engine_version)
+{
+  int i;
+
+#if 0
+  /* set default push delay values (corrected since version 3.0.7-1) */
+  if (engine_version < VERSION_IDENT(3,0,7,1))
+  {
+    game.default_push_delay_fixed = 2;
+    game.default_push_delay_random = 8;
+  }
+  else
+  {
+    game.default_push_delay_fixed = 8;
+    game.default_push_delay_random = 8;
+  }
+#endif
+
+#if 0
+  /* set uninitialized push delay values of custom elements in older levels */
+  for (i = 0; i < NUM_CUSTOM_ELEMENTS; i++)
+  {
+    int element = EL_CUSTOM_START + i;
+
+    if (element_info[element].push_delay_fixed == -1)
+      element_info[element].push_delay_fixed = game.default_push_delay_fixed;
+    if (element_info[element].push_delay_random == -1)
+      element_info[element].push_delay_random = game.default_push_delay_random;
+  }
+#endif
+
+#if 1
+  /* set some other uninitialized values of custom elements in older levels */
+  if (engine_version < VERSION_IDENT(3,1,0,0))
+  {
+    for (i = 0; i < NUM_CUSTOM_ELEMENTS; i++)
+    {
+      int element = EL_CUSTOM_START + i;
+
+      element_info[element].access_direction = MV_ALL_DIRECTIONS;
+
+      element_info[element].explosion_delay = 17;
+      element_info[element].ignition_delay = 8;
+    }
+  }
+#endif
+}
+
 static void InitGlobal()
 {
   int i;
@@ -4085,7 +4056,7 @@ void Execute_Command(char *command)
 {
   int i;
 
-  if (strcmp(command, "print graphicsinfo.conf") == 0)
+  if (strEqual(command, "print graphicsinfo.conf"))
   {
     printf("# You can configure additional/alternative image files here.\n");
     printf("# (The entries below are default and therefore commented out.)\n");
@@ -4101,7 +4072,7 @@ void Execute_Command(char *command)
 
     exit(0);
   }
-  else if (strcmp(command, "print soundsinfo.conf") == 0)
+  else if (strEqual(command, "print soundsinfo.conf"))
   {
     printf("# You can configure additional/alternative sound files here.\n");
     printf("# (The entries below are default and therefore commented out.)\n");
@@ -4117,7 +4088,7 @@ void Execute_Command(char *command)
 
     exit(0);
   }
-  else if (strcmp(command, "print musicinfo.conf") == 0)
+  else if (strEqual(command, "print musicinfo.conf"))
   {
     printf("# You can configure additional/alternative music files here.\n");
     printf("# (The entries below are default and therefore commented out.)\n");
@@ -4133,17 +4104,21 @@ void Execute_Command(char *command)
 
     exit(0);
   }
-  else if (strcmp(command, "print editorsetup.conf") == 0)
+  else if (strEqual(command, "print editorsetup.conf"))
   {
     printf("# You can configure your personal editor element list here.\n");
     printf("# (The entries below are default and therefore commented out.)\n");
     printf("\n");
 
+    /* this is needed to be able to check element list for cascade elements */
+    InitElementPropertiesStatic();
+    InitElementPropertiesEngine(GAME_VERSION_ACTUAL);
+
     PrintEditorElementList();
 
     exit(0);
   }
-  else if (strcmp(command, "print helpanim.conf") == 0)
+  else if (strEqual(command, "print helpanim.conf"))
   {
     printf("# You can configure different element help animations here.\n");
     printf("# (The entries below are default and therefore commented out.)\n");
@@ -4154,13 +4129,13 @@ void Execute_Command(char *command)
       printf("# %s\n", getFormattedSetupEntry(helpanim_config[i].token,
                                              helpanim_config[i].value));
 
-      if (strcmp(helpanim_config[i].token, "end") == 0)
+      if (strEqual(helpanim_config[i].token, "end"))
        printf("#\n");
     }
 
     exit(0);
   }
-  else if (strcmp(command, "print helptext.conf") == 0)
+  else if (strEqual(command, "print helptext.conf"))
   {
     printf("# You can configure different element help text here.\n");
     printf("# (The entries below are default and therefore commented out.)\n");
@@ -4231,24 +4206,6 @@ void Execute_Command(char *command)
       while (*str_ptr != ' ' && *str_ptr != '\t' && *str_ptr != '\0')
        str_ptr++;
     }
-
-#if 0
-    printf("level set == '%s'\n", global.autoplay_leveldir);
-
-    if (global.autoplay_all)
-      printf("play all levels\n");
-    else
-    {
-      printf("play the following levels:");
-
-      for (i = 0; i < MAX_TAPES_PER_SET; i++)
-       if (global.autoplay_level[i])
-         printf(" %03d", i);
-
-      printf("\n");
-    }
-#endif
-
   }
   else if (strncmp(command, "convert ", 8) == 0)
   {
@@ -4280,6 +4237,11 @@ static void InitSetup()
     options.verbose = TRUE;
 }
 
+static void InitGameInfo()
+{
+  game.restart_level = FALSE;
+}
+
 static void InitPlayerInfo()
 {
   int i;
@@ -4347,7 +4309,7 @@ static void InitArtworkConfig()
   static char *sound_id_prefix[2 * MAX_NUM_ELEMENTS + 1];
   static char *music_id_prefix[NUM_MUSIC_PREFIXES + 1];
   static char *action_id_suffix[NUM_ACTIONS + 1];
-  static char *direction_id_suffix[NUM_DIRECTIONS + 1];
+  static char *direction_id_suffix[NUM_DIRECTIONS_FULL + 1];
   static char *special_id_suffix[NUM_SPECIAL_GFX_ARGS + 1];
   static char *level_id_suffix[MAX_LEVELS + 1];
   static char *dummy[1] = { NULL };
@@ -4415,15 +4377,15 @@ static void InitArtworkConfig()
 
   for (i = 0; i < NUM_MUSIC_PREFIXES; i++)
     music_id_prefix[i] = music_prefix_info[i].prefix;
-  music_id_prefix[MAX_LEVELS] = NULL;
+  music_id_prefix[NUM_MUSIC_PREFIXES] = 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++)
+  for (i = 0; i < NUM_DIRECTIONS_FULL; i++)
     direction_id_suffix[i] = element_direction_info[i].suffix;
-  direction_id_suffix[NUM_DIRECTIONS] = NULL;
+  direction_id_suffix[NUM_DIRECTIONS_FULL] = NULL;
 
   for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
     special_id_suffix[i] = special_suffix_info[i].suffix;
@@ -4467,18 +4429,18 @@ void InitGfx()
       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)
+      if (strEqual(image_config[i].token, font_token))
        filename_font_initial = image_config[i].value;
       else if (strlen(image_config[i].token) > len_font_token &&
               strncmp(image_config[i].token, font_token, len_font_token) == 0)
       {
-       if (strcmp(&image_config[i].token[len_font_token], ".x") == 0)
+       if (strEqual(&image_config[i].token[len_font_token], ".x"))
          font_initial[j].src_x = atoi(image_config[i].value);
-       else if (strcmp(&image_config[i].token[len_font_token], ".y") == 0)
+       else if (strEqual(&image_config[i].token[len_font_token], ".y"))
          font_initial[j].src_y = atoi(image_config[i].value);
-       else if (strcmp(&image_config[i].token[len_font_token], ".width") == 0)
+       else if (strEqual(&image_config[i].token[len_font_token], ".width"))
          font_initial[j].width = atoi(image_config[i].value);
-       else if (strcmp(&image_config[i].token[len_font_token],".height") == 0)
+       else if (strEqual(&image_config[i].token[len_font_token],".height"))
          font_initial[j].height = atoi(image_config[i].value);
       }
     }
@@ -4493,7 +4455,8 @@ void InitGfx()
   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 */
+  /* create additional image buffers for double-buffering and cross-fading */
+  bitmap_db_title = CreateBitmap(WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH);
   bitmap_db_field = CreateBitmap(FXSIZE, FYSIZE, DEFAULT_DEPTH);
   bitmap_db_door  = CreateBitmap(3 * DXSIZE, DYSIZE + VYSIZE, DEFAULT_DEPTH);
 
@@ -4516,8 +4479,14 @@ void InitGfx()
   DrawInitText(PROGRAM_COPYRIGHT_STRING, 50, FC_RED);
 
   DrawInitText("Loading graphics:", 120, FC_GREEN);
+}
+
+void RedrawBackground()
+{
+  BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, backbuffer,
+            0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
 
-  InitTileClipmasks();
+  redraw_mask = REDRAW_ALL;
 }
 
 void InitGfxBackground()
@@ -4528,8 +4497,8 @@ void InitGfxBackground()
   fieldbuffer = bitmap_db_field;
   SetDrawtoField(DRAW_BACKBUFFER);
 
-  BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, backbuffer,
-            0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
+  RedrawBackground();
+
   ClearRectangle(backbuffer, REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE);
   ClearRectangle(bitmap_db_door, 0, 0, 3 * DXSIZE, DYSIZE + VYSIZE);
 
@@ -4554,9 +4523,7 @@ void InitLevelArtworkInfo()
 
 static void InitImages()
 {
-#if 1
   setLevelArtworkDir(artwork.gfx_first);
-#endif
 
 #if 0
   printf("::: InitImages for '%s' ['%s', '%s'] ['%s', '%s']\n",
@@ -4580,10 +4547,8 @@ static void InitSound(char *identifier)
   if (identifier == NULL)
     identifier = artwork.snd_current->identifier;
 
-#if 1
   /* set artwork path to send it to the sound server process */
   setLevelArtworkDir(artwork.snd_first);
-#endif
 
   InitReloadCustomSounds(identifier);
   ReinitializeSounds();
@@ -4594,10 +4559,8 @@ static void InitMusic(char *identifier)
   if (identifier == NULL)
     identifier = artwork.mus_current->identifier;
 
-#if 1
   /* set artwork path to send it to the sound server process */
   setLevelArtworkDir(artwork.mus_first);
-#endif
 
   InitReloadCustomMusic(identifier);
   ReinitializeMusic();
@@ -4706,16 +4669,11 @@ static char *getNewArtworkIdentifier(int type)
 #endif
 
   /* ---------- reload if current artwork identifier has changed ----------- */
-  if (strcmp(ARTWORK_CURRENT_IDENTIFIER(artwork, type),
-            artwork_current_identifier) != 0)
+  if (!strEqual(ARTWORK_CURRENT_IDENTIFIER(artwork, type),
+               artwork_current_identifier))
     artwork_new_identifier = artwork_current_identifier;
 
-#if 1
   *(ARTWORK_CURRENT_IDENTIFIER_PTR(artwork, type))= artwork_current_identifier;
-#else
-  /* newer versions of gcc do not like this anymore :-/ */
-  *(&(ARTWORK_CURRENT_IDENTIFIER(artwork, type))) = artwork_current_identifier;
-#endif
 
 #if 0
   if (type == ARTWORK_TYPE_GRAPHICS)
@@ -4746,14 +4704,20 @@ static char *getNewArtworkIdentifier(int type)
 
 void ReloadCustomArtwork(int force_reload)
 {
-  char *gfx_new_identifier = getNewArtworkIdentifier(ARTWORK_TYPE_GRAPHICS);
-  char *snd_new_identifier = getNewArtworkIdentifier(ARTWORK_TYPE_SOUNDS);
-  char *mus_new_identifier = getNewArtworkIdentifier(ARTWORK_TYPE_MUSIC);
+  char *gfx_new_identifier;
+  char *snd_new_identifier;
+  char *mus_new_identifier;
   boolean force_reload_gfx = (force_reload & (1 << ARTWORK_TYPE_GRAPHICS));
   boolean force_reload_snd = (force_reload & (1 << ARTWORK_TYPE_SOUNDS));
   boolean force_reload_mus = (force_reload & (1 << ARTWORK_TYPE_MUSIC));
   boolean redraw_screen = FALSE;
 
+  force_reload_gfx |= AdjustGraphicsForEMC();
+
+  gfx_new_identifier = getNewArtworkIdentifier(ARTWORK_TYPE_GRAPHICS);
+  snd_new_identifier = getNewArtworkIdentifier(ARTWORK_TYPE_SOUNDS);
+  mus_new_identifier = getNewArtworkIdentifier(ARTWORK_TYPE_MUSIC);
+
   if (gfx_new_identifier != NULL || force_reload_gfx)
   {
 #if 0
@@ -4768,14 +4732,6 @@ void ReloadCustomArtwork(int force_reload)
 
     InitImages();
 
-#if 0
-    printf("... '%s'\n",
-          leveldir_current->graphics_set);
-#endif
-
-    FreeTileClipmasks();
-    InitTileClipmasks();
-
     redraw_screen = TRUE;
   }
 
@@ -4799,7 +4755,11 @@ void ReloadCustomArtwork(int force_reload)
 
   if (redraw_screen)
   {
+#if 1
+    RedrawBackground();
+#else
     InitGfxBackground();
+#endif
 
     /* force redraw of (open or closed) door graphics */
     SetDoorState(DOOR_OPEN_ALL);
@@ -4838,6 +4798,7 @@ void OpenAll()
 
   InitSetup();
 
+  InitGameInfo();
   InitPlayerInfo();
   InitArtworkInfo();           /* needed before loading gfx, sound & music */
   InitArtworkConfig();         /* needed before forking sound child process */
@@ -4904,7 +4865,6 @@ void CloseAllAndExit(int exit_value)
 #endif
 
   FreeAllImages();
-  FreeTileClipmasks();
 
 #if defined(TARGET_SDL)
   if (network_server)  /* terminate network server */
index 08f999e3e6df1a51179d58384a4d774e92a85e2e..1bfd49bc32333c93f3a03c082a6b963f433d70a9 100644 (file)
@@ -16,7 +16,6 @@
 
 #include "main.h"
 
-#if 1
 #define setMoveIntoAcidProperty(l, e, v)                       \
        (setBitfieldProperty(&(l)->can_move_into_acid_bits,     \
                             EP_CAN_MOVE_INTO_ACID, e, v))
 void setBitfieldProperty(int *, int, int, boolean);
 boolean getBitfieldProperty(int *, int, int);
 
-#else
-
-void setMoveIntoAcidProperty(struct LevelInfo *, int, boolean);
-boolean getMoveIntoAcidProperty(struct LevelInfo *, int);
-#endif
-
 void InitElementPropertiesStatic(void);
 void InitElementPropertiesEngine(int);
+void InitElementPropertiesAfterLoading(int);
 
 void ReloadCustomArtwork(int);
+void RedrawBackground();
 
 void KeyboardAutoRepeatOffUnlessAutoplay();
 
index 5ac104c8a254688839d0f1111ce3f17efa951fc0..ede8cfc7f54cad4888b0209ef96a99db72a93f24 100644 (file)
@@ -28,6 +28,7 @@
 
 static struct GadgetInfo *gadget_list_first_entry = NULL;
 static struct GadgetInfo *gadget_list_last_entry = NULL;
+static struct GadgetInfo *last_info_gi = NULL;
 static int next_free_gadget_id = 1;
 static boolean gadget_id_wrapped = FALSE;
 
@@ -64,21 +65,6 @@ static int getNewGadgetID()
   return id;
 }
 
-#if 0
-void DUMP_GADGET_MAP_STATE()
-{
-  struct GadgetInfo *gi = gadget_list_first_entry;
-
-  while (gi != NULL)
-  {
-    printf("-XXX-1-> '%s': %s\n",
-          gi->info_text, (gi->mapped ? "mapped" : "not mapped"));
-
-    gi = gi->next;
-  }
-}
-#endif
-
 static struct GadgetInfo *getGadgetInfoFromMousePosition(int mx, int my)
 {
   struct GadgetInfo *gi;
@@ -178,12 +164,16 @@ static void default_callback_action(void *ptr)
 
 static void DrawGadget(struct GadgetInfo *gi, boolean pressed, boolean direct)
 {
+  struct GadgetDesign *gd;
   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;
 
+  if (gi == NULL)
+    return;
+
+  gd = (!gi->active ? &gi->alt_design[state] :
+       gi->checked ? &gi->alt_design[state] : &gi->design[state]);
+
   switch (gi->type)
   {
     case GD_TYPE_NORMAL_BUTTON:
@@ -701,6 +691,9 @@ static void HandleGadgetTags(struct GadgetInfo *gi, int first_tag, va_list ap)
 {
   int tag = first_tag;
 
+  if (gi == NULL)
+    return;
+
   while (tag != GDI_END)
   {
     switch(tag)
@@ -1164,6 +1157,9 @@ void ModifyGadget(struct GadgetInfo *gi, int first_tag, ...)
 
 void RedrawGadget(struct GadgetInfo *gi)
 {
+  if (gi == NULL)
+    return;
+
   if (gi->mapped)
     DrawGadget(gi, gi->state, gi->direct_draw);
 }
@@ -1202,6 +1198,10 @@ void FreeGadget(struct GadgetInfo *gi)
 {
   struct GadgetInfo *gi_previous = gadget_list_first_entry;
 
+  /* prevent "last_info_gi" from pointing to memory that will be freed */
+  if (last_info_gi == gi)
+    last_info_gi = NULL;
+
   while (gi_previous != NULL && gi_previous->next != gi)
     gi_previous = gi_previous->next;
 
@@ -1381,11 +1381,11 @@ void ClickOnGadget(struct GadgetInfo *gi, int button)
 
 boolean HandleGadgets(int mx, int my, int button)
 {
-  static struct GadgetInfo *last_info_gi = NULL;
   static unsigned long pressed_delay = 0;
   static int last_button = 0;
   static int last_mx = 0, last_my = 0;
   static int pressed_mx = 0, pressed_my = 0;
+  static boolean keep_selectbox_open = FALSE;
   int scrollbar_mouse_pos = 0;
   struct GadgetInfo *new_gi, *gi;
   boolean press_event;
@@ -1452,14 +1452,9 @@ boolean HandleGadgets(int mx, int my, int button)
      insideSelectboxLine(new_gi, mx, my));
 
   /* if mouse button pressed outside text or selectbox gadget, deactivate it */
-#if 1
   if (anyTextGadgetActive() &&
       (gadget_pressed_off_borders ||
        (gadget_pressed_inside_select_line && !mouse_inside_select_area)))
-#else
-  if (anyTextGadgetActive() &&
-      button != 0 && !motion_status && new_gi != last_gi)
-#endif
   {
     struct GadgetInfo *gi = last_gi;
     boolean gadget_changed = (gi->event_mask & GD_EVENT_TEXT_LEAVING);
@@ -1469,7 +1464,7 @@ boolean HandleGadgets(int mx, int my, int button)
     {
       CheckRangeOfNumericInputGadget(gi);
 
-      if (strcmp(gi->textinput.value, gi->textinput.last_value) != 0)
+      if (!strEqual(gi->textinput.last_value, gi->textinput.value))
        strcpy(gi->textinput.last_value, gi->textinput.value);
       else
        gadget_changed = FALSE;
@@ -1483,13 +1478,8 @@ boolean HandleGadgets(int mx, int my, int button)
 
     gi->event.type = GD_EVENT_TEXT_LEAVING;
 
-#if 1
     if (gadget_changed && !(gi->type & GD_TYPE_SELECTBOX))
       gi->callback_action(gi);
-#else
-    if (gi->event_mask & GD_EVENT_TEXT_LEAVING)
-      gi->callback_action(gi);
-#endif
 
     last_gi = NULL;
 
@@ -1513,19 +1503,8 @@ boolean HandleGadgets(int mx, int my, int button)
   /* when handling selectbox, set additional state values */
   if (gadget_released_inside && (last_gi->type & GD_TYPE_SELECTBOX))
   {
-    struct GadgetInfo *gi = last_gi;
-
-#if 1
-    gadget_released_inside_select_line = insideSelectboxLine(gi, mx, my);
-    gadget_released_inside_select_area = insideSelectboxArea(gi, mx, my);
-#else
-    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);
-#endif
+    gadget_released_inside_select_line = insideSelectboxLine(last_gi, mx, my);
+    gadget_released_inside_select_area = insideSelectboxArea(last_gi, mx, my);
   }
   else
   {
@@ -1533,6 +1512,10 @@ boolean HandleGadgets(int mx, int my, int button)
     gadget_released_inside_select_area = FALSE;
   }
 
+  /* setting state for handling over-large selectbox */
+  if (keep_selectbox_open && (press_event || !mouse_inside_select_line))
+    keep_selectbox_open = FALSE;
+
   /* if new gadget pressed, store this gadget  */
   if (gadget_pressed)
     last_gi = new_gi;
@@ -1548,21 +1531,15 @@ boolean HandleGadgets(int mx, int my, int button)
   /* if mouse button released, no gadget needs to be handled anymore */
   if (gadget_released)
   {
-#if 1
     if (gi->type & GD_TYPE_SELECTBOX &&
-       (mouse_released_where_pressed ||
-       !gadget_released_inside_select_area))        /* selectbox stays open */
+       (keep_selectbox_open ||
+        mouse_released_where_pressed ||
+        !gadget_released_inside_select_area))       /* selectbox stays open */
     {
       gi->selectbox.stay_open = TRUE;
       pressed_mx = 0;
       pressed_my = 0;
     }
-#else
-    if (gi->type & GD_TYPE_SELECTBOX &&
-       (gadget_released_inside_select_line ||
-        gadget_released_off_borders))               /* selectbox stays open */
-      gi->selectbox.stay_open = TRUE;
-#endif
     else if (!(gi->type & GD_TYPE_TEXT_INPUT ||
               gi->type & GD_TYPE_TEXT_AREA))       /* text input stays open */
       last_gi = NULL;
@@ -1618,7 +1595,8 @@ boolean HandleGadgets(int mx, int my, int button)
       if (gi->textarea.cursor_position != old_cursor_position)
        DrawGadget(gi, DG_PRESSED, gi->direct_draw);
     }
-    else if (gi->type & GD_TYPE_SELECTBOX && gi->selectbox.open)
+    else if (gi->type & GD_TYPE_SELECTBOX && gi->selectbox.open &&
+            !keep_selectbox_open)
     {
       int old_index = gi->selectbox.current_index;
 
@@ -1742,6 +1720,12 @@ boolean HandleGadgets(int mx, int my, int button)
        return TRUE;
       }
     }
+    else if (gi->type & GD_TYPE_SELECTBOX)
+    {
+      /* keep selectbox open in case of over-large selectbox */
+      keep_selectbox_open = (mouse_inside_select_line &&
+                            mouse_inside_select_area);
+    }
 
     DrawGadget(gi, DG_PRESSED, gi->direct_draw);
 
@@ -1775,7 +1759,7 @@ boolean HandleGadgets(int mx, int my, int button)
       else if (gadget_moving_off_borders && gi->state == GD_BUTTON_PRESSED)
        DrawGadget(gi, DG_UNPRESSED, gi->direct_draw);
     }
-    else if (gi->type & GD_TYPE_SELECTBOX)
+    else if (gi->type & GD_TYPE_SELECTBOX && !keep_selectbox_open)
     {
       int old_index = gi->selectbox.current_index;
 
@@ -1847,21 +1831,13 @@ boolean HandleGadgets(int mx, int my, int button)
 
     if (gi->type & GD_TYPE_SELECTBOX)
     {
-#if 1
-      if (mouse_released_where_pressed ||
+      if (keep_selectbox_open ||
+         mouse_released_where_pressed ||
          !gadget_released_inside_select_area)       /* selectbox stays open */
       {
        deactivate_gadget = FALSE;
        gadget_changed = FALSE;
       }
-#else
-      if (gadget_released_inside_select_line ||
-         gadget_released_off_borders)               /* selectbox stays open */
-      {
-       deactivate_gadget = FALSE;
-       gadget_changed = FALSE;
-      }
-#endif
       else if (gi->selectbox.index != gi->selectbox.current_index)
        gi->selectbox.index = gi->selectbox.current_index;
       else
@@ -1876,15 +1852,10 @@ boolean HandleGadgets(int mx, int my, int button)
     gi->state = GD_BUTTON_UNPRESSED;
     gi->event.type = GD_EVENT_RELEASED;
 
-#if 1
     if ((gi->event_mask & GD_EVENT_RELEASED) && gadget_changed)
     {
       gi->callback_action(gi);
     }
-#else
-    if ((gi->event_mask & GD_EVENT_RELEASED) && deactivate_gadget)
-      gi->callback_action(gi);
-#endif
   }
 
   if (gadget_released_off_borders)
@@ -1940,7 +1911,7 @@ boolean HandleGadgetsKeyInput(Key key)
     {
       CheckRangeOfNumericInputGadget(gi);
 
-      if (strcmp(gi->textinput.value, gi->textinput.last_value) != 0)
+      if (!strEqual(gi->textinput.last_value, gi->textinput.value))
        strcpy(gi->textinput.last_value, gi->textinput.value);
       else
        gadget_changed = FALSE;
@@ -1968,13 +1939,8 @@ boolean HandleGadgetsKeyInput(Key key)
       last_gi = NULL;
     }
 
-#if 1
     if (gadget_changed)
       gi->callback_action(gi);
-#else
-    if (gi->event_mask & GD_EVENT_TEXT_RETURN)
-      gi->callback_action(gi);
-#endif
   }
   else if (gi->type & GD_TYPE_TEXT_INPUT)      /* only valid for text input */
   {
index 09ec64f6f869f423e7192d3c3ded3bce679cc6d6..cb8de4c87ed46ab8397a46f8f6a852843cb3344b 100644 (file)
@@ -31,13 +31,6 @@ Image *newImage(unsigned int width, unsigned int height, unsigned int depth)
   unsigned int bytes_per_pixel = (depth + 7) / 8;
   int i;
 
-#if 0
-  if (depth > 8)
-    Error(ERR_EXIT, "images with more than 256 colors are not supported");
-
-  depth = 8;
-#endif
-
   image = checked_calloc(sizeof(Image));
   image->data = checked_calloc(width * height * bytes_per_pixel);
   image->width = width;
@@ -836,7 +829,7 @@ static void *Load_PCX(char *filename)
   ImageInfo *img_info;
 
 #if 0
-  printf("loading PCX file '%s'\n", filename);
+  printf("::: loading PCX file '%s'\n", filename);
 #endif
 
   img_info = checked_calloc(sizeof(ImageInfo));
@@ -937,7 +930,7 @@ int getImageIDFromToken(char *token)
   int i;
 
   for (i = 0; i < num_list_entries; i++)
-    if (strcmp(file_list[i].token, token) == 0)
+    if (strEqual(file_list[i].token, token))
       return i;
 
   return -1;
@@ -1036,7 +1029,7 @@ void InitImageList(struct ConfigInfo *config_list, int num_file_list_entries,
 void ReloadCustomImages()
 {
 #if 0
-  printf("DEBUG: reloading images '%s' ...\n", artwork.gfx_current_identifier);
+  printf("::: reloading images '%s' ...\n", artwork.gfx_current_identifier);
 #endif
 
   LoadArtworkConfig(image_info);
@@ -1054,16 +1047,19 @@ void CreateImageWithSmallImages(int pos, int zoom_factor)
 
   img_info->contains_small_images = TRUE;
   img_info->scaled_up = TRUE;
+}
 
-#if 0
-  if (zoom_factor)
-    printf("CreateImageWithSmallImages: '%s' zoomed by factor %d\n",
-          img_info->source_filename, zoom_factor);
-#endif
+void ScaleImage(int pos, int zoom_factor)
+{
+  ImageInfo *img_info = getImageInfoEntryFromImageID(pos);
 
-#if 0
-  printf("CreateImageWithSmallImages: '%s' done\n", img_info->source_filename);
-#endif
+  if (img_info == NULL || img_info->scaled_up)
+    return;
+
+  if (zoom_factor != 1)
+    ScaleBitmap(img_info->bitmap, zoom_factor);
+
+  img_info->scaled_up = TRUE;
 }
 
 void FreeAllImages()
index 3a2ac2023158aed2ddfb9f60c51d3bc9a87ce232..3791c4bc8578be5944fee672044813d45eaeca5d 100644 (file)
@@ -91,6 +91,7 @@ void InitImageList(struct ConfigInfo *, int, struct ConfigTypeInfo *,
 
 void ReloadCustomImages();
 void CreateImageWithSmallImages(int, int);
+void ScaleImage(int, int);
 
 void FreeAllImages();
 
index c2d0c192cc0d6323458f7d698eb0d4bfcf0f4f1c..8cf04cf69be4fe6d0c8dd7f57d0461389b8f765d 100644 (file)
@@ -148,7 +148,7 @@ void translate_joyname(int *joysymbol, char **name, int mode)
 
     for (i = 0; i < 6; i++)
     {
-      if (strcmp(*name, translate_joy[i].name) == 0)
+      if (strEqual(*name, translate_joy[i].name))
       {
        *joysymbol = translate_joy[i].joysymbol;
        break;
index 3881d202338a5d3ab1971a35cf080fab644b2241..c04c256dd4989c54d363fb06fb958e90732f581b 100644 (file)
@@ -52,6 +52,12 @@ void printf_line(char *line_string, int line_length)
   fprintf_line(stdout, line_string, line_length);
 }
 
+void printf_line_with_prefix(char *prefix, char *line_string, int line_length)
+{
+  fprintf(stdout, "%s", prefix);
+  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,
@@ -206,14 +212,6 @@ static void sleep_milliseconds(unsigned long milliseconds_delay)
 {
   boolean do_busy_waiting = (milliseconds_delay < 5 ? TRUE : FALSE);
 
-#if 0
-#if defined(PLATFORM_MSDOS)
-  /* don't use select() to perform waiting operations under DOS
-     environment; always use a busy loop for waiting instead */
-  do_busy_waiting = TRUE;
-#endif
-#endif
-
   if (do_busy_waiting)
   {
     /* we want to wait only a few ms -- if we assume that we have a
@@ -567,6 +565,14 @@ void setString(char **old_value, char *new_value)
   *old_value = getStringCopy(new_value);
 }
 
+boolean strEqual(char *s1, char *s2)
+{
+  return (s1 == NULL && s2 == NULL ? TRUE  :
+         s1 == NULL && s2 != NULL ? FALSE :
+         s1 != NULL && s2 == NULL ? FALSE :
+         strcmp(s1, s2) == 0);
+}
+
 
 /* ------------------------------------------------------------------------- */
 /* command line option handling functions                                    */
@@ -585,9 +591,9 @@ void GetOptions(char *argv[], void (*print_usage_function)(void))
      in an application package directory -- do not try to use this directory
      as the program data directory (Mac OS X handles this correctly anyway) */
 
-  if (strcmp(ro_base_path, ".") == 0)
+  if (strEqual(ro_base_path, "."))
     ro_base_path = program.command_basepath;
-  if (strcmp(rw_base_path, ".") == 0)
+  if (strEqual(rw_base_path, "."))
     rw_base_path = program.command_basepath;
 #endif
 
@@ -627,7 +633,7 @@ void GetOptions(char *argv[], void (*print_usage_function)(void))
     strcpy(option_str, option);                        /* copy argument into buffer */
     option = option_str;
 
-    if (strcmp(option, "--") == 0)             /* stop scanning arguments */
+    if (strEqual(option, "--"))                        /* stop scanning arguments */
       break;
 
     if (strncmp(option, "--", 2) == 0)         /* treat '--' like '-' */
@@ -645,7 +651,7 @@ void GetOptions(char *argv[], void (*print_usage_function)(void))
 
     option_len = strlen(option);
 
-    if (strcmp(option, "-") == 0)
+    if (strEqual(option, "-"))
       Error(ERR_EXIT_HELP, "unrecognized option '%s'", option);
     else if (strncmp(option, "-help", option_len) == 0)
     {
@@ -741,10 +747,8 @@ void GetOptions(char *argv[], void (*print_usage_function)(void))
       if (option_arg == next_option)
        options_left++;
 
-#if 1
       /* when doing batch processing, always enable verbose mode (warnings) */
       options.verbose = TRUE;
-#endif
     }
     else if (*option == '-')
     {
@@ -935,6 +939,25 @@ inline void swap_number_pairs(int *x1, int *y1, int *x2, int *y2)
   *y2 = help_y;
 }
 
+/* the "put" variants of the following file access functions check for the file
+   pointer being != NULL and return the number of bytes they have or would have
+   written; this allows for chunk writing functions to first determine the size
+   of the (not yet written) chunk, write the correct chunk size and finally
+   write the chunk itself */
+
+int getFile8BitInteger(FILE *file)
+{
+  return fgetc(file);
+}
+
+int putFile8BitInteger(FILE *file, int value)
+{
+  if (file != NULL)
+    fputc(value, file);
+
+  return 1;
+}
+
 int getFile16BitInteger(FILE *file, int byte_order)
 {
   if (byte_order == BYTE_ORDER_BIG_ENDIAN)
@@ -945,18 +968,23 @@ int getFile16BitInteger(FILE *file, int byte_order)
            (fgetc(file) << 8));
 }
 
-void putFile16BitInteger(FILE *file, int value, int byte_order)
+int putFile16BitInteger(FILE *file, int value, int byte_order)
 {
-  if (byte_order == BYTE_ORDER_BIG_ENDIAN)
-  {
-    fputc((value >> 8) & 0xff, file);
-    fputc((value >> 0) & 0xff, file);
-  }
-  else          /* BYTE_ORDER_LITTLE_ENDIAN */
+  if (file != NULL)
   {
-    fputc((value >> 0) & 0xff, file);
-    fputc((value >> 8) & 0xff, file);
+    if (byte_order == BYTE_ORDER_BIG_ENDIAN)
+    {
+      fputc((value >> 8) & 0xff, file);
+      fputc((value >> 0) & 0xff, file);
+    }
+    else          /* BYTE_ORDER_LITTLE_ENDIAN */
+    {
+      fputc((value >> 0) & 0xff, file);
+      fputc((value >> 8) & 0xff, file);
+    }
   }
+
+  return 2;
 }
 
 int getFile32BitInteger(FILE *file, int byte_order)
@@ -973,22 +1001,27 @@ int getFile32BitInteger(FILE *file, int byte_order)
            (fgetc(file) << 24));
 }
 
-void putFile32BitInteger(FILE *file, int value, int byte_order)
+int putFile32BitInteger(FILE *file, int value, int byte_order)
 {
-  if (byte_order == BYTE_ORDER_BIG_ENDIAN)
-  {
-    fputc((value >> 24) & 0xff, file);
-    fputc((value >> 16) & 0xff, file);
-    fputc((value >>  8) & 0xff, file);
-    fputc((value >>  0) & 0xff, file);
-  }
-  else          /* BYTE_ORDER_LITTLE_ENDIAN */
+  if (file != NULL)
   {
-    fputc((value >>  0) & 0xff, file);
-    fputc((value >>  8) & 0xff, file);
-    fputc((value >> 16) & 0xff, file);
-    fputc((value >> 24) & 0xff, file);
+    if (byte_order == BYTE_ORDER_BIG_ENDIAN)
+    {
+      fputc((value >> 24) & 0xff, file);
+      fputc((value >> 16) & 0xff, file);
+      fputc((value >>  8) & 0xff, file);
+      fputc((value >>  0) & 0xff, file);
+    }
+    else          /* BYTE_ORDER_LITTLE_ENDIAN */
+    {
+      fputc((value >>  0) & 0xff, file);
+      fputc((value >>  8) & 0xff, file);
+      fputc((value >> 16) & 0xff, file);
+      fputc((value >> 24) & 0xff, file);
+    }
   }
+
+  return 4;
 }
 
 boolean getFileChunk(FILE *file, char *chunk_name, int *chunk_size,
@@ -1008,17 +1041,27 @@ boolean getFileChunk(FILE *file, char *chunk_name, int *chunk_size,
   return (feof(file) || ferror(file) ? FALSE : TRUE);
 }
 
-void putFileChunk(FILE *file, char *chunk_name, int chunk_size,
-                 int byte_order)
+int putFileChunk(FILE *file, char *chunk_name, int chunk_size,
+                int byte_order)
 {
+  int num_bytes = 0;
+
   /* write chunk name */
-  fputs(chunk_name, file);
+  if (file != NULL)
+    fputs(chunk_name, file);
+
+  num_bytes += strlen(chunk_name);
 
   if (chunk_size >= 0)
   {
     /* write chunk size */
-    putFile32BitInteger(file, chunk_size, byte_order);
+    if (file != NULL)
+      putFile32BitInteger(file, chunk_size, byte_order);
+
+    num_bytes += 4;
   }
+
+  return num_bytes;
 }
 
 int getFileVersion(FILE *file)
@@ -1032,17 +1075,38 @@ int getFileVersion(FILE *file)
                       version_build);
 }
 
-void putFileVersion(FILE *file, int version)
+int putFileVersion(FILE *file, int version)
+{
+  if (file != NULL)
+  {
+    int version_major = VERSION_MAJOR(version);
+    int version_minor = VERSION_MINOR(version);
+    int version_patch = VERSION_PATCH(version);
+    int version_build = VERSION_BUILD(version);
+
+    fputc(version_major, file);
+    fputc(version_minor, file);
+    fputc(version_patch, file);
+    fputc(version_build, file);
+  }
+
+  return 4;
+}
+
+void ReadBytesFromFile(FILE *file, byte *buffer, unsigned long bytes)
+{
+  int i;
+
+  for(i = 0; i < bytes && !feof(file); i++)
+    buffer[i] = fgetc(file);
+}
+
+void WriteBytesToFile(FILE *file, byte *buffer, unsigned long bytes)
 {
-  int version_major = VERSION_MAJOR(version);
-  int version_minor = VERSION_MINOR(version);
-  int version_patch = VERSION_PATCH(version);
-  int version_build = VERSION_BUILD(version);
+  int i;
 
-  fputc(version_major, file);
-  fputc(version_minor, file);
-  fputc(version_patch, file);
-  fputc(version_build, file);
+  for(i = 0; i < bytes; i++)
+    fputc(buffer[i], file);
 }
 
 void ReadUnusedBytesFromFile(FILE *file, unsigned long bytes)
@@ -1152,16 +1216,16 @@ void translate_keyname(Key *keysym, char **x11name, char **name, int mode)
 
     /* more ASCII keys */
     { KSYM_bracketleft,        "XK_bracketleft",       "[" },
-    { KSYM_backslash,  "XK_backslash",         "backslash" },
+    { KSYM_backslash,  "XK_backslash",         "\\" },
     { KSYM_bracketright,"XK_bracketright",     "]" },
-    { KSYM_asciicircum,        "XK_asciicircum",       "circumflex" },
+    { KSYM_asciicircum,        "XK_asciicircum",       "^" },
     { KSYM_underscore, "XK_underscore",        "_" },
     { KSYM_grave,      "XK_grave",             "grave" },
     { KSYM_quoteleft,  "XK_quoteleft",         "quote left" },
     { KSYM_braceleft,  "XK_braceleft",         "brace left" },
     { KSYM_bar,                "XK_bar",               "bar" },
     { KSYM_braceright, "XK_braceright",        "brace right" },
-    { KSYM_asciitilde, "XK_asciitilde",        "ascii tilde" },
+    { KSYM_asciitilde, "XK_asciitilde",        "~" },
 
     /* special (non-ASCII) keys */
     { KSYM_Adiaeresis, "XK_Adiaeresis",        "Ä" },
@@ -1191,8 +1255,13 @@ void translate_keyname(Key *keysym, char **x11name, char **name, int mode)
       sprintf(name_buffer, "%c", '0' + (char)(key - KSYM_0));
     else if (key >= KSYM_KP_0 && key <= KSYM_KP_9)
       sprintf(name_buffer, "keypad %c", '0' + (char)(key - KSYM_KP_0));
+#if 1
+    else if (key >= KSYM_FKEY_FIRST && key <= KSYM_FKEY_LAST)
+      sprintf(name_buffer, "F%d", (int)(key - KSYM_FKEY_FIRST + 1));
+#else
     else if (key >= KSYM_FKEY_FIRST && key <= KSYM_FKEY_LAST)
       sprintf(name_buffer, "function F%d", (int)(key - KSYM_FKEY_FIRST + 1));
+#endif
     else if (key == KSYM_UNDEFINED)
       strcpy(name_buffer, "(undefined)");
     else
@@ -1259,7 +1328,7 @@ void translate_keyname(Key *keysym, char **x11name, char **name, int mode)
     i = 0;
     do
     {
-      if (strcmp(translate_key[i].name, *name) == 0)
+      if (strEqual(translate_key[i].name, *name))
       {
        key = translate_key[i].key;
        break;
@@ -1314,7 +1383,7 @@ void translate_keyname(Key *keysym, char **x11name, char **name, int mode)
 
       do
       {
-       if (strcmp(name_ptr, translate_key[i].x11name) == 0)
+       if (strEqual(name_ptr, translate_key[i].x11name))
        {
          key = translate_key[i].key;
          break;
@@ -1396,9 +1465,9 @@ char getCharFromKey(Key key)
 
   if (strlen(keyname) == 1)
     letter = keyname[0];
-  else if (strcmp(keyname, "space") == 0)
+  else if (strEqual(keyname, "space"))
     letter = ' ';
-  else if (strcmp(keyname, "circumflex") == 0)
+  else if (strEqual(keyname, "circumflex"))
     letter = '^';
 
   return letter;
@@ -1436,14 +1505,14 @@ int get_integer_from_string(char *s)
 
   for (i = 0; number_text[i][0] != NULL; i++)
     for (j = 0; j < 3; j++)
-      if (strcmp(s_lower, number_text[i][j]) == 0)
+      if (strEqual(s_lower, number_text[i][j]))
        result = i;
 
   if (result == -1)
   {
-    if (strcmp(s_lower, "false") == 0)
+    if (strEqual(s_lower, "false"))
       result = 0;
-    else if (strcmp(s_lower, "true") == 0)
+    else if (strEqual(s_lower, "true"))
       result = 1;
     else
       result = atoi(s);
@@ -1459,9 +1528,9 @@ boolean get_boolean_from_string(char *s)
   char *s_lower = getStringToLower(s);
   boolean result = FALSE;
 
-  if (strcmp(s_lower, "true") == 0 ||
-      strcmp(s_lower, "yes") == 0 ||
-      strcmp(s_lower, "on") == 0 ||
+  if (strEqual(s_lower, "true") ||
+      strEqual(s_lower, "yes") ||
+      strEqual(s_lower, "on") ||
       get_integer_from_string(s) == 1)
     result = TRUE;
 
@@ -1484,10 +1553,6 @@ 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;
@@ -1500,17 +1565,8 @@ void deleteNodeFromList(ListNode **node_first, char *key,
   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 (strEqual((*node_first)->key, key))
   {
-#if 0
-    printf("[DELETING LIST ENTRY]\n");
-#endif
-
     free((*node_first)->key);
     if (destructor_function)
       destructor_function((*node_first)->content);
@@ -1525,7 +1581,7 @@ ListNode *getNodeFromKey(ListNode *node_first, char *key)
   if (node_first == NULL)
     return NULL;
 
-  if (strcmp(node_first->key, key) == 0)
+  if (strEqual(node_first->key, key))
     return node_first;
   else
     return getNodeFromKey(node_first->next, key);
@@ -1560,10 +1616,6 @@ boolean fileExists(char *filename)
   if (filename == NULL)
     return FALSE;
 
-#if 0
-  printf("checking file '%s'\n", filename);
-#endif
-
   return (access(filename, F_OK) == 0);
 }
 
@@ -1605,7 +1657,7 @@ boolean fileHasSuffix(char *basename, char *suffix)
 
   if (basename_length > suffix_length + 1 &&
       basename_lower[basename_length - suffix_length - 1] == '.' &&
-      strcmp(&basename_lower[basename_length - suffix_length], suffix) == 0)
+      strEqual(&basename_lower[basename_length - suffix_length], suffix))
     return TRUE;
 
   return FALSE;
@@ -1720,36 +1772,45 @@ static boolean string_has_parameter(char *s, char *s_contained)
   return string_has_parameter(substring, s_contained);
 }
 
-int get_parameter_value(char *suffix, char *value_raw, int type)
+int get_parameter_value(char *value_raw, char *suffix, int type)
 {
   char *value = getStringToLower(value_raw);
   int result = 0;      /* probably a save default value */
 
-  if (strcmp(suffix, ".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(suffix, ".anim_mode") == 0)
-  {
-    result = (string_has_parameter(value, "none")       ? ANIM_NONE :
-             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, "horizontal") ? ANIM_HORIZONTAL :
-             string_has_parameter(value, "vertical")   ? ANIM_VERTICAL :
+  if (strEqual(suffix, ".direction"))
+  {
+    result = (strEqual(value, "left")  ? MV_LEFT :
+             strEqual(value, "right") ? MV_RIGHT :
+             strEqual(value, "up")    ? MV_UP :
+             strEqual(value, "down")  ? MV_DOWN : MV_NONE);
+  }
+  else if (strEqual(suffix, ".anim_mode"))
+  {
+    result = (string_has_parameter(value, "none")      ? ANIM_NONE :
+             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, "ce_value")   ? ANIM_CE_VALUE :
+             string_has_parameter(value, "ce_score")   ? ANIM_CE_SCORE :
+             string_has_parameter(value, "ce_delay")   ? ANIM_CE_DELAY :
+             string_has_parameter(value, "horizontal") ? ANIM_HORIZONTAL :
+             string_has_parameter(value, "vertical")   ? ANIM_VERTICAL :
              ANIM_DEFAULT);
 
     if (string_has_parameter(value, "reverse"))
       result |= ANIM_REVERSE;
+
+    if (string_has_parameter(value, "opaque_player"))
+      result |= ANIM_OPAQUE_PLAYER;
+
+    if (string_has_parameter(value, "static_panel"))
+      result |= ANIM_STATIC_PANEL;
   }
   else         /* generic parameter of type integer or boolean */
   {
-    result = (strcmp(value, ARG_UNDEFINED) == 0 ? ARG_UNDEFINED_VALUE :
+    result = (strEqual(value, ARG_UNDEFINED) ? ARG_UNDEFINED_VALUE :
              type == TYPE_INTEGER ? get_integer_from_string(value) :
              type == TYPE_BOOLEAN ? get_boolean_from_string(value) :
              ARG_UNDEFINED_VALUE);
@@ -1771,7 +1832,7 @@ int get_auto_parameter_value(char *token, char *value_raw)
   if (suffix == NULL)
     suffix = token;
 
-  return get_parameter_value(suffix, value_raw, TYPE_INTEGER);
+  return get_parameter_value(value_raw, suffix, TYPE_INTEGER);
 }
 
 static void FreeCustomArtworkList(struct ArtworkListInfo *,
@@ -1831,8 +1892,8 @@ struct FileInfo *getFileListFromConfigList(struct ConfigInfo *config_list,
       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)
+         strEqual(&config_list[i].token[len_config_token - len_suffix],
+                  suffix_list[j].token))
       {
        setString(&file_list[list_pos].default_parameter[j],
                  config_list[i].value);
@@ -1844,7 +1905,7 @@ struct FileInfo *getFileListFromConfigList(struct ConfigInfo *config_list,
 
     /* 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)
+      if (strEqual(config_list[i].token, ignore_tokens[j]))
        is_file_entry = FALSE;
 
     if (is_file_entry)
@@ -1856,9 +1917,9 @@ struct FileInfo *getFileListFromConfigList(struct ConfigInfo *config_list,
        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)
+      if (!strEqual(&config_list[i].value[len_config_value - 4], ".pcx") &&
+         !strEqual(&config_list[i].value[len_config_value - 4], ".wav") &&
+         !strEqual(config_list[i].value, UNDEFINED_FILENAME))
       {
        Error(ERR_RETURN, "Configuration directive '%s' -> '%s':",
              config_list[i].token, config_list[i].value);
@@ -1890,11 +1951,6 @@ 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;
 
@@ -1937,16 +1993,6 @@ static void read_token_parameters(SetupFileHash *setup_file_hash,
     /* 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++)
@@ -1976,11 +2022,6 @@ static void add_dynamic_file_list_entry(struct FileInfo **list,
   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];
@@ -2043,7 +2084,7 @@ static void LoadArtworkConfigFromFilename(struct ArtworkListInfo *artwork_info,
     return;
 
 #if 0
-  printf("::: LoadArtworkConfigFromFilename: '%s'\n", filename);
+  printf("LoadArtworkConfigFromFilename '%s' ...\n", filename);
 #endif
 
   if ((setup_file_hash = loadSetupFileHash(filename)) == NULL)
@@ -2064,7 +2105,6 @@ static void LoadArtworkConfigFromFilename(struct ArtworkListInfo *artwork_info,
   /* at this point, we do not need the setup file hash anymore -- free it */
   freeSetupFileHash(setup_file_hash);
 
-#if 1
   /* map deprecated to current tokens (using prefix match and replace) */
   BEGIN_HASH_ITERATION(valid_file_hash, itr)
   {
@@ -2085,7 +2125,6 @@ static void LoadArtworkConfigFromFilename(struct ArtworkListInfo *artwork_info,
     }
   }
   END_HASH_ITERATION(valid_file_hash, itr)
-#endif
 
   /* read parameters for all known config file tokens */
   for (i = 0; i < num_file_list_entries; i++)
@@ -2101,7 +2140,7 @@ static void LoadArtworkConfigFromFilename(struct ArtworkListInfo *artwork_info,
   {
     char *value = HASH_ITERATION_VALUE(itr);
 
-    if (strcmp(value, known_token_value) != 0)
+    if (!strEqual(value, known_token_value))
       setHashEntry(extra_file_hash, HASH_ITERATION_TOKEN(itr), value);
   }
   END_HASH_ITERATION(valid_file_hash, itr)
@@ -2143,16 +2182,6 @@ static void LoadArtworkConfigFromFilename(struct ArtworkListInfo *artwork_info,
        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;
 
@@ -2340,7 +2369,7 @@ static void LoadArtworkConfigFromFilename(struct ArtworkListInfo *artwork_info,
 
     BEGIN_HASH_ITERATION(extra_file_hash, itr)
     {
-      if (strcmp(HASH_ITERATION_VALUE(itr), known_token_value) == 0)
+      if (strEqual(HASH_ITERATION_VALUE(itr), known_token_value))
        dynamic_tokens_found = TRUE;
       else
        unknown_tokens_found = TRUE;
@@ -2357,7 +2386,7 @@ static void LoadArtworkConfigFromFilename(struct ArtworkListInfo *artwork_info,
       {
        char *value = getHashEntry(extra_file_hash, list->token);
 
-       if (value != NULL && strcmp(value, known_token_value) == 0)
+       if (value != NULL && strEqual(value, known_token_value))
          Error(ERR_RETURN, "- dynamic token: '%s'", list->token);
       }
 
@@ -2374,7 +2403,7 @@ static void LoadArtworkConfigFromFilename(struct ArtworkListInfo *artwork_info,
       {
        char *value = getHashEntry(extra_file_hash, list->token);
 
-       if (value != NULL && strcmp(value, known_token_value) != 0)
+       if (value != NULL && !strEqual(value, known_token_value))
          Error(ERR_RETURN, "- dynamic token: '%s'", list->token);
       }
 
@@ -2424,10 +2453,6 @@ void LoadArtworkConfig(struct ArtworkListInfo *artwork_info)
   char *filename_base = UNDEFINED_FILENAME, *filename_local;
   int i, j;
 
-#if 0
-  printf("GOT CUSTOM ARTWORK CONFIG FILE '%s'\n", filename);
-#endif
-
   DrawInitText("Loading artwork config:", 120, FC_GREEN);
   DrawInitText(ARTWORKINFO_FILENAME(artwork_info->type), 150, FC_YELLOW);
 
@@ -2480,7 +2505,7 @@ void LoadArtworkConfig(struct ArtworkListInfo *artwork_info)
 
   filename_local = getCustomArtworkConfigFilename(artwork_info->type);
 
-  if (filename_local != NULL && strcmp(filename_base, filename_local) != 0)
+  if (filename_local != NULL && !strEqual(filename_base, filename_local))
     LoadArtworkConfigFromFilename(artwork_info, filename_local);
 }
 
@@ -2491,25 +2516,14 @@ static void deleteArtworkListEntry(struct ArtworkListInfo *artwork_info,
   {
     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;
   }
 }
 
-#if 1
 static void replaceArtworkListEntry(struct ArtworkListInfo *artwork_info,
                                    struct ListNodeInfo **listnode,
                                    struct FileInfo *file_list_entry)
@@ -2525,12 +2539,6 @@ static void replaceArtworkListEntry(struct ArtworkListInfo *artwork_info,
   char *basename = file_list_entry->filename;
   char *filename = getCustomArtworkFilename(basename, artwork_info->type);
 
-#if 0
-  if (strcmp(file_list_entry->token, "background.DOOR") == 0)
-    printf("::: replaceArtworkListEntry: '%s' => '%s'\n",
-          basename, filename);
-#endif
-
   if (filename == NULL)
   {
     Error(ERR_WARN, "cannot find artwork file '%s'", basename);
@@ -2538,7 +2546,7 @@ static void replaceArtworkListEntry(struct ArtworkListInfo *artwork_info,
     basename = file_list_entry->default_filename;
 
     /* dynamic artwork has no default filename / skip empty default artwork */
-    if (basename == NULL || strcmp(basename, UNDEFINED_FILENAME) == 0)
+    if (basename == NULL || strEqual(basename, UNDEFINED_FILENAME))
       return;
 
     file_list_entry->fallback_to_default = TRUE;
@@ -2562,7 +2570,7 @@ static void replaceArtworkListEntry(struct ArtworkListInfo *artwork_info,
   }
 
   /* check if the old and the new artwork file are the same */
-  if (*listnode && strcmp((*listnode)->source_filename, filename) == 0)
+  if (*listnode && strEqual((*listnode)->source_filename, filename))
   {
     /* 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
@@ -2591,15 +2599,6 @@ static void replaceArtworkListEntry(struct ArtworkListInfo *artwork_info,
       return;
   }
 
-#if 0
-  if (strcmp(file_list_entry->token, "background.DOOR") == 0)
-    printf("::: replaceArtworkListEntry: LOAD IT'\n");
-#endif
-
-#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);
 
@@ -2617,114 +2616,15 @@ static void replaceArtworkListEntry(struct ArtworkListInfo *artwork_info,
   {
     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;
   }
 }
 
-#else
-
-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
-    /* !!! NEW ARTWORK FALLBACK CODE !!! NEARLY UNTESTED !!! */
-    /* before failing, try fallback to default artwork */
-#else
-    /* 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;
-  }
-}
-#endif
-
-#if 1
 static void LoadCustomArtwork(struct ArtworkListInfo *artwork_info,
                              struct ListNodeInfo **listnode,
                              struct FileInfo *file_list_entry)
@@ -2733,13 +2633,7 @@ static void LoadCustomArtwork(struct ArtworkListInfo *artwork_info,
   printf("GOT CUSTOM ARTWORK FILE '%s'\n", filename);
 #endif
 
-#if 0
-  if (strcmp(file_list_entry->token, "background.DOOR") == 0)
-    printf("::: -> '%s' -> '%s'\n",
-          file_list_entry->token, file_list_entry->filename);
-#endif
-
-  if (strcmp(file_list_entry->filename, UNDEFINED_FILENAME) == 0)
+  if (strEqual(file_list_entry->filename, UNDEFINED_FILENAME))
   {
     deleteArtworkListEntry(artwork_info, listnode);
     return;
@@ -2748,86 +2642,6 @@ static void LoadCustomArtwork(struct ArtworkListInfo *artwork_info,
   replaceArtworkListEntry(artwork_info, listnode, file_list_entry);
 }
 
-#else
-
-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);
-}
-#endif
-
-#if 1
-static void LoadArtworkToList(struct ArtworkListInfo *artwork_info,
-                             struct ListNodeInfo **listnode,
-                             struct FileInfo *file_list_entry)
-{
-#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",
-        file_list_entry->filename, getNumNodes(artwork_info->content_list));
-#endif
-
-#if 1
-  LoadCustomArtwork(artwork_info, listnode, file_list_entry);
-#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
-}
-
-#else
-
-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
-}
-#endif
-
 void ReloadCustomArtworkList(struct ArtworkListInfo *artwork_info)
 {
   struct FileInfo *file_list = artwork_info->file_list;
@@ -2837,86 +2651,13 @@ void ReloadCustomArtworkList(struct ArtworkListInfo *artwork_info)
     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.DOOR") == 0)
-      printf("::: '%s' -> '%s'\n", file_list[i].token, file_list[i].filename);
-#endif
-
-#if 1
-    LoadArtworkToList(artwork_info, &artwork_info->artwork_list[i],
+    LoadCustomArtwork(artwork_info, &artwork_info->artwork_list[i],
                      &file_list[i]);
-#else
-    LoadArtworkToList(artwork_info, &artwork_info->artwork_list[i],
-                     file_list[i].filename, i);
-#endif
-
-#if 0
-    if (strcmp(file_list[i].token, "background.DOOR") == 0)
-    {
-      Bitmap *bitmap = getBitmapFromImageID(i);
-
-      printf("::: BITMAP: %08lx\n", bitmap);
-
-#if 0
-      BlitBitmap(bitmap, window, 0, 0, 100, 280, 0, 0);
-#endif
-    }
-#endif
-
-#if 0
-    /* !!! NEW ARTWORK FALLBACK CODE !!! NEARLY UNTESTED !!! */
-    if (artwork_info->artwork_list[i] == NULL &&
-       strcmp(file_list[i].filename, UNDEFINED_FILENAME) != 0 &&
-       strcmp(file_list[i].default_filename, file_list[i].filename) != 0 &&
-       strcmp(file_list[i].default_filename, UNDEFINED_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);
-
-      /* even the fallback to default artwork was not successful -- fail now */
-      if (artwork_info->artwork_list[i] == NULL &&
-         artwork_info->type == ARTWORK_TYPE_GRAPHICS)
-       Error(ERR_EXIT, "cannot find artwork file '%s' or default file '%s'",
-             file_list[i].filename, file_list[i].default_filename);
-
-      file_list[i].fallback_to_default = TRUE;
-    }
-#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++)
-  {
-#if 1
-    LoadArtworkToList(artwork_info, &artwork_info->dynamic_artwork_list[i],
+    LoadCustomArtwork(artwork_info, &artwork_info->dynamic_artwork_list[i],
                      &dynamic_file_list[i]);
-#else
-    LoadArtworkToList(artwork_info, &artwork_info->dynamic_artwork_list[i],
-                     dynamic_file_list[i].filename, i);
-#endif
-
-#if 0
-    printf("::: '%s', '0x%08x'\n",
-          dynamic_file_list[i].filename,
-          dynamic_file_list[i].default_filename);
-#endif
-
-    /* dynamic artwork does not have default filename! */
-  }
 
 #if 0
   dumpList(artwork_info->content_list);
@@ -2945,21 +2686,11 @@ 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
 }
 
 
index b89be4e87d6382ef19d4305f876d28364a97692f..fa4c1e97ed51996709cac6b4aababc1245b00ab1 100644 (file)
@@ -69,6 +69,7 @@
 
 void fprintf_line(FILE *, char *, int);
 void printf_line(char *, int);
+void printf_line_with_prefix(char *, char *, int);
 char *int2str(int, int);
 char *i_to_a(unsigned int);
 int log_2(unsigned int);
@@ -103,6 +104,7 @@ char *getStringCat2(char *, char *);
 char *getStringCopy(char *);
 char *getStringToLower(char *);
 void setString(char **, char *);
+boolean strEqual(char *, char *);
 
 void GetOptions(char **, void (*print_usage_function)(void));
 
@@ -115,22 +117,29 @@ void *checked_calloc(unsigned long);
 void *checked_realloc(void *, unsigned long);
 void checked_free(void *);
 
-inline void swap_numbers(int *, int *);
-inline void swap_number_pairs(int *, int *, int *, int *);
+void swap_numbers(int *, int *);
+void swap_number_pairs(int *, int *, int *, int *);
 
+int getFile8BitInteger(FILE *);
+int putFile8BitInteger(FILE *, int);
 int getFile16BitInteger(FILE *, int);
-void putFile16BitInteger(FILE *, int, int);
+int putFile16BitInteger(FILE *, int, int);
 int getFile32BitInteger(FILE *, int);
-void putFile32BitInteger(FILE *, int, int);
+int putFile32BitInteger(FILE *, int, int);
+
 boolean getFileChunk(FILE *, char *, int *, int);
-void putFileChunk(FILE *, char *, int, int);
+int putFileChunk(FILE *, char *, int, int);
 int getFileVersion(FILE *);
-void putFileVersion(FILE *, int);
+int putFileVersion(FILE *, int);
+
+void ReadBytesFromFile(FILE *, byte *, unsigned long);
+void WriteBytesToFile(FILE *, byte *, unsigned long);
+
 void ReadUnusedBytesFromFile(FILE *, unsigned long);
 void WriteUnusedBytesToFile(FILE *, unsigned long);
 
-#define getFile8Bit(f)        fgetc(f)
-#define putFile8Bit(f,x)      fputc(x, f)
+#define getFile8Bit(f)        getFile8BitInteger(f)
+#define putFile8Bit(f,x)      putFile8BitInteger(f,x)
 #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)
@@ -139,6 +148,7 @@ void WriteUnusedBytesToFile(FILE *, unsigned long);
 #define getFile32BitLE(f)     getFile32BitInteger(f,BYTE_ORDER_LITTLE_ENDIAN)
 #define putFile32BitBE(f,x)   putFile32BitInteger(f,x,BYTE_ORDER_BIG_ENDIAN)
 #define putFile32BitLE(f,x)   putFile32BitInteger(f,x,BYTE_ORDER_LITTLE_ENDIAN)
+
 #define getFileChunkBE(f,s,x) getFileChunk(f,s,x,BYTE_ORDER_BIG_ENDIAN)
 #define getFileChunkLE(f,s,x) getFileChunk(f,s,x,BYTE_ORDER_LITTLE_ENDIAN)
 #define putFileChunkBE(f,s,x) putFileChunk(f,s,x,BYTE_ORDER_BIG_ENDIAN)
index e976420e06f0931e9ee23c0df69753d1fbe36de6..8307a054dd0e57b523eff5a8927d17c3ee6d269a 100644 (file)
@@ -722,8 +722,8 @@ void XFillRectangle(Display *, Drawable, GC, int, int,
 Pixmap XCreatePixmap(Display *, Drawable, unsigned int, unsigned int,
                     unsigned int);
 void XSync(Display *, Bool);
-inline void XCopyArea(Display *, Drawable, Drawable, GC, int, int,
-                     unsigned int, unsigned int, int, int);
+void XCopyArea(Display *, Drawable, Drawable, GC, int, int,
+              unsigned int, unsigned int, int, int);
 int Read_PCX_to_Pixmap(Display *, Window, GC, char *, Pixmap *, Pixmap *);
 int XReadBitmapFile(Display *, Drawable, char *,
                    unsigned int *, unsigned int *, Pixmap *, int *, int *);
index 5fdf6f3ecb56d7a53e3272c8b6d88e7df2a604fa..8bf4d6c1424a2ca62fc61a8ccbfe68ef6ade2111 100644 (file)
@@ -53,52 +53,6 @@ struct PCX_Header
 /* global PCX error value */
 int errno_pcx = PCX_Success;
 
-#if 0
-static byte *PCX_ReadBitmap(Image *image, byte *buffer_ptr, byte *buffer_last)
-{
-  /* Run Length Encoding: If the two high bits are set,
-   * then the low 6 bits contain a repeat count, and the byte to
-   * repeat is the next byte in the file.  If the two high bits are
-   * not set, then this is the byte to write.
-   */
-
-  unsigned int bytes_per_pixel = (image->depth + 7) / 8;
-  register byte *bitmap_ptr, *bitmap_last;
-  register byte value, count;
-
-  bitmap_ptr = image->data;
-  bitmap_last = bitmap_ptr + (image->width * image->height * bytes_per_pixel);
-
-  while (bitmap_ptr < bitmap_last && buffer_ptr < buffer_last)
-  {
-    value = *buffer_ptr++;
-
-    if ((value & 0xc0) == 0xc0)                /* this is a repeat count byte */
-    {
-      count = value & 0x3f;            /* extract repeat count from byte */
-      value = *buffer_ptr++;           /* next byte is value to repeat */
-
-      for (; count && bitmap_ptr < bitmap_last; count--)
-       *bitmap_ptr++ = value;
-
-      if (count)                       /* repeat count spans end of bitmap */
-       return NULL;
-    }
-    else
-      *bitmap_ptr++ = value;
-
-    image->rgb.color_used[value] = TRUE;
-  }
-
-  /* check if end of buffer was reached before end of bitmap */
-  if (bitmap_ptr < bitmap_last)
-    return NULL;
-
-  /* return current buffer position for next decoding function */
-  return buffer_ptr;
-}
-#endif
-
 static boolean PCX_ReadBitmap(FILE *file, struct PCX_Header *pcx, Image *image)
 {
   int width = image->width;
@@ -203,35 +157,6 @@ static boolean PCX_ReadBitmap(FILE *file, struct PCX_Header *pcx, Image *image)
   return TRUE;
 }
 
-#if 0
-static byte *PCX_ReadColormap(Image *image,byte *buffer_ptr, byte *buffer_last)
-{
-  int i, magic;
-
-  /* read colormap magic byte */
-  magic = *buffer_ptr++;
-
-  /* check magic colormap header byte */
-  if (magic != PCX_256COLORS_MAGIC)
-    return NULL;
-
-  /* check if enough bytes left for a complete colormap */
-  if (buffer_ptr + PCX_COLORMAP_SIZE > buffer_last)
-    return NULL;
-
-  /* read 256 colors from PCX colormap */
-  for (i = 0; i < PCX_MAXCOLORS; i++)
-  {
-    image->rgb.red[i]   = *buffer_ptr++ << 8;
-    image->rgb.green[i] = *buffer_ptr++ << 8;
-    image->rgb.blue[i]  = *buffer_ptr++ << 8;
-  }
-
-  /* return current buffer position for next decoding function */
-  return buffer_ptr;
-}
-#endif
-
 static boolean PCX_ReadColormap(FILE *file,struct PCX_Header *pcx,Image *image)
 {
   int pcx_depth = pcx->bits_per_pixel * pcx->color_planes;
index b127c7844055152de46fc5f8474abd93c5be1237..df3a0e349dddbd31c74a9ad5f0f9424c1f50e099 100644 (file)
@@ -24,7 +24,7 @@
 /* ========================================================================= */
 
 /* functions from SGE library */
-inline void sge_Line(SDL_Surface *, Sint16, Sint16, Sint16, Sint16, Uint32);
+void sge_Line(SDL_Surface *, Sint16, Sint16, Sint16, Sint16, Uint32);
 
 /* #ifdef PLATFORM_WIN32 */
 #define FULLSCREEN_BUG
@@ -38,7 +38,7 @@ static int fullscreen_yoffset;
 static int video_xoffset;
 static int video_yoffset;
 
-inline void SDLInitVideoDisplay(void)
+void SDLInitVideoDisplay(void)
 {
   putenv("SDL_VIDEO_CENTERED=1");
 
@@ -50,8 +50,8 @@ inline void SDLInitVideoDisplay(void)
   video.default_depth = SDL_GetVideoInfo()->vfmt->BitsPerPixel;
 }
 
-inline void SDLInitVideoBuffer(DrawBuffer **backbuffer, DrawWindow **window,
-                              boolean fullscreen)
+void SDLInitVideoBuffer(DrawBuffer **backbuffer, DrawWindow **window,
+                       boolean fullscreen)
 {
 #ifdef FULLSCREEN_BUG
   int i;
@@ -109,7 +109,7 @@ inline void SDLInitVideoBuffer(DrawBuffer **backbuffer, DrawWindow **window,
   *window = CreateBitmap(video.width, video.height, video.depth);
 }
 
-inline boolean SDLSetVideoMode(DrawBuffer **backbuffer, boolean fullscreen)
+boolean SDLSetVideoMode(DrawBuffer **backbuffer, boolean fullscreen)
 {
   boolean success = TRUE;
   int surface_flags_fullscreen = SURFACE_FLAGS | SDL_FULLSCREEN;
@@ -172,8 +172,8 @@ inline boolean SDLSetVideoMode(DrawBuffer **backbuffer, boolean fullscreen)
   return success;
 }
 
-inline void SDLCreateBitmapContent(Bitmap *new_bitmap,
-                                  int width, int height, int depth)
+void SDLCreateBitmapContent(Bitmap *new_bitmap, int width, int height,
+                           int depth)
 {
   SDL_Surface *surface_tmp, *surface_native;
 
@@ -190,7 +190,7 @@ inline void SDLCreateBitmapContent(Bitmap *new_bitmap,
   new_bitmap->surface = surface_native;
 }
 
-inline void SDLFreeBitmapPointers(Bitmap *bitmap)
+void SDLFreeBitmapPointers(Bitmap *bitmap)
 {
   if (bitmap->surface)
     SDL_FreeSurface(bitmap->surface);
@@ -200,10 +200,9 @@ inline void SDLFreeBitmapPointers(Bitmap *bitmap)
   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 mask_mode)
+void SDLCopyArea(Bitmap *src_bitmap, Bitmap *dst_bitmap,
+                int src_x, int src_y, int width, int height,
+                int dst_x, int dst_y, int mask_mode)
 {
   Bitmap *real_dst_bitmap = (dst_bitmap == window ? backbuffer : dst_bitmap);
   SDL_Rect src_rect, dst_rect;
@@ -243,16 +242,11 @@ inline void SDLCopyArea(Bitmap *src_bitmap, Bitmap *dst_bitmap,
     SDL_UpdateRect(backbuffer->surface, dst_x, dst_y, width, height);
 }
 
-inline void SDLFillRectangle(Bitmap *dst_bitmap, int x, int y,
-                            int width, int height, Uint32 color)
+void SDLFillRectangle(Bitmap *dst_bitmap, int x, int y,
+                     int width, int height, Uint32 color)
 {
   Bitmap *real_dst_bitmap = (dst_bitmap == window ? backbuffer : dst_bitmap);
   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
 
 #ifdef FULLSCREEN_BUG
   if (dst_bitmap == backbuffer || dst_bitmap == window)
@@ -267,29 +261,145 @@ 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, Uint32 color)
+void SDLFadeScreen(Bitmap *bitmap_cross, int fade_mode, int fade_delay,
+                  int post_delay)
 {
-  SDL_Surface *surface = dst_bitmap->surface;
-  SDL_Rect rect;
+  static boolean initialization_needed = TRUE;
+  static SDL_Surface *surface_screen_copy = NULL;
+  static SDL_Surface *surface_black = NULL;
+  SDL_Surface *surface_screen = backbuffer->surface;
+  SDL_Surface *surface_cross;          /* initialized later */
+  SDL_Rect src_rect, dst_rect;
+  int src_x = 0, src_y = 0;
+  int dst_x = 0, dst_y = 0;
+  boolean fade_reverse = (fade_mode == FADE_MODE_FADE_IN ? TRUE : FALSE);
+  unsigned int time_last, time_current;
+  float alpha;
+  int alpha_final;
+
+  src_rect.x = src_x;
+  src_rect.y = src_y;
+  src_rect.w = video.width;
+  src_rect.h = video.height;
+
+#ifdef FULLSCREEN_BUG
+  dst_x += video_xoffset;
+  dst_y += video_yoffset;
+#endif
+
+  dst_rect.x = dst_x;
+  dst_rect.y = dst_y;
+  dst_rect.w = video.width;
+  dst_rect.h = video.height;
+
 #if 0
-  unsigned int color_r = (color >> 16) & 0xff;
-  unsigned int color_g = (color >>  8) & 0xff;
-  unsigned int color_b = (color >>  0) & 0xff;
+  if (!initialization_needed)
+  {
+    /* check if screen size has changed (can happen when toggling fullscreen) */
+    if (surface_screen_copy->w != surface_screen->w ||
+       surface_screen_copy->h != surface_screen->h)
+    {
+      SDL_FreeSurface(surface_screen_copy);
+      SDL_FreeSurface(surface_black);
+
+      initialization_needed = TRUE;
+    }
+  }
 #endif
 
+  if (initialization_needed)
+  {
+    unsigned int flags = SDL_SRCALPHA;
+
+    /* use same surface type as screen surface */
+    if ((surface_screen->flags & SDL_HWSURFACE))
+      flags |= SDL_HWSURFACE;
+    else
+      flags |= SDL_SWSURFACE;
+
+    /* create surface for temporary copy of screen buffer */
+    if ((surface_screen_copy =
+        SDL_CreateRGBSurface(flags,
+#if 1
+                             video.width,
+                             video.height,
+#else
+                             surface_screen->w,
+                             surface_screen->h,
+#endif
+                             surface_screen->format->BitsPerPixel,
+                             surface_screen->format->Rmask,
+                             surface_screen->format->Gmask,
+                             surface_screen->format->Bmask,
+                             surface_screen->format->Amask)) == NULL)
+      Error(ERR_EXIT, "SDL_CreateRGBSurface(   ) failed: %s", SDL_GetError());
+
+    /* create black surface for fading from/to black */
+    if ((surface_black =
+        SDL_CreateRGBSurface(flags,
+#if 1
+                             video.width,
+                             video.height,
+#else
+                             surface_screen->w,
+                             surface_screen->h,
+#endif
+                             surface_screen->format->BitsPerPixel,
+                             surface_screen->format->Rmask,
+                             surface_screen->format->Gmask,
+                             surface_screen->format->Bmask,
+                             surface_screen->format->Amask)) == NULL)
+      Error(ERR_EXIT, "SDL_CreateRGBSurface(   ) failed: %s", SDL_GetError());
+
+    /* completely fill the surface with black color pixels */
+    SDL_FillRect(surface_black, NULL,
+                SDL_MapRGB(surface_screen->format, 0, 0, 0));
+
+    initialization_needed = FALSE;
+  }
+
+  /* copy the current screen backbuffer to the temporary screen copy buffer */
+  SDL_BlitSurface(surface_screen, &dst_rect, surface_screen_copy, &src_rect);
+
+  surface_cross = (fade_mode == FADE_MODE_CROSSFADE ? bitmap_cross->surface :
+                  surface_black);
+
+  time_current = SDL_GetTicks();
+
+  for (alpha = 0.0; alpha < 255.0;)
+  {
+    time_last = time_current;
+    time_current = SDL_GetTicks();
+    alpha += 255 * ((float)(time_current - time_last) / fade_delay);
+    alpha_final = (int)(fade_reverse ? 255.0 - alpha : alpha);
+    alpha_final = MIN(MAX(0, alpha_final), 255);
+
+    /* draw existing image to screen buffer */
+    SDL_BlitSurface(surface_screen_copy, &src_rect, surface_screen, &dst_rect);
+
+    /* draw new image to screen buffer using alpha blending */
+    SDL_SetAlpha(surface_cross, SDL_SRCALPHA, alpha_final);
+    SDL_BlitSurface(surface_cross, &src_rect, surface_screen, &dst_rect);
+
+    /* draw screen buffer to visible display */
+    SDL_Flip(surface_screen);
+  }
+
+  Delay(post_delay);
+}
+
+void SDLDrawSimpleLine(Bitmap *dst_bitmap, int from_x, int from_y,
+                      int to_x, int to_y, Uint32 color)
+{
+  SDL_Surface *surface = dst_bitmap->surface;
+  SDL_Rect rect;
+
   if (from_x > to_x)
     swap_numbers(&from_x, &to_x);
 
@@ -309,16 +419,11 @@ 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,
-                       int to_x, int to_y, Uint32 color)
+void SDLDrawLine(Bitmap *dst_bitmap, int from_x, int from_y,
+                int to_x, int to_y, Uint32 color)
 {
 #ifdef FULLSCREEN_BUG
   if (dst_bitmap == backbuffer || dst_bitmap == window)
@@ -334,8 +439,8 @@ inline void SDLDrawLine(Bitmap *dst_bitmap, int from_x, int from_y,
 }
 
 #if 0
-inline void SDLDrawLines(SDL_Surface *surface, struct XY *points,
-                        int num_points, Uint32 color)
+void SDLDrawLines(SDL_Surface *surface, struct XY *points,
+                 int num_points, Uint32 color)
 {
   int i, x, y;
   int line_width = 4;
@@ -363,7 +468,7 @@ inline void SDLDrawLines(SDL_Surface *surface, struct XY *points,
 }
 #endif
 
-inline Pixel SDLGetPixel(Bitmap *src_bitmap, int x, int y)
+Pixel SDLGetPixel(Bitmap *src_bitmap, int x, int y)
 {
   SDL_Surface *surface = src_bitmap->surface;
 
@@ -864,7 +969,7 @@ 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)
+void SDLPutPixel(Bitmap *dst_bitmap, int x, int y, Pixel pixel)
 {
 #ifdef FULLSCREEN_BUG
   if (dst_bitmap == backbuffer || dst_bitmap == window)
@@ -884,8 +989,8 @@ inline void SDLPutPixel(Bitmap *dst_bitmap, int x, int y, Pixel pixel)
   -----------------------------------------------------------------------------
 */
 
-inline void SDLInvertArea(Bitmap *bitmap, int src_x, int src_y,
-                         int width, int height, Uint32 color)
+void SDLInvertArea(Bitmap *bitmap, int src_x, int src_y,
+                  int width, int height, Uint32 color)
 {
   int x, y;
 
@@ -900,9 +1005,9 @@ inline void SDLInvertArea(Bitmap *bitmap, int src_x, int src_y,
   }
 }
 
-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)
+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;
 
@@ -1303,9 +1408,9 @@ void SDLSetMouseCursor(struct MouseCursorInfo *cursor_info)
 /* audio functions                                                           */
 /* ========================================================================= */
 
-inline void SDLOpenAudio(void)
+void SDLOpenAudio(void)
 {
-  if (strcmp(setup.system.sdl_audiodriver, ARG_DEFAULT) != 0)
+  if (!strEqual(setup.system.sdl_audiodriver, ARG_DEFAULT))
     putenv(getStringCat2("SDL_AUDIODRIVER=", setup.system.sdl_audiodriver));
 
   if (SDL_InitSubSystem(SDL_INIT_AUDIO) < 0)
@@ -1335,7 +1440,7 @@ inline void SDLOpenAudio(void)
   Mixer_InitChannels();
 }
 
-inline void SDLCloseAudio(void)
+void SDLCloseAudio(void)
 {
   Mix_HaltMusic();
   Mix_HaltChannel(-1);
@@ -1349,7 +1454,7 @@ inline void SDLCloseAudio(void)
 /* event functions                                                           */
 /* ========================================================================= */
 
-inline void SDLNextEvent(Event *event)
+void SDLNextEvent(Event *event)
 {
   SDL_WaitEvent(event);
 
@@ -1456,6 +1561,7 @@ void SDLInitJoysticks()
 
   for (i = 0; i < MAX_PLAYERS; i++)
   {
+    /* get configured joystick for this player */
     char *device_name = setup.input[i].joy.device_name;
     int joystick_nr = getJoystickNrFromDeviceName(device_name);
 
index fc05cb7063ad22ebbe4d8c88c66ab51b8a7d62d9..f817e3294b34cc403d9ea2b78fb0cf2a03093c38 100644 (file)
 #ifndef SDL_H
 #define SDL_H
 
-#include "SDL.h"
-#include "SDL_image.h"
-#include "SDL_mixer.h"
-#include "SDL_net.h"
-#include "SDL_thread.h"
+#include <SDL.h>
+#include <SDL_image.h>
+#include <SDL_mixer.h>
+#include <SDL_net.h>
+#include <SDL_thread.h>
 
 
 /* definitions needed for "system.c" */
@@ -352,21 +352,21 @@ struct XY
 
 /* 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, 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 SDLInitVideoDisplay(void);
+void SDLInitVideoBuffer(DrawBuffer **, DrawWindow **, boolean);
+boolean SDLSetVideoMode(DrawBuffer **, boolean);
+void SDLCreateBitmapContent(Bitmap *, int, int, int);
+void SDLFreeBitmapPointers(Bitmap *);
+void SDLCopyArea(Bitmap *, Bitmap *, int, int, int, int, int, int, int);
+void SDLFillRectangle(Bitmap *, int, int, int, int, Uint32);
+void SDLFadeScreen(Bitmap *, int, int, int);
+void SDLDrawSimpleLine(Bitmap *, int, int, int, int, Uint32);
+void SDLDrawLine(Bitmap *, int, int, int, int, Uint32);
+Pixel SDLGetPixel(Bitmap *, int, int);
+void SDLPutPixel(Bitmap *, int, int, Pixel);
+
+void SDLInvertArea(Bitmap *, int, int, int, int, Uint32);
+void SDLCopyInverseMasked(Bitmap *, Bitmap *, int, int, int, int, int, int);
 
 void SDLZoomBitmap(Bitmap *, Bitmap *);
 
@@ -374,10 +374,10 @@ Bitmap *SDLLoadImage(char *);
 
 void SDLSetMouseCursor(struct MouseCursorInfo *);
 
-inline void SDLOpenAudio(void);
-inline void SDLCloseAudio(void);
+void SDLOpenAudio(void);
+void SDLCloseAudio(void);
 
-inline void SDLNextEvent(Event *);
+void SDLNextEvent(Event *);
 
 void HandleJoystickEvent(Event *);
 void SDLInitJoysticks(void);
index 3b9438e6031316e9fec7ebb2fd295c038b5f05e9..a004bc82fda34659823eb1b50811b43d578098a4 100644 (file)
@@ -799,7 +799,7 @@ void InitLevelSetupDirectory(char *level_subdir)
 
 
 /* ------------------------------------------------------------------------- */
-/* some functions to handle lists of level directories                       */
+/* some functions to handle lists of level and artwork directories           */
 /* ------------------------------------------------------------------------- */
 
 TreeInfo *newTreeInfo()
@@ -917,7 +917,7 @@ TreeInfo *getTreeInfoFromIdentifier(TreeInfo *node, char *identifier)
     }
     else if (!node->parent_link)
     {
-      if (strcmp(identifier, node->identifier) == 0)
+      if (strEqual(identifier, node->identifier))
        return node;
     }
 
@@ -927,6 +927,71 @@ TreeInfo *getTreeInfoFromIdentifier(TreeInfo *node, char *identifier)
   return NULL;
 }
 
+TreeInfo *cloneTreeNode(TreeInfo **node_top, TreeInfo *node_parent,
+                       TreeInfo *node, boolean skip_sets_without_levels)
+{
+  TreeInfo *node_new;
+
+  if (node == NULL)
+    return NULL;
+
+  if (!node->parent_link && !node->level_group &&
+      skip_sets_without_levels && node->levels == 0)
+    return cloneTreeNode(node_top, node_parent, node->next,
+                        skip_sets_without_levels);
+
+  node_new = newTreeInfo();
+
+  *node_new = *node;                           /* copy complete node */
+
+  node_new->node_top = node_top;               /* correct top node link */
+  node_new->node_parent = node_parent;         /* correct parent node link */
+
+  if (node->level_group)
+    node_new->node_group = cloneTreeNode(node_top, node_new, node->node_group,
+                                        skip_sets_without_levels);
+
+  node_new->next = cloneTreeNode(node_top, node_parent, node->next,
+                                skip_sets_without_levels);
+  
+  return node_new;
+}
+
+void cloneTree(TreeInfo **ti_new, TreeInfo *ti, boolean skip_empty_sets)
+{
+  TreeInfo *ti_cloned = cloneTreeNode(ti_new, NULL, ti, skip_empty_sets);
+
+  *ti_new = ti_cloned;
+}
+
+static boolean adjustTreeGraphicsForEMC(TreeInfo *node)
+{
+  boolean settings_changed = FALSE;
+
+  while (node)
+  {
+    if (node->graphics_set_ecs && !setup.prefer_aga_graphics &&
+       !strEqual(node->graphics_set, node->graphics_set_ecs))
+    {
+      setString(&node->graphics_set, node->graphics_set_ecs);
+      settings_changed = TRUE;
+    }
+    else if (node->graphics_set_aga && setup.prefer_aga_graphics &&
+            !strEqual(node->graphics_set, node->graphics_set_aga))
+    {
+      setString(&node->graphics_set, node->graphics_set_aga);
+      settings_changed = TRUE;
+    }
+
+    if (node->node_group != NULL)
+      settings_changed |= adjustTreeGraphicsForEMC(node->node_group);
+
+    node = node->next;
+  }
+
+  return settings_changed;
+}
+
 void dumpTreeInfo(TreeInfo *node, int depth)
 {
   int i;
@@ -938,13 +1003,8 @@ void dumpTreeInfo(TreeInfo *node, int depth)
     for (i = 0; i < (depth + 1) * 3; i++)
       printf(" ");
 
-#if 1
     printf("subdir == '%s' ['%s', '%s'] [%d])\n",
           node->subdir, node->fullpath, node->basepath, node->in_user_dir);
-#else
-    printf("subdir == '%s' (%s) [%s] (%d)\n",
-          node->subdir, node->name, node->identifier, node->sort_priority);
-#endif
 
     if (node->node_group != NULL)
       dumpTreeInfo(node->node_group, depth + 1);
@@ -1068,7 +1128,7 @@ char *getCommonDataDir(void)
     char *dir = checked_malloc(MAX_PATH + 1);
 
     if (SUCCEEDED(SHGetFolderPath(NULL, CSIDL_COMMON_DOCUMENTS, NULL, 0, dir))
-       && strcmp(dir, "") != 0)        /* empty for Windows 95/98 */
+       && !strEqual(dir, ""))          /* empty for Windows 95/98 */
       common_data_dir = getPath2(dir, program.userdata_directory);
     else
       common_data_dir = options.rw_base_directory;
@@ -1249,7 +1309,7 @@ char *getListEntry(SetupFileList *list, char *token)
   if (list == NULL)
     return NULL;
 
-  if (strcmp(list->token, token) == 0)
+  if (strEqual(list->token, token))
     return list->value;
   else
     return getListEntry(list->next, token);
@@ -1260,7 +1320,7 @@ SetupFileList *setListEntry(SetupFileList *list, char *token, char *value)
   if (list == NULL)
     return NULL;
 
-  if (strcmp(list->token, token) == 0)
+  if (strEqual(list->token, token))
   {
     checked_free(list->value);
 
@@ -1342,7 +1402,7 @@ static unsigned int get_hash_from_key(void *key)
 
 static int keys_are_equal(void *key1, void *key2)
 {
-  return (strcmp((char *)key1, (char *)key2) == 0);
+  return (strEqual((char *)key1, (char *)key2));
 }
 
 SetupFileHash *newSetupFileHash()
@@ -1396,7 +1456,6 @@ char *removeHashEntry(SetupFileHash *hash, char *token)
 }
 
 #if 0
-#ifdef DEBUG
 static void printSetupFileHash(SetupFileHash *hash)
 {
   BEGIN_HASH_ITERATION(hash, itr)
@@ -1407,7 +1466,6 @@ static void printSetupFileHash(SetupFileHash *hash)
   END_HASH_ITERATION(hash, itr)
 }
 #endif
-#endif
 
 static void *loadSetupFileData(char *filename, boolean use_hash)
 {
@@ -1560,14 +1618,14 @@ SetupFileHash *loadSetupFileHash(char *filename)
 }
 
 void checkSetupFileHashIdentifier(SetupFileHash *setup_file_hash,
-                                 char *identifier)
+                                 char *filename, char *identifier)
 {
   char *value = getHashEntry(setup_file_hash, TOKEN_STR_FILE_IDENTIFIER);
 
   if (value == NULL)
-    Error(ERR_WARN, "configuration file has no file identifier");
+    Error(ERR_WARN, "config file '%s' has no file identifier", filename);
   else if (!checkCookieString(value, identifier))
-    Error(ERR_WARN, "configuration file has wrong file identifier");
+    Error(ERR_WARN, "config file '%s' has wrong file identifier", filename);
 }
 
 
@@ -1575,57 +1633,61 @@ void checkSetupFileHashIdentifier(SetupFileHash *setup_file_hash,
 /* setup file stuff                                                          */
 /* ========================================================================= */
 
-#define TOKEN_STR_LAST_LEVEL_SERIES    "last_level_series"
-#define TOKEN_STR_LAST_PLAYED_LEVEL    "last_played_level"
-#define TOKEN_STR_HANDICAP_LEVEL       "handicap_level"
+#define TOKEN_STR_LAST_LEVEL_SERIES            "last_level_series"
+#define TOKEN_STR_LAST_PLAYED_LEVEL            "last_played_level"
+#define TOKEN_STR_HANDICAP_LEVEL               "handicap_level"
 
 /* level directory info */
-#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
-#define LEVELINFO_TOKEN_IMPORTED_BY    5
-#define LEVELINFO_TOKEN_LEVELS         6
-#define LEVELINFO_TOKEN_FIRST_LEVEL    7
-#define LEVELINFO_TOKEN_SORT_PRIORITY  8
-#define LEVELINFO_TOKEN_LATEST_ENGINE  9
-#define LEVELINFO_TOKEN_LEVEL_GROUP    10
-#define LEVELINFO_TOKEN_READONLY       11
-#define LEVELINFO_TOKEN_GRAPHICS_SET   12
-#define LEVELINFO_TOKEN_SOUNDS_SET     13
-#define LEVELINFO_TOKEN_MUSIC_SET      14
-#define LEVELINFO_TOKEN_FILENAME       15
-#define LEVELINFO_TOKEN_FILETYPE       16
-#define LEVELINFO_TOKEN_HANDICAP       17
-#define LEVELINFO_TOKEN_SKIP_LEVELS    18
-
-#define NUM_LEVELINFO_TOKENS           19
+#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
+#define LEVELINFO_TOKEN_IMPORTED_BY            5
+#define LEVELINFO_TOKEN_LEVELS                 6
+#define LEVELINFO_TOKEN_FIRST_LEVEL            7
+#define LEVELINFO_TOKEN_SORT_PRIORITY          8
+#define LEVELINFO_TOKEN_LATEST_ENGINE          9
+#define LEVELINFO_TOKEN_LEVEL_GROUP            10
+#define LEVELINFO_TOKEN_READONLY               11
+#define LEVELINFO_TOKEN_GRAPHICS_SET_ECS       12
+#define LEVELINFO_TOKEN_GRAPHICS_SET_AGA       13
+#define LEVELINFO_TOKEN_GRAPHICS_SET           14
+#define LEVELINFO_TOKEN_SOUNDS_SET             15
+#define LEVELINFO_TOKEN_MUSIC_SET              16
+#define LEVELINFO_TOKEN_FILENAME               17
+#define LEVELINFO_TOKEN_FILETYPE               18
+#define LEVELINFO_TOKEN_HANDICAP               19
+#define LEVELINFO_TOKEN_SKIP_LEVELS            20
+
+#define NUM_LEVELINFO_TOKENS                   21
 
 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_sorting,      "name_sorting"  },
-  { TYPE_STRING,       &ldi.author,            "author"        },
-  { TYPE_STRING,       &ldi.imported_from,     "imported_from" },
-  { TYPE_STRING,       &ldi.imported_by,       "imported_by"   },
-  { TYPE_INTEGER,      &ldi.levels,            "levels"        },
-  { TYPE_INTEGER,      &ldi.first_level,       "first_level"   },
-  { TYPE_INTEGER,      &ldi.sort_priority,     "sort_priority" },
-  { TYPE_BOOLEAN,      &ldi.latest_engine,     "latest_engine" },
-  { TYPE_BOOLEAN,      &ldi.level_group,       "level_group"   },
-  { 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"     },
-  { TYPE_STRING,       &ldi.level_filename,    "filename"      },
-  { TYPE_STRING,       &ldi.level_filetype,    "filetype"      },
-  { TYPE_BOOLEAN,      &ldi.handicap,          "handicap"      },
-  { TYPE_BOOLEAN,      &ldi.skip_levels,       "skip_levels"   }
+  { TYPE_STRING,       &ldi.identifier,        "identifier"            },
+  { TYPE_STRING,       &ldi.name,              "name"                  },
+  { TYPE_STRING,       &ldi.name_sorting,      "name_sorting"          },
+  { TYPE_STRING,       &ldi.author,            "author"                },
+  { TYPE_STRING,       &ldi.imported_from,     "imported_from"         },
+  { TYPE_STRING,       &ldi.imported_by,       "imported_by"           },
+  { TYPE_INTEGER,      &ldi.levels,            "levels"                },
+  { TYPE_INTEGER,      &ldi.first_level,       "first_level"           },
+  { TYPE_INTEGER,      &ldi.sort_priority,     "sort_priority"         },
+  { TYPE_BOOLEAN,      &ldi.latest_engine,     "latest_engine"         },
+  { TYPE_BOOLEAN,      &ldi.level_group,       "level_group"           },
+  { TYPE_BOOLEAN,      &ldi.readonly,          "readonly"              },
+  { TYPE_STRING,       &ldi.graphics_set_ecs,  "graphics_set.ecs"      },
+  { TYPE_STRING,       &ldi.graphics_set_aga,  "graphics_set.aga"      },
+  { TYPE_STRING,       &ldi.graphics_set,      "graphics_set"          },
+  { TYPE_STRING,       &ldi.sounds_set,        "sounds_set"            },
+  { TYPE_STRING,       &ldi.music_set,         "music_set"             },
+  { TYPE_STRING,       &ldi.level_filename,    "filename"              },
+  { TYPE_STRING,       &ldi.level_filetype,    "filetype"              },
+  { TYPE_BOOLEAN,      &ldi.handicap,          "handicap"              },
+  { TYPE_BOOLEAN,      &ldi.skip_levels,       "skip_levels"           }
 };
 
 static void setTreeInfoToDefaults(TreeInfo *ldi, int type)
@@ -1666,6 +1728,8 @@ static void setTreeInfoToDefaults(TreeInfo *ldi, int type)
     ldi->imported_from = NULL;
     ldi->imported_by = NULL;
 
+    ldi->graphics_set_ecs = NULL;
+    ldi->graphics_set_aga = NULL;
     ldi->graphics_set = NULL;
     ldi->sounds_set = NULL;
     ldi->music_set = NULL;
@@ -1698,7 +1762,6 @@ static void setTreeInfoToDefaultsFromParent(TreeInfo *ldi, TreeInfo *parent)
     return;
   }
 
-#if 1
   /* copy all values from the parent structure */
 
   ldi->type = parent->type;
@@ -1732,6 +1795,8 @@ static void setTreeInfoToDefaultsFromParent(TreeInfo *ldi, TreeInfo *parent)
     ldi->imported_from = getStringCopy(parent->imported_from);
     ldi->imported_by = getStringCopy(parent->imported_by);
 
+    ldi->graphics_set_ecs = NULL;
+    ldi->graphics_set_aga = NULL;
     ldi->graphics_set = NULL;
     ldi->sounds_set = NULL;
     ldi->music_set = NULL;
@@ -1751,47 +1816,6 @@ static void setTreeInfoToDefaultsFromParent(TreeInfo *ldi, TreeInfo *parent)
     ldi->handicap = TRUE;
     ldi->skip_levels = FALSE;
   }
-
-#else
-
-  /* first copy all values from the parent structure ... */
-  *ldi = *parent;
-
-  /* ... then set all fields to default that cannot be inherited from parent.
-     This is especially important for all those fields that can be set from
-     the 'levelinfo.conf' config file, because the function 'setSetupInfo()'
-     calls 'free()' for all already set token values which requires that no
-     other structure's pointer may point to them!
-  */
-
-  ldi->subdir = 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->imported_from = getStringCopy(parent->imported_from);
-  ldi->imported_by = getStringCopy(parent->imported_by);
-  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;
-
-  ldi->node_top = parent->node_top;
-  ldi->node_parent = parent;
-  ldi->node_group = NULL;
-  ldi->next = NULL;
-
-#endif
 }
 
 static void freeTreeInfo(TreeInfo *ldi)
@@ -1812,6 +1836,8 @@ static void freeTreeInfo(TreeInfo *ldi)
     checked_free(ldi->imported_from);
     checked_free(ldi->imported_by);
 
+    checked_free(ldi->graphics_set_ecs);
+    checked_free(ldi->graphics_set_aga);
     checked_free(ldi->graphics_set);
     checked_free(ldi->sounds_set);
     checked_free(ldi->music_set);
@@ -1915,7 +1941,6 @@ static void createParentTreeInfoNode(TreeInfo *node_parent)
   ti_new->node_parent = node_parent;
   ti_new->parent_link = TRUE;
 
-#if 1
   setString(&ti_new->identifier, node_parent->identifier);
   setString(&ti_new->name, ".. (parent directory)");
   setString(&ti_new->name_sorting, ti_new->name);
@@ -1927,19 +1952,6 @@ static void createParentTreeInfoNode(TreeInfo *node_parent)
   ti_new->latest_engine = node_parent->latest_engine;
 
   setString(&ti_new->class_desc, getLevelClassDescription(ti_new));
-#else
-  ti_new->identifier = getStringCopy(node_parent->identifier);
-  ti_new->name = ".. (parent directory)";
-  ti_new->name_sorting = getStringCopy(ti_new->name);
-
-  ti_new->subdir = "..";
-  ti_new->fullpath = getStringCopy(node_parent->fullpath);
-
-  ti_new->sort_priority = node_parent->sort_priority;
-  ti_new->latest_engine = node_parent->latest_engine;
-
-  ti_new->class_desc = getLevelClassDescription(ti_new);
-#endif
 
   pushTreeInfo(&node_parent->node_group, ti_new);
 }
@@ -1988,7 +2000,8 @@ static boolean LoadLevelInfoFromLevelConf(TreeInfo **node_first,
 
   leveldir_new->subdir = getStringCopy(directory_name);
 
-  checkSetupFileHashIdentifier(setup_file_hash, getCookie("LEVELINFO"));
+  checkSetupFileHashIdentifier(setup_file_hash, filename,
+                              getCookie("LEVELINFO"));
 
   /* set all structure fields according to the token/value pairs */
   ldi = *leveldir_new;
@@ -1997,16 +2010,8 @@ static boolean LoadLevelInfoFromLevelConf(TreeInfo **node_first,
                 getHashEntry(setup_file_hash, levelinfo_tokens[i].text));
   *leveldir_new = ldi;
 
-#if 1
-  if (strcmp(leveldir_new->name, ANONYMOUS_NAME) == 0)
+  if (strEqual(leveldir_new->name, ANONYMOUS_NAME))
     setString(&leveldir_new->name, leveldir_new->subdir);
-#else
-  if (strcmp(leveldir_new->name, ANONYMOUS_NAME) == 0)
-  {
-    free(leveldir_new->name);
-    leveldir_new->name = getStringCopy(leveldir_new->subdir);
-  }
-#endif
 
   DrawInitText(leveldir_new->name, 150, FC_YELLOW);
 
@@ -2027,54 +2032,55 @@ static boolean LoadLevelInfoFromLevelConf(TreeInfo **node_first,
     leveldir_new->fullpath = getPath2(node_parent->fullpath, directory_name);
   }
 
+#if 0
   if (leveldir_new->levels < 1)
     leveldir_new->levels = 1;
+#endif
 
   leveldir_new->last_level =
     leveldir_new->first_level + leveldir_new->levels - 1;
 
-#if 1
-  leveldir_new->in_user_dir =
-    (strcmp(leveldir_new->basepath, options.level_directory) != 0);
-#else
   leveldir_new->in_user_dir =
-    (leveldir_new->basepath == options.level_directory ? FALSE : TRUE);
-#endif
+    (!strEqual(leveldir_new->basepath, options.level_directory));
 
-#if 1
   /* adjust some settings if user's private level directory was detected */
   if (leveldir_new->sort_priority == LEVELCLASS_UNDEFINED &&
       leveldir_new->in_user_dir &&
-      (strcmp(leveldir_new->subdir, getLoginName()) == 0 ||
-       strcmp(leveldir_new->name,   getLoginName()) == 0 ||
-       strcmp(leveldir_new->author, getRealName())  == 0))
+      (strEqual(leveldir_new->subdir, getLoginName()) ||
+       strEqual(leveldir_new->name,   getLoginName()) ||
+       strEqual(leveldir_new->author, getRealName())))
   {
     leveldir_new->sort_priority = LEVELCLASS_PRIVATE_START;
     leveldir_new->readonly = FALSE;
   }
 
-#else
-  /* adjust sort priority if user's private level directory was detected */
-  if (leveldir_new->sort_priority == LEVELCLASS_UNDEFINED &&
-      leveldir_new->in_user_dir &&
-      strcmp(leveldir_new->subdir, getLoginName()) == 0)
-    leveldir_new->sort_priority = LEVELCLASS_PRIVATE_START;
-#endif
-
   leveldir_new->user_defined =
     (leveldir_new->in_user_dir && IS_LEVELCLASS_PRIVATE(leveldir_new));
 
   leveldir_new->color = LEVELCOLOR(leveldir_new);
-#if 1
+
   setString(&leveldir_new->class_desc, getLevelClassDescription(leveldir_new));
-#else
-  leveldir_new->class_desc = getLevelClassDescription(leveldir_new);
-#endif
 
   leveldir_new->handicap_level =       /* set handicap to default value */
     (leveldir_new->user_defined || !leveldir_new->handicap ?
      leveldir_new->last_level : leveldir_new->first_level);
 
+#if 0
+  /* !!! don't skip sets without levels (else artwork base sets are missing) */
+#if 1
+  if (leveldir_new->levels < 1 && !leveldir_new->level_group)
+  {
+    /* skip level sets without levels (which are probably artwork base sets) */
+
+    freeSetupFileHash(setup_file_hash);
+    free(directory_path);
+    free(filename);
+
+    return FALSE;
+  }
+#endif
+#endif
+
   pushTreeInfo(node_first, leveldir_new);
 
   freeSetupFileHash(setup_file_hash);
@@ -2116,8 +2122,8 @@ static void LoadLevelInfoFromLevelDir(TreeInfo **node_first,
     char *directory_path = getPath2(level_directory, directory_name);
 
     /* skip entries for current and parent directory */
-    if (strcmp(directory_name, ".")  == 0 ||
-       strcmp(directory_name, "..") == 0)
+    if (strEqual(directory_name, ".") ||
+       strEqual(directory_name, ".."))
     {
       free(directory_path);
       continue;
@@ -2133,9 +2139,9 @@ static void LoadLevelInfoFromLevelDir(TreeInfo **node_first,
 
     free(directory_path);
 
-    if (strcmp(directory_name, GRAPHICS_DIRECTORY) == 0 ||
-       strcmp(directory_name, SOUNDS_DIRECTORY) == 0 ||
-       strcmp(directory_name, MUSIC_DIRECTORY) == 0)
+    if (strEqual(directory_name, GRAPHICS_DIRECTORY) ||
+       strEqual(directory_name, SOUNDS_DIRECTORY) ||
+       strEqual(directory_name, MUSIC_DIRECTORY))
       continue;
 
     valid_entry_found |= LoadLevelInfoFromLevelConf(node_first, node_parent,
@@ -2145,7 +2151,8 @@ static void LoadLevelInfoFromLevelDir(TreeInfo **node_first,
 
   closedir(dir);
 
-  if (!valid_entry_found)
+  /* special case: top level directory may directly contain "levelinfo.conf" */
+  if (node_parent == NULL && !valid_entry_found)
   {
     /* check if this directory directly contains a file "levelinfo.conf" */
     valid_entry_found |= LoadLevelInfoFromLevelConf(node_first, node_parent,
@@ -2157,6 +2164,16 @@ static void LoadLevelInfoFromLevelDir(TreeInfo **node_first,
          level_directory);
 }
 
+boolean AdjustGraphicsForEMC()
+{
+  boolean settings_changed = FALSE;
+
+  settings_changed |= adjustTreeGraphicsForEMC(leveldir_first_all);
+  settings_changed |= adjustTreeGraphicsForEMC(leveldir_first);
+
+  return settings_changed;
+}
+
 void LoadLevelInfo()
 {
   InitUserLevelDirectory(getLoginName());
@@ -2166,6 +2183,17 @@ void LoadLevelInfo()
   LoadLevelInfoFromLevelDir(&leveldir_first, NULL, options.level_directory);
   LoadLevelInfoFromLevelDir(&leveldir_first, NULL, getUserLevelDir(NULL));
 
+#if 1
+  /* after loading all level set information, clone the level directory tree
+     and remove all level sets without levels (these may still contain artwork
+     to be offered in the setup menu as "custom artwork", and are therefore
+     checked for existing artwork in the function "LoadLevelArtworkInfo()") */
+  leveldir_first_all = leveldir_first;
+  cloneTree(&leveldir_first, leveldir_first_all, TRUE);
+#endif
+
+  AdjustGraphicsForEMC();
+
   /* before sorting, the first entries will be from the user directory */
   leveldir_current = getFirstValidTreeInfoEntry(leveldir_first);
 
@@ -2217,7 +2245,7 @@ static boolean LoadArtworkInfoFromArtworkConf(TreeInfo **node_first,
 
     if (!valid_file_found)
     {
-      if (strcmp(directory_name, ".") != 0)
+      if (!strEqual(directory_name, "."))
        Error(ERR_WARN, "ignoring artwork directory '%s'", directory_path);
 
       free(directory_path);
@@ -2239,7 +2267,7 @@ static boolean LoadArtworkInfoFromArtworkConf(TreeInfo **node_first,
   if (setup_file_hash) /* (before defining ".color" and ".class_desc") */
   {
 #if 0
-    checkSetupFileHashIdentifier(setup_file_hash, getCookie("..."));
+    checkSetupFileHashIdentifier(setup_file_hash, filename, getCookie("..."));
 #endif
 
     /* set all structure fields according to the token/value pairs */
@@ -2249,16 +2277,8 @@ static boolean LoadArtworkInfoFromArtworkConf(TreeInfo **node_first,
                   getHashEntry(setup_file_hash, levelinfo_tokens[i].text));
     *artwork_new = ldi;
 
-#if 1
-    if (strcmp(artwork_new->name, ANONYMOUS_NAME) == 0)
+    if (strEqual(artwork_new->name, ANONYMOUS_NAME))
       setString(&artwork_new->name, artwork_new->subdir);
-#else
-    if (strcmp(artwork_new->name, ANONYMOUS_NAME) == 0)
-    {
-      free(artwork_new->name);
-      artwork_new->name = getStringCopy(artwork_new->subdir);
-    }
-#endif
 
 #if 0
     DrawInitText(artwork_new->name, 150, FC_YELLOW);
@@ -2282,86 +2302,42 @@ static boolean LoadArtworkInfoFromArtworkConf(TreeInfo **node_first,
     artwork_new->fullpath = getPath2(node_parent->fullpath, directory_name);
   }
 
-#if 1
-  artwork_new->in_user_dir =
-    (strcmp(artwork_new->basepath, OPTIONS_ARTWORK_DIRECTORY(type)) != 0);
-#else
   artwork_new->in_user_dir =
-    (artwork_new->basepath == OPTIONS_ARTWORK_DIRECTORY(type) ? FALSE : TRUE);
-#endif
+    (!strEqual(artwork_new->basepath, OPTIONS_ARTWORK_DIRECTORY(type)));
 
   /* (may use ".sort_priority" from "setup_file_hash" above) */
   artwork_new->color = ARTWORKCOLOR(artwork_new);
-#if 1
+
   setString(&artwork_new->class_desc, getLevelClassDescription(artwork_new));
-#else
-  artwork_new->class_desc = getLevelClassDescription(artwork_new);
-#endif
 
   if (setup_file_hash == NULL) /* (after determining ".user_defined") */
   {
-#if 0
-    if (artwork_new->name != NULL)
-    {
-      free(artwork_new->name);
-      artwork_new->name = NULL;
-    }
-#endif
-
-#if 0
-    if (artwork_new->identifier != NULL)
-    {
-      free(artwork_new->identifier);
-      artwork_new->identifier = NULL;
-    }
-#endif
-
-    if (strcmp(artwork_new->subdir, ".") == 0)
+    if (strEqual(artwork_new->subdir, "."))
     {
       if (artwork_new->user_defined)
       {
-#if 1
        setString(&artwork_new->identifier, "private");
-#else
-       artwork_new->identifier = getStringCopy("private");
-#endif
        artwork_new->sort_priority = ARTWORKCLASS_PRIVATE;
       }
       else
       {
-#if 1
        setString(&artwork_new->identifier, "classic");
-#else
-       artwork_new->identifier = getStringCopy("classic");
-#endif
        artwork_new->sort_priority = ARTWORKCLASS_CLASSICS;
       }
 
       /* set to new values after changing ".sort_priority" */
       artwork_new->color = ARTWORKCOLOR(artwork_new);
-#if 1
+
       setString(&artwork_new->class_desc,
                getLevelClassDescription(artwork_new));
-#else
-      artwork_new->class_desc = getLevelClassDescription(artwork_new);
-#endif
     }
     else
     {
-#if 1
       setString(&artwork_new->identifier, artwork_new->subdir);
-#else
-      artwork_new->identifier = getStringCopy(artwork_new->subdir);
-#endif
     }
 
-#if 1
     setString(&artwork_new->name, artwork_new->identifier);
     setString(&artwork_new->name_sorting, artwork_new->name);
-#else
-    artwork_new->name = getStringCopy(artwork_new->identifier);
-    artwork_new->name_sorting = getStringCopy(artwork_new->name);
-#endif
   }
 
   DrawInitText(artwork_new->name, 150, FC_YELLOW);
@@ -2386,8 +2362,10 @@ static void LoadArtworkInfoFromArtworkDir(TreeInfo **node_first,
 
   if ((dir = opendir(base_directory)) == NULL)
   {
+    /* display error if directory is main "options.graphics_directory" etc. */
     if (base_directory == OPTIONS_ARTWORK_DIRECTORY(type))
       Error(ERR_WARN, "cannot read directory '%s'", base_directory);
+
     return;
   }
 
@@ -2397,15 +2375,15 @@ static void LoadArtworkInfoFromArtworkDir(TreeInfo **node_first,
     char *directory_name = dir_entry->d_name;
     char *directory_path = getPath2(base_directory, directory_name);
 
-    /* skip entries for current and parent directory */
-    if (strcmp(directory_name, ".")  == 0 ||
-       strcmp(directory_name, "..") == 0)
+    /* skip directory entries for current and parent directory */
+    if (strEqual(directory_name, ".") ||
+       strEqual(directory_name, ".."))
     {
       free(directory_path);
       continue;
     }
 
-    /* find out if directory entry is itself a directory */
+    /* skip directory entries which are not a directory or are not accessible */
     if (stat(directory_path, &file_status) != 0 ||     /* cannot stat file */
        (file_status.st_mode & S_IFMT) != S_IFDIR)      /* not a directory */
     {
@@ -2416,7 +2394,7 @@ static void LoadArtworkInfoFromArtworkDir(TreeInfo **node_first,
     free(directory_path);
 
     /* check if this directory contains artwork with or without config file */
-    valid_entry_found |= LoadArtworkInfoFromArtworkConf(node_first,node_parent,
+    valid_entry_found |= LoadArtworkInfoFromArtworkConf(node_first, node_parent,
                                                        base_directory,
                                                        directory_name, type);
   }
@@ -2424,7 +2402,7 @@ static void LoadArtworkInfoFromArtworkDir(TreeInfo **node_first,
   closedir(dir);
 
   /* check if this directory directly contains artwork itself */
-  valid_entry_found |= LoadArtworkInfoFromArtworkConf(node_first,node_parent,
+  valid_entry_found |= LoadArtworkInfoFromArtworkConf(node_first, node_parent,
                                                      base_directory, ".",
                                                      type);
   if (!valid_entry_found)
@@ -2439,7 +2417,6 @@ static TreeInfo *getDummyArtworkInfo(int type)
 
   setTreeInfoToDefaults(artwork_new, type);
 
-#if 1
   setString(&artwork_new->subdir,   UNDEFINED_FILENAME);
   setString(&artwork_new->fullpath, UNDEFINED_FILENAME);
   setString(&artwork_new->basepath, UNDEFINED_FILENAME);
@@ -2447,17 +2424,6 @@ static TreeInfo *getDummyArtworkInfo(int type)
   setString(&artwork_new->identifier,   UNDEFINED_FILENAME);
   setString(&artwork_new->name,         UNDEFINED_FILENAME);
   setString(&artwork_new->name_sorting, UNDEFINED_FILENAME);
-#else
-  artwork_new->subdir   = getStringCopy(UNDEFINED_FILENAME);
-  artwork_new->fullpath = getStringCopy(UNDEFINED_FILENAME);
-  artwork_new->basepath = getStringCopy(UNDEFINED_FILENAME);
-
-  checked_free(artwork_new->name);
-
-  artwork_new->identifier   = getStringCopy(UNDEFINED_FILENAME);
-  artwork_new->name         = getStringCopy(UNDEFINED_FILENAME);
-  artwork_new->name_sorting = getStringCopy(UNDEFINED_FILENAME);
-#endif
 
   return artwork_new;
 }
@@ -2547,18 +2513,12 @@ void LoadArtworkInfoFromLevelInfo(ArtworkDirTree **artwork_node,
 
   while (level_node)
   {
-    char *path = getPath2(getLevelDirFromTreeInfo(level_node),
-                         ARTWORK_DIRECTORY((*artwork_node)->type));
-
-#if 0
-    if (!level_node->parent_link)
-      printf("CHECKING '%s' ['%s', '%s'] ...\n", path,
-            level_node->subdir, level_node->name);
-#endif
-
+    /* check all tree entries for artwork, but skip parent link entries */
     if (!level_node->parent_link)
     {
       TreeInfo *topnode_last = *artwork_node;
+      char *path = getPath2(getLevelDirFromTreeInfo(level_node),
+                           ARTWORK_DIRECTORY((*artwork_node)->type));
 
       LoadArtworkInfoFromArtworkDir(artwork_node, NULL, path,
                                    (*artwork_node)->type);
@@ -2576,9 +2536,9 @@ void LoadArtworkInfoFromLevelInfo(ArtworkDirTree **artwork_node,
        (*artwork_node)->sort_priority = level_node->sort_priority;
        (*artwork_node)->color = LEVELCOLOR((*artwork_node));
       }
-    }
 
-    free(path);
+      free(path);
+    }
 
     if (level_node->node_group != NULL)
       LoadArtworkInfoFromLevelInfo(artwork_node, level_node->node_group);
@@ -2591,13 +2551,13 @@ void LoadLevelArtworkInfo()
 {
   DrawInitText("Looking for custom level artwork:", 120, FC_GREEN);
 
-  LoadArtworkInfoFromLevelInfo(&artwork.gfx_first, leveldir_first);
-  LoadArtworkInfoFromLevelInfo(&artwork.snd_first, leveldir_first);
-  LoadArtworkInfoFromLevelInfo(&artwork.mus_first, leveldir_first);
+  LoadArtworkInfoFromLevelInfo(&artwork.gfx_first, leveldir_first_all);
+  LoadArtworkInfoFromLevelInfo(&artwork.snd_first, leveldir_first_all);
+  LoadArtworkInfoFromLevelInfo(&artwork.mus_first, leveldir_first_all);
 
   /* needed for reloading level artwork not known at ealier stage */
 
-  if (strcmp(artwork.gfx_current_identifier, setup.graphics_set) != 0)
+  if (!strEqual(artwork.gfx_current_identifier, setup.graphics_set))
   {
     artwork.gfx_current =
       getTreeInfoFromIdentifier(artwork.gfx_first, setup.graphics_set);
@@ -2608,7 +2568,7 @@ void LoadLevelArtworkInfo()
       artwork.gfx_current = getFirstValidTreeInfoEntry(artwork.gfx_first);
   }
 
-  if (strcmp(artwork.snd_current_identifier, setup.sounds_set) != 0)
+  if (!strEqual(artwork.snd_current_identifier, setup.sounds_set))
   {
     artwork.snd_current =
       getTreeInfoFromIdentifier(artwork.snd_first, setup.sounds_set);
@@ -2619,7 +2579,7 @@ void LoadLevelArtworkInfo()
       artwork.snd_current = getFirstValidTreeInfoEntry(artwork.snd_first);
   }
 
-  if (strcmp(artwork.mus_current_identifier, setup.music_set) != 0)
+  if (!strEqual(artwork.mus_current_identifier, setup.music_set))
   {
     artwork.mus_current =
       getTreeInfoFromIdentifier(artwork.mus_first, setup.music_set);
@@ -2662,29 +2622,10 @@ static void SaveUserLevelInfo()
   /* always start with reliable default values */
   setTreeInfoToDefaults(level_info, TREE_TYPE_LEVEL_DIR);
 
-#if 1
   setString(&level_info->name, getLoginName());
   setString(&level_info->author, getRealName());
   level_info->levels = 100;
   level_info->first_level = 1;
-#if 0
-  level_info->sort_priority = LEVELCLASS_PRIVATE_START;
-  level_info->readonly = FALSE;
-  setString(&level_info->graphics_set, GFX_CLASSIC_SUBDIR);
-  setString(&level_info->sounds_set,   SND_CLASSIC_SUBDIR);
-  setString(&level_info->music_set,    MUS_CLASSIC_SUBDIR);
-#endif
-#else
-  ldi.name = getStringCopy(getLoginName());
-  ldi.author = getStringCopy(getRealName());
-  ldi.levels = 100;
-  ldi.first_level = 1;
-  ldi.sort_priority = LEVELCLASS_PRIVATE_START;
-  ldi.readonly = FALSE;
-  ldi.graphics_set = getStringCopy(GFX_CLASSIC_SUBDIR);
-  ldi.sounds_set = getStringCopy(SND_CLASSIC_SUBDIR);
-  ldi.music_set = getStringCopy(MUS_CLASSIC_SUBDIR);
-#endif
 
   token_value_position = TOKEN_VALUE_POSITION_SHORT;
 
@@ -2694,7 +2635,6 @@ static void SaveUserLevelInfo()
   ldi = *level_info;
   for (i = 0; i < NUM_LEVELINFO_TOKENS; i++)
   {
-#if 1
     if (i == LEVELINFO_TOKEN_NAME ||
        i == LEVELINFO_TOKEN_AUTHOR ||
        i == LEVELINFO_TOKEN_LEVELS ||
@@ -2704,15 +2644,6 @@ static void SaveUserLevelInfo()
     /* just to make things nicer :) */
     if (i == LEVELINFO_TOKEN_AUTHOR)
       fprintf(file, "\n");     
-#else
-    if (i != LEVELINFO_TOKEN_IDENTIFIER &&
-       i != LEVELINFO_TOKEN_NAME_SORTING &&
-       i != LEVELINFO_TOKEN_IMPORTED_FROM &&
-       i != LEVELINFO_TOKEN_IMPORTED_BY &&
-       i != LEVELINFO_TOKEN_FILENAME &&
-       i != LEVELINFO_TOKEN_FILETYPE)
-      fprintf(file, "%s\n", getSetupLine(levelinfo_tokens, "", i));
-#endif
   }
 
   token_value_position = TOKEN_VALUE_POSITION_DEFAULT;
@@ -2746,6 +2677,10 @@ char *getSetupValue(int type, void *value)
       strcpy(value_string, (*(boolean *)value ? "yes" : "no"));
       break;
 
+    case TYPE_ECS_AGA:
+      strcpy(value_string, (*(boolean *)value ? "AGA" : "ECS"));
+      break;
+
     case TYPE_KEY:
       strcpy(value_string, getKeyNameFromKey(*(Key *)value));
       break;
@@ -2767,6 +2702,9 @@ char *getSetupValue(int type, void *value)
       break;
   }
 
+  if (type & TYPE_GHOSTED)
+    strcpy(value_string, "n/a");
+
   return value_string;
 }
 
@@ -2792,8 +2730,8 @@ char *getSetupLine(struct TokenInfo *token_info, char *prefix, int token_nr)
     char *keyname = getKeyNameFromKey(key);
 
     /* add comment, if useful */
-    if (strcmp(keyname, "(undefined)") != 0 &&
-       strcmp(keyname, "(unknown)") != 0)
+    if (!strEqual(keyname, "(undefined)") &&
+       !strEqual(keyname, "(unknown)"))
     {
       /* add at least one whitespace */
       strcat(line, " ");
@@ -2830,7 +2768,8 @@ void LoadLevelSetup_LastSeries()
     if (leveldir_current == NULL)
       leveldir_current = getFirstValidTreeInfoEntry(leveldir_first);
 
-    checkSetupFileHashIdentifier(level_setup_hash, getCookie("LEVELSETUP"));
+    checkSetupFileHashIdentifier(level_setup_hash, filename,
+                                getCookie("LEVELSETUP"));
 
     freeSetupFileHash(level_setup_hash);
   }
@@ -2894,7 +2833,7 @@ static void checkSeriesInfo()
   {
     if (strlen(dir_entry->d_name) > 4 &&
        dir_entry->d_name[3] == '.' &&
-       strcmp(&dir_entry->d_name[4], LEVELFILE_EXTENSION) == 0)
+       strEqual(&dir_entry->d_name[4], LEVELFILE_EXTENSION))
     {
       char levelnum_str[4];
       int levelnum_value;
@@ -2974,7 +2913,8 @@ void LoadLevelSetup_SeriesInfo()
       leveldir_current->handicap_level = level_nr;
     }
 
-    checkSetupFileHashIdentifier(level_setup_hash, getCookie("LEVELSETUP"));
+    checkSetupFileHashIdentifier(level_setup_hash, filename,
+                                getCookie("LEVELSETUP"));
 
     freeSetupFileHash(level_setup_hash);
   }
index 67a4c28287dc997a173b487e758dcc71a96cd805..ab46527686333faf1190cb5be99b16d7505be880 100644 (file)
 #define TYPE_BOOLEAN                   (1 << 0)
 #define TYPE_SWITCH                    (1 << 1)
 #define TYPE_YES_NO                    (1 << 2)
-#define TYPE_KEY                       (1 << 3)
-#define TYPE_KEY_X11                   (1 << 4)
-#define TYPE_INTEGER                   (1 << 5)
-#define TYPE_STRING                    (1 << 6)
-#define TYPE_TOKEN                     (1 << 7)
+#define TYPE_ECS_AGA                   (1 << 3)
+#define TYPE_KEY                       (1 << 4)
+#define TYPE_KEY_X11                   (1 << 5)
+#define TYPE_INTEGER                   (1 << 6)
+#define TYPE_STRING                    (1 << 7)
+#define TYPE_TOKEN                     (1 << 8)
 
+/* additional values for setup screen */
+#define TYPE_ENTER_SCREEN              (1 << 9)
+#define TYPE_ENTER_MENU                        (1 << 10)
+#define TYPE_LEAVE_MENU                        (1 << 11)
+#define TYPE_EMPTY                     (1 << 12)
+#define TYPE_KEYTEXT                   (1 << 13)
+
+#define TYPE_GHOSTED                   (1 << 14)
+#define TYPE_QUERY                     (1 << 15)
+
+/* additional values for internal purposes */
+#define TYPE_BITFIELD                  (1 << 16)
+#define TYPE_ELEMENT                   (1 << 17)
+#define TYPE_CONTENT                   (1 << 18)
+#define TYPE_ELEMENT_LIST              (1 << 19)
+#define TYPE_CONTENT_LIST              (1 << 20)
+
+/* derived values for setup file handling */
 #define TYPE_BOOLEAN_STYLE             (TYPE_BOOLEAN | \
                                         TYPE_SWITCH  | \
-                                        TYPE_YES_NO)
-
-/* additional values for setup screen */
-#define TYPE_ENTER_SCREEN              (1 << 8)
-#define TYPE_ENTER_MENU                        (1 << 9)
-#define TYPE_LEAVE_MENU                        (1 << 10)
-#define TYPE_EMPTY                     (1 << 11)
-#define TYPE_KEYTEXT                   (1 << 12)
-
-#define TYPE_GHOSTED                   (1 << 13)
-#define TYPE_QUERY                     (1 << 14)
+                                        TYPE_YES_NO  | \
+                                        TYPE_ECS_AGA )
 
+/* derived values for setup screen */
 #define TYPE_VALUE                     (TYPE_BOOLEAN_STYLE     | \
                                         TYPE_KEY               | \
                                         TYPE_KEY_X11           | \
@@ -265,11 +276,13 @@ char *getHashEntry(SetupFileHash *, char *);
 void setHashEntry(SetupFileHash *, char *, char *);
 char *removeHashEntry(SetupFileHash *, char *);
 SetupFileHash *loadSetupFileHash(char *);
-void checkSetupFileHashIdentifier(SetupFileHash *, char *);
+void checkSetupFileHashIdentifier(SetupFileHash *, char *, char *);
 void setSetupInfo(struct TokenInfo *, int, char *);
 char *getSetupValue(int, void *);
 char *getSetupLine(struct TokenInfo *, char *, int);
 
+boolean AdjustGraphicsForEMC();
+
 void LoadLevelInfo(void);
 void LoadArtworkInfo(void);
 void LoadLevelArtworkInfo(void);
index 6eb1de14df23ca62529752743f0fd5ef64f406d5..d75acaf3f0c5b186f204147702f0eddf7d4311a0 100644 (file)
 #define SAME_SOUND_NR(x,y)             ((x).nr == (y).nr)
 #define SAME_SOUND_DATA(x,y)           ((x).data_ptr == (y).data_ptr)
 
-#if 0
-struct SoundHeader_SUN
-{
-  unsigned long magic;
-  unsigned long hdr_size;
-  unsigned long data_size;
-  unsigned long encoding;
-  unsigned long sample_rate;
-  unsigned long channels;
-};
-
-struct SoundHeader_8SVX
-{
-  char magic_FORM[4];
-  unsigned long chunk_size;
-  char magic_8SVX[4];
-};
-#endif
-
 #if defined(AUDIO_UNIX_NATIVE)
 struct SoundHeader_WAV
 {
@@ -151,16 +132,8 @@ typedef struct SoundControl SoundControl;
 static struct ArtworkListInfo *sound_info = NULL;
 static struct ArtworkListInfo *music_info = NULL;
 
-#if 0
-static SoundInfo **Sound = NULL;
-#endif
-
 static MusicInfo **Music_NoConf = NULL;
 
-#if 0
-static int num_sounds = 0;
-#endif
-
 static int num_music_noconf = 0;
 static int stereo_volume[SOUND_MAX_LEFT2RIGHT + 1];
 
@@ -271,11 +244,6 @@ static boolean ForkAudioProcess(void)
   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
@@ -831,22 +799,6 @@ static void Mixer_InsertSound(SoundControl snd_ctrl)
   int num_sounds = getSoundListSize();
   int num_music  = getMusicListSize();
 
-#if 0
-  if (IS_MUSIC(snd_ctrl))
-    printf("NEW MUSIC %d ARRIVED [%d/%d] [%d ACTIVE CHANNELS]\n",
-          snd_ctrl.nr, num_music, num_music_noconf, mixer_active_channels);
-  else
-    printf("NEW SOUND %d ARRIVED [%d] [%d ACTIVE CHANNELS]\n",
-          snd_ctrl.nr, num_sounds, mixer_active_channels);
-#endif
-
-#if 0
-  /* !!! TEST ONLY !!! */
-  if (IS_MUSIC(snd_ctrl))
-    snd_ctrl.nr = 0;
-#endif
-
-#if 1
   if (IS_MUSIC(snd_ctrl))
   {
     if (snd_ctrl.nr >= num_music)      /* invalid music */
@@ -871,32 +823,6 @@ static void Mixer_InsertSound(SoundControl snd_ctrl)
     snd_info = getSoundInfoEntryFromSoundID(snd_ctrl.nr);
   }
 
-  /*
-  if (snd_ctrl.nr >= (IS_MUSIC(snd_ctrl) ? num_music : num_sounds))
-    return;
-  */
-#else
-  if (IS_MUSIC(snd_ctrl))
-  {
-    if (num_music_noconf == 0)
-      return;
-
-    snd_ctrl.nr = snd_ctrl.nr % num_music_noconf;
-  }
-  else if (snd_ctrl.nr >= num_sounds)
-    return;
-#endif
-
-#if 0
-#if 1
-  snd_info = (IS_MUSIC(snd_ctrl) ? getMusicInfoEntryFromMusicID(snd_ctrl.nr) :
-             getSoundInfoEntryFromSoundID(snd_ctrl.nr));
-#else
-  snd_info = (IS_MUSIC(snd_ctrl) ? Music_NoConf[snd_ctrl.nr] :
-             getSoundInfoEntryFromSoundID(snd_ctrl.nr));
-#endif
-#endif
-
   if (snd_info == NULL)
     return;
 
@@ -910,10 +836,6 @@ static void Mixer_InsertSound(SoundControl snd_ctrl)
   /* play music samples on a dedicated music channel */
   if (IS_MUSIC(snd_ctrl))
   {
-#if 0
-    printf("::: slot %d, ptr 0x%08x\n", snd_ctrl.nr, snd_ctrl.data_ptr);
-#endif
-
     Mixer_StopMusicChannel();
 
     mixer[audio.music_channel] = snd_ctrl;
@@ -927,10 +849,6 @@ static void Mixer_InsertSound(SoundControl snd_ctrl)
     if (mixer[i].active && SAME_SOUND_DATA(mixer[i], snd_ctrl))
       k++;
 
-#if 0
-  printf("SOUND %d [CURRENTLY PLAYING %d TIMES]\n", snd_ctrl.nr, k);
-#endif
-
   /* reset expiration delay for already playing loop sounds */
   if (k > 0 && IS_LOOP(snd_ctrl))
   {
@@ -938,10 +856,6 @@ static void Mixer_InsertSound(SoundControl snd_ctrl)
     {
       if (mixer[i].active && SAME_SOUND_DATA(mixer[i], snd_ctrl))
       {
-#if 0
-       printf("RESETTING EXPIRATION FOR SOUND %d\n", snd_ctrl.nr);
-#endif
-
        if (IS_FADING(mixer[i]))
          Mixer_UnFadeChannel(i);
 
@@ -951,21 +865,12 @@ static void Mixer_InsertSound(SoundControl snd_ctrl)
 
        Mixer_SetChannelProperties(i);
        Mixer_ResetChannelExpiration(i);
-
-#if 0
-       printf("RESETTING VOLUME/STEREO FOR SOUND %d TO %d/%d\n",
-              snd_ctrl.nr, snd_ctrl.volume, snd_ctrl.stereo_position);
-#endif
       }
     }
 
     return;
   }
 
-#if 0
-  printf("PLAYING NEW SOUND %d\n", snd_ctrl.nr);
-#endif
-
   /* don't play sound more than n times simultaneously (with n == 2 for now) */
   if (k >= 2)
   {
@@ -1052,16 +957,8 @@ static void Mixer_InsertSound(SoundControl snd_ctrl)
   /* add the new sound to the mixer */
   for (i = audio.first_sound_channel; i < audio.num_channels; i++)
   {
-#if 0
-    printf("CHECKING CHANNEL %d FOR SOUND %d ...\n", i, snd_ctrl.nr);
-#endif
-
     if (!mixer[i].active)
     {
-#if 0
-      printf("ADDING NEW SOUND %d TO MIXER\n", snd_ctrl.nr);
-#endif
-
 #if defined(AUDIO_UNIX_NATIVE)
       if (snd_info->data_len == 0)
       {
@@ -1408,11 +1305,9 @@ static int Mixer_Main_SimpleAudio(SoundControl snd_ctrl)
        mixer[i].volume * (long)premix_first_buffer[j] / SOUND_MAX_VOLUME;
 
   /* might be needed for u-law /dev/audio */
-#if 1
   for (j = 0; j < sample_size; j++)
     playing_buffer[j] =
       linear_to_ulaw(premix_first_buffer[j]);
-#endif
 
   /* delete completed sound entries from the mixer */
   if (mixer[i].playing_pos >= mixer[i].data_len)
@@ -1638,10 +1533,6 @@ static void *Load_WAV(char *filename)
   if (!audio.sound_available)
     return NULL;
 
-#if 0
-  printf("loading WAV file '%s'\n", filename);
-#endif
-
   snd_info = checked_calloc(sizeof(SoundInfo));
 
 #if defined(TARGET_SDL)
@@ -1677,7 +1568,7 @@ static void *Load_WAV(char *filename)
 
   /* read chunk id "RIFF" */
   getFileChunkLE(file, chunk_name, &chunk_size);
-  if (strcmp(chunk_name, "RIFF") != 0)
+  if (!strEqual(chunk_name, "RIFF"))
   {
     Error(ERR_WARN, "missing 'RIFF' chunk of sound file '%s'", filename);
     fclose(file);
@@ -1687,7 +1578,7 @@ static void *Load_WAV(char *filename)
 
   /* read "RIFF" type id "WAVE" */
   getFileChunkLE(file, chunk_name, NULL);
-  if (strcmp(chunk_name, "WAVE") != 0)
+  if (!strEqual(chunk_name, "WAVE"))
   {
     Error(ERR_WARN, "missing 'WAVE' type ID of sound file '%s'", filename);
     fclose(file);
@@ -1697,7 +1588,7 @@ static void *Load_WAV(char *filename)
 
   while (getFileChunkLE(file, chunk_name, &chunk_size))
   {
-    if (strcmp(chunk_name, "fmt ") == 0)
+    if (strEqual(chunk_name, "fmt "))
     {
       if (chunk_size < WAV_HEADER_SIZE)
       {
@@ -1761,7 +1652,7 @@ static void *Load_WAV(char *filename)
       printf("  Significant bits per sample: %d'\n", header.bits_per_sample);
 #endif
     }
-    else if (strcmp(chunk_name, "data") == 0)
+    else if (strEqual(chunk_name, "data"))
     {
       data_byte_len = chunk_size;
 
@@ -1884,7 +1775,7 @@ void LoadCustomMusic_NoConf(void)
     return;
 
   if (last_music_directory != NULL &&
-      strcmp(last_music_directory, music_directory) == 0)
+      strEqual(last_music_directory, music_directory))
     return;    /* old and new music directory are the same */
 
   if (last_music_directory != NULL)
@@ -1916,7 +1807,7 @@ void LoadCustomMusic_NoConf(void)
     {
       struct FileInfo *music = getMusicListEntry(i);
 
-      if (strcmp(basename, music->filename) == 0)
+      if (strEqual(basename, music->filename))
       {
        music_already_used = TRUE;
        break;
@@ -1926,25 +1817,13 @@ void LoadCustomMusic_NoConf(void)
     if (music_already_used)
       continue;
 
-#if 0
-    if (FileIsSound(basename) || FileIsMusic(basename))
-      printf("DEBUG: loading music '%s' ...\n", basename);
-#endif
-
     if (draw_init_text)
       DrawInitText(basename, 150, FC_YELLOW);
 
     filename = getPath2(music_directory, basename);
 
-#if 1
     if (FileIsMusic(basename))
       mus_info = Load_WAV_or_MOD(filename);
-#else
-    if (FileIsSound(basename))
-      mus_info = Load_WAV(filename);
-    else if (FileIsMusic(basename))
-      mus_info = Load_MOD(filename);
-#endif
 
     free(filename);
 
@@ -2107,11 +1986,6 @@ void InitSoundList(struct ConfigInfo *config_list, int num_file_list_entries,
 
   sound_info->load_artwork = Load_WAV;
   sound_info->free_artwork = FreeSound;
-
-#if 0
-  num_sounds = sound_info->num_file_list_entries;
-  Sound = (SoundInfo **)sound_info->artwork_list;
-#endif
 }
 
 void InitMusicList(struct ConfigInfo *config_list, int num_file_list_entries,
@@ -2309,30 +2183,24 @@ void StopSoundExt(int nr, int state)
 static void ReloadCustomSounds()
 {
 #if 0
-  printf("DEBUG: reloading sounds '%s' ...\n", artwork.snd_current_identifier);
+  printf("::: reloading sounds '%s' ...\n", artwork.snd_current_identifier);
 #endif
 
   LoadArtworkConfig(sound_info);
   ReloadCustomArtworkList(sound_info);
-
-#if 0
-  num_sounds = getSoundListSize();
-#endif
 }
 
 static void ReloadCustomMusic()
 {
 #if 0
-  printf("DEBUG: reloading music '%s' ...\n", artwork.mus_current_identifier);
+  printf("::: reloading music '%s' ...\n", artwork.mus_current_identifier);
 #endif
 
   LoadArtworkConfig(music_info);
   ReloadCustomArtworkList(music_info);
 
-#if 1
   /* load all music files from directory not defined in "musicinfo.conf" */
   LoadCustomMusic_NoConf();
-#endif
 }
 
 void InitReloadCustomSounds(char *set_identifier)
index 8e65d97056a32dd2baebed276d6016ab46dedc30..3c460375b03aa4ec67d7a0474413726a298a5d2f 100644 (file)
@@ -41,6 +41,7 @@ struct ArtworkInfo    artwork;
 struct JoystickInfo    joystick;
 struct SetupInfo       setup;
 
+LevelDirTree          *leveldir_first_all = NULL;
 LevelDirTree          *leveldir_first = NULL;
 LevelDirTree          *leveldir_current = NULL;
 int                    level_nr;
@@ -213,29 +214,6 @@ static void DrawBitmapFromTile(Bitmap *bitmap, Bitmap *tile,
 
 void SetBackgroundBitmap(Bitmap *background_bitmap_tile, int mask)
 {
-  /* !!! THIS DOES NOT WORK !!! REPLACED BITMAPS MAY HAVE SAME ADDRESS !!! */
-#if 0
-  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;
-#endif
-
   if (background_bitmap_tile != NULL)
     gfx.background_bitmap_mask |= mask;
   else
@@ -303,7 +281,7 @@ inline static void sysCopyArea(Bitmap *src_bitmap, Bitmap *dst_bitmap,
 #endif
 }
 
-inline void InitVideoDisplay(void)
+void InitVideoDisplay(void)
 {
 #if defined(TARGET_SDL)
   SDLInitVideoDisplay();
@@ -312,7 +290,7 @@ inline void InitVideoDisplay(void)
 #endif
 }
 
-inline void CloseVideoDisplay(void)
+void CloseVideoDisplay(void)
 {
   KeyboardAutoRepeatOn();
 
@@ -324,9 +302,8 @@ inline void CloseVideoDisplay(void)
 #endif
 }
 
-inline void InitVideoBuffer(DrawBuffer **backbuffer, DrawWindow **window,
-                           int width, int height, int depth,
-                           boolean fullscreen)
+void InitVideoBuffer(DrawBuffer **backbuffer, DrawWindow **window,
+                    int width, int height, int depth, boolean fullscreen)
 {
   video.width = width;
   video.height = height;
@@ -341,7 +318,7 @@ inline void InitVideoBuffer(DrawBuffer **backbuffer, DrawWindow **window,
 #endif
 }
 
-inline Bitmap *CreateBitmapStruct(void)
+Bitmap *CreateBitmapStruct(void)
 {
 #if defined(TARGET_SDL)
   return checked_calloc(sizeof(struct SDLSurfaceInfo));
@@ -350,7 +327,7 @@ inline Bitmap *CreateBitmapStruct(void)
 #endif
 }
 
-inline Bitmap *CreateBitmap(int width, int height, int depth)
+Bitmap *CreateBitmap(int width, int height, int depth)
 {
   Bitmap *new_bitmap = CreateBitmapStruct();
   int real_depth = GetRealDepth(depth);
@@ -393,7 +370,7 @@ inline static void TransferBitmapPointers(Bitmap *src_bitmap,
   *dst_bitmap = *src_bitmap;
 }
 
-inline void FreeBitmap(Bitmap *bitmap)
+void FreeBitmap(Bitmap *bitmap)
 {
   if (bitmap == NULL)
     return;
@@ -403,7 +380,7 @@ inline void FreeBitmap(Bitmap *bitmap)
   free(bitmap);
 }
 
-inline void CloseWindow(DrawWindow *window)
+void CloseWindow(DrawWindow *window)
 {
 #if defined(TARGET_X11)
   if (window->drawable)
@@ -416,7 +393,7 @@ inline void CloseWindow(DrawWindow *window)
 #endif
 }
 
-static inline boolean CheckDrawingArea(int x, int y, int width, int height,
+inline static boolean CheckDrawingArea(int x, int y, int width, int height,
                                       int draw_mask)
 {
   if (draw_mask == REDRAW_NONE)
@@ -437,25 +414,20 @@ static inline boolean CheckDrawingArea(int x, int y, int width, int height,
   return FALSE;
 }
 
-inline boolean DrawingDeactivated(int x, int y, int width, int height)
+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)
+boolean DrawingOnBackground(int x, int y)
 {
-#if 1
   return (CheckDrawingArea(x, y, 1, 1, gfx.background_bitmap_mask) &&
          CheckDrawingArea(x, y, 1, 1, gfx.draw_background_mask));
-#else
-  return ((gfx.draw_background_mask & gfx.background_bitmap_mask) &&
-         CheckDrawingArea(x, y, 1, 1, gfx.draw_background_mask));
-#endif
 }
 
-inline void BlitBitmap(Bitmap *src_bitmap, Bitmap *dst_bitmap,
-                      int src_x, int src_y, int width, int height,
-                      int dst_x, int dst_y)
+void BlitBitmap(Bitmap *src_bitmap, Bitmap *dst_bitmap,
+               int src_x, int src_y, int width, int height,
+               int dst_x, int dst_y)
 {
   if (DrawingDeactivated(dst_x, dst_y, width, height))
     return;
@@ -464,8 +436,18 @@ inline void BlitBitmap(Bitmap *src_bitmap, Bitmap *dst_bitmap,
              dst_x, dst_y, BLIT_OPAQUE);
 }
 
-inline void FillRectangle(Bitmap *bitmap, int x, int y, int width, int height,
-                         Pixel color)
+void FadeScreen(Bitmap *bitmap_cross, int fade_mode, int fade_delay,
+               int post_delay)
+{
+#if defined(TARGET_SDL)
+  SDLFadeScreen(bitmap_cross, fade_mode, fade_delay, post_delay);
+#else
+  X11FadeScreen(bitmap_cross, fade_mode, fade_delay, post_delay);
+#endif
+}
+
+void FillRectangle(Bitmap *bitmap, int x, int y, int width, int height,
+                  Pixel color)
 {
   if (DrawingDeactivated(x, y, width, height))
     return;
@@ -473,13 +455,13 @@ inline void FillRectangle(Bitmap *bitmap, int x, int y, int width, int height,
   sysFillRectangle(bitmap, x, y, width, height, color);
 }
 
-inline void ClearRectangle(Bitmap *bitmap, int x, int y, int width, int height)
+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)
+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);
@@ -487,13 +469,7 @@ inline void ClearRectangleOnBackground(Bitmap *bitmap, int x, int y,
     ClearRectangle(bitmap, x, y, width, height);
 }
 
-#if 0
-#ifndef TARGET_SDL
-static GC last_clip_gc = 0;    /* needed for XCopyArea() through clip mask */
-#endif
-#endif
-
-inline void SetClipMask(Bitmap *bitmap, GC clip_gc, Pixmap clip_pixmap)
+void SetClipMask(Bitmap *bitmap, GC clip_gc, Pixmap clip_pixmap)
 {
 #if defined(TARGET_X11)
   if (clip_gc)
@@ -501,13 +477,10 @@ inline void SetClipMask(Bitmap *bitmap, GC clip_gc, Pixmap clip_pixmap)
     bitmap->clip_gc = clip_gc;
     XSetClipMask(display, bitmap->clip_gc, clip_pixmap);
   }
-#if 0
-  last_clip_gc = clip_gc;
-#endif
 #endif
 }
 
-inline void SetClipOrigin(Bitmap *bitmap, GC clip_gc, int clip_x, int clip_y)
+void SetClipOrigin(Bitmap *bitmap, GC clip_gc, int clip_x, int clip_y)
 {
 #if defined(TARGET_X11)
   if (clip_gc)
@@ -515,16 +488,12 @@ inline void SetClipOrigin(Bitmap *bitmap, GC clip_gc, int clip_x, int clip_y)
     bitmap->clip_gc = clip_gc;
     XSetClipOrigin(display, bitmap->clip_gc, clip_x, clip_y);
   }
-#if 0
-  last_clip_gc = clip_gc;
-#endif
 #endif
 }
 
-inline void BlitBitmapMasked(Bitmap *src_bitmap, Bitmap *dst_bitmap,
-                            int src_x, int src_y,
-                            int width, int height,
-                            int dst_x, int dst_y)
+void BlitBitmapMasked(Bitmap *src_bitmap, Bitmap *dst_bitmap,
+                     int src_x, int src_y, int width, int height,
+                     int dst_x, int dst_y)
 {
   if (DrawingDeactivated(dst_x, dst_y, width, height))
     return;
@@ -533,10 +502,9 @@ inline void BlitBitmapMasked(Bitmap *src_bitmap, Bitmap *dst_bitmap,
              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)
+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))
   {
@@ -555,8 +523,18 @@ inline void BlitBitmapOnBackground(Bitmap *src_bitmap, Bitmap *dst_bitmap,
               dst_x, dst_y);
 }
 
-inline void DrawSimpleWhiteLine(Bitmap *bitmap, int from_x, int from_y,
-                               int to_x, int to_y)
+void DrawSimpleBlackLine(Bitmap *bitmap, int from_x, int from_y,
+                        int to_x, int to_y)
+{
+#if defined(TARGET_SDL)
+  SDLDrawSimpleLine(bitmap, from_x, from_y, to_x, to_y, BLACK_PIXEL);
+#else
+  X11DrawSimpleLine(bitmap, from_x, from_y, to_x, to_y, BLACK_PIXEL);
+#endif
+}
+
+void DrawSimpleWhiteLine(Bitmap *bitmap, int from_x, int from_y,
+                        int to_x, int to_y)
 {
 #if defined(TARGET_SDL)
   SDLDrawSimpleLine(bitmap, from_x, from_y, to_x, to_y, WHITE_PIXEL);
@@ -566,8 +544,8 @@ inline void DrawSimpleWhiteLine(Bitmap *bitmap, int from_x, int from_y,
 }
 
 #if !defined(TARGET_X11_NATIVE)
-inline void DrawLine(Bitmap *bitmap, int from_x, int from_y,
-                    int to_x, int to_y, Pixel pixel, int line_width)
+void DrawLine(Bitmap *bitmap, int from_x, int from_y,
+             int to_x, int to_y, Pixel pixel, int line_width)
 {
   int x, y;
 
@@ -596,8 +574,7 @@ inline void DrawLine(Bitmap *bitmap, int from_x, int from_y,
 }
 #endif
 
-inline void DrawLines(Bitmap *bitmap, struct XY *points, int num_points,
-                     Pixel pixel)
+void DrawLines(Bitmap *bitmap, struct XY *points, int num_points, Pixel pixel)
 {
 #if !defined(TARGET_X11_NATIVE)
   int line_width = 4;
@@ -617,7 +594,7 @@ inline void DrawLines(Bitmap *bitmap, struct XY *points, int num_points,
 #endif
 }
 
-inline Pixel GetPixel(Bitmap *bitmap, int x, int y)
+Pixel GetPixel(Bitmap *bitmap, int x, int y)
 {
   if (x < 0 || x >= bitmap->width ||
       y < 0 || y >= bitmap->height)
@@ -632,8 +609,8 @@ inline Pixel GetPixel(Bitmap *bitmap, int x, int y)
 #endif
 }
 
-inline Pixel GetPixelFromRGB(Bitmap *bitmap, unsigned int color_r,
-                            unsigned int color_g, unsigned int color_b)
+Pixel GetPixelFromRGB(Bitmap *bitmap, unsigned int color_r,
+                     unsigned int color_g, unsigned int color_b)
 {
 #if defined(TARGET_SDL)
   return SDL_MapRGB(bitmap->surface->format, color_r, color_g, color_b);
@@ -644,7 +621,7 @@ inline Pixel GetPixelFromRGB(Bitmap *bitmap, unsigned int color_r,
 #endif
 }
 
-inline Pixel GetPixelFromRGBcompact(Bitmap *bitmap, unsigned int color)
+Pixel GetPixelFromRGBcompact(Bitmap *bitmap, unsigned int color)
 {
   unsigned int color_r = (color >> 16) & 0xff;
   unsigned int color_g = (color >>  8) & 0xff;
@@ -654,7 +631,7 @@ inline Pixel GetPixelFromRGBcompact(Bitmap *bitmap, unsigned int color)
 }
 
 /* execute all pending screen drawing operations */
-inline void FlushDisplay(void)
+void FlushDisplay(void)
 {
 #ifndef TARGET_SDL
   XFlush(display);
@@ -662,14 +639,14 @@ inline void FlushDisplay(void)
 }
 
 /* execute and wait for all pending screen drawing operations */
-inline void SyncDisplay(void)
+void SyncDisplay(void)
 {
 #ifndef TARGET_SDL
   XSync(display, FALSE);
 #endif
 }
 
-inline void KeyboardAutoRepeatOn(void)
+void KeyboardAutoRepeatOn(void)
 {
 #if defined(TARGET_SDL)
   SDL_EnableKeyRepeat(SDL_DEFAULT_REPEAT_DELAY / 2,
@@ -681,7 +658,7 @@ inline void KeyboardAutoRepeatOn(void)
 #endif
 }
 
-inline void KeyboardAutoRepeatOff(void)
+void KeyboardAutoRepeatOff(void)
 {
 #if defined(TARGET_SDL)
   SDL_EnableKeyRepeat(0, SDL_DEFAULT_REPEAT_INTERVAL);
@@ -692,7 +669,7 @@ inline void KeyboardAutoRepeatOff(void)
 #endif
 }
 
-inline boolean PointerInWindow(DrawWindow *window)
+boolean PointerInWindow(DrawWindow *window)
 {
 #if defined(TARGET_SDL)
   return TRUE;
@@ -709,7 +686,7 @@ inline boolean PointerInWindow(DrawWindow *window)
 #endif
 }
 
-inline boolean SetVideoMode(boolean fullscreen)
+boolean SetVideoMode(boolean fullscreen)
 {
 #if defined(TARGET_SDL)
   return SDLSetVideoMode(&backbuffer, fullscreen);
@@ -730,7 +707,7 @@ inline boolean SetVideoMode(boolean fullscreen)
 #endif
 }
 
-inline boolean ChangeVideoModeIfNeeded(boolean fullscreen)
+boolean ChangeVideoModeIfNeeded(boolean fullscreen)
 {
 #if defined(TARGET_SDL)
   if ((fullscreen && !video.fullscreen_enabled && video.fullscreen_available)||
@@ -782,7 +759,7 @@ void ReloadCustomImage(Bitmap *bitmap, char *basename)
     return;
   }
 
-  if (strcmp(filename, bitmap->source_filename) == 0)
+  if (strEqual(filename, bitmap->source_filename))
   {
     /* The old and new image are the same (have the same filename and path).
        This usually means that this image does not exist in this graphic set
@@ -823,19 +800,17 @@ Bitmap *ZoomBitmap(Bitmap *src_bitmap, int zoom_width, int zoom_height)
   return dst_bitmap;
 }
 
-void CreateBitmapWithSmallBitmaps(Bitmap *old_bitmap, int zoom_factor)
+static void CreateScaledBitmaps(Bitmap *old_bitmap, int zoom_factor,
+                               boolean create_small_bitmaps)
 {
   Bitmap swap_bitmap;
   Bitmap *new_bitmap, *tmp_bitmap_1, *tmp_bitmap_2, *tmp_bitmap_8;
   int width_1, height_1, width_2, height_2, width_8, height_8;
   int new_width, new_height;
 
+  /* calculate new image dimensions for normal sized image */
   width_1  = old_bitmap->width  * zoom_factor;
   height_1 = old_bitmap->height * zoom_factor;
-  width_2  = width_1  / 2;
-  height_2 = height_1 / 2;
-  width_8  = width_1  / 8;
-  height_8 = height_1 / 8;
 
   /* get image with normal size (this might require scaling up) */
   if (zoom_factor != 1)
@@ -843,17 +818,29 @@ void CreateBitmapWithSmallBitmaps(Bitmap *old_bitmap, int zoom_factor)
   else
     tmp_bitmap_1 = old_bitmap;
 
-  /* get image with 1/2 of normal size (for use in the level editor) */
-  if (zoom_factor != 2)
-    tmp_bitmap_2 = ZoomBitmap(tmp_bitmap_1, width_1 / 2, height_1 / 2);
-  else
-    tmp_bitmap_2 = old_bitmap;
+  /* this is only needed to make compilers happy */
+  tmp_bitmap_2 = tmp_bitmap_8 = NULL;
 
-  /* get image with 1/8 of normal size (for use on the preview screen) */
-  if (zoom_factor != 8)
-    tmp_bitmap_8 = ZoomBitmap(tmp_bitmap_1, width_1 / 8, height_1 / 8);
-  else
-    tmp_bitmap_8 = old_bitmap;
+  if (create_small_bitmaps)
+  {
+    /* calculate new image dimensions for small images */
+    width_2  = width_1  / 2;
+    height_2 = height_1 / 2;
+    width_8  = width_1  / 8;
+    height_8 = height_1 / 8;
+
+    /* get image with 1/2 of normal size (for use in the level editor) */
+    if (zoom_factor != 2)
+      tmp_bitmap_2 = ZoomBitmap(tmp_bitmap_1, width_1 / 2, height_1 / 2);
+    else
+      tmp_bitmap_2 = old_bitmap;
+
+    /* get image with 1/8 of normal size (for use on the preview screen) */
+    if (zoom_factor != 8)
+      tmp_bitmap_8 = ZoomBitmap(tmp_bitmap_1, width_1 / 8, height_1 / 8);
+    else
+      tmp_bitmap_8 = old_bitmap;
+  }
 
   /* if image was scaled up, create new clipmask for normal size image */
   if (zoom_factor != 1)
@@ -880,39 +867,39 @@ void CreateBitmapWithSmallBitmaps(Bitmap *old_bitmap, int zoom_factor)
 #endif
   }
 
-  new_width  = width_1;
-  new_height = height_1 + (height_1 + 1) / 2;     /* prevent odd height */
-
-  new_bitmap = CreateBitmap(new_width, new_height, DEFAULT_DEPTH);
+  if (create_small_bitmaps)
+  {
+    new_width  = width_1;
+    new_height = height_1 + (height_1 + 1) / 2;     /* prevent odd height */
 
-  BlitBitmap(tmp_bitmap_1, new_bitmap, 0, 0, width_1, height_1, 0, 0);
-  BlitBitmap(tmp_bitmap_2, new_bitmap, 0, 0, width_1 / 2, height_1 / 2,
-            0, height_1);
-  BlitBitmap(tmp_bitmap_8, new_bitmap, 0, 0, width_1 / 8, height_1 / 8,
-            3 * width_1 / 4, height_1);
+    new_bitmap = CreateBitmap(new_width, new_height, DEFAULT_DEPTH);
 
-  if (zoom_factor != 1)
-    FreeBitmap(tmp_bitmap_1);
-
-  if (zoom_factor != 2)
-    FreeBitmap(tmp_bitmap_2);
+    BlitBitmap(tmp_bitmap_1, new_bitmap, 0, 0, width_1, height_1, 0, 0);
+    BlitBitmap(tmp_bitmap_2, new_bitmap, 0, 0, width_1 / 2, height_1 / 2,
+              0, height_1);
+    BlitBitmap(tmp_bitmap_8, new_bitmap, 0, 0, width_1 / 8, height_1 / 8,
+              3 * width_1 / 4, height_1);
+  }
+  else
+  {
+    new_width  = width_1;
+    new_height = height_1;
 
-  if (zoom_factor != 8)
-    FreeBitmap(tmp_bitmap_8);
+    new_bitmap = tmp_bitmap_1; /* directly use tmp_bitmap_1 as new bitmap */
+  }
 
-#if 0
+  if (create_small_bitmaps)
+  {
+    /* if no small bitmaps created, tmp_bitmap_1 is used as new bitmap now */
+    if (zoom_factor != 1)
+      FreeBitmap(tmp_bitmap_1);
 
-#if defined(TARGET_SDL)
-  /* !!! what about the old old_bitmap->surface ??? FIX ME !!! */
-  old_bitmap->surface = new_bitmap->surface;
-  new_bitmap->surface = NULL;
-#else
-  /* !!! see above !!! */
-  old_bitmap->drawable = new_bitmap->drawable;
-  new_bitmap->drawable = None;
-#endif
+    if (zoom_factor != 2)
+      FreeBitmap(tmp_bitmap_2);
 
-#else
+    if (zoom_factor != 8)
+      FreeBitmap(tmp_bitmap_8);
+  }
 
   /* replace image with extended image (containing normal, 1/2 and 1/8 size) */
 #if defined(TARGET_SDL)
@@ -923,14 +910,22 @@ void CreateBitmapWithSmallBitmaps(Bitmap *old_bitmap, int zoom_factor)
   swap_bitmap.drawable = old_bitmap->drawable;
   old_bitmap->drawable = new_bitmap->drawable;
   new_bitmap->drawable = swap_bitmap.drawable;
-#endif
-
 #endif
 
   old_bitmap->width  = new_bitmap->width;
   old_bitmap->height = new_bitmap->height;
 
-  FreeBitmap(new_bitmap);
+  FreeBitmap(new_bitmap);      /* this actually frees the _old_ bitmap now */
+}
+
+void CreateBitmapWithSmallBitmaps(Bitmap *old_bitmap, int zoom_factor)
+{
+  CreateScaledBitmaps(old_bitmap, zoom_factor, TRUE);
+}
+
+void ScaleBitmap(Bitmap *old_bitmap, int zoom_factor)
+{
+  CreateScaledBitmaps(old_bitmap, zoom_factor, FALSE);
 }
 
 
@@ -974,7 +969,9 @@ static const char *cursor_image_playfield[] =
 
   /* hot spot */
   "0,0"
+
 #else
+
   /* pixels */
   " X              ",
   "X.X             ",
@@ -1073,7 +1070,7 @@ void SetMouseCursor(int mode)
 /* audio functions                                                           */
 /* ========================================================================= */
 
-inline void OpenAudio(void)
+void OpenAudio(void)
 {
   /* always start with reliable default values */
   audio.sound_available = FALSE;
@@ -1101,7 +1098,7 @@ inline void OpenAudio(void)
 #endif
 }
 
-inline void CloseAudio(void)
+void CloseAudio(void)
 {
 #if defined(TARGET_SDL)
   SDLCloseAudio();
@@ -1114,7 +1111,7 @@ inline void CloseAudio(void)
   audio.sound_enabled = FALSE;
 }
 
-inline void SetAudioMode(boolean enabled)
+void SetAudioMode(boolean enabled)
 {
   if (!audio.sound_available)
     return;
@@ -1127,7 +1124,7 @@ inline void SetAudioMode(boolean enabled)
 /* event functions                                                           */
 /* ========================================================================= */
 
-inline void InitEventFilter(EventFilter filter_function)
+void InitEventFilter(EventFilter filter_function)
 {
 #if defined(TARGET_SDL)
   /* set event filter to filter out certain events */
@@ -1135,7 +1132,7 @@ inline void InitEventFilter(EventFilter filter_function)
 #endif
 }
 
-inline boolean PendingEvent(void)
+boolean PendingEvent(void)
 {
 #if defined(TARGET_SDL)
   return (SDL_PollEvent(NULL) ? TRUE : FALSE);
@@ -1144,7 +1141,7 @@ inline boolean PendingEvent(void)
 #endif
 }
 
-inline void NextEvent(Event *event)
+void NextEvent(Event *event)
 {
 #if defined(TARGET_SDL)
   SDLNextEvent(event);
@@ -1153,7 +1150,7 @@ inline void NextEvent(Event *event)
 #endif
 }
 
-inline void PeekEvent(Event *event)
+void PeekEvent(Event *event)
 {
 #if defined(TARGET_SDL)
   SDL_PeepEvents(event, 1, SDL_PEEKEVENT, SDL_ALLEVENTS);
@@ -1162,9 +1159,10 @@ inline void PeekEvent(Event *event)
 #endif
 }
 
-inline Key GetEventKey(KeyEvent *event, boolean with_modifiers)
+Key GetEventKey(KeyEvent *event, boolean with_modifiers)
 {
 #if defined(TARGET_SDL)
+
 #if 0
   printf("unicode == '%d', sym == '%d', mod == '0x%04x'\n",
         (int)event->keysym.unicode,
@@ -1178,7 +1176,9 @@ inline Key GetEventKey(KeyEvent *event, boolean with_modifiers)
     return event->keysym.unicode;
   else
     return event->keysym.sym;
+
 #else
+
 #if 0
   printf("with modifiers == '0x%04x', without modifiers == '0x%04x'\n",
         (int)XLookupKeysym(event, event->state),
@@ -1192,7 +1192,7 @@ inline Key GetEventKey(KeyEvent *event, boolean with_modifiers)
 #endif
 }
 
-inline KeyMod HandleKeyModState(Key key, int key_status)
+KeyMod HandleKeyModState(Key key, int key_status)
 {
   static KeyMod current_modifiers = KMOD_None;
 
@@ -1241,7 +1241,7 @@ inline KeyMod HandleKeyModState(Key key, int key_status)
   return current_modifiers;
 }
 
-inline KeyMod GetKeyModState()
+KeyMod GetKeyModState()
 {
 #if defined(TARGET_SDL)
   return (KeyMod)SDL_GetModState();
@@ -1250,7 +1250,7 @@ inline KeyMod GetKeyModState()
 #endif
 }
 
-inline boolean CheckCloseWindowEvent(ClientMessageEvent *event)
+boolean CheckCloseWindowEvent(ClientMessageEvent *event)
 {
   if (event->type != EVENT_CLIENTMESSAGE)
     return FALSE;
@@ -1271,7 +1271,7 @@ inline boolean CheckCloseWindowEvent(ClientMessageEvent *event)
 /* joystick functions                                                        */
 /* ========================================================================= */
 
-inline void InitJoysticks()
+void InitJoysticks()
 {
   int i;
 
@@ -1291,9 +1291,14 @@ inline void InitJoysticks()
 #elif defined(PLATFORM_MSDOS)
   MSDOSInitJoysticks();
 #endif
+
+#if 0
+  for (i = 0; i < MAX_PLAYERS; i++)
+    printf("::: Joystick for player %d: %d\n", i, joystick.fd[i]);
+#endif
 }
 
-inline boolean ReadJoystick(int nr, int *x, int *y, boolean *b1, boolean *b2)
+boolean ReadJoystick(int nr, int *x, int *y, boolean *b1, boolean *b2)
 {
 #if defined(TARGET_SDL)
   return SDLReadJoystick(nr, x, y, b1, b2);
index 0b210ed01f0584645db71364b390fbfa5700432a..9d90cd9969e29540aa0548cec0a51b01435dcd88 100644 (file)
 
 
 /* the additional 'b' is needed for Win32 to open files in binary mode */
-#define MODE_READ              "rb"
-#define MODE_WRITE             "wb"
-#define MODE_APPEND            "ab"
+#define MODE_READ                      "rb"
+#define MODE_WRITE                     "wb"
+#define MODE_APPEND                    "ab"
 
-#define DEFAULT_DEPTH          0
+#define DEFAULT_DEPTH                  0
 
-#define BLIT_OPAQUE            0
-#define BLIT_MASKED            1
-#define BLIT_INVERSE           2
-#define BLIT_ON_BACKGROUND     3
+#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 FULLSCREEN_NOT_AVAILABLE       FALSE
+#define FULLSCREEN_AVAILABLE           TRUE
 
 /* default input keys */
-#define DEFAULT_KEY_LEFT       KSYM_Left
-#define DEFAULT_KEY_RIGHT      KSYM_Right
-#define DEFAULT_KEY_UP         KSYM_Up
-#define DEFAULT_KEY_DOWN       KSYM_Down
+#define DEFAULT_KEY_LEFT               KSYM_Left
+#define DEFAULT_KEY_RIGHT              KSYM_Right
+#define DEFAULT_KEY_UP                 KSYM_Up
+#define DEFAULT_KEY_DOWN               KSYM_Down
 #if defined(PLATFORM_MACOSX)
-#define DEFAULT_KEY_SNAP       KSYM_Control_L
-#define DEFAULT_KEY_DROP       KSYM_KP_Enter
+#define DEFAULT_KEY_SNAP               KSYM_Control_L
+#define DEFAULT_KEY_DROP               KSYM_KP_Enter
 #else
-#define DEFAULT_KEY_SNAP       KSYM_Control_L
-#define DEFAULT_KEY_DROP       KSYM_Control_R
+#define DEFAULT_KEY_SNAP               KSYM_Control_L
+#define DEFAULT_KEY_DROP               KSYM_Control_R
 #endif
-#define DEFAULT_KEY_OKAY       KSYM_Return
-#define DEFAULT_KEY_CANCEL     KSYM_Escape
+#define DEFAULT_KEY_OKAY               KSYM_Return
+#define DEFAULT_KEY_CANCEL             KSYM_Escape
 
 /* default shortcut keys */
-#define DEFAULT_KEY_SAVE_GAME  KSYM_F1
-#define DEFAULT_KEY_LOAD_GAME  KSYM_F2
-#define DEFAULT_KEY_TOGGLE_PAUSE KSYM_space
+#define DEFAULT_KEY_SAVE_GAME          KSYM_F1
+#define DEFAULT_KEY_LOAD_GAME          KSYM_F2
+#define DEFAULT_KEY_TOGGLE_PAUSE       KSYM_space
+#define DEFAULT_KEY_FOCUS_PLAYER_1     KSYM_F5
+#define DEFAULT_KEY_FOCUS_PLAYER_2     KSYM_F6
+#define DEFAULT_KEY_FOCUS_PLAYER_3     KSYM_F7
+#define DEFAULT_KEY_FOCUS_PLAYER_4     KSYM_F8
+#define DEFAULT_KEY_FOCUS_PLAYER_ALL   KSYM_F9
 
 /* values for key_status */
-#define KEY_NOT_PRESSED                FALSE
-#define KEY_RELEASED           FALSE
-#define KEY_PRESSED            TRUE
+#define KEY_NOT_PRESSED                        FALSE
+#define KEY_RELEASED                   FALSE
+#define KEY_PRESSED                    TRUE
 
 /* values for button status */
-#define MB_NOT_PRESSED         FALSE
-#define MB_NOT_RELEASED                TRUE
-#define MB_RELEASED            FALSE
-#define MB_PRESSED             TRUE
-#define MB_MENU_CHOICE         FALSE
-#define MB_MENU_MARK           TRUE
-#define MB_MENU_INITIALIZE     (-1)
-#define MB_MENU_LEAVE          (-2)
-#define MB_LEFTBUTTON          1
-#define MB_MIDDLEBUTTON                2
-#define MB_RIGHTBUTTON         3
+#define MB_NOT_PRESSED                 FALSE
+#define MB_NOT_RELEASED                        TRUE
+#define MB_RELEASED                    FALSE
+#define MB_PRESSED                     TRUE
+#define MB_MENU_CHOICE                 FALSE
+#define MB_MENU_MARK                   TRUE
+#define MB_MENU_INITIALIZE             (-1)
+#define MB_MENU_LEAVE                  (-2)
+#define MB_LEFTBUTTON                  1
+#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 MV_BIT_LEFT                    0
+#define MV_BIT_RIGHT                   1
+#define MV_BIT_UP                      2
+#define MV_BIT_DOWN                    3
 
-#define NUM_DIRECTIONS         4
+#define NUM_DIRECTIONS                 4
+
+/* diagonal movement directions are used in a different contect than buttons */
+#define MV_BIT_UPLEFT                  4
+#define MV_BIT_UPRIGHT                 5
+#define MV_BIT_DOWNLEFT                        6
+#define MV_BIT_DOWNRIGHT               7
+
+#define NUM_DIRECTIONS_FULL            8
 
 /* values for special "button" bitmasks */
-#define BUTTON_1               4
-#define BUTTON_2               5
+#define BUTTON_1                       4
+#define BUTTON_2                       5
+
+/* values for special "focus player" bitmasks */
+#define BIT_SET_FOCUS                  6
 
 /* values for move directions and special "button" key bitmasks */
-#define MV_NO_MOVING           0
+#define MV_NONE                        0
 #define MV_LEFT                        (1 << MV_BIT_LEFT)
 #define MV_RIGHT               (1 << MV_BIT_RIGHT)
 #define MV_UP                  (1 << MV_BIT_UP)
 #define MV_DOWN                        (1 << MV_BIT_DOWN)
 
+#define MV_UPLEFT              (MV_UP   | MV_LEFT)
+#define MV_UPRIGHT             (MV_UP   | MV_RIGHT)
+#define MV_DOWNLEFT            (MV_DOWN | MV_LEFT)
+#define MV_DOWNRIGHT           (MV_DOWN | MV_RIGHT)
+
 #define MV_HORIZONTAL          (MV_LEFT | MV_RIGHT)
 #define MV_VERTICAL            (MV_UP   | MV_DOWN)
 #define MV_ALL_DIRECTIONS      (MV_LEFT | MV_RIGHT | MV_UP | MV_DOWN)
 #define MV_ANY_DIRECTION       (MV_ALL_DIRECTIONS)
-#define MV_NO_DIRECTIONS       (MV_NO_MOVING)
+#define MV_NO_DIRECTION                (MV_NONE)
 
 #define KEY_BUTTON_1           (1 << BUTTON_1)
 #define KEY_BUTTON_2           (1 << BUTTON_2)
 #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)
-
-#define MV_DIR_OPPOSITE(x)     ((x) == MV_LEFT  ? MV_RIGHT :           \
-                                (x) == MV_RIGHT ? MV_LEFT  :           \
-                                (x) == MV_UP    ? MV_DOWN  :           \
-                                (x) == MV_DOWN  ? MV_UP    : MV_NO_MOVING)
-
+#define KEY_SET_FOCUS          (1 << BIT_SET_FOCUS)
+
+#define MV_DIR_FROM_BIT(x)     ((x) < NUM_DIRECTIONS ? 1 << (x) :        \
+                                (x) == MV_BIT_UPLEFT    ? MV_UPLEFT    : \
+                                (x) == MV_BIT_UPRIGHT   ? MV_UPRIGHT   : \
+                                (x) == MV_BIT_DOWNLEFT  ? MV_DOWNLEFT  : \
+                                (x) == MV_BIT_DOWNRIGHT ? MV_DOWNRIGHT : \
+                                MV_NONE)
+
+#define MV_DIR_TO_BIT(x)       ((x) == MV_LEFT      ? MV_BIT_LEFT      : \
+                                (x) == MV_RIGHT     ? MV_BIT_RIGHT     : \
+                                (x) == MV_UP        ? MV_BIT_UP        : \
+                                (x) == MV_DOWN      ? MV_BIT_DOWN      : \
+                                (x) == MV_UPLEFT    ? MV_BIT_UPLEFT    : \
+                                (x) == MV_UPRIGHT   ? MV_BIT_UPRIGHT   : \
+                                (x) == MV_DOWNLEFT  ? MV_BIT_DOWNLEFT  : \
+                                (x) == MV_DOWNRIGHT ? MV_BIT_DOWNRIGHT : \
+                                MV_BIT_DOWN)
+
+#define MV_DIR_OPPOSITE(x)     ((x) == MV_LEFT      ? MV_RIGHT     : \
+                                (x) == MV_RIGHT     ? MV_LEFT      : \
+                                (x) == MV_UP        ? MV_DOWN      : \
+                                (x) == MV_DOWN      ? MV_UP        : \
+                                (x) == MV_UPLEFT    ? MV_DOWNRIGHT : \
+                                (x) == MV_UPRIGHT   ? MV_DOWNLEFT  : \
+                                (x) == MV_DOWNLEFT  ? MV_UPRIGHT   : \
+                                (x) == MV_DOWNRIGHT ? MV_UPLEFT    : \
+                                MV_NONE)
 
 /* values for animation mode (frame order and direction) */
 #define ANIM_NONE              0
 #define ANIM_PINGPONG          (1 << 2)
 #define ANIM_PINGPONG2         (1 << 3)
 #define ANIM_RANDOM            (1 << 4)
-#define ANIM_REVERSE           (1 << 5)
+#define ANIM_CE_VALUE          (1 << 5)
+#define ANIM_CE_SCORE          (1 << 6)
+#define ANIM_CE_DELAY          (1 << 7)
+#define ANIM_REVERSE           (1 << 8)
+#define ANIM_OPAQUE_PLAYER     (1 << 9)
 
 /* values for special (non game element) animation modes */
-#define ANIM_HORIZONTAL                (1 << 6)
-#define ANIM_VERTICAL          (1 << 7)
+#define ANIM_HORIZONTAL                (1 << 10)
+#define ANIM_VERTICAL          (1 << 11)
+#define ANIM_STATIC_PANEL      (1 << 12)
 
 #define ANIM_DEFAULT           ANIM_LOOP
 
 #define REDRAW_FPS             (1 << 11)
 #define REDRAWTILES_THRESHOLD  (SCR_FIELDX * SCR_FIELDY / 2)
 
+#define FADE_MODE_FADE_IN      0
+#define FADE_MODE_FADE_OUT     1
+#define FADE_MODE_CROSSFADE    2
+
 #define IN_GFX_SCREEN(x, y)    (x >= gfx.sx && x < gfx.sx + gfx.sxsize && \
                                 y >= gfx.sy && y < gfx.sy + gfx.sysize)
 #define IN_GFX_DOOR(x, y)      (x >= gfx.dx && x < gfx.dx + gfx.dxsize && \
 #define CURSOR_DEFAULT         0
 #define CURSOR_PLAYFIELD       1
 
+/* fundamental game speed values */
+#define ONE_SECOND_DELAY       1000    /* delay value for one second */
+#define GAME_FRAME_DELAY       20      /* frame delay in milliseconds */
+#define FFWD_FRAME_DELAY       10      /* 200% speed for fast forward */
+#define FRAMES_PER_SECOND      (ONE_SECOND_DELAY / GAME_FRAME_DELAY)
+
+/* maximum playfield size supported by libgame functions */
+#define MAX_PLAYFIELD_WIDTH    128
+#define MAX_PLAYFIELD_HEIGHT   128
 
 /* maximum number of parallel players supported by libgame functions */
 #define MAX_PLAYERS            4
 #define SETUP_FILENAME         "setup.conf"
 #define LEVELSETUP_FILENAME    "levelsetup.conf"
 #define EDITORSETUP_FILENAME   "editorsetup.conf"
+#define EDITORCASCADE_FILENAME "editorcascade.conf"
 #define HELPANIM_FILENAME      "helpanim.conf"
 #define HELPTEXT_FILENAME      "helptext.conf"
 #define LEVELINFO_FILENAME     "levelinfo.conf"
 #define SETUP_FILENAME         "setup.cnf"
 #define LEVELSETUP_FILENAME    "lvlsetup.cnf"
 #define EDITORSETUP_FILENAME   "edsetup.cnf"
+#define EDITORCASCADE_FILENAME "edcascad.conf"
 #define HELPANIM_FILENAME      "helpanim.cnf"
 #define HELPTEXT_FILENAME      "helptext.cnf"
 #define LEVELINFO_FILENAME     "lvlinfo.cnf"
 
 #define ARTWORK_FIRST_NODE(artwork, type)                              \
                                ((type) == ARTWORK_TYPE_GRAPHICS ?      \
-                                (artwork).gfx_first :  \
+                                (artwork).gfx_first :                  \
                                 (type) == ARTWORK_TYPE_SOUNDS ?        \
-                                (artwork).snd_first :  \
+                                (artwork).snd_first :                  \
                                 (artwork).mus_first)
 
 #define ARTWORK_CURRENT_IDENTIFIER_PTR(artwork, type)                  \
@@ -506,9 +566,13 @@ struct AudioSystemInfo
 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 draw_xoffset;            /* offset for drawing font characters */
+  int draw_yoffset;            /* offset for drawing font characters */
+
   int num_chars;
   int num_chars_per_line;
 
@@ -586,10 +650,33 @@ struct SetupEditorInfo
   boolean el_dx_boulderdash;
   boolean el_chars;
   boolean el_custom;
-  boolean el_custom_more;
   boolean el_user_defined;
+  boolean el_dynamic;
 
   boolean el_headlines;
+
+  boolean el_by_game;
+  boolean el_by_type;
+
+  boolean show_element_token;
+};
+
+struct SetupEditorCascadeInfo
+{
+  boolean el_bd;
+  boolean el_em;
+  boolean el_emc;
+  boolean el_rnd;
+  boolean el_sb;
+  boolean el_sp;
+  boolean el_dc;
+  boolean el_dx;
+  boolean el_chars;
+  boolean el_ce;
+  boolean el_ge;
+  boolean el_ref;
+  boolean el_user;
+  boolean el_dynamic;
 };
 
 struct SetupShortcutInfo
@@ -597,6 +684,9 @@ struct SetupShortcutInfo
   Key save_game;
   Key load_game;
   Key toggle_pause;
+
+  Key focus_player[MAX_PLAYERS];
+  Key focus_player_all;
 };
 
 struct SetupSystemInfo
@@ -620,6 +710,7 @@ struct SetupInfo
   boolean soft_scrolling;
   boolean fading;
   boolean autorecord;
+  boolean show_titlescreen;
   boolean quick_doors;
   boolean team_mode;
   boolean handicap;
@@ -627,6 +718,10 @@ struct SetupInfo
   boolean time_limit;
   boolean fullscreen;
   boolean ask_on_escape;
+  boolean ask_on_escape_editor;
+  boolean quick_switch;
+  boolean input_on_focus;
+  boolean prefer_aga_graphics;
 
   char *graphics_set;
   char *sounds_set;
@@ -636,6 +731,7 @@ struct SetupInfo
   boolean override_level_music;
 
   struct SetupEditorInfo editor;
+  struct SetupEditorCascadeInfo editor_cascade;
   struct SetupShortcutInfo shortcut;
   struct SetupInputInfo input[MAX_PLAYERS];
   struct SetupSystemInfo system;
@@ -666,6 +762,8 @@ struct TreeInfo
   char *imported_from; /* optional comment for imported levels or artwork */
   char *imported_by;   /* optional comment for imported levels or artwork */
 
+  char *graphics_set_ecs; /* special EMC custom graphics set (ECS graphics) */
+  char *graphics_set_aga; /* special EMC custom graphics set (AGA graphics) */
   char *graphics_set;  /* optional custom graphics set (level tree only) */
   char *sounds_set;    /* optional custom sounds set (level tree only) */
   char *music_set;     /* optional custom music set (level tree only) */
@@ -832,6 +930,7 @@ extern struct ArtworkInfo   artwork;
 extern struct JoystickInfo     joystick;
 extern struct SetupInfo                setup;
 
+extern LevelDirTree           *leveldir_first_all;
 extern LevelDirTree           *leveldir_first;
 extern LevelDirTree           *leveldir_current;
 extern int                     level_nr;
@@ -872,35 +971,36 @@ void SetDrawBackgroundMask(int);
 void SetMainBackgroundBitmap(Bitmap *);
 void SetDoorBackgroundBitmap(Bitmap *);
 
-inline void InitVideoDisplay(void);
-inline void CloseVideoDisplay(void);
-inline void InitVideoBuffer(DrawBuffer **,DrawWindow **, int,int,int, boolean);
-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);
-inline Pixel GetPixelFromRGB(Bitmap *, unsigned int,unsigned int,unsigned int);
-inline Pixel GetPixelFromRGBcompact(Bitmap *, unsigned int);
-
-inline void FlushDisplay(void);
-inline void SyncDisplay(void);
-inline void KeyboardAutoRepeatOn(void);
-inline void KeyboardAutoRepeatOff(void);
-inline boolean PointerInWindow(DrawWindow *);
-inline boolean SetVideoMode(boolean);
-inline boolean ChangeVideoModeIfNeeded(boolean);
+void InitVideoDisplay(void);
+void CloseVideoDisplay(void);
+void InitVideoBuffer(DrawBuffer **,DrawWindow **, int,int,int, boolean);
+Bitmap *CreateBitmapStruct(void);
+Bitmap *CreateBitmap(int, int, int);
+void FreeBitmap(Bitmap *);
+void BlitBitmap(Bitmap *, Bitmap *, int, int, int, int, int, int);
+void FadeScreen(Bitmap *bitmap, int, int, int);
+void FillRectangle(Bitmap *, int, int, int, int, Pixel);
+void ClearRectangle(Bitmap *, int, int, int, int);
+void ClearRectangleOnBackground(Bitmap *, int, int, int, int);
+void SetClipMask(Bitmap *, GC, Pixmap);
+void SetClipOrigin(Bitmap *, GC, int, int);
+void BlitBitmapMasked(Bitmap *, Bitmap *, int, int, int, int, int, int);
+boolean DrawingOnBackground(int, int);
+void BlitBitmapOnBackground(Bitmap *, Bitmap *, int, int, int, int, int, int);
+void DrawSimpleBlackLine(Bitmap *, int, int, int, int);
+void DrawSimpleWhiteLine(Bitmap *, int, int, int, int);
+void DrawLines(Bitmap *, struct XY *, int, Pixel);
+Pixel GetPixel(Bitmap *, int, int);
+Pixel GetPixelFromRGB(Bitmap *, unsigned int,unsigned int,unsigned int);
+Pixel GetPixelFromRGBcompact(Bitmap *, unsigned int);
+
+void FlushDisplay(void);
+void SyncDisplay(void);
+void KeyboardAutoRepeatOn(void);
+void KeyboardAutoRepeatOff(void);
+boolean PointerInWindow(DrawWindow *);
+boolean SetVideoMode(boolean);
+boolean ChangeVideoModeIfNeeded(boolean);
 
 Bitmap *LoadImage(char *);
 Bitmap *LoadCustomImage(char *);
@@ -908,23 +1008,24 @@ void ReloadCustomImage(Bitmap *, char *);
 
 Bitmap *ZoomBitmap(Bitmap *, int, int);
 void CreateBitmapWithSmallBitmaps(Bitmap *, int);
+void ScaleBitmap(Bitmap *, int);
 
 void SetMouseCursor(int);
 
-inline void OpenAudio(void);
-inline void CloseAudio(void);
-inline void SetAudioMode(boolean);
-
-inline void InitEventFilter(EventFilter);
-inline boolean PendingEvent(void);
-inline void NextEvent(Event *event);
-inline void PeekEvent(Event *event);
-inline Key GetEventKey(KeyEvent *, boolean);
-inline KeyMod HandleKeyModState(Key, int);
-inline KeyMod GetKeyModState();
-inline boolean CheckCloseWindowEvent(ClientMessageEvent *);
-
-inline void InitJoysticks();
-inline boolean ReadJoystick(int, int *, int *, boolean *, boolean *);
+void OpenAudio(void);
+void CloseAudio(void);
+void SetAudioMode(boolean);
+
+void InitEventFilter(EventFilter);
+boolean PendingEvent(void);
+void NextEvent(Event *event);
+void PeekEvent(Event *event);
+Key GetEventKey(KeyEvent *, boolean);
+KeyMod HandleKeyModState(Key, int);
+KeyMod GetKeyModState();
+boolean CheckCloseWindowEvent(ClientMessageEvent *);
+
+void InitJoysticks();
+boolean ReadJoystick(int, int *, int *, boolean *, boolean *);
 
 #endif /* SYSTEM_H */
index 6fd437359014dad05bcacdf93216028f74cab43b..45de4987c279401ae4654f72b73a915e7a8817e7 100644 (file)
@@ -130,6 +130,13 @@ void FreeFontInfo(struct FontBitmapInfo *font_bitmap_info)
   free(font_bitmap_info);
 }
 
+struct FontBitmapInfo *getFontBitmapInfo(int font_nr)
+{
+  int font_bitmap_id = gfx.select_font_function(font_nr);
+
+  return &gfx.font_bitmap_info[font_bitmap_id];
+}
+
 int getFontWidth(int font_nr)
 {
   int font_bitmap_id = gfx.select_font_function(font_nr);
@@ -255,6 +262,11 @@ void DrawTextExt(DrawBuffer *dst_bitmap, int dst_x, int dst_y, char *text,
   struct FontBitmapInfo *font = &gfx.font_bitmap_info[font_bitmap_id];
   int font_width = getFontWidth(font_nr);
   int font_height = getFontHeight(font_nr);
+#if 0
+  int border_1 = gfx.sx + gfx.sxsize;
+  int border_2 = gfx.dx + gfx.dxsize;
+  int dst_x_start = dst_x;
+#endif
   Bitmap *src_bitmap;
   int src_x, src_y;
   char *text_ptr = text;
@@ -262,9 +274,13 @@ void DrawTextExt(DrawBuffer *dst_bitmap, int dst_x, int dst_y, char *text,
   if (font->bitmap == NULL)
     return;
 
+  /* skip text to be printed outside the window (left/right will be clipped) */
+  if (dst_y < 0 || dst_y + font_height > video.height)
+    return;
+
   /* add offset for drawing font characters */
-  dst_x += font->draw_x;
-  dst_y += font->draw_y;
+  dst_x += font->draw_xoffset;
+  dst_y += font->draw_yoffset;
 
   while (*text_ptr)
   {
@@ -275,6 +291,25 @@ void DrawTextExt(DrawBuffer *dst_bitmap, int dst_x, int dst_y, char *text,
 
     getFontCharSource(font_nr, c, &src_bitmap, &src_x, &src_y);
 
+    /* clip text at the left side of the window */
+    if (dst_x < 0)
+    {
+      dst_x += font_width;
+
+      continue;
+    }
+
+    /* clip text at the right side of the window */
+#if 1
+    if (dst_x + font_width > video.width)
+      break;
+#else
+    /* (this does not work well when trying to print text to whole screen) */
+    if ((dst_x_start < border_1 && dst_x + font_width > border_1) ||
+       (dst_x_start < border_2 && dst_x + font_width > border_2))
+      break;
+#endif
+
     if (mask_mode == BLIT_INVERSE)     /* special mode for text gadgets */
     {
       /* first step: draw solid colored rectangle (use "cursor" character) */
index 0c5c7586d5873d5cb185c112efe4a424c10f8226..7c331d572a89d3eb45ea2ee87e0445286cb37ee4 100644 (file)
@@ -55,6 +55,8 @@
 void InitFontInfo(struct FontBitmapInfo *, int, int (*function)(int));
 void FreeFontInfo(struct FontBitmapInfo *);
 
+struct FontBitmapInfo *getFontBitmapInfo(int);
+
 int getFontWidth(int);
 int getFontHeight(int);
 int getTextWidth(char *, int);
index 2d0a355014bd05595f2413d6f60d4b31a188da79..855e54f74192ce194174007d061c10afba9f79e9 100644 (file)
@@ -48,11 +48,7 @@ int getAnimationFrame(int num_frames, int delay, int mode, int start_frame,
   }
   else if (mode & ANIM_PINGPONG)       /* oscillate (border frames once) */
   {
-#if 1
     int max_anim_frames = (num_frames > 1 ? 2 * num_frames - 2 : 1);
-#else
-    int max_anim_frames = 2 * num_frames - 2;
-#endif
 
     frame = (sync_frame % (delay * max_anim_frames)) / delay;
     frame = (frame < num_frames ? frame : max_anim_frames - frame);
@@ -73,6 +69,10 @@ int getAnimationFrame(int num_frames, int delay, int mode, int start_frame,
     else
       frame = gfx.anim_random_frame % num_frames;
   }
+  else if (mode & (ANIM_CE_VALUE | ANIM_CE_SCORE | ANIM_CE_DELAY))
+  {
+    frame = sync_frame % num_frames;
+  }
 
   if (mode & ANIM_REVERSE)             /* use reverse animation direction */
     frame = num_frames - frame - 1;
@@ -88,11 +88,11 @@ int getAnimationFrame(int num_frames, int delay, int mode, int start_frame,
 static int get_toon_direction(char *direction_string_raw)
 {
   char *direction_string = getStringToLower(direction_string_raw);
-  int direction = (strcmp(direction_string, "left")  == 0 ? MV_LEFT :
-                  strcmp(direction_string, "right") == 0 ? MV_RIGHT :
-                  strcmp(direction_string, "up")    == 0 ? MV_UP :
-                  strcmp(direction_string, "down")  == 0 ? MV_DOWN :
-                  MV_NO_MOVING);
+  int direction = (strEqual(direction_string, "left")  ? MV_LEFT :
+                  strEqual(direction_string, "right") ? MV_RIGHT :
+                  strEqual(direction_string, "up")    ? MV_UP :
+                  strEqual(direction_string, "down")  ? MV_DOWN :
+                  MV_NONE);
 
   free(direction_string);
 
@@ -127,7 +127,6 @@ void DrawAnim(Bitmap *toon_bitmap, GC toon_clip_gc,
 {
   int buf_x = DOOR_GFX_PAGEX3, buf_y = DOOR_GFX_PAGEY1;
 
-#if 1
   /* special method to avoid flickering interference with BackToFront() */
   BlitBitmap(backbuffer, screen_info.save_buffer, dest_x-pad_x, dest_y-pad_y,
             width+2*pad_x, height+2*pad_y, buf_x, buf_y);
@@ -141,16 +140,6 @@ void DrawAnim(Bitmap *toon_bitmap, GC toon_clip_gc,
 
   BlitBitmap(screen_info.save_buffer, backbuffer, buf_x, buf_y,
            width+2*pad_x, height+2*pad_y, dest_x-pad_x, dest_y-pad_y);
-#else
-  /* normal method, causing flickering interference with BackToFront() */
-  BlitBitmap(backbuffer, screen_info.save_buffer, dest_x-pad_x, dest_y-pad_y,
-            width+2*pad_x, height+2*pad_y, buf_x, buf_y);
-  SetClipOrigin(toon_bitmap,toon_clip_gc, buf_x-src_x+pad_x,buf_y-src_y+pad_y);
-  BlitBitmapMasked(toon_bitmap, screen_info.save_buffer,
-                  src_x, src_y, width, height, buf_x+pad_x, buf_y+pad_y);
-  BlitBitmap(screen_info.save_buffer, window, buf_x, buf_y,
-            width+2*pad_x, height+2*pad_y, dest_x-pad_x, dest_y-pad_y);
-#endif
 
   FlushDisplay();
 }
@@ -188,13 +177,13 @@ boolean AnimateToon(int toon_nr, boolean restart)
     {
       int pos_bottom = screen_info.height - anim->height;
 
-      if (strcmp(anim->position, "top") == 0)
+      if (strEqual(anim->position, "top"))
        pos_y = 0;
-      else if (strcmp(anim->position, "bottom") == 0)
+      else if (strEqual(anim->position, "bottom"))
        pos_y = pos_bottom;
-      else if (strcmp(anim->position, "upper")  == 0)
+      else if (strEqual(anim->position, "upper"))
        pos_y = SimpleRND(pos_bottom / 2);
-      else if (strcmp(anim->position, "lower")  == 0)
+      else if (strEqual(anim->position, "lower"))
        pos_y = pos_bottom / 2 + SimpleRND(pos_bottom / 2);
       else
        pos_y = SimpleRND(pos_bottom);
@@ -216,9 +205,9 @@ boolean AnimateToon(int toon_nr, boolean restart)
     {
       int pos_right = screen_info.width - anim->width;
 
-      if (strcmp(anim->position, "left") == 0)
+      if (strEqual(anim->position, "left"))
        pos_x = 0;
-      else if (strcmp(anim->position, "right")  == 0)
+      else if (strEqual(anim->position, "right"))
        pos_x = pos_right;
       else
        pos_x = SimpleRND(pos_right);
@@ -321,7 +310,7 @@ void HandleAnimation(int mode)
   static int toon_nr = 0;
   int draw_mode;
 
-  if (!setup.toons)
+  if (!setup.toons || screen_info.num_toons == 0)
     return;
 
   /* this may happen after reloading graphics and redefining "num_toons" */
index 313458372e363252b52ed40af19317fc3125c83b..4d3e0be8a08d2579177c915d82fe38bb17756871 100644 (file)
@@ -35,27 +35,8 @@ struct ToonScreenInfo
 
 struct ToonInfo
 {
-#if 0
-  int graphic;
-  int width, height;
-  int src_x, src_y;
-  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;
@@ -64,9 +45,9 @@ struct ToonInfo
   int anim_mode;
   int step_offset;
   int step_delay;
+
   char *direction;
   char *position;
-#endif
 };
 
 
index f03e961cd8c461e1d1abf5368ee5139ca24a9909..b0d70d55d7e57738cadfe9bd1c094548713ecc3e 100644 (file)
@@ -22,7 +22,7 @@
 static void X11InitDisplay();
 static DrawWindow *X11InitWindow();
 
-inline void X11InitVideoDisplay(void)
+void X11InitVideoDisplay(void)
 {
   /* initialize X11 video */
   X11InitDisplay();
@@ -31,7 +31,7 @@ inline void X11InitVideoDisplay(void)
   video.default_depth = XDefaultDepth(display, screen);
 }
 
-inline void X11InitVideoBuffer(DrawBuffer **backbuffer, DrawWindow **window)
+void X11InitVideoBuffer(DrawBuffer **backbuffer, DrawWindow **window)
 {
   *window = X11InitWindow();
 
@@ -93,9 +93,6 @@ static DrawWindow *X11InitWindow()
   Pixmap icon_pixmap, iconmask_pixmap;
   unsigned int icon_width, icon_height;
   int icon_hot_x, icon_hot_y;
-#if 0
-  char icon_filename[256];
-#endif
   XSizeHints size_hints;
   XWMHints wm_hints;
   XClassHint class_hints;
@@ -111,16 +108,6 @@ static DrawWindow *X11InitWindow()
   const int width = video.width, height = video.height;
   int i;
 
-#if 0
-#if !defined(PLATFORM_MSDOS)
-  static struct IconFileInfo icon_pic =
-  {
-    "rocks_icon.xbm",
-    "rocks_iconmask.xbm"
-  };
-#endif
-#endif
-
   screen_width = XDisplayWidth(display, screen);
   screen_height = XDisplayHeight(display, screen);
 
@@ -140,10 +127,6 @@ static DrawWindow *X11InitWindow()
     XChangeProperty(display, new_window->drawable, proto_atom, XA_ATOM, 32,
                    PropModePrepend, (unsigned char *) &delete_atom, 1);
 
-#if 0
-  sprintf(icon_filename, "%s/%s", options.graphics_directory,
-         icon_pic.picture_filename);
-#endif
   if (XReadBitmapFile(display, new_window->drawable,
                      getCustomImageFilename(program.x11_icon_filename),
                      &icon_width, &icon_height, &icon_pixmap,
@@ -151,10 +134,6 @@ static DrawWindow *X11InitWindow()
     Error(ERR_EXIT, "cannot read icon bitmap file '%s'",
          program.x11_icon_filename);
 
-#if 0
-  sprintf(icon_filename, "%s/%s", options.graphics_directory,
-         icon_pic.picturemask_filename);
-#endif
   if (XReadBitmapFile(display, new_window->drawable,
                      getCustomImageFilename(program.x11_iconmask_filename),
                      &icon_width, &icon_height, &iconmask_pixmap,
@@ -328,8 +307,8 @@ Bitmap *X11LoadImage(char *filename)
   return new_bitmap;
 }
 
-inline void X11CreateBitmapContent(Bitmap *new_bitmap,
-                                  int width, int height, int depth)
+void X11CreateBitmapContent(Bitmap *new_bitmap,
+                           int width, int height, int depth)
 {
   Pixmap pixmap;
 
@@ -348,7 +327,7 @@ inline void X11CreateBitmapContent(Bitmap *new_bitmap,
   new_bitmap->line_gc[1] = window->line_gc[1];
 }
 
-inline void X11FreeBitmapPointers(Bitmap *bitmap)
+void X11FreeBitmapPointers(Bitmap *bitmap)
 {
   /* The X11 version seems to have a memory leak here -- although
      "XFreePixmap()" is called, the corresponding memory seems not
@@ -367,30 +346,44 @@ inline void X11FreeBitmapPointers(Bitmap *bitmap)
   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)
+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)
+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)
+void X11FadeScreen(Bitmap *bitmap_cross, int fade_mode, int fade_delay,
+                  int post_delay)
+{
+  /* fading currently not supported -- simply copy target image to screen */
+
+  if (fade_mode == FADE_MODE_FADE_OUT)
+    X11FillRectangle(window, 0, 0, video.width, video.height, BLACK_PIXEL);
+  else
+    X11CopyArea(bitmap_cross != NULL ? bitmap_cross : backbuffer, window,
+               0, 0, video.width, video.height, 0, 0, BLIT_OPAQUE);
+
+  /* as we currently cannot use the fade delay, also do not use post delay */
+}
+
+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)
+Pixel X11GetPixel(Bitmap *bitmap, int x, int y)
 {
   XImage *pixel_image;
   Pixel pixel_value;
@@ -405,8 +398,8 @@ inline Pixel X11GetPixel(Bitmap *bitmap, int x, int y)
 }
 
 #if defined(TARGET_X11_NATIVE)
-inline Pixel X11GetPixelFromRGB(unsigned int color_r, unsigned int color_g,
-                               unsigned int color_b)
+Pixel X11GetPixelFromRGB(unsigned int color_r, unsigned int color_g,
+                        unsigned int color_b)
 {
   XColor xcolor;
   Pixel pixel;
@@ -423,7 +416,7 @@ inline Pixel X11GetPixelFromRGB(unsigned int color_r, unsigned int color_g,
 }
 #endif /* TARGET_X11_NATIVE */
 
-inline void X11DestroyImage(XImage *ximage)
+void X11DestroyImage(XImage *ximage)
 {
 #if defined(TARGET_X11_NATIVE)
   /* this seems to be needed for OS/2, but does not hurt on other platforms */
index 7c69a323c0cd6f67a92c2c6973956d948e25f435..2519955ff530d1f00ee05091943b552ffd6010d8 100644 (file)
@@ -334,20 +334,21 @@ struct XY
 
 /* X11 function definitions */
 
-inline void X11InitVideoDisplay(void);
-inline void X11InitVideoBuffer(DrawBuffer **, DrawWindow **);
+void X11InitVideoDisplay(void);
+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);
-inline void X11DestroyImage(XImage *);
+void X11CreateBitmapContent(Bitmap *, int, int, int);
+void X11FreeBitmapPointers(Bitmap *);
+void X11CopyArea(Bitmap *, Bitmap *, int, int, int, int, int, int, int);
+void X11FillRectangle(Bitmap *, int, int, int, int, Pixel);
+void X11FadeScreen(Bitmap *, int, int, int);
+void X11DrawSimpleLine(Bitmap *, int, int, int, int, Pixel);
+Pixel X11GetPixel(Bitmap *, int, int);
+Pixel X11GetPixelFromRGB(unsigned int, unsigned int, unsigned int);
+void X11DestroyImage(XImage *);
 
 #if defined(TARGET_X11_NATIVE)
 void X11SetMouseCursor(struct MouseCursorInfo *);
index f2db9290d0f05161acc2f816c3ce3f116f79c589..4506c8e373868b40e790a09fa5068ad70cf032fc 100644 (file)
 #include "main.h"
 #include "init.h"
 #include "game.h"
+#include "tape.h"
 #include "events.h"
 #include "config.h"
 
-#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
+Bitmap                *bitmap_db_title;
+Bitmap                *bitmap_db_field;
+Bitmap                *bitmap_db_door;
 DrawBuffer            *fieldbuffer;
 DrawBuffer            *drawto_field;
 
@@ -50,13 +46,14 @@ short                       MovDir[MAX_LEV_FIELDX][MAX_LEV_FIELDY];
 short                  MovDelay[MAX_LEV_FIELDX][MAX_LEV_FIELDY];
 short                  ChangeDelay[MAX_LEV_FIELDX][MAX_LEV_FIELDY];
 short                  ChangePage[MAX_LEV_FIELDX][MAX_LEV_FIELDY];
+short                  CustomValue[MAX_LEV_FIELDX][MAX_LEV_FIELDY];
 short                  Store[MAX_LEV_FIELDX][MAX_LEV_FIELDY];
 short                  Store2[MAX_LEV_FIELDX][MAX_LEV_FIELDY];
 short                  StorePlayer[MAX_LEV_FIELDX][MAX_LEV_FIELDY];
 short                  Back[MAX_LEV_FIELDX][MAX_LEV_FIELDY];
 boolean                        Stop[MAX_LEV_FIELDX][MAX_LEV_FIELDY];
 boolean                        Pushed[MAX_LEV_FIELDX][MAX_LEV_FIELDY];
-boolean                        Changed[MAX_LEV_FIELDX][MAX_LEV_FIELDY];
+short                  ChangeCount[MAX_LEV_FIELDX][MAX_LEV_FIELDY];
 short                  ChangeEvent[MAX_LEV_FIELDX][MAX_LEV_FIELDY];
 short                  WasJustMoving[MAX_LEV_FIELDX][MAX_LEV_FIELDY];
 short                  WasJustFalling[MAX_LEV_FIELDX][MAX_LEV_FIELDY];
@@ -70,7 +67,9 @@ short                 ExplodeDelay[MAX_LEV_FIELDX][MAX_LEV_FIELDY];
 int                    RunnerVisit[MAX_LEV_FIELDX][MAX_LEV_FIELDY];
 int                    PlayerVisit[MAX_LEV_FIELDX][MAX_LEV_FIELDY];
 
+#if 0
 unsigned long          Properties[MAX_NUM_ELEMENTS][NUM_EP_BITFIELDS];
+#endif
 
 int                    GfxFrame[MAX_LEV_FIELDX][MAX_LEV_FIELDY];
 int                    GfxRandom[MAX_LEV_FIELDX][MAX_LEV_FIELDY];
@@ -83,7 +82,7 @@ int                   scroll_x, scroll_y;
 
 int                    FX = SX, FY = SY;
 int                    ScrollStepSize;
-int                    ScreenMovDir = MV_NO_MOVING, ScreenMovPos = 0;
+int                    ScreenMovDir = MV_NONE, ScreenMovPos = 0;
 int                    ScreenGfxPos = 0;
 int                    BorderElement = EL_STEELWALL;
 int                    GameFrameDelay = GAME_FRAME_DELAY;
@@ -191,7 +190,7 @@ struct ElementNameInfo element_name_info[MAX_NUM_ELEMENTS + 1] =
   {
     "yamyam",
     "yamyam",
-    "yam yam"
+    "yam yam (random start direction)"
   },
   {
     "robot",
@@ -200,7 +199,7 @@ struct ElementNameInfo element_name_info[MAX_NUM_ELEMENTS + 1] =
   },
   {
     "steelwall",
-    "wall",
+    "steelwall",
     "steel wall"
   },
   {
@@ -251,7 +250,7 @@ struct ElementNameInfo element_name_info[MAX_NUM_ELEMENTS + 1] =
   {
     "amoeba_wet",
     "amoeba",
-    "dropping amoeba"
+    "dropping amoeba (EM style)"
   },
   {
     "amoeba_dry",
@@ -296,60 +295,63 @@ struct ElementNameInfo element_name_info[MAX_NUM_ELEMENTS + 1] =
   {
     "key_1",
     "key",
-    "red key"
+    "key 1"
   },
   {
     "key_2",
     "key",
-    "yellow key"
+    "key 2"
   },
   {
     "key_3",
     "key",
-    "green key"
+    "key 3"
   },
   {
     "key_4",
     "key",
-    "blue key"
+    "key 4"
   },
   {
     "gate_1",
     "gate",
-    "red door"
+    "door 1"
   },
   {
     "gate_2",
     "gate",
-    "yellow door"
+    "door 2"
   },
   {
     "gate_3",
     "gate",
-    "green door"
+    "door 3"
   },
   {
     "gate_4",
     "gate",
-    "blue door"
+    "door 4"
   },
   {
     "gate_1_gray",
     "gate",
-    "gray door (opened by red key)"
+    "gray door (opened by key 1)"
   },
   {
     "gate_2_gray",
     "gate",
-    "gray door (opened by yellow key)"},
+    "gray door (opened by key 2)"
+  },
   {
     "gate_3_gray",
     "gate",
-    "gray door (opened by green key)"},
+    "gray door (opened by key 3)"
+  },
   {
     "gate_4_gray",
     "gate",
-    "gray door (opened by blue key)"},
+    "gray door (opened by key 4)"
+  },
   {
     "dynamite",
     "dynamite",
@@ -408,7 +410,7 @@ struct ElementNameInfo element_name_info[MAX_NUM_ELEMENTS + 1] =
   {
     "expandable_wall",
     "wall",
-    "growing wall"
+    "growing wall (horizontal, visible)"
   },
   {
     "bd_diamond",
@@ -442,7 +444,7 @@ struct ElementNameInfo element_name_info[MAX_NUM_ELEMENTS + 1] =
   },
   {
     "invisible_steelwall",
-    "wall",
+    "steelwall",
     "invisible steel wall"
   },
   {
@@ -530,22 +532,22 @@ struct ElementNameInfo element_name_info[MAX_NUM_ELEMENTS + 1] =
   {
     "player_1",
     "player",
-    "yellow player"
+    "player 1"
   },
   {
     "player_2",
     "player",
-    "red player"
+    "player 2"
   },
   {
     "player_3",
     "player",
-    "green player"
+    "player 3"
   },
   {
     "player_4",
     "player",
-    "blue player"
+    "player 4"
   },
   {
     "bug.right",
@@ -1142,22 +1144,22 @@ struct ElementNameInfo element_name_info[MAX_NUM_ELEMENTS + 1] =
   {
     "em_gate_1",
     "gate",
-    "red door (EM style)"
+    "door 1 (EM style)"
   },
   {
     "em_gate_2",
     "gate",
-    "yellow door (EM style)"
+    "door 2 (EM style)"
   },
   {
     "em_gate_3",
     "gate",
-    "green door (EM style)"
+    "door 3 (EM style)"
   },
   {
     "em_gate_4",
     "gate",
-    "blue door (EM style)"
+    "door 4 (EM style)"
   },
   {
     "em_key_2_file_obsolete",
@@ -1377,32 +1379,32 @@ struct ElementNameInfo element_name_info[MAX_NUM_ELEMENTS + 1] =
   {
     "em_gate_1_gray",
     "gate",
-    "gray door (EM style, red key)"
+    "gray door (EM style, key 1)"
   },
   {
     "em_gate_2_gray",
     "gate",
-    "gray door (EM style, yellow key)"
+    "gray door (EM style, key 2)"
   },
   {
     "em_gate_3_gray",
     "gate",
-    "gray door (EM style, green key)"
+    "gray door (EM style, key 3)"
   },
   {
     "em_gate_4_gray",
     "gate",
-    "gray door (EM style, blue key)"
+    "gray door (EM style, key 4)"
   },
   {
-    "unused_254",
-    "unused",
-    "(not used)"
+    "em_dynamite",
+    "dynamite",
+    "dynamite (EM style)"
   },
   {
-    "unused_255",
-    "unused",
-    "(not used)"
+    "em_dynamite.active",
+    "dynamite",
+    "burning dynamite (EM style)"
   },
   {
     "pearl",
@@ -1482,122 +1484,122 @@ struct ElementNameInfo element_name_info[MAX_NUM_ELEMENTS + 1] =
   {
     "conveyor_belt_1_left",
     "conveyor_belt",
-    "red conveyor belt (left)"
+    "conveyor belt 1 (left)"
   },
   {
     "conveyor_belt_1_middle",
     "conveyor_belt",
-    "red conveyor belt (middle)"
+    "conveyor belt 1 (middle)"
   },
   {
     "conveyor_belt_1_right",
     "conveyor_belt",
-    "red conveyor belt (right)"
+    "conveyor belt 1 (right)"
   },
   {
     "conveyor_belt_1_switch_left",
     "conveyor_belt_switch",
-    "switch for red conveyor belt (left)"
+    "switch for conveyor belt 1 (left)"
   },
   {
     "conveyor_belt_1_switch_middle",
     "conveyor_belt_switch",
-    "switch for red conveyor belt (middle)"
+    "switch for conveyor belt 1 (middle)"
   },
   {
     "conveyor_belt_1_switch_right",
     "conveyor_belt_switch",
-    "switch for red conveyor belt (right)"
+    "switch for conveyor belt 1 (right)"
   },
   {
     "conveyor_belt_2_left",
     "conveyor_belt",
-    "yellow conveyor belt (left)"
+    "conveyor belt 2 (left)"
   },
   {
     "conveyor_belt_2_middle",
     "conveyor_belt",
-    "yellow conveyor belt (middle)"
+    "conveyor belt 2 (middle)"
   },
   {
     "conveyor_belt_2_right",
     "conveyor_belt",
-    "yellow conveyor belt (right)"
+    "conveyor belt 2 (right)"
   },
   {
     "conveyor_belt_2_switch_left",
     "conveyor_belt_switch",
-    "switch for yellow conveyor belt (left)"
+    "switch for conveyor belt 2 (left)"
   },
   {
     "conveyor_belt_2_switch_middle",
     "conveyor_belt_switch",
-    "switch for yellow conveyor belt (middle)"
+    "switch for conveyor belt 2 (middle)"
   },
   {
     "conveyor_belt_2_switch_right",
     "conveyor_belt_switch",
-    "switch for yellow conveyor belt (right)"
+    "switch for conveyor belt 2 (right)"
   },
   {
     "conveyor_belt_3_left",
     "conveyor_belt",
-    "green conveyor belt (left)"
+    "conveyor belt 3 (left)"
   },
   {
     "conveyor_belt_3_middle",
     "conveyor_belt",
-    "green conveyor belt (middle)"
+    "conveyor belt 3 (middle)"
   },
   {
     "conveyor_belt_3_right",
     "conveyor_belt",
-    "green conveyor belt (right)"
+    "conveyor belt 3 (right)"
   },
   {
     "conveyor_belt_3_switch_left",
     "conveyor_belt_switch",
-    "switch for green conveyor belt (left)"
+    "switch for conveyor belt 3 (left)"
   },
   {
     "conveyor_belt_3_switch_middle",
     "conveyor_belt_switch",
-    "switch for green conveyor belt (middle)"
+    "switch for conveyor belt 3 (middle)"
   },
   {
     "conveyor_belt_3_switch_right",
     "conveyor_belt_switch",
-    "switch for green conveyor belt (right)"
+    "switch for conveyor belt 3 (right)"
   },
   {
     "conveyor_belt_4_left",
     "conveyor_belt",
-    "blue conveyor belt (left)"
+    "conveyor belt 4 (left)"
   },
   {
     "conveyor_belt_4_middle",
     "conveyor_belt",
-    "blue conveyor belt (middle)"
+    "conveyor belt 4 (middle)"
   },
   {
     "conveyor_belt_4_right",
     "conveyor_belt",
-    "blue conveyor belt (right)"
+    "conveyor belt 4 (right)"
   },
   {
     "conveyor_belt_4_switch_left",
     "conveyor_belt_switch",
-    "switch for blue conveyor belt (left)"
+    "switch for conveyor belt 4 (left)"
   },
   {
     "conveyor_belt_4_switch_middle",
     "conveyor_belt_switch",
-    "switch for blue conveyor belt (middle)"
+    "switch for conveyor belt 4 (middle)"
   },
   {
     "conveyor_belt_4_switch_right",
     "conveyor_belt_switch",
-    "switch for blue conveyor belt (right)"
+    "switch for conveyor belt 4 (right)"
   },
   {
     "landmine",
@@ -1701,7 +1703,7 @@ struct ElementNameInfo element_name_info[MAX_NUM_ELEMENTS + 1] =
   },
   {
     "steelwall_slippery",
-    "wall",
+    "steelwall",
     "slippery steel wall"
   },
   {
@@ -1762,46 +1764,46 @@ struct ElementNameInfo element_name_info[MAX_NUM_ELEMENTS + 1] =
   {
     "balloon_switch_left",
     "balloon_switch",
-    "send balloon to the left"
+    "wind switch (left)"
   },
   {
     "balloon_switch_right",
     "balloon_switch",
-    "send balloon to the right"
+    "wind switch (right)"
   },
   {
     "balloon_switch_up",
     "balloon_switch",
-    "send balloon up"
+    "wind switch (up)"
   },
   {
     "balloon_switch_down",
     "balloon_switch",
-    "send balloon down"
+    "wind switch (down)"
   },
   {
     "balloon_switch_any",
     "balloon_switch",
-    "send balloon in pressed direction"
+    "wind switch (any direction)"
   },
   {
     "emc_steelwall_1",
-    "wall",
+    "steelwall",
     "steel wall"
   },
   {
     "emc_steelwall_2",
-    "wall",
+    "steelwall",
     "steel wall"
   },
   {
     "emc_steelwall_3",
-    "wall",
+    "steelwall",
     "steel wall"
   },
   {
     "emc_steelwall_4",
-    "wall",
+    "steelwall",
     "steel wall"
   },
   {
@@ -3207,22 +3209,22 @@ struct ElementNameInfo element_name_info[MAX_NUM_ELEMENTS + 1] =
   {
     "em_key_1",
     "key",
-    "red key (EM style)"
+    "key 1 (EM style)"
     },
   {
     "em_key_2",
     "key",
-    "yellow key (EM style)"
+    "key 2 (EM style)"
     },
   {
     "em_key_3",
     "key",
-    "green key (EM style)"
+    "key 3 (EM style)"
   },
   {
     "em_key_4",
     "key",
-    "blue key (EM style)"
+    "key 4 (EM style)"
   },
   {
     "envelope_1",
@@ -3462,7 +3464,7 @@ struct ElementNameInfo element_name_info[MAX_NUM_ELEMENTS + 1] =
   {
     "balloon_switch_none",
     "balloon_switch",
-    "stop moving balloon"
+    "wind switch (off)"
   },
   {
     "emc_gate_5",
@@ -3636,12 +3638,12 @@ struct ElementNameInfo element_name_info[MAX_NUM_ELEMENTS + 1] =
   },
   {
     "emc_fake_grass",
-    "fake grass",
+    "fake_grass",
     "fake grass"
   },
   {
     "emc_fake_acid",
-    "fake acid",
+    "fake_acid",
     "fake acid"
   },
   {
@@ -3649,6 +3651,51 @@ struct ElementNameInfo element_name_info[MAX_NUM_ELEMENTS + 1] =
     "dripper",
     "dripper"
   },
+  {
+    "trigger_ce_value",
+    "trigger",
+    "CE value of element triggering change"
+  },
+  {
+    "trigger_ce_score",
+    "trigger",
+    "CE score of element triggering change"
+  },
+  {
+    "current_ce_value",
+    "current",
+    "CE value of current element"
+  },
+  {
+    "current_ce_score",
+    "current",
+    "CE score of current element"
+  },
+  {
+    "yamyam.left",
+    "yamyam",
+    "yam yam (starts moving left)"
+  },
+  {
+    "yamyam.right",
+    "yamyam",
+    "yam yam (starts moving right)"
+  },
+  {
+    "yamyam.up",
+    "yamyam",
+    "yam yam (starts moving up)"
+  },
+  {
+    "yamyam.down",
+    "yamyam",
+    "yam yam (starts moving down)"
+  },
+  {
+    "bd_expandable_wall",
+    "wall",
+    "growing wall (horizontal, BD style)"
+  },
 
   /* ----------------------------------------------------------------------- */
   /* "real" (and therefore drawable) runtime elements                        */
@@ -3711,7 +3758,7 @@ struct ElementNameInfo element_name_info[MAX_NUM_ELEMENTS + 1] =
   },
   {
     "invisible_steelwall.active",
-    "wall",
+    "steelwall",
     "-"
   },
   {
@@ -3880,6 +3927,82 @@ struct ElementNameInfo element_name_info[MAX_NUM_ELEMENTS + 1] =
     "-"
   },
 
+  {
+    "emc_fake_grass.active",
+    "fake_grass",
+    "-"
+  },
+  {
+    "gate_1_gray.active",
+    "gate",
+    ""
+  },
+  {
+    "gate_2_gray.active",
+    "gate",
+    ""
+  },
+  {
+    "gate_3_gray.active",
+    "gate",
+    ""
+  },
+  {
+    "gate_4_gray.active",
+    "gate",
+    ""
+  },
+  {
+    "em_gate_1_gray.active",
+    "gate",
+    ""
+  },
+  {
+    "em_gate_2_gray.active",
+    "gate",
+    ""
+  },
+  {
+    "em_gate_3_gray.active",
+    "gate",
+    ""
+  },
+  {
+    "em_gate_4_gray.active",
+    "gate",
+    ""
+  },
+  {
+    "emc_gate_5_gray.active",
+    "gate",
+    "",
+  },
+  {
+    "emc_gate_6_gray.active",
+    "gate",
+    "",
+  },
+  {
+    "emc_gate_7_gray.active",
+    "gate",
+    "",
+  },
+  {
+    "emc_gate_8_gray.active",
+    "gate",
+    "",
+  },
+  {
+    "emc_dripper.active",
+    "dripper",
+    "dripper"
+  },
+  {
+    "emc_spring_bumper.active",
+    "emc_spring_bumper",
+    "spring bumper",
+  },
+
   /* ----------------------------------------------------------------------- */
   /* "unreal" (and therefore not drawable) runtime elements                  */
   /* ----------------------------------------------------------------------- */
@@ -3974,6 +4097,21 @@ struct ElementNameInfo element_name_info[MAX_NUM_ELEMENTS + 1] =
     "-",
     "-"
   },
+  {
+    "element.snapping",
+    "-",
+    "-"
+  },
+  {
+    "diagonal.shrinking",
+    "-",
+    "-"
+  },
+  {
+    "diagonal.growing",
+    "-",
+    "-"
+  },
 
   /* ----------------------------------------------------------------------- */
   /* dummy elements (never used as game elements, only used as graphics)     */
@@ -4124,6 +4262,146 @@ struct ElementNameInfo element_name_info[MAX_NUM_ELEMENTS + 1] =
     "internal",
     "-"
   },
+  {
+    "internal_cascade_bd",
+    "internal",
+    "show Boulder Dash elements"
+  },
+  {
+    "internal_cascade_bd.active",
+    "internal",
+    "hide Boulder Dash elements"
+  },
+  {
+    "internal_cascade_em",
+    "internal",
+    "show Emerald Mine elements"
+  },
+  {
+    "internal_cascade_em.active",
+    "internal",
+    "hide Emerald Mine elements"
+  },
+  {
+    "internal_cascade_emc",
+    "internal",
+    "show Emerald Mine Club elements"
+  },
+  {
+    "internal_cascade_emc.active",
+    "internal",
+    "hide Emerald Mine Club elements"
+  },
+  {
+    "internal_cascade_rnd",
+    "internal",
+    "show Rocks'n'Diamonds elements"
+  },
+  {
+    "internal_cascade_rnd.active",
+    "internal",
+    "hide Rocks'n'Diamonds elements"
+  },
+  {
+    "internal_cascade_sb",
+    "internal",
+    "show Sokoban elements"
+  },
+  {
+    "internal_cascade_sb.active",
+    "internal",
+    "hide Sokoban elements"
+  },
+  {
+    "internal_cascade_sp",
+    "internal",
+    "show Supaplex elements"
+  },
+  {
+    "internal_cascade_sp.active",
+    "internal",
+    "hide Supaplex elements"
+  },
+  {
+    "internal_cascade_dc",
+    "internal",
+    "show Diamond Caves II elements"
+  },
+  {
+    "internal_cascade_dc.active",
+    "internal",
+    "hide Diamond Caves II elements"
+  },
+  {
+    "internal_cascade_dx",
+    "internal",
+    "show DX Boulderdash elements"
+  },
+  {
+    "internal_cascade_dx.active",
+    "internal",
+    "hide DX Boulderdash elements"
+  },
+  {
+    "internal_cascade_chars",
+    "internal",
+    "show text elements"
+  },
+  {
+    "internal_cascade_chars.active",
+    "internal",
+    "hide text elements"
+  },
+  {
+    "internal_cascade_ce",
+    "internal",
+    "show custom elements"
+  },
+  {
+    "internal_cascade_ce.active",
+    "internal",
+    "hide custom elements"
+  },
+  {
+    "internal_cascade_ge",
+    "internal",
+    "show group elements"
+  },
+  {
+    "internal_cascade_ge.active",
+    "internal",
+    "hide group elements"
+  },
+  {
+    "internal_cascade_ref",
+    "internal",
+    "show reference elements"
+  },
+  {
+    "internal_cascade_ref.active",
+    "internal",
+    "hide reference elements"
+  },
+  {
+    "internal_cascade_user",
+    "internal",
+    "show user defined elements"
+  },
+  {
+    "internal_cascade_user.active",
+    "internal",
+    "hide user defined elements"
+  },
+  {
+    "internal_cascade_dynamic",
+    "internal",
+    "show elements used in this level"
+  },
+  {
+    "internal_cascade_dynamic.active",
+    "internal",
+    "hide elements used in this level"
+  },
 
   /* keyword to stop parser: "ELEMENT_INFO_END" <-- do not change! */
 
@@ -4190,9 +4468,41 @@ struct ElementActionInfo element_action_info[NUM_ACTIONS + 1 + 1] =
   { ".turning_from_down",      ACTION_TURNING_FROM_DOWN,       FALSE   },
   { ".smashed_by_rock",                ACTION_SMASHED_BY_ROCK,         FALSE   },
   { ".smashed_by_spring",      ACTION_SMASHED_BY_SPRING,       FALSE   },
-  { ".slurped_by_spring",      ACTION_SLURPED_BY_SPRING,       FALSE   },
+  { ".eating",                 ACTION_EATING,                  FALSE   },
   { ".twinkling",              ACTION_TWINKLING,               FALSE   },
   { ".splashing",              ACTION_SPLASHING,               FALSE   },
+  { ".page[1]",                        ACTION_PAGE_1,                  FALSE   },
+  { ".page[2]",                        ACTION_PAGE_2,                  FALSE   },
+  { ".page[3]",                        ACTION_PAGE_3,                  FALSE   },
+  { ".page[4]",                        ACTION_PAGE_4,                  FALSE   },
+  { ".page[5]",                        ACTION_PAGE_5,                  FALSE   },
+  { ".page[6]",                        ACTION_PAGE_6,                  FALSE   },
+  { ".page[7]",                        ACTION_PAGE_7,                  FALSE   },
+  { ".page[8]",                        ACTION_PAGE_8,                  FALSE   },
+  { ".page[9]",                        ACTION_PAGE_9,                  FALSE   },
+  { ".page[10]",               ACTION_PAGE_10,                 FALSE   },
+  { ".page[11]",               ACTION_PAGE_11,                 FALSE   },
+  { ".page[12]",               ACTION_PAGE_12,                 FALSE   },
+  { ".page[13]",               ACTION_PAGE_13,                 FALSE   },
+  { ".page[14]",               ACTION_PAGE_14,                 FALSE   },
+  { ".page[15]",               ACTION_PAGE_15,                 FALSE   },
+  { ".page[16]",               ACTION_PAGE_16,                 FALSE   },
+  { ".page[17]",               ACTION_PAGE_17,                 FALSE   },
+  { ".page[18]",               ACTION_PAGE_18,                 FALSE   },
+  { ".page[19]",               ACTION_PAGE_19,                 FALSE   },
+  { ".page[20]",               ACTION_PAGE_20,                 FALSE   },
+  { ".page[21]",               ACTION_PAGE_21,                 FALSE   },
+  { ".page[22]",               ACTION_PAGE_22,                 FALSE   },
+  { ".page[23]",               ACTION_PAGE_23,                 FALSE   },
+  { ".page[24]",               ACTION_PAGE_24,                 FALSE   },
+  { ".page[25]",               ACTION_PAGE_25,                 FALSE   },
+  { ".page[26]",               ACTION_PAGE_26,                 FALSE   },
+  { ".page[27]",               ACTION_PAGE_27,                 FALSE   },
+  { ".page[28]",               ACTION_PAGE_28,                 FALSE   },
+  { ".page[29]",               ACTION_PAGE_29,                 FALSE   },
+  { ".page[30]",               ACTION_PAGE_30,                 FALSE   },
+  { ".page[31]",               ACTION_PAGE_31,                 FALSE   },
+  { ".page[32]",               ACTION_PAGE_32,                 FALSE   },
   { ".other",                  ACTION_OTHER,                   FALSE   },
 
   /* empty suffix always matches -- check as last entry in InitSoundInfo() */
@@ -4201,12 +4511,16 @@ struct ElementActionInfo element_action_info[NUM_ACTIONS + 1 + 1] =
   { NULL,                      0,                              0       }
 };
 
-struct ElementDirectionInfo element_direction_info[NUM_DIRECTIONS + 1] =
+struct ElementDirectionInfo element_direction_info[NUM_DIRECTIONS_FULL + 1] =
 {
   { ".left",           MV_BIT_LEFT                     },
   { ".right",          MV_BIT_RIGHT                    },
   { ".up",             MV_BIT_UP                       },
   { ".down",           MV_BIT_DOWN                     },
+  { ".upleft",         MV_BIT_UP                       },
+  { ".upright",                MV_BIT_RIGHT                    },
+  { ".downleft",       MV_BIT_LEFT                     },
+  { ".downright",      MV_BIT_DOWN                     },
 
   { NULL,              0                               }
 };
@@ -4214,6 +4528,7 @@ struct ElementDirectionInfo element_direction_info[NUM_DIRECTIONS + 1] =
 struct SpecialSuffixInfo special_suffix_info[NUM_SPECIAL_GFX_ARGS + 1 + 1] =
 {
   { ".[DEFAULT]",      GAME_MODE_DEFAULT,              },
+  { ".TITLE",          GAME_MODE_TITLE,                },
   { ".MAIN",           GAME_MODE_MAIN,                 },
   { ".LEVELS",         GAME_MODE_LEVELS                },
   { ".SCORES",         GAME_MODE_SCORES,               },
@@ -4257,9 +4572,13 @@ struct TokenIntPtrInfo image_config_vars[] =
   { "menu.list_size.SCORES",   &menu.list_size[GFX_SPECIAL_ARG_SCORES]    },
   { "menu.list_size.INFO",     &menu.list_size[GFX_SPECIAL_ARG_INFO]      },
 
+  { "door_1.width",            &door_1.width                              },
+  { "door_1.height",           &door_1.height                             },
   { "door_1.step_offset",      &door_1.step_offset                        },
   { "door_1.step_delay",       &door_1.step_delay                         },
   { "door_1.anim_mode",                &door_1.anim_mode                          },
+  { "door_2.width",            &door_2.width                              },
+  { "door_2.height",           &door_2.height                             },
   { "door_2.step_offset",      &door_2.step_offset                        },
   { "door_2.step_delay",       &door_2.step_delay                         },
   { "door_2.anim_mode",                &door_2.anim_mode                          },
@@ -4311,6 +4630,7 @@ struct FontInfo font_info[NUM_FONTS + 1] =
   { "font.value_1"             },
   { "font.value_2"             },
   { "font.value_old"           },
+  { "font.level_number.active" },
   { "font.level_number"                },
   { "font.tape_recorder"       },
   { "font.game_info"           },
index 2de55a4e53d280cdbe06df2ffa67c4c25877d8dc..645adfd82b8ccdb3c1fe8b1fcc4dbc75bc22486a 100644 (file)
 #include "conf_snd.h"  /* include auto-generated data structure definitions */
 #include "conf_mus.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 MUS_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 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 MUS_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                 MAX_PLAYFIELD_WIDTH
+#define MAX_LEV_FIELDY                 MAX_PLAYFIELD_HEIGHT
+
+#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 configurable properties (custom elem's only, else pre-defined) */
-#define EP_DIGGABLE            0
-#define EP_COLLECTIBLE_ONLY    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_EXPLODES_BY_FIRE    13
-#define EP_EXPLODES_SMASHED    14
-#define EP_EXPLODES_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_DROPPABLE           22
-#define EP_EXPLODES_1X1_OLD    23
-#define EP_PUSHABLE            24
-#define EP_EXPLODES_CROSS_OLD  25
-#define EP_PROTECTED           26
-#define EP_CAN_MOVE_INTO_ACID  27
-#define EP_THROWABLE           28
-#define EP_CAN_EXPLODE         29
-#define EP_GRAVITY_REACHABLE   30
+#define EP_DIGGABLE                    0
+#define EP_COLLECTIBLE_ONLY            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_EXPLODES_BY_FIRE            13
+#define EP_EXPLODES_SMASHED            14
+#define EP_EXPLODES_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_DROPPABLE                   22
+#define EP_EXPLODES_1X1_OLD            23
+#define EP_PUSHABLE                    24
+#define EP_EXPLODES_CROSS_OLD          25
+#define EP_PROTECTED                   26
+#define EP_CAN_MOVE_INTO_ACID          27
+#define EP_THROWABLE                   28
+#define EP_CAN_EXPLODE                 29
+#define EP_GRAVITY_REACHABLE           30
 
 /* values for pre-defined properties */
-#define EP_PLAYER              32
-#define EP_CAN_PASS_MAGIC_WALL 33
-#define EP_SWITCHABLE          34
-#define EP_BD_ELEMENT          35
-#define EP_SP_ELEMENT          36
-#define EP_SB_ELEMENT          37
-#define EP_GEM                 38
-#define EP_FOOD_DARK_YAMYAM    39
-#define EP_FOOD_PENGUIN                40
-#define EP_FOOD_PIG            41
-#define EP_HISTORIC_WALL       42
-#define EP_HISTORIC_SOLID      43
-#define EP_CLASSIC_ENEMY       44
-#define EP_BELT                        45
-#define EP_BELT_ACTIVE         46
-#define EP_BELT_SWITCH         47
-#define EP_TUBE                        48
-#define EP_KEYGATE             49
-#define EP_AMOEBOID            50
-#define EP_AMOEBALIVE          51
-#define EP_HAS_CONTENT         52
-#define EP_CAN_TURN_EACH_MOVE  53
-#define EP_CAN_GROW            54
-#define EP_ACTIVE_BOMB         55
-#define EP_INACTIVE            56
+#define EP_PLAYER                      32
+#define EP_CAN_PASS_MAGIC_WALL         33
+#define EP_SWITCHABLE                  34
+#define EP_BD_ELEMENT                  35
+#define EP_SP_ELEMENT                  36
+#define EP_SB_ELEMENT                  37
+#define EP_GEM                         38
+#define EP_FOOD_DARK_YAMYAM            39
+#define EP_FOOD_PENGUIN                        40
+#define EP_FOOD_PIG                    41
+#define EP_HISTORIC_WALL               42
+#define EP_HISTORIC_SOLID              43
+#define EP_CLASSIC_ENEMY               44
+#define EP_BELT                                45
+#define EP_BELT_ACTIVE                 46
+#define EP_BELT_SWITCH                 47
+#define EP_TUBE                                48
+#define EP_KEYGATE                     49
+#define EP_AMOEBOID                    50
+#define EP_AMOEBALIVE                  51
+#define EP_HAS_EDITOR_CONTENT          52
+#define EP_CAN_TURN_EACH_MOVE          53
+#define EP_CAN_GROW                    54
+#define EP_ACTIVE_BOMB                 55
+#define EP_INACTIVE                    56
 
 /* values for special configurable properties (depending on level settings) */
-#define EP_EM_SLIPPERY_WALL    57
+#define EP_EM_SLIPPERY_WALL            57
 
 /* values for special graphics properties (no effect on game engine) */
-#define EP_GFX_CRUMBLED                58
+#define EP_GFX_CRUMBLED                        58
 
 /* values for derived properties (determined from properties above) */
-#define EP_ACCESSIBLE_OVER     59
-#define EP_ACCESSIBLE_INSIDE   60
-#define EP_ACCESSIBLE_UNDER    61
-#define EP_WALKABLE            62
-#define EP_PASSABLE            63
-#define EP_ACCESSIBLE          64
-#define EP_COLLECTIBLE         65
-#define EP_SNAPPABLE           66
-#define EP_WALL                        67
-#define EP_SOLID_FOR_PUSHING   68
-#define EP_DRAGONFIRE_PROOF    69
-#define EP_EXPLOSION_PROOF     70
-#define EP_CAN_SMASH           71
-#define EP_EXPLODES_3X3_OLD    72
-#define EP_CAN_EXPLODE_BY_FIRE 73
-#define EP_CAN_EXPLODE_SMASHED 74
-#define EP_CAN_EXPLODE_IMPACT  75
-#define EP_SP_PORT             76
+#define EP_ACCESSIBLE_OVER             59
+#define EP_ACCESSIBLE_INSIDE           60
+#define EP_ACCESSIBLE_UNDER            61
+#define EP_WALKABLE                    62
+#define EP_PASSABLE                    63
+#define EP_ACCESSIBLE                  64
+#define EP_COLLECTIBLE                 65
+#define EP_SNAPPABLE                   66
+#define EP_WALL                                67
+#define EP_SOLID_FOR_PUSHING           68
+#define EP_DRAGONFIRE_PROOF            69
+#define EP_EXPLOSION_PROOF             70
+#define EP_CAN_SMASH                   71
+#define EP_EXPLODES_3X3_OLD            72
+#define EP_CAN_EXPLODE_BY_FIRE         73
+#define EP_CAN_EXPLODE_SMASHED         74
+#define EP_CAN_EXPLODE_IMPACT          75
+#define EP_SP_PORT                     76
 #define EP_CAN_EXPLODE_BY_DRAGONFIRE   77
 #define EP_CAN_EXPLODE_BY_EXPLOSION    78
 #define EP_COULD_MOVE_INTO_ACID                79
 #define EP_MAYBE_DONT_COLLIDE_WITH     80
+#define EP_CAN_BE_CLONED_BY_ANDROID    81
 
 /* values for internal purpose only (level editor) */
-#define EP_WALK_TO_OBJECT      81
-#define EP_DEADLY              82
+#define EP_WALK_TO_OBJECT              82
+#define EP_DEADLY                      83
+#define EP_EDITOR_CASCADE              84
+#define EP_EDITOR_CASCADE_ACTIVE       85
+#define EP_EDITOR_CASCADE_INACTIVE     86
 
-#define NUM_ELEMENT_PROPERTIES 83
+/* values for internal purpose only (game engine) */
+#define EP_HAS_ACTION                  87
+#define EP_CAN_CHANGE_OR_HAS_ACTION    88
 
-#define NUM_EP_BITFIELDS       ((NUM_ELEMENT_PROPERTIES + 31) / 32)
-#define EP_BITFIELD_BASE       0
+/* values for internal purpose only (other) */
+#define EP_OBSOLETE                    89
 
-#define EP_BITMASK_DEFAULT     0
+#define NUM_ELEMENT_PROPERTIES         90
 
-#define PROPERTY_BIT(p)                (1 << ((p) % 32))
-#define PROPERTY_VAR(e,p)      (Properties[e][(p) / 32])
+#define NUM_EP_BITFIELDS               ((NUM_ELEMENT_PROPERTIES + 31) / 32)
+#define EP_BITFIELD_BASE_NR            0
+
+#define EP_BITMASK_BASE_DEFAULT                (1 << EP_CAN_MOVE_INTO_ACID)
+#define EP_BITMASK_DEFAULT             0
+
+#define PROPERTY_BIT(p)                        (1 << ((p) % 32))
+#if 1
+#define PROPERTY_VAR(e,p)              (element_info[e].properties[(p) / 32])
+#else
+#define PROPERTY_VAR(e,p)              (Properties[e][(p) / 32])
+#endif
 #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)) : \
 
 
 /* values for change events for custom elements (stored in level file) */
-#define CE_DELAY               0
-#define CE_TOUCHED_BY_PLAYER   1
-#define CE_PRESSED_BY_PLAYER   2
-#define CE_PUSHED_BY_PLAYER    3
-#define CE_DROPPED_BY_PLAYER   4
-#define CE_HITTING_SOMETHING   5
-#define CE_IMPACT              6
-#define CE_SMASHED             7
-#define CE_TOUCHING_X          8
-#define CE_CHANGE_OF_X         9
-#define CE_EXPLOSION_OF_X      10
-#define CE_PLAYER_TOUCHES_X    11
-#define CE_PLAYER_PRESSES_X    12
-#define CE_PLAYER_PUSHES_X     13
-#define CE_PLAYER_COLLECTS_X   14
-#define CE_PLAYER_DROPS_X      15
-#define CE_BY_PLAYER_OBSOLETE  16      /* obsolete; now CE_BY_DIRECT_ACTION */
-#define CE_BY_COLLISION_OBSOLETE 17    /* obsolete; now CE_BY_DIRECT_ACTION */
-#define CE_BY_OTHER_ACTION     18      /* activates other element events */
-#define CE_BY_DIRECT_ACTION    19      /* activates direct element events */
-#define CE_PLAYER_DIGS_X       20
-#define CE_ENTERED_BY_PLAYER   21
-#define CE_LEFT_BY_PLAYER      22
-#define CE_PLAYER_ENTERS_X     23
-#define CE_PLAYER_LEAVES_X     24
-#define CE_SWITCHED            25
-#define CE_SWITCH_OF_X         26
-#define CE_HIT_BY_SOMETHING    27
-#define CE_HITTING_X           28
-#define CE_HIT_BY_X            29
-#define CE_BLOCKED             30
-
-#define NUM_CHANGE_EVENTS      31
-
-#define CE_BITMASK_DEFAULT     0
-
-#if 1
-
-#define CH_EVENT_VAR(e,c)      (element_info[e].change->has_event[c])
-#define CH_ANY_EVENT_VAR(e,c)  (element_info[e].has_change_event[c])
-
-#define PAGE_HAS_CHANGE_EVENT(p,c)  ((p)->has_event[c])
-#define HAS_CHANGE_EVENT(e,c)      (IS_CUSTOM_ELEMENT(e) &&            \
-                                    CH_EVENT_VAR(e,c))
-#define HAS_ANY_CHANGE_EVENT(e,c)   (IS_CUSTOM_ELEMENT(e) &&           \
-                                    CH_ANY_EVENT_VAR(e,c))
-
-#define SET_CHANGE_EVENT(e,c,v)     (IS_CUSTOM_ELEMENT(e) ?            \
-                                    CH_EVENT_VAR(e,c) = (v) : 0)
-#define SET_ANY_CHANGE_EVENT(e,c,v) (IS_CUSTOM_ELEMENT(e) ?            \
-                                    CH_ANY_EVENT_VAR(e,c) = (v) : 0)
-
-#else
-
-#define CH_EVENT_BIT(c)                (1 << (c))
-#define CH_EVENT_VAR(e)                (element_info[e].change->events)
-#define CH_ANY_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 HAS_ANY_CHANGE_EVENT(e,c) (IS_CUSTOM_ELEMENT(e) &&               \
-                                (CH_ANY_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)
-#define SET_ANY_CHANGE_EVENT(e,c,v) (IS_CUSTOM_ELEMENT(e) ?              \
-                              ((v) ?                                     \
-                               (CH_ANY_EVENT_VAR(e) |=  CH_EVENT_BIT(c)) : \
-                               (CH_ANY_EVENT_VAR(e) &= ~CH_EVENT_BIT(c))) : 0)
-#endif
+#define CE_DELAY                       0
+#define CE_TOUCHED_BY_PLAYER           1
+#define CE_PRESSED_BY_PLAYER           2
+#define CE_PUSHED_BY_PLAYER            3
+#define CE_DROPPED_BY_PLAYER           4
+#define CE_HITTING_SOMETHING           5
+#define CE_IMPACT                      6
+#define CE_SMASHED                     7
+#define CE_TOUCHING_X                  8
+#define CE_CHANGE_OF_X                 9
+#define CE_EXPLOSION_OF_X              10
+#define CE_PLAYER_TOUCHES_X            11
+#define CE_PLAYER_PRESSES_X            12
+#define CE_PLAYER_PUSHES_X             13
+#define CE_PLAYER_COLLECTS_X           14
+#define CE_PLAYER_DROPS_X              15
+#define CE_VALUE_GETS_ZERO             16
+#define CE_VALUE_GETS_ZERO_OF_X                17
+#define CE_BY_OTHER_ACTION             18
+#define CE_BY_DIRECT_ACTION            19
+#define CE_PLAYER_DIGS_X               20
+#define CE_ENTERED_BY_PLAYER           21
+#define CE_LEFT_BY_PLAYER              22
+#define CE_PLAYER_ENTERS_X             23
+#define CE_PLAYER_LEAVES_X             24
+#define CE_SWITCHED                    25
+#define CE_SWITCH_OF_X                 26
+#define CE_HIT_BY_SOMETHING            27
+#define CE_HITTING_X                   28
+#define CE_HIT_BY_X                    29
+#define CE_BLOCKED                     30
+#define CE_SWITCHED_BY_PLAYER          31
+#define CE_PLAYER_SWITCHES_X           32
+#define CE_SNAPPED_BY_PLAYER           33
+#define CE_PLAYER_SNAPS_X              34
+#define CE_MOVE_OF_X                   35
+#define CE_DIGGING_X                   36
+#define CE_CREATION_OF_X               37
+#define CE_SCORE_GETS_ZERO             38
+#define CE_SCORE_GETS_ZERO_OF_X                39
+#define CE_VALUE_CHANGES               40
+#define CE_VALUE_CHANGES_OF_X          41
+#define CE_SCORE_CHANGES               42
+#define CE_SCORE_CHANGES_OF_X          43
+
+#define NUM_CHANGE_EVENTS              44
+
+#define NUM_CE_BITFIELDS               ((NUM_CHANGE_EVENTS + 31) / 32)
+
+#define CE_BITMASK_DEFAULT             0
+
+#define CH_EVENT_BITFIELD_NR(e)                (e / 32)
+#define CH_EVENT_BIT(e)                        (1 << ((e) % 32))
+
+#define CH_EVENT_VAR(e,c)              (element_info[e].change->has_event[c])
+#define CH_ANY_EVENT_VAR(e,c)          (element_info[e].has_change_event[c])
+
+#define PAGE_HAS_CHANGE_EVENT(p,c)     ((p)->has_event[c])
+#define HAS_CHANGE_EVENT(e,c)          (IS_CUSTOM_ELEMENT(e) &&        \
+                                        CH_EVENT_VAR(e,c))
+#define HAS_ANY_CHANGE_EVENT(e,c)      (IS_CUSTOM_ELEMENT(e) &&        \
+                                        CH_ANY_EVENT_VAR(e,c))
+
+#define SET_CHANGE_EVENT(e,c,v)                (IS_CUSTOM_ELEMENT(e) ?         \
+                                        CH_EVENT_VAR(e,c) = (v) : 0)
+#define SET_ANY_CHANGE_EVENT(e,c,v)    (IS_CUSTOM_ELEMENT(e) ?         \
+                                        CH_ANY_EVENT_VAR(e,c) = (v) : 0)
+
+/* values for player bitmasks */
+#define PLAYER_BITS_NONE               0
+#define PLAYER_BITS_1                  (1 << 0)
+#define PLAYER_BITS_2                  (1 << 1)
+#define PLAYER_BITS_3                  (1 << 2)
+#define PLAYER_BITS_4                  (1 << 3)
+#define PLAYER_BITS_ANY                        (PLAYER_BITS_1 | \
+                                        PLAYER_BITS_2 | \
+                                        PLAYER_BITS_3 | \
+                                        PLAYER_BITS_4)
+#define PLAYER_BITS_TRIGGER            (1 << 4)
+
+/* values for move directions (bits 0 - 3: basic move directions) */
+#define MV_BIT_PREVIOUS                        4
+#define MV_BIT_TRIGGER                 5
+#define MV_BIT_TRIGGER_BACK            6
+#define MV_BIT_NORMAL                  MV_BIT_TRIGGER
+#define MV_BIT_REVERSE                 MV_BIT_TRIGGER_BACK
+
+#define MV_PREVIOUS                    (1 << MV_BIT_PREVIOUS)
+#define MV_TRIGGER                     (1 << MV_BIT_TRIGGER)
+#define MV_TRIGGER_BACK                        (1 << MV_BIT_TRIGGER_BACK)
+#define MV_NORMAL                      (1 << MV_BIT_NORMAL)
+#define MV_REVERSE                     (1 << MV_BIT_REVERSE)
+
+/* values for move stepsize */
+#define STEPSIZE_NOT_MOVING            0
+#define STEPSIZE_VERY_SLOW             1
+#define STEPSIZE_SLOW                  2
+#define STEPSIZE_NORMAL                        4
+#define STEPSIZE_FAST                  8
+#define STEPSIZE_VERY_FAST             16
+#define STEPSIZE_EVEN_FASTER           32
+#define STEPSIZE_SLOWER                        50      /* (symbolic value only) */
+#define STEPSIZE_FASTER                        200     /* (symbolic value only) */
+#define STEPSIZE_RESET                 100     /* (symbolic value only) */
 
 /* values for change side for custom elements */
-#define CH_SIDE_NONE           MV_NO_MOVING
-#define CH_SIDE_LEFT           MV_LEFT
-#define CH_SIDE_RIGHT          MV_RIGHT
-#define CH_SIDE_TOP            MV_UP
-#define CH_SIDE_BOTTOM         MV_DOWN
-#define CH_SIDE_LEFT_RIGHT     MV_HORIZONTAL
-#define CH_SIDE_TOP_BOTTOM     MV_VERTICAL
-#define CH_SIDE_ANY            MV_ANY_DIRECTION
+#define CH_SIDE_NONE                   MV_NONE
+#define CH_SIDE_LEFT                   MV_LEFT
+#define CH_SIDE_RIGHT                  MV_RIGHT
+#define CH_SIDE_TOP                    MV_UP
+#define CH_SIDE_BOTTOM                 MV_DOWN
+#define CH_SIDE_LEFT_RIGHT             MV_HORIZONTAL
+#define CH_SIDE_TOP_BOTTOM             MV_VERTICAL
+#define CH_SIDE_ANY                    MV_ANY_DIRECTION
 
 /* values for change player for custom elements */
-#define CH_PLAYER_NONE         0
-#define CH_PLAYER_1            (1 << 0)
-#define CH_PLAYER_2            (1 << 1)
-#define CH_PLAYER_3            (1 << 2)
-#define CH_PLAYER_4            (1 << 3)
-#define CH_PLAYER_ANY          (CH_PLAYER_1 | CH_PLAYER_2 | CH_PLAYER_3 | \
-                                CH_PLAYER_4)
+#define CH_PLAYER_NONE                 PLAYER_BITS_NONE
+#define CH_PLAYER_1                    PLAYER_BITS_1
+#define CH_PLAYER_2                    PLAYER_BITS_2
+#define CH_PLAYER_3                    PLAYER_BITS_3
+#define CH_PLAYER_4                    PLAYER_BITS_4
+#define CH_PLAYER_ANY                  PLAYER_BITS_ANY
 
 /* values for change page for custom elements */
-#define CH_PAGE_ANY_FILE       (0xff)
-#define CH_PAGE_ANY            (0xffffffff)
+#define CH_PAGE_ANY_FILE               (0xff)
+#define CH_PAGE_ANY                    (0xffffffff)
 
 /* values for change power for custom elements */
-#define CP_WHEN_EMPTY          0
-#define CP_WHEN_DIGGABLE       1
-#define CP_WHEN_DESTRUCTIBLE   2
-#define CP_WHEN_COLLECTIBLE    3
-#define CP_WHEN_REMOVABLE      4
-#define CP_WHEN_WALKABLE       5
+#define CP_WHEN_EMPTY                  0
+#define CP_WHEN_DIGGABLE               1
+#define CP_WHEN_DESTRUCTIBLE           2
+#define CP_WHEN_COLLECTIBLE            3
+#define CP_WHEN_REMOVABLE              4
+#define CP_WHEN_WALKABLE               5
+
+/* values for change actions for custom elements */
+#define CA_NO_ACTION                   0
+#define CA_EXIT_PLAYER                 1
+#define CA_KILL_PLAYER                 2
+#define CA_MOVE_PLAYER                 3
+#define CA_RESTART_LEVEL               4
+#define CA_SHOW_ENVELOPE               5
+#define CA_SET_LEVEL_TIME              6
+#define CA_SET_LEVEL_GEMS              7
+#define CA_SET_LEVEL_SCORE             8
+#define CA_SET_LEVEL_WIND              9
+#define CA_SET_PLAYER_GRAVITY          10
+#define CA_SET_PLAYER_KEYS             11
+#define CA_SET_PLAYER_SPEED            12
+#define CA_SET_PLAYER_SHIELD           13
+#define CA_SET_PLAYER_ARTWORK          14
+#define CA_SET_CE_SCORE                        15
+#define CA_SET_CE_VALUE                        16
+#define CA_SET_ENGINE_SCAN_MODE                17
+
+#define CA_HEADLINE_LEVEL_ACTIONS      250
+#define CA_HEADLINE_PLAYER_ACTIONS     251
+#define CA_HEADLINE_CE_ACTIONS         252
+#define CA_HEADLINE_ENGINE_ACTIONS     253
+#define CA_UNDEFINED                   255
+
+/* values for change action mode for custom elements */
+#define CA_MODE_UNDEFINED              0
+#define CA_MODE_SET                    1
+#define CA_MODE_ADD                    2
+#define CA_MODE_SUBTRACT               3
+#define CA_MODE_MULTIPLY               4
+#define CA_MODE_DIVIDE                 5
+#define CA_MODE_MODULO                 6
+
+/* values for change action parameters for custom elements */
+#define CA_ARG_MIN                     0
+#define CA_ARG_0                       0
+#define CA_ARG_1                       1
+#define CA_ARG_2                       2
+#define CA_ARG_3                       3
+#define CA_ARG_4                       4
+#define CA_ARG_5                       5
+#define CA_ARG_6                       6
+#define CA_ARG_7                       7
+#define CA_ARG_8                       8
+#define CA_ARG_9                       9
+#define CA_ARG_10                      10
+#define CA_ARG_100                     100
+#define CA_ARG_1000                    1000
+#define CA_ARG_MAX                     9999
+#define CA_ARG_PLAYER                  10000
+#define CA_ARG_PLAYER_1                        (CA_ARG_PLAYER + PLAYER_BITS_1)
+#define CA_ARG_PLAYER_2                        (CA_ARG_PLAYER + PLAYER_BITS_2)
+#define CA_ARG_PLAYER_3                        (CA_ARG_PLAYER + PLAYER_BITS_3)
+#define CA_ARG_PLAYER_4                        (CA_ARG_PLAYER + PLAYER_BITS_4)
+#define CA_ARG_PLAYER_ANY              (CA_ARG_PLAYER + PLAYER_BITS_ANY)
+#define CA_ARG_PLAYER_TRIGGER          (CA_ARG_PLAYER + PLAYER_BITS_TRIGGER)
+#define CA_ARG_PLAYER_HEADLINE         (CA_ARG_PLAYER + 999)
+#define CA_ARG_NUMBER                  11000
+#define CA_ARG_NUMBER_MIN              (CA_ARG_NUMBER + 0)
+#define CA_ARG_NUMBER_MAX              (CA_ARG_NUMBER + 1)
+#define CA_ARG_NUMBER_RESET            (CA_ARG_NUMBER + 2)
+#define CA_ARG_NUMBER_CE_SCORE         (CA_ARG_NUMBER + 3)
+#define CA_ARG_NUMBER_CE_VALUE         (CA_ARG_NUMBER + 4)
+#define CA_ARG_NUMBER_CE_DELAY         (CA_ARG_NUMBER + 5)
+#define CA_ARG_NUMBER_LEVEL_TIME       (CA_ARG_NUMBER + 6)
+#define CA_ARG_NUMBER_LEVEL_GEMS       (CA_ARG_NUMBER + 7)
+#define CA_ARG_NUMBER_LEVEL_SCORE      (CA_ARG_NUMBER + 8)
+#define CA_ARG_NUMBER_HEADLINE         (CA_ARG_NUMBER + 999)
+#define CA_ARG_ELEMENT                 12000
+#define CA_ARG_ELEMENT_RESET           (CA_ARG_ELEMENT + 0)
+#define CA_ARG_ELEMENT_TARGET          (CA_ARG_ELEMENT + 1)
+#define CA_ARG_ELEMENT_TRIGGER         (CA_ARG_ELEMENT + 2)
+#define CA_ARG_ELEMENT_HEADLINE                (CA_ARG_ELEMENT + 997)
+#define CA_ARG_ELEMENT_CV_TARGET       (CA_ARG_ELEMENT_TARGET)
+#define CA_ARG_ELEMENT_CV_TRIGGER      (CA_ARG_ELEMENT_TRIGGER)
+#define CA_ARG_ELEMENT_CV_HEADLINE     (CA_ARG_ELEMENT_HEADLINE)
+#define CA_ARG_ELEMENT_NR_TARGET       (CA_ARG_ELEMENT + 3)
+#define CA_ARG_ELEMENT_NR_TRIGGER      (CA_ARG_ELEMENT + 4)
+#define CA_ARG_ELEMENT_NR_HEADLINE     (CA_ARG_ELEMENT + 998)
+#define CA_ARG_ELEMENT_CS_TARGET       (CA_ARG_ELEMENT + 5)
+#define CA_ARG_ELEMENT_CS_TRIGGER      (CA_ARG_ELEMENT + 6)
+#define CA_ARG_ELEMENT_CS_HEADLINE     (CA_ARG_ELEMENT + 999)
+#define CA_ARG_SPEED                   13000
+#define CA_ARG_SPEED_NOT_MOVING                (CA_ARG_SPEED + STEPSIZE_NOT_MOVING)
+#define CA_ARG_SPEED_VERY_SLOW         (CA_ARG_SPEED + STEPSIZE_VERY_SLOW)
+#define CA_ARG_SPEED_SLOW              (CA_ARG_SPEED + STEPSIZE_SLOW)
+#define CA_ARG_SPEED_NORMAL            (CA_ARG_SPEED + STEPSIZE_NORMAL)
+#define CA_ARG_SPEED_FAST              (CA_ARG_SPEED + STEPSIZE_FAST)
+#define CA_ARG_SPEED_VERY_FAST         (CA_ARG_SPEED + STEPSIZE_VERY_FAST)
+#define CA_ARG_SPEED_EVEN_FASTER       (CA_ARG_SPEED + STEPSIZE_EVEN_FASTER)
+#define CA_ARG_SPEED_SLOWER            (CA_ARG_SPEED + STEPSIZE_SLOWER)
+#define CA_ARG_SPEED_FASTER            (CA_ARG_SPEED + STEPSIZE_FASTER)
+#define CA_ARG_SPEED_RESET             (CA_ARG_SPEED + STEPSIZE_RESET)
+#define CA_ARG_SPEED_HEADLINE          (CA_ARG_SPEED + 999)
+#define CA_ARG_GRAVITY                 14000
+#define CA_ARG_GRAVITY_OFF             (CA_ARG_GRAVITY + 0)
+#define CA_ARG_GRAVITY_ON              (CA_ARG_GRAVITY + 1)
+#define CA_ARG_GRAVITY_TOGGLE          (CA_ARG_GRAVITY + 2)
+#define CA_ARG_GRAVITY_HEADLINE                (CA_ARG_GRAVITY + 999)
+#define CA_ARG_DIRECTION               15000
+#define CA_ARG_DIRECTION_NONE          (CA_ARG_DIRECTION + MV_NONE)
+#define CA_ARG_DIRECTION_LEFT          (CA_ARG_DIRECTION + MV_LEFT)
+#define CA_ARG_DIRECTION_RIGHT         (CA_ARG_DIRECTION + MV_RIGHT)
+#define CA_ARG_DIRECTION_UP            (CA_ARG_DIRECTION + MV_UP)
+#define CA_ARG_DIRECTION_DOWN          (CA_ARG_DIRECTION + MV_DOWN)
+#define CA_ARG_DIRECTION_TRIGGER       (CA_ARG_DIRECTION + MV_TRIGGER)
+#define CA_ARG_DIRECTION_TRIGGER_BACK  (CA_ARG_DIRECTION + MV_TRIGGER_BACK)
+#define CA_ARG_DIRECTION_HEADLINE      (CA_ARG_DIRECTION + 999)
+#define CA_ARG_SHIELD                  16000
+#define CA_ARG_SHIELD_OFF              (CA_ARG_SHIELD + 0)
+#define CA_ARG_SHIELD_NORMAL           (CA_ARG_SHIELD + 1)
+#define CA_ARG_SHIELD_DEADLY           (CA_ARG_SHIELD + 2)
+#define CA_ARG_SHIELD_HEADLINE         (CA_ARG_SHIELD + 999)
+#define CA_ARG_SCAN_MODE               17000
+#define CA_ARG_SCAN_MODE_NORMAL                (CA_ARG_SCAN_MODE + MV_NORMAL)
+#define CA_ARG_SCAN_MODE_REVERSE       (CA_ARG_SCAN_MODE + MV_REVERSE)
+#define CA_ARG_SCAN_MODE_HEADLINE      (CA_ARG_SCAN_MODE + 999)
+#define CA_ARG_UNDEFINED               65535
 
 /* values for custom 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
-#define MV_BIT_WHEN_PUSHED     10
-#define MV_BIT_MAZE_RUNNER     11
-#define MV_BIT_MAZE_HUNTER     12
-#define MV_BIT_WHEN_DROPPED    13
-#define MV_BIT_TURNING_LEFT_RIGHT 14
-#define MV_BIT_TURNING_RIGHT_LEFT 15
-#define MV_BIT_TURNING_RANDOM  16
+#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
+#define MV_BIT_WHEN_PUSHED             10
+#define MV_BIT_MAZE_RUNNER             11
+#define MV_BIT_MAZE_HUNTER             12
+#define MV_BIT_WHEN_DROPPED            13
+#define MV_BIT_TURNING_LEFT_RIGHT      14
+#define MV_BIT_TURNING_RIGHT_LEFT      15
+#define MV_BIT_TURNING_RANDOM          16
+#define MV_BIT_WIND_DIRECTION          17
 
 /* values for custom move patterns */
-#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)
-#define MV_WHEN_PUSHED         (1 << MV_BIT_WHEN_PUSHED)
-#define MV_MAZE_RUNNER         (1 << MV_BIT_MAZE_RUNNER)
-#define MV_MAZE_HUNTER         (1 << MV_BIT_MAZE_HUNTER)
-#define MV_MAZE_RUNNER_STYLE   (MV_MAZE_RUNNER | MV_MAZE_HUNTER)
-#define MV_WHEN_DROPPED                (1 << MV_BIT_WHEN_DROPPED)
-#define MV_TURNING_LEFT_RIGHT  (1 << MV_BIT_TURNING_LEFT_RIGHT)
-#define MV_TURNING_RIGHT_LEFT  (1 << MV_BIT_TURNING_RIGHT_LEFT)
-#define MV_TURNING_RANDOM      (1 << MV_BIT_TURNING_RANDOM)
-
-/* values for initial move direction (bits 0 - 3: basic move directions) */
-#define MV_START_BIT_PREVIOUS  4
+#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)
+#define MV_WHEN_PUSHED                 (1 << MV_BIT_WHEN_PUSHED)
+#define MV_MAZE_RUNNER                 (1 << MV_BIT_MAZE_RUNNER)
+#define MV_MAZE_HUNTER                 (1 << MV_BIT_MAZE_HUNTER)
+#define MV_MAZE_RUNNER_STYLE           (MV_MAZE_RUNNER | MV_MAZE_HUNTER)
+#define MV_WHEN_DROPPED                        (1 << MV_BIT_WHEN_DROPPED)
+#define MV_TURNING_LEFT_RIGHT          (1 << MV_BIT_TURNING_LEFT_RIGHT)
+#define MV_TURNING_RIGHT_LEFT          (1 << MV_BIT_TURNING_RIGHT_LEFT)
+#define MV_TURNING_RANDOM              (1 << MV_BIT_TURNING_RANDOM)
+#define MV_WIND_DIRECTION              (1 << MV_BIT_WIND_DIRECTION)
 
 /* values for initial move direction */
-#define MV_START_AUTOMATIC     (MV_NO_MOVING)
-#define MV_START_LEFT          (MV_LEFT)
-#define MV_START_RIGHT         (MV_RIGHT)
-#define MV_START_UP            (MV_UP)
-#define MV_START_DOWN          (MV_DOWN)
-#define MV_START_RANDOM                (MV_ALL_DIRECTIONS)
-#define MV_START_PREVIOUS      (1 << MV_START_BIT_PREVIOUS)
+#define MV_START_NONE                  (MV_NONE)
+#define MV_START_AUTOMATIC             (MV_NONE)
+#define MV_START_LEFT                  (MV_LEFT)
+#define MV_START_RIGHT                 (MV_RIGHT)
+#define MV_START_UP                    (MV_UP)
+#define MV_START_DOWN                  (MV_DOWN)
+#define MV_START_RANDOM                        (MV_ALL_DIRECTIONS)
+#define MV_START_PREVIOUS              (MV_PREVIOUS)
 
 /* values for elements left behind by custom elements */
-#define LEAVE_TYPE_UNLIMITED   0
-#define LEAVE_TYPE_LIMITED     1
+#define LEAVE_TYPE_UNLIMITED           0
+#define LEAVE_TYPE_LIMITED             1
 
 /* 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
+#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
 
 /* values for explosion type for custom elements */
-#define EXPLODES_3X3           0
-#define EXPLODES_1X1           1
-#define EXPLODES_CROSS         2
+#define EXPLODES_3X3                   0
+#define EXPLODES_1X1                   1
+#define EXPLODES_CROSS                 2
 
 /* macros for configurable properties */
 #define IS_DIGGABLE(e)         HAS_PROPERTY(e, EP_DIGGABLE)
 #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 HAS_EDITOR_CONTENT(e)  HAS_PROPERTY(e, EP_HAS_EDITOR_CONTENT)
 #define CAN_TURN_EACH_MOVE(e)  HAS_PROPERTY(e, EP_CAN_TURN_EACH_MOVE)
 #define CAN_GROW(e)            HAS_PROPERTY(e, EP_CAN_GROW)
 #define IS_ACTIVE_BOMB(e)      HAS_PROPERTY(e, EP_ACTIVE_BOMB)
                                HAS_PROPERTY(e, EP_CAN_EXPLODE_BY_EXPLOSION)
 #define COULD_MOVE_INTO_ACID(e)        HAS_PROPERTY(e, EP_COULD_MOVE_INTO_ACID)
 #define MAYBE_DONT_COLLIDE_WITH(e) HAS_PROPERTY(e, EP_MAYBE_DONT_COLLIDE_WITH)
+#define CAN_BE_CLONED_BY_ANDROID(e)    \
+                               HAS_PROPERTY(e, EP_CAN_BE_CLONED_BY_ANDROID)
+
+#define IS_EDITOR_CASCADE(e)   HAS_PROPERTY(e, EP_EDITOR_CASCADE)
+#define IS_EDITOR_CASCADE_ACTIVE(e)    \
+                               HAS_PROPERTY(e, EP_EDITOR_CASCADE_ACTIVE)
+#define IS_EDITOR_CASCADE_INACTIVE(e)  \
+                               HAS_PROPERTY(e, EP_EDITOR_CASCADE_INACTIVE)
+
+#define HAS_ACTION(e)          HAS_PROPERTY(e, EP_HAS_ACTION)
+#define CAN_CHANGE_OR_HAS_ACTION(e)    \
+                               HAS_PROPERTY(e, EP_CAN_CHANGE_OR_HAS_ACTION)
+
+#define IS_OBSOLETE(e)         HAS_PROPERTY(e, EP_OBSOLETE)
 
 /* special macros used in game engine */
 #define IS_CUSTOM_ELEMENT(e)   ((e) >= EL_CUSTOM_START &&              \
 
 #define IS_RND_GATE_GRAY(e)    ((e) >= EL_GATE_1_GRAY &&               \
                                 (e) <= EL_GATE_4_GRAY)
+#define IS_RND_GATE_GRAY_ACTIVE(e) ((e) >= EL_GATE_1_GRAY_ACTIVE &&    \
+                                (e) <= EL_GATE_4_GRAY_ACTIVE)
 #define IS_EM_GATE_GRAY(e)     ((e) >= EL_EM_GATE_1_GRAY &&            \
                                 (e) <= EL_EM_GATE_4_GRAY)
+#define IS_EM_GATE_GRAY_ACTIVE(e) ((e) >= EL_EM_GATE_1_GRAY_ACTIVE &&  \
+                                (e) <= EL_EM_GATE_4_GRAY_ACTIVE)
 #define IS_EMC_GATE_GRAY(e)    ((e) >= EL_EMC_GATE_5_GRAY &&           \
                                 (e) <= EL_EMC_GATE_8_GRAY)
+#define IS_EMC_GATE_GRAY_ACTIVE(e) ((e) >= EL_EMC_GATE_5_GRAY_ACTIVE &&        \
+                                (e) <= EL_EMC_GATE_8_GRAY_ACTIVE)
 #define IS_GATE_GRAY(e)                (IS_RND_GATE_GRAY(e) ||                 \
                                 IS_EM_GATE_GRAY(e) ||                  \
                                 IS_EMC_GATE_GRAY(e))
+#define IS_GATE_GRAY_ACTIVE(e) (IS_RND_GATE_GRAY_ACTIVE(e) ||          \
+                                IS_EM_GATE_GRAY_ACTIVE(e) ||           \
+                                IS_EMC_GATE_GRAY_ACTIVE(e))
 #define RND_GATE_GRAY_NR(e)    ((e) - EL_GATE_1_GRAY)
+#define RND_GATE_GRAY_ACTIVE_NR(e) ((e) - EL_GATE_1_GRAY_ACTIVE)
 #define EM_GATE_GRAY_NR(e)     ((e) - EL_EM_GATE_1_GRAY)
+#define EM_GATE_GRAY_ACTIVE_NR(e) ((e) - EL_EM_GATE_1_GRAY_ACTIVE)
 #define EMC_GATE_GRAY_NR(e)    ((e) - EL_EMC_GATE_5_GRAY + 4)
+#define EMC_GATE_GRAY_ACTIVE_NR(e) ((e) - EL_EMC_GATE_5_GRAY_ACTIVE + 4)
 #define GATE_GRAY_NR(e)                (IS_RND_GATE_GRAY(e) ? RND_GATE_GRAY_NR(e) :  \
                                 IS_EM_GATE_GRAY(e) ?  EM_GATE_GRAY_NR(e) :   \
                                 IS_EMC_GATE_GRAY(e) ? EMC_GATE_GRAY_NR(e) : 0)
 #define GFX_ELEMENT(e)         (element_info[e].use_gfx_element ?      \
                                 element_info[e].gfx_element : e)
 
+/* !!! CHECK THIS !!! */
+#if 1
+#define TILE_GFX_ELEMENT(x, y)                                         \
+                  (GfxElement[x][y] != EL_UNDEFINED &&                 \
+                   Feld[x][y] != EL_EXPLOSION ?                        \
+                   GfxElement[x][y] : Feld[x][y])
+#else
+#define TILE_GFX_ELEMENT(x, y)                                         \
+       GFX_ELEMENT(GfxElement[x][y] != EL_UNDEFINED &&                 \
+                   Feld[x][y] != EL_EXPLOSION ?                        \
+                   GfxElement[x][y] : Feld[x][y])
+#endif
+
 /* !!! "use sound" deactivated due to problems with level "bug machine" !!! */
 /* (solution: add separate "use sound of element" to level file and editor) */
 #if 0
 #define SND_ELEMENT(e)         (e)
 #endif
 
+#if 1
+#define GROUP_NR(e)            ((e) - EL_GROUP_START)
+#define IS_IN_GROUP(e, nr)     (element_info[e].in_group[nr] == TRUE)
+#define IS_IN_GROUP_EL(e, ge)  (IS_IN_GROUP(e, (ge) - EL_GROUP_START))
+
+#define IS_EQUAL_OR_IN_GROUP(e, ge)                                    \
+       (IS_GROUP_ELEMENT(ge) ? IS_IN_GROUP(e, GROUP_NR(ge)) : (e) == (ge))
+#endif
+
 #define IS_PLAYER(x, y)                (ELEM_IS_PLAYER(StorePlayer[x][y]))
 
 #define IS_FREE(x, y)          (Feld[x][y] == EL_EMPTY && !IS_PLAYER(x, y))
 #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 IS_MV_DIAGONAL(x)      ((x) & MV_HORIZONTAL && (x) & MV_VERTICAL)
+
 #define EL_CHANGED(e)          ((e) == EL_ROCK           ? EL_EMERALD :    \
                                 (e) == EL_BD_ROCK        ? EL_BD_DIAMOND : \
                                 (e) == EL_EMERALD        ? EL_DIAMOND :    \
 #define PLAYERINFO(x,y)                (&stored_player[StorePlayer[x][y]-EL_PLAYER_1])
 #define SHIELD_ON(p)           ((p)->shield_normal_time_left > 0)
 
-#if 1
-
 #define ENEMY_PROTECTED_FIELD(x,y)     (IS_PROTECTED(Feld[x][y]) ||       \
                                         IS_PROTECTED(Back[x][y]))
 #define EXPLOSION_PROTECTED_FIELD(x,y)  (IS_EXPLOSION_PROOF(Feld[x][y]))
 #define PLAYER_EXPLOSION_PROTECTED(x,y) (SHIELD_ON(PLAYERINFO(x, y)) ||           \
                                         EXPLOSION_PROTECTED_FIELD(x, y))
 
-#else
-
-#define PROTECTED_FIELD(x,y)   (IS_ACCESSIBLE_INSIDE(Feld[x][y]) &&    \
-                                IS_INDESTRUCTIBLE(Feld[x][y]))
-#define PLAYER_ENEMY_PROTECTED(x,y)    (SHIELD_ON(PLAYERINFO(x, y)) || \
-                                PROTECTED_FIELD(x, y))
-#define PLAYER_EXPLOSION_PROTECTED(x,y)        (SHIELD_ON(PLAYERINFO(x, y)) || \
-                                PROTECTED_FIELD(x, y))
-#endif
-
 #define PLAYER_SWITCHING(p,x,y)        ((p)->is_switching &&                   \
                                 (p)->switch_x == (x) && (p)->switch_y == (y))
 
 
 #define PLAYER_NR_GFX(g,i)     ((g) + i * (IMG_PLAYER_2 - IMG_PLAYER_1))
 
+#define GET_PLAYER_ELEMENT(e)  ((e) >= EL_PLAYER_1 && (e) <= EL_PLAYER_4 ? \
+                                (e) : EL_PLAYER_1)
+
+#define GET_PLAYER_NR(e)       (GET_PLAYER_ELEMENT(e) - EL_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_LOOP_SOUND(s)       (sound_info[s].loop)
 
+#define EL_CASCADE_ACTIVE(e)   (IS_EDITOR_CASCADE_INACTIVE(e) ? (e) + 1 : (e))
+#define EL_CASCADE_INACTIVE(e) (IS_EDITOR_CASCADE_ACTIVE(e)   ? (e) - 1 : (e))
+#define EL_CASCADE_TOGGLE(e)   (IS_EDITOR_CASCADE_INACTIVE(e) ? (e) + 1 :    \
+                                IS_EDITOR_CASCADE_ACTIVE(e)   ? (e) - 1 : (e))
+
+#define EL_NAME(e)             ((e) >= 0 ? element_info[e].token_name : "(?)")
+#define MV_TEXT(d)             ((d) == MV_NONE  ? "MV_NONE"  :         \
+                                (d) == MV_LEFT  ? "MV_LEFT"  :         \
+                                (d) == MV_RIGHT ? "MV_RIGHT" :         \
+                                (d) == MV_UP    ? "MV_UP"    :         \
+                                (d) == MV_DOWN  ? "MV_DOWN"  : "(various)")
 
 /* fundamental game speed values */
-#define ONE_SECOND_DELAY       1000    /* delay value for one second */
-#define GAME_FRAME_DELAY       20      /* frame delay in milliseconds */
-#define FFWD_FRAME_DELAY       10      /* 200% speed for fast forward */
-#define FRAMES_PER_SECOND      (ONE_SECOND_DELAY / GAME_FRAME_DELAY)
 #define MICROLEVEL_SCROLL_DELAY        50      /* delay for scrolling micro level */
 #define MICROLEVEL_LABEL_DELAY 250     /* delay for micro level label */
 
 #define MAX_LEVEL_NAME_LEN     32
 #define MAX_LEVEL_AUTHOR_LEN   32
 #define MAX_ELEMENT_NAME_LEN   32
-#define MAX_TAPE_LEN           (1000 * FRAMES_PER_SECOND) /* max.time x fps */
 #define MAX_TAPES_PER_SET      1024
 #define MAX_SCORE_ENTRIES      100
+#define MAX_NUM_TITLE_SCREENS  5
+
 #define MAX_NUM_AMOEBA         100
+
+#if 0  /* game.h */
 #define MAX_INVENTORY_SIZE     1000
 #define STD_NUM_KEYS           4
 #define MAX_NUM_KEYS           8
+#endif
+
 #define NUM_BELTS              4
 #define NUM_BELT_PARTS         3
+#define NUM_ENVELOPES          4
 #define MIN_ENVELOPE_XSIZE     1
 #define MIN_ENVELOPE_YSIZE     1
 #define MAX_ENVELOPE_XSIZE     30
 #define MAX_CHANGE_PAGES       32
 #define MIN_ELEMENTS_IN_GROUP  1
 #define MAX_ELEMENTS_IN_GROUP  16
+#define MIN_ANDROID_ELEMENTS   1
+#define MAX_ANDROID_ELEMENTS   16
 
 /* values for elements with content */
 #define MIN_ELEMENT_CONTENTS   1
 #define STD_ELEMENT_CONTENTS   4
 #define MAX_ELEMENT_CONTENTS   8
-#define NUM_MAGIC_BALL_CONTENTS        8
-
-#define LEVEL_SCORE_ELEMENTS   16      /* level elements with score */
 
 /* often used screen positions */
 #define SX                     8
 #define SC_CRYSTAL             11
 #define SC_PEARL               12
 #define SC_SHIELD              13
+#define SC_UNKNOWN_14          14
+#define SC_UNKNOWN_15          15
+
+#define LEVEL_SCORE_ELEMENTS   16      /* level elements with score */
 
 
 /* "real" level file elements */
 #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_EM_DYNAMITE                 254
+#define EL_EM_DYNAMITE_ACTIVE          255
 
 #define EL_PEARL                       256
 #define EL_CRYSTAL                     257
 #define EL_TRIGGER_ELEMENT             657
 #define EL_TRIGGER_PLAYER              658
 
+/* SP style elements */
 #define EL_SP_GRAVITY_ON_PORT_RIGHT    659
 #define EL_SP_GRAVITY_ON_PORT_DOWN     660
 #define EL_SP_GRAVITY_ON_PORT_LEFT     661
 #define EL_SP_GRAVITY_OFF_PORT_LEFT    665
 #define EL_SP_GRAVITY_OFF_PORT_UP      666
 
-
-/* the following EMC style elements are currently not implemented in R'n'D */
+/* EMC style elements */
 #define EL_BALLOON_SWITCH_NONE         667
 #define EL_EMC_GATE_5                  668
 #define EL_EMC_GATE_6                  669
 #define EL_EMC_FAKE_ACID               703
 #define EL_EMC_DRIPPER                 704
 
-#define NUM_FILE_ELEMENTS              705
+#define EL_TRIGGER_CE_VALUE            705
+#define EL_TRIGGER_CE_SCORE            706
+#define EL_CURRENT_CE_VALUE            707
+#define EL_CURRENT_CE_SCORE            708
+
+#define EL_YAMYAM_LEFT                 709
+#define EL_YAMYAM_RIGHT                        710
+#define EL_YAMYAM_UP                   711
+#define EL_YAMYAM_DOWN                 712
+
+#define EL_BD_EXPANDABLE_WALL          713
+
+#define NUM_FILE_ELEMENTS              714
 
 
 /* "real" (and therefore drawable) runtime elements */
 #define EL_BD_MAGIC_WALL_EMPTYING      (EL_FIRST_RUNTIME_REAL + 42)
 #define EL_MAGIC_WALL_DEAD             (EL_FIRST_RUNTIME_REAL + 43)
 #define EL_BD_MAGIC_WALL_DEAD          (EL_FIRST_RUNTIME_REAL + 44)
+#define EL_EMC_FAKE_GRASS_ACTIVE       (EL_FIRST_RUNTIME_REAL + 45)
+#define EL_GATE_1_GRAY_ACTIVE          (EL_FIRST_RUNTIME_REAL + 46)
+#define EL_GATE_2_GRAY_ACTIVE          (EL_FIRST_RUNTIME_REAL + 47)
+#define EL_GATE_3_GRAY_ACTIVE          (EL_FIRST_RUNTIME_REAL + 48)
+#define EL_GATE_4_GRAY_ACTIVE          (EL_FIRST_RUNTIME_REAL + 49)
+#define EL_EM_GATE_1_GRAY_ACTIVE       (EL_FIRST_RUNTIME_REAL + 50)
+#define EL_EM_GATE_2_GRAY_ACTIVE       (EL_FIRST_RUNTIME_REAL + 51)
+#define EL_EM_GATE_3_GRAY_ACTIVE       (EL_FIRST_RUNTIME_REAL + 52)
+#define EL_EM_GATE_4_GRAY_ACTIVE       (EL_FIRST_RUNTIME_REAL + 53)
+#define EL_EMC_GATE_5_GRAY_ACTIVE      (EL_FIRST_RUNTIME_REAL + 54)
+#define EL_EMC_GATE_6_GRAY_ACTIVE      (EL_FIRST_RUNTIME_REAL + 55)
+#define EL_EMC_GATE_7_GRAY_ACTIVE      (EL_FIRST_RUNTIME_REAL + 56)
+#define EL_EMC_GATE_8_GRAY_ACTIVE      (EL_FIRST_RUNTIME_REAL + 57)
+#define EL_EMC_DRIPPER_ACTIVE          (EL_FIRST_RUNTIME_REAL + 58)
+#define EL_EMC_SPRING_BUMPER_ACTIVE    (EL_FIRST_RUNTIME_REAL + 59)
 
 /* "unreal" (and therefore not drawable) runtime elements */
-#define EL_FIRST_RUNTIME_UNREAL                (EL_FIRST_RUNTIME_REAL + 45)
+#define EL_FIRST_RUNTIME_UNREAL                (EL_FIRST_RUNTIME_REAL + 60)
 
 #define EL_BLOCKED                     (EL_FIRST_RUNTIME_UNREAL + 0)
 #define EL_EXPLOSION                   (EL_FIRST_RUNTIME_UNREAL + 1)
 #define EL_QUICKSAND_FILLING           (EL_FIRST_RUNTIME_UNREAL + 15)
 #define EL_MAGIC_WALL_FILLING          (EL_FIRST_RUNTIME_UNREAL + 16)
 #define EL_BD_MAGIC_WALL_FILLING       (EL_FIRST_RUNTIME_UNREAL + 17)
+#define EL_ELEMENT_SNAPPING            (EL_FIRST_RUNTIME_UNREAL + 18)
+#define EL_DIAGONAL_SHRINKING          (EL_FIRST_RUNTIME_UNREAL + 19)
+#define EL_DIAGONAL_GROWING            (EL_FIRST_RUNTIME_UNREAL + 20)
+
+#define NUM_RUNTIME_ELEMENTS           (EL_FIRST_RUNTIME_UNREAL + 21)
 
 /* dummy elements (never used as game elements, only used as graphics) */
-#define EL_FIRST_DUMMY                 (EL_FIRST_RUNTIME_UNREAL + 18)
+#define EL_FIRST_DUMMY                 NUM_RUNTIME_ELEMENTS
 
 #define EL_STEELWALL_TOPLEFT           (EL_FIRST_DUMMY + 0)
 #define EL_STEELWALL_TOPRIGHT          (EL_FIRST_DUMMY + 1)
 #define EL_INTERNAL_CLIPBOARD_GROUP    (EL_FIRST_INTERNAL + 2)
 #define EL_INTERNAL_DUMMY              (EL_FIRST_INTERNAL + 3)
 
+#define EL_INTERNAL_CASCADE_BD                 (EL_FIRST_INTERNAL + 4)
+#define EL_INTERNAL_CASCADE_BD_ACTIVE          (EL_FIRST_INTERNAL + 5)
+#define EL_INTERNAL_CASCADE_EM                 (EL_FIRST_INTERNAL + 6)
+#define EL_INTERNAL_CASCADE_EM_ACTIVE          (EL_FIRST_INTERNAL + 7)
+#define EL_INTERNAL_CASCADE_EMC                        (EL_FIRST_INTERNAL + 8)
+#define EL_INTERNAL_CASCADE_EMC_ACTIVE         (EL_FIRST_INTERNAL + 9)
+#define EL_INTERNAL_CASCADE_RND                        (EL_FIRST_INTERNAL + 10)
+#define EL_INTERNAL_CASCADE_RND_ACTIVE         (EL_FIRST_INTERNAL + 11)
+#define EL_INTERNAL_CASCADE_SB                 (EL_FIRST_INTERNAL + 12)
+#define EL_INTERNAL_CASCADE_SB_ACTIVE          (EL_FIRST_INTERNAL + 13)
+#define EL_INTERNAL_CASCADE_SP                 (EL_FIRST_INTERNAL + 14)
+#define EL_INTERNAL_CASCADE_SP_ACTIVE          (EL_FIRST_INTERNAL + 15)
+#define EL_INTERNAL_CASCADE_DC                 (EL_FIRST_INTERNAL + 16)
+#define EL_INTERNAL_CASCADE_DC_ACTIVE          (EL_FIRST_INTERNAL + 17)
+#define EL_INTERNAL_CASCADE_DX                 (EL_FIRST_INTERNAL + 18)
+#define EL_INTERNAL_CASCADE_DX_ACTIVE          (EL_FIRST_INTERNAL + 19)
+#define EL_INTERNAL_CASCADE_CHARS              (EL_FIRST_INTERNAL + 20)
+#define EL_INTERNAL_CASCADE_CHARS_ACTIVE       (EL_FIRST_INTERNAL + 21)
+#define EL_INTERNAL_CASCADE_CE                 (EL_FIRST_INTERNAL + 22)
+#define EL_INTERNAL_CASCADE_CE_ACTIVE          (EL_FIRST_INTERNAL + 23)
+#define EL_INTERNAL_CASCADE_GE                 (EL_FIRST_INTERNAL + 24)
+#define EL_INTERNAL_CASCADE_GE_ACTIVE          (EL_FIRST_INTERNAL + 25)
+#define EL_INTERNAL_CASCADE_REF                        (EL_FIRST_INTERNAL + 26)
+#define EL_INTERNAL_CASCADE_REF_ACTIVE         (EL_FIRST_INTERNAL + 27)
+#define EL_INTERNAL_CASCADE_USER               (EL_FIRST_INTERNAL + 28)
+#define EL_INTERNAL_CASCADE_USER_ACTIVE                (EL_FIRST_INTERNAL + 29)
+#define EL_INTERNAL_CASCADE_DYNAMIC            (EL_FIRST_INTERNAL + 30)
+#define EL_INTERNAL_CASCADE_DYNAMIC_ACTIVE     (EL_FIRST_INTERNAL + 31)
+
 #define EL_INTERNAL_CLIPBOARD_START    (EL_FIRST_INTERNAL + 0)
 #define EL_INTERNAL_CLIPBOARD_END      (EL_FIRST_INTERNAL + 2)
 #define EL_INTERNAL_START              (EL_FIRST_INTERNAL + 0)
-#define EL_INTERNAL_END                        (EL_FIRST_INTERNAL + 3)
+#define EL_INTERNAL_END                        (EL_FIRST_INTERNAL + 31)
 
-#define MAX_NUM_ELEMENTS               (EL_FIRST_INTERNAL + 4)
+#define MAX_NUM_ELEMENTS               (EL_FIRST_INTERNAL + 32)
 
 
 /* values for graphics/sounds action types */
 #define ACTION_TURNING_FROM_DOWN       46
 #define ACTION_SMASHED_BY_ROCK         47
 #define ACTION_SMASHED_BY_SPRING       48
-#define ACTION_SLURPED_BY_SPRING       49
+#define ACTION_EATING                  49
 #define ACTION_TWINKLING               50
 #define ACTION_SPLASHING               51
-#define ACTION_OTHER                   52
-
-#define NUM_ACTIONS                    53
+#define ACTION_PAGE_1                  52
+#define ACTION_PAGE_2                  53
+#define ACTION_PAGE_3                  54
+#define ACTION_PAGE_4                  55
+#define ACTION_PAGE_5                  56
+#define ACTION_PAGE_6                  57
+#define ACTION_PAGE_7                  58
+#define ACTION_PAGE_8                  59
+#define ACTION_PAGE_9                  60
+#define ACTION_PAGE_10                 61
+#define ACTION_PAGE_11                 62
+#define ACTION_PAGE_12                 63
+#define ACTION_PAGE_13                 64
+#define ACTION_PAGE_14                 65
+#define ACTION_PAGE_15                 66
+#define ACTION_PAGE_16                 67
+#define ACTION_PAGE_17                 68
+#define ACTION_PAGE_18                 69
+#define ACTION_PAGE_19                 70
+#define ACTION_PAGE_20                 71
+#define ACTION_PAGE_21                 72
+#define ACTION_PAGE_22                 73
+#define ACTION_PAGE_23                 74
+#define ACTION_PAGE_24                 75
+#define ACTION_PAGE_25                 76
+#define ACTION_PAGE_26                 77
+#define ACTION_PAGE_27                 78
+#define ACTION_PAGE_28                 79
+#define ACTION_PAGE_29                 80
+#define ACTION_PAGE_30                 81
+#define ACTION_PAGE_31                 82
+#define ACTION_PAGE_32                 83
+#define ACTION_OTHER                   84
+
+#define NUM_ACTIONS                    85
 
 #define ACTION_BORING_LAST             ACTION_BORING_10
 #define ACTION_SLEEPING_LAST           ACTION_SLEEPING_3
 
 /* values for special image configuration suffixes (must match game mode) */
 #define GFX_SPECIAL_ARG_DEFAULT                0
-#define GFX_SPECIAL_ARG_MAIN           1
-#define GFX_SPECIAL_ARG_LEVELS         2
-#define GFX_SPECIAL_ARG_SCORES         3
-#define GFX_SPECIAL_ARG_EDITOR         4
-#define GFX_SPECIAL_ARG_INFO           5
-#define GFX_SPECIAL_ARG_SETUP          6
-#define GFX_SPECIAL_ARG_PLAYING                7
-#define GFX_SPECIAL_ARG_DOOR           8
-#define GFX_SPECIAL_ARG_PREVIEW                9
-#define GFX_SPECIAL_ARG_CRUMBLED       10
+#define GFX_SPECIAL_ARG_TITLE          1
+#define GFX_SPECIAL_ARG_MAIN           2
+#define GFX_SPECIAL_ARG_LEVELS         3
+#define GFX_SPECIAL_ARG_SCORES         4
+#define GFX_SPECIAL_ARG_EDITOR         5
+#define GFX_SPECIAL_ARG_INFO           6
+#define GFX_SPECIAL_ARG_SETUP          7
+#define GFX_SPECIAL_ARG_PLAYING                8
+#define GFX_SPECIAL_ARG_DOOR           9
+#define GFX_SPECIAL_ARG_PREVIEW                10
+#define GFX_SPECIAL_ARG_CRUMBLED       11
 
-#define NUM_SPECIAL_GFX_ARGS           11
+#define NUM_SPECIAL_GFX_ARGS           12
 
 
 /* values for image configuration suffixes */
 #define GFX_ARG_POST_DELAY_RANDOM      35
 #define GFX_ARG_NAME                   36
 #define GFX_ARG_SCALE_UP_FACTOR                37
+#define GFX_ARG_CLONE_FROM             38
 
-#define NUM_GFX_ARGS                   38
+#define NUM_GFX_ARGS                   39
 
 
 /* values for sound configuration suffixes */
 #define FONT_VALUE_1                   26
 #define FONT_VALUE_2                   27
 #define FONT_VALUE_OLD                 28
-#define FONT_LEVEL_NUMBER              29
-#define FONT_TAPE_RECORDER             30
-#define FONT_GAME_INFO                 31
+#define FONT_LEVEL_NUMBER_ACTIVE       29
+#define FONT_LEVEL_NUMBER              30
+#define FONT_TAPE_RECORDER             31
+#define FONT_GAME_INFO                 32
 
-#define NUM_FONTS                      32
+#define NUM_FONTS                      33
 #define NUM_INITIAL_FONTS              4
 
 /* values for game_status (must match special image configuration suffixes) */
 #define GAME_MODE_DEFAULT              0
-#define GAME_MODE_MAIN                 1
-#define GAME_MODE_LEVELS               2
-#define GAME_MODE_SCORES               3
-#define GAME_MODE_EDITOR               4
-#define GAME_MODE_INFO                 5
-#define GAME_MODE_SETUP                        6
-#define GAME_MODE_PLAYING              7
-#define GAME_MODE_PSEUDO_DOOR          8
-#define GAME_MODE_PSEUDO_PREVIEW       9
-#define GAME_MODE_PSEUDO_CRUMBLED      10
+#define GAME_MODE_TITLE                        1
+#define GAME_MODE_MAIN                 2
+#define GAME_MODE_LEVELS               3
+#define GAME_MODE_SCORES               4
+#define GAME_MODE_EDITOR               5
+#define GAME_MODE_INFO                 6
+#define GAME_MODE_SETUP                        7
+#define GAME_MODE_PLAYING              8
+#define GAME_MODE_PSEUDO_DOOR          9
+#define GAME_MODE_PSEUDO_PREVIEW       10
+#define GAME_MODE_PSEUDO_CRUMBLED      11
 
 /* there are no special config file suffixes for these modes */
-#define GAME_MODE_PSEUDO_TYPENAME      11
-#define GAME_MODE_QUIT                 12
+#define GAME_MODE_PSEUDO_TYPENAME      12
+#define GAME_MODE_QUIT                 13
 
 /* special definitions currently only used for custom artwork configuration */
 #define MUSIC_PREFIX_BACKGROUND                0
 
 
 /* program information and versioning definitions */
-
-#define RELEASE_312                    TRUE
-
 #define PROGRAM_VERSION_MAJOR          3
-#define PROGRAM_VERSION_MINOR          1
-#define PROGRAM_VERSION_PATCH          2
-#define PROGRAM_VERSION_BUILD          0
+#define PROGRAM_VERSION_MINOR          2
+#define PROGRAM_VERSION_PATCH          0
+#define PROGRAM_VERSION_BUILD          9
 
 #define PROGRAM_TITLE_STRING           "Rocks'n'Diamonds"
 #define PROGRAM_AUTHOR_STRING          "Holger Schemel"
 #define FILE_VERSION_1_2               VERSION_IDENT(1,2,0,0)
 #define FILE_VERSION_1_4               VERSION_IDENT(1,4,0,0)
 #define FILE_VERSION_2_0               VERSION_IDENT(2,0,0,0)
+#define FILE_VERSION_3_0               VERSION_IDENT(3,0,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 FILE_VERSION_ACTUAL            FILE_VERSION_3_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_3_0               FILE_VERSION_3_0
 
 #define GAME_VERSION_ACTUAL            VERSION_IDENT(PROGRAM_VERSION_MAJOR, \
                                                      PROGRAM_VERSION_MINOR, \
@@ -1483,6 +1807,8 @@ struct MenuInfo
 
 struct DoorInfo
 {
+  int width;
+  int height;
   int step_offset;
   int step_delay;
   int anim_mode;
@@ -1494,109 +1820,17 @@ struct HiScore
   int Score;
 };
 
-struct PlayerInfo
+struct Content
 {
-  boolean present;             /* player present in level playfield */
-  boolean connected;           /* player connected (locally or via network) */
-  boolean active;              /* player present and connected */
-
-  int index_nr;                        /* player number (0 to 3) */
-  int index_bit;               /* player number bit (1 << 0 to 1 << 3) */
-  int element_nr;              /* element (EL_PLAYER_1 to EL_PLAYER_4) */
-  int client_nr;               /* network client identifier */
-
-  byte action;                 /* action from local input device */
-  byte effective_action;       /* action acknowledged from network server
-                                  or summarized over all configured input
-                                  devices when in single player mode */
-  byte programmed_action;      /* action forced by game itself (like moving
-                                  through doors); overrides other actions */
-
-  int jx, jy, last_jx, last_jy;
-  int MovDir, MovPos, GfxDir, GfxPos;
-  int Frame, StepFrame;
-
-  int GfxAction;
-
-  boolean use_murphy_graphic;
-
-  boolean block_last_field;
-  int block_delay_adjustment;  /* needed for different engine versions */
-
-  boolean can_fall_into_acid;
-
-  boolean LevelSolved, GameOver;
-
-  int last_move_dir;
-
-  boolean is_waiting;
-  boolean is_moving;
-  boolean is_auto_moving;
-  boolean is_digging;
-  boolean is_snapping;
-  boolean is_collecting;
-  boolean is_pushing;
-  boolean is_switching;
-  boolean is_dropping;
-
-  boolean is_bored;
-  boolean is_sleeping;
-
-  int frame_counter_bored;
-  int frame_counter_sleeping;
-
-  int anim_delay_counter;
-  int post_delay_counter;
-
-  int action_waiting, last_action_waiting;
-  int special_action_bored;
-  int special_action_sleeping;
-
-  int num_special_action_bored;
-  int num_special_action_sleeping;
-
-  int switch_x, switch_y;
-  int drop_x, drop_y;
-
-  int show_envelope;
-
-#if 1  /* USE_NEW_MOVE_DELAY */
-  int move_delay;
-  int move_delay_value;
-#else
-  unsigned long move_delay;
-  int move_delay_value;
-#endif
-
-  int move_delay_reset_counter;
-
-#if 1  /* USE_NEW_PUSH_DELAY */
-  int push_delay;
-  int push_delay_value;
-#else
-  unsigned long push_delay;
-  unsigned long push_delay_value;
-#endif
-
-  unsigned long actual_frame_counter;
-
-  int drop_delay;
-
-  int step_counter;
+  int e[3][3];
+};
 
-  int score;
-  int gems_still_needed;
-  int sokobanfields_still_needed;
-  int lights_still_needed;
-  int friends_still_needed;
-  int key[MAX_NUM_KEYS];
-  int dynabomb_count, dynabomb_size, dynabombs_left, dynabomb_xl;
-  int shield_normal_time_left;
-  int shield_deadly_time_left;
+struct EnvelopeInfo
+{
+  int xsize;
+  int ysize;
 
-  int inventory_element[MAX_INVENTORY_SIZE];
-  int inventory_infinite_element;
-  int inventory_size;
+  char text[MAX_ENVELOPE_TEXT_LEN + 1];
 };
 
 struct LevelSetInfo
@@ -1613,6 +1847,13 @@ struct LevelFileInfo
   char *filename;
 };
 
+struct DateInfo
+{
+  int year;
+  int month;
+  int day;
+};
+
 struct LevelInfo
 {
   struct LevelFileInfo file_info;
@@ -1625,6 +1866,8 @@ struct LevelInfo
   int file_version;    /* file format version the level is stored with    */
   int game_version;    /* game release version the level was created with */
 
+  struct DateInfo creation_date;
+
   boolean encoding_16bit_field;                /* level contains 16-bit elements  */
   boolean encoding_16bit_yamyam;       /* yamyam contains 16-bit elements */
   boolean encoding_16bit_amoeba;       /* amoeba contains 16-bit elements */
@@ -1637,22 +1880,42 @@ struct LevelInfo
   char name[MAX_LEVEL_NAME_LEN + 1];
   char author[MAX_LEVEL_AUTHOR_LEN + 1];
 
-  char envelope_text[4][MAX_ENVELOPE_TEXT_LEN + 1];
-  int envelope_xsize[4], envelope_ysize[4];
+  struct EnvelopeInfo envelope[NUM_ENVELOPES];
 
   int score[LEVEL_SCORE_ELEMENTS];
 
-  int yamyam_content[MAX_ELEMENT_CONTENTS][3][3];
+  struct Content yamyam_content[MAX_ELEMENT_CONTENTS];
   int num_yamyam_contents;
 
   int amoeba_speed;
   int amoeba_content;
 
+  int game_of_life[4];
+  int biomaze[4];
+
   int time_magic_wall;
   int time_wheel;
   int time_light;
   int time_timegate;
 
+  int shield_normal_time;
+  int shield_deadly_time;
+
+  int extra_time;
+  int time_orb_time;
+
+  int extra_time_score;
+
+  int start_element[MAX_PLAYERS];
+  boolean use_start_element[MAX_PLAYERS];
+
+  int artwork_element[MAX_PLAYERS];
+  boolean use_artwork_element[MAX_PLAYERS];
+
+  int explosion_element[MAX_PLAYERS];
+  boolean use_explosion_element[MAX_PLAYERS];
+
+#if 1
   /* values for the new EMC elements */
   int android_move_time;
   int android_clone_time;
@@ -1665,28 +1928,35 @@ struct LevelInfo
   int lenses_time;
   int magnify_time;
   int wind_direction_initial;
-  int ball_content[NUM_MAGIC_BALL_CONTENTS][3][3];
+
+  struct Content ball_content[MAX_ELEMENT_CONTENTS];
+  int num_ball_contents;
+
+#if 0
   boolean android_array[16];
+#endif
+  int num_android_clone_elements;
+  int android_clone_element[MAX_ANDROID_ELEMENTS];
+#endif
 
   int can_move_into_acid_bits; /* bitfield to store property for elements */
   int dont_collide_with_bits;  /* bitfield to store property for elements */
 
-  boolean double_speed;
-  boolean initial_gravity;
+  int initial_player_stepsize[MAX_PLAYERS];    /* initial player speed */
+  boolean initial_player_gravity[MAX_PLAYERS];
+
   boolean em_slippery_gems;    /* EM style "gems slip from wall" behaviour */
   boolean use_spring_bug;      /* for compatibility with old levels */
+  boolean use_time_orb_bug;    /* for compatibility with old levels */
   boolean instant_relocation;  /* no visual delay when relocating player */
   boolean can_pass_to_walkable;        /* player can pass to empty or walkable tile */
   boolean grow_into_diggable;  /* amoeba can grow into anything diggable */
 
+  boolean continuous_snapping; /* repeated snapping without releasing key */
+  boolean block_snap_field;    /* snapping blocks field to show animation */
   boolean block_last_field;    /* player blocks previous field while moving */
   boolean sp_block_last_field; /* player blocks previous field while moving */
 
-#if 0  /* !!! THIS IS NOT A LEVEL SETTING => LOGIC MOVED TO "game.c" !!! */
-  int block_delay;             /* delay for blocking previous field */
-  int sp_block_delay;          /* delay for blocking previous field */
-#endif
-
   /* ('int' instead of 'boolean' because used as selectbox value in editor) */
   int use_step_counter;                /* count steps instead of seconds for level */
 
@@ -1699,81 +1969,6 @@ struct LevelInfo
   boolean changed;             /* set when level was changed in the editor */
 };
 
-struct TapeInfo
-{
-  int file_version;    /* file format version the tape is stored with    */
-  int game_version;    /* game release version the tape was created with */
-  int engine_version;  /* game engine version the tape was recorded with */
-
-  char *level_identifier;
-  int level_nr;
-  unsigned long random_seed;
-  unsigned long date;
-  unsigned long counter;
-  unsigned long length;
-  unsigned long length_seconds;
-  unsigned int delay_played;
-  boolean pause_before_death;
-  boolean recording, playing, pausing;
-  boolean fast_forward;
-  boolean warp_forward;
-  boolean deactivate_display;
-  boolean auto_play;
-  boolean auto_play_level_solved;
-  boolean quick_resume;
-  boolean single_step;
-  boolean changed;
-  boolean player_participates[MAX_PLAYERS];
-  int num_participating_players;
-
-  struct
-  {
-    byte action[MAX_PLAYERS];
-    byte delay;
-  } pos[MAX_TAPE_LEN];
-
-  boolean no_valid_file;       /* set when tape file missing or invalid */
-};
-
-struct GameInfo
-{
-  /* values for engine initialization */
-  int default_push_delay_fixed;
-  int default_push_delay_random;
-
-  /* constant within running game */
-  int engine_version;
-  int emulation;
-  int initial_move_delay;
-  int initial_move_delay_value;
-  int initial_push_delay_value;
-
-  /* flags to handle bugs in and changes between different engine versions */
-  /* (for the latest engine version, these flags should always be "FALSE") */
-  boolean use_change_when_pushing_bug;
-  boolean use_block_last_field_bug;
-
-  /* variable within running game */
-  int yamyam_content_nr;
-  boolean magic_wall_active;
-  int magic_wall_time_left;
-  int light_time_left;
-  int timegate_time_left;
-  int belt_dir[4];
-  int belt_dir_nr[4];
-  int switchgate_pos;
-  int balloon_dir;
-  boolean gravity;
-  boolean explosions_delayed;
-  boolean envelope_active;
-
-  /* values for player idle animation (no effect on engine) */
-  int player_boring_delay_fixed;
-  int player_boring_delay_random;
-  int player_sleeping_delay_fixed;
-  int player_sleeping_delay_random;
-};
-
 struct GlobalInfo
 {
   char *autoplay_leveldir;
@@ -1794,25 +1989,21 @@ struct ElementChangeInfo
 {
   boolean can_change;          /* use or ignore this change info */
 
-#if 1
   boolean has_event[NUM_CHANGE_EVENTS];                /* change events */
-#else
-  unsigned long events;                /* change events */
-#endif
 
   int trigger_player;          /* player triggering change */
   int trigger_side;            /* side triggering change */
   int trigger_page;            /* page triggering change */
 
-  short target_element;                /* target element after change */
+  int target_element;          /* target element after change */
 
   int delay_fixed;             /* added frame delay before changed (fixed) */
   int delay_random;            /* added frame delay before changed (random) */
   int delay_frames;            /* either 1 (frames) or 50 (seconds; 50 fps) */
 
-  short trigger_element;       /* element triggering change */
+  int trigger_element;         /* element triggering change */
 
-  int target_content[3][3];    /* elements for extended change target */
+  struct Content target_content;/* elements for extended change target */
   boolean use_target_content;  /* use extended change target */
   boolean only_if_complete;    /* only use complete target content */
   boolean use_random_replace;  /* use random value for replacing elements */
@@ -1821,6 +2012,11 @@ struct ElementChangeInfo
 
   boolean explode;             /* explode instead of change */
 
+  boolean has_action;          /* execute action on specified condition */
+  int action_type;             /* type of action */
+  int action_mode;             /* mode of action */
+  int action_arg;              /* parameter of action */
+
   /* ---------- internal values used at runtime when playing ---------- */
 
   /* functions that are called before, while and after the change of an
@@ -1830,7 +2026,12 @@ struct ElementChangeInfo
   void (*post_change_function)(int x, int y);
 
   short actual_trigger_element;        /* element that actually triggered change */
+  int actual_trigger_side;     /* element side that triggered the change */
   int actual_trigger_player;   /* player which actually triggered change */
+  int actual_trigger_ce_value; /* CE value of element that triggered change */
+  int actual_trigger_ce_score; /* CE score of element that triggered change */
+
+  boolean can_change_or_has_action;    /* can_change | has_action */
 
   /* ---------- internal values used in level editor ---------- */
 
@@ -1841,7 +2042,7 @@ struct ElementChangeInfo
 struct ElementGroupInfo
 {
   int num_elements;                    /* number of elements in this group */
-  short element[MAX_ELEMENTS_IN_GROUP];        /* list of elements in this group */
+  int element[MAX_ELEMENTS_IN_GROUP];  /* list of elements in this group */
 
   int choice_mode;             /* how to choose element from group */
 
@@ -1877,11 +2078,11 @@ struct ElementInfo
   /* ---------- graphic and sound definitions ---------- */
 
   int graphic[NUM_ACTIONS];    /* default graphics for several actions */
-  int direction_graphic[NUM_ACTIONS][NUM_DIRECTIONS];
+  int direction_graphic[NUM_ACTIONS][NUM_DIRECTIONS_FULL];
                                /* special graphics for left/right/up/down */
 
   int crumbled[NUM_ACTIONS];   /* crumbled graphics for several actions */
-  int direction_crumbled[NUM_ACTIONS][NUM_DIRECTIONS];
+  int direction_crumbled[NUM_ACTIONS][NUM_DIRECTIONS_FULL];
                                /* crumbled graphics for left/right/up/down */
 
   int special_graphic[NUM_SPECIAL_GFX_ARGS];
@@ -1891,13 +2092,19 @@ struct ElementInfo
 
   /* ---------- special element property values ---------- */
 
+  unsigned long properties[NUM_EP_BITFIELDS];  /* element base properties */
+
   boolean use_gfx_element;     /* use custom graphic element */
-  short gfx_element;           /* optional custom graphic element */
+  int gfx_element;             /* optional custom graphic element */
 
   int access_direction;                /* accessible from which direction */
 
-  int collect_score;           /* score value for collecting */
-  int collect_count;           /* count value for collecting */
+  int collect_score_initial;   /* initial score value for collecting */
+  int collect_count_initial;   /* initial count value for collecting */
+
+  int ce_value_fixed_initial;  /* initial value for custom variable (fix) */
+  int ce_value_random_initial; /* initial value for custom variable (rnd) */
+  boolean use_last_ce_value;   /* use value from element before change */
 
   int push_delay_fixed;                /* constant delay before pushing */
   int push_delay_random;       /* additional random delay before pushing */
@@ -1916,7 +2123,7 @@ struct ElementInfo
 
   int slippery_type;           /* how/where other elements slip away */
 
-  int content[3][3];           /* new elements after explosion */
+  struct Content content;      /* new elements after explosion */
 
   int explosion_type;          /* type of explosion, like 3x3, 3+3 or 1x1 */
   int explosion_delay;         /* duration of explosion of this element */
@@ -1932,21 +2139,14 @@ struct ElementInfo
 
   /* ---------- internal values used at runtime when playing ---------- */
 
-#if 1
   boolean has_change_event[NUM_CHANGE_EVENTS];
-#else
-  unsigned long change_events; /* bitfield for combined change events */
-#endif
 
   int event_page_nr[NUM_CHANGE_EVENTS]; /* page number for each event */
   struct ElementChangeInfo *event_page[NUM_CHANGE_EVENTS]; /* page for event */
 
   boolean in_group[NUM_GROUP_ELEMENTS];
 
-#if 0
-  boolean can_leave_element;   /* element can leave other element behind */
-  boolean can_leave_element_last;
-#endif
+  int collect_score;           /* runtime score value for collecting */
 
   /* ---------- internal values used in level editor ---------- */
 
@@ -1978,6 +2178,9 @@ struct FontInfo
 struct GraphicInfo
 {
   Bitmap *bitmap;
+  int src_image_width;         /* scaled bitmap size, but w/o small images */
+  int src_image_height;                /* scaled bitmap size, but w/o small images */
+
   int src_x, src_y;            /* start position of animation frames */
   int width, height;           /* width/height of each animation frame */
   int offset_x, offset_y;      /* x/y offset to next animation frame */
@@ -1994,6 +2197,7 @@ struct GraphicInfo
   int diggable_like;           /* element for cloning digging graphics */
   int border_size;             /* border size for "crumbled" graphics */
   int scale_up_factor;         /* optional factor for scaling image up */
+  int clone_from;              /* graphic for cloning *all* settings */
 
   int anim_delay_fixed;                /* optional delay values for bored and   */
   int anim_delay_random;       /* sleeping player animations (animation */
@@ -2003,7 +2207,8 @@ struct GraphicInfo
   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 */
+  int draw_xoffset;            /* optional offset for drawing font chars */
+  int draw_yoffset;            /* optional offset for drawing font chars */
 
   int draw_masked;             /* optional setting for drawing envelope gfx */
 
@@ -2081,14 +2286,12 @@ struct HelpAnimInfo
 };
 
 
-#if 0
-extern GC                      tile_clip_gc;
-extern Bitmap                 *pix[];
-#endif
-extern Bitmap                 *bitmap_db_field, *bitmap_db_door;
+extern Bitmap                 *bitmap_db_title;
+extern Bitmap                 *bitmap_db_field;
+extern Bitmap                 *bitmap_db_door;
 extern Pixmap                  tile_clipmask[];
-extern DrawBuffer            *fieldbuffer;
-extern DrawBuffer            *drawto_field;
+extern DrawBuffer             *fieldbuffer;
+extern DrawBuffer             *drawto_field;
 
 extern int                     game_status;
 extern boolean                 level_editor_test_game;
@@ -2110,13 +2313,14 @@ extern short                    MovDir[MAX_LEV_FIELDX][MAX_LEV_FIELDY];
 extern short                   MovDelay[MAX_LEV_FIELDX][MAX_LEV_FIELDY];
 extern short                   ChangeDelay[MAX_LEV_FIELDX][MAX_LEV_FIELDY];
 extern short                   ChangePage[MAX_LEV_FIELDX][MAX_LEV_FIELDY];
+extern short                   CustomValue[MAX_LEV_FIELDX][MAX_LEV_FIELDY];
 extern short                   Store[MAX_LEV_FIELDX][MAX_LEV_FIELDY];
 extern short                   Store2[MAX_LEV_FIELDX][MAX_LEV_FIELDY];
 extern short                   StorePlayer[MAX_LEV_FIELDX][MAX_LEV_FIELDY];
 extern short                   Back[MAX_LEV_FIELDX][MAX_LEV_FIELDY];
 extern boolean                 Stop[MAX_LEV_FIELDX][MAX_LEV_FIELDY];
 extern boolean                 Pushed[MAX_LEV_FIELDX][MAX_LEV_FIELDY];
-extern boolean                 Changed[MAX_LEV_FIELDX][MAX_LEV_FIELDY];
+extern short                   ChangeCount[MAX_LEV_FIELDX][MAX_LEV_FIELDY];
 extern short                   ChangeEvent[MAX_LEV_FIELDX][MAX_LEV_FIELDY];
 extern short                   WasJustMoving[MAX_LEV_FIELDX][MAX_LEV_FIELDY];
 extern short                   WasJustFalling[MAX_LEV_FIELDX][MAX_LEV_FIELDY];
@@ -2130,7 +2334,9 @@ extern short                      ExplodeDelay[MAX_LEV_FIELDX][MAX_LEV_FIELDY];
 extern int                     RunnerVisit[MAX_LEV_FIELDX][MAX_LEV_FIELDY];
 extern int                     PlayerVisit[MAX_LEV_FIELDX][MAX_LEV_FIELDY];
 
+#if 0
 extern unsigned long           Properties[MAX_NUM_ELEMENTS][NUM_EP_BITFIELDS];
+#endif
 
 extern int                     GfxFrame[MAX_LEV_FIELDX][MAX_LEV_FIELDY];
 extern int                     GfxRandom[MAX_LEV_FIELDX][MAX_LEV_FIELDY];
@@ -2165,10 +2371,8 @@ extern int                       graphics_action_mapping[];
 
 extern struct LevelSetInfo     levelset;
 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_1, door_2;
index 692265338b597df45b8b62510eb2bb736da08919..8a41aee586b8caa48be7d43acee1ce6e1c34578c 100644 (file)
@@ -203,7 +203,6 @@ static void AddPlayer(int fd)
 
   nxn = 1;
 
-#if 1
   while (again)
   {
     again = FALSE;
@@ -221,19 +220,6 @@ static void AddPlayer(int fd)
       v = v->next;
     }
   }
-#else
- again:
-  v = player->next;
-  while (v)
-  {
-    if (v->number == nxn)
-    {
-      nxn++;
-      goto again;
-    }
-    v = v->next;
-  }
-#endif
 
   player->number = nxn;
 #if !defined(TARGET_SDL)
@@ -307,11 +293,11 @@ static void Handle_OP_NUMBER_WANTED(struct NetworkServerPlayerInfo *player)
       Error(ERR_NETWORK_SERVER, "client %d (%s) switches to # %d",
            player->number, player->player_name, nr_wanted);
     else if (player->number == nr_wanted)
-      Error(ERR_NETWORK_SERVER, "client %d (%s) still has # %d",
+      Error(ERR_NETWORK_SERVER, "client %d (%s) already has # %d",
            player->number, player->player_name, nr_wanted);
     else
       Error(ERR_NETWORK_SERVER,
-           "client %d (%s) cannot switch (client %d still exists)",
+           "client %d (%s) cannot switch (client %d already exists)",
            player->number, player->player_name, nr_wanted);
   }
 
@@ -389,11 +375,11 @@ static void Handle_OP_START_PLAYING(struct NetworkServerPlayerInfo *player)
 
   if (options.verbose)
     Error(ERR_NETWORK_SERVER,
-         "client %d (%s) starts game [level %d from levedir %d (%s)]",
+         "client %d (%s) starts game [level %d from leveldir %d (%s)]",
          player->number, player->player_name,
          (buffer[2] << 8) + buffer[3],
          (buffer[4] << 8) + buffer[5],
-         &buffer[6]);
+         &buffer[10]);
 
   for (w = first_player; w; w = w->next)
     if (w->introduced)
@@ -402,6 +388,8 @@ static void Handle_OP_START_PLAYING(struct NetworkServerPlayerInfo *player)
   /* reset frame counter */
   ServerFrameCounter = 0;
 
+  Error(ERR_NETWORK_SERVER, "resetting ServerFrameCounter to 0");
+
   /* reset player actions */
   for (v = first_player; v; v = v->next)
   {
@@ -430,10 +418,12 @@ static void Handle_OP_CONTINUE_PLAYING(struct NetworkServerPlayerInfo *player)
 
 static void Handle_OP_STOP_PLAYING(struct NetworkServerPlayerInfo *player)
 {
+  int cause_for_stopping = buffer[2];
+
   if (options.verbose)
-    Error(ERR_NETWORK_SERVER, "client %d (%s) stops game",
-         player->number, player->player_name);
-  broadcast(NULL, 2, 0);
+    Error(ERR_NETWORK_SERVER, "client %d (%s) stops game [%d]",
+         player->number, player->player_name, cause_for_stopping);
+  broadcast(NULL, 3, 0);
 }
 
 static void Handle_OP_MOVE_PLAYER(struct NetworkServerPlayerInfo *player)
@@ -481,6 +471,11 @@ static void Handle_OP_MOVE_PLAYER(struct NetworkServerPlayerInfo *player)
 
   broadcast(NULL, 6 + last_client_nr, 0);
 
+#if 0
+  Error(ERR_NETWORK_SERVER, "sending ServerFrameCounter value %d",
+       ServerFrameCounter);
+#endif
+
   ServerFrameCounter++;
 }
 
index 575e846b38fe3c49fc001528be157055738da28b..feb79bd9769d58098d75a5120d8aa457025a8fc5 100644 (file)
@@ -66,6 +66,7 @@ static byte realbuffer[512];
 static byte readbuffer[MAX_BUFFER_SIZE], writbuffer[MAX_BUFFER_SIZE];
 static byte *buffer = realbuffer + 4;
 static int nread = 0, nwrite = 0;
+static boolean stop_network_game = FALSE;
 
 static void SendBufferToServer(int size)
 {
@@ -342,11 +343,12 @@ void SendToServer_ContinuePlaying()
   SendBufferToServer(2);
 }
 
-void SendToServer_StopPlaying()
+void SendToServer_StopPlaying(int cause_for_stopping)
 {
   buffer[1] = OP_STOP_PLAYING;
+  buffer[2] = cause_for_stopping;
 
-  SendBufferToServer(2);
+  SendBufferToServer(3);
 }
 
 void SendToServer_MovePlayer(byte player_action)
@@ -429,11 +431,18 @@ static void Handle_OP_NUMBER_WANTED()
   }
   else if (old_client_nr == first_player.nr)   /* failed -- local player? */
   {
+#if 0
     char *color[] = { "yellow", "red", "green", "blue" };
+#endif
     char request[100];
 
+#if 1
+    sprintf(request, "Sorry ! Player %d already exists ! You are player %d !",
+           index_nr_wanted + 1, new_index_nr + 1);
+#else
     sprintf(request, "Sorry ! %s player still exists ! You are %s player !",
            color[index_nr_wanted], color[new_index_nr]);
+#endif
     Request(request, REQ_CONFIRM);
 
     Error(ERR_NETWORK_CLIENT, "cannot switch -- you keep client # %d",
@@ -500,12 +509,12 @@ static void Handle_OP_START_PLAYING()
 {
   LevelDirTree *new_leveldir;
   int new_level_nr;
-  int dummy;                           /* !!! HAS NO MEANING ANYMORE !!! */
+  int dummy;
   unsigned long new_random_seed;
   char *new_leveldir_identifier;
 
   new_level_nr = (buffer[2] << 8) + buffer[3];
-  dummy = (buffer[4] << 8) + buffer[5];
+  dummy = (buffer[4] << 8) + buffer[5];                        /* (obsolete) */
   new_random_seed =
     (buffer[6] << 24) | (buffer[7] << 16) | (buffer[8] << 8) | (buffer[9]);
   new_leveldir_identifier = (char *)&buffer[10];
@@ -532,6 +541,9 @@ static void Handle_OP_START_PLAYING()
   LoadTape(level_nr);
   LoadLevel(level_nr);
 
+#if 1
+  StartGameActions(FALSE, setup.autorecord, new_random_seed);
+#else
   if (setup.autorecord)
     TapeStartRecording();
 
@@ -542,6 +554,7 @@ static void Handle_OP_START_PLAYING()
 
   game_status = GAME_MODE_PLAYING;
   InitGame();
+#endif
 }
 
 static void Handle_OP_PAUSE_PLAYING()
@@ -564,8 +577,18 @@ static void Handle_OP_CONTINUE_PLAYING()
 
 static void Handle_OP_STOP_PLAYING()
 {
-  printf("OP_STOP_PLAYING: %d\n", buffer[0]);
-  Error(ERR_NETWORK_CLIENT, "client %d stops game", buffer[0]);
+  printf("OP_STOP_PLAYING: %d [%d]\n", buffer[0], buffer[2]);
+  Error(ERR_NETWORK_CLIENT, "client %d stops game [%d]", buffer[0], buffer[2]);
+
+  if (game_status == GAME_MODE_PLAYING)
+  {
+    if (buffer[2] == NETWORK_STOP_BY_PLAYER)
+      Request("Network game stopped by player!", REQ_CONFIRM);
+    else if (buffer[2] == NETWORK_STOP_BY_ERROR)
+      Request("Network game stopped due to internal error!", REQ_CONFIRM);
+    else
+      Request("Network game stopped !", REQ_CONFIRM);
+  }
 
   game_status = GAME_MODE_MAIN;
   DrawMainMenu();
@@ -582,12 +605,26 @@ static void Handle_OP_MOVE_PLAYER(unsigned int len)
   server_frame_counter =
     (buffer[2] << 24) | (buffer[3] << 16) | (buffer[4] << 8) | (buffer[5]);
 
+#if 0
+  Error(ERR_NETWORK_CLIENT, "receiving server frame counter value %d [%d]",
+       server_frame_counter, FrameCounter);
+#endif
+
   if (server_frame_counter != FrameCounter)
   {
     Error(ERR_RETURN, "client and servers frame counters out of sync");
     Error(ERR_RETURN, "frame counter of client is %d", FrameCounter);
     Error(ERR_RETURN, "frame counter of server is %d", server_frame_counter);
+
+#if 1
+    Error(ERR_RETURN, "this should not happen -- please debug");
+
+    stop_network_game = TRUE;
+
+    return;
+#else
     Error(ERR_EXIT,   "this should not happen -- please debug");
+#endif
   }
 
   /* copy valid player actions */
@@ -602,6 +639,8 @@ static void HandleNetworkingMessages()
 {
   unsigned int message_length;
 
+  stop_network_game = FALSE;
+
   while (nread >= 4 && nread >= 4 + readbuffer[3])
   {
     message_length = readbuffer[3];
@@ -666,6 +705,10 @@ static void HandleNetworkingMessages()
   }
 
   fflush(stdout);
+
+  /* in case of internal error, stop network game */
+  if (stop_network_game)
+    SendToServer_StopPlaying(NETWORK_STOP_BY_ERROR);
 }
 
 /* TODO */
index 6819bf27279a6dd823a15d65bea124b9005c0d58..72c58445d24e0509727e1e043e32f292dcbb6f9a 100644 (file)
@@ -16,6 +16,9 @@
 
 #include "main.h"
 
+#define NETWORK_STOP_BY_PLAYER         0
+#define NETWORK_STOP_BY_ERROR          1
+
 boolean ConnectToServer(char *, int);
 void SendToServer_PlayerName(char *);
 void SendToServer_ProtocolVersion(void);
@@ -23,7 +26,7 @@ void SendToServer_NrWanted(int);
 void SendToServer_StartPlaying(void);
 void SendToServer_PausePlaying(void);
 void SendToServer_ContinuePlaying(void);
-void SendToServer_StopPlaying(void);
+void SendToServer_StopPlaying(int);
 void SendToServer_MovePlayer(byte);
 void HandleNetworking(void);
 
index 7d783a9b21a3f672e3f5c13ce5574d63db856b8a..831b8489ad38879940474d214b470830a5279167 100644 (file)
 #define SETUP_MODE_GAME                        1
 #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 SETUP_MODE_SHORTCUT_1          4
+#define SETUP_MODE_SHORTCUT_2          5
+#define SETUP_MODE_GRAPHICS            6
+#define SETUP_MODE_SOUND               7
+#define SETUP_MODE_ARTWORK             8
+#define SETUP_MODE_CHOOSE_GRAPHICS     9
+#define SETUP_MODE_CHOOSE_SOUNDS       10
+#define SETUP_MODE_CHOOSE_MUSIC                11
 
-#define MAX_SETUP_MODES                        11
+#define MAX_SETUP_MODES                        12
 
 /* for input setup functions */
 #define SETUPINPUT_SCREEN_POS_START    0
 
 /* screens on the info screen */
 #define INFO_MODE_MAIN                 0
-#define INFO_MODE_ELEMENTS             1
-#define INFO_MODE_MUSIC                        2
-#define INFO_MODE_CREDITS              3
-#define INFO_MODE_PROGRAM              4
-#define INFO_MODE_LEVELSET             5
+#define INFO_MODE_TITLE                        1
+#define INFO_MODE_ELEMENTS             2
+#define INFO_MODE_MUSIC                        3
+#define INFO_MODE_CREDITS              4
+#define INFO_MODE_PROGRAM              5
+#define INFO_MODE_LEVELSET             6
 
-#define MAX_INFO_MODES                 6
+#define MAX_INFO_MODES                 7
 
 /* for various menu stuff  */
-#define MAX_INFO_ELEMENTS_ON_SCREEN    10
-#define MAX_MENU_ENTRIES_ON_SCREEN     (SCR_FIELDY - 2)
+#define MENU_SCREEN_START_XPOS         1
 #define MENU_SCREEN_START_YPOS         2
 #define MENU_SCREEN_VALUE_XPOS         14
+#define MENU_SCREEN_MAX_XPOS           (SCR_FIELDX - 1)
+#define MENU_TITLE1_YPOS               8
+#define MENU_TITLE2_YPOS               46
+#define MAX_INFO_ELEMENTS_ON_SCREEN    10
+#define MAX_MENU_ENTRIES_ON_SCREEN     (SCR_FIELDY - MENU_SCREEN_START_YPOS)
+#define MAX_MENU_TEXT_LENGTH_BIG       (MENU_SCREEN_VALUE_XPOS -       \
+                                        MENU_SCREEN_START_XPOS)
+#define MAX_MENU_TEXT_LENGTH_MEDIUM    (MAX_MENU_TEXT_LENGTH_BIG * 2)
 
 /* buttons and scrollbars identifiers */
 #define SCREEN_CTRL_ID_SCROLL_UP       0
 #define NUM_SCREEN_SCROLLBARS          1
 #define NUM_SCREEN_GADGETS             3
 
+/* graphic position and size values for buttons and scrollbars */
+#define SC_SCROLLBUTTON_XSIZE          TILEX
+#define SC_SCROLLBUTTON_YSIZE          TILEY
+
+#define SC_SCROLLBAR_XPOS              (SXSIZE - SC_SCROLLBUTTON_XSIZE)
+
+#define SC_SCROLL_VERTICAL_XSIZE       SC_SCROLLBUTTON_XSIZE
+#define SC_SCROLL_VERTICAL_YSIZE       ((MAX_MENU_ENTRIES_ON_SCREEN - 2) * \
+                                        SC_SCROLLBUTTON_YSIZE)
+
+#define SC_SCROLL_UP_XPOS              SC_SCROLLBAR_XPOS
+#define SC_SCROLL_UP_YPOS              (2 * SC_SCROLLBUTTON_YSIZE)
+
+#define SC_SCROLL_VERTICAL_XPOS                SC_SCROLLBAR_XPOS
+#define SC_SCROLL_VERTICAL_YPOS                (SC_SCROLL_UP_YPOS + \
+                                        SC_SCROLLBUTTON_YSIZE)
+
+#define SC_SCROLL_DOWN_XPOS            SC_SCROLLBAR_XPOS
+#define SC_SCROLL_DOWN_YPOS            (SC_SCROLL_VERTICAL_YPOS + \
+                                        SC_SCROLL_VERTICAL_YSIZE)
+
+#define SC_BORDER_SIZE                 14
+
+
 /* forward declarations of internal functions */
 static void HandleScreenGadgets(struct GadgetInfo *);
 static void HandleSetupScreen_Generic(int, int, int, int, int);
@@ -83,9 +116,12 @@ static void DrawChooseLevel(void);
 static void DrawInfoScreen(void);
 static void DrawSetupScreen(void);
 
+static void DrawInfoScreenExt(int);
+static void DrawInfoScreen_NotAvailable(char *, char *);
 static void DrawInfoScreen_HelpAnim(int, int, boolean);
 static void DrawInfoScreen_HelpText(int, int, int, int);
 static void HandleInfoScreen_Main(int, int, int, int, int);
+static void HandleInfoScreen_TitleScreen(int);
 static void HandleInfoScreen_Elements(int);
 static void HandleInfoScreen_Music(int);
 static void HandleInfoScreen_Credits(int);
@@ -115,28 +151,31 @@ static Bitmap *scrollbar_bitmap[NUM_SCROLLBAR_BITMAPS];
 #endif
 
 
-static void drawCursorExt(int xpos, int ypos, int color, int graphic)
+static void drawCursorExt(int xpos, int ypos, int color, int g)
 {
   static int cursor_array[SCR_FIELDY];
 
   if (xpos == 0)
   {
-    if (graphic != 0)
-      cursor_array[ypos] = graphic;
+    if (g != 0)
+      cursor_array[ypos] = g;
     else
-      graphic = cursor_array[ypos];
+      g = cursor_array[ypos];
   }
 
   if (color == FC_RED)
-    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);
+    g = (g == IMG_MENU_BUTTON_LEFT  ? IMG_MENU_BUTTON_LEFT_ACTIVE  :
+        g == IMG_MENU_BUTTON_RIGHT ? IMG_MENU_BUTTON_RIGHT_ACTIVE :
+        g == IMG_MENU_BUTTON_LEAVE_MENU ? IMG_MENU_BUTTON_LEAVE_MENU_ACTIVE :
+        g == IMG_MENU_BUTTON_ENTER_MENU ? IMG_MENU_BUTTON_ENTER_MENU_ACTIVE :
+        g == IMG_MENU_BUTTON_LAST_LEVEL ? IMG_MENU_BUTTON_LAST_LEVEL_ACTIVE :
+        g == IMG_MENU_BUTTON_NEXT_LEVEL ? IMG_MENU_BUTTON_NEXT_LEVEL_ACTIVE :
+        IMG_MENU_BUTTON_ACTIVE);
 
   ypos += MENU_SCREEN_START_YPOS;
 
   DrawBackground(mSX + xpos * TILEX, mSY + ypos * TILEY, TILEX, TILEY);
-  DrawGraphicThruMaskExt(drawto, mSX + xpos * TILEX, mSY + ypos * TILEY,
-                        graphic, 0);
+  DrawGraphicThruMaskExt(drawto, mSX + xpos * TILEX, mSY + ypos * TILEY, g, 0);
 }
 
 static void initCursor(int ypos, int graphic)
@@ -166,44 +205,10 @@ static void drawChooseTreeCursor(int ypos, int color)
   game_status = last_game_status;      /* restore current game status */
 }
 
-static void PlayMenuSound()
-{
-  int sound = menu.sound[game_status];
-
-  if (sound == SND_UNDEFINED)
-    return;
-
-  if (sound_info[sound].loop)
-    PlaySoundLoop(sound);
-  else
-    PlaySound(sound);
-}
-
-static void PlayMenuSoundIfLoop()
-{
-  int sound = menu.sound[game_status];
-
-  if (sound == SND_UNDEFINED)
-    return;
-
-  if (sound_info[sound].loop)
-    PlaySoundLoop(sound);
-}
-
-static void PlayMenuMusic()
-{
-  int music = menu.music[game_status];
-
-  if (music == MUS_UNDEFINED)
-    return;
-
-  PlayMusic(music);
-}
-
 void DrawHeadline()
 {
-  DrawTextSCentered(8,  FONT_TITLE_1, PROGRAM_TITLE_STRING);
-  DrawTextSCentered(46, FONT_TITLE_2, PROGRAM_COPYRIGHT_STRING);
+  DrawTextSCentered(MENU_TITLE1_YPOS, FONT_TITLE_1, PROGRAM_TITLE_STRING);
+  DrawTextSCentered(MENU_TITLE2_YPOS, FONT_TITLE_2, PROGRAM_COPYRIGHT_STRING);
 }
 
 static void ToggleFullscreenIfNeeded()
@@ -230,10 +235,86 @@ static void ToggleFullscreenIfNeeded()
   }
 }
 
-void DrawMainMenu()
+static int getLastLevelButtonPos()
+{
+  return 10;
+}
+
+static int getCurrentLevelTextPos()
+{
+  return (getLastLevelButtonPos() + 1);
+}
+
+static int getNextLevelButtonPos()
+{
+  return getLastLevelButtonPos() + 3 + 1;
+}
+
+static int getLevelRangeTextPos()
+{
+  return getNextLevelButtonPos() + 1;
+}
+
+void DrawTitleScreenImage(int nr)
+{
+  int graphic = IMG_TITLESCREEN_1 + nr;
+  Bitmap *bitmap = graphic_info[graphic].bitmap;
+  int width  = graphic_info[graphic].src_image_width;
+  int height = graphic_info[graphic].src_image_height;
+  int src_x = 0, src_y = 0;
+  int dst_x, dst_y;
+
+  if (bitmap == NULL)
+    return;
+
+  if (width > WIN_XSIZE)
+  {
+    /* image width too large for window => center image horizontally */
+    src_x = (width - WIN_XSIZE) / 2;
+    width = WIN_XSIZE;
+  }
+
+  if (height > WIN_YSIZE)
+  {
+    /* image height too large for window => center image vertically */
+    src_y = (height - WIN_YSIZE) / 2;
+    height = WIN_YSIZE;
+  }
+
+  dst_x = (WIN_XSIZE - width) / 2;
+  dst_y = (WIN_YSIZE - height) / 2;
+
+  ClearRectangleOnBackground(drawto, 0, 0, WIN_XSIZE, WIN_YSIZE);
+
+  if (DrawingOnBackground(dst_x, dst_y))
+    BlitBitmapMasked(bitmap, drawto, src_x, src_y, width, height, dst_x, dst_y);
+  else
+    BlitBitmap(bitmap, drawto, src_x, src_y, width, height, dst_x, dst_y);
+
+  redraw_mask = REDRAW_ALL;
+}
+
+void DrawTitleScreen()
+{
+  KeyboardAutoRepeatOff();
+
+  SetMainBackgroundImage(IMG_BACKGROUND_TITLE);
+
+  HandleTitleScreen(0, 0, 0, 0, MB_MENU_INITIALIZE);
+
+  StopAnimation();
+}
+
+static void DrawMainMenuExt(int fade_delay)
 {
   static LevelDirTree *leveldir_last_valid = NULL;
+  boolean levelset_has_changed = FALSE;
   char *name_text = (!options.network && setup.team_mode ? "Team:" : "Name:");
+#if 1
+  char *level_text = "Levelset";
+#else
+  char *level_text = "Level:";
+#endif
   int name_width, level_width;
   int i;
 
@@ -248,6 +329,10 @@ void DrawMainMenu()
 
   audio.sound_deactivated = FALSE;
 
+#if 1
+  GetPlayerConfig();
+#endif
+
   /* needed if last screen was the playing screen, invoked from level editor */
   if (level_editor_test_game)
   {
@@ -267,6 +352,9 @@ void DrawMainMenu()
   if (!validLevelSeries(leveldir_current))
     leveldir_current = getFirstValidTreeInfoEntry(leveldir_last_valid);
 
+  if (leveldir_current != leveldir_last_valid)
+    levelset_has_changed = TRUE;
+
   /* store valid level series information */
   leveldir_last_valid = leveldir_current;
 
@@ -277,14 +365,28 @@ void DrawMainMenu()
   SetDrawtoField(DRAW_BACKBUFFER);
 #endif
 
+  if (setup.show_titlescreen &&
+      levelset_has_changed &&
+      graphic_info[IMG_TITLESCREEN_1].bitmap != NULL)
+  {
+    game_status = GAME_MODE_TITLE;
+    DrawTitleScreen();
+
+    return;
+  }
+
+#if 0
   /* map gadgets for main menu screen */
   MapTapeButtons();
+#endif
 
   /* 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;
 
+#if 0
   GetPlayerConfig();
+#endif
   LoadLevel(level_nr);
 
   SetMainBackgroundImage(IMG_BACKGROUND_MAIN);
@@ -292,28 +394,74 @@ void DrawMainMenu()
 
   DrawHeadline();
 
-  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, mSY + 2 * 32, name_text,       FONT_MENU_1);
+  DrawText(mSX + 32, mSY + 3 * 32, level_text,      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);
 
   /* calculated after (possible) reload of custom artwork */
-  name_width = getTextWidth(name_text, FONT_MENU_1);
-  level_width = getTextWidth("Level:", FONT_MENU_1);
+  name_width  = getTextWidth(name_text,  FONT_MENU_1);
+#if 1
+  level_width = 9 * 32;
+#else
+#if 1
+  level_width = 9 * getFontWidth(FONT_MENU_1);
+#else
+  level_width = getTextWidth(level_text, FONT_MENU_1);
+#endif
+#endif
 
-  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),
+  DrawText(mSX + 32 + name_width, mSY + 2 * 32, setup.player_name,
+          FONT_INPUT_1);
+
+#if 1
+  DrawText(mSX + getCurrentLevelTextPos() * 32, mSY + 3 * 32,
+          int2str(level_nr, 3), FONT_VALUE_1);
+#else
+#if 1
+  DrawText(mSX + level_width + 2 * 32, mSY + 3 * 32, int2str(level_nr, 3),
           FONT_VALUE_1);
+#else
+  DrawText(mSX + level_width + 5 * 32, mSY + 3 * 32, int2str(level_nr, 3),
+          FONT_VALUE_1);
+#endif
+#endif
 
   DrawMicroLevel(MICROLEVEL_XPOS, MICROLEVEL_YPOS, TRUE);
 
-  DrawTextF(mSX + 32 + level_width - 2, mSY + 3*32 + 1, FONT_TEXT_3, "%d-%d",
+#if 1
+
+#if 1
+  {
+    int text_height = getFontHeight(FONT_TEXT_3);
+#if 1
+    int xpos = getLevelRangeTextPos() * 32;
+#else
+    int xpos = level_width + 6 * 32;
+#endif
+    int ypos2 = -SY + 3 * 32 + 16;
+    int ypos1 = ypos2 - text_height;
+
+    DrawTextF(mSX + xpos, mSY + ypos1, FONT_TEXT_3,
+             "%03d", leveldir_current->first_level);
+    DrawTextF(mSX + xpos, mSY + ypos2, FONT_TEXT_3,
+             "%03d", leveldir_current->last_level);
+  }
+#else
+  DrawTextF(mSX + level_width + 6 * 32, mSY + 3 * 32 + 1, FONT_TEXT_3,
+           "%d", leveldir_current->levels);
+#endif
+
+#else
+  DrawTextF(mSX + 32 + level_width - 2, mSY + 3 * 32 + 1, FONT_TEXT_3, "%d-%d",
            leveldir_current->first_level, leveldir_current->last_level);
+#endif
 
+#if 0
   if (leveldir_current->readonly)
   {
     DrawTextS(mSX + level_width + 9 * 32 - 2,
@@ -321,18 +469,33 @@ void DrawMainMenu()
     DrawTextS(mSX + level_width + 9 * 32 - 2,
              mSY + 3 * 32 + 1 + 7, FONT_TEXT_3, "ONLY");
   }
+#endif
 
   for (i = 0; i < 8; i++)
-    initCursor(i, (i == 1 || i == 4 || i == 6 ? IMG_MENU_BUTTON_RIGHT :
+    initCursor(i, (i == 1 || i == 4 || i == 6 ? IMG_MENU_BUTTON_ENTER_MENU :
                   IMG_MENU_BUTTON));
 
-  drawCursorXY(level_width/32 + 4, 1, IMG_MENU_BUTTON_LEFT);
-  drawCursorXY(level_width/32 + 8, 1, IMG_MENU_BUTTON_RIGHT);
+#if 1
+  drawCursorXY(getLastLevelButtonPos(), 1, IMG_MENU_BUTTON_LAST_LEVEL);
+  drawCursorXY(getNextLevelButtonPos(), 1, IMG_MENU_BUTTON_NEXT_LEVEL);
+#else
+#if 1
+  drawCursorXY(level_width / 32 + 1, 1, IMG_MENU_BUTTON_LEFT);
+  drawCursorXY(level_width / 32 + 5, 1, IMG_MENU_BUTTON_RIGHT);
+#else
+  drawCursorXY(level_width / 32 + 4, 1, IMG_MENU_BUTTON_LEFT);
+  drawCursorXY(level_width / 32 + 8, 1, IMG_MENU_BUTTON_RIGHT);
+#endif
+#endif
 
   DrawTextSCentered(326, FONT_TITLE_2, "A Game by Artsoft Entertainment");
 
+#if 0
   FadeToFront();
+#endif
+#if 0
   InitAnimation();
+#endif
 
   HandleMainMenu(0, 0, 0, 0, MB_MENU_INITIALIZE);
 
@@ -344,7 +507,46 @@ void DrawMainMenu()
   PlayMenuSound();
   PlayMenuMusic();
 
+#if 0
+#if 1
+  OpenDoor(DOOR_CLOSE_1 | DOOR_OPEN_2);
+#else
+  if (fade_delay > 0)
+    OpenDoor(DOOR_CLOSE_1 | DOOR_OPEN_2 | DOOR_NO_DELAY | DOOR_FORCE_REDRAW);
+  else
+    OpenDoor(DOOR_CLOSE_1 | DOOR_OPEN_2);
+#endif
+#endif
+
+#if 0
+  InitAnimation();
+#endif
+
+#if 1
+  /* map gadgets for main menu screen */
+  MapTapeButtons();
+#endif
+
+#if 1
+#if 1
+  FadeIn(fade_delay);
+#else
+  BackToFront();
+#endif
+#endif
+
+#if 1
+  InitAnimation();
+#endif
+
+#if 1
   OpenDoor(DOOR_CLOSE_1 | DOOR_OPEN_2);
+#endif
+}
+
+void DrawMainMenu()
+{
+  DrawMainMenuExt(0);
 }
 
 #if 0
@@ -378,6 +580,120 @@ static void gotoTopLevelDir()
 }
 #endif
 
+void HandleTitleScreen(int mx, int my, int dx, int dy, int button)
+{
+  static int title_nr = 0;
+  boolean return_to_main_menu = FALSE;
+  boolean use_fading_main_menu = TRUE;
+  boolean use_cross_fading = TRUE;
+  int fade_delay = 500;
+  int post_delay = fade_delay / 2;
+
+  if (button == MB_MENU_INITIALIZE)
+  {
+    int last_game_status = game_status;        /* save current game status */
+    title_nr = 0;
+
+    if (game_status == GAME_MODE_INFO)
+    {
+      if (graphic_info[IMG_TITLESCREEN_1].bitmap == NULL)
+      {
+       DrawInfoScreen_NotAvailable("Title screen information:",
+                                   "No title screen for this level set.");
+
+       return;
+      }
+
+      FadeSoundsAndMusic();
+
+      FadeOut(fade_delay, post_delay);
+    }
+
+    /* force TITLE music on title info screen */
+    game_status = GAME_MODE_TITLE;
+
+    PlayMenuSound();
+    PlayMenuMusic();
+
+    game_status = last_game_status;    /* restore current game status */
+
+    DrawTitleScreenImage(title_nr);
+
+    FadeIn(fade_delay);
+
+    return;
+  }
+  else if (button == MB_MENU_LEAVE)
+  {
+    return_to_main_menu = TRUE;
+    use_fading_main_menu = FALSE;
+  }
+  else if (button == MB_MENU_CHOICE)
+  {
+    if (game_status == GAME_MODE_INFO &&
+       graphic_info[IMG_TITLESCREEN_1].bitmap == NULL)
+    {
+      info_mode = INFO_MODE_MAIN;
+      DrawInfoScreen();
+
+      return;
+    }
+
+    title_nr++;
+
+    if (!use_cross_fading)
+      FadeOut(fade_delay, post_delay);
+
+    if (title_nr < MAX_NUM_TITLE_SCREENS &&
+       graphic_info[IMG_TITLESCREEN_1 + title_nr].bitmap != NULL)
+    {
+      Bitmap *drawto_last = drawto;
+
+      if (use_cross_fading)
+       drawto = bitmap_db_title;
+
+      DrawTitleScreenImage(title_nr);
+
+      drawto = drawto_last;
+
+      if (use_cross_fading)
+       FadeCross(fade_delay);
+      else
+       FadeIn(fade_delay);
+    }
+    else
+    {
+      FadeSoundsAndMusic();
+
+      FadeOut(fade_delay, post_delay);
+
+      return_to_main_menu = TRUE;
+    }
+  }
+
+  if (return_to_main_menu)
+  {
+    int menu_fade_delay = (use_fading_main_menu ? fade_delay : 0);
+
+    RedrawBackground();
+
+    if (game_status == GAME_MODE_INFO)
+    {
+      OpenDoor(DOOR_CLOSE_1 | DOOR_CLOSE_2 | DOOR_NO_DELAY | DOOR_FORCE_REDRAW);
+
+      info_mode = INFO_MODE_MAIN;
+      DrawInfoScreenExt(menu_fade_delay);
+    }
+    else       /* default: return to main menu */
+    {
+      OpenDoor(DOOR_CLOSE_1 | DOOR_OPEN_2 | DOOR_NO_DELAY | DOOR_FORCE_REDRAW);
+
+      game_status = GAME_MODE_MAIN;
+      DrawMainMenuExt(menu_fade_delay);
+    }
+  }
+}
+
 void HandleMainMenu(int mx, int my, int dx, int dy, int button)
 {
   static unsigned long level_delay = 0;
@@ -400,6 +716,11 @@ void HandleMainMenu(int mx, int my, int dx, int dy, int button)
   {
     if (dx && choice == 1)
       x = (dx < 0 ? 10 : 14);
+    else if (dx > 0)
+    {
+      if (choice == 4 || choice == 6)
+       button = MB_MENU_CHOICE;
+    }
     else if (dy)
       y = choice + dy;
   }
@@ -418,7 +739,6 @@ void HandleMainMenu(int mx, int my, int dx, int dy, int button)
     if (new_level_nr > leveldir_current->last_level)
       new_level_nr = leveldir_current->last_level;
 
-#if 1
     if (setup.handicap && new_level_nr > leveldir_current->handicap_level)
     {
       /* skipping levels is only allowed when trying to skip single level */
@@ -431,10 +751,6 @@ void HandleMainMenu(int mx, int my, int dx, int dy, int button)
 
       new_level_nr = leveldir_current->handicap_level;
     }
-#else
-    if (setup.handicap && new_level_nr > leveldir_current->handicap_level)
-      new_level_nr = leveldir_current->handicap_level;
-#endif
 
     if (new_level_nr != old_level_nr)
     {
@@ -498,7 +814,7 @@ void HandleMainMenu(int mx, int my, int dx, int dy, int button)
       else if (y == 3)
       {
        if (leveldir_current->readonly &&
-           strcmp(setup.player_name, "Artsoft") != 0)
+           !strEqual(setup.player_name, "Artsoft"))
          Request("This level is read only !", REQ_CONFIRM);
        game_status = GAME_MODE_EDITOR;
        DrawLevelEd();
@@ -511,30 +827,20 @@ void HandleMainMenu(int mx, int my, int dx, int dy, int button)
       }
       else if (y == 5)
       {
-       if (setup.autorecord)
-         TapeStartRecording();
-
-#if defined(NETWORK_AVALIABLE)
-       if (options.network)
-         SendToServer_StartPlaying();
-       else
-#endif
-       {
-         game_status = GAME_MODE_PLAYING;
-         StopAnimation();
-         InitGame();
-       }
+       StartGameActions(options.network, setup.autorecord, NEW_RANDOMIZE);
       }
       else if (y == 6)
       {
        game_status = GAME_MODE_SETUP;
        setup_mode = SETUP_MODE_MAIN;
+
        DrawSetupScreen();
       }
       else if (y == 7)
       {
        SaveLevelSetup_LastSeries();
        SaveLevelSetup_SeriesInfo();
+
         if (Request("Do you really want to quit ?", REQ_ASK | REQ_STAY_CLOSED))
          game_status = GAME_MODE_QUIT;
       }
@@ -556,6 +862,12 @@ void HandleMainMenu(int mx, int my, int dx, int dy, int button)
 static struct TokenInfo *info_info;
 static int num_info_info;
 
+static void execInfoTitleScreen()
+{
+  info_mode = INFO_MODE_TITLE;
+  DrawInfoScreen();
+}
+
 static void execInfoElements()
 {
   info_mode = INFO_MODE_ELEMENTS;
@@ -594,6 +906,7 @@ static void execExitInfo()
 
 static struct TokenInfo info_info_main[] =
 {
+  { TYPE_ENTER_SCREEN, execInfoTitleScreen,    "Title Screen"          },
   { TYPE_ENTER_SCREEN, execInfoElements,       "Elements Info"         },
   { TYPE_ENTER_SCREEN, execInfoMusic,          "Music Info"            },
   { TYPE_ENTER_SCREEN, execInfoCredits,        "Credits"               },
@@ -605,7 +918,7 @@ static struct TokenInfo info_info_main[] =
   { 0,                 NULL,                   NULL                    }
 };
 
-static void DrawInfoScreen_Main()
+static void DrawInfoScreen_Main(int fade_delay)
 {
   int i;
 
@@ -614,28 +927,45 @@ static void DrawInfoScreen_Main()
 
   ClearWindow();
 
+#if 1
+  DrawTextSCentered(mSY - SY + 16, FONT_TITLE_1, "Info Screen");
+#else
   DrawText(mSX + 16, mSY + 16, "Info Screen", FONT_TITLE_1);
+#endif
 
   info_info = info_info_main;
   num_info_info = 0;
 
   for (i = 0; info_info[i].type != 0 && i < NUM_MENU_ENTRIES_ON_SCREEN; i++)
   {
+    int xpos = MENU_SCREEN_START_XPOS;
     int ypos = MENU_SCREEN_START_YPOS + i;
     int font_nr = FONT_MENU_1;
 
-    DrawText(mSX + 32, mSY + ypos * 32, info_info[i].text, font_nr);
+    DrawText(mSX + xpos * 32, mSY + ypos * 32, info_info[i].text, font_nr);
 
     if (info_info[i].type & TYPE_ENTER_MENU)
-      initCursor(i, IMG_MENU_BUTTON_RIGHT);
+      initCursor(i, IMG_MENU_BUTTON_ENTER_MENU);
     else if (info_info[i].type & TYPE_LEAVE_MENU)
-      initCursor(i, IMG_MENU_BUTTON_LEFT);
+      initCursor(i, IMG_MENU_BUTTON_LEAVE_MENU);
     else if (info_info[i].type & ~TYPE_SKIP_ENTRY)
       initCursor(i, IMG_MENU_BUTTON);
 
     num_info_info++;
   }
 
+#if 1
+
+  HandleInfoScreen_Main(0, 0, 0, 0, MB_MENU_INITIALIZE);
+
+  PlayMenuSound();
+  PlayMenuMusic();
+
+  FadeIn(fade_delay);
+  InitAnimation();
+
+#else
+
   FadeToFront();
   InitAnimation();
 
@@ -643,6 +973,7 @@ static void DrawInfoScreen_Main()
   PlayMenuMusic();
 
   HandleInfoScreen_Main(0, 0, 0, 0, MB_MENU_INITIALIZE);
+#endif
 }
 
 void HandleInfoScreen_Main(int mx, int my, int dx, int dy, int button)
@@ -728,6 +1059,24 @@ void HandleInfoScreen_Main(int mx, int my, int dx, int dy, int button)
   }
 }
 
+void DrawInfoScreen_NotAvailable(char *text_title, char *text_error)
+{
+  int ystart = 150;
+  int ybottom = SYSIZE - 20;
+
+  SetMainBackgroundImageIfDefined(IMG_BACKGROUND_INFO_LEVELSET);
+
+  ClearWindow();
+  DrawHeadline();
+
+  DrawTextSCentered(100, FONT_TEXT_1, text_title);
+
+  DrawTextSCentered(ybottom, FONT_TEXT_4,
+                   "Press any key or button for info menu");
+
+  DrawTextSCentered(ystart, FONT_TEXT_2, text_error);
+}
+
 void DrawInfoScreen_HelpAnim(int start, int max_anims, boolean init)
 {
   static int infoscreen_step[MAX_INFO_ELEMENTS_ON_SCREEN];
@@ -746,7 +1095,6 @@ void DrawInfoScreen_HelpAnim(int start, int max_anims, boolean init)
     for (i = 0; i < MAX_INFO_ELEMENTS_ON_SCREEN; i++)
       infoscreen_step[i] = infoscreen_frame[i] = 0;
 
-    SetMainBackgroundImage(IMG_BACKGROUND_INFO);
     ClearWindow();
     DrawHeadline();
 
@@ -781,12 +1129,15 @@ void DrawInfoScreen_HelpAnim(int start, int max_anims, boolean init)
     action = helpanim_info[j].action;
     direction = helpanim_info[j].direction;
 
+    if (element < 0)
+      element = EL_UNKNOWN;
+
     if (action != -1 && direction != -1)
       graphic = el_act_dir2img(element, action, direction);
     else if (action != -1)
       graphic = el_act2img(element, action);
     else if (direction != -1)
-      graphic = el_act2img(element, direction);
+      graphic = el_dir2img(element, direction);
     else
       graphic = el2img(element);
 
@@ -847,18 +1198,14 @@ static char *getHelpText(int element, int action, int direction)
     strcat(token, element_action_info[action].suffix);
 
   if (direction != -1)
-    strcat(token, element_direction_info[MV_DIR_BIT(direction)].suffix);
+    strcat(token, element_direction_info[MV_DIR_TO_BIT(direction)].suffix);
 
   return getHashEntry(helptext_info, token);
 }
 
 void DrawInfoScreen_HelpText(int element, int action, int direction, int ypos)
 {
-#if 0
-  int font_nr = FONT_TEXT_2;
-#else
   int font_nr = FONT_LEVEL_NUMBER;
-#endif
   int font_width = getFontWidth(font_nr);
   int sx = mSX + MINI_TILEX + TILEX + MINI_TILEX;
   int sy = mSY + 65 + 2 * 32 + 1;
@@ -886,12 +1233,24 @@ void DrawInfoScreen_HelpText(int element, int action, int direction, int ypos)
   if (strlen(text) <= max_chars_per_line)      /* only one line of text */
     sy += getFontHeight(font_nr) / 2;
 
-  DrawTextWrapped(sx, sy + ypos * ystep, text, font_nr,
-                 max_chars_per_line, max_lines_per_text);
+  DrawTextWrapped(sx, sy + ypos * ystep, text, font_nr,
+                 max_chars_per_line, max_lines_per_text);
+}
+
+void DrawInfoScreen_TitleScreen()
+{
+  DrawTitleScreen();
+}
+
+void HandleInfoScreen_TitleScreen(int button)
+{
+  HandleTitleScreen(0, 0, 0, 0, button);
 }
 
 void DrawInfoScreen_Elements()
 {
+  SetMainBackgroundImageIfDefined(IMG_BACKGROUND_INFO_ELEMENTS);
+
   LoadHelpAnimInfo();
   LoadHelpTextInfo();
 
@@ -957,7 +1316,7 @@ void HandleInfoScreen_Elements(int button)
   }
   else
   {
-    if (DelayReached(&info_delay, GAME_FRAME_DELAY))
+    if (DelayReached(&info_delay, GameFrameDelay))
       if (page < num_pages)
        DrawInfoScreen_HelpAnim(page * anims_per_page, num_anims, FALSE);
 
@@ -967,6 +1326,8 @@ void HandleInfoScreen_Elements(int button)
 
 void DrawInfoScreen_Music()
 {
+  SetMainBackgroundImageIfDefined(IMG_BACKGROUND_INFO_MUSIC);
+
   ClearWindow();
   DrawHeadline();
 
@@ -1048,17 +1409,17 @@ void HandleInfoScreen_Music(int button)
       DrawTextSCentered(100, FONT_TEXT_1, "The Game Background Music:");
     }
 
-    if (strcmp(list->title, UNKNOWN_NAME) != 0)
+    if (!strEqual(list->title, UNKNOWN_NAME))
     {
-      if (strcmp(list->title_header, UNKNOWN_NAME) != 0)
+      if (!strEqual(list->title_header, UNKNOWN_NAME))
        DrawTextSCentered(ystart + y++ * dy, FONT_TEXT_2, list->title_header);
 
       DrawTextFCentered(ystart + y++ * dy, FONT_TEXT_3, "\"%s\"", list->title);
     }
 
-    if (strcmp(list->artist, UNKNOWN_NAME) != 0)
+    if (!strEqual(list->artist, UNKNOWN_NAME))
     {
-      if (strcmp(list->artist_header, UNKNOWN_NAME) != 0)
+      if (!strEqual(list->artist_header, UNKNOWN_NAME))
        DrawTextSCentered(ystart + y++ * dy, FONT_TEXT_2, list->artist_header);
       else
        DrawTextSCentered(ystart + y++ * dy, FONT_TEXT_2, "by");
@@ -1066,9 +1427,9 @@ void HandleInfoScreen_Music(int button)
       DrawTextFCentered(ystart + y++ * dy, FONT_TEXT_3, "%s", list->artist);
     }
 
-    if (strcmp(list->album, UNKNOWN_NAME) != 0)
+    if (!strEqual(list->album, UNKNOWN_NAME))
     {
-      if (strcmp(list->album_header, UNKNOWN_NAME) != 0)
+      if (!strEqual(list->album_header, UNKNOWN_NAME))
        DrawTextSCentered(ystart + y++ * dy, FONT_TEXT_2, list->album_header);
       else
        DrawTextSCentered(ystart + y++ * dy, FONT_TEXT_2, "from the album");
@@ -1076,9 +1437,9 @@ void HandleInfoScreen_Music(int button)
       DrawTextFCentered(ystart + y++ * dy, FONT_TEXT_3, "\"%s\"", list->album);
     }
 
-    if (strcmp(list->year, UNKNOWN_NAME) != 0)
+    if (!strEqual(list->year, UNKNOWN_NAME))
     {
-      if (strcmp(list->year_header, UNKNOWN_NAME) != 0)
+      if (!strEqual(list->year_header, UNKNOWN_NAME))
        DrawTextSCentered(ystart + y++ * dy, FONT_TEXT_2, list->year_header);
       else
        DrawTextSCentered(ystart + y++ * dy, FONT_TEXT_2, "from the year");
@@ -1094,47 +1455,213 @@ void HandleInfoScreen_Music(int button)
     PlaySoundLoop(list->music);
 }
 
-void DrawInfoScreen_Credits()
+static boolean DrawInfoScreen_CreditsScreen(int screen_nr)
 {
   int ystart = 150, ystep = 30;
   int ybottom = SYSIZE - 20;
 
-  FadeSoundsAndMusic();
-
   ClearWindow();
   DrawHeadline();
 
   DrawTextSCentered(100, FONT_TEXT_1, "Credits:");
-  DrawTextSCentered(ystart + 0 * ystep, FONT_TEXT_2, "DOS port of the game:");
-  DrawTextSCentered(ystart + 1 * ystep, FONT_TEXT_3, "Guido Schulz");
-  DrawTextSCentered(ystart + 2 * ystep, FONT_TEXT_2, "Additional toons:");
-  DrawTextSCentered(ystart + 3 * ystep, FONT_TEXT_3, "Karl Hörnell");
-  DrawTextSCentered(ystart + 5 * ystep, FONT_TEXT_2,
-                   "...and many thanks to all contributors");
-  DrawTextSCentered(ystart + 6 * ystep, FONT_TEXT_2, "of new levels!");
+
+  if (screen_nr == 0)
+  {
+    DrawTextSCentered(ystart + 0 * ystep, FONT_TEXT_2,
+                     "Special thanks to");
+    DrawTextSCentered(ystart + 1 * ystep, FONT_TEXT_3,
+                     "Peter Liepa");
+    DrawTextSCentered(ystart + 2 * ystep, FONT_TEXT_2,
+                     "for creating");
+    DrawTextSCentered(ystart + 3 * ystep, FONT_TEXT_3,
+                     "\"Boulder Dash\"");
+    DrawTextSCentered(ystart + 4 * ystep, FONT_TEXT_2,
+                     "in the year");
+    DrawTextSCentered(ystart + 5 * ystep, FONT_TEXT_3,
+                     "1984");
+    DrawTextSCentered(ystart + 6 * ystep, FONT_TEXT_2,
+                     "published by");
+    DrawTextSCentered(ystart + 7 * ystep, FONT_TEXT_3,
+                     "First Star Software");
+  }
+  else if (screen_nr == 1)
+  {
+    DrawTextSCentered(ystart + 0 * ystep, FONT_TEXT_2,
+                     "Special thanks to");
+    DrawTextSCentered(ystart + 1 * ystep, FONT_TEXT_3,
+                     "Klaus Heinz & Volker Wertich");
+    DrawTextSCentered(ystart + 2 * ystep, FONT_TEXT_2,
+                     "for creating");
+    DrawTextSCentered(ystart + 3 * ystep, FONT_TEXT_3,
+                     "\"Emerald Mine\"");
+    DrawTextSCentered(ystart + 4 * ystep, FONT_TEXT_2,
+                     "in the year");
+    DrawTextSCentered(ystart + 5 * ystep, FONT_TEXT_3,
+                     "1987");
+    DrawTextSCentered(ystart + 6 * ystep, FONT_TEXT_2,
+                     "published by");
+    DrawTextSCentered(ystart + 7 * ystep, FONT_TEXT_3,
+                     "Kingsoft");
+  }
+  else if (screen_nr == 2)
+  {
+    DrawTextSCentered(ystart + 0 * ystep, FONT_TEXT_2,
+                     "Special thanks to");
+    DrawTextSCentered(ystart + 1 * ystep, FONT_TEXT_3,
+                     "Michael Stopp & Philip Jespersen");
+    DrawTextSCentered(ystart + 2 * ystep, FONT_TEXT_2,
+                     "for creating");
+    DrawTextSCentered(ystart + 3 * ystep, FONT_TEXT_3,
+                     "\"Supaplex\"");
+    DrawTextSCentered(ystart + 4 * ystep, FONT_TEXT_2,
+                     "in the year");
+    DrawTextSCentered(ystart + 5 * ystep, FONT_TEXT_3,
+                     "1991");
+    DrawTextSCentered(ystart + 6 * ystep, FONT_TEXT_2,
+                     "published by");
+    DrawTextSCentered(ystart + 7 * ystep, FONT_TEXT_3,
+                     "Digital Integration");
+  }
+  else if (screen_nr == 3)
+  {
+    DrawTextSCentered(ystart + 0 * ystep, FONT_TEXT_2,
+                     "Special thanks to");
+    DrawTextSCentered(ystart + 1 * ystep, FONT_TEXT_3,
+                     "Hiroyuki Imabayashi");
+    DrawTextSCentered(ystart + 2 * ystep, FONT_TEXT_2,
+                     "for creating");
+    DrawTextSCentered(ystart + 3 * ystep, FONT_TEXT_3,
+                     "\"Sokoban\"");
+    DrawTextSCentered(ystart + 4 * ystep, FONT_TEXT_2,
+                     "in the year");
+    DrawTextSCentered(ystart + 5 * ystep, FONT_TEXT_3,
+                     "1982");
+    DrawTextSCentered(ystart + 6 * ystep, FONT_TEXT_2,
+                     "published by");
+    DrawTextSCentered(ystart + 7 * ystep, FONT_TEXT_3,
+                     "Thinking Rabbit");
+  }
+  else if (screen_nr == 4)
+  {
+    DrawTextSCentered(ystart + 0 * ystep, FONT_TEXT_2,
+                     "Special thanks to");
+    DrawTextSCentered(ystart + 1 * ystep, FONT_TEXT_3,
+                     "Alan Bond");
+    DrawTextSCentered(ystart + 2 * ystep, FONT_TEXT_2,
+                     "and");
+    DrawTextSCentered(ystart + 3 * ystep, FONT_TEXT_3,
+                     "Jürgen Bonhagen");
+    DrawTextSCentered(ystart + 4 * ystep, FONT_TEXT_2,
+                     "for the continuous creation");
+    DrawTextSCentered(ystart + 5 * ystep, FONT_TEXT_2,
+                     "of outstanding level sets");
+  }
+  else if (screen_nr == 5)
+  {
+    DrawTextSCentered(ystart + 0 * ystep, FONT_TEXT_2,
+                     "Thanks to");
+    DrawTextSCentered(ystart + 1 * ystep, FONT_TEXT_3,
+                     "Peter Elzner");
+    DrawTextSCentered(ystart + 2 * ystep, FONT_TEXT_2,
+                     "for ideas and inspiration by");
+    DrawTextSCentered(ystart + 3 * ystep, FONT_TEXT_3,
+                     "Diamond Caves");
+
+    DrawTextSCentered(ystart + 5 * ystep, FONT_TEXT_2,
+                     "Thanks to");
+    DrawTextSCentered(ystart + 6 * ystep, FONT_TEXT_3,
+                     "Steffest");
+    DrawTextSCentered(ystart + 7 * ystep, FONT_TEXT_2,
+                     "for ideas and inspiration by");
+    DrawTextSCentered(ystart + 8 * ystep, FONT_TEXT_3,
+                     "DX-Boulderdash");
+  }
+  else if (screen_nr == 6)
+  {
+    DrawTextSCentered(ystart + 0 * ystep, FONT_TEXT_2,
+                     "Thanks to");
+    DrawTextSCentered(ystart + 1 * ystep, FONT_TEXT_3,
+                     "David Tritscher");
+    DrawTextSCentered(ystart + 2 * ystep, FONT_TEXT_2,
+                     "for the new Emerald Mine engine");
+  }
+  else if (screen_nr == 7)
+  {
+    DrawTextSCentered(ystart + 0 * ystep, FONT_TEXT_2,
+                     "Thanks to");
+    DrawTextSCentered(ystart + 1 * ystep, FONT_TEXT_3,
+                     "Guido Schulz");
+    DrawTextSCentered(ystart + 2 * ystep, FONT_TEXT_2,
+                     "for the initial DOS port");
+
+    DrawTextSCentered(ystart + 4 * ystep, FONT_TEXT_2,
+                     "Thanks to");
+    DrawTextSCentered(ystart + 5 * ystep, FONT_TEXT_3,
+                     "Karl Hörnell");
+    DrawTextSCentered(ystart + 6 * ystep, FONT_TEXT_2,
+                     "for some additional toons");
+  }
+  else if (screen_nr == 8)
+  {
+    DrawTextSCentered(ystart + 0 * ystep, FONT_TEXT_2,
+                     "And not to forget:");
+    DrawTextSCentered(ystart + 1 * ystep, FONT_TEXT_2,
+                     "Many thanks to");
+    DrawTextSCentered(ystart + 2 * ystep, FONT_TEXT_3,
+                     "All those who contributed");
+    DrawTextSCentered(ystart + 3 * ystep, FONT_TEXT_3,
+                     "levels to this game");
+    DrawTextSCentered(ystart + 4 * ystep, FONT_TEXT_3,
+                     "since 1995");
+  }
+  else
+  {
+    return FALSE;
+  }
 
   DrawTextSCentered(ybottom, FONT_TEXT_4,
-                   "Press any key or button for info menu");
+                   "Press any key or button for next page");
+
+  return TRUE;
+}
+
+void DrawInfoScreen_Credits()
+{
+  SetMainBackgroundImageIfDefined(IMG_BACKGROUND_INFO_CREDITS);
+
+  FadeSoundsAndMusic();
+
+  HandleInfoScreen_Credits(MB_MENU_INITIALIZE);
 }
 
 void HandleInfoScreen_Credits(int button)
 {
-  int button_released = !button;
+  static int screen_nr = 0;
 
-  if (button == MB_MENU_LEAVE)
+  if (button == MB_MENU_INITIALIZE)
+  {
+    screen_nr = 0;
+
+    DrawInfoScreen_CreditsScreen(screen_nr);
+  }
+  else if (button == MB_MENU_LEAVE)
   {
     info_mode = INFO_MODE_MAIN;
     DrawInfoScreen();
 
     return;
   }
-
-  if (button_released)
+  else if (button == MB_MENU_CHOICE)
   {
-    FadeSoundsAndMusic();
+    screen_nr++;
 
-    info_mode = INFO_MODE_MAIN;
-    DrawInfoScreen();
+    if (!DrawInfoScreen_CreditsScreen(screen_nr))
+    {
+      FadeSoundsAndMusic();
+
+      info_mode = INFO_MODE_MAIN;
+      DrawInfoScreen();
+    }
   }
   else
   {
@@ -1147,6 +1674,8 @@ void DrawInfoScreen_Program()
   int ystart = 150, ystep = 30;
   int ybottom = SYSIZE - 20;
 
+  SetMainBackgroundImageIfDefined(IMG_BACKGROUND_INFO_PROGRAM);
+
   ClearWindow();
   DrawHeadline();
 
@@ -1210,11 +1739,7 @@ void DrawInfoScreen_LevelSet()
   int ystart = 150;
   int ybottom = SYSIZE - 20;
   char *filename = getLevelSetInfoFilename();
-#if 0
-  int font_nr = FONT_TEXT_2;
-#else
   int font_nr = FONT_LEVEL_NUMBER;
-#endif
   int font_width = getFontWidth(font_nr);
   int font_height = getFontHeight(font_nr);
   int pad_x = 32;
@@ -1224,6 +1749,8 @@ void DrawInfoScreen_LevelSet()
   int max_chars_per_line = (SXSIZE - 2 * pad_x) / font_width;
   int max_lines_per_screen = (SYSIZE - pad_y) / font_height - 1;
 
+  SetMainBackgroundImageIfDefined(IMG_BACKGROUND_INFO_LEVELSET);
+
   ClearWindow();
   DrawHeadline();
 
@@ -1265,11 +1792,13 @@ void HandleInfoScreen_LevelSet(int button)
   }
 }
 
-void DrawInfoScreen()
+static void DrawInfoScreenExt(int fade_delay)
 {
   SetMainBackgroundImage(IMG_BACKGROUND_INFO);
 
-  if (info_mode == INFO_MODE_ELEMENTS)
+  if (info_mode == INFO_MODE_TITLE)
+    DrawInfoScreen_TitleScreen();
+  else if (info_mode == INFO_MODE_ELEMENTS)
     DrawInfoScreen_Elements();
   else if (info_mode == INFO_MODE_MUSIC)
     DrawInfoScreen_Music();
@@ -1280,18 +1809,27 @@ void DrawInfoScreen()
   else if (info_mode == INFO_MODE_LEVELSET)
     DrawInfoScreen_LevelSet();
   else
-    DrawInfoScreen_Main();
+    DrawInfoScreen_Main(fade_delay);
 
-  if (info_mode != INFO_MODE_MUSIC)
+  if (info_mode != INFO_MODE_MAIN &&
+      info_mode != INFO_MODE_TITLE &&
+      info_mode != INFO_MODE_MUSIC)
   {
     PlayMenuSound();
     PlayMenuMusic();
   }
 }
 
+void DrawInfoScreen()
+{
+  DrawInfoScreenExt(0);
+}
+
 void HandleInfoScreen(int mx, int my, int dx, int dy, int button)
 {
-  if (info_mode == INFO_MODE_ELEMENTS)
+  if (info_mode == INFO_MODE_TITLE)
+    HandleInfoScreen_TitleScreen(button);
+  else if (info_mode == INFO_MODE_ELEMENTS)
     HandleInfoScreen_Elements(button);
   else if (info_mode == INFO_MODE_MUSIC)
     HandleInfoScreen_Music(button);
@@ -1409,49 +1947,76 @@ static void drawChooseTreeList(int first_entry, int num_page_entries,
                               TreeInfo *ti)
 {
   int i;
-  char buffer[SCR_FIELDX * 2];
-  int max_buffer_len = (SCR_FIELDX - 2) * 2;
   char *title_string = NULL;
+#if 0
+  int xoffset_sets = 16;
+#endif
+  int yoffset_sets = MENU_TITLE1_YPOS;
+#if 0
   int xoffset_setup = 16;
+#endif
   int yoffset_setup = 16;
+#if 1
+#if 0
+  int xoffset = (ti->type == TREE_TYPE_LEVEL_DIR ? xoffset_sets :
+                xoffset_setup);
+#endif
+  int yoffset = (ti->type == TREE_TYPE_LEVEL_DIR ? yoffset_sets :
+                yoffset_setup);
+#else
   int xoffset = (ti->type == TREE_TYPE_LEVEL_DIR ? 0 : xoffset_setup);
   int yoffset = (ti->type == TREE_TYPE_LEVEL_DIR ? 0 : yoffset_setup);
+#endif
   int last_game_status = game_status;  /* save current game status */
 
   title_string =
-    (ti->type == TREE_TYPE_LEVEL_DIR ? "Level Directories" :
+    (ti->type == TREE_TYPE_LEVEL_DIR ? "Level Sets" :
      ti->type == TREE_TYPE_GRAPHICS_DIR ? "Custom Graphics" :
      ti->type == TREE_TYPE_SOUNDS_DIR ? "Custom Sounds" :
      ti->type == TREE_TYPE_MUSIC_DIR ? "Custom Music" : "");
 
+#if 1
+  DrawTextSCentered(mSY - SY + yoffset, FONT_TITLE_1, title_string);
+#else
   DrawText(SX + xoffset, SY + yoffset, title_string, FONT_TITLE_1);
+#endif
 
   /* force LEVELS font on artwork setup screen */
   game_status = GAME_MODE_LEVELS;
 
   /* clear tree list area, but not title or scrollbar */
   DrawBackground(mSX, mSY + MENU_SCREEN_START_YPOS * 32,
-                SXSIZE - 32 + menu.scrollbar_xoffset,
+                SC_SCROLLBAR_XPOS + menu.scrollbar_xoffset,
                 MAX_MENU_ENTRIES_ON_SCREEN * 32);
 
   for (i = 0; i < num_page_entries; i++)
   {
     TreeInfo *node, *node_first;
     int entry_pos = first_entry + i;
+    int xpos = MENU_SCREEN_START_XPOS;
     int ypos = MENU_SCREEN_START_YPOS + i;
+    int startx = mSX + xpos * 32;
+    int starty = mSY + ypos * 32;
+    int font_nr = FONT_TEXT_1;
+    int font_xoffset = getFontBitmapInfo(font_nr)->draw_xoffset;
+    int startx_text = startx + font_xoffset;
+    int startx_scrollbar = mSX + SC_SCROLLBAR_XPOS + menu.scrollbar_xoffset;
+    int text_size = startx_scrollbar - startx_text;
+    int max_buffer_len = text_size / getFontWidth(font_nr);
+    char buffer[max_buffer_len + 1];
 
     node_first = getTreeInfoFirstGroupEntry(ti);
     node = getTreeInfoFromPos(node_first, entry_pos);
 
-    strncpy(buffer, node->name , max_buffer_len);
+    strncpy(buffer, node->name, max_buffer_len);
     buffer[max_buffer_len] = '\0';
 
-    DrawText(mSX + 32, mSY + ypos * 32, buffer, FONT_TEXT_1 + node->color);
+    DrawText(startx, starty, buffer, font_nr + node->color);
 
     if (node->parent_link)
-      initCursor(i, IMG_MENU_BUTTON_LEFT);
+      initCursor(i, IMG_MENU_BUTTON_LEAVE_MENU);
     else if (node->level_group)
-      initCursor(i, IMG_MENU_BUTTON_RIGHT);
+      initCursor(i, IMG_MENU_BUTTON_ENTER_MENU);
     else
       initCursor(i, IMG_MENU_BUTTON);
   }
@@ -1465,6 +2030,11 @@ static void drawChooseTreeInfo(int entry_pos, TreeInfo *ti)
 {
   TreeInfo *node, *node_first;
   int x, last_redraw_mask = redraw_mask;
+#if 1
+  int ypos = MENU_TITLE2_YPOS;
+#else
+  int ypos = 40;
+#endif
 
   if (ti->type != TREE_TYPE_LEVEL_DIR)
     return;
@@ -1472,16 +2042,16 @@ static void drawChooseTreeInfo(int entry_pos, TreeInfo *ti)
   node_first = getTreeInfoFirstGroupEntry(ti);
   node = getTreeInfoFromPos(node_first, entry_pos);
 
-  DrawBackground(SX + 32, SY + 32, SXSIZE - 64, 32);
+  DrawBackground(SX, SY + ypos, SXSIZE, getFontHeight(FONT_TITLE_2));
 
   if (node->parent_link)
-    DrawTextFCentered(40, FONT_TITLE_2, "leave group \"%s\"",
+    DrawTextFCentered(ypos, FONT_TITLE_2, "leave group \"%s\"",
                      node->class_desc);
   else if (node->level_group)
-    DrawTextFCentered(40, FONT_TITLE_2, "enter group \"%s\"",
+    DrawTextFCentered(ypos, FONT_TITLE_2, "enter group \"%s\"",
                      node->class_desc);
   else if (ti->type == TREE_TYPE_LEVEL_DIR)
-    DrawTextFCentered(40, FONT_TITLE_2, "%3d levels (%s)",
+    DrawTextFCentered(ypos, FONT_TITLE_2, "%3d levels (%s)",
                      node->levels, node->class_desc);
 
   /* let BackToFront() redraw only what is needed */
@@ -1760,8 +2330,15 @@ static void drawHallOfFameList(int first_entry, int highlight_position)
   SetMainBackgroundImage(IMG_BACKGROUND_SCORES);
   ClearWindow();
 
-  DrawText(mSX + 80, mSY + 8, "Hall Of Fame", FONT_TITLE_1);
-  DrawTextFCentered(46, FONT_TITLE_2, "HighScores of Level %d", level_nr);
+#if 1
+  DrawTextSCentered(MENU_TITLE1_YPOS, FONT_TITLE_1, "Hall Of Fame");
+  DrawTextFCentered(MENU_TITLE2_YPOS, FONT_TITLE_2,
+                   "HighScores of Level %d", level_nr);
+#else
+  DrawText(mSX + 80, mSY + MENU_TITLE1_YPOS, "Hall Of Fame", FONT_TITLE_1);
+  DrawTextFCentered(MENU_TITLE2_YPOS, FONT_TITLE_2,
+                   "HighScores of Level %d", level_nr);
+#endif
 
   for (i = 0; i < NUM_MENU_ENTRIES_ON_SCREEN; i++)
   {
@@ -1779,8 +2356,10 @@ static void drawHallOfFameList(int first_entry, int highlight_position)
     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)
+
+    if (!strEqual(highscore[entry].Name, EMPTY_PLAYER_NAME))
       DrawText(mSX + dx2, sy, highscore[entry].Name, font_nr2);
+
     DrawText(mSX + dx3, sy, int2str(highscore[entry].Score, 5), font_nr4);
   }
 
@@ -1925,9 +2504,15 @@ static void execSetupInput()
   DrawSetupScreen();
 }
 
-static void execSetupShortcut()
+static void execSetupShortcut1()
+{
+  setup_mode = SETUP_MODE_SHORTCUT_1;
+  DrawSetupScreen();
+}
+
+static void execSetupShortcut2()
 {
-  setup_mode = SETUP_MODE_SHORTCUT;
+  setup_mode = SETUP_MODE_SHORTCUT_2;
   DrawSetupScreen();
 }
 
@@ -1945,13 +2530,14 @@ static void execSaveAndExitSetup()
 
 static struct TokenInfo setup_info_main[] =
 {
-  { TYPE_ENTER_MENU,   execSetupGame,          "Game Settings"         },
-  { TYPE_ENTER_MENU,   execSetupEditor,        "Editor Settings"       },
+  { TYPE_ENTER_MENU,   execSetupGame,          "Game & Menu"           },
+  { TYPE_ENTER_MENU,   execSetupEditor,        "Editor"                },
   { TYPE_ENTER_MENU,   execSetupGraphics,      "Graphics"              },
   { TYPE_ENTER_MENU,   execSetupSound,         "Sound & Music"         },
   { TYPE_ENTER_MENU,   execSetupArtwork,       "Custom Artwork"        },
   { TYPE_ENTER_MENU,   execSetupInput,         "Input Devices"         },
-  { TYPE_ENTER_MENU,   execSetupShortcut,      "Key Shortcuts"         },
+  { TYPE_ENTER_MENU,   execSetupShortcut1,     "Key Shortcuts 1"       },
+  { TYPE_ENTER_MENU,   execSetupShortcut2,     "Key Shortcuts 2"       },
   { TYPE_EMPTY,                NULL,                   ""                      },
   { TYPE_LEAVE_MENU,   execExitSetup,          "Exit"                  },
   { TYPE_LEAVE_MENU,   execSaveAndExitSetup,   "Save and Exit"         },
@@ -1961,11 +2547,12 @@ static struct TokenInfo setup_info_main[] =
 
 static struct TokenInfo setup_info_game[] =
 {
-  { TYPE_SWITCH,       &setup.team_mode,       "Team-Mode:"            },
+  { TYPE_SWITCH,       &setup.team_mode,       "Team-Mode (Multi-Player):" },
+  { TYPE_YES_NO,       &setup.input_on_focus,  "Only Move Focussed Player:" },
   { TYPE_SWITCH,       &setup.handicap,        "Handicap:"             },
-  { TYPE_SWITCH,       &setup.skip_levels,     "Skip Levels:"          },
-  { TYPE_SWITCH,       &setup.time_limit,      "Timelimit:"            },
-  { TYPE_SWITCH,       &setup.autorecord,      "Auto-Record:"          },
+  { TYPE_SWITCH,       &setup.skip_levels,     "Skip Unsolved Levels:" },
+  { TYPE_SWITCH,       &setup.time_limit,      "Time Limit:"           },
+  { TYPE_SWITCH,       &setup.autorecord,      "Auto-Record Tapes:"    },
   { TYPE_EMPTY,                NULL,                   ""                      },
   { TYPE_LEAVE_MENU,   execSetupMain,          "Back"                  },
 
@@ -1975,21 +2562,29 @@ static struct TokenInfo setup_info_game[] =
 static struct TokenInfo setup_info_editor[] =
 {
 #if 0
-  { TYPE_STRING,       NULL,                   "Offer Special Elements:"},
-#endif
-  { TYPE_SWITCH,       &setup.editor.el_boulderdash,   "BoulderDash:"  },
+  { TYPE_SWITCH,       &setup.editor.el_boulderdash,   "Boulder Dash:" },
   { TYPE_SWITCH,       &setup.editor.el_emerald_mine,  "Emerald Mine:" },
-  { TYPE_SWITCH,       &setup.editor.el_emerald_mine_club,"E.M. Club:" },
-  { TYPE_SWITCH,       &setup.editor.el_more,          "More:"         },
+  { TYPE_SWITCH, &setup.editor.el_emerald_mine_club,   "Emerald Mine Club:" },
+  { TYPE_SWITCH,       &setup.editor.el_more,          "Rocks'n'Diamonds:" },
   { TYPE_SWITCH,       &setup.editor.el_sokoban,       "Sokoban:"      },
   { TYPE_SWITCH,       &setup.editor.el_supaplex,      "Supaplex:"     },
-  { TYPE_SWITCH,       &setup.editor.el_diamond_caves, "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_SWITCH,       &setup.editor.el_custom_more,   "More Custom:"  },
+  { TYPE_SWITCH,       &setup.editor.el_diamond_caves, "Diamond Caves II:" },
+  { TYPE_SWITCH,       &setup.editor.el_dx_boulderdash,"DX-Boulderdash:" },
+#endif
+  { TYPE_SWITCH,       &setup.editor.el_chars,         "Text Characters:" },
+  { TYPE_SWITCH,       &setup.editor.el_custom,  "Custom & Group Elements:" },
+#if 0
   { TYPE_SWITCH,       &setup.editor.el_headlines,     "Headlines:"    },
-  { TYPE_SWITCH,       &setup.editor.el_user_defined,  "User defined:" },
+#endif
+  { TYPE_SWITCH, &setup.editor.el_user_defined, "User defined element list:" },
+  { TYPE_SWITCH,       &setup.editor.el_dynamic,  "Dynamic level elements:" },
+  { TYPE_EMPTY,                NULL,                   ""                      },
+#if 0
+  { TYPE_SWITCH,       &setup.editor.el_by_game,   "Show elements by game:" },
+  { TYPE_SWITCH,       &setup.editor.el_by_type,   "Show elements by type:" },
+  { TYPE_EMPTY,                NULL,                   ""                      },
+#endif
+  { TYPE_SWITCH, &setup.editor.show_element_token,     "Show element token:" },
   { TYPE_EMPTY,                NULL,                   ""                      },
   { TYPE_LEAVE_MENU,   execSetupMain,          "Back"                  },
 
@@ -1998,15 +2593,18 @@ static struct TokenInfo setup_info_editor[] =
 
 static struct TokenInfo setup_info_graphics[] =
 {
-  { TYPE_SWITCH,       &setup.fullscreen,      "Fullscreen:"           },
-  { TYPE_SWITCH,       &setup.scroll_delay,    "Scroll Delay:"         },
-  { TYPE_SWITCH,       &setup.soft_scrolling,  "Soft Scroll.:"         },
+  { TYPE_SWITCH,       &setup.fullscreen,      "Fullscreen Mode:"      },
+  { TYPE_SWITCH,       &setup.scroll_delay,    "Delayed Scrolling:"    },
 #if 0
-  { TYPE_SWITCH,       &setup.double_buffering,"Buffered gfx:"         },
+  { TYPE_SWITCH,       &setup.soft_scrolling,  "Soft Scrolling:"       },
+  { TYPE_SWITCH,       &setup.double_buffering,"Double-Buffering:"     },
   { TYPE_SWITCH,       &setup.fading,          "Fading:"               },
 #endif
-  { TYPE_SWITCH,       &setup.quick_doors,     "Quick Doors:"          },
-  { TYPE_SWITCH,       &setup.toons,           "Toons:"                },
+  { TYPE_SWITCH,       &setup.quick_switch,    "Quick Player Focus Switch:" },
+  { TYPE_SWITCH,       &setup.quick_doors,     "Quick Menu Doors:"     },
+  { TYPE_SWITCH,       &setup.show_titlescreen,"Show Title Screens:"   },
+  { TYPE_SWITCH,       &setup.toons,           "Show Toons:"           },
+  { TYPE_ECS_AGA,      &setup.prefer_aga_graphics,"EMC graphics preference:" },
   { TYPE_EMPTY,                NULL,                   ""                      },
   { TYPE_LEAVE_MENU,   execSetupMain,          "Back"                  },
 
@@ -2015,9 +2613,9 @@ static struct TokenInfo setup_info_graphics[] =
 
 static struct TokenInfo setup_info_sound[] =
 {
-  { TYPE_SWITCH,       &setup.sound_simple,    "Simple Sound:"         },
-  { TYPE_SWITCH,       &setup.sound_loops,     "Sound Loops:"          },
-  { TYPE_SWITCH,       &setup.sound_music,     "Game Music:"           },
+  { TYPE_SWITCH,       &setup.sound_simple,    "Sound Effects (Normal):"  },
+  { TYPE_SWITCH,       &setup.sound_loops,     "Sound Effects (Looping):" },
+  { TYPE_SWITCH,       &setup.sound_music,     "Music:"                },
   { TYPE_EMPTY,                NULL,                   ""                      },
   { TYPE_LEAVE_MENU,   execSetupMain,          "Back"                  },
 
@@ -2033,26 +2631,51 @@ static struct TokenInfo setup_info_artwork[] =
   { TYPE_ENTER_MENU,   execSetupChooseMusic,   "Custom Music"          },
   { TYPE_STRING,       &music_set_name,        ""                      },
   { TYPE_EMPTY,                NULL,                   ""                      },
+#if 1
+  { TYPE_YES_NO, &setup.override_level_graphics,"Override Level Graphics:" },
+  { TYPE_YES_NO, &setup.override_level_sounds, "Override Level Sounds:"   },
+  { TYPE_YES_NO, &setup.override_level_music,  "Override Level Music:"    },
+#else
   { 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:"        },
+#endif
   { TYPE_EMPTY,                NULL,                   ""                      },
   { TYPE_LEAVE_MENU,   execSetupMain,          "Back"                  },
 
   { 0,                 NULL,                   NULL                    }
 };
 
-static struct TokenInfo setup_info_shortcut[] =
+static struct TokenInfo setup_info_shortcut_1[] =
 {
-  { TYPE_KEYTEXT,      NULL,                   "Quick Save Game:",     },
-  { TYPE_KEY,          &setup.shortcut.save_game,      ""              },
-  { TYPE_KEYTEXT,      NULL,                   "Quick Load Game:",     },
-  { TYPE_KEY,          &setup.shortcut.load_game,      ""              },
-  { TYPE_KEYTEXT,      NULL,                   "Toggle Pause:",        },
-  { TYPE_KEY,          &setup.shortcut.toggle_pause,   ""              },
+  { TYPE_KEYTEXT,      NULL,           "Quick Save Game to Tape:",     },
+  { TYPE_KEY,          &setup.shortcut.save_game, ""                   },
+  { TYPE_KEYTEXT,      NULL,           "Quick Load Game from Tape:",   },
+  { TYPE_KEY,          &setup.shortcut.load_game, ""                   },
+  { TYPE_KEYTEXT,      NULL,           "Start Game & Toggle Pause:",   },
+  { TYPE_KEY,          &setup.shortcut.toggle_pause, ""                },
   { TYPE_EMPTY,                NULL,                   ""                      },
-  { TYPE_YES_NO,       &setup.ask_on_escape,   "Ask on Esc:"           },
+  { TYPE_YES_NO,       &setup.ask_on_escape,   "Ask on 'Esc' Key:"     },
+  { TYPE_YES_NO, &setup.ask_on_escape_editor,  "Ask on 'Esc' Key (Editor):" },
+  { TYPE_EMPTY,                NULL,                   ""                      },
+  { TYPE_LEAVE_MENU,   execSetupMain,          "Back"                  },
+
+  { 0,                 NULL,                   NULL                    }
+};
+
+static struct TokenInfo setup_info_shortcut_2[] =
+{
+  { TYPE_KEYTEXT,      NULL,           "Set Focus to Player 1:",       },
+  { TYPE_KEY,          &setup.shortcut.focus_player[0], ""             },
+  { TYPE_KEYTEXT,      NULL,           "Set Focus to Player 2:",       },
+  { TYPE_KEY,          &setup.shortcut.focus_player[1], ""             },
+  { TYPE_KEYTEXT,      NULL,           "Set Focus to Player 3:",       },
+  { TYPE_KEY,          &setup.shortcut.focus_player[2], ""             },
+  { TYPE_KEYTEXT,      NULL,           "Set Focus to Player 4:",       },
+  { TYPE_KEY,          &setup.shortcut.focus_player[3], ""             },
+  { TYPE_KEYTEXT,      NULL,           "Set Focus to All Players:",    },
+  { TYPE_KEY,          &setup.shortcut.focus_player_all, ""            },
   { TYPE_EMPTY,                NULL,                   ""                      },
   { TYPE_LEAVE_MENU,   execSetupMain,          "Back"                  },
 
@@ -2106,47 +2729,153 @@ static Key getSetupKey()
   return key;
 }
 
+static int getSetupTextFont(int type)
+{
+  if (type & (TYPE_SWITCH |
+             TYPE_YES_NO |
+             TYPE_STRING |
+             TYPE_ECS_AGA |
+             TYPE_KEYTEXT))
+    return FONT_MENU_2;
+  else
+    return FONT_MENU_1;
+}
+
+static int getSetupValueFont(int type, void *value)
+{
+  if (type & TYPE_KEY)
+    return (type & TYPE_QUERY ? FONT_INPUT_1_ACTIVE : FONT_VALUE_1);
+  else if (type & TYPE_STRING)
+    return FONT_VALUE_2;
+  else if (type & TYPE_ECS_AGA)
+    return FONT_VALUE_1;
+  else if (type & TYPE_BOOLEAN_STYLE)
+    return (*(boolean *)value ? FONT_OPTION_ON : FONT_OPTION_OFF);
+  else
+    return FONT_VALUE_1;
+}
+
 static void drawSetupValue(int pos)
 {
+  boolean font_draw_xoffset_modified = FALSE;
+  int font_draw_xoffset_old = -1;
   int xpos = MENU_SCREEN_VALUE_XPOS;
   int ypos = MENU_SCREEN_START_YPOS + pos;
-  int font_nr = FONT_VALUE_1;
+  int startx = mSX + xpos * 32;
+  int starty = mSY + ypos * 32;
+  int font_nr, font_width;
   int type = setup_info[pos].type;
   void *value = setup_info[pos].value;
-  char *value_string = (!(type & TYPE_GHOSTED) ? getSetupValue(type, value) :
-                       "n/a");
+  char *value_string = getSetupValue(type, value);
+  int i;
 
   if (value_string == NULL)
     return;
 
   if (type & TYPE_KEY)
   {
+#if 1
+    xpos = MENU_SCREEN_START_XPOS;
+#else
     xpos = 3;
+#endif
 
     if (type & TYPE_QUERY)
     {
       value_string = "<press key>";
+#if 0
       font_nr = FONT_INPUT_1_ACTIVE;
+#endif
     }
   }
   else if (type & TYPE_STRING)
   {
     int max_value_len = (SCR_FIELDX - 2) * 2;
 
-    xpos = 1;
+    xpos = MENU_SCREEN_START_XPOS;
+#if 0
     font_nr = FONT_VALUE_2;
+#endif
 
     if (strlen(value_string) > max_value_len)
       value_string[max_value_len] = '\0';
   }
+  else if (type & TYPE_ECS_AGA)
+  {
+#if 0
+    font_nr = FONT_VALUE_1;
+#endif
+  }
   else if (type & TYPE_BOOLEAN_STYLE)
   {
+#if 0
     font_nr = (*(boolean *)value ? FONT_OPTION_ON : FONT_OPTION_OFF);
+#endif
+  }
+
+  startx = mSX + xpos * 32;
+  starty = mSY + ypos * 32;
+  font_nr = getSetupValueFont(type, value);
+  font_width = getFontWidth(font_nr);
+
+  /* downward compatibility correction for Juergen Bonhagen's menu settings */
+  if (setup_mode != SETUP_MODE_INPUT)
+  {
+    int check_font_nr = FONT_OPTION_ON; /* known font that needs correction */
+    int font1_xoffset = getFontBitmapInfo(font_nr)->draw_xoffset;
+    int font2_xoffset = getFontBitmapInfo(check_font_nr)->draw_xoffset;
+    int text_startx = mSX + MENU_SCREEN_START_XPOS * 32;
+    int text_font_nr = getSetupTextFont(FONT_MENU_2);
+    int text_font_xoffset = getFontBitmapInfo(text_font_nr)->draw_xoffset;
+    int text_width = MAX_MENU_TEXT_LENGTH_MEDIUM * getFontWidth(text_font_nr);
+    boolean correct_font_draw_xoffset = FALSE;
+
+    if (xpos == MENU_SCREEN_START_XPOS &&
+       startx + font1_xoffset < text_startx + text_font_xoffset)
+      correct_font_draw_xoffset = TRUE;
+
+    if (xpos == MENU_SCREEN_VALUE_XPOS &&
+       startx + font2_xoffset < text_startx + text_width + text_font_xoffset)
+      correct_font_draw_xoffset = TRUE;
+
+#if 0
+    printf("::: %d + %d < %d + %d + %d\n",
+          startx, font_xoffset, text_startx, text_width, text_font_xoffset);
+    printf("::: => need correction == %d\n", correct_font_draw_xoffset);
+#endif
+
+    /* check if setup value would overlap with setup text when printed */
+    /* (this can happen for extreme/wrong values for font draw offset) */
+    if (correct_font_draw_xoffset)
+    {
+      font_draw_xoffset_old = getFontBitmapInfo(font_nr)->draw_xoffset;
+      font_draw_xoffset_modified = TRUE;
+
+      if (type & TYPE_KEY)
+       getFontBitmapInfo(font_nr)->draw_xoffset += 2 * getFontWidth(font_nr);
+      else if (!(type & TYPE_STRING))
+       getFontBitmapInfo(font_nr)->draw_xoffset = text_font_xoffset + 20 -
+         MAX_MENU_TEXT_LENGTH_MEDIUM * (16 - getFontWidth(text_font_nr));
+    }
   }
 
-  DrawText(mSX + xpos * 32, mSY + ypos * 32,
+#if 1
+  for (i = 0; i <= MENU_SCREEN_MAX_XPOS - xpos; i++)
+    DrawText(startx + i * font_width, starty, " ", font_nr);
+#else
+#if 1
+  for (i = xpos; i <= MENU_SCREEN_MAX_XPOS; i++)
+    DrawText(mSX + i * 32, starty, " ", font_nr);
+#else
+  DrawText(startx, starty,
           (xpos == 3 ? "              " : "   "), font_nr);
-  DrawText(mSX + xpos * 32, mSY + ypos * 32, value_string, font_nr);
+#endif
+#endif
+
+  DrawText(startx, starty, value_string, font_nr);
+
+  if (font_draw_xoffset_modified)
+    getFontBitmapInfo(font_nr)->draw_xoffset = font_draw_xoffset_old;
 }
 
 static void changeSetupValue(int pos)
@@ -2211,20 +2940,34 @@ static void DrawSetupScreen_Generic()
     setup_info = setup_info_artwork;
     title_string = "Custom Artwork";
   }
-  else if (setup_mode == SETUP_MODE_SHORTCUT)
+  else if (setup_mode == SETUP_MODE_SHORTCUT_1)
   {
-    setup_info = setup_info_shortcut;
+    setup_info = setup_info_shortcut_1;
+    title_string = "Setup Shortcuts";
+  }
+  else if (setup_mode == SETUP_MODE_SHORTCUT_2)
+  {
+    setup_info = setup_info_shortcut_2;
     title_string = "Setup Shortcuts";
   }
 
+#if 1
+  DrawTextSCentered(mSY - SY + 16, FONT_TITLE_1, title_string);
+#else
   DrawText(mSX + 16, mSY + 16, title_string, FONT_TITLE_1);
+#endif
 
   num_setup_info = 0;
   for (i = 0; setup_info[i].type != 0 && i < NUM_MENU_ENTRIES_ON_SCREEN; i++)
   {
     void *value_ptr = setup_info[i].value;
+    int xpos = MENU_SCREEN_START_XPOS;
     int ypos = MENU_SCREEN_START_YPOS + i;
+#if 1
+    int font_nr;
+#else
     int font_nr = FONT_MENU_1;
+#endif
 
     /* set some entries to "unchangeable" according to other variables */
     if ((value_ptr == &setup.sound_simple && !audio.sound_available) ||
@@ -2233,21 +2976,28 @@ static void DrawSetupScreen_Generic()
        (value_ptr == &setup.fullscreen   && !video.fullscreen_available))
       setup_info[i].type |= TYPE_GHOSTED;
 
-#if 0
-    if (setup_info[i].type & TYPE_STRING ||
-       (setup_info[i].type & TYPE_SWITCH && setup_mode == SETUP_MODE_EDITOR))
+#if 1
+    font_nr = getSetupTextFont(setup_info[i].type);
+#else
+#if 1
+    if (setup_info[i].type & (TYPE_SWITCH |
+                             TYPE_YES_NO |
+                             TYPE_STRING |
+                             TYPE_ECS_AGA |
+                             TYPE_KEYTEXT))
       font_nr = FONT_MENU_2;
 #else
     if (setup_info[i].type & TYPE_STRING)
       font_nr = FONT_MENU_2;
+#endif
 #endif
 
-    DrawText(mSX + 32, mSY + ypos * 32, setup_info[i].text, font_nr);
+    DrawText(mSX + xpos * 32, mSY + ypos * 32, setup_info[i].text, font_nr);
 
     if (setup_info[i].type & TYPE_ENTER_MENU)
-      initCursor(i, IMG_MENU_BUTTON_RIGHT);
+      initCursor(i, IMG_MENU_BUTTON_ENTER_MENU);
     else if (setup_info[i].type & TYPE_LEAVE_MENU)
-      initCursor(i, IMG_MENU_BUTTON_LEFT);
+      initCursor(i, IMG_MENU_BUTTON_LEAVE_MENU);
     else if (setup_info[i].type & ~TYPE_SKIP_ENTRY)
       initCursor(i, IMG_MENU_BUTTON);
 
@@ -2257,6 +3007,11 @@ static void DrawSetupScreen_Generic()
     num_setup_info++;
   }
 
+#if 0
+  DrawTextSCentered(SYSIZE - 20, FONT_TEXT_4,
+                   "Joysticks deactivated in setup menu");
+#endif
+
   FadeToFront();
   InitAnimation();
   HandleSetupScreen_Generic(0, 0, 0, 0, MB_MENU_INITIALIZE);
@@ -2357,22 +3112,28 @@ void DrawSetupScreen_Input()
 {
   ClearWindow();
 
-  DrawText(mSX+16, mSY+16, "Setup Input", FONT_TITLE_1);
+#if 1
+  DrawTextSCentered(mSY - SY + 16, FONT_TITLE_1, "Setup Input");
+#else
+  DrawText(mSX + 16, mSY + 16, "Setup Input", FONT_TITLE_1);
+#endif
 
-  initCursor(0, IMG_MENU_BUTTON);
-  initCursor(1, IMG_MENU_BUTTON);
-  initCursor(2, IMG_MENU_BUTTON_RIGHT);
-  initCursor(13, IMG_MENU_BUTTON_LEFT);
+  initCursor(0,  IMG_MENU_BUTTON);
+  initCursor(1,  IMG_MENU_BUTTON);
+  initCursor(2,  IMG_MENU_BUTTON_ENTER_MENU);
+  initCursor(13, IMG_MENU_BUTTON_LEAVE_MENU);
 
   drawCursorXY(10, 0, IMG_MENU_BUTTON_LEFT);
   drawCursorXY(12, 0, IMG_MENU_BUTTON_RIGHT);
 
-  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);
+  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();
+#endif
+#if 1
   DrawTextSCentered(SYSIZE - 20, FONT_TEXT_4,
                    "Joysticks deactivated on this screen");
 #endif
@@ -2428,52 +3189,52 @@ static void drawPlayerSetupInputInfo(int player_nr)
     "Joystick4"
   };
 
+  InitJoysticks();
+
   custom_key = setup.input[player_nr].key;
 
-  DrawText(mSX+11*32, mSY+2*32, int2str(player_nr +1, 1), FONT_INPUT_1_ACTIVE);
-#if 1
+  DrawText(mSX + 11 * 32, mSY + 2 * 32, int2str(player_nr + 1, 1),
+          FONT_INPUT_1_ACTIVE);
+
   ClearRectangleOnBackground(drawto, mSX + 8 * TILEX, mSY + 2 * TILEY,
                             TILEX, TILEY);
   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;
+    char *text = joystick_name[getJoystickNrFromDeviceName(device_name)];
+    int font_nr = (joystick.fd[player_nr] < 0 ? FONT_VALUE_OLD : FONT_VALUE_1);
 
-    DrawText(mSX+8*32, mSY+3*32,
-            joystick_name[getJoystickNrFromDeviceName(device_name)],
-            FONT_VALUE_1);
-    DrawText(mSX+32, mSY+4*32, "Calibrate", FONT_MENU_1);
+    DrawText(mSX + 8 * 32, mSY + 3 * 32, text, font_nr);
+    DrawText(mSX + 32, mSY + 4 * 32, "Calibrate", FONT_MENU_1);
   }
   else
   {
-    DrawText(mSX+8*32, mSY+3*32, "Keyboard ", FONT_VALUE_1);
-    DrawText(mSX+32,   mSY+4*32, "Customize", FONT_MENU_1);
+    DrawText(mSX + 8 * 32, mSY + 3 * 32, "Keyboard ", FONT_VALUE_1);
+    DrawText(mSX + 1 * 32, mSY + 4 * 32, "Customize", FONT_MENU_1);
   }
 
-  DrawText(mSX+32, mSY+5*32, "Actual Settings:", FONT_MENU_1);
+  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, "Drop Element:", FONT_VALUE_OLD);
+  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 + 1 * 32, mSY + 10 * 32, "Snap Field:", FONT_VALUE_OLD);
+  DrawText(mSX + 1 * 32, mSY + 12 * 32, "Drop Element:", FONT_VALUE_OLD);
 
   for (i = 0; i < 6; i++)
   {
     int ypos = 6 + i + (i > 3 ? i-3 : 0);
 
-    DrawText(mSX + 3*32, mSY + ypos*32,
+    DrawText(mSX + 3 * 32, mSY + ypos * 32,
             "              ", FONT_VALUE_1);
-    DrawText(mSX + 3*32, mSY + ypos*32,
+    DrawText(mSX + 3 * 32, mSY + ypos * 32,
             (setup.input[player_nr].use_joystick ?
              custom[i].text :
              getKeyNameFromKey(*custom[i].key)), FONT_VALUE_1);
@@ -2623,17 +3384,22 @@ void CustomizeKeyboard(int player_nr)
   custom_key = setup.input[player_nr].key;
 
   ClearWindow();
+
+#if 1
+  DrawTextSCentered(mSY - SY + 16, FONT_TITLE_1, "Keyboard Input");
+#else
   DrawText(mSX + 16, mSY + 16, "Keyboard Input", FONT_TITLE_1);
+#endif
 
   BackToFront();
   InitAnimation();
 
   step_nr = 0;
-  DrawText(mSX, mSY + (2+2*step_nr)*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,
+  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,
+  DrawText(mSX + 4 * 32, mSY + (2 + 2 * step_nr + 1) * 32,
           getKeyNameFromKey(*customize_step[step_nr].key), FONT_VALUE_OLD);
 
   while (!finished)
@@ -2673,32 +3439,32 @@ void CustomizeKeyboard(int player_nr)
 
            /* got new key binding */
            *customize_step[step_nr].key = key;
-           DrawText(mSX + 4*32, mSY + (2+2*step_nr+1)*32,
+           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,
+           DrawText(mSX + 4 * 32, mSY + (2 + 2 * step_nr + 1) * 32,
                     getKeyNameFromKey(key), FONT_VALUE_1);
            step_nr++;
 
            /* un-highlight last query */
-           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,
+           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(mSX + 16, mSY + 15*32+16,
+             DrawText(mSX + 16, mSY + 15 * 32 + 16,
                       "Press Enter", FONT_TITLE_1);
              break;
            }
 
            /* query next key binding */
-           DrawText(mSX, mSY+(2+2*step_nr)*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,
+           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,
+           DrawText(mSX + 4 * 32, mSY + (2 + 2 * step_nr + 1) * 32,
                     getKeyNameFromKey(*customize_step[step_nr].key),
                     FONT_VALUE_OLD);
          }
@@ -2761,13 +3527,13 @@ static boolean CalibrateJoystickMain(int player_nr)
     }
   }
 
-  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);
+  DrawTextSCentered(mSY - SY +  6 * 32, FONT_TITLE_1, "Rotate joystick");
+  DrawTextSCentered(mSY - SY +  7 * 32, FONT_TITLE_1, "in all directions");
+  DrawTextSCentered(mSY - SY +  9 * 32, FONT_TITLE_1, "if all balls");
+  DrawTextSCentered(mSY - SY + 10 * 32, FONT_TITLE_1, "are marked,");
+  DrawTextSCentered(mSY - SY + 11 * 32, FONT_TITLE_1, "center joystick");
+  DrawTextSCentered(mSY - SY + 12 * 32, FONT_TITLE_1, "and");
+  DrawTextSCentered(mSY - SY + 13 * 32, FONT_TITLE_1, "press any button!");
 
   joy_value = Joystick(player_nr);
   last_x = (joy_value & JOY_LEFT ? -1 : joy_value & JOY_RIGHT ? +1 : 0);
@@ -2893,7 +3659,9 @@ static boolean CalibrateJoystickMain(int player_nr)
 
   StopAnimation();
 
+#if 0
   DrawSetupScreen_Input();
+#endif
 
   /* wait until the last pressed button was released */
   while (Joystick(player_nr) & JOY_BUTTON)
@@ -2916,13 +3684,25 @@ void CalibrateJoystick(int player_nr)
 {
   if (!CalibrateJoystickMain(player_nr))
   {
+    char *device_name = setup.input[player_nr].joy.device_name;
+    int nr = getJoystickNrFromDeviceName(device_name) + 1;
+    int xpos = mSX - SX;
+    int ypos = mSY - SY;
+
     ClearWindow();
 
-    DrawText(mSX + 16, mSY + 6 * 32, "  JOYSTICK NOT  ",  FONT_TITLE_1);
-    DrawText(mSX,      mSY + 7 * 32, "    AVAILABLE    ", FONT_TITLE_1);
+    DrawTextF(xpos + 16, ypos + 6 * 32, FONT_TITLE_1, "   JOYSTICK %d   ", nr);
+    DrawTextF(xpos + 16, ypos + 7 * 32, FONT_TITLE_1, " NOT AVAILABLE! ");
     BackToFront();
-    Delay(2000);       /* show error message for two seconds */
+
+    Delay(2000);               /* show error message for a short time */
+
+    ClearEventQueue();
   }
+
+#if 1
+  DrawSetupScreen_Input();
+#endif
 }
 
 void DrawSetupScreen()
@@ -2967,154 +3747,14 @@ void HandleGameActions()
   if (game_status != GAME_MODE_PLAYING)
     return;
 
-  /* !!! FIX THIS (START) !!! */
-  if (level.game_engine_type == GAME_ENGINE_TYPE_EM)
-  {
-    byte *recorded_player_action;
-    byte summarized_player_action = 0;
-    byte tape_action[MAX_PLAYERS];
-    int i;
-
-    if (level.native_em_level->lev->home == 0) /* all players at home */
-    {
-      GameWon();
-
-      if (!TAPE_IS_STOPPED(tape))
-       TapeStop();
-
-      if (game_status != GAME_MODE_PLAYING)
-       return;
-    }
-
-    if (level.native_em_level->ply1->alive == 0 &&
-       level.native_em_level->ply2->alive == 0)        /* all dead */
-      AllPlayersGone = TRUE;
-
-    if (AllPlayersGone && !TAPE_IS_STOPPED(tape))
-      TapeStop();
-
-    /* --- game actions --- */
+  GameActions();       /* main game loop */
 
-    if (tape.pausing)
-    {
-      /* don't use 100% CPU while in pause mode -- this should better be solved
-        like in the R'n'D game engine! */
-
-      Delay(10);
-
-      return;
-    }
-
-    recorded_player_action = (tape.playing ? TapePlayAction() : NULL);
-
-#if 1
-    /* !!! CHECK THIS (tape.pausing is always FALSE here!) !!! */
-    if (recorded_player_action == NULL && tape.pausing)
-      return;
-#endif
-
-    for (i = 0; i < MAX_PLAYERS; i++)
-    {
-      summarized_player_action |= stored_player[i].action;
-
-      if (!network_playing)
-       stored_player[i].effective_action = stored_player[i].action;
-    }
-
-    if (!options.network && !setup.team_mode)
-      local_player->effective_action = summarized_player_action;
-
-    if (recorded_player_action != NULL)
-      for (i = 0; i < MAX_PLAYERS; i++)
-       stored_player[i].effective_action = recorded_player_action[i];
-
-    for (i = 0; i < MAX_PLAYERS; i++)
-    {
-      tape_action[i] = stored_player[i].effective_action;
-
-      /* !!! (this does not happen in the EM engine) !!! */
-      if (tape.recording && tape_action[i] && !tape.player_participates[i])
-       tape.player_participates[i] = TRUE;  /* player just appeared from CE */
-    }
-
-    /* only save actions from input devices, but not programmed actions */
-    if (tape.recording)
-      TapeRecordAction(tape_action);
-
-    GameActions_EM(local_player->effective_action);
-
-    if (TimeFrames >= FRAMES_PER_SECOND)
-    {
-      TimeFrames = 0;
-      TapeTime++;
-
-      if (!level.use_step_counter)
-      {
-       TimePlayed++;
-
-       if (TimeLeft > 0)
-       {
-         TimeLeft--;
-
-         if (TimeLeft <= 10 && setup.time_limit)
-           PlaySoundStereo(SND_GAME_RUNNING_OUT_OF_TIME, SOUND_MIDDLE);
-
-         DrawGameValue_Time(TimeLeft);
-
-         if (!TimeLeft && setup.time_limit)
-           level.native_em_level->lev->killed_out_of_time = TRUE;
-       }
-       else if (level.time == 0 && level.native_em_level->lev->home > 0)
-         DrawGameValue_Time(TimePlayed);
-
-       level.native_em_level->lev->time =
-         (level.time == 0 ? TimePlayed : TimeLeft);
-      }
-
-      if (tape.recording || tape.playing)
-       DrawVideoDisplay(VIDEO_STATE_TIME_ON, TapeTime);
-    }
-
-    FrameCounter++;
-    TimeFrames++;
-
-    BackToFront();
-  }
-  else
-  {
-    if (local_player->LevelSolved)
-      GameWon();
-
-    if (AllPlayersGone && !TAPE_IS_STOPPED(tape))
-      TapeStop();
-
-    GameActions();
-    BackToFront();
-
-    if (tape.auto_play && !tape.playing)
-      AutoPlayTape();  /* continue automatically playing next tape */
-  }
+  if (tape.auto_play && !tape.playing)
+    AutoPlayTape();    /* continue automatically playing next tape */
 }
 
-/* ---------- new screen button stuff -------------------------------------- */
-
-/* graphic position and size values for buttons and scrollbars */
-#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              (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_DOWN_XPOS            SC_SCROLL_UP_XPOS
-#define SC_SCROLL_DOWN_YPOS            (SC_SCROLL_VERTICAL_YPOS + \
-                                        SC_SCROLL_VERTICAL_YSIZE)
 
-#define SC_BORDER_SIZE                 14
+/* ---------- new screen button stuff -------------------------------------- */
 
 static struct
 {
index 949267f001e0586a8b9e2ffd078ca0648785d53a..e895c4feefa9610b74200a8b745989bb8308cdad 100644 (file)
@@ -24,6 +24,7 @@
 void DrawMainMenu(void);
 void DrawHallOfFame(int);
 
+void HandleTitleScreen(int, int, int, int, int);
 void HandleMainMenu(int, int, int, int, int);
 void HandleChooseLevel(int, int, int, int, int);
 void HandleHallOfFame(int, int, int, int, int);
index 172af415b67bdf451da87957f3dd39926853aa0d..2f912cff26e45a63c98338504939b5d6e0a9d964 100644 (file)
@@ -345,102 +345,6 @@ void DrawVideoDisplay(unsigned long state, unsigned long value)
     },
   };
 
-#if 0
-  if (state & VIDEO_STATE_FFWD_OFF)
-  {
-#if 1
-    int cx = DOOR_GFX_PAGEX3, cy = DOOR_GFX_PAGEY2;
-
-    if (value != VIDEO_DISPLAY_SYMBOL_ONLY)
-      BlitBitmap(graphic_info[IMG_GLOBAL_DOOR].bitmap, drawto,
-                cx + VIDEO_LABEL_XPOS,
-                cy + VIDEO_LABEL_YPOS,
-                VIDEO_LABEL_XSIZE,
-                VIDEO_LABEL_YSIZE,
-                VX + VIDEO_LABEL_XPOS,
-                VY + VIDEO_LABEL_YPOS);
-
-    cx = DOOR_GFX_PAGEX3;
-    cy = DOOR_GFX_PAGEY2;
-
-    if (value != VIDEO_DISPLAY_LABEL_ONLY)
-      BlitBitmap(graphic_info[IMG_GLOBAL_DOOR].bitmap, drawto,
-                cx + VIDEO_FFWD_SYMBOL_XPOS,
-                cy + VIDEO_SYMBOL_YPOS,
-                VIDEO_FFWD_SYMBOL_XSIZE,
-                VIDEO_FFWD_SYMBOL_YSIZE,
-                VX + VIDEO_SYMBOL_XPOS,
-                VY + VIDEO_SYMBOL_YPOS);
-#else
-    int cx = DOOR_GFX_PAGEX3, cy = DOOR_GFX_PAGEY2;
-
-    BlitBitmap(graphic_info[IMG_GLOBAL_DOOR].bitmap, drawto,
-              cx + VIDEO_PLAY_SYMBOL_XPOS - 9,
-              cy + VIDEO_PLAY_SYMBOL_YPOS,
-              VIDEO_PLAY_SYMBOL_XSIZE - 2,
-              VIDEO_PLAY_SYMBOL_YSIZE,
-              VX + VIDEO_PLAY_SYMBOL_XPOS - 9,
-              VY + VIDEO_PLAY_SYMBOL_YPOS);
-#endif
-  }
-#endif
-
-#if 0
-  if (state & VIDEO_STATE_PBEND_OFF)
-  {
-#if 1
-    int cx = DOOR_GFX_PAGEX3, cy = DOOR_GFX_PAGEY2;
-
-    if (value != VIDEO_DISPLAY_SYMBOL_ONLY)
-      BlitBitmap(graphic_info[IMG_GLOBAL_DOOR].bitmap, drawto,
-                cx + VIDEO_LABEL_XPOS,
-                cy + VIDEO_LABEL_YPOS,
-                VIDEO_LABEL_XSIZE,
-                VIDEO_LABEL_YSIZE,
-                VX + VIDEO_LABEL_XPOS,
-                VY + VIDEO_LABEL_YPOS);
-
-    cx = DOOR_GFX_PAGEX3;
-    cy = DOOR_GFX_PAGEY2;
-
-    if (value != VIDEO_DISPLAY_LABEL_ONLY)
-      BlitBitmap(graphic_info[IMG_GLOBAL_DOOR].bitmap, drawto,
-                cx + VIDEO_PBEND_SYMBOL_XPOS,
-                cy + VIDEO_SYMBOL_YPOS,
-                VIDEO_PBEND_SYMBOL_XSIZE,
-                VIDEO_PBEND_SYMBOL_YSIZE,
-                VX + VIDEO_PBEND_SYMBOL_XPOS,
-                VY + VIDEO_SYMBOL_YPOS);
-#else
-    int cx = DOOR_GFX_PAGEX3, cy = DOOR_GFX_PAGEY2;
-
-    BlitBitmap(graphic_info[IMG_GLOBAL_DOOR].bitmap, drawto,
-              cx + VIDEO_REC_LABEL_XPOS,
-              cy + VIDEO_REC_LABEL_YPOS,
-              VIDEO_PBEND_LABEL_XSIZE,
-              VIDEO_PBEND_LABEL_YSIZE,
-              VX + VIDEO_REC_LABEL_XPOS,
-              VY + VIDEO_REC_LABEL_YPOS);
-#endif
-  }
-#endif
-
-#if 0
-  if (state & VIDEO_STATE_1STEP_OFF)
-  {
-    int cx = DOOR_GFX_PAGEX3, cy = DOOR_GFX_PAGEY2;
-
-    if (value != VIDEO_DISPLAY_LABEL_ONLY)
-      BlitBitmap(graphic_info[IMG_GLOBAL_DOOR].bitmap, drawto,
-                cx + VIDEO_1STEP_SYMBOL_XPOS,
-                cy + VIDEO_SYMBOL_YPOS,
-                VIDEO_1STEP_SYMBOL_XSIZE,
-                VIDEO_1STEP_SYMBOL_YSIZE,
-                VX + VIDEO_1STEP_SYMBOL_XPOS,
-                VY + VIDEO_SYMBOL_YPOS);
-  }
-#endif
-
   for (k = 0; k < NUM_TAPE_FUNCTION_STATES; k++)       /* on or off states */
   {
     for (i = 0; i < NUM_TAPE_FUNCTIONS; i++)           /* record, play, ... */
@@ -476,102 +380,6 @@ void DrawVideoDisplay(unsigned long state, unsigned long value)
     }
   }
 
-#if 0
-  if (state & VIDEO_STATE_FFWD_ON)
-  {
-#if 1
-    int cx = DOOR_GFX_PAGEX6, cy = DOOR_GFX_PAGEY1;
-
-    if (value != VIDEO_DISPLAY_SYMBOL_ONLY)
-      BlitBitmap(graphic_info[IMG_GLOBAL_DOOR].bitmap, drawto,
-                cx + VIDEO_FFWD_LABEL_XPOS,
-                cy + VIDEO_FFWD_LABEL_YPOS,
-                VIDEO_LABEL_XSIZE,
-                VIDEO_LABEL_YSIZE,
-                VX + VIDEO_LABEL_XPOS,
-                VY + VIDEO_LABEL_YPOS);
-
-    cx = DOOR_GFX_PAGEX6;
-    cy = DOOR_GFX_PAGEY1;
-
-    if (value != VIDEO_DISPLAY_LABEL_ONLY)
-      BlitBitmap(graphic_info[IMG_GLOBAL_DOOR].bitmap, drawto,
-                cx + VIDEO_FFWD_SYMBOL_XPOS,
-                cy + VIDEO_FFWD_SYMBOL_YPOS,
-                VIDEO_FFWD_SYMBOL_XSIZE,
-                VIDEO_FFWD_SYMBOL_YSIZE,
-                VX + VIDEO_SYMBOL_XPOS,
-                VY + VIDEO_SYMBOL_YPOS);
-#else
-    int cx = DOOR_GFX_PAGEX4, cy = DOOR_GFX_PAGEY2;
-
-    BlitBitmap(graphic_info[IMG_GLOBAL_DOOR].bitmap, drawto,
-              cx + VIDEO_PLAY_SYMBOL_XPOS,
-              cy + VIDEO_PLAY_SYMBOL_YPOS,
-              VIDEO_PLAY_SYMBOL_XSIZE - 2,
-              VIDEO_PLAY_SYMBOL_YSIZE,
-              VX + VIDEO_PLAY_SYMBOL_XPOS - 9,
-              VY + VIDEO_PLAY_SYMBOL_YPOS);
-#endif
-  }
-#endif
-
-#if 0
-  if (state & VIDEO_STATE_PBEND_ON)
-  {
-#if 1
-    int cx = DOOR_GFX_PAGEX6, cy = DOOR_GFX_PAGEY1;
-
-    if (value != VIDEO_DISPLAY_SYMBOL_ONLY)
-      BlitBitmap(graphic_info[IMG_GLOBAL_DOOR].bitmap, drawto,
-                cx + VIDEO_PBEND_LABEL_XPOS,
-                cy + VIDEO_PBEND_LABEL_YPOS,
-                VIDEO_LABEL_XSIZE,
-                VIDEO_LABEL_YSIZE,
-                VX + VIDEO_LABEL_XPOS,
-                VY + VIDEO_LABEL_YPOS);
-
-    cx = DOOR_GFX_PAGEX6;
-    cy = DOOR_GFX_PAGEY1;
-
-    if (value != VIDEO_DISPLAY_LABEL_ONLY)
-      BlitBitmap(graphic_info[IMG_GLOBAL_DOOR].bitmap, drawto,
-                cx + VIDEO_PBEND_SYMBOL_XPOS,
-                cy + VIDEO_PBEND_SYMBOL_YPOS,
-                VIDEO_PBEND_SYMBOL_XSIZE,
-                VIDEO_PBEND_SYMBOL_YSIZE,
-                VX + VIDEO_SYMBOL_XPOS,
-                VY + VIDEO_SYMBOL_YPOS);
-#else
-    int cx = DOOR_GFX_PAGEX6, cy = DOOR_GFX_PAGEY1;
-
-    BlitBitmap(graphic_info[IMG_GLOBAL_DOOR].bitmap, drawto,
-              cx + VIDEO_PBEND_LABEL_XPOS,
-              cy + VIDEO_PBEND_LABEL_YPOS,
-              VIDEO_PBEND_LABEL_XSIZE,
-              VIDEO_PBEND_LABEL_YSIZE,
-              VX + VIDEO_REC_LABEL_XPOS,
-              VY + VIDEO_REC_LABEL_YPOS);
-#endif
-  }
-#endif
-
-#if 0
-  if (state & VIDEO_STATE_1STEP_ON)
-  {
-    int cx = DOOR_GFX_PAGEX6, cy = DOOR_GFX_PAGEY1;
-
-    if (value != VIDEO_DISPLAY_LABEL_ONLY)
-      BlitBitmap(graphic_info[IMG_GLOBAL_DOOR].bitmap, drawto,
-                cx + VIDEO_1STEP_SYMBOL_XPOS,
-                cy + VIDEO_1STEP_SYMBOL_YPOS,
-                VIDEO_1STEP_SYMBOL_XSIZE,
-                VIDEO_1STEP_SYMBOL_YSIZE,
-                VX + VIDEO_1STEP_SYMBOL_XPOS,
-                VY + VIDEO_SYMBOL_YPOS);
-  }
-#endif
-
   if (state & VIDEO_STATE_DATE_ON)
   {
     int tag = value % 100;
@@ -597,16 +405,7 @@ void DrawVideoDisplay(unsigned long state, unsigned long value)
             int2str(sec, 2), FONT_TAPE_RECORDER);
   }
 
-#if 1
   redraw_mask |= REDRAW_DOOR_2;
-#else
-  if (state & VIDEO_STATE_DATE)
-    redraw_mask |= REDRAW_VIDEO_1;
-  if ((state & ~VIDEO_STATE_DATE) & VIDEO_STATE)
-    redraw_mask |= REDRAW_VIDEO_2;
-  if (state & VIDEO_PRESS)
-    redraw_mask |= REDRAW_VIDEO_3;
-#endif
 }
 
 void DrawCompleteVideoDisplay()
@@ -684,13 +483,11 @@ void TapeErase()
 
   TapeSetDate();
 
-#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;
+
+  tape.centered_player_nr_next = -1;
+  tape.set_centered_player = FALSE;
 }
 
 static void TapeRewind()
@@ -708,16 +505,25 @@ static void TapeRewind()
   tape.quick_resume = FALSE;
   tape.single_step = FALSE;
 
+  tape.centered_player_nr_next = -1;
+  tape.set_centered_player = FALSE;
+
   InitRND(tape.random_seed);
 }
 
-void TapeStartRecording()
+static void TapeSetRandomSeed(long random_seed)
+{
+  tape.random_seed = InitRND(random_seed);
+}
+
+void TapeStartRecording(long random_seed)
 {
   if (!TAPE_IS_STOPPED(tape))
     TapeStop();
 
   TapeErase();
   TapeRewind();
+  TapeSetRandomSeed(random_seed);
 
   tape.recording = TRUE;
 
@@ -732,7 +538,7 @@ void TapeStartRecording()
 
 static void TapeStartGameRecording()
 {
-  TapeStartRecording();
+  TapeStartRecording(NEW_RANDOMIZE);
 
 #if defined(NETWORK_AVALIABLE)
   if (options.network)
@@ -776,11 +582,6 @@ void TapeHaltRecording()
 
 void TapeStopRecording()
 {
-#if 0
-  if (!tape.recording)
-    return;
-#endif
-
   TapeHaltRecording();
 
   tape.recording = FALSE;
@@ -790,17 +591,13 @@ void TapeStopRecording()
   MapTapeEjectButton();
 }
 
-void TapeRecordAction(byte action[MAX_PLAYERS])
+void TapeRecordAction(byte action_raw[MAX_PLAYERS])
 {
+  byte action[MAX_PLAYERS];
   int i;
 
-#if 1
-  if (!tape.recording)         /* record action even when tape is paused! */
-    return;
-#else
-  if (!tape.recording || tape.pausing)
+  if (!tape.recording)         /* (record action even when tape is paused) */
     return;
-#endif
 
   if (tape.counter >= MAX_TAPE_LEN - 1)
   {
@@ -808,9 +605,18 @@ void TapeRecordAction(byte action[MAX_PLAYERS])
     return;
   }
 
-#if 0
-  printf("::: %05d: recording action: %d\n", FrameCounter, action[0]);
-#endif
+  for (i = 0; i < MAX_PLAYERS; i++)
+    action[i] = action_raw[i];
+
+  if (tape.set_centered_player)
+  {
+    for (i = 0; i < MAX_PLAYERS; i++)
+      if (tape.centered_player_nr_next == i ||
+         tape.centered_player_nr_next == -1)
+       action[i] |= KEY_SET_FOCUS;
+
+    tape.set_centered_player = FALSE;
+  }
 
   if (tape.pos[tape.counter].delay > 0)                /* already stored action */
   {
@@ -831,11 +637,6 @@ void TapeRecordAction(byte action[MAX_PLAYERS])
 
   if (tape.pos[tape.counter].delay == 0)       /* store new action */
   {
-
-#if 0
-    printf("::: %05d: new sequence\n", FrameCounter);
-#endif
-
     for (i = 0; i < MAX_PLAYERS; i++)
       tape.pos[tape.counter].action[i] = action[i];
 
@@ -847,11 +648,6 @@ void TapeTogglePause(boolean toggle_manual)
 {
   int state = 0;
 
-#if 0
-  if (!tape.recording && !tape.playing)
-    return;
-#endif
-
   if (tape.pause_before_death)
     state |= VIDEO_STATE_PBEND_OFF;
   else if (tape.fast_forward)
@@ -872,11 +668,6 @@ void TapeTogglePause(boolean toggle_manual)
 
   DrawVideoDisplay(state, 0);
 
-#if 0
-  if (tape.pausing)
-    DrawVideoDisplay(VIDEO_STATE_PAUSE_ON, 0);
-#endif
-
   if (tape.warp_forward)
   {
     TapeStopWarpForward();
@@ -886,9 +677,6 @@ void TapeTogglePause(boolean toggle_manual)
       tape.quick_resume = FALSE;
 
       TapeAppendRecording();
-#if 0
-      TapeTogglePause(toggle_manual);
-#endif
     }
   }
 }
@@ -925,11 +713,6 @@ static void TapeStartGamePlaying()
 
 void TapeStopPlaying()
 {
-#if 0
-  if (!tape.playing)
-    return;
-#endif
-
   tape.playing = FALSE;
   tape.pausing = FALSE;
 
@@ -1015,6 +798,21 @@ byte *TapePlayAction()
   for (i = 0; i < MAX_PLAYERS; i++)
     action[i] = tape.pos[tape.counter].action[i];
 
+  tape.set_centered_player = FALSE;
+  tape.centered_player_nr_next = -999;
+
+  for (i = 0; i < MAX_PLAYERS; i++)
+  {
+    if (action[i] & KEY_SET_FOCUS)
+    {
+      tape.set_centered_player = TRUE;
+      tape.centered_player_nr_next =
+       (tape.centered_player_nr_next == -999 ? i : -1);
+    }
+
+    action[i] &= ~KEY_SET_FOCUS;
+  }
+
   tape.delay_played++;
   if (tape.delay_played >= tape.pos[tape.counter].delay)
   {
@@ -1022,22 +820,11 @@ byte *TapePlayAction()
     tape.delay_played = 0;
   }
 
-#if 0
-  printf("::: %05d: replaying action: %d\n", FrameCounter, action[0]);
-#endif
-
   return action;
 }
 
 void TapeStop()
 {
-#if 0
-  if (tape.recording)
-    printf("::: stopped recording: %d\n", FrameCounter);
-  else if (tape.playing)
-    printf("::: stopped playing:   %d\n\n", FrameCounter);
-#endif
-
   TapeStopRecording();
   TapeStopPlaying();
 
@@ -1073,7 +860,6 @@ static void TapeStartWarpForward()
 {
   tape.warp_forward = TRUE;
 
-#if 1
   if (!tape.fast_forward && !tape.pause_before_death)
   {
     tape.pausing = FALSE;
@@ -1081,15 +867,6 @@ static void TapeStartWarpForward()
 
     TapeDeactivateDisplayOn();
   }
-#else
-  if (!tape.fast_forward || tape.pause_before_death)
-  {
-    tape.pausing = FALSE;
-    tape.deactivate_display = TRUE;
-
-    TapeDeactivateDisplayOn();
-  }
-#endif
 
   if (tape.fast_forward || tape.pause_before_death)
     DrawVideoDisplay(VIDEO_STATE_WARP_ON, VIDEO_DISPLAY_SYMBOL_ONLY);
@@ -1106,16 +883,6 @@ static void TapeStopWarpForward()
 
   TapeDeactivateDisplayOff(game_status == GAME_MODE_PLAYING);
 
-#if 0
-#if 1
-  if (game_status == GAME_MODE_PLAYING)
-#endif
-  {
-    RedrawPlayfield(TRUE, 0,0,0,0);
-    DrawGameDoorValues();
-  }
-#endif
-
   if (tape.pause_before_death)
     state |= VIDEO_STATE_WARP_OFF | VIDEO_STATE_PBEND_ON;
   else if (tape.fast_forward)
@@ -1297,12 +1064,15 @@ void AutoPlayTape()
       continue;
     }
 
+#if 0
+    /* ACTIVATE THIS FOR LOADING/TESTING OF LEVELS ONLY */
+    printf("(only testing level)\n");
+    continue;
+#endif
+
     LoadSolutionTape(level_nr);
-#if 1
+
     if (tape.no_valid_file)
-#else
-    if (TAPE_IS_EMPTY(tape))
-#endif
     {
       num_tape_missing++;
       if (level_nr >= 0 && level_nr < MAX_TAPES_PER_SET)
@@ -1531,15 +1301,6 @@ static void HandleTapeButtons(struct GadgetInfo *gi)
        else                                    /* WARP FORWARD PLAY -> PLAY */
        {
          TapeStopWarpForward();
-
-#if 0
-         if (tape.pause_before_death)
-           DrawVideoDisplay(VIDEO_STATE_WARP_OFF | VIDEO_STATE_PLAY_ON, 0);
-         else if (tape.fast_forward)
-           DrawVideoDisplay(VIDEO_STATE_WARP_OFF | VIDEO_STATE_FFWD_ON, 0);
-         else
-           DrawVideoDisplay(VIDEO_STATE_WARP_OFF | VIDEO_STATE_PBEND_ON, 0);
-#endif
        }
       }
       else if (tape.recording)
@@ -1588,28 +1349,17 @@ static void HandleTapeButtons(struct GadgetInfo *gi)
        else if (!tape.pause_before_death)      /* FFWD PLAY -> AUTO PAUSE */
        {
          tape.pause_before_death = TRUE;
-#if 1
          DrawVideoDisplay(VIDEO_STATE_FFWD_OFF | VIDEO_STATE_PBEND_ON, 0);
-#else
-         DrawVideoDisplay(VIDEO_STATE_PBEND_ON, VIDEO_DISPLAY_LABEL_ONLY);
-#endif
        }
        else                                    /* AUTO PAUSE -> NORMAL PLAY */
        {
-#if 1
          if (tape.warp_forward)
            TapeStopWarpForward();
-#else
-         tape.warp_forward = FALSE;
-#endif
+
          tape.fast_forward = FALSE;
          tape.pause_before_death = FALSE;
 
-#if 1
          DrawVideoDisplay(VIDEO_STATE_PBEND_OFF | VIDEO_STATE_PLAY_ON, 0);
-#else
-         DrawVideoDisplay(VIDEO_STATE_FFWD_OFF | VIDEO_STATE_PBEND_OFF, 0);
-#endif
        }
       }
       break;
index 4bddf23b6497305256d276882e0c380a7bbf587f..18107addd01b106324effba8e4f9ba552d8d8fb0 100644 (file)
 #ifndef TAPE_H
 #define TAPE_H
 
-#include "main.h"
-
 
 /* values for TapeTogglePause() */
 #define        TAPE_TOGGLE_MANUAL      TRUE
 #define        TAPE_TOGGLE_AUTOMATIC   FALSE
 
+/* values for tape properties */
+#define MAX_TAPE_LEN           (1000 * FRAMES_PER_SECOND) /* max.time x fps */
+
 /* some positions in the video tape control window */
 #define VIDEO_DISPLAY1_XPOS    5
 #define VIDEO_DISPLAY1_YPOS    5
 #define VIDEO_DISPLAY_SYMBOL_ONLY      -2
 
 
+struct TapeInfo
+{
+  int file_version;    /* file format version the tape is stored with    */
+  int game_version;    /* game release version the tape was created with */
+  int engine_version;  /* game engine version the tape was recorded with */
+
+  char *level_identifier;
+  int level_nr;
+  unsigned long random_seed;
+  unsigned long date;
+  unsigned long counter;
+  unsigned long length;
+  unsigned long length_seconds;
+  unsigned int delay_played;
+  boolean pause_before_death;
+  boolean recording, playing, pausing;
+  boolean fast_forward;
+  boolean warp_forward;
+  boolean deactivate_display;
+  boolean auto_play;
+  boolean auto_play_level_solved;
+  boolean quick_resume;
+  boolean single_step;
+  boolean changed;
+  boolean player_participates[MAX_PLAYERS];
+  int num_participating_players;
+  int centered_player_nr_next;
+  boolean set_centered_player;
+
+  struct
+  {
+    byte action[MAX_PLAYERS];
+    byte delay;
+  } pos[MAX_TAPE_LEN];
+
+  boolean no_valid_file;       /* set when tape file missing or invalid */
+};
+
+
 void DrawVideoDisplay(unsigned long, unsigned long);
 void DrawCompleteVideoDisplay(void);
 
 void TapeDeactivateDisplayOn();
 void TapeDeactivateDisplayOff(boolean);
 
-void TapeStartRecording(void);
+void TapeStartRecording(long);
 void TapeHaltRecording(void);
 void TapeStopRecording(void);
 void TapeRecordAction(byte *);
index eedf5d60284157f4aa9c79b60d0d49ff43cde1ad..3a2b962a3469435f1d8f00d6acf497f5be894d87 100644 (file)
 #include "network.h"
 #include "tape.h"
 
+
+/* select level set with EMC X11 graphics before activating EM GFX debugging */
+#define DEBUG_EM_GFX   0
+
 /* tool button identifiers */
 #define TOOL_CTRL_ID_YES       0
 #define TOOL_CTRL_ID_NO                1
@@ -63,6 +67,12 @@ void DumpTile(int x, int y)
   int sx = SCREENX(x);
   int sy = SCREENY(y);
 
+  if (level.game_engine_type == GAME_ENGINE_TYPE_EM)
+  {
+    x--;
+    y--;
+  }
+
   printf_line("-", 79);
   printf("Field Info: SCREEN(%d, %d), LEVEL(%d, %d)\n", sx, sy, x, y);
   printf_line("-", 79);
@@ -85,6 +95,7 @@ void DumpTile(int x, int y)
   printf("  MovDir:      %d\n", MovDir[x][y]);
   printf("  MovDelay:    %d\n", MovDelay[x][y]);
   printf("  ChangeDelay: %d\n", ChangeDelay[x][y]);
+  printf("  CustomValue: %d\n", CustomValue[x][y]);
   printf("  GfxElement:  %d\n", GfxElement[x][y]);
   printf("  GfxAction:   %d\n", GfxAction[x][y]);
   printf("  GfxFrame:    %d\n", GfxFrame[x][y]);
@@ -126,7 +137,9 @@ void RedrawPlayfield(boolean force_redraw, int x, int y, int width, int height)
   if (game_status == GAME_MODE_PLAYING &&
       level.game_engine_type == GAME_ENGINE_TYPE_EM)
   {
-    BlitScreenToBitmap_EM(backbuffer);
+    /* currently there is no partial redraw -- always redraw whole playfield */
+
+    RedrawPlayfield_EM(TRUE);
   }
   else if (game_status == GAME_MODE_PLAYING && !game.envelope_active)
   {
@@ -228,7 +241,8 @@ void BackToFront()
   if (redraw_mask & REDRAW_ALL)
   {
     BlitBitmap(backbuffer, window, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
-    redraw_mask = 0;
+
+    redraw_mask = REDRAW_NONE;
   }
 
   if (redraw_mask & REDRAW_FIELD)
@@ -256,8 +270,8 @@ void BackToFront()
       {
        BlitBitmap(buffer, window, fx, fy, SXSIZE, SYSIZE, SX, SY);
 
-#ifdef DEBUG
 #if 0
+#ifdef DEBUG
        printf("redrawing all (ScreenGfxPos == %d) because %s\n",
               ScreenGfxPos,
               (setup.soft_scrolling ?
@@ -281,32 +295,7 @@ void BackToFront()
       BlitBitmap(backbuffer, window, DX, DY, DXSIZE, DYSIZE, DX, DY);
 
     if (redraw_mask & REDRAW_DOOR_2)
-    {
-#if 0
-      if ((redraw_mask & REDRAW_DOOR_2) == REDRAW_DOOR_2)
-#endif
-       BlitBitmap(backbuffer, window, VX, VY, VXSIZE, VYSIZE, VX, VY);
-#if 0
-      else
-      {
-       if (redraw_mask & REDRAW_VIDEO_1)
-         BlitBitmap(backbuffer, window,
-                    VX + VIDEO_DISPLAY1_XPOS, VY + VIDEO_DISPLAY1_YPOS,
-                    VIDEO_DISPLAY_XSIZE, VIDEO_DISPLAY_YSIZE,
-                    VX + VIDEO_DISPLAY1_XPOS, VY + VIDEO_DISPLAY1_YPOS);
-       if (redraw_mask & REDRAW_VIDEO_2)
-         BlitBitmap(backbuffer, window,
-                    VX + VIDEO_DISPLAY2_XPOS, VY + VIDEO_DISPLAY2_YPOS,
-                    VIDEO_DISPLAY_XSIZE, VIDEO_DISPLAY_YSIZE,
-                    VX + VIDEO_DISPLAY2_XPOS, VY + VIDEO_DISPLAY2_YPOS);
-       if (redraw_mask & REDRAW_VIDEO_3)
-         BlitBitmap(backbuffer, window,
-                    VX + VIDEO_CONTROL_XPOS, VY + VIDEO_CONTROL_YPOS,
-                    VIDEO_CONTROL_XSIZE, VIDEO_CONTROL_YSIZE,
-                    VX + VIDEO_CONTROL_XPOS, VY + VIDEO_CONTROL_YPOS);
-      }
-#endif
-    }
+      BlitBitmap(backbuffer, window, VX, VY, VXSIZE, VYSIZE, VX, VY);
 
     if (redraw_mask & REDRAW_DOOR_3)
       BlitBitmap(backbuffer, window, EX, EY, EXSIZE, EYSIZE, EX, EY);
@@ -425,6 +414,56 @@ void FadeToFront()
   BackToFront();
 }
 
+void FadeIn(int fade_delay)
+{
+  if (fade_delay == 0)
+  {
+    BackToFront();
+
+    return;
+  }
+
+  FadeScreen(NULL, FADE_MODE_FADE_IN, fade_delay, 0);
+
+  redraw_mask = REDRAW_NONE;
+}
+
+void FadeOut(int fade_delay, int post_delay)
+{
+  if (fade_delay == 0)
+  {
+    ClearRectangle(backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE);
+    BackToFront();
+
+    return;
+  }
+
+  FadeScreen(NULL, FADE_MODE_FADE_OUT, fade_delay, post_delay);
+
+  redraw_mask = REDRAW_NONE;
+}
+
+void FadeCross(int fade_delay)
+{
+  if (fade_delay == 0)
+  {
+    BlitBitmap(bitmap_db_title, backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
+    BackToFront();
+
+    return;
+  }
+
+  FadeScreen(bitmap_db_title, FADE_MODE_CROSSFADE, fade_delay, 0);
+
+  redraw_mask = REDRAW_NONE;
+}
+
+void SetMainBackgroundImageIfDefined(int graphic)
+{
+  if (graphic_info[graphic].bitmap)
+    SetMainBackgroundImage(graphic);
+}
+
 void SetMainBackgroundImage(int graphic)
 {
   SetMainBackgroundBitmap(graphic == IMG_UNDEFINED ? NULL :
@@ -509,6 +548,17 @@ inline int getGraphicAnimationFrame(int graphic, int sync_frame)
   if (graphic_info[graphic].anim_global_sync || sync_frame < 0)
     sync_frame = FrameCounter;
 
+#if 0
+  if (graphic == element_info[EL_CUSTOM_START + 255].graphic[ACTION_DEFAULT] &&
+      sync_frame == 0 &&
+      FrameCounter > 10)
+  {
+    int x = 1 / 0;
+
+    printf("::: FOO!\n");
+  }
+#endif
+
   return getAnimationFrame(graphic_info[graphic].anim_frames,
                           graphic_info[graphic].anim_delay,
                           graphic_info[graphic].anim_mode,
@@ -528,28 +578,18 @@ inline void getGraphicSourceExt(int graphic, int frame, Bitmap **bitmap,
   if (g->offset_y == 0)                /* frames are ordered horizontally */
   {
     int max_width = g->anim_frames_per_line * g->width;
-#if 1
     int pos = (src_y / g->height) * max_width + src_x + frame * g->offset_x;
 
     *x = pos % max_width;
     *y = src_y % g->height + pos / max_width * g->height;
-#else
-    *x = (src_x + frame * g->offset_x) % max_width;
-    *y = src_y + (src_x + frame * g->offset_x) / max_width * g->height;
-#endif
   }
   else if (g->offset_x == 0)   /* frames are ordered vertically */
   {
     int max_height = g->anim_frames_per_line * g->height;
-#if 1
     int pos = (src_x / g->width) * max_height + src_y + frame * g->offset_y;
 
     *x = src_x % g->width + pos / max_height * g->width;
     *y = pos % max_height;
-#else
-    *x = src_x + (src_y + frame * g->offset_y) / max_height * g->width;
-    *y = (src_y + frame * g->offset_y) % max_height;
-#endif
   }
   else                         /* frames are ordered diagonally */
   {
@@ -765,11 +805,14 @@ inline static void DrawGraphicShiftedDouble(int x, int y, int dx, int dy,
   int y2 = y + SIGN(dy);
   int anim_frames = graphic_info[graphic].anim_frames;
   int sync_frame = (dx ? ABS(dx) : ABS(dy)) * anim_frames / TILESIZE;
+  boolean draw_start_tile = (cut_mode != CUT_ABOVE);   /* only for falling! */
+  boolean draw_end_tile   = (cut_mode != CUT_BELOW);   /* only for falling! */
 
   /* re-calculate animation frame for two-tile movement animation */
   frame = getGraphicAnimationFrame(graphic, sync_frame);
 
-  if (IN_SCR_FIELD(x1, y1))    /* movement start graphic inside screen area */
+  /* check if movement start graphic inside screen area and should be drawn */
+  if (draw_start_tile && IN_SCR_FIELD(x1, y1))
   {
     getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y, TRUE);
 
@@ -790,7 +833,8 @@ inline static void DrawGraphicShiftedDouble(int x, int y, int dx, int dy,
     MarkTileDirty(x1, y1);
   }
 
-  if (IN_SCR_FIELD(x2, y2))    /* movement end graphic inside screen area */
+  /* check if movement end graphic inside screen area and should be drawn */
+  if (draw_end_tile && IN_SCR_FIELD(x2, y2))
   {
     getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y, FALSE);
 
@@ -810,12 +854,6 @@ inline static void DrawGraphicShiftedDouble(int x, int y, int dx, int dy,
 
     MarkTileDirty(x2, y2);
   }
-
-#if 0
-  printf("::: DONE DrawGraphicShiftedDouble");
-  BackToFront();
-  Delay(1000);
-#endif
 }
 
 static void DrawGraphicShifted(int x, int y, int dx, int dy,
@@ -929,10 +967,6 @@ void DrawLevelFieldThruMask(int x, int y)
   DrawLevelElementExt(x, y, 0, 0, Feld[x][y], NO_CUTTING, USE_MASKING);
 }
 
-#define TILE_GFX_ELEMENT(x, y)                                             \
-       (GfxElement[x][y] != EL_UNDEFINED && Feld[x][y] != EL_EXPLOSION ?   \
-        GfxElement[x][y] : Feld[x][y])
-
 static void DrawLevelFieldCrumbledSandExt(int x, int y, int graphic, int frame)
 {
   Bitmap *src_bitmap;
@@ -940,11 +974,7 @@ static void DrawLevelFieldCrumbledSandExt(int x, int y, int graphic, int frame)
   int sx = SCREENX(x), sy = SCREENY(y);
   int element;
   int width, height, cx, cy, i;
-#if 1
   int crumbled_border_size = graphic_info[graphic].border_size;
-#else
-  int snip = TILEX / 8;        /* number of border pixels from "crumbled graphic" */
-#endif
   static int xy[4][2] =
   {
     { 0, -1 },
@@ -953,12 +983,6 @@ static void DrawLevelFieldCrumbledSandExt(int x, int y, int graphic, int frame)
     { 0, +1 }
   };
 
-#if 0
-  if (x == 0 && y == 7)
-    printf("::: %d, %d [%d]\n", GfxElement[x][y], Feld[x][y],
-          crumbled_border_size);
-#endif
-
   if (!IN_LEV_FIELD(x, y))
     return;
 
@@ -977,24 +1001,13 @@ static void DrawLevelFieldCrumbledSandExt(int x, int y, int graphic, int frame)
       int xx = x + xy[i][0];
       int yy = y + xy[i][1];
 
-#if 1
       element = (IN_LEV_FIELD(xx, yy) ? TILE_GFX_ELEMENT(xx, yy) :
                 BorderElement);
-#else
-      element = (IN_LEV_FIELD(xx, yy) ? Feld[xx][yy] : BorderElement);
-#endif
 
       /* check if neighbour field is of same type */
       if (GFX_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,
-              GFX_CRUMBLED(element), IS_MOVING(x, y));
-#endif
-
       if (i == 1 || i == 2)
       {
        width = crumbled_border_size;
@@ -1018,10 +1031,6 @@ static void DrawLevelFieldCrumbledSandExt(int x, int y, int graphic, int frame)
   }
   else         /* crumble neighbour fields */
   {
-#if 0
-    getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
-#endif
-
     for (i = 0; i < 4; i++)
     {
       int xx = x + xy[i][0];
@@ -1035,6 +1044,11 @@ static void DrawLevelFieldCrumbledSandExt(int x, int y, int graphic, int frame)
          IS_MOVING(xx, yy))
        continue;
 
+#if 1
+      if (Feld[xx][yy] == EL_ELEMENT_SNAPPING)
+       continue;
+#endif
+
       element = TILE_GFX_ELEMENT(xx, yy);
 
       if (!GFX_CRUMBLED(element))
@@ -1048,11 +1062,13 @@ static void DrawLevelFieldCrumbledSandExt(int x, int y, int graphic, int frame)
 #endif
 
 #if 1
+      graphic = el_act2crm(element, ACTION_DEFAULT);
+#else
       graphic = el_act2crm(Feld[xx][yy], ACTION_DEFAULT);
+#endif
       crumbled_border_size = graphic_info[graphic].border_size;
 
       getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
-#endif
 
       if (i == 1 || i == 2)
       {
@@ -1079,30 +1095,43 @@ static void DrawLevelFieldCrumbledSandExt(int x, int y, int graphic, int frame)
 
 void DrawLevelFieldCrumbledSand(int x, int y)
 {
-#if 1
   int graphic;
 
   if (!IN_LEV_FIELD(x, y))
     return;
 
-  graphic = el_act2crm(Feld[x][y], ACTION_DEFAULT);
+#if 1
+  /* !!! CHECK THIS !!! */
 
-  DrawLevelFieldCrumbledSandExt(x, y, graphic, 0);
+  /*
+  if (Feld[x][y] == EL_ELEMENT_SNAPPING &&
+      GFX_CRUMBLED(GfxElement[x][y]))
+  */
+
+  if (Feld[x][y] == EL_ELEMENT_SNAPPING &&
+      GfxElement[x][y] != EL_UNDEFINED &&
+      GFX_CRUMBLED(GfxElement[x][y]))
+  {
+    DrawLevelFieldCrumbledSandDigging(x, y, GfxDir[x][y], GfxFrame[x][y]);
+
+    return;
+  }
+#endif
+
+#if 1
+  graphic = el_act2crm(TILE_GFX_ELEMENT(x, y), ACTION_DEFAULT);
 #else
-  DrawLevelFieldCrumbledSandExt(x, y, IMG_SAND_CRUMBLED, 0);
+  graphic = el_act2crm(Feld[x][y], ACTION_DEFAULT);
 #endif
+
+  DrawLevelFieldCrumbledSandExt(x, y, graphic, 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);
@@ -1359,13 +1388,8 @@ void DrawEnvelopeBackground(int envelope_nr, int startx, int starty,
 void AnimateEnvelope(int envelope_nr, int anim_mode, int action)
 {
   int graphic = IMG_BACKGROUND_ENVELOPE_1 + envelope_nr;
-#if 1
   Bitmap *src_bitmap = graphic_info[graphic].bitmap;
   int mask_mode = (src_bitmap != NULL ? BLIT_MASKED : BLIT_ON_BACKGROUND);
-#else
-  boolean draw_masked = graphic_info[graphic].draw_masked;
-  int mask_mode = (draw_masked ? BLIT_MASKED : BLIT_ON_BACKGROUND);
-#endif
   boolean ffwd_delay = (tape.playing && tape.fast_forward);
   boolean no_delay = (tape.warp_forward);
   unsigned long anim_delay = 0;
@@ -1374,8 +1398,8 @@ void AnimateEnvelope(int envelope_nr, int anim_mode, int action)
   int font_nr = FONT_ENVELOPE_1 + envelope_nr;
   int font_width = getFontWidth(font_nr);
   int font_height = getFontHeight(font_nr);
-  int max_xsize = level.envelope_xsize[envelope_nr];
-  int max_ysize = level.envelope_ysize[envelope_nr];
+  int max_xsize = level.envelope[envelope_nr].xsize;
+  int max_ysize = level.envelope[envelope_nr].ysize;
   int xstart = (anim_mode & ANIM_VERTICAL ? max_xsize : 0);
   int ystart = (anim_mode & ANIM_HORIZONTAL ? max_ysize : 0);
   int xend = max_xsize;
@@ -1402,7 +1426,7 @@ void AnimateEnvelope(int envelope_nr, int anim_mode, int action)
       DrawEnvelopeBackground(envelope_nr, sx,sy, xx,yy, xsize, ysize, font_nr);
 
     DrawTextToTextArea(SX + sx + font_width, SY + sy + font_height,
-                      level.envelope_text[envelope_nr], font_nr, max_xsize,
+                      level.envelope[envelope_nr].text, font_nr, max_xsize,
                       xsize - 2, ysize - 2, mask_mode);
 
     redraw_mask |= REDRAW_FIELD | REDRAW_FROM_BACKBUFFER;
@@ -1428,7 +1452,7 @@ void ShowEnvelope(int envelope_nr)
 
   game.envelope_active = TRUE; /* needed for RedrawPlayfield() events */
 
-  PlaySoundStereo(sound_opening, SOUND_MIDDLE);
+  PlayMenuSoundStereo(sound_opening, SOUND_MIDDLE);
 
   if (anim_mode == ANIM_DEFAULT)
     AnimateEnvelope(envelope_nr, ANIM_DEFAULT, ACTION_OPENING);
@@ -1440,7 +1464,7 @@ void ShowEnvelope(int envelope_nr)
   else
     WaitForEventToContinue();
 
-  PlaySoundStereo(sound_closing, SOUND_MIDDLE);
+  PlayMenuSoundStereo(sound_closing, SOUND_MIDDLE);
 
   if (anim_mode != ANIM_NONE)
     AnimateEnvelope(envelope_nr, main_anim_mode, ACTION_CLOSING);
@@ -1561,8 +1585,6 @@ static void DrawMicroLevelLabelExt(int mode)
 
   max_len_label_text = SXSIZE / getFontWidth(font_nr);
 
-#if 1
-
   for (i = 0; i < max_len_label_text; i++)
     label_text[i] = ' ';
   label_text[max_len_label_text] = '\0';
@@ -1575,12 +1597,6 @@ static void DrawMicroLevelLabelExt(int mode)
     DrawText(lxpos, lypos, label_text, font_nr);
   }
 
-#else
-
-  DrawBackground(SX, MICROLABEL2_YPOS, SXSIZE, getFontHeight(font_nr));
-
-#endif
-
   strncpy(label_text,
          (mode == MICROLABEL_LEVEL_NAME ? level.name :
           mode == MICROLABEL_LEVEL_AUTHOR_HEAD ? "created by" :
@@ -1692,9 +1708,9 @@ void DrawMicroLevel(int xpos, int ypos, boolean restart)
 
   /* !!! THIS ALL SUCKS -- SHOULD BE CLEANLY REWRITTEN !!! */
   /* redraw micro level label, if needed */
-  if (strcmp(level.name, NAMELESS_LEVEL_NAME) != 0 &&
-      strcmp(level.author, ANONYMOUS_NAME) != 0 &&
-      strcmp(level.author, leveldir_current->name) != 0 &&
+  if (!strEqual(level.name, NAMELESS_LEVEL_NAME) &&
+      !strEqual(level.author, ANONYMOUS_NAME) &&
+      !strEqual(level.author, leveldir_current->name) &&
       DelayReached(&label_delay, MICROLEVEL_LABEL_DELAY))
   {
     int max_label_counter = 23;
@@ -1764,13 +1780,9 @@ void DrawLevelGraphicAnimation(int x, int y, int graphic)
 
 void DrawLevelElementAnimation(int x, int y, int element)
 {
-#if 1
   int graphic = el_act_dir2img(element, GfxAction[x][y], GfxDir[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)
@@ -1785,8 +1797,13 @@ inline void DrawLevelGraphicAnimationIfNeeded(int x, int y, int graphic)
 
   DrawGraphicAnimation(sx, sy, graphic);
 
+#if 1
+  if (GFX_CRUMBLED(TILE_GFX_ELEMENT(x, y)))
+    DrawLevelFieldCrumbledSand(x, y);
+#else
   if (GFX_CRUMBLED(Feld[x][y]))
     DrawLevelFieldCrumbledSand(x, y);
+#endif
 }
 
 void DrawLevelElementAnimationIfNeeded(int x, int y, int element)
@@ -1810,7 +1827,7 @@ void DrawLevelElementAnimationIfNeeded(int x, int y, int element)
 
 static int getPlayerGraphic(struct PlayerInfo *player, int move_dir)
 {
-  if (player->use_murphy_graphic)
+  if (player->use_murphy)
   {
     /* this works only because currently only one player can be "murphy" ... */
     static int last_horizontal_dir = MV_LEFT;
@@ -1829,7 +1846,7 @@ static int getPlayerGraphic(struct PlayerInfo *player, int move_dir)
     return graphic;
   }
   else
-    return el_act_dir2img(player->element_nr, player->GfxAction, move_dir);
+    return el_act_dir2img(player->artwork_element, player->GfxAction,move_dir);
 }
 
 static boolean equalGraphics(int graphic1, int graphic2)
@@ -1867,13 +1884,6 @@ void DrawPlayer(struct PlayerInfo *player)
   int jx = player->jx;
   int jy = player->jy;
   int move_dir = player->MovDir;
-#if 0
-  int last_jx = player->last_jx;
-  int last_jy = player->last_jy;
-  int next_jx = jx + (jx - last_jx);
-  int next_jy = jy + (jy - last_jy);
-  boolean player_is_moving = (last_jx != jx || last_jy != jy ? TRUE : FALSE);
-#else
   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);
@@ -1881,7 +1891,7 @@ void DrawPlayer(struct PlayerInfo *player)
   int next_jx = jx + dx;
   int next_jy = jy + dy;
   boolean player_is_moving = (player->MovPos ? TRUE : FALSE);
-#endif
+  boolean player_is_opaque = FALSE;
   int sx = SCREENX(jx), sy = SCREENY(jy);
   int sxx = 0, syy = 0;
   int element = Feld[jx][jy], last_element = Feld[last_jx][last_jy];
@@ -1891,6 +1901,13 @@ void DrawPlayer(struct PlayerInfo *player)
   int last_player_frame = player->Frame;
   int frame = 0;
 
+#if 1
+  /* GfxElement[][] is set to the element the player is digging or collecting;
+     remove also for off-screen player if the player is not moving anymore */
+  if (IN_LEV_FIELD(jx, jy) && !player_is_moving)
+    GfxElement[jx][jy] = EL_UNDEFINED;
+#endif
+
   if (!player->active || !IN_SCR_FIELD(SCREENX(last_jx), SCREENY(last_jy)))
     return;
 
@@ -1915,33 +1932,45 @@ void DrawPlayer(struct PlayerInfo *player)
            player->is_dropping   ? ACTION_DROPPING        :
            player->is_waiting    ? player->action_waiting : ACTION_DEFAULT);
 
+#if 1
+  if (player->is_waiting)
+    move_dir = player->dir_waiting;
+#endif
+
   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 (Back[last_jx][last_jy] && IS_DRAWABLE(last_element))
     {
       DrawLevelElement(last_jx, last_jy, Back[last_jx][last_jy]);
 
       if (last_element == EL_DYNAMITE_ACTIVE ||
+         last_element == EL_EM_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 ||
+            last_element == EL_EM_DYNAMITE_ACTIVE ||
             last_element == EL_SP_DISK_RED_ACTIVE)
       DrawDynamite(last_jx, last_jy);
+#if 0
+    /* !!! this is not enough to prevent flickering of players which are
+       moving next to each others without a free tile between them -- this
+       can only be solved by drawing all players layer by layer (first the
+       background, then the foreground etc.) !!! => TODO */
+    else if (!IS_PLAYER(last_jx, last_jy))
+      DrawLevelField(last_jx, last_jy);
+#else
     else
       DrawLevelField(last_jx, last_jy);
+#endif
 
     if (player->is_pushing && IN_SCR_FIELD(SCREENX(next_jx), SCREENY(next_jy)))
       DrawLevelElement(next_jx, next_jy, EL_EMPTY);
@@ -1965,21 +1994,26 @@ void DrawPlayer(struct PlayerInfo *player)
   {
     if (player_is_moving && GfxElement[jx][jy] != EL_UNDEFINED)
     {
-      if (GFX_CRUMBLED(GfxElement[jx][jy]))
+      int old_element = GfxElement[jx][jy];
+      int old_graphic = el_act_dir2img(old_element, action, move_dir);
+      int frame = getGraphicAnimationFrame(old_graphic, player->StepFrame);
+
+      if (GFX_CRUMBLED(old_element))
        DrawLevelFieldCrumbledSandDigging(jx, jy, move_dir, player->StepFrame);
       else
-      {
-       int old_element = GfxElement[jx][jy];
-       int old_graphic = el_act_dir2img(old_element, action, move_dir);
-       int frame = getGraphicAnimationFrame(old_graphic, player->StepFrame);
-
        DrawGraphic(sx, sy, old_graphic, frame);
-      }
+
+      if (graphic_info[old_graphic].anim_mode & ANIM_OPAQUE_PLAYER)
+       player_is_opaque = TRUE;
     }
     else
     {
       GfxElement[jx][jy] = EL_UNDEFINED;
 
+      /* make sure that pushed elements are drawn with correct frame rate */
+      if (player->is_pushing && player->is_moving)
+       GfxFrame[jx][jy] = player->StepFrame;
+
       DrawLevelField(jx, jy);
     }
   }
@@ -1988,8 +2022,6 @@ void DrawPlayer(struct PlayerInfo *player)
   /* draw player himself                                                     */
   /* ----------------------------------------------------------------------- */
 
-#if 1
-
   graphic = getPlayerGraphic(player, move_dir);
 
   /* in the case of changed player action or direction, prevent the current
@@ -1997,29 +2029,6 @@ void DrawPlayer(struct PlayerInfo *player)
   if (player->Frame == 0 && equalGraphics(graphic, last_player_graphic))
     player->Frame = last_player_frame;
 
-#else
-
-  if (player->use_murphy_graphic)
-  {
-    static int last_horizontal_dir = MV_LEFT;
-
-    if (move_dir == MV_LEFT || move_dir == MV_RIGHT)
-      last_horizontal_dir = move_dir;
-
-    graphic = el_act_dir2img(EL_SP_MURPHY, player->GfxAction, move_dir);
-
-    if (graphic == IMG_SP_MURPHY)      /* undefined => use special graphic */
-    {
-      int direction = (player->is_snapping ? 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);
-
-#endif
-
   frame = getGraphicAnimationFrame(graphic, player->Frame);
 
   if (player->GfxPos)
@@ -2033,7 +2042,10 @@ void DrawPlayer(struct PlayerInfo *player)
   if (!setup.soft_scrolling && ScreenMovPos)
     sxx = syy = 0;
 
-  DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
+  if (player_is_opaque)
+    DrawGraphicShifted(sx, sy, sxx, syy, graphic, frame,NO_CUTTING,NO_MASKING);
+  else
+    DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
 
   if (SHIELD_ON(player))
   {
@@ -2056,21 +2068,11 @@ void DrawPlayer(struct PlayerInfo *player)
 
 #if 1
   if (player->is_pushing && player->is_moving)
-#else
-  if (player->is_pushing && player_is_moving)
-#endif
   {
-#if 1
     int px = SCREENX(jx), py = SCREENY(jy);
     int pxx = (TILEX - ABS(sxx)) * dx;
     int pyy = (TILEY - ABS(syy)) * dy;
-#else
-    int px = SCREENX(next_jx), py = SCREENY(next_jy);
-    int pxx = sxx;
-    int pyy = syy;
-#endif
 
-#if 1
     int graphic;
     int frame;
 
@@ -2086,35 +2088,8 @@ void DrawPlayer(struct PlayerInfo *player)
 
     /* masked drawing is needed for EMC style (double) movement graphics */
     DrawGraphicShiftedThruMask(px, py, pxx, pyy, graphic, frame, NO_CUTTING);
-
-#else
-    if (Back[next_jx][next_jy])
-      DrawLevelElement(next_jx, next_jy, Back[next_jx][next_jy]);
-
-    if ((pxx || pyy) && element == EL_SOKOBAN_OBJECT)
-      DrawGraphicShiftedThruMask(px, py, pxx, pyy, IMG_SOKOBAN_OBJECT, 0,
-                                NO_CUTTING);
-    else
-    {
-      int element = MovingOrBlocked2Element(next_jx, next_jy);
-      int graphic = el_act_dir2img(element, ACTION_PUSHING, move_dir);
-#if 1
-      int frame = getGraphicAnimationFrame(graphic, player->StepFrame);
-#else
-      int frame = getGraphicAnimationFrame(graphic, player->Frame);
-#endif
-
-#if 1
-      /* masked drawing is needed for EMC style (double) movement graphics */
-      DrawGraphicShiftedThruMask(px, py, pxx, pyy, graphic, frame,
-                                NO_CUTTING);
-#else
-      DrawGraphicShifted(px, py, pxx, pyy, graphic, frame,
-                        NO_CUTTING, NO_MASKING);
-#endif
-    }
-#endif
   }
+#endif
 
   /* ----------------------------------------------------------------------- */
   /* draw things in front of player (active dynamite or dynabombs)           */
@@ -2133,7 +2108,9 @@ void DrawPlayer(struct PlayerInfo *player)
 
   if (player_is_moving && last_element == EL_EXPLOSION)
   {
-    int graphic = el_act2img(GfxElement[last_jx][last_jy], ACTION_EXPLODING);
+    int element = (GfxElement[last_jx][last_jy] != EL_UNDEFINED ?
+                  GfxElement[last_jx][last_jy] :  EL_EMPTY);
+    int graphic = el_act2img(element, ACTION_EXPLODING);
     int delay = (game.emulation == EMU_SUPAPLEX ? 3 : 2);
     int phase = ExplodePhase[last_jx][last_jy] - 1;
     int frame = getGraphicAnimationFrame(graphic, phase - delay);
@@ -2155,7 +2132,6 @@ void DrawPlayer(struct PlayerInfo *player)
       DrawLevelFieldThruMask(last_jx, last_jy);
   }
 
-#if 1
   /* do not redraw accessible elements if the player is just pushing them */
   if (!player_is_moving || !player->is_pushing)
   {
@@ -2166,22 +2142,6 @@ void DrawPlayer(struct PlayerInfo *player)
       DrawLevelFieldThruMask(jx, jy);
   }
 
-#else
-
-#if 0
-  /* !!! I have forgotton what this should be good for !!! */
-  /* !!! causes player being visible when pushing from within tubes !!! */
-  if (!player->is_pushing)
-#endif
-  {
-    /* ... and the field the player is entering */
-    if (IS_ACCESSIBLE_INSIDE(element))
-      DrawLevelField(jx, jy);
-    else if (IS_ACCESSIBLE_UNDER(element))
-      DrawLevelFieldThruMask(jx, jy);
-  }
-#endif
-
   if (setup.direct_draw)
   {
     int dst_x = SX + SCREENX(MIN(jx, last_jx)) * TILEX;
@@ -2272,21 +2232,15 @@ boolean Request(char *text, unsigned int req_state)
     }
   }
 
-#if 1
   if (game_status == GAME_MODE_PLAYING &&
       level.game_engine_type == GAME_ENGINE_TYPE_EM)
     BlitScreenToBitmap_EM(backbuffer);
-#endif
 
-#if 1
   /* disable deactivated drawing when quick-loading level tape recording */
   if (tape.playing && tape.deactivate_display)
     TapeDeactivateDisplayOff(TRUE);
-#endif
 
-#if 1
   SetMouseCursor(CURSOR_DEFAULT);
-#endif
 
 #if defined(NETWORK_AVALIABLE)
   /* pause network game while waiting for request to answer */
@@ -2381,10 +2335,6 @@ boolean Request(char *text, unsigned int req_state)
 
   OpenDoor(DOOR_OPEN_1);
 
-#if 0
-  ClearEventQueue();
-#endif
-
   if (!(req_state & REQUEST_WAIT_FOR_INPUT))
   {
     SetDrawBackgroundMask(REDRAW_FIELD);
@@ -2401,10 +2351,6 @@ boolean Request(char *text, unsigned int req_state)
 
   SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
 
-#if 0
-  SetMouseCursor(CURSOR_DEFAULT);
-#endif
-
   while (result < 0)
   {
     if (PendingEvent())
@@ -2546,11 +2492,9 @@ boolean Request(char *text, unsigned int req_state)
     SendToServer_ContinuePlaying();
 #endif
 
-#if 1
   /* restore deactivated drawing when quick-loading level tape recording */
   if (tape.playing && tape.deactivate_display)
     TapeDeactivateDisplayOn();
-#endif
 
   return result;
 }
@@ -2613,8 +2557,17 @@ unsigned int MoveDoor(unsigned int door_state)
   unsigned long door_delay_value;
   int stepsize = 1;
 
+  if (door_1.width < 0 || door_1.width > DXSIZE)
+    door_1.width = DXSIZE;
+  if (door_1.height < 0 || door_1.height > DYSIZE)
+    door_1.height = DYSIZE;
+  if (door_2.width < 0 || door_2.width > VXSIZE)
+    door_2.width = VXSIZE;
+  if (door_2.height < 0 || door_2.height > VYSIZE)
+    door_2.height = VYSIZE;
+
   if (door_state == DOOR_GET_STATE)
-    return(door1 | door2);
+    return (door1 | door2);
 
   if (door_state & DOOR_SET_STATE)
   {
@@ -2623,17 +2576,20 @@ unsigned int MoveDoor(unsigned int door_state)
     if (door_state & DOOR_ACTION_2)
       door2 = door_state & DOOR_ACTION_2;
 
-    return(door1 | door2);
+    return (door1 | door2);
   }
 
-  if (door1 == DOOR_OPEN_1 && door_state & DOOR_OPEN_1)
-    door_state &= ~DOOR_OPEN_1;
-  else if (door1 == DOOR_CLOSE_1 && door_state & DOOR_CLOSE_1)
-    door_state &= ~DOOR_CLOSE_1;
-  if (door2 == DOOR_OPEN_2 && door_state & DOOR_OPEN_2)
-    door_state &= ~DOOR_OPEN_2;
-  else if (door2 == DOOR_CLOSE_2 && door_state & DOOR_CLOSE_2)
-    door_state &= ~DOOR_CLOSE_2;
+  if (!(door_state & DOOR_FORCE_REDRAW))
+  {
+    if (door1 == DOOR_OPEN_1 && door_state & DOOR_OPEN_1)
+      door_state &= ~DOOR_OPEN_1;
+    else if (door1 == DOOR_CLOSE_1 && door_state & DOOR_CLOSE_1)
+      door_state &= ~DOOR_CLOSE_1;
+    if (door2 == DOOR_OPEN_2 && door_state & DOOR_OPEN_2)
+      door_state &= ~DOOR_OPEN_2;
+    else if (door2 == DOOR_CLOSE_2 && door_state & DOOR_CLOSE_2)
+      door_state &= ~DOOR_CLOSE_2;
+  }
 
   door_delay_value = (door_state & DOOR_ACTION_1 ? door_1.step_delay :
                      door_2.step_delay);
@@ -2642,11 +2598,6 @@ unsigned int MoveDoor(unsigned int door_state)
   {
     stepsize = 20;             /* must be choosen to always draw last frame */
     door_delay_value = 0;
-
-#if 0
-    StopSound(SND_DOOR_OPENING);
-    StopSound(SND_DOOR_CLOSING);
-#endif
   }
 
   if (global.autoplay_leveldir)
@@ -2657,42 +2608,69 @@ unsigned int MoveDoor(unsigned int door_state)
 
   if (door_state & DOOR_ACTION)
   {
-    boolean door_1_done = !(door_state & DOOR_ACTION_1);
-    boolean door_2_done = !(door_state & DOOR_ACTION_2);
-    int start = ((door_state & DOOR_NO_DELAY) ? DXSIZE : 0);
-    int end = (door_state & DOOR_ACTION_1 &&
-              door_1.anim_mode == ANIM_VERTICAL ? DYSIZE : DXSIZE);
-    int x;
+    boolean handle_door_1 = (door_state & DOOR_ACTION_1);
+    boolean handle_door_2 = (door_state & DOOR_ACTION_2);
+    boolean door_1_done = (!handle_door_1);
+    boolean door_2_done = (!handle_door_2);
+    boolean door_1_vertical = (door_1.anim_mode & ANIM_VERTICAL);
+    boolean door_2_vertical = (door_2.anim_mode & ANIM_VERTICAL);
+    int door_size_1 = (door_1_vertical ? door_1.height : door_1.width);
+    int door_size_2 = (door_2_vertical ? door_2.height : door_2.width);
+    int max_door_size_1 = (door_1_vertical ? DYSIZE : DXSIZE);
+    int max_door_size_2 = (door_2_vertical ? VYSIZE : VXSIZE);
+    int door_size     = (handle_door_1 ? door_size_1     : door_size_2);
+    int max_door_size = (handle_door_1 ? max_door_size_1 : max_door_size_2);
+    int door_skip = max_door_size - door_size;
+#if 1
+    int end = door_size;
+#else
+    int end = (door_state & DOOR_ACTION_1 && door_1.anim_mode & ANIM_VERTICAL ?
+              DYSIZE : DXSIZE);
+#endif
+#if 1
+    int start = ((door_state & DOOR_NO_DELAY) ? end : 0);
+#else
+    int start = ((door_state & DOOR_NO_DELAY) ? end : offset_skip);
+#endif
+    int k;
 
     if (!(door_state & DOOR_NO_DELAY) && !setup.quick_doors)
     {
       /* opening door sound has priority over simultaneously closing door */
       if (door_state & (DOOR_OPEN_1 | DOOR_OPEN_2))
-       PlaySoundStereo(SND_DOOR_OPENING, SOUND_MIDDLE);
+       PlayMenuSoundStereo(SND_DOOR_OPENING, SOUND_MIDDLE);
       else if (door_state & (DOOR_CLOSE_1 | DOOR_CLOSE_2))
-       PlaySoundStereo(SND_DOOR_CLOSING, SOUND_MIDDLE);
+       PlayMenuSoundStereo(SND_DOOR_CLOSING, SOUND_MIDDLE);
     }
 
-    for (x = start; x <= end && !(door_1_done && door_2_done); x += stepsize)
+    for (k = start; k <= end && !(door_1_done && door_2_done); k += stepsize)
     {
+      int x = k;
       Bitmap *bitmap = graphic_info[IMG_GLOBAL_DOOR].bitmap;
       GC gc = bitmap->stored_clip_gc;
 
       if (door_state & DOOR_ACTION_1)
       {
        int a = MIN(x * door_1.step_offset, end);
-       int i = (door_state & DOOR_OPEN_1 ? end - a : a);
+       int p = (door_state & DOOR_OPEN_1 ? end - a : a);
+       int i = p + door_skip;
 
-       if (x <= a)
+       if (door_1.anim_mode & ANIM_STATIC_PANEL)
        {
          BlitBitmap(bitmap_db_door, drawto,
-                    DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1 + i / 2,
-                    DXSIZE, DYSIZE - i / 2, DX, DY);
+                    DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1,
+                    DXSIZE, DYSIZE, DX, DY);
+       }
+       else if (x <= a)
+       {
+         BlitBitmap(bitmap_db_door, drawto,
+                    DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1 + p / 2,
+                    DXSIZE, DYSIZE - p / 2, DX, DY);
 
-         ClearRectangle(drawto, DX, DY + DYSIZE - i / 2, DXSIZE, i / 2);
+         ClearRectangle(drawto, DX, DY + DYSIZE - p / 2, DXSIZE, p / 2);
        }
 
-       if (door_1.anim_mode == ANIM_HORIZONTAL && x <= DXSIZE)
+       if (door_1.anim_mode & ANIM_HORIZONTAL && x <= DXSIZE)
        {
          int src1_x = DXSIZE,          src1_y = DOOR_GFX_PAGEY1;
          int dst1_x = DX + DXSIZE - i, dst1_y = DY;
@@ -2708,7 +2686,7 @@ unsigned int MoveDoor(unsigned int door_state)
          BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height,
                           dst2_x, dst2_y);
        }
-       else if (door_1.anim_mode == ANIM_VERTICAL && x <= DYSIZE)
+       else if (door_1.anim_mode & ANIM_VERTICAL && x <= DYSIZE)
        {
          int src1_x = DXSIZE,          src1_y = DOOR_GFX_PAGEY1;
          int dst1_x = DX,              dst1_y = DY + DYSIZE - i;
@@ -2765,19 +2743,32 @@ unsigned int MoveDoor(unsigned int door_state)
 
       if (door_state & DOOR_ACTION_2)
       {
-       int a = MIN(x * door_2.step_offset, VXSIZE);
-       int i = (door_state & DOOR_OPEN_2 ? VXSIZE - a : a);
+#if 1
+       int a = MIN(x * door_2.step_offset, door_size);
+       int p = (door_state & DOOR_OPEN_2 ? door_size - a : a);
+       int i = p + door_skip;
+#else
+       int a = MIN(x * door_2.step_offset, door_size_2);
+       int p = (door_state & DOOR_OPEN_2 ? door_size_2 - a : a);
+       int i = p + door_skip;
+#endif
 
-       if (x <= VYSIZE)
+       if (door_2.anim_mode & ANIM_STATIC_PANEL)
+       {
+         BlitBitmap(bitmap_db_door, drawto,
+                    DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2,
+                    VXSIZE, VYSIZE, VX, VY);
+       }
+       else if (x <= VYSIZE)
        {
          BlitBitmap(bitmap_db_door, drawto,
-                    DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2 + i / 2,
-                    VXSIZE, VYSIZE - i / 2, VX, VY);
+                    DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2 + p / 2,
+                    VXSIZE, VYSIZE - p / 2, VX, VY);
 
-         ClearRectangle(drawto, VX, VY + VYSIZE - i / 2, VXSIZE, i / 2);
+         ClearRectangle(drawto, VX, VY + VYSIZE - p / 2, VXSIZE, p / 2);
        }
 
-       if (door_2.anim_mode == ANIM_HORIZONTAL && x <= VXSIZE)
+       if (door_2.anim_mode & ANIM_HORIZONTAL && x <= VXSIZE)
        {
          int src1_x = VXSIZE,          src1_y = DOOR_GFX_PAGEY2;
          int dst1_x = VX + VXSIZE - i, dst1_y = VY;
@@ -2793,7 +2784,7 @@ unsigned int MoveDoor(unsigned int door_state)
          BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height,
                           dst2_x, dst2_y);
        }
-       else if (door_2.anim_mode == ANIM_VERTICAL && x <= VYSIZE)
+       else if (door_2.anim_mode & ANIM_VERTICAL && x <= VYSIZE)
        {
          int src1_x = VXSIZE,          src1_y = DOOR_GFX_PAGEY2;
          int dst1_x = VX,              dst1_y = VY + VYSIZE - i;
@@ -2837,24 +2828,18 @@ unsigned int MoveDoor(unsigned int door_state)
        door_2_done = (a == VXSIZE);
       }
 
-      BackToFront();
+      if (!(door_state & DOOR_NO_DELAY))
+      {
+       BackToFront();
 
-      if (game_status == GAME_MODE_MAIN)
-       DoAnimation();
+       if (game_status == GAME_MODE_MAIN)
+         DoAnimation();
 
-      if (!(door_state & DOOR_NO_DELAY))
        WaitUntilDelayReached(&door_delay, door_delay_value);
+      }
     }
   }
 
-#if 0
-  if (setup.quick_doors)
-  {
-    StopSound(SND_DOOR_OPENING);
-    StopSound(SND_DOOR_CLOSING);
-  }
-#endif
-
   if (door_state & DOOR_ACTION_1)
     door1 = door_state & DOOR_ACTION_1;
   if (door_state & DOOR_ACTION_2)
@@ -2870,8 +2855,8 @@ void DrawSpecialEditorDoor()
             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);
+            EX - 6, VY - 4, EXSIZE + 12, EYSIZE - VYSIZE + 4,
+            EX - 6, EY - 4);
 
   redraw_mask |= REDRAW_ALL;
 }
@@ -2880,8 +2865,8 @@ void UndrawSpecialEditorDoor()
 {
   /* draw normal tape recorder window */
   BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto,
-            EX - 4, EY - 12, EXSIZE + 8, EYSIZE - VYSIZE + 12,
-            EX - 4, EY - 12);
+            EX - 6, EY - 12, EXSIZE + 12, EYSIZE - VYSIZE + 12,
+            EX - 6, EY - 12);
 
   redraw_mask |= REDRAW_ALL;
 }
@@ -3067,8 +3052,6 @@ static void HandleToolButtons(struct GadgetInfo *gi)
   request_gadget_id = gi->custom_id;
 }
 
-#if 1
-
 static struct Mapping_EM_to_RND_object
 {
   int element_em;
@@ -3471,11 +3454,11 @@ em_object_mapping_list[] =
   },
   {
     Yandroid_ne,                       FALSE,  FALSE,
-    EL_EMC_ANDROID,                    ACTION_TURNING_FROM_UP, MV_BIT_RIGHT
+    EL_EMC_ANDROID,                    ACTION_GROWING, MV_BIT_UPRIGHT
   },
   {
     Yandroid_neB,                      FALSE,  TRUE,
-    EL_EMC_ANDROID,                    ACTION_TURNING_FROM_UP, MV_BIT_RIGHT
+    EL_EMC_ANDROID,                    ACTION_SHRINKING, MV_BIT_UPRIGHT
   },
   {
     Yandroid_e,                                FALSE,  FALSE,
@@ -3487,11 +3470,11 @@ em_object_mapping_list[] =
   },
   {
     Yandroid_se,                       FALSE,  FALSE,
-    EL_EMC_ANDROID,                    ACTION_TURNING_FROM_DOWN, MV_BIT_RIGHT
+    EL_EMC_ANDROID,                    ACTION_GROWING, MV_BIT_DOWNRIGHT
   },
   {
     Yandroid_seB,                      FALSE,  TRUE,
-    EL_EMC_ANDROID,                    ACTION_TURNING_FROM_DOWN, MV_BIT_RIGHT
+    EL_EMC_ANDROID,                    ACTION_SHRINKING, MV_BIT_DOWNRIGHT
   },
   {
     Yandroid_s,                                FALSE,  FALSE,
@@ -3503,11 +3486,11 @@ em_object_mapping_list[] =
   },
   {
     Yandroid_sw,                       FALSE,  FALSE,
-    EL_EMC_ANDROID,                    ACTION_TURNING_FROM_DOWN, MV_BIT_LEFT
+    EL_EMC_ANDROID,                    ACTION_GROWING, MV_BIT_DOWNLEFT
   },
   {
     Yandroid_swB,                      FALSE,  TRUE,
-    EL_EMC_ANDROID,                    ACTION_TURNING_FROM_DOWN, MV_BIT_LEFT
+    EL_EMC_ANDROID,                    ACTION_SHRINKING, MV_BIT_DOWNLEFT
   },
   {
     Yandroid_w,                                FALSE,  FALSE,
@@ -3519,11 +3502,11 @@ em_object_mapping_list[] =
   },
   {
     Yandroid_nw,                       FALSE,  FALSE,
-    EL_EMC_ANDROID,                    ACTION_TURNING_FROM_UP, MV_BIT_LEFT
+    EL_EMC_ANDROID,                    ACTION_GROWING, MV_BIT_UPLEFT
   },
   {
     Yandroid_nwB,                      FALSE,  TRUE,
-    EL_EMC_ANDROID,                    ACTION_TURNING_FROM_UP, MV_BIT_LEFT
+    EL_EMC_ANDROID,                    ACTION_SHRINKING, MV_BIT_UPLEFT
   },
   {
     Xspring,                           TRUE,   FALSE,
@@ -3571,35 +3554,35 @@ em_object_mapping_list[] =
   },
   {
     Yspring_kill_e,                    FALSE,  FALSE,
-    EL_ROBOT,                          ACTION_SLURPED_BY_SPRING, MV_BIT_RIGHT
+    EL_SPRING,                         ACTION_EATING, MV_BIT_RIGHT
   },
   {
     Yspring_kill_eB,                   FALSE,  TRUE,
-    EL_ROBOT,                          ACTION_SLURPED_BY_SPRING, MV_BIT_RIGHT
+    EL_SPRING,                         ACTION_EATING, MV_BIT_RIGHT
   },
   {
     Yspring_kill_w,                    FALSE,  FALSE,
-    EL_ROBOT,                          ACTION_SLURPED_BY_SPRING, MV_BIT_LEFT
+    EL_SPRING,                         ACTION_EATING, MV_BIT_LEFT
   },
   {
     Yspring_kill_wB,                   FALSE,  TRUE,
-    EL_ROBOT,                          ACTION_SLURPED_BY_SPRING, MV_BIT_LEFT
+    EL_SPRING,                         ACTION_EATING, MV_BIT_LEFT
   },
   {
     Xeater_n,                          TRUE,   FALSE,
-    EL_YAMYAM,                         -1, -1
+    EL_YAMYAM_UP,                      -1, -1
   },
   {
-    Xeater_e,                          FALSE,  FALSE,
-    EL_YAMYAM,                         -1, -1
+    Xeater_e,                          TRUE,   FALSE,
+    EL_YAMYAM_RIGHT,                   -1, -1
   },
   {
-    Xeater_w,                          FALSE,  FALSE,
-    EL_YAMYAM,                         -1, -1
+    Xeater_w,                          TRUE,   FALSE,
+    EL_YAMYAM_LEFT,                    -1, -1
   },
   {
-    Xeater_s,                          FALSE,  FALSE,
-    EL_YAMYAM,                         -1, -1
+    Xeater_s,                          TRUE,   FALSE,
+    EL_YAMYAM_DOWN,                    -1, -1
   },
   {
     Yeater_n,                          FALSE,  FALSE,
@@ -4215,27 +4198,27 @@ em_object_mapping_list[] =
   },
   {
     Xdynamite,                         TRUE,   FALSE,
-    EL_DYNAMITE,                       -1, -1
+    EL_EM_DYNAMITE,                    -1, -1
   },
   {
     Ydynamite_eat,                     FALSE,  FALSE,
-    EL_DYNAMITE,                       ACTION_COLLECTING, -1
+    EL_EM_DYNAMITE,                    ACTION_COLLECTING, -1
   },
   {
     Xdynamite_1,                       TRUE,   FALSE,
-    EL_DYNAMITE_ACTIVE,                        -1, -1
+    EL_EM_DYNAMITE_ACTIVE,             -1, -1
   },
   {
     Xdynamite_2,                       FALSE,  FALSE,
-    EL_DYNAMITE_ACTIVE,                        -1, -1
+    EL_EM_DYNAMITE_ACTIVE,             -1, -1
   },
   {
     Xdynamite_3,                       FALSE,  FALSE,
-    EL_DYNAMITE_ACTIVE,                        -1, -1
+    EL_EM_DYNAMITE_ACTIVE,             -1, -1
   },
   {
     Xdynamite_4,                       FALSE,  FALSE,
-    EL_DYNAMITE_ACTIVE,                        -1, -1
+    EL_EM_DYNAMITE_ACTIVE,             -1, -1
   },
   {
     Xbumper,                           TRUE,   FALSE,
@@ -4270,19 +4253,19 @@ em_object_mapping_list[] =
     EL_QUICKSAND_FULL,                 -1, -1
   },
   {
-    Xsand_stonein_1,                   FALSE,  FALSE,
+    Xsand_stonein_1,                   FALSE,  TRUE,
     EL_ROCK,                           ACTION_FILLING, -1
   },
   {
-    Xsand_stonein_2,                   FALSE,  FALSE,
+    Xsand_stonein_2,                   FALSE,  TRUE,
     EL_ROCK,                           ACTION_FILLING, -1
   },
   {
-    Xsand_stonein_3,                   FALSE,  FALSE,
+    Xsand_stonein_3,                   FALSE,  TRUE,
     EL_ROCK,                           ACTION_FILLING, -1
   },
   {
-    Xsand_stonein_4,                   FALSE,  FALSE,
+    Xsand_stonein_4,                   FALSE,  TRUE,
     EL_ROCK,                           ACTION_FILLING, -1
   },
   {
@@ -4709,10 +4692,6 @@ em_object_mapping_list[] =
     Xalpha_copyr,                      TRUE,   FALSE,
     EL_CHAR('©'),                      -1, -1
   },
-  {
-    Xalpha_copyr,                      TRUE,   FALSE,
-    EL_CHAR('©'),                      -1, -1
-  },
 
   {
     Xboom_bug,                         FALSE,  FALSE,
@@ -4872,6 +4851,110 @@ em_player_mapping_list[] =
     SPR_still,                         1,
     EL_PLAYER_2,                       ACTION_DEFAULT, -1,
   },
+  {
+    SPR_walk + 0,                      2,
+    EL_PLAYER_3,                       ACTION_MOVING, MV_BIT_UP,
+  },
+  {
+    SPR_walk + 1,                      2,
+    EL_PLAYER_3,                       ACTION_MOVING, MV_BIT_RIGHT,
+  },
+  {
+    SPR_walk + 2,                      2,
+    EL_PLAYER_3,                       ACTION_MOVING, MV_BIT_DOWN,
+  },
+  {
+    SPR_walk + 3,                      2,
+    EL_PLAYER_3,                       ACTION_MOVING, MV_BIT_LEFT,
+  },
+  {
+    SPR_push + 0,                      2,
+    EL_PLAYER_3,                       ACTION_PUSHING, MV_BIT_UP,
+  },
+  {
+    SPR_push + 1,                      2,
+    EL_PLAYER_3,                       ACTION_PUSHING, MV_BIT_RIGHT,
+  },
+  {
+    SPR_push + 2,                      2,
+    EL_PLAYER_3,                       ACTION_PUSHING, MV_BIT_DOWN,
+  },
+  {
+    SPR_push + 3,                      2,
+    EL_PLAYER_3,                       ACTION_PUSHING, MV_BIT_LEFT,
+  },
+  {
+    SPR_spray + 0,                     2,
+    EL_PLAYER_3,                       ACTION_SNAPPING, MV_BIT_UP,
+  },
+  {
+    SPR_spray + 1,                     2,
+    EL_PLAYER_3,                       ACTION_SNAPPING, MV_BIT_RIGHT,
+  },
+  {
+    SPR_spray + 2,                     2,
+    EL_PLAYER_3,                       ACTION_SNAPPING, MV_BIT_DOWN,
+  },
+  {
+    SPR_spray + 3,                     2,
+    EL_PLAYER_3,                       ACTION_SNAPPING, MV_BIT_LEFT,
+  },
+  {
+    SPR_walk + 0,                      3,
+    EL_PLAYER_4,                       ACTION_MOVING, MV_BIT_UP,
+  },
+  {
+    SPR_walk + 1,                      3,
+    EL_PLAYER_4,                       ACTION_MOVING, MV_BIT_RIGHT,
+  },
+  {
+    SPR_walk + 2,                      3,
+    EL_PLAYER_4,                       ACTION_MOVING, MV_BIT_DOWN,
+  },
+  {
+    SPR_walk + 3,                      3,
+    EL_PLAYER_4,                       ACTION_MOVING, MV_BIT_LEFT,
+  },
+  {
+    SPR_push + 0,                      3,
+    EL_PLAYER_4,                       ACTION_PUSHING, MV_BIT_UP,
+  },
+  {
+    SPR_push + 1,                      3,
+    EL_PLAYER_4,                       ACTION_PUSHING, MV_BIT_RIGHT,
+  },
+  {
+    SPR_push + 2,                      3,
+    EL_PLAYER_4,                       ACTION_PUSHING, MV_BIT_DOWN,
+  },
+  {
+    SPR_push + 3,                      3,
+    EL_PLAYER_4,                       ACTION_PUSHING, MV_BIT_LEFT,
+  },
+  {
+    SPR_spray + 0,                     3,
+    EL_PLAYER_4,                       ACTION_SNAPPING, MV_BIT_UP,
+  },
+  {
+    SPR_spray + 1,                     3,
+    EL_PLAYER_4,                       ACTION_SNAPPING, MV_BIT_RIGHT,
+  },
+  {
+    SPR_spray + 2,                     3,
+    EL_PLAYER_4,                       ACTION_SNAPPING, MV_BIT_DOWN,
+  },
+  {
+    SPR_spray + 3,                     3,
+    EL_PLAYER_4,                       ACTION_SNAPPING, MV_BIT_LEFT,
+  },
+  {
+    SPR_still,                         2,
+    EL_PLAYER_3,                       ACTION_DEFAULT, -1,
+  },
+  {
+    SPR_still,                         3,
+    EL_PLAYER_4,                       ACTION_DEFAULT, -1,
+  },
 
   {
     -1,                                        -1,
@@ -4936,639 +5019,83 @@ int map_element_EM_to_RND(int element_em)
   return EL_UNKNOWN;
 }
 
-#else
-
-int map_element_RND_to_EM(int element_rnd)
+void map_android_clone_elements_RND_to_EM(struct LevelInfo *level)
 {
-  static unsigned short mapping_RND_to_EM[NUM_FILE_ELEMENTS];
-  static boolean mapping_initialized = FALSE;
+  struct LevelInfo_EM *level_em = level->native_em_level;
+  struct LEVEL *lev = level_em->lev;
+  int i, j;
 
-  struct
-  {
-    int element_em;
-    int element_rnd;
-  }
-  mapping_RND_to_EM_list[] =
-  {
-    { Xblank,                  EL_EMPTY                        },
-    { Xstone,                  EL_ROCK                         },
-    { Xnut,                    EL_NUT                          },
-    { Xbug_n,                  EL_BUG_UP                       },
-    { Xbug_e,                  EL_BUG_RIGHT                    },
-    { Xbug_s,                  EL_BUG_DOWN                     },
-    { Xbug_w,                  EL_BUG_LEFT                     },
-    { Xtank_n,                 EL_SPACESHIP_UP                 },
-    { Xtank_e,                 EL_SPACESHIP_RIGHT              },
-    { Xtank_s,                 EL_SPACESHIP_DOWN               },
-    { Xtank_w,                 EL_SPACESHIP_LEFT               },
-    { Xandroid,                        EL_EMC_ANDROID                  },
-    { Xandroid_1_n,            EL_EMC_ANDROID_UP               },
-    { Xandroid_1_e,            EL_EMC_ANDROID_RIGHT            },
-    { Xandroid_1_w,            EL_EMC_ANDROID_LEFT             },
-    { Xandroid_1_s,            EL_EMC_ANDROID_DOWN             },
-    { Xspring,                 EL_SPRING                       },
-    { Xeater_n,                        EL_YAMYAM                       },
-    { Xalien,                  EL_ROBOT                        },
-    { Xemerald,                        EL_EMERALD                      },
-    { Xdiamond,                        EL_DIAMOND                      },
-    { Xdrip_fall,              EL_AMOEBA_DROP                  },
-    { Xbomb,                   EL_BOMB                         },
-    { Xballoon,                        EL_BALLOON                      },
-    { Xgrass,                  EL_EMC_GRASS                    },
-    { Xdirt,                   EL_SAND                         },
-    { Xacid_ne,                        EL_ACID_POOL_TOPRIGHT           },
-    { Xacid_se,                        EL_ACID_POOL_BOTTOMRIGHT        },
-    { Xacid_s,                 EL_ACID_POOL_BOTTOM             },
-    { Xacid_sw,                        EL_ACID_POOL_BOTTOMLEFT         },
-    { Xacid_nw,                        EL_ACID_POOL_TOPLEFT            },
-    { Xacid_1,                 EL_ACID                         },
-    { Xball_1,                 EL_EMC_MAGIC_BALL               },
-    { Xgrow_ns,                        EL_EMC_GROW                     },
-    { Xwonderwall,             EL_MAGIC_WALL                   },
-    { Xamoeba_1,               EL_AMOEBA_WET                   },
-    { Xdoor_1,                 EL_EM_GATE_1                    },
-    { Xdoor_2,                 EL_EM_GATE_2                    },
-    { Xdoor_3,                 EL_EM_GATE_3                    },
-    { Xdoor_4,                 EL_EM_GATE_4                    },
-    { Xdoor_5,                 EL_EMC_GATE_5                   },
-    { Xdoor_6,                 EL_EMC_GATE_6                   },
-    { Xdoor_7,                 EL_EMC_GATE_7                   },
-    { Xdoor_8,                 EL_EMC_GATE_8                   },
-    { Xkey_1,                  EL_EM_KEY_1                     },
-    { Xkey_2,                  EL_EM_KEY_2                     },
-    { Xkey_3,                  EL_EM_KEY_3                     },
-    { Xkey_4,                  EL_EM_KEY_4                     },
-    { Xkey_5,                  EL_EMC_KEY_5                    },
-    { Xkey_6,                  EL_EMC_KEY_6                    },
-    { Xkey_7,                  EL_EMC_KEY_7                    },
-    { Xkey_8,                  EL_EMC_KEY_8                    },
-    { Xwind_n,                 EL_BALLOON_SWITCH_UP            },
-    { Xwind_e,                 EL_BALLOON_SWITCH_RIGHT         },
-    { Xwind_s,                 EL_BALLOON_SWITCH_DOWN          },
-    { Xwind_w,                 EL_BALLOON_SWITCH_LEFT          },
-    { Xwind_nesw,              EL_BALLOON_SWITCH_ANY           },
-    { Xwind_stop,              EL_BALLOON_SWITCH_NONE          },
-    { Xexit,                   EL_EXIT_CLOSED                  },
-    { Xexit_1,                 EL_EXIT_OPEN                    },
-    { Xdynamite,               EL_DYNAMITE                     },
-    { Xdynamite_1,             EL_DYNAMITE_ACTIVE              },
-    { Xbumper,                 EL_EMC_BUMPER                   },
-    { Xwheel,                  EL_ROBOT_WHEEL                  },
-    { Xswitch,                 EL_UNKNOWN                      },
-    { Xsand,                   EL_QUICKSAND_EMPTY              },
-    { Xsand_stone,             EL_QUICKSAND_FULL               },
-    { Xplant,                  EL_EMC_PLANT                    },
-    { Xlenses,                 EL_EMC_LENSES                   },
-    { Xmagnify,                        EL_EMC_MAGNIFIER                },
-    { Xdripper,                        EL_UNKNOWN                      },
-    { Xfake_blank,             EL_INVISIBLE_WALL               },
-    { Xfake_grass,             EL_INVISIBLE_SAND               },
-    { Xfake_door_1,            EL_EM_GATE_1_GRAY               },
-    { Xfake_door_2,            EL_EM_GATE_2_GRAY               },
-    { Xfake_door_3,            EL_EM_GATE_3_GRAY               },
-    { Xfake_door_4,            EL_EM_GATE_4_GRAY               },
-    { Xfake_door_5,            EL_EMC_GATE_5_GRAY              },
-    { Xfake_door_6,            EL_EMC_GATE_6_GRAY              },
-    { Xfake_door_7,            EL_EMC_GATE_7_GRAY              },
-    { Xfake_door_8,            EL_EMC_GATE_8_GRAY              },
-    { Xsteel_1,                        EL_STEELWALL                    },
-    { Xsteel_2,                        EL_UNKNOWN                      },
-    { Xsteel_3,                        EL_EMC_STEELWALL_1              },
-    { Xsteel_4,                        EL_UNKNOWN                      },
-    { Xwall_1,                 EL_WALL                         },
-    { Xwall_2,                 EL_UNKNOWN                      },
-    { Xwall_3,                 EL_UNKNOWN                      },
-    { Xwall_4,                 EL_UNKNOWN                      },
-    { Xround_wall_1,           EL_WALL_SLIPPERY                },
-    { Xround_wall_2,           EL_UNKNOWN                      },
-    { Xround_wall_3,           EL_UNKNOWN                      },
-    { Xround_wall_4,           EL_UNKNOWN                      },
-    { Xdecor_1,                        EL_UNKNOWN                      },
-    { Xdecor_2,                        EL_EMC_WALL_6                   },
-    { Xdecor_3,                        EL_EMC_WALL_4                   },
-    { Xdecor_4,                        EL_EMC_WALL_5                   },
-    { Xdecor_5,                        EL_EMC_WALL_7                   },
-    { Xdecor_6,                        EL_EMC_WALL_8                   },
-    { Xdecor_7,                        EL_UNKNOWN                      },
-    { Xdecor_8,                        EL_EMC_WALL_1                   },
-    { Xdecor_9,                        EL_EMC_WALL_2                   },
-    { Xdecor_10,               EL_EMC_WALL_3                   },
-    { Xdecor_11,               EL_UNKNOWN                      },
-    { Xdecor_12,               EL_UNKNOWN                      },
-    { Xalpha_0,                        EL_CHAR('0')                    },
-    { Xalpha_1,                        EL_CHAR('1')                    },
-    { Xalpha_2,                        EL_CHAR('2')                    },
-    { Xalpha_3,                        EL_CHAR('3')                    },
-    { Xalpha_4,                        EL_CHAR('4')                    },
-    { Xalpha_5,                        EL_CHAR('5')                    },
-    { Xalpha_6,                        EL_CHAR('6')                    },
-    { Xalpha_7,                        EL_CHAR('7')                    },
-    { Xalpha_8,                        EL_CHAR('8')                    },
-    { Xalpha_9,                        EL_CHAR('9')                    },
-    { Xalpha_excla,            EL_CHAR('!')                    },
-    { Xalpha_quote,            EL_CHAR('"')                    },
-    { Xalpha_comma,            EL_CHAR(',')                    },
-    { Xalpha_minus,            EL_CHAR('-')                    },
-    { Xalpha_perio,            EL_CHAR('.')                    },
-    { Xalpha_colon,            EL_CHAR(':')                    },
-    { Xalpha_quest,            EL_CHAR('?')                    },
-    { Xalpha_a,                        EL_CHAR('A')                    },
-    { Xalpha_b,                        EL_CHAR('B')                    },
-    { Xalpha_c,                        EL_CHAR('C')                    },
-    { Xalpha_d,                        EL_CHAR('D')                    },
-    { Xalpha_e,                        EL_CHAR('E')                    },
-    { Xalpha_f,                        EL_CHAR('F')                    },
-    { Xalpha_g,                        EL_CHAR('G')                    },
-    { Xalpha_h,                        EL_CHAR('H')                    },
-    { Xalpha_i,                        EL_CHAR('I')                    },
-    { Xalpha_j,                        EL_CHAR('J')                    },
-    { Xalpha_k,                        EL_CHAR('K')                    },
-    { Xalpha_l,                        EL_CHAR('L')                    },
-    { Xalpha_m,                        EL_CHAR('M')                    },
-    { Xalpha_n,                        EL_CHAR('N')                    },
-    { Xalpha_o,                        EL_CHAR('O')                    },
-    { Xalpha_p,                        EL_CHAR('P')                    },
-    { Xalpha_q,                        EL_CHAR('Q')                    },
-    { Xalpha_r,                        EL_CHAR('R')                    },
-    { Xalpha_s,                        EL_CHAR('S')                    },
-    { Xalpha_t,                        EL_CHAR('T')                    },
-    { Xalpha_u,                        EL_CHAR('U')                    },
-    { Xalpha_v,                        EL_CHAR('V')                    },
-    { Xalpha_w,                        EL_CHAR('W')                    },
-    { Xalpha_x,                        EL_CHAR('X')                    },
-    { Xalpha_y,                        EL_CHAR('Y')                    },
-    { Xalpha_z,                        EL_CHAR('Z')                    },
-    { Xalpha_arrow_e,          EL_CHAR('>')                    },
-    { Xalpha_arrow_w,          EL_CHAR('<')                    },
-    { Xalpha_copyr,            EL_CHAR('©')                    },
-
-    { Zplayer,                 EL_PLAYER_1                     },
-    { Zplayer,                 EL_PLAYER_2                     },
-    { Zplayer,                 EL_PLAYER_3                     },
-    { Zplayer,                 EL_PLAYER_4                     },
-
-    { ZBORDER,                 EL_EMC_LEVEL_BORDER             },
-
-    { -1,                      -1                              }
-  };
+  for (i = 0; i < TILE_MAX; i++)
+    lev->android_array[i] = Xblank;
 
-  if (!mapping_initialized)
+  for (i = 0; i < level->num_android_clone_elements; i++)
   {
-    int i;
-
-    /* return "Xalpha_quest" for all undefined elements in mapping array */
-    for (i = 0; i < NUM_FILE_ELEMENTS; i++)
-      mapping_RND_to_EM[i] = Xalpha_quest;
-
-    for (i = 0; mapping_RND_to_EM_list[i].element_rnd != -1; i++)
-      mapping_RND_to_EM[mapping_RND_to_EM_list[i].element_rnd] =
-       mapping_RND_to_EM_list[i].element_em;
+    int element_rnd = level->android_clone_element[i];
+    int element_em = map_element_RND_to_EM(element_rnd);
 
-    mapping_initialized = TRUE;
+    for (j = 0; em_object_mapping_list[j].element_em != -1; j++)
+      if (em_object_mapping_list[j].element_rnd == element_rnd)
+       lev->android_array[em_object_mapping_list[j].element_em] = element_em;
   }
-
-  if (element_rnd >= 0 && element_rnd < NUM_FILE_ELEMENTS)
-    return mapping_RND_to_EM[element_rnd];
-
-  Error(ERR_WARN, "invalid RND level element %d", element_rnd);
-
-  return EL_UNKNOWN;
 }
 
-int map_element_EM_to_RND(int element_em)
+void map_android_clone_elements_EM_to_RND(struct LevelInfo *level)
 {
-  static unsigned short mapping_EM_to_RND[TILE_MAX];
-  static boolean mapping_initialized = FALSE;
+  struct LevelInfo_EM *level_em = level->native_em_level;
+  struct LEVEL *lev = level_em->lev;
+  int i, j;
+
+  level->num_android_clone_elements = 0;
 
-  struct
+  for (i = 0; i < TILE_MAX; i++)
   {
-    int element_em;
+    int element_em = lev->android_array[i];
     int element_rnd;
-  }
-  em_object_mapping_list[] =
-  {
-    { Xblank,                  EL_EMPTY                        },
-    { Yacid_splash_eB,         EL_EMPTY                        },
-    { Yacid_splash_wB,         EL_EMPTY                        },
-
-#ifdef EM_ENGINE_BAD_ROLL
-    { Xstone_force_e,          EL_ROCK                         },
-    { Xstone_force_w,          EL_ROCK                         },
-    { Xnut_force_e,            EL_NUT                          },
-    { Xnut_force_w,            EL_NUT                          },
-    { Xspring_force_e,         EL_SPRING                       },
-    { Xspring_force_w,         EL_SPRING                       },
-    { Xemerald_force_e,                EL_EMERALD                      },
-    { Xemerald_force_w,                EL_EMERALD                      },
-    { Xdiamond_force_e,                EL_DIAMOND                      },
-    { Xdiamond_force_w,                EL_DIAMOND                      },
-    { Xbomb_force_e,           EL_BOMB                         },
-    { Xbomb_force_w,           EL_BOMB                         },
-#endif
+    boolean element_found = FALSE;
 
-    { Xstone,                  EL_ROCK                         },
-    { Xstone_pause,            EL_ROCK                         },
-    { Xstone_fall,             EL_ROCK                         },
-    { Ystone_s,                        EL_ROCK                         },
-    { Ystone_sB,               EL_ROCK                         },
-    { Ystone_e,                        EL_ROCK                         },
-    { Ystone_eB,               EL_ROCK                         },
-    { Ystone_w,                        EL_ROCK                         },
-    { Ystone_wB,               EL_ROCK                         },
-    { Xnut,                    EL_NUT                          },
-    { Xnut_pause,              EL_NUT                          },
-    { Xnut_fall,               EL_NUT                          },
-    { Ynut_s,                  EL_NUT                          },
-    { Ynut_sB,                 EL_NUT                          },
-    { Ynut_e,                  EL_NUT                          },
-    { Ynut_eB,                 EL_NUT                          },
-    { Ynut_w,                  EL_NUT                          },
-    { Ynut_wB,                 EL_NUT                          },
-    { Xbug_n,                  EL_BUG_UP                       },
-    { Xbug_e,                  EL_BUG_RIGHT                    },
-    { Xbug_s,                  EL_BUG_DOWN                     },
-    { Xbug_w,                  EL_BUG_LEFT                     },
-    { Xbug_gon,                        EL_BUG_UP                       },
-    { Xbug_goe,                        EL_BUG_RIGHT                    },
-    { Xbug_gos,                        EL_BUG_DOWN                     },
-    { Xbug_gow,                        EL_BUG_LEFT                     },
-    { Ybug_n,                  EL_BUG_UP                       },
-    { Ybug_nB,                 EL_BUG_UP                       },
-    { Ybug_e,                  EL_BUG_RIGHT                    },
-    { Ybug_eB,                 EL_BUG_RIGHT                    },
-    { Ybug_s,                  EL_BUG_DOWN                     },
-    { Ybug_sB,                 EL_BUG_DOWN                     },
-    { Ybug_w,                  EL_BUG_LEFT                     },
-    { Ybug_wB,                 EL_BUG_LEFT                     },
-    { Ybug_w_n,                        EL_BUG_UP                       },
-    { Ybug_n_e,                        EL_BUG_RIGHT                    },
-    { Ybug_e_s,                        EL_BUG_DOWN                     },
-    { Ybug_s_w,                        EL_BUG_LEFT                     },
-    { Ybug_e_n,                        EL_BUG_UP                       },
-    { Ybug_s_e,                        EL_BUG_RIGHT                    },
-    { Ybug_w_s,                        EL_BUG_DOWN                     },
-    { Ybug_n_w,                        EL_BUG_LEFT                     },
-    { Ybug_stone,              EL_ROCK                         },
-    { Ybug_spring,             EL_SPRING                       },
-    { Xtank_n,                 EL_SPACESHIP_UP                 },
-    { Xtank_e,                 EL_SPACESHIP_RIGHT              },
-    { Xtank_s,                 EL_SPACESHIP_DOWN               },
-    { Xtank_w,                 EL_SPACESHIP_LEFT               },
-    { Xtank_gon,               EL_SPACESHIP_UP                 },
-    { Xtank_goe,               EL_SPACESHIP_RIGHT              },
-    { Xtank_gos,               EL_SPACESHIP_DOWN               },
-    { Xtank_gow,               EL_SPACESHIP_LEFT               },
-    { Ytank_n,                 EL_SPACESHIP_UP                 },
-    { Ytank_nB,                        EL_SPACESHIP_UP                 },
-    { Ytank_e,                 EL_SPACESHIP_RIGHT              },
-    { Ytank_eB,                        EL_SPACESHIP_RIGHT              },
-    { Ytank_s,                 EL_SPACESHIP_DOWN               },
-    { Ytank_sB,                        EL_SPACESHIP_DOWN               },
-    { Ytank_w,                 EL_SPACESHIP_LEFT               },
-    { Ytank_wB,                        EL_SPACESHIP_LEFT               },
-    { Ytank_w_n,               EL_SPACESHIP_UP                 },
-    { Ytank_n_e,               EL_SPACESHIP_RIGHT              },
-    { Ytank_e_s,               EL_SPACESHIP_DOWN               },
-    { Ytank_s_w,               EL_SPACESHIP_LEFT               },
-    { Ytank_e_n,               EL_SPACESHIP_UP                 },
-    { Ytank_s_e,               EL_SPACESHIP_RIGHT              },
-    { Ytank_w_s,               EL_SPACESHIP_DOWN               },
-    { Ytank_n_w,               EL_SPACESHIP_LEFT               },
-    { Ytank_stone,             EL_ROCK                         },
-    { Ytank_spring,            EL_SPRING                       },
-    { Xandroid,                        EL_EMC_ANDROID                  },
-    { Xandroid_1_n,            EL_EMC_ANDROID_UP               },
-    { Xandroid_2_n,            EL_EMC_ANDROID_UP               },
-    { Xandroid_1_e,            EL_EMC_ANDROID_RIGHT            },
-    { Xandroid_2_e,            EL_EMC_ANDROID_RIGHT            },
-    { Xandroid_1_w,            EL_EMC_ANDROID_LEFT             },
-    { Xandroid_2_w,            EL_EMC_ANDROID_LEFT             },
-    { Xandroid_1_s,            EL_EMC_ANDROID_DOWN             },
-    { Xandroid_2_s,            EL_EMC_ANDROID_DOWN             },
-    { Yandroid_n,              EL_EMC_ANDROID_UP               },
-    { Yandroid_nB,             EL_EMC_ANDROID_UP               },
-    { Yandroid_ne,             EL_EMC_ANDROID_RIGHT_UP         },
-    { Yandroid_neB,            EL_EMC_ANDROID_RIGHT_UP         },
-    { Yandroid_e,              EL_EMC_ANDROID_RIGHT            },
-    { Yandroid_eB,             EL_EMC_ANDROID_RIGHT            },
-    { Yandroid_se,             EL_EMC_ANDROID_RIGHT_DOWN       },
-    { Yandroid_seB,            EL_EMC_ANDROID_RIGHT_DOWN       },
-    { Yandroid_s,              EL_EMC_ANDROID_DOWN             },
-    { Yandroid_sB,             EL_EMC_ANDROID_DOWN             },
-    { Yandroid_sw,             EL_EMC_ANDROID_LEFT_DOWN        },
-    { Yandroid_swB,            EL_EMC_ANDROID_LEFT_DOWN        },
-    { Yandroid_w,              EL_EMC_ANDROID_LEFT             },
-    { Yandroid_wB,             EL_EMC_ANDROID_LEFT             },
-    { Yandroid_nw,             EL_EMC_ANDROID_LEFT_UP          },
-    { Yandroid_nwB,            EL_EMC_ANDROID_LEFT_UP          },
-    { Xspring,                 EL_SPRING                       },
-    { Xspring_pause,           EL_SPRING                       },
-    { Xspring_e,               EL_SPRING                       },
-    { Xspring_w,               EL_SPRING                       },
-    { Xspring_fall,            EL_SPRING                       },
-    { Yspring_s,               EL_SPRING                       },
-    { Yspring_sB,              EL_SPRING                       },
-    { Yspring_e,               EL_SPRING                       },
-    { Yspring_eB,              EL_SPRING                       },
-    { Yspring_w,               EL_SPRING                       },
-    { Yspring_wB,              EL_SPRING                       },
-    { Yspring_kill_e,          EL_SPRING                       },
-    { Yspring_kill_eB,         EL_SPRING                       },
-    { Yspring_kill_w,          EL_SPRING                       },
-    { Yspring_kill_wB,         EL_SPRING                       },
-    { Xeater_n,                        EL_YAMYAM                       },
-    { Xeater_e,                        EL_YAMYAM                       },
-    { Xeater_w,                        EL_YAMYAM                       },
-    { Xeater_s,                        EL_YAMYAM                       },
-    { Yeater_n,                        EL_YAMYAM                       },
-    { Yeater_nB,               EL_YAMYAM                       },
-    { Yeater_e,                        EL_YAMYAM                       },
-    { Yeater_eB,               EL_YAMYAM                       },
-    { Yeater_s,                        EL_YAMYAM                       },
-    { Yeater_sB,               EL_YAMYAM                       },
-    { Yeater_w,                        EL_YAMYAM                       },
-    { Yeater_wB,               EL_YAMYAM                       },
-    { Yeater_stone,            EL_ROCK                         },
-    { Yeater_spring,           EL_SPRING                       },
-    { Xalien,                  EL_ROBOT                        },
-    { Xalien_pause,            EL_ROBOT                        },
-    { Yalien_n,                        EL_ROBOT                        },
-    { Yalien_nB,               EL_ROBOT                        },
-    { Yalien_e,                        EL_ROBOT                        },
-    { Yalien_eB,               EL_ROBOT                        },
-    { Yalien_s,                        EL_ROBOT                        },
-    { Yalien_sB,               EL_ROBOT                        },
-    { Yalien_w,                        EL_ROBOT                        },
-    { Yalien_wB,               EL_ROBOT                        },
-    { Yalien_stone,            EL_ROCK                         },
-    { Yalien_spring,           EL_SPRING                       },
-    { Xemerald,                        EL_EMERALD                      },
-    { Xemerald_pause,          EL_EMERALD                      },
-    { Xemerald_fall,           EL_EMERALD                      },
-    { Xemerald_shine,          EL_EMERALD                      },
-    { Yemerald_s,              EL_EMERALD                      },
-    { Yemerald_sB,             EL_EMERALD                      },
-    { Yemerald_e,              EL_EMERALD                      },
-    { Yemerald_eB,             EL_EMERALD                      },
-    { Yemerald_w,              EL_EMERALD                      },
-    { Yemerald_wB,             EL_EMERALD                      },
-    { Yemerald_eat,            EL_EMERALD                      },
-    { Yemerald_stone,          EL_ROCK                         },
-    { Xdiamond,                        EL_DIAMOND                      },
-    { Xdiamond_pause,          EL_DIAMOND                      },
-    { Xdiamond_fall,           EL_DIAMOND                      },
-    { Xdiamond_shine,          EL_DIAMOND                      },
-    { Ydiamond_s,              EL_DIAMOND                      },
-    { Ydiamond_sB,             EL_DIAMOND                      },
-    { Ydiamond_e,              EL_DIAMOND                      },
-    { Ydiamond_eB,             EL_DIAMOND                      },
-    { Ydiamond_w,              EL_DIAMOND                      },
-    { Ydiamond_wB,             EL_DIAMOND                      },
-    { Ydiamond_eat,            EL_DIAMOND                      },
-    { Ydiamond_stone,          EL_ROCK                         },
-    { Xdrip_fall,              EL_AMOEBA_DROP                  },
-    { Xdrip_stretch,           EL_AMOEBA_DROP                  },
-    { Xdrip_stretchB,          EL_AMOEBA_DROP                  },
-    { Xdrip_eat,               EL_AMOEBA_DROP                  },
-    { Ydrip_s1,                        EL_AMOEBA_DROP                  },
-    { Ydrip_s1B,               EL_AMOEBA_DROP                  },
-    { Ydrip_s2,                        EL_AMOEBA_DROP                  },
-    { Ydrip_s2B,               EL_AMOEBA_DROP                  },
-    { Xbomb,                   EL_BOMB                         },
-    { Xbomb_pause,             EL_BOMB                         },
-    { Xbomb_fall,              EL_BOMB                         },
-    { Ybomb_s,                 EL_BOMB                         },
-    { Ybomb_sB,                        EL_BOMB                         },
-    { Ybomb_e,                 EL_BOMB                         },
-    { Ybomb_eB,                        EL_BOMB                         },
-    { Ybomb_w,                 EL_BOMB                         },
-    { Ybomb_wB,                        EL_BOMB                         },
-    { Ybomb_eat,               EL_BOMB                         },
-    { Xballoon,                        EL_BALLOON                      },
-    { Yballoon_n,              EL_BALLOON                      },
-    { Yballoon_nB,             EL_BALLOON                      },
-    { Yballoon_e,              EL_BALLOON                      },
-    { Yballoon_eB,             EL_BALLOON                      },
-    { Yballoon_s,              EL_BALLOON                      },
-    { Yballoon_sB,             EL_BALLOON                      },
-    { Yballoon_w,              EL_BALLOON                      },
-    { Yballoon_wB,             EL_BALLOON                      },
-    { Xgrass,                  EL_SAND                         },
-    { Ygrass_nB,               EL_SAND                         },
-    { Ygrass_eB,               EL_SAND                         },
-    { Ygrass_sB,               EL_SAND                         },
-    { Ygrass_wB,               EL_SAND                         },
-    { Xdirt,                   EL_SAND                         },
-    { Ydirt_nB,                        EL_SAND                         },
-    { Ydirt_eB,                        EL_SAND                         },
-    { Ydirt_sB,                        EL_SAND                         },
-    { Ydirt_wB,                        EL_SAND                         },
-    { Xacid_ne,                        EL_ACID_POOL_TOPRIGHT           },
-    { Xacid_se,                        EL_ACID_POOL_BOTTOMRIGHT        },
-    { Xacid_s,                 EL_ACID_POOL_BOTTOM             },
-    { Xacid_sw,                        EL_ACID_POOL_BOTTOMLEFT         },
-    { Xacid_nw,                        EL_ACID_POOL_TOPLEFT            },
-    { Xacid_1,                 EL_ACID                         },
-    { Xacid_2,                 EL_ACID                         },
-    { Xacid_3,                 EL_ACID                         },
-    { Xacid_4,                 EL_ACID                         },
-    { Xacid_5,                 EL_ACID                         },
-    { Xacid_6,                 EL_ACID                         },
-    { Xacid_7,                 EL_ACID                         },
-    { Xacid_8,                 EL_ACID                         },
-    { Xball_1,                 EL_EMC_MAGIC_BALL               },
-    { Xball_1B,                        EL_EMC_MAGIC_BALL               },
-    { Xball_2,                 EL_EMC_MAGIC_BALL               },
-    { Xball_2B,                        EL_EMC_MAGIC_BALL               },
-    { Yball_eat,               EL_EMC_MAGIC_BALL               },
-    { Xgrow_ns,                        EL_EMC_GROW                     },
-    { Ygrow_ns_eat,            EL_EMC_GROW                     },
-    { Xgrow_ew,                        EL_EMC_GROW                     },
-    { Ygrow_ew_eat,            EL_EMC_GROW                     },
-    { Xwonderwall,             EL_MAGIC_WALL                   },
-    { XwonderwallB,            EL_MAGIC_WALL                   },
-    { Xamoeba_1,               EL_AMOEBA_WET                   },
-    { Xamoeba_2,               EL_AMOEBA_WET                   },
-    { Xamoeba_3,               EL_AMOEBA_WET                   },
-    { Xamoeba_4,               EL_AMOEBA_WET                   },
-    { Xamoeba_5,               EL_AMOEBA_WET                   },
-    { Xamoeba_6,               EL_AMOEBA_WET                   },
-    { Xamoeba_7,               EL_AMOEBA_WET                   },
-    { Xamoeba_8,               EL_AMOEBA_WET                   },
-    { Xdoor_1,                 EL_EM_GATE_1                    },
-    { Xdoor_2,                 EL_EM_GATE_2                    },
-    { Xdoor_3,                 EL_EM_GATE_3                    },
-    { Xdoor_4,                 EL_EM_GATE_4                    },
-    { Xdoor_5,                 EL_EMC_GATE_5                   },
-    { Xdoor_6,                 EL_EMC_GATE_6                   },
-    { Xdoor_7,                 EL_EMC_GATE_7                   },
-    { Xdoor_8,                 EL_EMC_GATE_8                   },
-    { Xkey_1,                  EL_EM_KEY_1                     },
-    { Xkey_2,                  EL_EM_KEY_2                     },
-    { Xkey_3,                  EL_EM_KEY_3                     },
-    { Xkey_4,                  EL_EM_KEY_4                     },
-    { Xkey_5,                  EL_EMC_KEY_5                    },
-    { Xkey_6,                  EL_EMC_KEY_6                    },
-    { Xkey_7,                  EL_EMC_KEY_7                    },
-    { Xkey_8,                  EL_EMC_KEY_8                    },
-    { Xwind_n,                 EL_BALLOON_SWITCH_UP            },
-    { Xwind_e,                 EL_BALLOON_SWITCH_RIGHT         },
-    { Xwind_s,                 EL_BALLOON_SWITCH_DOWN          },
-    { Xwind_w,                 EL_BALLOON_SWITCH_LEFT          },
-    { Xwind_nesw,              EL_BALLOON_SWITCH_ANY           },
-    { Xwind_stop,              EL_BALLOON_SWITCH_NONE          },
-    { Xexit,                   EL_EXIT_CLOSED                  },
-    { Xexit_1,                 EL_EXIT_OPEN                    },
-    { Xexit_2,                 EL_EXIT_OPEN                    },
-    { Xexit_3,                 EL_EXIT_OPEN                    },
-    { Xdynamite,               EL_DYNAMITE                     },
-    { Ydynamite_eat,           EL_DYNAMITE                     },
-    { Xdynamite_1,             EL_DYNAMITE_ACTIVE              },
-    { Xdynamite_2,             EL_DYNAMITE_ACTIVE              },
-    { Xdynamite_3,             EL_DYNAMITE_ACTIVE              },
-    { Xdynamite_4,             EL_DYNAMITE_ACTIVE              },
-    { Xbumper,                 EL_EMC_BUMPER                   },
-    { XbumperB,                        EL_EMC_BUMPER                   },
-    { Xwheel,                  EL_ROBOT_WHEEL                  },
-    { XwheelB,                 EL_ROBOT_WHEEL                  },
-    { Xswitch,                 EL_UNKNOWN                      },
-    { XswitchB,                        EL_UNKNOWN                      },
-    { Xsand,                   EL_QUICKSAND_EMPTY              },
-    { Xsand_stone,             EL_QUICKSAND_FULL               },
-    { Xsand_stonein_1,         EL_QUICKSAND_FULL               },
-    { Xsand_stonein_2,         EL_QUICKSAND_FULL               },
-    { Xsand_stonein_3,         EL_QUICKSAND_FULL               },
-    { Xsand_stonein_4,         EL_QUICKSAND_FULL               },
-    { Xsand_stonesand_1,       EL_QUICKSAND_FULL               },
-    { Xsand_stonesand_2,       EL_QUICKSAND_FULL               },
-    { Xsand_stonesand_3,       EL_QUICKSAND_FULL               },
-    { Xsand_stonesand_4,       EL_QUICKSAND_FULL               },
-    { Xsand_stoneout_1,                EL_QUICKSAND_FULL               },
-    { Xsand_stoneout_2,                EL_QUICKSAND_FULL               },
-    { Xsand_sandstone_1,       EL_QUICKSAND_FULL               },
-    { Xsand_sandstone_2,       EL_QUICKSAND_FULL               },
-    { Xsand_sandstone_3,       EL_QUICKSAND_FULL               },
-    { Xsand_sandstone_4,       EL_QUICKSAND_FULL               },
-    { Xplant,                  EL_EMC_PLANT                    },
-    { Yplant,                  EL_EMC_PLANT                    },
-    { Xlenses,                 EL_EMC_LENSES                   },
-    { Xmagnify,                        EL_EMC_MAGNIFIER                },
-    { Xdripper,                        EL_UNKNOWN                      },
-    { XdripperB,               EL_UNKNOWN                      },
-    { Xfake_blank,             EL_INVISIBLE_WALL               },
-    { Xfake_blankB,            EL_INVISIBLE_WALL               },
-    { Xfake_grass,             EL_INVISIBLE_SAND               },
-    { Xfake_grassB,            EL_INVISIBLE_SAND               },
-    { Xfake_door_1,            EL_EM_GATE_1_GRAY               },
-    { Xfake_door_2,            EL_EM_GATE_2_GRAY               },
-    { Xfake_door_3,            EL_EM_GATE_3_GRAY               },
-    { Xfake_door_4,            EL_EM_GATE_4_GRAY               },
-    { Xfake_door_5,            EL_EMC_GATE_5_GRAY              },
-    { Xfake_door_6,            EL_EMC_GATE_6_GRAY              },
-    { Xfake_door_7,            EL_EMC_GATE_7_GRAY              },
-    { Xfake_door_8,            EL_EMC_GATE_8_GRAY              },
-    { Xsteel_1,                        EL_STEELWALL                    },
-    { Xsteel_2,                        EL_UNKNOWN                      },
-    { Xsteel_3,                        EL_EMC_STEELWALL_1              },
-    { Xsteel_4,                        EL_UNKNOWN                      },
-    { Xwall_1,                 EL_WALL                         },
-    { Xwall_2,                 EL_UNKNOWN                      },
-    { Xwall_3,                 EL_UNKNOWN                      },
-    { Xwall_4,                 EL_UNKNOWN                      },
-    { Xround_wall_1,           EL_WALL_SLIPPERY                },
-    { Xround_wall_2,           EL_UNKNOWN                      },
-    { Xround_wall_3,           EL_UNKNOWN                      },
-    { Xround_wall_4,           EL_UNKNOWN                      },
-    { Xdecor_1,                        EL_UNKNOWN                      },
-    { Xdecor_2,                        EL_EMC_WALL_6                   },
-    { Xdecor_3,                        EL_EMC_WALL_4                   },
-    { Xdecor_4,                        EL_EMC_WALL_5                   },
-    { Xdecor_5,                        EL_EMC_WALL_7                   },
-    { Xdecor_6,                        EL_EMC_WALL_8                   },
-    { Xdecor_7,                        EL_UNKNOWN                      },
-    { Xdecor_8,                        EL_EMC_WALL_1                   },
-    { Xdecor_9,                        EL_EMC_WALL_2                   },
-    { Xdecor_10,               EL_EMC_WALL_3                   },
-    { Xdecor_11,               EL_UNKNOWN                      },
-    { Xdecor_12,               EL_UNKNOWN                      },
-    { Xalpha_0,                        EL_CHAR('0')                    },
-    { Xalpha_1,                        EL_CHAR('1')                    },
-    { Xalpha_2,                        EL_CHAR('2')                    },
-    { Xalpha_3,                        EL_CHAR('3')                    },
-    { Xalpha_4,                        EL_CHAR('4')                    },
-    { Xalpha_5,                        EL_CHAR('5')                    },
-    { Xalpha_6,                        EL_CHAR('6')                    },
-    { Xalpha_7,                        EL_CHAR('7')                    },
-    { Xalpha_8,                        EL_CHAR('8')                    },
-    { Xalpha_9,                        EL_CHAR('9')                    },
-    { Xalpha_excla,            EL_CHAR('!')                    },
-    { Xalpha_quote,            EL_CHAR('"')                    },
-    { Xalpha_comma,            EL_CHAR(',')                    },
-    { Xalpha_minus,            EL_CHAR('-')                    },
-    { Xalpha_perio,            EL_CHAR('.')                    },
-    { Xalpha_colon,            EL_CHAR(':')                    },
-    { Xalpha_quest,            EL_CHAR('?')                    },
-    { Xalpha_a,                        EL_CHAR('A')                    },
-    { Xalpha_b,                        EL_CHAR('B')                    },
-    { Xalpha_c,                        EL_CHAR('C')                    },
-    { Xalpha_d,                        EL_CHAR('D')                    },
-    { Xalpha_e,                        EL_CHAR('E')                    },
-    { Xalpha_f,                        EL_CHAR('F')                    },
-    { Xalpha_g,                        EL_CHAR('G')                    },
-    { Xalpha_h,                        EL_CHAR('H')                    },
-    { Xalpha_i,                        EL_CHAR('I')                    },
-    { Xalpha_j,                        EL_CHAR('J')                    },
-    { Xalpha_k,                        EL_CHAR('K')                    },
-    { Xalpha_l,                        EL_CHAR('L')                    },
-    { Xalpha_m,                        EL_CHAR('M')                    },
-    { Xalpha_n,                        EL_CHAR('N')                    },
-    { Xalpha_o,                        EL_CHAR('O')                    },
-    { Xalpha_p,                        EL_CHAR('P')                    },
-    { Xalpha_q,                        EL_CHAR('Q')                    },
-    { Xalpha_r,                        EL_CHAR('R')                    },
-    { Xalpha_s,                        EL_CHAR('S')                    },
-    { Xalpha_t,                        EL_CHAR('T')                    },
-    { Xalpha_u,                        EL_CHAR('U')                    },
-    { Xalpha_v,                        EL_CHAR('V')                    },
-    { Xalpha_w,                        EL_CHAR('W')                    },
-    { Xalpha_x,                        EL_CHAR('X')                    },
-    { Xalpha_y,                        EL_CHAR('Y')                    },
-    { Xalpha_z,                        EL_CHAR('Z')                    },
-    { Xalpha_arrow_e,          EL_CHAR('>')                    },
-    { Xalpha_arrow_w,          EL_CHAR('<')                    },
-    { Xalpha_copyr,            EL_CHAR('©')                    },
-
-    { Zplayer,                 EL_PLAYER_1                     },
-
-    { ZBORDER,                 EL_EMC_LEVEL_BORDER             },
-
-    { -1,                      -1                              }
-  };
+    if (element_em == Xblank)
+      continue;
 
-  if (!mapping_initialized)
-  {
-    int i;
+    element_rnd = map_element_EM_to_RND(element_em);
 
-    /* return "EL_UNKNOWN" for all undefined elements in mapping array */
-    for (i = 0; i < TILE_MAX; i++)
-      mapping_EM_to_RND[i] = EL_UNKNOWN;
+    for (j = 0; j < level->num_android_clone_elements; j++)
+      if (level->android_clone_element[j] == element_rnd)
+       element_found = TRUE;
 
-    for (i = 0; em_object_mapping_list[i].element_em != -1; i++)
-      mapping_EM_to_RND[em_object_mapping_list[i].element_em] =
-       em_object_mapping_list[i].element_rnd;
+    if (!element_found)
+    {
+      level->android_clone_element[level->num_android_clone_elements++] =
+       element_rnd;
 
-    mapping_initialized = TRUE;
+      if (level->num_android_clone_elements == MAX_ANDROID_ELEMENTS)
+       break;
+    }
   }
 
-  if (element_em >= 0 && element_em < TILE_MAX)
-    return mapping_EM_to_RND[element_em];
-
-  Error(ERR_WARN, "invalid EM level element %d", element_em);
+  if (level->num_android_clone_elements == 0)
+  {
+    level->num_android_clone_elements = 1;
+    level->android_clone_element[0] = EL_EMPTY;
+  }
+}
 
-  return EL_UNKNOWN;
+int map_direction_RND_to_EM(int direction)
+{
+  return (direction == MV_UP    ? 0 :
+         direction == MV_RIGHT ? 1 :
+         direction == MV_DOWN  ? 2 :
+         direction == MV_LEFT  ? 3 :
+         -1);
 }
 
-#endif
+int map_direction_EM_to_RND(int direction)
+{
+  return (direction == 0 ? MV_UP    :
+         direction == 1 ? MV_RIGHT :
+         direction == 2 ? MV_DOWN  :
+         direction == 3 ? MV_LEFT  :
+         MV_NONE);
+}
 
 int get_next_element(int element)
 {
@@ -5591,10 +5118,10 @@ int el_act_dir2img(int element, int action, int direction)
 {
   element = GFX_ELEMENT(element);
 
-  if (direction == MV_NO_MOVING)
+  if (direction == MV_NONE)
     return element_info[element].graphic[action];
 
-  direction = MV_DIR_BIT(direction);
+  direction = MV_DIR_TO_BIT(direction);
 
   return element_info[element].direction_graphic[action][direction];
 }
@@ -5602,7 +5129,7 @@ int el_act_dir2img(int element, int action, int direction)
 int el_act_dir2img(int element, int action, int direction)
 {
   element = GFX_ELEMENT(element);
-  direction = MV_DIR_BIT(direction);   /* default: MV_NO_MOVING => MV_DOWN */
+  direction = MV_DIR_TO_BIT(direction);        /* default: MV_NONE => MV_DOWN */
 
   /* direction_graphic[][] == graphic[] for undefined direction graphics */
   return element_info[element].direction_graphic[action][direction];
@@ -5614,10 +5141,10 @@ static int el_act_dir2crm(int element, int action, int direction)
 {
   element = GFX_ELEMENT(element);
 
-  if (direction == MV_NO_MOVING)
+  if (direction == MV_NONE)
     return element_info[element].crumbled[action];
 
-  direction = MV_DIR_BIT(direction);
+  direction = MV_DIR_TO_BIT(direction);
 
   return element_info[element].direction_crumbled[action][direction];
 }
@@ -5625,7 +5152,7 @@ static int el_act_dir2crm(int element, int action, int direction)
 static int el_act_dir2crm(int element, int action, int direction)
 {
   element = GFX_ELEMENT(element);
-  direction = MV_DIR_BIT(direction);   /* default: MV_NO_MOVING => MV_DOWN */
+  direction = MV_DIR_TO_BIT(direction);        /* default: MV_NONE => MV_DOWN */
 
   /* direction_graphic[][] == graphic[] for undefined direction graphics */
   return element_info[element].direction_crumbled[action][direction];
@@ -5679,6 +5206,58 @@ int el2preimg(int element)
   return element_info[element].special_graphic[GFX_SPECIAL_ARG_PREVIEW];
 }
 
+int font2baseimg(int font_nr)
+{
+  return font_info[font_nr].special_graphic[GFX_SPECIAL_ARG_DEFAULT];
+}
+
+#if 0
+void setCenteredPlayerNr_EM(int centered_player_nr)
+{
+  game.centered_player_nr = game.centered_player_nr_next = centered_player_nr;
+}
+
+int getCenteredPlayerNr_EM()
+{
+#if 0
+  if (game.centered_player_nr_next >= 0 &&
+      !native_em_level.ply[game.centered_player_nr_next]->alive)
+    game.centered_player_nr_next = game.centered_player_nr;
+#endif
+
+  if (game.centered_player_nr != game.centered_player_nr_next)
+    game.centered_player_nr = game.centered_player_nr_next;
+
+  return game.centered_player_nr;
+}
+
+void setSetCenteredPlayer_EM(boolean set_centered_player)
+{
+  game.set_centered_player = set_centered_player;
+}
+
+boolean getSetCenteredPlayer_EM()
+{
+  return game.set_centered_player;
+}
+#endif
+
+int getNumActivePlayers_EM()
+{
+  int num_players = 0;
+  int i;
+
+  if (!tape.playing)
+    return -1;
+
+  for (i = 0; i < MAX_PLAYERS; i++)
+    if (tape.player_participates[i])
+      num_players++;
+
+  return num_players;
+}
+
+#if 1
 int getGameFrameDelay_EM(int native_em_game_frame_delay)
 {
   int game_frame_delay_value;
@@ -5693,6 +5272,7 @@ int getGameFrameDelay_EM(int native_em_game_frame_delay)
 
   return game_frame_delay_value;
 }
+#endif
 
 unsigned int InitRND(long seed)
 {
@@ -5702,21 +5282,23 @@ unsigned int InitRND(long seed)
     return InitEngineRND(seed);
 }
 
-#define DEBUG_EM_GFX   0
-
 void InitGraphicInfo_EM(void)
 {
   struct Mapping_EM_to_RND_object object_mapping[TILE_MAX];
-  struct Mapping_EM_to_RND_player player_mapping[2][SPR_MAX];
+  struct Mapping_EM_to_RND_player player_mapping[MAX_PLAYERS][SPR_MAX];
   int i, j, p;
 
 #if DEBUG_EM_GFX
+  int num_em_gfx_errors = 0;
+
   if (graphic_info_em_object[0][0].bitmap == NULL)
   {
     /* EM graphics not yet initialized in em_open_all() */
 
     return;
   }
+
+  printf("::: [4 errors can be ignored (1 x 'bomb', 3 x 'em_dynamite']\n");
 #endif
 
   /* always start with reliable default values */
@@ -5725,17 +5307,17 @@ void InitGraphicInfo_EM(void)
     object_mapping[i].element_rnd = EL_UNKNOWN;
     object_mapping[i].is_backside = FALSE;
     object_mapping[i].action = ACTION_DEFAULT;
-    object_mapping[i].direction = MV_NO_MOVING;
+    object_mapping[i].direction = MV_NONE;
   }
 
   /* always start with reliable default values */
-  for (p = 0; p < 2; p++)
+  for (p = 0; p < MAX_PLAYERS; p++)
   {
     for (i = 0; i < SPR_MAX; i++)
     {
       player_mapping[p][i].element_rnd = EL_UNKNOWN;
       player_mapping[p][i].action = ACTION_DEFAULT;
-      player_mapping[p][i].direction = MV_NO_MOVING;
+      player_mapping[p][i].direction = MV_NONE;
     }
   }
 
@@ -5750,7 +5332,8 @@ void InitGraphicInfo_EM(void)
       object_mapping[e].action = em_object_mapping_list[i].action;
 
     if (em_object_mapping_list[i].direction != -1)
-      object_mapping[e].direction = (1 << em_object_mapping_list[i].direction);
+      object_mapping[e].direction =
+       MV_DIR_FROM_BIT(em_object_mapping_list[i].direction);
   }
 
   for (i = 0; em_player_mapping_list[i].action_em != -1; i++)
@@ -5765,7 +5348,7 @@ void InitGraphicInfo_EM(void)
 
     if (em_player_mapping_list[i].direction != -1)
       player_mapping[p][a].direction =
-       (1 << em_player_mapping_list[i].direction);
+       MV_DIR_FROM_BIT(em_player_mapping_list[i].direction);
   }
 
   for (i = 0; i < TILE_MAX; i++)
@@ -5809,12 +5392,12 @@ void InitGraphicInfo_EM(void)
                               i == Ymagnify_eat ? element :
                               i == Ygrass_eat ? element :
                               i == Ydirt_eat ? element :
-                              i == Yspring_kill_e ? EL_SPRING :
-                              i == Yspring_kill_w ? EL_SPRING :
                               i == Yemerald_stone ? EL_EMERALD :
                               i == Ydiamond_stone ? EL_ROCK :
-                              i == Xsand_stonein_4 ? EL_EMPTY :
-                              i == Xsand_stoneout_2 ? EL_ROCK :
+                              i == Xsand_stonein_1 ? element :
+                              i == Xsand_stonein_2 ? element :
+                              i == Xsand_stonein_3 ? element :
+                              i == Xsand_stonein_4 ? element :
                               is_backside ? EL_EMPTY :
                               action_removing ? EL_EMPTY :
                               element);
@@ -5856,6 +5439,7 @@ void InitGraphicInfo_EM(void)
                                     direction));
       int base_graphic = el_act2img(effective_element, ACTION_DEFAULT);
       int base_crumbled = el_act2crm(effective_element, ACTION_DEFAULT);
+      boolean has_action_graphics = (graphic != base_graphic);
       boolean has_crumbled_graphics = (base_crumbled != base_graphic);
       struct GraphicInfo *g = &graphic_info[graphic];
       struct GraphicInfo_EM *g_em = &graphic_info_em_object[i][7 - j];
@@ -5912,9 +5496,9 @@ void InitGraphicInfo_EM(void)
                        i == Xexit_2 ? j + 8 :
                        i == Xexit_3 ? j + 16 :
                        i == Xdynamite_1 ? 0 :
-                       i == Xdynamite_2 ? 20 :
-                       i == Xdynamite_3 ? 40 :
-                       i == Xdynamite_4 ? 60 :
+                       i == Xdynamite_2 ? 8 :
+                       i == Xdynamite_3 ? 16 :
+                       i == Xdynamite_4 ? 24 :
                        i == Xsand_stonein_1 ? j + 1 :
                        i == Xsand_stonein_2 ? j + 9 :
                        i == Xsand_stonein_3 ? j + 17 :
@@ -5984,7 +5568,6 @@ void InitGraphicInfo_EM(void)
       getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y,
                          g->double_movement && is_backside);
 
-#if 1
       g_em->bitmap = src_bitmap;
       g_em->src_x = src_x;
       g_em->src_y = src_y;
@@ -6002,13 +5585,6 @@ void InitGraphicInfo_EM(void)
 
       g_em->has_crumbled_graphics = FALSE;
       g_em->preserve_background = FALSE;
-#endif
-
-#if 0
-      if (effective_element == EL_EMC_GRASS &&
-         effective_action == ACTION_DIGGING)
-       printf("::: %d\n", crumbled);
-#endif
 
 #if 0
       if (has_crumbled_graphics && crumbled == IMG_EMPTY_SPACE)
@@ -6031,23 +5607,43 @@ void InitGraphicInfo_EM(void)
        g_em->crumbled_border_size = graphic_info[crumbled].border_size;
       }
 
-#if 1
-      if (!g->double_movement && (effective_action == ACTION_FALLING ||
-                                 effective_action == ACTION_MOVING ||
-                                 effective_action == ACTION_PUSHING))
+#if 0
+      if (element == EL_ROCK &&
+         effective_action == ACTION_FILLING)
+       printf("::: has_action_graphics == %d\n", has_action_graphics);
+#endif
+
+      if ((!g->double_movement && (effective_action == ACTION_FALLING ||
+                                  effective_action == ACTION_MOVING  ||
+                                  effective_action == ACTION_PUSHING ||
+                                  effective_action == ACTION_EATING)) ||
+         (!has_action_graphics && (effective_action == ACTION_FILLING ||
+                                   effective_action == ACTION_EMPTYING)))
       {
        int move_dir =
-         (effective_action == ACTION_FALLING ? MV_DOWN : direction);
+         (effective_action == ACTION_FALLING ||
+          effective_action == ACTION_FILLING ||
+          effective_action == ACTION_EMPTYING ? MV_DOWN : direction);
        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 num_steps = (i == Ydrip_s1 ||
-                        i == Ydrip_s1B ||
-                        i == Ydrip_s2 ||
-                        i == Ydrip_s2B ? 16 : 8);
+       int num_steps = (i == Ydrip_s1  ? 16 :
+                        i == Ydrip_s1B ? 16 :
+                        i == Ydrip_s2  ? 16 :
+                        i == Ydrip_s2B ? 16 :
+                        i == Xsand_stonein_1 ? 32 :
+                        i == Xsand_stonein_2 ? 32 :
+                        i == Xsand_stonein_3 ? 32 :
+                        i == Xsand_stonein_4 ? 32 :
+                        i == Xsand_stoneout_1 ? 16 :
+                        i == Xsand_stoneout_2 ? 16 : 8);
        int cx = ABS(dx) * (TILEX / num_steps);
        int cy = ABS(dy) * (TILEY / num_steps);
-       int step_frame = (i == Ydrip_s2 ||
-                         i == Ydrip_s2B ? j + 8 : j) + 1;
+       int step_frame = (i == Ydrip_s2         ? j + 8 :
+                         i == Ydrip_s2B        ? j + 8 :
+                         i == Xsand_stonein_2  ? j + 8 :
+                         i == Xsand_stonein_3  ? j + 16 :
+                         i == Xsand_stonein_4  ? j + 24 :
+                         i == Xsand_stoneout_2 ? j + 8 : j) + 1;
        int step = (is_backside ? step_frame : num_steps - step_frame);
 
        if (is_backside)        /* tile where movement starts */
@@ -6081,77 +5677,15 @@ void InitGraphicInfo_EM(void)
        g_em->height = TILEY - cy * step;
       }
 
-#if 0
-      if (effective_action == ACTION_SMASHED_BY_ROCK &&
-         element_info[effective_element].graphic[effective_action] ==
-         element_info[effective_element].graphic[ACTION_DEFAULT])
-      {
-       int move_dir = MV_DOWN;
-       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 num_steps = 8;
-       int cx = ABS(dx) * (TILEX / num_steps);
-       int cy = ABS(dy) * (TILEY / num_steps);
-       int step_frame = j + 1;
-       int step = (is_backside ? step_frame : num_steps - step_frame);
-
-       graphic = (el_act_dir2img(EL_ROCK, ACTION_FALLING, MV_DOWN));
-       g = &graphic_info[graphic];
-       sync_frame = j;
-       frame = getAnimationFrame(g->anim_frames,
-                                 g->anim_delay,
-                                 g->anim_mode,
-                                 g->anim_start_frame,
-                                 sync_frame);
-       getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y,
-                           g->double_movement && is_backside);
-
-       g_em->bitmap = src_bitmap;
-       g_em->src_x = src_x;
-       g_em->src_y = src_y;
-       g_em->src_offset_x = 0;
-       g_em->src_offset_y = 0;
-       g_em->dst_offset_x = 0;
-       g_em->dst_offset_y = 0;
-
-       if (is_backside)        /* tile where movement starts */
-       {
-         if (dx < 0 || dy < 0)
-         {
-           g_em->src_offset_x = cx * step;
-           g_em->src_offset_y = cy * step;
-         }
-         else
-         {
-           g_em->dst_offset_x = cx * step;
-           g_em->dst_offset_y = cy * step;
-         }
-       }
-       else                    /* tile where movement ends */
-       {
-         if (dx < 0 || dy < 0)
-         {
-           g_em->dst_offset_x = cx * step;
-           g_em->dst_offset_y = cy * step;
-         }
-         else
-         {
-           g_em->src_offset_x = cx * step;
-           g_em->src_offset_y = cy * step;
-         }
-       }
-
-       g_em->width  = TILEX - cx * step;
-       g_em->height = TILEY - cy * step;
-
-#if 0
-       printf("::: -> '%s'\n", element_info[effective_element].token_name);
-#endif
-      }
-#endif
-
-#endif
-
+#if 1
+      /* create unique graphic identifier to decide if tile must be redrawn */
+      /* bit 31 - 16 (16 bit): EM style graphic
+        bit 15 - 12 ( 4 bit): EM style frame
+        bit 11 -  6 ( 6 bit): graphic width
+        bit  5 -  0 ( 6 bit): graphic height */
+      g_em->unique_identifier =
+       (graphic << 16) | (frame << 12) | (g_em->width << 6) | g_em->height;
+#else
       /* create unique graphic identifier to decide if tile must be redrawn */
       /* bit 31 - 16 (16 bit): EM style element
         bit 15 - 12 ( 4 bit): EM style frame
@@ -6159,8 +5693,22 @@ void InitGraphicInfo_EM(void)
         bit  5 -  0 ( 6 bit): graphic height */
       g_em->unique_identifier =
        (i << 16) | (j << 12) | (g_em->width << 6) | g_em->height;
+#endif
+
+#if 0
+      if (effective_element == EL_ROCK)
+       printf("::: EL_ROCK(%d, %d): %d, %d => %d\n",
+              effective_action, j, graphic, frame, g_em->unique_identifier);
+#endif
 
 #if DEBUG_EM_GFX
+
+#if 1
+      /* skip check for EMC elements not contained in original EMC artwork */
+      if (element == EL_EMC_FAKE_ACID)
+       continue;
+#endif
+
       if (g_em->bitmap != debug_bitmap ||
          g_em->src_x != debug_src_x ||
          g_em->src_y != debug_src_y ||
@@ -6217,27 +5765,44 @@ void InitGraphicInfo_EM(void)
          printf("    %d (%d): size %d,%d should be %d,%d\n",
                 j, is_backside,
                 g_em->width, g_em->height, TILEX, TILEY);
+
+       num_em_gfx_errors++;
       }
 #endif
 
     }
   }
 
-#if 1
   for (i = 0; i < TILE_MAX; i++)
   {
     for (j = 0; j < 8; j++)
     {
       int element = object_mapping[i].element_rnd;
       int action = object_mapping[i].action;
+      int direction = object_mapping[i].direction;
+      boolean is_backside = object_mapping[i].is_backside;
+#if 1
+      int graphic_action  = el_act_dir2img(element, action, direction);
+      int graphic_default = el_act_dir2img(element, ACTION_DEFAULT, direction);
+#else
+      int graphic_action  = element_info[element].graphic[action];
+      int graphic_default = element_info[element].graphic[ACTION_DEFAULT];
+#endif
 
-      if (action == ACTION_SMASHED_BY_ROCK &&
-         element_info[element].graphic[action] ==
-         element_info[element].graphic[ACTION_DEFAULT])
+      if ((action == ACTION_SMASHED_BY_ROCK ||
+          action == ACTION_SMASHED_BY_SPRING ||
+          action == ACTION_EATING) &&
+         graphic_action == graphic_default)
       {
+       int e = (action == ACTION_SMASHED_BY_ROCK   ? Ystone_s  :
+                action == ACTION_SMASHED_BY_SPRING ? Yspring_s :
+                direction == MV_LEFT  ? (is_backside? Yspring_wB: Yspring_w) :
+                direction == MV_RIGHT ? (is_backside? Yspring_eB: Yspring_e) :
+                Xspring);
+
        /* no separate animation for "smashed by rock" -- use rock instead */
        struct GraphicInfo_EM *g_em = &graphic_info_em_object[i][7 - j];
-       struct GraphicInfo_EM *g_xx = &graphic_info_em_object[Ystone_s][7 - j];
+       struct GraphicInfo_EM *g_xx = &graphic_info_em_object[e][7 - j];
 
        g_em->bitmap            = g_xx->bitmap;
        g_em->src_x             = g_xx->src_x;
@@ -6248,14 +5813,17 @@ void InitGraphicInfo_EM(void)
        g_em->dst_offset_y      = g_xx->dst_offset_y;
        g_em->width             = g_xx->width;
        g_em->height            = g_xx->height;
+#if 1
+       g_em->unique_identifier = g_xx->unique_identifier;
+#endif
 
-       g_em->preserve_background = TRUE;
+       if (!is_backside)
+         g_em->preserve_background = TRUE;
       }
     }
   }
-#endif
 
-  for (p = 0; p < 2; p++)
+  for (p = 0; p < MAX_PLAYERS; p++)
   {
     for (i = 0; i < SPR_MAX; i++)
     {
@@ -6267,7 +5835,7 @@ void InitGraphicInfo_EM(void)
       {
        int effective_element = element;
        int effective_action = action;
-       int graphic = (direction == MV_NO_MOVING ?
+       int graphic = (direction == MV_NONE ?
                       el_act2img(effective_element, effective_action) :
                       el_act_dir2img(effective_element, effective_action,
                                      direction));
@@ -6291,7 +5859,6 @@ void InitGraphicInfo_EM(void)
 
        getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x,&src_y, FALSE);
 
-#if 1
        g_em->bitmap = src_bitmap;
        g_em->src_x = src_x;
        g_em->src_y = src_y;
@@ -6301,9 +5868,16 @@ void InitGraphicInfo_EM(void)
        g_em->dst_offset_y = 0;
        g_em->width  = TILEX;
        g_em->height = TILEY;
-#endif
 
 #if DEBUG_EM_GFX
+
+#if 1
+       /* skip check for EMC elements not contained in original EMC artwork */
+       if (element == EL_PLAYER_3 ||
+           element == EL_PLAYER_4)
+         continue;
+#endif
+
        if (g_em->bitmap != debug_bitmap ||
            g_em->src_x != debug_src_x ||
            g_em->src_y != debug_src_y)
@@ -6339,6 +5913,8 @@ void InitGraphicInfo_EM(void)
                   g_em->src_x / 32, g_em->src_y / 32,
                   debug_src_x, debug_src_y,
                   debug_src_x / 32, debug_src_y / 32);
+
+         num_em_gfx_errors++;
        }
 #endif
 
@@ -6347,6 +5923,66 @@ void InitGraphicInfo_EM(void)
   }
 
 #if DEBUG_EM_GFX
+  printf("\n");
+  printf("::: [%d errors found]\n", num_em_gfx_errors);
+
   exit(0);
 #endif
 }
+
+void PlayMenuSound()
+{
+  int sound = menu.sound[game_status];
+
+  if (sound == SND_UNDEFINED)
+    return;
+
+  if ((!setup.sound_simple && !IS_LOOP_SOUND(sound)) ||
+      (!setup.sound_loops && IS_LOOP_SOUND(sound)))
+    return;
+
+  if (IS_LOOP_SOUND(sound))
+    PlaySoundLoop(sound);
+  else
+    PlaySound(sound);
+}
+
+void PlayMenuSoundStereo(int sound, int stereo_position)
+{
+  if (sound == SND_UNDEFINED)
+    return;
+
+  if ((!setup.sound_simple && !IS_LOOP_SOUND(sound)) ||
+      (!setup.sound_loops && IS_LOOP_SOUND(sound)))
+    return;
+
+  if (IS_LOOP_SOUND(sound))
+    PlaySoundExt(sound, SOUND_MAX_VOLUME, stereo_position, SND_CTRL_PLAY_LOOP);
+  else
+    PlaySoundStereo(sound, stereo_position);
+}
+
+void PlayMenuSoundIfLoop()
+{
+  int sound = menu.sound[game_status];
+
+  if (sound == SND_UNDEFINED)
+    return;
+
+  if ((!setup.sound_simple && !IS_LOOP_SOUND(sound)) ||
+      (!setup.sound_loops && IS_LOOP_SOUND(sound)))
+    return;
+
+  if (IS_LOOP_SOUND(sound))
+    PlaySoundLoop(sound);
+}
+
+void PlayMenuMusic()
+{
+  int music = menu.music[game_status];
+
+  if (music == MUS_UNDEFINED)
+    return;
+
+  PlayMusic(music);
+}
index f41b0f83308646597b2ce278531ed6bb77c087ca..f77a594acf99ef1da2b5670b47e8a1ca022a696c 100644 (file)
@@ -15,6 +15,7 @@
 #define TOOLS_H
 
 #include "main.h"
+#include "game.h"
 
 /* for SetDrawtoField */
 #define DRAW_DIRECT            0
@@ -45,8 +46,9 @@
 #define DOOR_COPY_BACK         (1 << 4)
 #define DOOR_NO_COPY_BACK      (1 << 5)
 #define DOOR_NO_DELAY          (1 << 6)
-#define DOOR_GET_STATE         (1 << 7)
-#define DOOR_SET_STATE         (1 << 8)
+#define DOOR_FORCE_REDRAW      (1 << 7)
+#define DOOR_GET_STATE         (1 << 8)
+#define DOOR_SET_STATE         (1 << 9)
 
 /* for Request */
 #define REQ_ASK                        (1 << 0)
@@ -64,7 +66,13 @@ void SetDrawtoField(int);
 void RedrawPlayfield(boolean, int, int, int, int);
 void BackToFront();
 void FadeToFront();
+
+void FadeIn(int);
+void FadeOut(int, int);
+void FadeCross(int);
+
 void ClearWindow();
+void SetMainBackgroundImageIfDefined(int);
 void SetMainBackgroundImage(int);
 void SetDoorBackgroundImage(int);
 void DrawBackground(int, int, int, int);
@@ -138,6 +146,11 @@ void FreeToolButtons();
 
 int map_element_RND_to_EM(int);
 int map_element_EM_to_RND(int);
+int map_direction_RND_to_EM(int);
+int map_direction_EM_to_RND(int);
+
+void map_android_clone_elements_RND_to_EM(struct LevelInfo *);
+void map_android_clone_elements_EM_to_RND(struct LevelInfo *);
 
 int get_next_element(int);
 int el_act_dir2img(int, int, int);
@@ -147,8 +160,14 @@ int el2baseimg(int);
 int el2img(int);
 int el2edimg(int);
 int el2preimg(int);
+int font2baseimg(int);
 
 unsigned int InitRND(long);
 void InitGraphicInfo_EM(void);
 
+void PlayMenuSound();
+void PlayMenuSoundStereo(int, int);
+void PlayMenuSoundIfLoop();
+void PlayMenuMusic();
+
 #endif /* TOOLS_H */