Merge branch 'master' into releases 3.1.0
authorHolger Schemel <info@artsoft.org>
Sat, 30 Aug 2014 08:47:19 +0000 (10:47 +0200)
committerHolger Schemel <info@artsoft.org>
Sat, 30 Aug 2014 08:47:19 +0000 (10:47 +0200)
45 files changed:
CHANGES
ChangeLog [new file with mode: 0644]
Makefile
src/Makefile
src/conf_e2g.c
src/conf_e2s.c
src/conf_esg.c
src/conf_gfx.c
src/conf_gfx.h
src/conf_grp.c [new file with mode: 0644]
src/conf_grp.h [new file with mode: 0644]
src/conf_hlp.c
src/conftime.h
src/editor.c
src/editor.h
src/events.c
src/files.c
src/files.h
src/game.c
src/game.h
src/init.c
src/init.h
src/libgame/gadgets.c
src/libgame/image.c
src/libgame/misc.c
src/libgame/misc.h
src/libgame/platform.h
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/x11.c
src/libgame/x11.h
src/main.c
src/main.h
src/netserv.c
src/netserv.h
src/network.c
src/screens.c
src/tape.c
src/tape.h
src/tools.c
src/tools.h

diff --git a/CHANGES b/CHANGES
index f8bad85919f05832bae9379472b28d6114b2948e..05c4210e16823f000b6e789a30f6e22a8aff7614 100644 (file)
--- a/CHANGES
+++ b/CHANGES
@@ -1,15 +1,36 @@
+Release Version 3.1.0 [07 JUN 2004]
+-----------------------------------
+       - fixed obvious bug with wrong "Murphy" graphics (when digging etc.)
+       - fixed a lot of Emerald Mine and Supaplex game engine emulation bugs
+       - re-converted Emerald Mine and Supaplex levels to apply engine fixes
+       - changed default snap/drop keys from left/right Shift to Control keys
+       - added level loader for loading native Emerald Mine levels
+       - added level loader for loading native Supaplex packed levels
+       - added group elements for multiple matches and random element creation
+       - added elements that can be digged or left behind by custom elements
+       - added element "Sokoban field with player" missing for Sokoban levels
+       - added custom element features to allow building of teleporters
+       - added option to use step limit instead of time limit for level
+       - added pressing "space" key as valid action to select menu options
+       - added clipboard (cut and paste buttons) for custom and group elements
+       - added shortcut to dump brush (type ":DB" in editor) for use in forum
+       - added network multiplayer code for Windows (still only command line)
+       - replaced old tutorial level set with far better one by Niko Böhm
+       - "contributions" levels now separate package to make base set smaller
+       - too many bugfixes and changes to list them all here (see ChangeLog)
+
 Release Version 3.0.8 [14 DEC 2003]
 -----------------------------------
        - added "musicinfo.conf" for menu and level music configuration
        - added "editorsetup.conf" for editor element list configuration
        - added "copy" and "exchange" functions for custom elements to editor
        - added configurable "bored" and "sleeping" animations for the player
-       - added "awakening" sound for player waking up after sleeping
+       - added "awakening" sound for player when waking up after sleeping
        - added configurable element animations for info screen
        - added configurable music credits for info screen
        - added configurable level set information for info screen
        - added warnings for undefined token values in artwork config files
-       - menu text now directly clickable
+       - menu entries now also selectable by clicking on entry text
        - better sniksnak turning movement (two steps instead of only one)
        - fixed turning movement of butterflies and fireflies (no frame reset)
        - fixed bug with wrong default impact sound for colored emeralds
diff --git a/ChangeLog b/ChangeLog
new file mode 100644 (file)
index 0000000..0e83674
--- /dev/null
+++ b/ChangeLog
@@ -0,0 +1,831 @@
+2004-06-07
+       * fixed bug with crash when writing user levelinfo.conf the first time
+
+2004-06-06
+       * added option "convert LEVELDIR [NR]" to command line batch commands
+       * re-converted Supaplex levels to apply latest engine fixes
+       * changed "use graphic/sound of element" to "use graphic of element"
+         due to compatibility problems with some levels ("bug machine" etc.)
+
+2004-05-23
+       * fixed bug with CE change replacing player with same or other player
+
+2004-05-16
+       * fixed bug with opaque font in envelope with background graphic when
+         background graphic is not transparent itself
+
+2004-05-12
+       * added "gravity on" and "gravity off" ports for Supaplex compatibility
+       * corrected original Supaplex level loading code to use these new ports
+       * also corrected Supaplex loader to auto-count infotrons if set to zero
+
+2004-05-10
+       * fixed bug with missing initialization of "modified" flag for GEs
+
+2004-05-09
+       * fixed bug that caused endless recursion loop when relocating player
+       * fixed tape recorder bug in "step mode" when using "pause before end"
+       * fixed tape recorder bug when changing from "warp forward" mode
+
+2004-05-08
+       * fixed bug with "when touching" for pushed elements at last position
+
+2004-05-05
+       * fixed bug that caused two activated toolbox buttons in level editor
+       * fixed bug with exploding dynabomb under player due to other explosion
+
+2004-05-02
+       * fixed bug with creating walkable custom element under player (again)
+       * fixed bug with not copying explosion type when copying CEs in editor
+       * fixed graphical bug when drawing player in setup menu (input devices)
+       * fixed graphical bug when the player is pushing an accessible element
+       * fixed bug with classic switchable elements triggering CE changes
+       * fixed bug with entering/leaving walkable element in RelocatePlayer()
+       * fixed crash bug when CE leaves behind the trigger player element
+
+2004-04-30
+       * fixed bug with broken tubes after placing/exploding dynamite in them
+       * fixed bug with exploding dynamite under player due to other explosion
+       * fixed bug with not resetting push delay under certain circumstances
+
+2004-04-27
+       * added option "handicap" for "levelinfo.conf" (thanks to Niko Böhm)
+       * added network multiplayer code for Windows (thanks to Niko Böhm)
+
+2004-04-25
+       * added option "reachable despite gravity" for gravity movement
+       * changed gravity movement of most classic walkable and passable
+         elements back to "not reachable" (for compatibility reasons)
+
+2004-04-24
+       * fixed (removed) "indestructible" / "can explode" dependency in editor
+       * fixed (removed) "accessible inside" / "protected" dependency
+       * fixed (removed) "step mode" / "shield time" dependency
+
+2004-04-23
+       * fixed dynabombs exploding now into anything diggable
+       * fixed Supaplex style gravity movement into buggy base now impossible
+       * added pressing key "space" as valid action to select menu options
+
+2004-04-20
+       * added "replace when walkable" to relocate player to walkable element
+       * added "enter"/"leave" event for elements affected by relocation
+       * fixed "direct"/"indirect" change order also for "when change" event
+       * fixed graphical bug when pushing things from elements walkable inside
+
+2004-04-18
+       * fixed graphic bug when player is snapping while moving in old levels
+       * fixed bug when a moving custom element leaves a player element behind
+       * fixed bug with mole not disappearing when moving into acid pool
+       * fixed bug with incomplete path setting when using "--basepath" option
+       * moving CE can now leave walkable elements behind under the player
+       * when relocating, player can be set on walkable element now
+       * fixed another gravity movement bug
+
+2004-04-12
+       * uploaded pre-release (test) version 3.1.0-2 binary and source code
+
+2004-04-10
+       * added "collectible" and "removable" to extended replacement types
+         (where "removable" replaces "diggable" and "collectible" elements)
+       * added "collectible & throwable" (to throw element to the next field)
+       * fixed bug with CEs digging elements that are just about to explode
+       * changed mouse cursor now always being visible when game is paused
+
+2004-04-09
+       * added possibility to push/press accessible elements from a side that
+         is not accessible
+       * fixed bug with not setting actual date when appending to tape
+
+2004-04-07
+       * fixed bug with incorrectly initialized custom element editor graphics
+
+2004-04-04
+       * corrected set "Contributions_1995-2000/rnd_kjell_kristiansson":
+         - number of levels corrected from 18 to 17 in "levelinfo.conf"
+
+2004-03-31
+       * fixed bug with destroyed robot wheel still attracting robots forever
+       * fixed bug with time gate switch deactivating after robot wheel time
+         (while the time gate itself is not affected by this misbehaviour)
+       * changed behaviour of BD style amoeba to always get blocked by player
+         (before it was different when there were non-BD elements in level)
+       * fixed bug with player destroying indestructable elements with shield
+
+2004-03-26
+       * added option to make growing elements grow into anything diggable
+         (for the various amoeba types, biomaze and "game of life")
+
+2004-03-24
+       * fixed bug with movable elements not moving after left behind by CEs
+       * changed gravity movement to anything diggable, not only sand/base
+       * optionally allowing passing to walkable element, not only empty space
+       * added option "can pass to walkable element" for players
+       * finally fixed gravity movement (hopefully)
+
+2004-03-23
+       * fixed bug with movable elements not moving anymore after falling down
+
+2004-03-22
+       * fixed another bug with custom elements digging and leaving elements
+       * fixed bug with "along left/right side" and automatic start direction
+       * trigger elements now also displayed when "more custom" deactivated
+       * fixed bug with clipboard element initialized when loading new level
+       * added option "drop delay" to set delay before dropping next element
+
+2004-03-21
+       * uploaded pre-release (test) version 3.1.0-1 binary and source code
+
+2004-03-20
+       * added copy and paste functions for custom change pages
+       * enhanced graphical display and functionality of tape recorder
+       * fixed bug with custom elements digging and leaving elements
+
+2004-03-19
+       * added move speed faster than "very fast" for custom elements
+       * fixed bug with 3+3 style explosions and missing border content
+       * fixed little bug when copying custom elements in the editor
+       * enhanced custom element changes by more side trigger actions
+
+2004-03-16
+       * added option "no scrolling when relocating" for instant teleporting
+       * uploaded pre-release (test) version 3.1.0-0 binary and source code
+
+2004-03-15
+       * added trigger element and trigger player to use as target elements
+       * added copy and paste functions for custom and group elements
+
+2004-03-14
+       * fixed graphical bug when displaying explosion animations
+       * fixed bug when appending to tapes, resulting in broken tapes
+       * re-recorded a few tapes broken by fixing gravity checking bug
+
+2004-03-13
+       * "can move into acid" property now for all elements independently
+       * "can fall into acid" property for player stored in same bitfield now
+       * added option for deadliness of Supaplex 'sniksnak' and 'electron'
+       * version number set to 3.1.0 (finally!)
+
+2004-03-09
+       * changed tape recording to only record input, not programmed actions
+
+2004-03-08
+       * fixed totally broken (every 8th frame skipped) step-by-step recording
+       * fixed bug with requester not displayed when quick-loading interrupted
+       * added option "can fall into acid (with gravity)" for players
+       * fixed bug with player not falling when snapping down with gravity
+
+2004-03-07
+       * fixed bug which messed up key config when using keypad number keys
+
+2004-03-03
+       * fixed bug which allowed moving upwards even when gravity was active
+       * fixed bug with missing error handling when dumping levels or tapes
+
+2004-03-02
+       * added different colored editor graphics for Supaplex gravity tubes
+
+2004-03-01
+       * fixed bug that allowed solvable tapes for unsolvable levels
+
+2004-02-28
+       * use unlimited number of droppable elements when "count" set to zero
+       * added option to use step limit instead of time limit for level
+
+2004-02-27
+       * added player and change page as trigger for custom element change
+
+2004-02-24
+       * fixed bug with exploding amoeba (explosion 3x3 instead of 1x1)
+
+2004-02-22
+       * fixed bug with dark yamyam changing to acid when moving over acid
+       * fixed handling of levels with more than 999 seconds level time
+         (example: level 76 of "Denmine")
+
+2004-02-21
+       * "spring push bug" reintroduced as configurable element property
+       * fixed bug with missing properties for "mole"
+       * fixed bug that showed up when fixing the above "mole" properties bug
+       * added option "can move into acid" for all movable elements
+       * fixed graphical bug for elements moving into acid
+       * changed event handling to handle all pending events before going on
+
+2004-02-17
+       * fixed bug which caused all CE change pages to be ignored which had
+         the same change event, but used a different element side
+         (reported by Simon Forsberg)
+
+       * fixed bug which caused elements that can move and fall and that are
+         transported by a conveyor belt to continue moving into that direction
+         after leaving the conveyor belt, regardless of their own movement
+         type; only elements which can not move are transported now
+         (reported by Simon Forsberg)
+
+       * fixed bug which could cause an array overflow in RelocatePlayer()
+         (reported by Niko Böhm)
+
+       * changed Emerald Mine style "passable / over" elements to "protected"
+         (fixing unsolvable level 10 of "Bondmine 9" with bug beside gate)
+
+       * added new option to select from which side a "walkable/passable"
+         element can be entered
+
+2004-02-16
+       * added explosion and ignition delay for elements that can explode
+
+2004-02-05
+       * fixed bug which caused player not being protected against enemies
+         when a CE was "walkable / inside" and was not "indestructible"
+       * added "walkable/passable" fields to be "protected/unprotected"
+         against enemies, even if not accessible "inside" but "over/under"
+
+2004-02-04
+       * corrected move pattern to 32 bit and initial move direction to 8 bit
+
+2004-02-03
+       * added second custom element base configuration page
+
+2004-02-02
+       * added some special EMC mappings to Emerald Mine level loader
+         (also covering previously unknown element in level 0 of "Bondmine 8")
+
+2004-01-30
+       * added option to block last field when player is moving (for Supaplex)
+       * adjusted push delay of Supaplex elements
+       * removed delays for envelopes etc. when replaying with maximum speed
+       * fixed bug when dropping element on a field that just changed to empty
+
+2004-01-29
+       * fixed bug: infotrons can now smash yellow disks
+       * fixed bug: when gravity active, port above player can now be entered
+       * removed "one white dot" mouse pointer which irritated some people
+
+2004-01-26
+       * added "choice type" for group element selection
+
+2004-01-25
+       * fixed bug with initial invulnerability of non-yellow player
+
+2004-01-23
+       * added level loader for loading native Supaplex packed levels
+         (including multi-part levels like the "splvls99" levels)
+
+2004-01-19
+       * fixed bug which allowed creating emeralds by escaping explosions
+
+2004-01-18
+       * custom elements can change (limited) or leave (unlimited) elements
+       * finally added multiple matches using group elements
+       * added shortcut to dump brush (type ":DB" in editor) for use in forum
+
+2004-01-17
+       * added new start movement type "previous" for continued CE movement
+       * added new start movement type "random" for random CE movement start
+
+2004-01-17
+       * added new element "sokoban_field_player" needed for Sokoban levels
+         (thanks to Ed Booker for pointing this out!)
+
+2004-01-15
+       * added elements that can be digged or left behind by custom elements
+
+2004-01-12
+       * added group elements for multiple matches and random element creation
+
+2004-01-11
+       * fixed some graphical errors displayed in old levels
+
+2004-01-10
+       * fixed wrong double speed movement after passing closing gates
+
+2004-01-03
+       * added level loader for loading native Emerald Mine levels
+
+2004-01-02
+       * changes for "shooting" style CE movement
+
+2004-01-01
+       * Happy New Year! ;-)
+
+2003-12-27
+       * changed default snap/drop keys from left/right Shift to Control keys
+
+2003-12-27
+       * fixed bug with dead player getting reanimated from custom element
+
+2003-12-14
+       * fixed bug with wrong penguin graphics (when entering exit)
+
+2003-12-14
+       * fixed bug with wrong "Murphy" graphics (when digging etc.)
+
+2003-12-14
+       * version number set to 3.0.9
+
+2003-12-14
+       * version 3.0.8 released
+
+2003-12-13
+       * added function checked_free()
+
+2003-12-13
+       * fixed bug with double nut cracking sound
+         (by eliminating "default element action sound" assignment in init.c)
+
+2003-12-10
+       * fixed crash when no music info files are available
+
+2003-12-07
+       * fixed boring and sleeping sounds
+
+2003-12-05
+       * added "maze runner" and "maze hunter" movement types
+       * added extended collision conditions for custom elements
+
+2003-12-03
+       * added warnings for undefined token values in artwork config files
+
+2003-12-02
+       * added menu entry for level set information to the info screen
+
+2003-12-02
+       * fixed bug with wrong default impact sound for colored emeralds
+
+2003-11-30
+       * added several sub-screens for the info screen
+       * menu text now also clickable (not only blue/red sphere left of it)
+
+2003-11-25
+       * added configurable "bored" and "sleeping" animations for the player
+       * added "awakening" sound for player when waking up after sleeping
+
+2003-11-22
+       * added "copy" and "exchange" functions for custom elements to editor
+
+2003-11-21
+       * added configurable element animations for info screen
+
+2003-11-20
+       * added configurable music credits for info screen
+
+2003-11-19
+       * finally fixed tape recording when player is created from CE change
+
+2003-11-18
+       * added "editorsetup.conf" for editor element list configuration
+
+2003-11-16
+       * added "musicinfo.conf" for menu and level music configuration
+
+2003-11-14
+       * fixed a very nasty bug in dragon turning code in TurnRoundExt()
+         (that only showed up on Linux, but not on Windows systems)
+
+2003-11-13
+       * fixed turning movement of butterflies and fireflies (no frame reset)
+       * enhanced sniksnak turning movement (two steps instead of only one)
+
+2003-11-10
+       * version number set to 3.0.8
+
+2003-11-10
+       * version 3.0.7 released
+
+2003-11-09
+       * fixed reset of player animation frame when, for example,
+         walking, digging or collecting share the same animation
+       * fixed CE with "deadly when touching" exploding when touching amoeba
+
+2003-11-08
+       * fixed tape recording when player is created from CE element change
+
+2003-11-04
+       * introduced "turning..." action graphic for elements with move delay
+         (non-CE: bug, spaceship, sniksnak, mole, pacman, yamyam)
+       * added turning animations for bug, spaceship and sniksnak
+
+2003-11-03
+       * prevent "extended" changed elements from delay change in same frame
+
+2003-11-02
+       * fixed bug when pushing element that can move away to the side
+         (like pushing falling elements, but now with moving elements)
+
+2003-11-01
+       * finally fixed serious bug in code for delayed element pushing (again)
+
+2003-10-19
+       * unavailable setup options now marked as "n/a" instead of "off"
+       * new boolean directive "latest_engine" for "levelinfo.conf": when set
+         to "true", levels are always played with the latest game engine,
+         which is desired for levels that are imported from other games; all
+         other levels are played with the engine version stored in level file
+         (which is normally the engine version the level was created with)
+
+2003-10-18
+       * fixed serious bug in code for delayed element pushing
+       * fixed little bug in animation frame selection for pushed elements
+       * speed-up of reading config file for verbose output
+
+2003-10-08
+       * added configuration option for opening and closing Supaplex exit
+       * added configuration option for moving up/down animation for Murphy
+       * fixed incorrectly displayed animation for attacking dragon
+       * fixed bug with not setting initial gravity for each new game
+       * fixed bug with teleportation of player by custom element change
+       * fixed bug with player not getting smashed by rock sometimes
+
+2003-10-06
+       * version number set to 3.0.7
+
+2003-10-06
+       * version 3.0.6 released
+
+2003-10-05
+       * added support for MP3 music for SDL version through SMPEG library
+
+2003-10-03
+       * fixed bug when initializing font graphic structure
+       * fixed bug with animation mode "pingpong" when using only 1 frame
+       * fixed bug with extended change target introduced in 3.0.5
+       * fixed bug where passing over moving element doubles player speed
+       * fixed bug with elements continuing to move into push direction
+       * fixed bug with duplicated player when dropping bomb with shield on
+       * added "switching" event for custom elements ("pressing" only once)
+       * fixed switching bug (resetting flag when not switching but not idle)
+
+2003-09-29
+       * fixed element tokens for certain file elements with ".active" etc.
+
+2003-09-29
+       * version number set to 3.0.6
+
+2003-09-29
+       * version 3.0.5 released
+
+2003-09-28
+       * now four envelope elements available
+       * font, background, animation and sound for envelope now configurable
+       * main menu doors opening/closing animation type now configurable
+
+2003-09-27
+       * active/inactive sides configurable for custom element changes
+       * new movement type "move when pushed" available for custom elements
+
+2003-09-20
+       * fixed bug in multiple config pages loader code that caused crashes
+
+2003-09-13
+       * enhanced (remaining low-resolution) Supaplex graphics
+
+2003-09-13
+       * version number set to 3.0.5
+
+2003-09-13
+       * version 3.0.4 released
+
+2003-09-12     src/tools.c
+       * fixed bug in custom definition of crumbled element graphics
+
+2003-09-11     src/files.c
+       * fixed bug in multiple config pages code that caused crashes
+
+2003-09-08
+       * version number set to 3.0.4
+
+2003-09-08
+       * version 3.0.3 released
+
+2003-09-07
+       * added music to Supaplex classic level set
+
+2003-09-07     src/libgame/misc.c
+       * added support for loading various music formats through SDL_mixer
+
+2003-09-06     (various source files)
+       * fixed several nasty bugs that may have caused crashes on some systems
+       * added envelope content which gets displayed when collecting envelope
+       * added multiple change event pages for custom elements
+
+2003-08-24     src/game.c
+       * fixed problem with player animation when snapping and moving
+
+2003-08-23     src/screens.c, src/cartoons.c, src/libgame/toons.c
+       * fixed problem with flickering when drawing toon animations
+
+2003-08-23     src/libgame/sdl.c
+       * fixed problem with setting mouse cursor in SDL version in fullscreen
+
+2003-08-23     src/game.c
+       * fixed bug (missing array boundary check) which could crash the game
+
+2003-08-23
+       * version number set to 3.0.3
+
+2003-08-22
+       * version 3.0.2 released
+
+2003-08-21     src/game.c
+       * fixed bug with creating inaccessible elements at player position
+
+2003-08-20     src/init.c
+       * fixed bug with not finding current level artwork directory
+
+2003-08-20     src/files.c
+       * fixed bug with choosing wrong engine version when playing tapes
+       * fixed bug with messing up custom element properties in 3.0.0 levels
+
+2003-08-18
+       * version number set to 3.0.2
+
+2003-08-18
+       * version 3.0.1 released
+
+2003-08-17     (no source files affected)
+       * changed all "classic" PCX image files with 16 colors or less to
+         256 color (8 bit) storage format, because the Allegro game library
+         cannot handle PCX files with less than 256 colors (contributed
+         graphics are not affected and might look wrong in the DOS version)
+
+2003-08-16     src/init.c
+       * fixed bug which (for example) crashed the level editor when defining
+         "dynamite.EDITOR:  [NONE]", because graphics may not be undefined
+         (only set to default) -- invalid graphics now set to default graphic
+
+2003-08-16     src/init.c
+       * fixed graphical bug of player digging/collecting/snapping element
+         when no corresponding graphic/animation is defined for this action,
+         resulting in player being drawn as EL_EMPTY (which should only be
+         done to elements being collected, but not to the player)
+
+2003-08-16     src/game.c
+       * fixed small graphical bug of player not totally moving into exit
+
+2003-08-16     src/libgame/setup.c
+       * fixed bug with wrong MS-DOS 8.3 filename conversion
+
+2003-08-16     src/tools.c
+       * fixed bug with invisible mouse cursor when pressing ESC while playing
+
+2003-08-16     (various source files)
+       * added another 128 custom elements (disabled in editor by default)
+
+2003-08-16     src/editor.c
+       * fixed NULL string bug causing Solaris to crash in sprintf()
+
+2003-08-16     src/screen.c
+       * fixed drawing over scrollbar on level selection with custom fonts
+
+2003-08-15     src/game.c
+       * cleanup of simple sounds / loop sounds / music settings
+
+2003-08-08     (various source files)
+       * added custom element property for dropping collected elements
+
+2003-08-08     src/conf_gfx.c
+       * fixed bug with missing graphic for active red disk bomb
+
+2003-08-07     src/files.c, src/editor.c src/game.c, src/main.h
+       * extended variable "level.gravity" to "level.initial_gravity" and
+         "game.current_gravity" to prevent level setting from being changed
+         by playing the level (keeping the runtime value after playing)
+
+       * fixed graphics bug when digging element that has 'crumbled' graphic
+         definition, but not 'diggable' graphic definition
+
+2003-08-06
+       * version number set to 3.0.1
+
+2003-08-05
+       * version 3.0.0 released
+
+2003-08-05
+       * various bug fixes; among others:
+         - fixed bug with pushing spring over empty space
+         - fixed bug with leaving tube while placing dynamite
+         - fixed bug with explosion of smashed penguins
+         - allow Murphy player graphic in levels with non-Supaplex elements
+
+2003-04-07
+       * various changes
+       * I have forgotten to document changes for some time
+
+2002-12-31
+       * pre-release version 2.2.0rc1 released
+
+2002-08-25
+       * version number set to 2.1.2
+
+2002-08-13
+       * version 2.1.1 released
+
+2002-08-10
+       * version number set to 2.1.1
+
+2002-08-05
+       * version 2.1.0 released
+       
+2002-05-19
+       * version number set to 2.1.0
+
+2002-04-03 to 2002-05-19       (various source files)
+       * graphics, sounds and music now fully configurable
+       * bug fixed that prevented walking through tubes when gravity on
+
+2002-04-02     src/events.c, src/editor.c
+       * Make Escape key less aggressive when playing or when editing level.
+         This can be configured as an option in the setup menu. (Default is
+         "less aggressive" which means "ask user if something can be lost"
+         when pressing the Escape key.)
+
+2002-04-02     src/screen.c
+       * Added "graphics setup" screen.
+
+2002-04-01     src/screen.c
+       * Changed "choose level" setup screen stuff to be more generic (to
+         make it easier to add more "choose from generic tree" setup screens).
+
+2002-04-01     src/config.c, src/timestamp.h
+       * Added source files "src/config.[ch]" and "src/timestamp.h" (which
+         automatically gets created by "src/Makefile" and contains an actual
+         compile-time timestamp to identify development versions of the game).
+
+2002-03-31     src/tape.c, src/events.c
+       * Added quick game/tape save/load functions to tape stuff which can be
+         invoked by a keyboard shortcut. Default: "F1" saves game/tape, "F2"
+         loads previously recorded tape and directly goes into recording mode
+         from the end of the tape (therefore appending to the tape).
+
+2002-03-31     src/tape.c
+       * Added "index mark" function to tape recorder. When playing or
+         recording, "eject" button changes to "index" button. Setting index
+         mark is not yet implemented, but pressing index button when playing
+         allows very quick advancing to end of tape (when normal playing),
+         very fast forward mode (when playing with normal fast forward) or
+         very fast reaching of "pause before end of tape" (when playing with
+         "pause before end" playing mode).
+
+2002-03-30     src/cartoons.c
+       * Moved some stuff from cartoons.c to the new "src/libgame/toons.c".
+
+2002-03-29     src/screen.c
+       * Changed setup screen stuff to be more generic (to make it easier
+         to add more setup screens).
+
+2002-03-23     src/main.c, src/main.h
+       * Various changes due to the introduction of the new libgame files
+         "setup.c" and "joystick.c".
+
+2002-03-23     src/files.c
+       * Generic parts of "src/files.c" (mainly setup and level directory
+         stuff) moved to new libgame file "src/libgame/setup.c".
+
+2002-03-23     src/joystick.c
+       * File "src/joystick.c" moved to libgame source tree, with
+         correspondig changes.
+
+2002-03-22     src/screens.c
+       * "HandleChooseLevel()": Another bug in level series navigation fixed.
+         (Wrong level series information displayed when entering main group.)
+
+2002-03-22     src/editor.c
+       * Slight change to support new gadget event "GD_EVENT_INFO_LEAVING".
+
+2002-03-22     src/editor.c
+       * Changed behaviour of "Escape" key in level editor to be more
+         intuitive: When in "Element Properties" or "Level Info" mode,
+         return to "Drawing Mode" instead of leaving the level editor.
+
+2002-03-21     src/game.c, src/editor.c, src/files.c
+       * 2.0.1 introduced the corrected "Emerald Mine" style behaviour of
+         gems (emeralds, diamonds, ...) slipping down from normal wall,
+         steel wall and growing wall (as in E.M.C. style levels). Although
+         the behaviour of contributed and private levels wasn't changed (due
+         to the use of "level.game_version"; see previous entry), editing
+         those levels will (of course) change the behaviour accordingly.
+
+         This change seems a bit too hard after thinking about it, because
+         the EM style behaviour is not the "expected" behaviour (gems would
+         normally only slip down from "rounded" walls). Therefore this was
+         now changed to an element property for gem style elements, with the
+         default setting "off" (which means: no special EM style behaviour).
+         To fix older converted levels, this flag is set to "on" for pre-2.0
+         levels that are neither contributed nor private levels.
+
+2002-03-20     src/files.h
+       * Corrected settings for "level.game_version" depending of level type.
+         (Contributed and private levels always get played with game engine
+         version they were created with, while converted levels always get
+         played with the most recent version of the game engine, to let new
+         corrections of the emulation behaviour take effect.)
+
+2002-03-20     src/main.h
+       * Added "#include <time.h>". This seems to be needed by "tape.c" for
+         compiling the SDL version on some systems.
+         Thanks to the several people who pointed this out.
+
+2002-03-19
+       * Version number set to 2.0.2.
+
+2002-03-19
+       * Version 2.0.1 released.
+
+2002-03-18     src/screens.c
+       * "HandleChooseLevel()": Small bug in level series navigation fixed.
+
+2002-03-18     src/files.c [src/libgame/misc.c]
+       * Moved some common functions from src/files.c to src/libgame/misc.c.
+
+2002-03-18     src/files.c [src/libgame/misc.c]
+       * Changed permissions for new directories and saved files (especially
+         score files) according to suggestions of Debian users and mantainers.
+         Thanks to Drew Parsons <dparsons@emerall.com> for the patch.
+
+2002-03-17     src/files.c
+       * Changed "{Load|Save}{Level|Tape}()" to IFF style file format:
+         Replaced "cookie" header string ("ROCKSNDIAMONDS_...\n") with
+         real IFF style header "RND1....XXXX" (where "XXXX" is "CAVE"
+         for levels and "TAPE" for tapes). Old "cookie" style format is
+         still supported for reading. New level and tape files are written
+         in new format.
+
+       * New IFF chunk "VERS" contains version numbers for file and game
+         (where "game version" is the version of the program that wrote the
+         file, and "file version" is a version number to distinguish files
+         with different format, for example after adding new features).
+
+2002-03-15     src/screen.c
+       * "DrawHallOfFame()": "FadeSounds()" when entering the hall of fame.
+         (Before, you heard a mixture of the in-game music and the
+         hall-of-fame music.)
+
+2002-03-14     src/events.c
+       * Function "DumpTape()" (files.c) now available by pressing 't' from
+         main menu (when in DEBUG mode).
+
+2002-03-14     src/game.c
+       * "GameWon()": When game was won playing a tape, now there is no delay
+         raising the score and no corresponding sound is played.
+
+2002-03-14     src/files.c
+       * Changed "LoadTape()" for real chunk support and also adjusted
+         "SaveTape()" accordingly.
+
+2002-03-14     src/game.c, src/tape.c, src/files.c
+       * Important changes to tape format: The old tape format stored all
+         actions with a real effect with a corresponding delay between the
+         stored actions. This had some major disadvantages (for example,
+         push delays had to be ignored, pressing a button for some seconds
+         mutated to several single button presses because of the non-action
+         delays between two action frames etc.). The new tape format just
+         stupidly records all device actions and replays them later. I really
+         don't know why I haven't solved it that way before?! Old-style tapes
+         (with tape file version less than 2.0) get converted to the new
+         format on-the-fly when loading and can therefore still be played;
+         only some minor parts of the old-style tape handling code was needed.
+         (A perfect conversion is not possible, because there is information
+         missing about the device actions between two action frames.)
+
+2002-03-14     src/files.c
+       * New function "DumpTape()" to dump the contents of the current tape
+         in a human readable format.
+
+2002-03-14     src/game.c
+       * Small tape bug fixed: When automatically advancing to next level
+         after a game was won, the tape from the previous level still was
+         loaded as a tape for the new level.
+
+2002-03-14     src/tape.c
+       * Small graphical bug fixed: When pressing ""Record" or "Play" on
+         tape, cartoons did not get completely removed because
+         StopAnimation() was not called.
+
+2002-03-13     src/files.c
+       * Changed "LoadLevel()" and "SaveLevel()" to add new chunk "CNT2".
+         Fixed bug of "CONT" and "BODY" (chunk size was set to 8-bit element
+         size even when using 16-bit elements). Added new chunk "CNT2" for
+         16-bit amoeba content (previously written in 8-bit field in "HEAD"
+         chunk even when content was 16-bit element). "CNT2" should now be
+         able to store content for arbitrary elements (up to eight blocks of
+         3 x 3 element arrays). All "CNT2" elements will always be stored as
+         16-bit elements. "CONT" (with 8/16-bit elements) now obsolete.
+
+2002-03-13     src/files.c
+       * Changed "LoadLevel()" for real chunk support.
+
+2002-03-12     src/game.c
+       * Fixed problem (introduced after 2.0.0 release) with penguins
+         not getting killed by enemies
+
+2002-02-24     src/game.c, src/main.h
+       * Added "player->is_moving"; now "player->last_move_dir" does
+         not contain any information if the player is just moving at
+         the moment or not.
+         Before, "player->last_move_dir" was misused for this purpose
+         for  the robot stuff (robots don't kill players when they are
+         moving). But setting "player->last_move_dir" to MV_NO_MOVING
+         broke tapes when walking through pipes!
+         ("IS_MOVING()" uses "MovPos[][]", but this fails when it is 0
+         in a continuous movement. This fact is ignored for friends and
+         enemies, though.)
index 0c0c57f4b21fb887b3efdddc107a18ddf9ae26ef..9f1e23217da1495a982230cd6eeef1709feea2a5 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -79,6 +79,9 @@ mac:
 msdos:
        @$(MAKE_CMD) PLATFORM=msdos
 
+os2:
+       @$(MAKE_CMD) PLATFORM=os2
+
 cross-msdos:
        @PATH=$(CROSS_PATH_MSDOS)/bin:${PATH} $(MAKE_CMD) PLATFORM=cross-msdos
 
@@ -96,24 +99,27 @@ clean:
 auto-conf:
        @$(MAKE_CMD) auto-conf
 
-run:
-       @$(MAKE_CMD) TARGET=$(DEFAULT_TARGET) && ./rocksndiamonds --verbose
+run: all
+       @./rocksndiamonds --verbose
 
-gdb:
-       @$(MAKE_CMD) TARGET=$(DEFAULT_TARGET) && gdb ./rocksndiamonds
+gdb: all
+       @gdb ./rocksndiamonds
 
-valgrind:
-       valgrind -v --leak-check=yes ./rocksndiamonds 2> valgrind.out
+valgrind: all
+       @valgrind -v --leak-check=yes ./rocksndiamonds 2> valgrind.out
 
-enginetest:
+enginetest: all
        ./Scripts/make_enginetest.sh
 
-enginetestcustom:
+enginetestcustom: all
        ./Scripts/make_enginetest.sh custom
 
-enginetestfast:
+enginetestfast: all
        ./Scripts/make_enginetest.sh fast
 
+enginetestnew: all
+       ./Scripts/make_enginetest.sh new
+
 backup:
        ./Scripts/make_backup.sh src
 
index 05eccd9916ed18c56496318ab01a9216a5f4c6b0..53bf400347a1dfdcc27386b3194c2074be27344a 100644 (file)
@@ -22,7 +22,7 @@ ifdef X11_PATH                        # path to X11 specified by top level Makefile
 XINC_PATH = $(X11_PATH)/include
 XLIB_PATH = $(X11_PATH)/lib
 X11_INCL = -I$(XINC_PATH)
-X11_LIBS = -L$(XLIB_PATH)
+X11_LIBS = -L$(XLIB_PATH) -lX11
 endif
 
 AR = ar
@@ -55,7 +55,16 @@ endif
 
 ifeq ($(PLATFORM),macosx)
 PLATFORM = unix
-TARGET=sdl
+TARGET = sdl
+endif
+
+ifeq ($(PLATFORM),os2)
+RANLIB = echo
+PROGNAME = ../$(PROGBASE).exe
+EXTRA_CFLAGS = -Zbin-files -D__ST_MT_ERRNO__ -Zmtd -fomit-frame-pointer
+EXTRA_LDFLAGS = -lsocket
+PLATFORM = unix
+TARGET = x11
 endif
 
 ifeq ($(PLATFORM),unix)
@@ -69,23 +78,20 @@ TARGET = allegro
 endif
 
 ifeq ($(PLATFORM),cross-win32)
-EXTRA_LDFLAGS = -lshfolder
+EXTRA_LDFLAGS = -lshfolder -lwsock32
 PROGNAME = ../$(PROGBASE).exe
 TARGET = sdl
 endif
 
 ifeq ($(TARGET),x11)
 SYS_CFLAGS  = -DTARGET_X11 $(X11_INCL)
-SYS_LDFLAGS = $(X11_LIBS) -lX11
+SYS_LDFLAGS = $(X11_LIBS)
 endif
 
 ifeq ($(TARGET),sdl)
 SYS_CFLAGS  = -DTARGET_SDL $(shell sdl-config --cflags)
-ifeq ($(PLATFORM),macosx)
-SYS_LDFLAGS = -lSDL_image -lSDL_mixer -lsmpeg $(shell sdl-config --libs)
-else
-SYS_LDFLAGS = -lSDL_image -lSDL_mixer $(shell sdl-config --libs)
-endif
+SDL_LIBS = -lSDL_image -lSDL_mixer -lSDL_net -lsmpeg
+SYS_LDFLAGS = $(SDL_LIBS) $(shell sdl-config --libs)
 endif
 
 ifeq ($(TARGET),allegro)
@@ -128,8 +134,8 @@ ifdef BUILD_DIST                            # distribution build
 OPTIONS = -O3 -Wall
 endif
 
-CFLAGS = $(OPTIONS) $(SYS_CFLAGS) $(CONFIG)
-LDFLAGS = $(SYS_LDFLAGS) $(EXTRA_LDFLAGS) -lm
+CFLAGS = $(OPTIONS) $(SYS_CFLAGS)  $(EXTRA_CFLAGS) $(CONFIG)
+LDFLAGS =           $(SYS_LDFLAGS) $(EXTRA_LDFLAGS) -lm
 
 
 SRCS = main.c          \
@@ -175,6 +181,8 @@ CNFS =      conf_gfx.h      \
        conf_chr.h      \
        conf_cus.c      \
        conf_cus.h      \
+       conf_grp.c      \
+       conf_grp.h      \
        conf_e2g.c      \
        conf_esg.c      \
        conf_e2s.c      \
index 2a70f7b836b6887b8298371e7aae1f71967d71d2..48c4401760a9a65724611d7c5a1ea6410aaa5f97 100644 (file)
@@ -325,6 +325,38 @@ element_to_graphic[] =
     EL_SP_GRAVITY_PORT_UP,             -1, -1, FALSE,
     IMG_SP_GRAVITY_PORT_UP
   },
+  {
+    EL_SP_GRAVITY_ON_PORT_RIGHT,       -1, -1, FALSE,
+    IMG_SP_GRAVITY_ON_PORT_RIGHT
+  },
+  {
+    EL_SP_GRAVITY_ON_PORT_DOWN,                -1, -1, FALSE,
+    IMG_SP_GRAVITY_ON_PORT_DOWN
+  },
+  {
+    EL_SP_GRAVITY_ON_PORT_LEFT,                -1, -1, FALSE,
+    IMG_SP_GRAVITY_ON_PORT_LEFT
+  },
+  {
+    EL_SP_GRAVITY_ON_PORT_UP,          -1, -1, FALSE,
+    IMG_SP_GRAVITY_ON_PORT_UP
+  },
+  {
+    EL_SP_GRAVITY_OFF_PORT_RIGHT,      -1, -1, FALSE,
+    IMG_SP_GRAVITY_OFF_PORT_RIGHT
+  },
+  {
+    EL_SP_GRAVITY_OFF_PORT_DOWN,       -1, -1, FALSE,
+    IMG_SP_GRAVITY_OFF_PORT_DOWN
+  },
+  {
+    EL_SP_GRAVITY_OFF_PORT_LEFT,       -1, -1, FALSE,
+    IMG_SP_GRAVITY_OFF_PORT_LEFT
+  },
+  {
+    EL_SP_GRAVITY_OFF_PORT_UP,         -1, -1, FALSE,
+    IMG_SP_GRAVITY_OFF_PORT_UP
+  },
   {
     EL_SP_SNIKSNAK,                    -1, -1, FALSE,
     IMG_SP_SNIKSNAK
@@ -453,6 +485,10 @@ element_to_graphic[] =
     EL_SOKOBAN_FIELD_FULL,             -1, -1, FALSE,
     IMG_SOKOBAN_FIELD_FULL
   },
+  {
+    EL_SOKOBAN_FIELD_PLAYER,           -1, -1, FALSE,
+    IMG_SOKOBAN_FIELD_PLAYER
+  },
   {
     EL_EMPTY_SPACE,                    -1, -1, FALSE,
     IMG_EMPTY_SPACE
@@ -2049,10 +2085,6 @@ element_to_graphic[] =
     EL_STONEBLOCK,                     -1, -1, FALSE,
     IMG_STONEBLOCK
   },
-  {
-    EL_MAZE_RUNNER,                    -1, -1, FALSE,
-    IMG_MAZE_RUNNER
-  },
   {
     EL_PLAYER_1,                       -1, -1, FALSE,
     IMG_PLAYER_1
@@ -2521,6 +2553,50 @@ element_to_graphic[] =
     EL_ARROW_DOWN,                     -1, -1, FALSE,
     IMG_ARROW_DOWN
   },
+  {
+    EL_UNKNOWN,                                -1, -1, FALSE,
+    IMG_UNKNOWN
+  },
+  {
+    EL_TRIGGER_ELEMENT,                        -1, -1, FALSE,
+    IMG_TRIGGER_ELEMENT
+  },
+  {
+    EL_TRIGGER_PLAYER,                 -1, -1, FALSE,
+    IMG_TRIGGER_PLAYER
+  },
+  {
+    EL_BD_BUTTERFLY_DOWN,              -1, -1, FALSE,
+    IMG_BD_BUTTERFLY
+  },
+  {
+    EL_BD_BUTTERFLY_LEFT,              -1, -1, FALSE,
+    IMG_BD_BUTTERFLY
+  },
+  {
+    EL_BD_BUTTERFLY_RIGHT,             -1, -1, FALSE,
+    IMG_BD_BUTTERFLY
+  },
+  {
+    EL_BD_BUTTERFLY_UP,                        -1, -1, FALSE,
+    IMG_BD_BUTTERFLY
+  },
+  {
+    EL_BD_FIREFLY_DOWN,                        -1, -1, FALSE,
+    IMG_BD_FIREFLY
+  },
+  {
+    EL_BD_FIREFLY_LEFT,                        -1, -1, FALSE,
+    IMG_BD_FIREFLY
+  },
+  {
+    EL_BD_FIREFLY_RIGHT,               -1, -1, FALSE,
+    IMG_BD_FIREFLY
+  },
+  {
+    EL_BD_FIREFLY_UP,                  -1, -1, FALSE,
+    IMG_BD_FIREFLY
+  },
   {
     EL_DOOR_WHITE,                     -1, -1, FALSE,
     IMG_CHAR_QUESTION
@@ -3889,6 +3965,134 @@ element_to_graphic[] =
     EL_CUSTOM_256,                     -1, -1, FALSE,
     IMG_CUSTOM_256
   },
+  {
+    EL_GROUP_1,                                -1, -1, FALSE,
+    IMG_GROUP_1
+  },
+  {
+    EL_GROUP_2,                                -1, -1, FALSE,
+    IMG_GROUP_2
+  },
+  {
+    EL_GROUP_3,                                -1, -1, FALSE,
+    IMG_GROUP_3
+  },
+  {
+    EL_GROUP_4,                                -1, -1, FALSE,
+    IMG_GROUP_4
+  },
+  {
+    EL_GROUP_5,                                -1, -1, FALSE,
+    IMG_GROUP_5
+  },
+  {
+    EL_GROUP_6,                                -1, -1, FALSE,
+    IMG_GROUP_6
+  },
+  {
+    EL_GROUP_7,                                -1, -1, FALSE,
+    IMG_GROUP_7
+  },
+  {
+    EL_GROUP_8,                                -1, -1, FALSE,
+    IMG_GROUP_8
+  },
+  {
+    EL_GROUP_9,                                -1, -1, FALSE,
+    IMG_GROUP_9
+  },
+  {
+    EL_GROUP_10,                       -1, -1, FALSE,
+    IMG_GROUP_10
+  },
+  {
+    EL_GROUP_11,                       -1, -1, FALSE,
+    IMG_GROUP_11
+  },
+  {
+    EL_GROUP_12,                       -1, -1, FALSE,
+    IMG_GROUP_12
+  },
+  {
+    EL_GROUP_13,                       -1, -1, FALSE,
+    IMG_GROUP_13
+  },
+  {
+    EL_GROUP_14,                       -1, -1, FALSE,
+    IMG_GROUP_14
+  },
+  {
+    EL_GROUP_15,                       -1, -1, FALSE,
+    IMG_GROUP_15
+  },
+  {
+    EL_GROUP_16,                       -1, -1, FALSE,
+    IMG_GROUP_16
+  },
+  {
+    EL_GROUP_17,                       -1, -1, FALSE,
+    IMG_GROUP_17
+  },
+  {
+    EL_GROUP_18,                       -1, -1, FALSE,
+    IMG_GROUP_18
+  },
+  {
+    EL_GROUP_19,                       -1, -1, FALSE,
+    IMG_GROUP_19
+  },
+  {
+    EL_GROUP_20,                       -1, -1, FALSE,
+    IMG_GROUP_20
+  },
+  {
+    EL_GROUP_21,                       -1, -1, FALSE,
+    IMG_GROUP_21
+  },
+  {
+    EL_GROUP_22,                       -1, -1, FALSE,
+    IMG_GROUP_22
+  },
+  {
+    EL_GROUP_23,                       -1, -1, FALSE,
+    IMG_GROUP_23
+  },
+  {
+    EL_GROUP_24,                       -1, -1, FALSE,
+    IMG_GROUP_24
+  },
+  {
+    EL_GROUP_25,                       -1, -1, FALSE,
+    IMG_GROUP_25
+  },
+  {
+    EL_GROUP_26,                       -1, -1, FALSE,
+    IMG_GROUP_26
+  },
+  {
+    EL_GROUP_27,                       -1, -1, FALSE,
+    IMG_GROUP_27
+  },
+  {
+    EL_GROUP_28,                       -1, -1, FALSE,
+    IMG_GROUP_28
+  },
+  {
+    EL_GROUP_29,                       -1, -1, FALSE,
+    IMG_GROUP_29
+  },
+  {
+    EL_GROUP_30,                       -1, -1, FALSE,
+    IMG_GROUP_30
+  },
+  {
+    EL_GROUP_31,                       -1, -1, FALSE,
+    IMG_GROUP_31
+  },
+  {
+    EL_GROUP_32,                       -1, -1, FALSE,
+    IMG_GROUP_32
+  },
   {
     -1,                                        -1, -1, FALSE,
     -1
index 9b293d5b5424e4a3389c003425e5b260f26ee29e..1ffbe755c9987bc675f620b9260d88717f1afc61 100644 (file)
@@ -217,15 +217,15 @@ element_to_sound[] =
     SND_SP_TERMINAL_ACTIVE
   },
   {
-    EL_SOKOBAN_OBJECT, TRUE,                   ACTION_PUSHING,
+    EL_SOKOBAN_FIELD_PLAYER, TRUE,             ACTION_PUSHING,
     SND_CLASS_SOKOBAN_PUSHING
   },
   {
-    EL_SOKOBAN_OBJECT, TRUE,                   ACTION_FILLING,
+    EL_SOKOBAN_FIELD_PLAYER, TRUE,             ACTION_FILLING,
     SND_CLASS_SOKOBAN_FILLING
   },
   {
-    EL_SOKOBAN_OBJECT, TRUE,                   ACTION_EMPTYING,
+    EL_SOKOBAN_FIELD_PLAYER, TRUE,             ACTION_EMPTYING,
     SND_CLASS_SOKOBAN_EMPTYING
   },
   {
index ce5fe3c329a59aefee0f33c181948a8f8fdc3cda..540fe48fd92111a8280663cf7357ade832812b73 100644 (file)
@@ -75,6 +75,54 @@ element_to_special_graphic[] =
     EL_SP_INFOTRON,                            GFX_SPECIAL_ARG_EDITOR,
     IMG_SP_INFOTRON_EDITOR
   },
+  {
+    EL_SP_GRAVITY_PORT_RIGHT,                  GFX_SPECIAL_ARG_EDITOR,
+    IMG_SP_GRAVITY_PORT_RIGHT_EDITOR
+  },
+  {
+    EL_SP_GRAVITY_PORT_DOWN,                   GFX_SPECIAL_ARG_EDITOR,
+    IMG_SP_GRAVITY_PORT_DOWN_EDITOR
+  },
+  {
+    EL_SP_GRAVITY_PORT_LEFT,                   GFX_SPECIAL_ARG_EDITOR,
+    IMG_SP_GRAVITY_PORT_LEFT_EDITOR
+  },
+  {
+    EL_SP_GRAVITY_PORT_UP,                     GFX_SPECIAL_ARG_EDITOR,
+    IMG_SP_GRAVITY_PORT_UP_EDITOR
+  },
+  {
+    EL_SP_GRAVITY_ON_PORT_RIGHT,               GFX_SPECIAL_ARG_EDITOR,
+    IMG_SP_GRAVITY_ON_PORT_RIGHT_EDITOR
+  },
+  {
+    EL_SP_GRAVITY_ON_PORT_DOWN,                        GFX_SPECIAL_ARG_EDITOR,
+    IMG_SP_GRAVITY_ON_PORT_DOWN_EDITOR
+  },
+  {
+    EL_SP_GRAVITY_ON_PORT_LEFT,                        GFX_SPECIAL_ARG_EDITOR,
+    IMG_SP_GRAVITY_ON_PORT_LEFT_EDITOR
+  },
+  {
+    EL_SP_GRAVITY_ON_PORT_UP,                  GFX_SPECIAL_ARG_EDITOR,
+    IMG_SP_GRAVITY_ON_PORT_UP_EDITOR
+  },
+  {
+    EL_SP_GRAVITY_OFF_PORT_RIGHT,              GFX_SPECIAL_ARG_EDITOR,
+    IMG_SP_GRAVITY_OFF_PORT_RIGHT_EDITOR
+  },
+  {
+    EL_SP_GRAVITY_OFF_PORT_DOWN,               GFX_SPECIAL_ARG_EDITOR,
+    IMG_SP_GRAVITY_OFF_PORT_DOWN_EDITOR
+  },
+  {
+    EL_SP_GRAVITY_OFF_PORT_LEFT,               GFX_SPECIAL_ARG_EDITOR,
+    IMG_SP_GRAVITY_OFF_PORT_LEFT_EDITOR
+  },
+  {
+    EL_SP_GRAVITY_OFF_PORT_UP,                 GFX_SPECIAL_ARG_EDITOR,
+    IMG_SP_GRAVITY_OFF_PORT_UP_EDITOR
+  },
   {
     EL_SP_ELECTRON,                            GFX_SPECIAL_ARG_EDITOR,
     IMG_SP_ELECTRON_EDITOR
@@ -91,6 +139,10 @@ element_to_special_graphic[] =
     EL_SOKOBAN_OBJECT,                         GFX_SPECIAL_ARG_EDITOR,
     IMG_SOKOBAN_OBJECT_EDITOR
   },
+  {
+    EL_SOKOBAN_FIELD_PLAYER,                   GFX_SPECIAL_ARG_EDITOR,
+    IMG_SOKOBAN_FIELD_PLAYER_EDITOR
+  },
   {
     EL_DYNAMITE,                               GFX_SPECIAL_ARG_EDITOR,
     IMG_DYNAMITE_EDITOR
@@ -1283,6 +1335,134 @@ element_to_special_graphic[] =
     EL_CUSTOM_256,                             GFX_SPECIAL_ARG_EDITOR,
     IMG_CUSTOM_256_EDITOR
   },
+  {
+    EL_GROUP_1,                                        GFX_SPECIAL_ARG_EDITOR,
+    IMG_GROUP_1_EDITOR
+  },
+  {
+    EL_GROUP_2,                                        GFX_SPECIAL_ARG_EDITOR,
+    IMG_GROUP_2_EDITOR
+  },
+  {
+    EL_GROUP_3,                                        GFX_SPECIAL_ARG_EDITOR,
+    IMG_GROUP_3_EDITOR
+  },
+  {
+    EL_GROUP_4,                                        GFX_SPECIAL_ARG_EDITOR,
+    IMG_GROUP_4_EDITOR
+  },
+  {
+    EL_GROUP_5,                                        GFX_SPECIAL_ARG_EDITOR,
+    IMG_GROUP_5_EDITOR
+  },
+  {
+    EL_GROUP_6,                                        GFX_SPECIAL_ARG_EDITOR,
+    IMG_GROUP_6_EDITOR
+  },
+  {
+    EL_GROUP_7,                                        GFX_SPECIAL_ARG_EDITOR,
+    IMG_GROUP_7_EDITOR
+  },
+  {
+    EL_GROUP_8,                                        GFX_SPECIAL_ARG_EDITOR,
+    IMG_GROUP_8_EDITOR
+  },
+  {
+    EL_GROUP_9,                                        GFX_SPECIAL_ARG_EDITOR,
+    IMG_GROUP_9_EDITOR
+  },
+  {
+    EL_GROUP_10,                               GFX_SPECIAL_ARG_EDITOR,
+    IMG_GROUP_10_EDITOR
+  },
+  {
+    EL_GROUP_11,                               GFX_SPECIAL_ARG_EDITOR,
+    IMG_GROUP_11_EDITOR
+  },
+  {
+    EL_GROUP_12,                               GFX_SPECIAL_ARG_EDITOR,
+    IMG_GROUP_12_EDITOR
+  },
+  {
+    EL_GROUP_13,                               GFX_SPECIAL_ARG_EDITOR,
+    IMG_GROUP_13_EDITOR
+  },
+  {
+    EL_GROUP_14,                               GFX_SPECIAL_ARG_EDITOR,
+    IMG_GROUP_14_EDITOR
+  },
+  {
+    EL_GROUP_15,                               GFX_SPECIAL_ARG_EDITOR,
+    IMG_GROUP_15_EDITOR
+  },
+  {
+    EL_GROUP_16,                               GFX_SPECIAL_ARG_EDITOR,
+    IMG_GROUP_16_EDITOR
+  },
+  {
+    EL_GROUP_17,                               GFX_SPECIAL_ARG_EDITOR,
+    IMG_GROUP_17_EDITOR
+  },
+  {
+    EL_GROUP_18,                               GFX_SPECIAL_ARG_EDITOR,
+    IMG_GROUP_18_EDITOR
+  },
+  {
+    EL_GROUP_19,                               GFX_SPECIAL_ARG_EDITOR,
+    IMG_GROUP_19_EDITOR
+  },
+  {
+    EL_GROUP_20,                               GFX_SPECIAL_ARG_EDITOR,
+    IMG_GROUP_20_EDITOR
+  },
+  {
+    EL_GROUP_21,                               GFX_SPECIAL_ARG_EDITOR,
+    IMG_GROUP_21_EDITOR
+  },
+  {
+    EL_GROUP_22,                               GFX_SPECIAL_ARG_EDITOR,
+    IMG_GROUP_22_EDITOR
+  },
+  {
+    EL_GROUP_23,                               GFX_SPECIAL_ARG_EDITOR,
+    IMG_GROUP_23_EDITOR
+  },
+  {
+    EL_GROUP_24,                               GFX_SPECIAL_ARG_EDITOR,
+    IMG_GROUP_24_EDITOR
+  },
+  {
+    EL_GROUP_25,                               GFX_SPECIAL_ARG_EDITOR,
+    IMG_GROUP_25_EDITOR
+  },
+  {
+    EL_GROUP_26,                               GFX_SPECIAL_ARG_EDITOR,
+    IMG_GROUP_26_EDITOR
+  },
+  {
+    EL_GROUP_27,                               GFX_SPECIAL_ARG_EDITOR,
+    IMG_GROUP_27_EDITOR
+  },
+  {
+    EL_GROUP_28,                               GFX_SPECIAL_ARG_EDITOR,
+    IMG_GROUP_28_EDITOR
+  },
+  {
+    EL_GROUP_29,                               GFX_SPECIAL_ARG_EDITOR,
+    IMG_GROUP_29_EDITOR
+  },
+  {
+    EL_GROUP_30,                               GFX_SPECIAL_ARG_EDITOR,
+    IMG_GROUP_30_EDITOR
+  },
+  {
+    EL_GROUP_31,                               GFX_SPECIAL_ARG_EDITOR,
+    IMG_GROUP_31_EDITOR
+  },
+  {
+    EL_GROUP_32,                               GFX_SPECIAL_ARG_EDITOR,
+    IMG_GROUP_32_EDITOR
+  },
   {
     -1,                                                -1,
     -1
index 984c0972d24e6e0e14cc5562fbfa94279a919a37..ada412c6c52b19b6b7dc0028bf31427fb30fa4fa 100644 (file)
@@ -436,21 +436,89 @@ struct ConfigInfo image_config[] =
   { "sp_port_any.ypos",                                "2"                     },
   { "sp_port_any.frames",                      "1"                     },
   { "sp_gravity_port_right",                   "RocksSP.pcx"           },
-  { "sp_gravity_port_right.xpos",              "5"                     },
+  { "sp_gravity_port_right.xpos",              "1"                     },
   { "sp_gravity_port_right.ypos",              "1"                     },
   { "sp_gravity_port_right.frames",            "1"                     },
+  { "sp_gravity_port_right.EDITOR",            "RocksSP.pcx"           },
+  { "sp_gravity_port_right.EDITOR.xpos",       "5"                     },
+  { "sp_gravity_port_right.EDITOR.ypos",       "1"                     },
   { "sp_gravity_port_down",                    "RocksSP.pcx"           },
-  { "sp_gravity_port_down.xpos",               "6"                     },
+  { "sp_gravity_port_down.xpos",               "2"                     },
   { "sp_gravity_port_down.ypos",               "1"                     },
   { "sp_gravity_port_down.frames",             "1"                     },
+  { "sp_gravity_port_down.EDITOR",             "RocksSP.pcx"           },
+  { "sp_gravity_port_down.EDITOR.xpos",                "6"                     },
+  { "sp_gravity_port_down.EDITOR.ypos",                "1"                     },
   { "sp_gravity_port_left",                    "RocksSP.pcx"           },
-  { "sp_gravity_port_left.xpos",               "7"                     },
+  { "sp_gravity_port_left.xpos",               "3"                     },
   { "sp_gravity_port_left.ypos",               "1"                     },
   { "sp_gravity_port_left.frames",             "1"                     },
+  { "sp_gravity_port_left.EDITOR",             "RocksSP.pcx"           },
+  { "sp_gravity_port_left.EDITOR.xpos",                "7"                     },
+  { "sp_gravity_port_left.EDITOR.ypos",                "1"                     },
   { "sp_gravity_port_up",                      "RocksSP.pcx"           },
-  { "sp_gravity_port_up.xpos",                 "0"                     },
-  { "sp_gravity_port_up.ypos",                 "2"                     },
+  { "sp_gravity_port_up.xpos",                 "4"                     },
+  { "sp_gravity_port_up.ypos",                 "1"                     },
   { "sp_gravity_port_up.frames",               "1"                     },
+  { "sp_gravity_port_up.EDITOR",               "RocksSP.pcx"           },
+  { "sp_gravity_port_up.EDITOR.xpos",          "0"                     },
+  { "sp_gravity_port_up.EDITOR.ypos",          "2"                     },
+  { "sp_gravity_on_port_right",                        "RocksSP.pcx"           },
+  { "sp_gravity_on_port_right.xpos",           "1"                     },
+  { "sp_gravity_on_port_right.ypos",           "1"                     },
+  { "sp_gravity_on_port_right.frames",         "1"                     },
+  { "sp_gravity_on_port_right.EDITOR",         "RocksSP.pcx"           },
+  { "sp_gravity_on_port_right.EDITOR.xpos",    "5"                     },
+  { "sp_gravity_on_port_right.EDITOR.ypos",    "1"                     },
+  { "sp_gravity_on_port_down",                 "RocksSP.pcx"           },
+  { "sp_gravity_on_port_down.xpos",            "2"                     },
+  { "sp_gravity_on_port_down.ypos",            "1"                     },
+  { "sp_gravity_on_port_down.frames",          "1"                     },
+  { "sp_gravity_on_port_down.EDITOR",          "RocksSP.pcx"           },
+  { "sp_gravity_on_port_down.EDITOR.xpos",     "6"                     },
+  { "sp_gravity_on_port_down.EDITOR.ypos",     "1"                     },
+  { "sp_gravity_on_port_left",                 "RocksSP.pcx"           },
+  { "sp_gravity_on_port_left.xpos",            "3"                     },
+  { "sp_gravity_on_port_left.ypos",            "1"                     },
+  { "sp_gravity_on_port_left.frames",          "1"                     },
+  { "sp_gravity_on_port_left.EDITOR",          "RocksSP.pcx"           },
+  { "sp_gravity_on_port_left.EDITOR.xpos",     "7"                     },
+  { "sp_gravity_on_port_left.EDITOR.ypos",     "1"                     },
+  { "sp_gravity_on_port_up",                   "RocksSP.pcx"           },
+  { "sp_gravity_on_port_up.xpos",              "4"                     },
+  { "sp_gravity_on_port_up.ypos",              "1"                     },
+  { "sp_gravity_on_port_up.frames",            "1"                     },
+  { "sp_gravity_on_port_up.EDITOR",            "RocksSP.pcx"           },
+  { "sp_gravity_on_port_up.EDITOR.xpos",       "0"                     },
+  { "sp_gravity_on_port_up.EDITOR.ypos",       "2"                     },
+  { "sp_gravity_off_port_right",               "RocksSP.pcx"           },
+  { "sp_gravity_off_port_right.xpos",          "1"                     },
+  { "sp_gravity_off_port_right.ypos",          "1"                     },
+  { "sp_gravity_off_port_right.frames",                "1"                     },
+  { "sp_gravity_off_port_right.EDITOR",                "RocksSP.pcx"           },
+  { "sp_gravity_off_port_right.EDITOR.xpos",   "5"                     },
+  { "sp_gravity_off_port_right.EDITOR.ypos",   "1"                     },
+  { "sp_gravity_off_port_down",                        "RocksSP.pcx"           },
+  { "sp_gravity_off_port_down.xpos",           "2"                     },
+  { "sp_gravity_off_port_down.ypos",           "1"                     },
+  { "sp_gravity_off_port_down.frames",         "1"                     },
+  { "sp_gravity_off_port_down.EDITOR",         "RocksSP.pcx"           },
+  { "sp_gravity_off_port_down.EDITOR.xpos",    "6"                     },
+  { "sp_gravity_off_port_down.EDITOR.ypos",    "1"                     },
+  { "sp_gravity_off_port_left",                        "RocksSP.pcx"           },
+  { "sp_gravity_off_port_left.xpos",           "3"                     },
+  { "sp_gravity_off_port_left.ypos",           "1"                     },
+  { "sp_gravity_off_port_left.frames",         "1"                     },
+  { "sp_gravity_off_port_left.EDITOR",         "RocksSP.pcx"           },
+  { "sp_gravity_off_port_left.EDITOR.xpos",    "7"                     },
+  { "sp_gravity_off_port_left.EDITOR.ypos",    "1"                     },
+  { "sp_gravity_off_port_up",                  "RocksSP.pcx"           },
+  { "sp_gravity_off_port_up.xpos",             "4"                     },
+  { "sp_gravity_off_port_up.ypos",             "1"                     },
+  { "sp_gravity_off_port_up.frames",           "1"                     },
+  { "sp_gravity_off_port_up.EDITOR",           "RocksSP.pcx"           },
+  { "sp_gravity_off_port_up.EDITOR.xpos",      "0"                     },
+  { "sp_gravity_off_port_up.EDITOR.ypos",      "2"                     },
 
   { "sp_sniksnak",                             "RocksSP.pcx"           },
   { "sp_sniksnak.xpos",                                "1"                     },
@@ -537,7 +605,8 @@ struct ConfigInfo image_config[] =
   { "sp_electron.xpos",                                "8"                     },
   { "sp_electron.ypos",                                "10"                    },
   { "sp_electron.frames",                      "8"                     },
-  { "sp_electron.delay",                       "2"                     },
+  { "sp_electron.delay",                       "4"                     },
+  { "sp_electron.global_sync",                 "true"                  },
   { "sp_electron.EDITOR",                      "RocksSP.pcx"           },
   { "sp_electron.EDITOR.xpos",                 "10"                    },
   { "sp_electron.EDITOR.ypos",                 "11"                    },
@@ -624,6 +693,14 @@ struct ConfigInfo image_config[] =
   { "sokoban_field_full.ypos",                 "7"                     },
   { "sokoban_field_full.frames",               "1"                     },
 
+  { "sokoban_field_player",                    "RocksHeroes.pcx"       },
+  { "sokoban_field_player.xpos",               "0"                     },
+  { "sokoban_field_player.ypos",               "15"                    },
+  { "sokoban_field_player.frames",             "1"                     },
+  { "sokoban_field_player.EDITOR",             "RocksHeroes.pcx"       },
+  { "sokoban_field_player.EDITOR.xpos",                "1"                     },
+  { "sokoban_field_player.EDITOR.ypos",                "15"                    },
+
   /* images for Emerald Mine style elements and actions */
 
   { "empty_space",                             "RocksSP.pcx"           },
@@ -2467,11 +2544,6 @@ struct ConfigInfo image_config[] =
   { "stoneblock.ypos",                         "1"                     },
   { "stoneblock.frames",                       "1"                     },
 
-  { "maze_runner",                             "RocksHeroes.pcx"       },
-  { "maze_runner.xpos",                                "15"                    },
-  { "maze_runner.ypos",                                "8"                     },
-  { "maze_runner.frames",                      "1"                     },
-
   /* images for other elements and actions */
 
   { "player_1",                                        "RocksHeroes.pcx"       },
@@ -3129,8 +3201,24 @@ struct ConfigInfo image_config[] =
   { "arrow_down.ypos",                         "8"                     },
   { "arrow_down.frames",                       "1"                     },
 
+  { "unknown",                                 "RocksFontEM.pcx"       },
+  { "unknown.xpos",                            "15"                    },
+  { "unknown.ypos",                            "1"                     },
+  { "unknown.frames",                          "1"                     },
+
+  { "trigger_element",                         "RocksDC.pcx"           },
+  { "trigger_element.xpos",                    "15"                    },
+  { "trigger_element.ypos",                    "14"                    },
+  { "trigger_element.frames",                  "1"                     },
+
+  { "trigger_player",                          "RocksDC.pcx"           },
+  { "trigger_player.xpos",                     "15"                    },
+  { "trigger_player.ypos",                     "13"                    },
+  { "trigger_player.frames",                   "1"                     },
+
 #include "conf_chr.c"  /* include auto-generated data structure definitions */
 #include "conf_cus.c"  /* include auto-generated data structure definitions */
+#include "conf_grp.c"  /* include auto-generated data structure definitions */
 
   /* images not associated to game elements (used for menu screens etc.) */
   /* keyword to stop parser: "NO_MORE_ELEMENT_IMAGES" <-- do not change! */
@@ -3676,6 +3764,7 @@ struct ConfigInfo image_config[] =
   { "background.SCORES",                       UNDEFINED_FILENAME      },
   { "background.EDITOR",                       UNDEFINED_FILENAME      },
   { "background.INFO",                         UNDEFINED_FILENAME      },
+  { "background.INFO[ELEMENTS]",               UNDEFINED_FILENAME      },
   { "background.SETUP",                                UNDEFINED_FILENAME      },
   { "background.DOOR",                         UNDEFINED_FILENAME      },
 
index 6025aada3405fa92b8d54828a1a02edee1961a24..697d8fbea657ed93f5c7cb38c4cad7c953e3c084 100644 (file)
 #define IMG_SP_PORT_VERTICAL                           76
 #define IMG_SP_PORT_ANY                                        77
 #define IMG_SP_GRAVITY_PORT_RIGHT                      78
-#define IMG_SP_GRAVITY_PORT_DOWN                       79
-#define IMG_SP_GRAVITY_PORT_LEFT                       80
-#define IMG_SP_GRAVITY_PORT_UP                         81
-#define IMG_SP_SNIKSNAK                                        82
-#define IMG_SP_SNIKSNAK_LEFT                           83
-#define IMG_SP_SNIKSNAK_RIGHT                          84
-#define IMG_SP_SNIKSNAK_UP                             85
-#define IMG_SP_SNIKSNAK_DOWN                           86
-#define IMG_SP_SNIKSNAK_TURNING_FROM_LEFT_UP           87
-#define IMG_SP_SNIKSNAK_TURNING_FROM_LEFT_DOWN         88
-#define IMG_SP_SNIKSNAK_TURNING_FROM_RIGHT_UP          89
-#define IMG_SP_SNIKSNAK_TURNING_FROM_RIGHT_DOWN                90
-#define IMG_SP_SNIKSNAK_TURNING_FROM_UP_LEFT           91
-#define IMG_SP_SNIKSNAK_TURNING_FROM_UP_RIGHT          92
-#define IMG_SP_SNIKSNAK_TURNING_FROM_DOWN_LEFT         93
-#define IMG_SP_SNIKSNAK_TURNING_FROM_DOWN_RIGHT                94
-#define IMG_SP_ELECTRON                                        95
-#define IMG_SP_ELECTRON_EDITOR                         96
-#define IMG_SP_ELECTRON_EXPLODING                      97
-#define IMG_SP_TERMINAL                                        98
-#define IMG_SP_TERMINAL_EDITOR                         99
-#define IMG_SP_TERMINAL_ACTIVE                         100
-#define IMG_SP_BUGGY_BASE                              101
-#define IMG_SP_BUGGY_BASE_EDITOR                       102
-#define IMG_SP_BUGGY_BASE_ACTIVATING                   103
-#define IMG_SP_BUGGY_BASE_ACTIVE                       104
-#define IMG_SP_HARDWARE_BASE_1                         105
-#define IMG_SP_HARDWARE_BASE_2                         106
-#define IMG_SP_HARDWARE_BASE_3                         107
-#define IMG_SP_HARDWARE_BASE_4                         108
-#define IMG_SP_HARDWARE_BASE_5                         109
-#define IMG_SP_HARDWARE_BASE_6                         110
-#define IMG_SOKOBAN_OBJECT                             111
-#define IMG_SOKOBAN_OBJECT_EDITOR                      112
-#define IMG_SOKOBAN_FIELD_EMPTY                                113
-#define IMG_SOKOBAN_FIELD_FULL                         114
-#define IMG_EMPTY_SPACE                                        115
-#define IMG_SAND                                       116
-#define IMG_SAND_CRUMBLED                              117
-#define IMG_SAND_DIGGING_LEFT                          118
-#define IMG_SAND_DIGGING_RIGHT                         119
-#define IMG_SAND_DIGGING_UP                            120
-#define IMG_SAND_DIGGING_DOWN                          121
-#define IMG_SAND_DIGGING_LEFT_CRUMBLED                 122
-#define IMG_SAND_DIGGING_RIGHT_CRUMBLED                        123
-#define IMG_SAND_DIGGING_UP_CRUMBLED                   124
-#define IMG_SAND_DIGGING_DOWN_CRUMBLED                 125
-#define IMG_WALL                                       126
-#define IMG_WALL_SLIPPERY                              127
-#define IMG_STEELWALL                                  128
-#define IMG_ROCK                                       129
-#define IMG_ROCK_MOVING_LEFT                           130
-#define IMG_ROCK_MOVING_RIGHT                          131
-#define IMG_ROCK_PUSHING_LEFT                          132
-#define IMG_ROCK_PUSHING_RIGHT                         133
-#define IMG_EMERALD                                    134
-#define IMG_EMERALD_MOVING                             135
-#define IMG_EMERALD_FALLING                            136
-#define IMG_EMERALD_COLLECTING                         137
-#define IMG_DIAMOND                                    138
-#define IMG_DIAMOND_MOVING                             139
-#define IMG_DIAMOND_FALLING                            140
-#define IMG_DIAMOND_COLLECTING                         141
-#define IMG_BOMB                                       142
-#define IMG_NUT                                                143
-#define IMG_NUT_BREAKING                               144
-#define IMG_DYNAMITE                                   145
-#define IMG_DYNAMITE_EDITOR                            146
-#define IMG_DYNAMITE_ACTIVE                            147
-#define IMG_DYNAMITE_ACTIVE_EDITOR                     148
-#define IMG_WALL_EMERALD                               149
-#define IMG_WALL_DIAMOND                               150
-#define IMG_BUG                                                151
-#define IMG_BUG_RIGHT                                  152
-#define IMG_BUG_UP                                     153
-#define IMG_BUG_LEFT                                   154
-#define IMG_BUG_DOWN                                   155
-#define IMG_BUG_MOVING_RIGHT                           156
-#define IMG_BUG_MOVING_UP                              157
-#define IMG_BUG_MOVING_LEFT                            158
-#define IMG_BUG_MOVING_DOWN                            159
-#define IMG_BUG_TURNING_FROM_RIGHT_UP                  160
-#define IMG_BUG_TURNING_FROM_UP_LEFT                   161
-#define IMG_BUG_TURNING_FROM_LEFT_DOWN                 162
-#define IMG_BUG_TURNING_FROM_DOWN_RIGHT                        163
-#define IMG_BUG_TURNING_FROM_RIGHT_DOWN                        164
-#define IMG_BUG_TURNING_FROM_UP_RIGHT                  165
-#define IMG_BUG_TURNING_FROM_LEFT_UP                   166
-#define IMG_BUG_TURNING_FROM_DOWN_LEFT                 167
-#define IMG_SPACESHIP                                  168
-#define IMG_SPACESHIP_RIGHT                            169
-#define IMG_SPACESHIP_UP                               170
-#define IMG_SPACESHIP_LEFT                             171
-#define IMG_SPACESHIP_DOWN                             172
-#define IMG_SPACESHIP_MOVING_RIGHT                     173
-#define IMG_SPACESHIP_MOVING_UP                                174
-#define IMG_SPACESHIP_MOVING_LEFT                      175
-#define IMG_SPACESHIP_MOVING_DOWN                      176
-#define IMG_SPACESHIP_TURNING_FROM_RIGHT_UP            177
-#define IMG_SPACESHIP_TURNING_FROM_UP_LEFT             178
-#define IMG_SPACESHIP_TURNING_FROM_LEFT_DOWN           179
-#define IMG_SPACESHIP_TURNING_FROM_DOWN_RIGHT          180
-#define IMG_SPACESHIP_TURNING_FROM_RIGHT_DOWN          181
-#define IMG_SPACESHIP_TURNING_FROM_UP_RIGHT            182
-#define IMG_SPACESHIP_TURNING_FROM_LEFT_UP             183
-#define IMG_SPACESHIP_TURNING_FROM_DOWN_LEFT           184
-#define IMG_YAMYAM                                     185
-#define IMG_YAMYAM_MOVING                              186
-#define IMG_ROBOT                                      187
-#define IMG_ROBOT_MOVING                               188
-#define IMG_ROBOT_WHEEL                                        189
-#define IMG_ROBOT_WHEEL_ACTIVE                         190
-#define IMG_MAGIC_WALL                                 191
-#define IMG_MAGIC_WALL_ACTIVE                          192
-#define IMG_MAGIC_WALL_FILLING                         193
-#define IMG_MAGIC_WALL_FULL                            194
-#define IMG_MAGIC_WALL_EMPTYING                                195
-#define IMG_MAGIC_WALL_DEAD                            196
-#define IMG_QUICKSAND_EMPTY                            197
-#define IMG_QUICKSAND_FILLING                          198
-#define IMG_QUICKSAND_FULL                             199
-#define IMG_QUICKSAND_FULL_EDITOR                      200
-#define IMG_QUICKSAND_EMPTYING                         201
-#define IMG_ACID_POOL_TOPLEFT                          202
-#define IMG_ACID_POOL_TOPRIGHT                         203
-#define IMG_ACID_POOL_BOTTOMLEFT                       204
-#define IMG_ACID_POOL_BOTTOM                           205
-#define IMG_ACID_POOL_BOTTOMRIGHT                      206
-#define IMG_ACID                                       207
-#define IMG_ACID_SPLASH_LEFT                           208
-#define IMG_ACID_SPLASH_RIGHT                          209
-#define IMG_AMOEBA_DROP                                        210
-#define IMG_AMOEBA_GROWING                             211
-#define IMG_AMOEBA_SHRINKING                           212
-#define IMG_AMOEBA_WET                                 213
-#define IMG_AMOEBA_WET_EDITOR                          214
-#define IMG_AMOEBA_DROPPING                            215
-#define IMG_AMOEBA_DRY                                 216
-#define IMG_AMOEBA_FULL                                        217
-#define IMG_AMOEBA_FULL_EDITOR                         218
-#define IMG_AMOEBA_DEAD                                        219
-#define IMG_AMOEBA_DEAD_EDITOR                         220
-#define IMG_EM_KEY_1                                   221
-#define IMG_EM_KEY_2                                   222
-#define IMG_EM_KEY_3                                   223
-#define IMG_EM_KEY_4                                   224
-#define IMG_EM_GATE_1                                  225
-#define IMG_EM_GATE_2                                  226
-#define IMG_EM_GATE_3                                  227
-#define IMG_EM_GATE_4                                  228
-#define IMG_EM_GATE_1_GRAY                             229
-#define IMG_EM_GATE_1_GRAY_EDITOR                      230
-#define IMG_EM_GATE_2_GRAY                             231
-#define IMG_EM_GATE_2_GRAY_EDITOR                      232
-#define IMG_EM_GATE_3_GRAY                             233
-#define IMG_EM_GATE_3_GRAY_EDITOR                      234
-#define IMG_EM_GATE_4_GRAY                             235
-#define IMG_EM_GATE_4_GRAY_EDITOR                      236
-#define IMG_EXIT_CLOSED                                        237
-#define IMG_EXIT_OPENING                               238
-#define IMG_EXIT_OPEN                                  239
-#define IMG_EXIT_CLOSING                               240
-#define IMG_BALLOON                                    241
-#define IMG_BALLOON_MOVING                             242
-#define IMG_BALLOON_PUSHING                            243
-#define IMG_BALLOON_SWITCH_LEFT                                244
-#define IMG_BALLOON_SWITCH_RIGHT                       245
-#define IMG_BALLOON_SWITCH_UP                          246
-#define IMG_BALLOON_SWITCH_DOWN                                247
-#define IMG_BALLOON_SWITCH_ANY                         248
-#define IMG_SPRING                                     249
-#define IMG_EMC_STEELWALL_1                            250
-#define IMG_EMC_STEELWALL_2                            251
-#define IMG_EMC_STEELWALL_3                            252
-#define IMG_EMC_STEELWALL_4                            253
-#define IMG_EMC_WALL_1                                 254
-#define IMG_EMC_WALL_2                                 255
-#define IMG_EMC_WALL_3                                 256
-#define IMG_EMC_WALL_4                                 257
-#define IMG_EMC_WALL_5                                 258
-#define IMG_EMC_WALL_6                                 259
-#define IMG_EMC_WALL_7                                 260
-#define IMG_EMC_WALL_8                                 261
-#define IMG_INVISIBLE_STEELWALL                                262
-#define IMG_INVISIBLE_STEELWALL_EDITOR                 263
-#define IMG_INVISIBLE_STEELWALL_ACTIVE                 264
-#define IMG_INVISIBLE_WALL                             265
-#define IMG_INVISIBLE_WALL_EDITOR                      266
-#define IMG_INVISIBLE_WALL_ACTIVE                      267
-#define IMG_INVISIBLE_SAND                             268
-#define IMG_INVISIBLE_SAND_EDITOR                      269
-#define IMG_INVISIBLE_SAND_ACTIVE                      270
-#define IMG_CONVEYOR_BELT_1_MIDDLE                     271
-#define IMG_CONVEYOR_BELT_1_MIDDLE_ACTIVE              272
-#define IMG_CONVEYOR_BELT_1_LEFT                       273
-#define IMG_CONVEYOR_BELT_1_LEFT_ACTIVE                        274
-#define IMG_CONVEYOR_BELT_1_RIGHT                      275
-#define IMG_CONVEYOR_BELT_1_RIGHT_ACTIVE               276
-#define IMG_CONVEYOR_BELT_1_SWITCH_LEFT                        277
-#define IMG_CONVEYOR_BELT_1_SWITCH_MIDDLE              278
-#define IMG_CONVEYOR_BELT_1_SWITCH_RIGHT               279
-#define IMG_CONVEYOR_BELT_2_MIDDLE                     280
-#define IMG_CONVEYOR_BELT_2_MIDDLE_ACTIVE              281
-#define IMG_CONVEYOR_BELT_2_LEFT                       282
-#define IMG_CONVEYOR_BELT_2_LEFT_ACTIVE                        283
-#define IMG_CONVEYOR_BELT_2_RIGHT                      284
-#define IMG_CONVEYOR_BELT_2_RIGHT_ACTIVE               285
-#define IMG_CONVEYOR_BELT_2_SWITCH_LEFT                        286
-#define IMG_CONVEYOR_BELT_2_SWITCH_MIDDLE              287
-#define IMG_CONVEYOR_BELT_2_SWITCH_RIGHT               288
-#define IMG_CONVEYOR_BELT_3_MIDDLE                     289
-#define IMG_CONVEYOR_BELT_3_MIDDLE_ACTIVE              290
-#define IMG_CONVEYOR_BELT_3_LEFT                       291
-#define IMG_CONVEYOR_BELT_3_LEFT_ACTIVE                        292
-#define IMG_CONVEYOR_BELT_3_RIGHT                      293
-#define IMG_CONVEYOR_BELT_3_RIGHT_ACTIVE               294
-#define IMG_CONVEYOR_BELT_3_SWITCH_LEFT                        295
-#define IMG_CONVEYOR_BELT_3_SWITCH_MIDDLE              296
-#define IMG_CONVEYOR_BELT_3_SWITCH_RIGHT               297
-#define IMG_CONVEYOR_BELT_4_MIDDLE                     298
-#define IMG_CONVEYOR_BELT_4_MIDDLE_ACTIVE              299
-#define IMG_CONVEYOR_BELT_4_LEFT                       300
-#define IMG_CONVEYOR_BELT_4_LEFT_ACTIVE                        301
-#define IMG_CONVEYOR_BELT_4_RIGHT                      302
-#define IMG_CONVEYOR_BELT_4_RIGHT_ACTIVE               303
-#define IMG_CONVEYOR_BELT_4_SWITCH_LEFT                        304
-#define IMG_CONVEYOR_BELT_4_SWITCH_MIDDLE              305
-#define IMG_CONVEYOR_BELT_4_SWITCH_RIGHT               306
-#define IMG_SWITCHGATE_SWITCH_UP                       307
-#define IMG_SWITCHGATE_SWITCH_DOWN                     308
-#define IMG_LIGHT_SWITCH                               309
-#define IMG_LIGHT_SWITCH_ACTIVE                                310
-#define IMG_TIMEGATE_SWITCH                            311
-#define IMG_TIMEGATE_SWITCH_ACTIVE                     312
-#define IMG_ENVELOPE_1                                 313
-#define IMG_ENVELOPE_1_COLLECTING                      314
-#define IMG_ENVELOPE_2                                 315
-#define IMG_ENVELOPE_2_COLLECTING                      316
-#define IMG_ENVELOPE_3                                 317
-#define IMG_ENVELOPE_3_COLLECTING                      318
-#define IMG_ENVELOPE_4                                 319
-#define IMG_ENVELOPE_4_COLLECTING                      320
-#define IMG_SIGN_EXCLAMATION                           321
-#define IMG_SIGN_STOP                                  322
-#define IMG_LANDMINE                                   323
-#define IMG_STEELWALL_SLIPPERY                         324
-#define IMG_EXTRA_TIME                                 325
-#define IMG_SHIELD_NORMAL                              326
-#define IMG_SHIELD_NORMAL_ACTIVE                       327
-#define IMG_SHIELD_DEADLY                              328
-#define IMG_SHIELD_DEADLY_ACTIVE                       329
-#define IMG_SWITCHGATE_CLOSED                          330
-#define IMG_SWITCHGATE_OPENING                         331
-#define IMG_SWITCHGATE_OPEN                            332
-#define IMG_SWITCHGATE_CLOSING                         333
-#define IMG_TIMEGATE_CLOSED                            334
-#define IMG_TIMEGATE_OPENING                           335
-#define IMG_TIMEGATE_OPEN                              336
-#define IMG_TIMEGATE_CLOSING                           337
-#define IMG_PEARL                                      338
-#define IMG_PEARL_BREAKING                             339
-#define IMG_CRYSTAL                                    340
-#define IMG_WALL_PEARL                                 341
-#define IMG_WALL_CRYSTAL                               342
-#define IMG_TUBE_RIGHT_DOWN                            343
-#define IMG_TUBE_HORIZONTAL_DOWN                       344
-#define IMG_TUBE_LEFT_DOWN                             345
-#define IMG_TUBE_HORIZONTAL                            346
-#define IMG_TUBE_VERTICAL_RIGHT                                347
-#define IMG_TUBE_ANY                                   348
-#define IMG_TUBE_VERTICAL_LEFT                         349
-#define IMG_TUBE_VERTICAL                              350
-#define IMG_TUBE_RIGHT_UP                              351
-#define IMG_TUBE_HORIZONTAL_UP                         352
-#define IMG_TUBE_LEFT_UP                               353
-#define IMG_TRAP                                       354
-#define IMG_TRAP_ACTIVE                                        355
-#define IMG_DX_SUPABOMB                                        356
-#define IMG_KEY_1                                      357
-#define IMG_KEY_1_EDITOR                               358
-#define IMG_KEY_2                                      359
-#define IMG_KEY_2_EDITOR                               360
-#define IMG_KEY_3                                      361
-#define IMG_KEY_3_EDITOR                               362
-#define IMG_KEY_4                                      363
-#define IMG_KEY_4_EDITOR                               364
-#define IMG_GATE_1                                     365
-#define IMG_GATE_2                                     366
-#define IMG_GATE_3                                     367
-#define IMG_GATE_4                                     368
-#define IMG_GATE_1_GRAY                                        369
-#define IMG_GATE_1_GRAY_EDITOR                         370
-#define IMG_GATE_2_GRAY                                        371
-#define IMG_GATE_2_GRAY_EDITOR                         372
-#define IMG_GATE_3_GRAY                                        373
-#define IMG_GATE_3_GRAY_EDITOR                         374
-#define IMG_GATE_4_GRAY                                        375
-#define IMG_GATE_4_GRAY_EDITOR                         376
-#define IMG_GAME_OF_LIFE                               377
-#define IMG_BIOMAZE                                    378
-#define IMG_PACMAN                                     379
-#define IMG_PACMAN_RIGHT                               380
-#define IMG_PACMAN_UP                                  381
-#define IMG_PACMAN_LEFT                                        382
-#define IMG_PACMAN_DOWN                                        383
-#define IMG_PACMAN_TURNING_FROM_RIGHT                  384
-#define IMG_PACMAN_TURNING_FROM_UP                     385
-#define IMG_PACMAN_TURNING_FROM_LEFT                   386
-#define IMG_PACMAN_TURNING_FROM_DOWN                   387
-#define IMG_LAMP                                       388
-#define IMG_LAMP_EDITOR                                        389
-#define IMG_LAMP_ACTIVE                                        390
-#define IMG_TIME_ORB_FULL                              391
-#define IMG_TIME_ORB_EMPTY                             392
-#define IMG_EMERALD_YELLOW                             393
-#define IMG_EMERALD_YELLOW_MOVING                      394
-#define IMG_EMERALD_YELLOW_FALLING                     395
-#define IMG_EMERALD_RED                                        396
-#define IMG_EMERALD_RED_MOVING                         397
-#define IMG_EMERALD_RED_FALLING                                398
-#define IMG_EMERALD_PURPLE                             399
-#define IMG_EMERALD_PURPLE_MOVING                      400
-#define IMG_EMERALD_PURPLE_FALLING                     401
-#define IMG_WALL_EMERALD_YELLOW                                402
-#define IMG_WALL_EMERALD_RED                           403
-#define IMG_WALL_EMERALD_PURPLE                                404
-#define IMG_WALL_BD_DIAMOND                            405
-#define IMG_EXPANDABLE_WALL                            406
-#define IMG_EXPANDABLE_WALL_HORIZONTAL                 407
-#define IMG_EXPANDABLE_WALL_HORIZONTAL_EDITOR          408
-#define IMG_EXPANDABLE_WALL_VERTICAL                   409
-#define IMG_EXPANDABLE_WALL_VERTICAL_EDITOR            410
-#define IMG_EXPANDABLE_WALL_ANY                                411
-#define IMG_EXPANDABLE_WALL_ANY_EDITOR                 412
-#define IMG_EXPANDABLE_WALL_GROWING_LEFT               413
-#define IMG_EXPANDABLE_WALL_GROWING_RIGHT              414
-#define IMG_EXPANDABLE_WALL_GROWING_UP                 415
-#define IMG_EXPANDABLE_WALL_GROWING_DOWN               416
-#define IMG_BLACK_ORB                                  417
-#define IMG_SPEED_PILL                                 418
-#define IMG_DARK_YAMYAM                                        419
-#define IMG_DYNABOMB                                   420
-#define IMG_DYNABOMB_ACTIVE                            421
-#define IMG_DYNABOMB_PLAYER_1                          422
-#define IMG_DYNABOMB_PLAYER_1_ACTIVE                   423
-#define IMG_DYNABOMB_PLAYER_2                          424
-#define IMG_DYNABOMB_PLAYER_2_ACTIVE                   425
-#define IMG_DYNABOMB_PLAYER_3                          426
-#define IMG_DYNABOMB_PLAYER_3_ACTIVE                   427
-#define IMG_DYNABOMB_PLAYER_4                          428
-#define IMG_DYNABOMB_PLAYER_4_ACTIVE                   429
-#define IMG_DYNABOMB_INCREASE_NUMBER                   430
-#define IMG_DYNABOMB_INCREASE_SIZE                     431
-#define IMG_DYNABOMB_INCREASE_POWER                    432
-#define IMG_PIG                                                433
-#define IMG_PIG_DOWN                                   434
-#define IMG_PIG_UP                                     435
-#define IMG_PIG_LEFT                                   436
-#define IMG_PIG_RIGHT                                  437
-#define IMG_PIG_MOVING_DOWN                            438
-#define IMG_PIG_MOVING_UP                              439
-#define IMG_PIG_MOVING_LEFT                            440
-#define IMG_PIG_MOVING_RIGHT                           441
-#define IMG_PIG_DIGGING_DOWN                           442
-#define IMG_PIG_DIGGING_UP                             443
-#define IMG_PIG_DIGGING_LEFT                           444
-#define IMG_PIG_DIGGING_RIGHT                          445
-#define IMG_DRAGON                                     446
-#define IMG_DRAGON_DOWN                                        447
-#define IMG_DRAGON_UP                                  448
-#define IMG_DRAGON_LEFT                                        449
-#define IMG_DRAGON_RIGHT                               450
-#define IMG_DRAGON_MOVING_DOWN                         451
-#define IMG_DRAGON_MOVING_UP                           452
-#define IMG_DRAGON_MOVING_LEFT                         453
-#define IMG_DRAGON_MOVING_RIGHT                                454
-#define IMG_DRAGON_ATTACKING_DOWN                      455
-#define IMG_DRAGON_ATTACKING_UP                                456
-#define IMG_DRAGON_ATTACKING_LEFT                      457
-#define IMG_DRAGON_ATTACKING_RIGHT                     458
-#define IMG_MOLE                                       459
-#define IMG_MOLE_DOWN                                  460
-#define IMG_MOLE_UP                                    461
-#define IMG_MOLE_LEFT                                  462
-#define IMG_MOLE_RIGHT                                 463
-#define IMG_MOLE_MOVING_DOWN                           464
-#define IMG_MOLE_MOVING_UP                             465
-#define IMG_MOLE_MOVING_LEFT                           466
-#define IMG_MOLE_MOVING_RIGHT                          467
-#define IMG_MOLE_DIGGING_DOWN                          468
-#define IMG_MOLE_DIGGING_UP                            469
-#define IMG_MOLE_DIGGING_LEFT                          470
-#define IMG_MOLE_DIGGING_RIGHT                         471
-#define IMG_PENGUIN                                    472
-#define IMG_PENGUIN_EDITOR                             473
-#define IMG_PENGUIN_DOWN                               474
-#define IMG_PENGUIN_UP                                 475
-#define IMG_PENGUIN_LEFT                               476
-#define IMG_PENGUIN_RIGHT                              477
-#define IMG_PENGUIN_MOVING_DOWN                                478
-#define IMG_PENGUIN_MOVING_UP                          479
-#define IMG_PENGUIN_MOVING_LEFT                                480
-#define IMG_PENGUIN_MOVING_RIGHT                       481
-#define IMG_SATELLITE                                  482
-#define IMG_FLAMES_1_LEFT                              483
-#define IMG_FLAMES_2_LEFT                              484
-#define IMG_FLAMES_3_LEFT                              485
-#define IMG_FLAMES_1_RIGHT                             486
-#define IMG_FLAMES_2_RIGHT                             487
-#define IMG_FLAMES_3_RIGHT                             488
-#define IMG_FLAMES_1_UP                                        489
-#define IMG_FLAMES_2_UP                                        490
-#define IMG_FLAMES_3_UP                                        491
-#define IMG_FLAMES_1_DOWN                              492
-#define IMG_FLAMES_2_DOWN                              493
-#define IMG_FLAMES_3_DOWN                              494
-#define IMG_STONEBLOCK                                 495
-#define IMG_MAZE_RUNNER                                        496
-#define IMG_PLAYER_1                                   497
-#define IMG_PLAYER_1_EDITOR                            498
-#define IMG_PLAYER_1_DOWN                              499
-#define IMG_PLAYER_1_UP                                        500
-#define IMG_PLAYER_1_LEFT                              501
-#define IMG_PLAYER_1_RIGHT                             502
-#define IMG_PLAYER_1_MOVING_DOWN                       503
-#define IMG_PLAYER_1_MOVING_UP                         504
-#define IMG_PLAYER_1_MOVING_LEFT                       505
-#define IMG_PLAYER_1_MOVING_RIGHT                      506
-#define IMG_PLAYER_1_DIGGING_DOWN                      507
-#define IMG_PLAYER_1_DIGGING_UP                                508
-#define IMG_PLAYER_1_DIGGING_LEFT                      509
-#define IMG_PLAYER_1_DIGGING_RIGHT                     510
-#define IMG_PLAYER_1_COLLECTING_DOWN                   511
-#define IMG_PLAYER_1_COLLECTING_UP                     512
-#define IMG_PLAYER_1_COLLECTING_LEFT                   513
-#define IMG_PLAYER_1_COLLECTING_RIGHT                  514
-#define IMG_PLAYER_1_PUSHING_DOWN                      515
-#define IMG_PLAYER_1_PUSHING_UP                                516
-#define IMG_PLAYER_1_PUSHING_LEFT                      517
-#define IMG_PLAYER_1_PUSHING_RIGHT                     518
-#define IMG_PLAYER_1_SNAPPING_DOWN                     519
-#define IMG_PLAYER_1_SNAPPING_UP                       520
-#define IMG_PLAYER_1_SNAPPING_LEFT                     521
-#define IMG_PLAYER_1_SNAPPING_RIGHT                    522
-#define IMG_PLAYER_2                                   523
-#define IMG_PLAYER_2_EDITOR                            524
-#define IMG_PLAYER_2_DOWN                              525
-#define IMG_PLAYER_2_UP                                        526
-#define IMG_PLAYER_2_LEFT                              527
-#define IMG_PLAYER_2_RIGHT                             528
-#define IMG_PLAYER_2_MOVING_DOWN                       529
-#define IMG_PLAYER_2_MOVING_UP                         530
-#define IMG_PLAYER_2_MOVING_LEFT                       531
-#define IMG_PLAYER_2_MOVING_RIGHT                      532
-#define IMG_PLAYER_2_DIGGING_DOWN                      533
-#define IMG_PLAYER_2_DIGGING_UP                                534
-#define IMG_PLAYER_2_DIGGING_LEFT                      535
-#define IMG_PLAYER_2_DIGGING_RIGHT                     536
-#define IMG_PLAYER_2_COLLECTING_DOWN                   537
-#define IMG_PLAYER_2_COLLECTING_UP                     538
-#define IMG_PLAYER_2_COLLECTING_LEFT                   539
-#define IMG_PLAYER_2_COLLECTING_RIGHT                  540
-#define IMG_PLAYER_2_PUSHING_DOWN                      541
-#define IMG_PLAYER_2_PUSHING_UP                                542
-#define IMG_PLAYER_2_PUSHING_LEFT                      543
-#define IMG_PLAYER_2_PUSHING_RIGHT                     544
-#define IMG_PLAYER_2_SNAPPING_DOWN                     545
-#define IMG_PLAYER_2_SNAPPING_UP                       546
-#define IMG_PLAYER_2_SNAPPING_LEFT                     547
-#define IMG_PLAYER_2_SNAPPING_RIGHT                    548
-#define IMG_PLAYER_3                                   549
-#define IMG_PLAYER_3_EDITOR                            550
-#define IMG_PLAYER_3_DOWN                              551
-#define IMG_PLAYER_3_UP                                        552
-#define IMG_PLAYER_3_LEFT                              553
-#define IMG_PLAYER_3_RIGHT                             554
-#define IMG_PLAYER_3_MOVING_DOWN                       555
-#define IMG_PLAYER_3_MOVING_UP                         556
-#define IMG_PLAYER_3_MOVING_LEFT                       557
-#define IMG_PLAYER_3_MOVING_RIGHT                      558
-#define IMG_PLAYER_3_DIGGING_DOWN                      559
-#define IMG_PLAYER_3_DIGGING_UP                                560
-#define IMG_PLAYER_3_DIGGING_LEFT                      561
-#define IMG_PLAYER_3_DIGGING_RIGHT                     562
-#define IMG_PLAYER_3_COLLECTING_DOWN                   563
-#define IMG_PLAYER_3_COLLECTING_UP                     564
-#define IMG_PLAYER_3_COLLECTING_LEFT                   565
-#define IMG_PLAYER_3_COLLECTING_RIGHT                  566
-#define IMG_PLAYER_3_PUSHING_DOWN                      567
-#define IMG_PLAYER_3_PUSHING_UP                                568
-#define IMG_PLAYER_3_PUSHING_LEFT                      569
-#define IMG_PLAYER_3_PUSHING_RIGHT                     570
-#define IMG_PLAYER_3_SNAPPING_DOWN                     571
-#define IMG_PLAYER_3_SNAPPING_UP                       572
-#define IMG_PLAYER_3_SNAPPING_LEFT                     573
-#define IMG_PLAYER_3_SNAPPING_RIGHT                    574
-#define IMG_PLAYER_4                                   575
-#define IMG_PLAYER_4_EDITOR                            576
-#define IMG_PLAYER_4_DOWN                              577
-#define IMG_PLAYER_4_UP                                        578
-#define IMG_PLAYER_4_LEFT                              579
-#define IMG_PLAYER_4_RIGHT                             580
-#define IMG_PLAYER_4_MOVING_DOWN                       581
-#define IMG_PLAYER_4_MOVING_UP                         582
-#define IMG_PLAYER_4_MOVING_LEFT                       583
-#define IMG_PLAYER_4_MOVING_RIGHT                      584
-#define IMG_PLAYER_4_DIGGING_DOWN                      585
-#define IMG_PLAYER_4_DIGGING_UP                                586
-#define IMG_PLAYER_4_DIGGING_LEFT                      587
-#define IMG_PLAYER_4_DIGGING_RIGHT                     588
-#define IMG_PLAYER_4_COLLECTING_DOWN                   589
-#define IMG_PLAYER_4_COLLECTING_UP                     590
-#define IMG_PLAYER_4_COLLECTING_LEFT                   591
-#define IMG_PLAYER_4_COLLECTING_RIGHT                  592
-#define IMG_PLAYER_4_PUSHING_DOWN                      593
-#define IMG_PLAYER_4_PUSHING_UP                                594
-#define IMG_PLAYER_4_PUSHING_LEFT                      595
-#define IMG_PLAYER_4_PUSHING_RIGHT                     596
-#define IMG_PLAYER_4_SNAPPING_DOWN                     597
-#define IMG_PLAYER_4_SNAPPING_UP                       598
-#define IMG_PLAYER_4_SNAPPING_LEFT                     599
-#define IMG_PLAYER_4_SNAPPING_RIGHT                    600
-#define IMG_DEFAULT_EXPLODING                          601
-#define IMG_TWINKLE_BLUE                               602
-#define IMG_TWINKLE_WHITE                              603
-#define IMG_STEELWALL_TOPLEFT                          604
-#define IMG_STEELWALL_TOPRIGHT                         605
-#define IMG_STEELWALL_BOTTOMLEFT                       606
-#define IMG_STEELWALL_BOTTOMRIGHT                      607
-#define IMG_STEELWALL_HORIZONTAL                       608
-#define IMG_STEELWALL_VERTICAL                         609
-#define IMG_STEELWALL_TOPLEFT_EDITOR                   610
-#define IMG_STEELWALL_TOPRIGHT_EDITOR                  611
-#define IMG_STEELWALL_BOTTOMLEFT_EDITOR                        612
-#define IMG_STEELWALL_BOTTOMRIGHT_EDITOR               613
-#define IMG_STEELWALL_HORIZONTAL_EDITOR                        614
-#define IMG_STEELWALL_VERTICAL_EDITOR                  615
-#define IMG_INVISIBLE_STEELWALL_TOPLEFT                        616
-#define IMG_INVISIBLE_STEELWALL_TOPRIGHT               617
-#define IMG_INVISIBLE_STEELWALL_BOTTOMLEFT             618
-#define IMG_INVISIBLE_STEELWALL_BOTTOMRIGHT            619
-#define IMG_INVISIBLE_STEELWALL_HORIZONTAL             620
-#define IMG_INVISIBLE_STEELWALL_VERTICAL               621
-#define IMG_INVISIBLE_STEELWALL_TOPLEFT_EDITOR         622
-#define IMG_INVISIBLE_STEELWALL_TOPRIGHT_EDITOR                623
-#define IMG_INVISIBLE_STEELWALL_BOTTOMLEFT_EDITOR      624
-#define IMG_INVISIBLE_STEELWALL_BOTTOMRIGHT_EDITOR     625
-#define IMG_INVISIBLE_STEELWALL_HORIZONTAL_EDITOR      626
-#define IMG_INVISIBLE_STEELWALL_VERTICAL_EDITOR                627
-#define IMG_ARROW_LEFT                                 628
-#define IMG_ARROW_RIGHT                                        629
-#define IMG_ARROW_UP                                   630
-#define IMG_ARROW_DOWN                                 631
-#define IMG_CHAR_SPACE                                 632
-#define IMG_CHAR_EXCLAM                                        633
-#define IMG_CHAR_QUOTEDBL                              634
-#define IMG_CHAR_NUMBERSIGN                            635
-#define IMG_CHAR_DOLLAR                                        636
-#define IMG_CHAR_PROCENT                               637
-#define IMG_CHAR_AMPERSAND                             638
-#define IMG_CHAR_APOSTROPHE                            639
-#define IMG_CHAR_PARENLEFT                             640
-#define IMG_CHAR_PARENRIGHT                            641
-#define IMG_CHAR_ASTERISK                              642
-#define IMG_CHAR_PLUS                                  643
-#define IMG_CHAR_COMMA                                 644
-#define IMG_CHAR_MINUS                                 645
-#define IMG_CHAR_PERIOD                                        646
-#define IMG_CHAR_SLASH                                 647
-#define IMG_CHAR_0                                     648
-#define IMG_CHAR_1                                     649
-#define IMG_CHAR_2                                     650
-#define IMG_CHAR_3                                     651
-#define IMG_CHAR_4                                     652
-#define IMG_CHAR_5                                     653
-#define IMG_CHAR_6                                     654
-#define IMG_CHAR_7                                     655
-#define IMG_CHAR_8                                     656
-#define IMG_CHAR_9                                     657
-#define IMG_CHAR_COLON                                 658
-#define IMG_CHAR_SEMICOLON                             659
-#define IMG_CHAR_LESS                                  660
-#define IMG_CHAR_EQUAL                                 661
-#define IMG_CHAR_GREATER                               662
-#define IMG_CHAR_QUESTION                              663
-#define IMG_CHAR_AT                                    664
-#define IMG_CHAR_A                                     665
-#define IMG_CHAR_B                                     666
-#define IMG_CHAR_C                                     667
-#define IMG_CHAR_D                                     668
-#define IMG_CHAR_E                                     669
-#define IMG_CHAR_F                                     670
-#define IMG_CHAR_G                                     671
-#define IMG_CHAR_H                                     672
-#define IMG_CHAR_I                                     673
-#define IMG_CHAR_J                                     674
-#define IMG_CHAR_K                                     675
-#define IMG_CHAR_L                                     676
-#define IMG_CHAR_M                                     677
-#define IMG_CHAR_N                                     678
-#define IMG_CHAR_O                                     679
-#define IMG_CHAR_P                                     680
-#define IMG_CHAR_Q                                     681
-#define IMG_CHAR_R                                     682
-#define IMG_CHAR_S                                     683
-#define IMG_CHAR_T                                     684
-#define IMG_CHAR_U                                     685
-#define IMG_CHAR_V                                     686
-#define IMG_CHAR_W                                     687
-#define IMG_CHAR_X                                     688
-#define IMG_CHAR_Y                                     689
-#define IMG_CHAR_Z                                     690
-#define IMG_CHAR_BRACKETLEFT                           691
-#define IMG_CHAR_BACKSLASH                             692
-#define IMG_CHAR_BRACKETRIGHT                          693
-#define IMG_CHAR_ASCIICIRCUM                           694
-#define IMG_CHAR_UNDERSCORE                            695
-#define IMG_CHAR_COPYRIGHT                             696
-#define IMG_CHAR_AUMLAUT                               697
-#define IMG_CHAR_OUMLAUT                               698
-#define IMG_CHAR_UUMLAUT                               699
-#define IMG_CHAR_DEGREE                                        700
-#define IMG_CHAR_TRADEMARK                             701
-#define IMG_CHAR_CURSOR                                        702
-#define IMG_CUSTOM_1                                   703
-#define IMG_CUSTOM_1_EDITOR                            704
-#define IMG_CUSTOM_2                                   705
-#define IMG_CUSTOM_2_EDITOR                            706
-#define IMG_CUSTOM_3                                   707
-#define IMG_CUSTOM_3_EDITOR                            708
-#define IMG_CUSTOM_4                                   709
-#define IMG_CUSTOM_4_EDITOR                            710
-#define IMG_CUSTOM_5                                   711
-#define IMG_CUSTOM_5_EDITOR                            712
-#define IMG_CUSTOM_6                                   713
-#define IMG_CUSTOM_6_EDITOR                            714
-#define IMG_CUSTOM_7                                   715
-#define IMG_CUSTOM_7_EDITOR                            716
-#define IMG_CUSTOM_8                                   717
-#define IMG_CUSTOM_8_EDITOR                            718
-#define IMG_CUSTOM_9                                   719
-#define IMG_CUSTOM_9_EDITOR                            720
-#define IMG_CUSTOM_10                                  721
-#define IMG_CUSTOM_10_EDITOR                           722
-#define IMG_CUSTOM_11                                  723
-#define IMG_CUSTOM_11_EDITOR                           724
-#define IMG_CUSTOM_12                                  725
-#define IMG_CUSTOM_12_EDITOR                           726
-#define IMG_CUSTOM_13                                  727
-#define IMG_CUSTOM_13_EDITOR                           728
-#define IMG_CUSTOM_14                                  729
-#define IMG_CUSTOM_14_EDITOR                           730
-#define IMG_CUSTOM_15                                  731
-#define IMG_CUSTOM_15_EDITOR                           732
-#define IMG_CUSTOM_16                                  733
-#define IMG_CUSTOM_16_EDITOR                           734
-#define IMG_CUSTOM_17                                  735
-#define IMG_CUSTOM_17_EDITOR                           736
-#define IMG_CUSTOM_18                                  737
-#define IMG_CUSTOM_18_EDITOR                           738
-#define IMG_CUSTOM_19                                  739
-#define IMG_CUSTOM_19_EDITOR                           740
-#define IMG_CUSTOM_20                                  741
-#define IMG_CUSTOM_20_EDITOR                           742
-#define IMG_CUSTOM_21                                  743
-#define IMG_CUSTOM_21_EDITOR                           744
-#define IMG_CUSTOM_22                                  745
-#define IMG_CUSTOM_22_EDITOR                           746
-#define IMG_CUSTOM_23                                  747
-#define IMG_CUSTOM_23_EDITOR                           748
-#define IMG_CUSTOM_24                                  749
-#define IMG_CUSTOM_24_EDITOR                           750
-#define IMG_CUSTOM_25                                  751
-#define IMG_CUSTOM_25_EDITOR                           752
-#define IMG_CUSTOM_26                                  753
-#define IMG_CUSTOM_26_EDITOR                           754
-#define IMG_CUSTOM_27                                  755
-#define IMG_CUSTOM_27_EDITOR                           756
-#define IMG_CUSTOM_28                                  757
-#define IMG_CUSTOM_28_EDITOR                           758
-#define IMG_CUSTOM_29                                  759
-#define IMG_CUSTOM_29_EDITOR                           760
-#define IMG_CUSTOM_30                                  761
-#define IMG_CUSTOM_30_EDITOR                           762
-#define IMG_CUSTOM_31                                  763
-#define IMG_CUSTOM_31_EDITOR                           764
-#define IMG_CUSTOM_32                                  765
-#define IMG_CUSTOM_32_EDITOR                           766
-#define IMG_CUSTOM_33                                  767
-#define IMG_CUSTOM_33_EDITOR                           768
-#define IMG_CUSTOM_34                                  769
-#define IMG_CUSTOM_34_EDITOR                           770
-#define IMG_CUSTOM_35                                  771
-#define IMG_CUSTOM_35_EDITOR                           772
-#define IMG_CUSTOM_36                                  773
-#define IMG_CUSTOM_36_EDITOR                           774
-#define IMG_CUSTOM_37                                  775
-#define IMG_CUSTOM_37_EDITOR                           776
-#define IMG_CUSTOM_38                                  777
-#define IMG_CUSTOM_38_EDITOR                           778
-#define IMG_CUSTOM_39                                  779
-#define IMG_CUSTOM_39_EDITOR                           780
-#define IMG_CUSTOM_40                                  781
-#define IMG_CUSTOM_40_EDITOR                           782
-#define IMG_CUSTOM_41                                  783
-#define IMG_CUSTOM_41_EDITOR                           784
-#define IMG_CUSTOM_42                                  785
-#define IMG_CUSTOM_42_EDITOR                           786
-#define IMG_CUSTOM_43                                  787
-#define IMG_CUSTOM_43_EDITOR                           788
-#define IMG_CUSTOM_44                                  789
-#define IMG_CUSTOM_44_EDITOR                           790
-#define IMG_CUSTOM_45                                  791
-#define IMG_CUSTOM_45_EDITOR                           792
-#define IMG_CUSTOM_46                                  793
-#define IMG_CUSTOM_46_EDITOR                           794
-#define IMG_CUSTOM_47                                  795
-#define IMG_CUSTOM_47_EDITOR                           796
-#define IMG_CUSTOM_48                                  797
-#define IMG_CUSTOM_48_EDITOR                           798
-#define IMG_CUSTOM_49                                  799
-#define IMG_CUSTOM_49_EDITOR                           800
-#define IMG_CUSTOM_50                                  801
-#define IMG_CUSTOM_50_EDITOR                           802
-#define IMG_CUSTOM_51                                  803
-#define IMG_CUSTOM_51_EDITOR                           804
-#define IMG_CUSTOM_52                                  805
-#define IMG_CUSTOM_52_EDITOR                           806
-#define IMG_CUSTOM_53                                  807
-#define IMG_CUSTOM_53_EDITOR                           808
-#define IMG_CUSTOM_54                                  809
-#define IMG_CUSTOM_54_EDITOR                           810
-#define IMG_CUSTOM_55                                  811
-#define IMG_CUSTOM_55_EDITOR                           812
-#define IMG_CUSTOM_56                                  813
-#define IMG_CUSTOM_56_EDITOR                           814
-#define IMG_CUSTOM_57                                  815
-#define IMG_CUSTOM_57_EDITOR                           816
-#define IMG_CUSTOM_58                                  817
-#define IMG_CUSTOM_58_EDITOR                           818
-#define IMG_CUSTOM_59                                  819
-#define IMG_CUSTOM_59_EDITOR                           820
-#define IMG_CUSTOM_60                                  821
-#define IMG_CUSTOM_60_EDITOR                           822
-#define IMG_CUSTOM_61                                  823
-#define IMG_CUSTOM_61_EDITOR                           824
-#define IMG_CUSTOM_62                                  825
-#define IMG_CUSTOM_62_EDITOR                           826
-#define IMG_CUSTOM_63                                  827
-#define IMG_CUSTOM_63_EDITOR                           828
-#define IMG_CUSTOM_64                                  829
-#define IMG_CUSTOM_64_EDITOR                           830
-#define IMG_CUSTOM_65                                  831
-#define IMG_CUSTOM_65_EDITOR                           832
-#define IMG_CUSTOM_66                                  833
-#define IMG_CUSTOM_66_EDITOR                           834
-#define IMG_CUSTOM_67                                  835
-#define IMG_CUSTOM_67_EDITOR                           836
-#define IMG_CUSTOM_68                                  837
-#define IMG_CUSTOM_68_EDITOR                           838
-#define IMG_CUSTOM_69                                  839
-#define IMG_CUSTOM_69_EDITOR                           840
-#define IMG_CUSTOM_70                                  841
-#define IMG_CUSTOM_70_EDITOR                           842
-#define IMG_CUSTOM_71                                  843
-#define IMG_CUSTOM_71_EDITOR                           844
-#define IMG_CUSTOM_72                                  845
-#define IMG_CUSTOM_72_EDITOR                           846
-#define IMG_CUSTOM_73                                  847
-#define IMG_CUSTOM_73_EDITOR                           848
-#define IMG_CUSTOM_74                                  849
-#define IMG_CUSTOM_74_EDITOR                           850
-#define IMG_CUSTOM_75                                  851
-#define IMG_CUSTOM_75_EDITOR                           852
-#define IMG_CUSTOM_76                                  853
-#define IMG_CUSTOM_76_EDITOR                           854
-#define IMG_CUSTOM_77                                  855
-#define IMG_CUSTOM_77_EDITOR                           856
-#define IMG_CUSTOM_78                                  857
-#define IMG_CUSTOM_78_EDITOR                           858
-#define IMG_CUSTOM_79                                  859
-#define IMG_CUSTOM_79_EDITOR                           860
-#define IMG_CUSTOM_80                                  861
-#define IMG_CUSTOM_80_EDITOR                           862
-#define IMG_CUSTOM_81                                  863
-#define IMG_CUSTOM_81_EDITOR                           864
-#define IMG_CUSTOM_82                                  865
-#define IMG_CUSTOM_82_EDITOR                           866
-#define IMG_CUSTOM_83                                  867
-#define IMG_CUSTOM_83_EDITOR                           868
-#define IMG_CUSTOM_84                                  869
-#define IMG_CUSTOM_84_EDITOR                           870
-#define IMG_CUSTOM_85                                  871
-#define IMG_CUSTOM_85_EDITOR                           872
-#define IMG_CUSTOM_86                                  873
-#define IMG_CUSTOM_86_EDITOR                           874
-#define IMG_CUSTOM_87                                  875
-#define IMG_CUSTOM_87_EDITOR                           876
-#define IMG_CUSTOM_88                                  877
-#define IMG_CUSTOM_88_EDITOR                           878
-#define IMG_CUSTOM_89                                  879
-#define IMG_CUSTOM_89_EDITOR                           880
-#define IMG_CUSTOM_90                                  881
-#define IMG_CUSTOM_90_EDITOR                           882
-#define IMG_CUSTOM_91                                  883
-#define IMG_CUSTOM_91_EDITOR                           884
-#define IMG_CUSTOM_92                                  885
-#define IMG_CUSTOM_92_EDITOR                           886
-#define IMG_CUSTOM_93                                  887
-#define IMG_CUSTOM_93_EDITOR                           888
-#define IMG_CUSTOM_94                                  889
-#define IMG_CUSTOM_94_EDITOR                           890
-#define IMG_CUSTOM_95                                  891
-#define IMG_CUSTOM_95_EDITOR                           892
-#define IMG_CUSTOM_96                                  893
-#define IMG_CUSTOM_96_EDITOR                           894
-#define IMG_CUSTOM_97                                  895
-#define IMG_CUSTOM_97_EDITOR                           896
-#define IMG_CUSTOM_98                                  897
-#define IMG_CUSTOM_98_EDITOR                           898
-#define IMG_CUSTOM_99                                  899
-#define IMG_CUSTOM_99_EDITOR                           900
-#define IMG_CUSTOM_100                                 901
-#define IMG_CUSTOM_100_EDITOR                          902
-#define IMG_CUSTOM_101                                 903
-#define IMG_CUSTOM_101_EDITOR                          904
-#define IMG_CUSTOM_102                                 905
-#define IMG_CUSTOM_102_EDITOR                          906
-#define IMG_CUSTOM_103                                 907
-#define IMG_CUSTOM_103_EDITOR                          908
-#define IMG_CUSTOM_104                                 909
-#define IMG_CUSTOM_104_EDITOR                          910
-#define IMG_CUSTOM_105                                 911
-#define IMG_CUSTOM_105_EDITOR                          912
-#define IMG_CUSTOM_106                                 913
-#define IMG_CUSTOM_106_EDITOR                          914
-#define IMG_CUSTOM_107                                 915
-#define IMG_CUSTOM_107_EDITOR                          916
-#define IMG_CUSTOM_108                                 917
-#define IMG_CUSTOM_108_EDITOR                          918
-#define IMG_CUSTOM_109                                 919
-#define IMG_CUSTOM_109_EDITOR                          920
-#define IMG_CUSTOM_110                                 921
-#define IMG_CUSTOM_110_EDITOR                          922
-#define IMG_CUSTOM_111                                 923
-#define IMG_CUSTOM_111_EDITOR                          924
-#define IMG_CUSTOM_112                                 925
-#define IMG_CUSTOM_112_EDITOR                          926
-#define IMG_CUSTOM_113                                 927
-#define IMG_CUSTOM_113_EDITOR                          928
-#define IMG_CUSTOM_114                                 929
-#define IMG_CUSTOM_114_EDITOR                          930
-#define IMG_CUSTOM_115                                 931
-#define IMG_CUSTOM_115_EDITOR                          932
-#define IMG_CUSTOM_116                                 933
-#define IMG_CUSTOM_116_EDITOR                          934
-#define IMG_CUSTOM_117                                 935
-#define IMG_CUSTOM_117_EDITOR                          936
-#define IMG_CUSTOM_118                                 937
-#define IMG_CUSTOM_118_EDITOR                          938
-#define IMG_CUSTOM_119                                 939
-#define IMG_CUSTOM_119_EDITOR                          940
-#define IMG_CUSTOM_120                                 941
-#define IMG_CUSTOM_120_EDITOR                          942
-#define IMG_CUSTOM_121                                 943
-#define IMG_CUSTOM_121_EDITOR                          944
-#define IMG_CUSTOM_122                                 945
-#define IMG_CUSTOM_122_EDITOR                          946
-#define IMG_CUSTOM_123                                 947
-#define IMG_CUSTOM_123_EDITOR                          948
-#define IMG_CUSTOM_124                                 949
-#define IMG_CUSTOM_124_EDITOR                          950
-#define IMG_CUSTOM_125                                 951
-#define IMG_CUSTOM_125_EDITOR                          952
-#define IMG_CUSTOM_126                                 953
-#define IMG_CUSTOM_126_EDITOR                          954
-#define IMG_CUSTOM_127                                 955
-#define IMG_CUSTOM_127_EDITOR                          956
-#define IMG_CUSTOM_128                                 957
-#define IMG_CUSTOM_128_EDITOR                          958
-#define IMG_CUSTOM_129                                 959
-#define IMG_CUSTOM_129_EDITOR                          960
-#define IMG_CUSTOM_130                                 961
-#define IMG_CUSTOM_130_EDITOR                          962
-#define IMG_CUSTOM_131                                 963
-#define IMG_CUSTOM_131_EDITOR                          964
-#define IMG_CUSTOM_132                                 965
-#define IMG_CUSTOM_132_EDITOR                          966
-#define IMG_CUSTOM_133                                 967
-#define IMG_CUSTOM_133_EDITOR                          968
-#define IMG_CUSTOM_134                                 969
-#define IMG_CUSTOM_134_EDITOR                          970
-#define IMG_CUSTOM_135                                 971
-#define IMG_CUSTOM_135_EDITOR                          972
-#define IMG_CUSTOM_136                                 973
-#define IMG_CUSTOM_136_EDITOR                          974
-#define IMG_CUSTOM_137                                 975
-#define IMG_CUSTOM_137_EDITOR                          976
-#define IMG_CUSTOM_138                                 977
-#define IMG_CUSTOM_138_EDITOR                          978
-#define IMG_CUSTOM_139                                 979
-#define IMG_CUSTOM_139_EDITOR                          980
-#define IMG_CUSTOM_140                                 981
-#define IMG_CUSTOM_140_EDITOR                          982
-#define IMG_CUSTOM_141                                 983
-#define IMG_CUSTOM_141_EDITOR                          984
-#define IMG_CUSTOM_142                                 985
-#define IMG_CUSTOM_142_EDITOR                          986
-#define IMG_CUSTOM_143                                 987
-#define IMG_CUSTOM_143_EDITOR                          988
-#define IMG_CUSTOM_144                                 989
-#define IMG_CUSTOM_144_EDITOR                          990
-#define IMG_CUSTOM_145                                 991
-#define IMG_CUSTOM_145_EDITOR                          992
-#define IMG_CUSTOM_146                                 993
-#define IMG_CUSTOM_146_EDITOR                          994
-#define IMG_CUSTOM_147                                 995
-#define IMG_CUSTOM_147_EDITOR                          996
-#define IMG_CUSTOM_148                                 997
-#define IMG_CUSTOM_148_EDITOR                          998
-#define IMG_CUSTOM_149                                 999
-#define IMG_CUSTOM_149_EDITOR                          1000
-#define IMG_CUSTOM_150                                 1001
-#define IMG_CUSTOM_150_EDITOR                          1002
-#define IMG_CUSTOM_151                                 1003
-#define IMG_CUSTOM_151_EDITOR                          1004
-#define IMG_CUSTOM_152                                 1005
-#define IMG_CUSTOM_152_EDITOR                          1006
-#define IMG_CUSTOM_153                                 1007
-#define IMG_CUSTOM_153_EDITOR                          1008
-#define IMG_CUSTOM_154                                 1009
-#define IMG_CUSTOM_154_EDITOR                          1010
-#define IMG_CUSTOM_155                                 1011
-#define IMG_CUSTOM_155_EDITOR                          1012
-#define IMG_CUSTOM_156                                 1013
-#define IMG_CUSTOM_156_EDITOR                          1014
-#define IMG_CUSTOM_157                                 1015
-#define IMG_CUSTOM_157_EDITOR                          1016
-#define IMG_CUSTOM_158                                 1017
-#define IMG_CUSTOM_158_EDITOR                          1018
-#define IMG_CUSTOM_159                                 1019
-#define IMG_CUSTOM_159_EDITOR                          1020
-#define IMG_CUSTOM_160                                 1021
-#define IMG_CUSTOM_160_EDITOR                          1022
-#define IMG_CUSTOM_161                                 1023
-#define IMG_CUSTOM_161_EDITOR                          1024
-#define IMG_CUSTOM_162                                 1025
-#define IMG_CUSTOM_162_EDITOR                          1026
-#define IMG_CUSTOM_163                                 1027
-#define IMG_CUSTOM_163_EDITOR                          1028
-#define IMG_CUSTOM_164                                 1029
-#define IMG_CUSTOM_164_EDITOR                          1030
-#define IMG_CUSTOM_165                                 1031
-#define IMG_CUSTOM_165_EDITOR                          1032
-#define IMG_CUSTOM_166                                 1033
-#define IMG_CUSTOM_166_EDITOR                          1034
-#define IMG_CUSTOM_167                                 1035
-#define IMG_CUSTOM_167_EDITOR                          1036
-#define IMG_CUSTOM_168                                 1037
-#define IMG_CUSTOM_168_EDITOR                          1038
-#define IMG_CUSTOM_169                                 1039
-#define IMG_CUSTOM_169_EDITOR                          1040
-#define IMG_CUSTOM_170                                 1041
-#define IMG_CUSTOM_170_EDITOR                          1042
-#define IMG_CUSTOM_171                                 1043
-#define IMG_CUSTOM_171_EDITOR                          1044
-#define IMG_CUSTOM_172                                 1045
-#define IMG_CUSTOM_172_EDITOR                          1046
-#define IMG_CUSTOM_173                                 1047
-#define IMG_CUSTOM_173_EDITOR                          1048
-#define IMG_CUSTOM_174                                 1049
-#define IMG_CUSTOM_174_EDITOR                          1050
-#define IMG_CUSTOM_175                                 1051
-#define IMG_CUSTOM_175_EDITOR                          1052
-#define IMG_CUSTOM_176                                 1053
-#define IMG_CUSTOM_176_EDITOR                          1054
-#define IMG_CUSTOM_177                                 1055
-#define IMG_CUSTOM_177_EDITOR                          1056
-#define IMG_CUSTOM_178                                 1057
-#define IMG_CUSTOM_178_EDITOR                          1058
-#define IMG_CUSTOM_179                                 1059
-#define IMG_CUSTOM_179_EDITOR                          1060
-#define IMG_CUSTOM_180                                 1061
-#define IMG_CUSTOM_180_EDITOR                          1062
-#define IMG_CUSTOM_181                                 1063
-#define IMG_CUSTOM_181_EDITOR                          1064
-#define IMG_CUSTOM_182                                 1065
-#define IMG_CUSTOM_182_EDITOR                          1066
-#define IMG_CUSTOM_183                                 1067
-#define IMG_CUSTOM_183_EDITOR                          1068
-#define IMG_CUSTOM_184                                 1069
-#define IMG_CUSTOM_184_EDITOR                          1070
-#define IMG_CUSTOM_185                                 1071
-#define IMG_CUSTOM_185_EDITOR                          1072
-#define IMG_CUSTOM_186                                 1073
-#define IMG_CUSTOM_186_EDITOR                          1074
-#define IMG_CUSTOM_187                                 1075
-#define IMG_CUSTOM_187_EDITOR                          1076
-#define IMG_CUSTOM_188                                 1077
-#define IMG_CUSTOM_188_EDITOR                          1078
-#define IMG_CUSTOM_189                                 1079
-#define IMG_CUSTOM_189_EDITOR                          1080
-#define IMG_CUSTOM_190                                 1081
-#define IMG_CUSTOM_190_EDITOR                          1082
-#define IMG_CUSTOM_191                                 1083
-#define IMG_CUSTOM_191_EDITOR                          1084
-#define IMG_CUSTOM_192                                 1085
-#define IMG_CUSTOM_192_EDITOR                          1086
-#define IMG_CUSTOM_193                                 1087
-#define IMG_CUSTOM_193_EDITOR                          1088
-#define IMG_CUSTOM_194                                 1089
-#define IMG_CUSTOM_194_EDITOR                          1090
-#define IMG_CUSTOM_195                                 1091
-#define IMG_CUSTOM_195_EDITOR                          1092
-#define IMG_CUSTOM_196                                 1093
-#define IMG_CUSTOM_196_EDITOR                          1094
-#define IMG_CUSTOM_197                                 1095
-#define IMG_CUSTOM_197_EDITOR                          1096
-#define IMG_CUSTOM_198                                 1097
-#define IMG_CUSTOM_198_EDITOR                          1098
-#define IMG_CUSTOM_199                                 1099
-#define IMG_CUSTOM_199_EDITOR                          1100
-#define IMG_CUSTOM_200                                 1101
-#define IMG_CUSTOM_200_EDITOR                          1102
-#define IMG_CUSTOM_201                                 1103
-#define IMG_CUSTOM_201_EDITOR                          1104
-#define IMG_CUSTOM_202                                 1105
-#define IMG_CUSTOM_202_EDITOR                          1106
-#define IMG_CUSTOM_203                                 1107
-#define IMG_CUSTOM_203_EDITOR                          1108
-#define IMG_CUSTOM_204                                 1109
-#define IMG_CUSTOM_204_EDITOR                          1110
-#define IMG_CUSTOM_205                                 1111
-#define IMG_CUSTOM_205_EDITOR                          1112
-#define IMG_CUSTOM_206                                 1113
-#define IMG_CUSTOM_206_EDITOR                          1114
-#define IMG_CUSTOM_207                                 1115
-#define IMG_CUSTOM_207_EDITOR                          1116
-#define IMG_CUSTOM_208                                 1117
-#define IMG_CUSTOM_208_EDITOR                          1118
-#define IMG_CUSTOM_209                                 1119
-#define IMG_CUSTOM_209_EDITOR                          1120
-#define IMG_CUSTOM_210                                 1121
-#define IMG_CUSTOM_210_EDITOR                          1122
-#define IMG_CUSTOM_211                                 1123
-#define IMG_CUSTOM_211_EDITOR                          1124
-#define IMG_CUSTOM_212                                 1125
-#define IMG_CUSTOM_212_EDITOR                          1126
-#define IMG_CUSTOM_213                                 1127
-#define IMG_CUSTOM_213_EDITOR                          1128
-#define IMG_CUSTOM_214                                 1129
-#define IMG_CUSTOM_214_EDITOR                          1130
-#define IMG_CUSTOM_215                                 1131
-#define IMG_CUSTOM_215_EDITOR                          1132
-#define IMG_CUSTOM_216                                 1133
-#define IMG_CUSTOM_216_EDITOR                          1134
-#define IMG_CUSTOM_217                                 1135
-#define IMG_CUSTOM_217_EDITOR                          1136
-#define IMG_CUSTOM_218                                 1137
-#define IMG_CUSTOM_218_EDITOR                          1138
-#define IMG_CUSTOM_219                                 1139
-#define IMG_CUSTOM_219_EDITOR                          1140
-#define IMG_CUSTOM_220                                 1141
-#define IMG_CUSTOM_220_EDITOR                          1142
-#define IMG_CUSTOM_221                                 1143
-#define IMG_CUSTOM_221_EDITOR                          1144
-#define IMG_CUSTOM_222                                 1145
-#define IMG_CUSTOM_222_EDITOR                          1146
-#define IMG_CUSTOM_223                                 1147
-#define IMG_CUSTOM_223_EDITOR                          1148
-#define IMG_CUSTOM_224                                 1149
-#define IMG_CUSTOM_224_EDITOR                          1150
-#define IMG_CUSTOM_225                                 1151
-#define IMG_CUSTOM_225_EDITOR                          1152
-#define IMG_CUSTOM_226                                 1153
-#define IMG_CUSTOM_226_EDITOR                          1154
-#define IMG_CUSTOM_227                                 1155
-#define IMG_CUSTOM_227_EDITOR                          1156
-#define IMG_CUSTOM_228                                 1157
-#define IMG_CUSTOM_228_EDITOR                          1158
-#define IMG_CUSTOM_229                                 1159
-#define IMG_CUSTOM_229_EDITOR                          1160
-#define IMG_CUSTOM_230                                 1161
-#define IMG_CUSTOM_230_EDITOR                          1162
-#define IMG_CUSTOM_231                                 1163
-#define IMG_CUSTOM_231_EDITOR                          1164
-#define IMG_CUSTOM_232                                 1165
-#define IMG_CUSTOM_232_EDITOR                          1166
-#define IMG_CUSTOM_233                                 1167
-#define IMG_CUSTOM_233_EDITOR                          1168
-#define IMG_CUSTOM_234                                 1169
-#define IMG_CUSTOM_234_EDITOR                          1170
-#define IMG_CUSTOM_235                                 1171
-#define IMG_CUSTOM_235_EDITOR                          1172
-#define IMG_CUSTOM_236                                 1173
-#define IMG_CUSTOM_236_EDITOR                          1174
-#define IMG_CUSTOM_237                                 1175
-#define IMG_CUSTOM_237_EDITOR                          1176
-#define IMG_CUSTOM_238                                 1177
-#define IMG_CUSTOM_238_EDITOR                          1178
-#define IMG_CUSTOM_239                                 1179
-#define IMG_CUSTOM_239_EDITOR                          1180
-#define IMG_CUSTOM_240                                 1181
-#define IMG_CUSTOM_240_EDITOR                          1182
-#define IMG_CUSTOM_241                                 1183
-#define IMG_CUSTOM_241_EDITOR                          1184
-#define IMG_CUSTOM_242                                 1185
-#define IMG_CUSTOM_242_EDITOR                          1186
-#define IMG_CUSTOM_243                                 1187
-#define IMG_CUSTOM_243_EDITOR                          1188
-#define IMG_CUSTOM_244                                 1189
-#define IMG_CUSTOM_244_EDITOR                          1190
-#define IMG_CUSTOM_245                                 1191
-#define IMG_CUSTOM_245_EDITOR                          1192
-#define IMG_CUSTOM_246                                 1193
-#define IMG_CUSTOM_246_EDITOR                          1194
-#define IMG_CUSTOM_247                                 1195
-#define IMG_CUSTOM_247_EDITOR                          1196
-#define IMG_CUSTOM_248                                 1197
-#define IMG_CUSTOM_248_EDITOR                          1198
-#define IMG_CUSTOM_249                                 1199
-#define IMG_CUSTOM_249_EDITOR                          1200
-#define IMG_CUSTOM_250                                 1201
-#define IMG_CUSTOM_250_EDITOR                          1202
-#define IMG_CUSTOM_251                                 1203
-#define IMG_CUSTOM_251_EDITOR                          1204
-#define IMG_CUSTOM_252                                 1205
-#define IMG_CUSTOM_252_EDITOR                          1206
-#define IMG_CUSTOM_253                                 1207
-#define IMG_CUSTOM_253_EDITOR                          1208
-#define IMG_CUSTOM_254                                 1209
-#define IMG_CUSTOM_254_EDITOR                          1210
-#define IMG_CUSTOM_255                                 1211
-#define IMG_CUSTOM_255_EDITOR                          1212
-#define IMG_CUSTOM_256                                 1213
-#define IMG_CUSTOM_256_EDITOR                          1214
-#define IMG_TOON_1                                     1215
-#define IMG_TOON_2                                     1216
-#define IMG_TOON_3                                     1217
-#define IMG_TOON_4                                     1218
-#define IMG_TOON_5                                     1219
-#define IMG_TOON_6                                     1220
-#define IMG_TOON_7                                     1221
-#define IMG_TOON_8                                     1222
-#define IMG_TOON_9                                     1223
-#define IMG_TOON_10                                    1224
-#define IMG_TOON_11                                    1225
-#define IMG_TOON_12                                    1226
-#define IMG_TOON_13                                    1227
-#define IMG_TOON_14                                    1228
-#define IMG_TOON_15                                    1229
-#define IMG_TOON_16                                    1230
-#define IMG_TOON_17                                    1231
-#define IMG_TOON_18                                    1232
-#define IMG_TOON_19                                    1233
-#define IMG_TOON_20                                    1234
-#define IMG_MENU_CALIBRATE_RED                         1235
-#define IMG_MENU_CALIBRATE_BLUE                                1236
-#define IMG_MENU_CALIBRATE_YELLOW                      1237
-#define IMG_MENU_BUTTON                                        1238
-#define IMG_MENU_BUTTON_ACTIVE                         1239
-#define IMG_MENU_BUTTON_LEFT                           1240
-#define IMG_MENU_BUTTON_RIGHT                          1241
-#define IMG_MENU_BUTTON_UP                             1242
-#define IMG_MENU_BUTTON_DOWN                           1243
-#define IMG_MENU_BUTTON_LEFT_ACTIVE                    1244
-#define IMG_MENU_BUTTON_RIGHT_ACTIVE                   1245
-#define IMG_MENU_BUTTON_UP_ACTIVE                      1246
-#define IMG_MENU_BUTTON_DOWN_ACTIVE                    1247
-#define IMG_MENU_SCROLLBAR                             1248
-#define IMG_MENU_SCROLLBAR_ACTIVE                      1249
-#define IMG_FONT_INITIAL_1                             1250
-#define IMG_FONT_INITIAL_2                             1251
-#define IMG_FONT_INITIAL_3                             1252
-#define IMG_FONT_INITIAL_4                             1253
-#define IMG_FONT_TITLE_1                               1254
-#define IMG_FONT_TITLE_1_LEVELS                                1255
-#define IMG_FONT_TITLE_2                               1256
-#define IMG_FONT_MENU_1                                        1257
-#define IMG_FONT_MENU_2                                        1258
-#define IMG_FONT_TEXT_1                                        1259
-#define IMG_FONT_TEXT_1_LEVELS                         1260
-#define IMG_FONT_TEXT_1_PREVIEW                                1261
-#define IMG_FONT_TEXT_1_SCORES                         1262
-#define IMG_FONT_TEXT_1_ACTIVE_SCORES                  1263
-#define IMG_FONT_TEXT_2                                        1264
-#define IMG_FONT_TEXT_2_LEVELS                         1265
-#define IMG_FONT_TEXT_2_PREVIEW                                1266
-#define IMG_FONT_TEXT_2_SCORES                         1267
-#define IMG_FONT_TEXT_2_ACTIVE_SCORES                  1268
-#define IMG_FONT_TEXT_3                                        1269
-#define IMG_FONT_TEXT_3_LEVELS                         1270
-#define IMG_FONT_TEXT_3_PREVIEW                                1271
-#define IMG_FONT_TEXT_3_SCORES                         1272
-#define IMG_FONT_TEXT_3_ACTIVE_SCORES                  1273
-#define IMG_FONT_TEXT_4                                        1274
-#define IMG_FONT_TEXT_4_LEVELS                         1275
-#define IMG_FONT_TEXT_4_SCORES                         1276
-#define IMG_FONT_TEXT_4_ACTIVE_SCORES                  1277
-#define IMG_FONT_ENVELOPE_1                            1278
-#define IMG_FONT_ENVELOPE_2                            1279
-#define IMG_FONT_ENVELOPE_3                            1280
-#define IMG_FONT_ENVELOPE_4                            1281
-#define IMG_FONT_INPUT_1                               1282
-#define IMG_FONT_INPUT_1_MAIN                          1283
-#define IMG_FONT_INPUT_1_ACTIVE                                1284
-#define IMG_FONT_INPUT_1_ACTIVE_MAIN                   1285
-#define IMG_FONT_INPUT_1_ACTIVE_SETUP                  1286
-#define IMG_FONT_INPUT_2                               1287
-#define IMG_FONT_INPUT_2_ACTIVE                                1288
-#define IMG_FONT_OPTION_OFF                            1289
-#define IMG_FONT_OPTION_ON                             1290
-#define IMG_FONT_VALUE_1                               1291
-#define IMG_FONT_VALUE_2                               1292
-#define IMG_FONT_VALUE_OLD                             1293
-#define IMG_FONT_LEVEL_NUMBER                          1294
-#define IMG_FONT_TAPE_RECORDER                         1295
-#define IMG_FONT_GAME_INFO                             1296
-#define IMG_GLOBAL_BORDER                              1297
-#define IMG_GLOBAL_DOOR                                        1298
-#define IMG_EDITOR_ELEMENT_BORDER                      1299
-#define IMG_EDITOR_ELEMENT_BORDER_INPUT                        1300
-#define IMG_BACKGROUND_ENVELOPE_1                      1301
-#define IMG_BACKGROUND_ENVELOPE_2                      1302
-#define IMG_BACKGROUND_ENVELOPE_3                      1303
-#define IMG_BACKGROUND_ENVELOPE_4                      1304
-#define IMG_BACKGROUND                                 1305
-#define IMG_BACKGROUND_MAIN                            1306
-#define IMG_BACKGROUND_LEVELS                          1307
-#define IMG_BACKGROUND_SCORES                          1308
-#define IMG_BACKGROUND_EDITOR                          1309
-#define IMG_BACKGROUND_INFO                            1310
-#define IMG_BACKGROUND_SETUP                           1311
-#define IMG_BACKGROUND_DOOR                            1312
+#define IMG_SP_GRAVITY_PORT_RIGHT_EDITOR               79
+#define IMG_SP_GRAVITY_PORT_DOWN                       80
+#define IMG_SP_GRAVITY_PORT_DOWN_EDITOR                        81
+#define IMG_SP_GRAVITY_PORT_LEFT                       82
+#define IMG_SP_GRAVITY_PORT_LEFT_EDITOR                        83
+#define IMG_SP_GRAVITY_PORT_UP                         84
+#define IMG_SP_GRAVITY_PORT_UP_EDITOR                  85
+#define IMG_SP_GRAVITY_ON_PORT_RIGHT                   86
+#define IMG_SP_GRAVITY_ON_PORT_RIGHT_EDITOR            87
+#define IMG_SP_GRAVITY_ON_PORT_DOWN                    88
+#define IMG_SP_GRAVITY_ON_PORT_DOWN_EDITOR             89
+#define IMG_SP_GRAVITY_ON_PORT_LEFT                    90
+#define IMG_SP_GRAVITY_ON_PORT_LEFT_EDITOR             91
+#define IMG_SP_GRAVITY_ON_PORT_UP                      92
+#define IMG_SP_GRAVITY_ON_PORT_UP_EDITOR               93
+#define IMG_SP_GRAVITY_OFF_PORT_RIGHT                  94
+#define IMG_SP_GRAVITY_OFF_PORT_RIGHT_EDITOR           95
+#define IMG_SP_GRAVITY_OFF_PORT_DOWN                   96
+#define IMG_SP_GRAVITY_OFF_PORT_DOWN_EDITOR            97
+#define IMG_SP_GRAVITY_OFF_PORT_LEFT                   98
+#define IMG_SP_GRAVITY_OFF_PORT_LEFT_EDITOR            99
+#define IMG_SP_GRAVITY_OFF_PORT_UP                     100
+#define IMG_SP_GRAVITY_OFF_PORT_UP_EDITOR              101
+#define IMG_SP_SNIKSNAK                                        102
+#define IMG_SP_SNIKSNAK_LEFT                           103
+#define IMG_SP_SNIKSNAK_RIGHT                          104
+#define IMG_SP_SNIKSNAK_UP                             105
+#define IMG_SP_SNIKSNAK_DOWN                           106
+#define IMG_SP_SNIKSNAK_TURNING_FROM_LEFT_UP           107
+#define IMG_SP_SNIKSNAK_TURNING_FROM_LEFT_DOWN         108
+#define IMG_SP_SNIKSNAK_TURNING_FROM_RIGHT_UP          109
+#define IMG_SP_SNIKSNAK_TURNING_FROM_RIGHT_DOWN                110
+#define IMG_SP_SNIKSNAK_TURNING_FROM_UP_LEFT           111
+#define IMG_SP_SNIKSNAK_TURNING_FROM_UP_RIGHT          112
+#define IMG_SP_SNIKSNAK_TURNING_FROM_DOWN_LEFT         113
+#define IMG_SP_SNIKSNAK_TURNING_FROM_DOWN_RIGHT                114
+#define IMG_SP_ELECTRON                                        115
+#define IMG_SP_ELECTRON_EDITOR                         116
+#define IMG_SP_ELECTRON_EXPLODING                      117
+#define IMG_SP_TERMINAL                                        118
+#define IMG_SP_TERMINAL_EDITOR                         119
+#define IMG_SP_TERMINAL_ACTIVE                         120
+#define IMG_SP_BUGGY_BASE                              121
+#define IMG_SP_BUGGY_BASE_EDITOR                       122
+#define IMG_SP_BUGGY_BASE_ACTIVATING                   123
+#define IMG_SP_BUGGY_BASE_ACTIVE                       124
+#define IMG_SP_HARDWARE_BASE_1                         125
+#define IMG_SP_HARDWARE_BASE_2                         126
+#define IMG_SP_HARDWARE_BASE_3                         127
+#define IMG_SP_HARDWARE_BASE_4                         128
+#define IMG_SP_HARDWARE_BASE_5                         129
+#define IMG_SP_HARDWARE_BASE_6                         130
+#define IMG_SOKOBAN_OBJECT                             131
+#define IMG_SOKOBAN_OBJECT_EDITOR                      132
+#define IMG_SOKOBAN_FIELD_EMPTY                                133
+#define IMG_SOKOBAN_FIELD_FULL                         134
+#define IMG_SOKOBAN_FIELD_PLAYER                       135
+#define IMG_SOKOBAN_FIELD_PLAYER_EDITOR                        136
+#define IMG_EMPTY_SPACE                                        137
+#define IMG_SAND                                       138
+#define IMG_SAND_CRUMBLED                              139
+#define IMG_SAND_DIGGING_LEFT                          140
+#define IMG_SAND_DIGGING_RIGHT                         141
+#define IMG_SAND_DIGGING_UP                            142
+#define IMG_SAND_DIGGING_DOWN                          143
+#define IMG_SAND_DIGGING_LEFT_CRUMBLED                 144
+#define IMG_SAND_DIGGING_RIGHT_CRUMBLED                        145
+#define IMG_SAND_DIGGING_UP_CRUMBLED                   146
+#define IMG_SAND_DIGGING_DOWN_CRUMBLED                 147
+#define IMG_WALL                                       148
+#define IMG_WALL_SLIPPERY                              149
+#define IMG_STEELWALL                                  150
+#define IMG_ROCK                                       151
+#define IMG_ROCK_MOVING_LEFT                           152
+#define IMG_ROCK_MOVING_RIGHT                          153
+#define IMG_ROCK_PUSHING_LEFT                          154
+#define IMG_ROCK_PUSHING_RIGHT                         155
+#define IMG_EMERALD                                    156
+#define IMG_EMERALD_MOVING                             157
+#define IMG_EMERALD_FALLING                            158
+#define IMG_EMERALD_COLLECTING                         159
+#define IMG_DIAMOND                                    160
+#define IMG_DIAMOND_MOVING                             161
+#define IMG_DIAMOND_FALLING                            162
+#define IMG_DIAMOND_COLLECTING                         163
+#define IMG_BOMB                                       164
+#define IMG_NUT                                                165
+#define IMG_NUT_BREAKING                               166
+#define IMG_DYNAMITE                                   167
+#define IMG_DYNAMITE_EDITOR                            168
+#define IMG_DYNAMITE_ACTIVE                            169
+#define IMG_DYNAMITE_ACTIVE_EDITOR                     170
+#define IMG_WALL_EMERALD                               171
+#define IMG_WALL_DIAMOND                               172
+#define IMG_BUG                                                173
+#define IMG_BUG_RIGHT                                  174
+#define IMG_BUG_UP                                     175
+#define IMG_BUG_LEFT                                   176
+#define IMG_BUG_DOWN                                   177
+#define IMG_BUG_MOVING_RIGHT                           178
+#define IMG_BUG_MOVING_UP                              179
+#define IMG_BUG_MOVING_LEFT                            180
+#define IMG_BUG_MOVING_DOWN                            181
+#define IMG_BUG_TURNING_FROM_RIGHT_UP                  182
+#define IMG_BUG_TURNING_FROM_UP_LEFT                   183
+#define IMG_BUG_TURNING_FROM_LEFT_DOWN                 184
+#define IMG_BUG_TURNING_FROM_DOWN_RIGHT                        185
+#define IMG_BUG_TURNING_FROM_RIGHT_DOWN                        186
+#define IMG_BUG_TURNING_FROM_UP_RIGHT                  187
+#define IMG_BUG_TURNING_FROM_LEFT_UP                   188
+#define IMG_BUG_TURNING_FROM_DOWN_LEFT                 189
+#define IMG_SPACESHIP                                  190
+#define IMG_SPACESHIP_RIGHT                            191
+#define IMG_SPACESHIP_UP                               192
+#define IMG_SPACESHIP_LEFT                             193
+#define IMG_SPACESHIP_DOWN                             194
+#define IMG_SPACESHIP_MOVING_RIGHT                     195
+#define IMG_SPACESHIP_MOVING_UP                                196
+#define IMG_SPACESHIP_MOVING_LEFT                      197
+#define IMG_SPACESHIP_MOVING_DOWN                      198
+#define IMG_SPACESHIP_TURNING_FROM_RIGHT_UP            199
+#define IMG_SPACESHIP_TURNING_FROM_UP_LEFT             200
+#define IMG_SPACESHIP_TURNING_FROM_LEFT_DOWN           201
+#define IMG_SPACESHIP_TURNING_FROM_DOWN_RIGHT          202
+#define IMG_SPACESHIP_TURNING_FROM_RIGHT_DOWN          203
+#define IMG_SPACESHIP_TURNING_FROM_UP_RIGHT            204
+#define IMG_SPACESHIP_TURNING_FROM_LEFT_UP             205
+#define IMG_SPACESHIP_TURNING_FROM_DOWN_LEFT           206
+#define IMG_YAMYAM                                     207
+#define IMG_YAMYAM_MOVING                              208
+#define IMG_ROBOT                                      209
+#define IMG_ROBOT_MOVING                               210
+#define IMG_ROBOT_WHEEL                                        211
+#define IMG_ROBOT_WHEEL_ACTIVE                         212
+#define IMG_MAGIC_WALL                                 213
+#define IMG_MAGIC_WALL_ACTIVE                          214
+#define IMG_MAGIC_WALL_FILLING                         215
+#define IMG_MAGIC_WALL_FULL                            216
+#define IMG_MAGIC_WALL_EMPTYING                                217
+#define IMG_MAGIC_WALL_DEAD                            218
+#define IMG_QUICKSAND_EMPTY                            219
+#define IMG_QUICKSAND_FILLING                          220
+#define IMG_QUICKSAND_FULL                             221
+#define IMG_QUICKSAND_FULL_EDITOR                      222
+#define IMG_QUICKSAND_EMPTYING                         223
+#define IMG_ACID_POOL_TOPLEFT                          224
+#define IMG_ACID_POOL_TOPRIGHT                         225
+#define IMG_ACID_POOL_BOTTOMLEFT                       226
+#define IMG_ACID_POOL_BOTTOM                           227
+#define IMG_ACID_POOL_BOTTOMRIGHT                      228
+#define IMG_ACID                                       229
+#define IMG_ACID_SPLASH_LEFT                           230
+#define IMG_ACID_SPLASH_RIGHT                          231
+#define IMG_AMOEBA_DROP                                        232
+#define IMG_AMOEBA_GROWING                             233
+#define IMG_AMOEBA_SHRINKING                           234
+#define IMG_AMOEBA_WET                                 235
+#define IMG_AMOEBA_WET_EDITOR                          236
+#define IMG_AMOEBA_DROPPING                            237
+#define IMG_AMOEBA_DRY                                 238
+#define IMG_AMOEBA_FULL                                        239
+#define IMG_AMOEBA_FULL_EDITOR                         240
+#define IMG_AMOEBA_DEAD                                        241
+#define IMG_AMOEBA_DEAD_EDITOR                         242
+#define IMG_EM_KEY_1                                   243
+#define IMG_EM_KEY_2                                   244
+#define IMG_EM_KEY_3                                   245
+#define IMG_EM_KEY_4                                   246
+#define IMG_EM_GATE_1                                  247
+#define IMG_EM_GATE_2                                  248
+#define IMG_EM_GATE_3                                  249
+#define IMG_EM_GATE_4                                  250
+#define IMG_EM_GATE_1_GRAY                             251
+#define IMG_EM_GATE_1_GRAY_EDITOR                      252
+#define IMG_EM_GATE_2_GRAY                             253
+#define IMG_EM_GATE_2_GRAY_EDITOR                      254
+#define IMG_EM_GATE_3_GRAY                             255
+#define IMG_EM_GATE_3_GRAY_EDITOR                      256
+#define IMG_EM_GATE_4_GRAY                             257
+#define IMG_EM_GATE_4_GRAY_EDITOR                      258
+#define IMG_EXIT_CLOSED                                        259
+#define IMG_EXIT_OPENING                               260
+#define IMG_EXIT_OPEN                                  261
+#define IMG_EXIT_CLOSING                               262
+#define IMG_BALLOON                                    263
+#define IMG_BALLOON_MOVING                             264
+#define IMG_BALLOON_PUSHING                            265
+#define IMG_BALLOON_SWITCH_LEFT                                266
+#define IMG_BALLOON_SWITCH_RIGHT                       267
+#define IMG_BALLOON_SWITCH_UP                          268
+#define IMG_BALLOON_SWITCH_DOWN                                269
+#define IMG_BALLOON_SWITCH_ANY                         270
+#define IMG_SPRING                                     271
+#define IMG_EMC_STEELWALL_1                            272
+#define IMG_EMC_STEELWALL_2                            273
+#define IMG_EMC_STEELWALL_3                            274
+#define IMG_EMC_STEELWALL_4                            275
+#define IMG_EMC_WALL_1                                 276
+#define IMG_EMC_WALL_2                                 277
+#define IMG_EMC_WALL_3                                 278
+#define IMG_EMC_WALL_4                                 279
+#define IMG_EMC_WALL_5                                 280
+#define IMG_EMC_WALL_6                                 281
+#define IMG_EMC_WALL_7                                 282
+#define IMG_EMC_WALL_8                                 283
+#define IMG_INVISIBLE_STEELWALL                                284
+#define IMG_INVISIBLE_STEELWALL_EDITOR                 285
+#define IMG_INVISIBLE_STEELWALL_ACTIVE                 286
+#define IMG_INVISIBLE_WALL                             287
+#define IMG_INVISIBLE_WALL_EDITOR                      288
+#define IMG_INVISIBLE_WALL_ACTIVE                      289
+#define IMG_INVISIBLE_SAND                             290
+#define IMG_INVISIBLE_SAND_EDITOR                      291
+#define IMG_INVISIBLE_SAND_ACTIVE                      292
+#define IMG_CONVEYOR_BELT_1_MIDDLE                     293
+#define IMG_CONVEYOR_BELT_1_MIDDLE_ACTIVE              294
+#define IMG_CONVEYOR_BELT_1_LEFT                       295
+#define IMG_CONVEYOR_BELT_1_LEFT_ACTIVE                        296
+#define IMG_CONVEYOR_BELT_1_RIGHT                      297
+#define IMG_CONVEYOR_BELT_1_RIGHT_ACTIVE               298
+#define IMG_CONVEYOR_BELT_1_SWITCH_LEFT                        299
+#define IMG_CONVEYOR_BELT_1_SWITCH_MIDDLE              300
+#define IMG_CONVEYOR_BELT_1_SWITCH_RIGHT               301
+#define IMG_CONVEYOR_BELT_2_MIDDLE                     302
+#define IMG_CONVEYOR_BELT_2_MIDDLE_ACTIVE              303
+#define IMG_CONVEYOR_BELT_2_LEFT                       304
+#define IMG_CONVEYOR_BELT_2_LEFT_ACTIVE                        305
+#define IMG_CONVEYOR_BELT_2_RIGHT                      306
+#define IMG_CONVEYOR_BELT_2_RIGHT_ACTIVE               307
+#define IMG_CONVEYOR_BELT_2_SWITCH_LEFT                        308
+#define IMG_CONVEYOR_BELT_2_SWITCH_MIDDLE              309
+#define IMG_CONVEYOR_BELT_2_SWITCH_RIGHT               310
+#define IMG_CONVEYOR_BELT_3_MIDDLE                     311
+#define IMG_CONVEYOR_BELT_3_MIDDLE_ACTIVE              312
+#define IMG_CONVEYOR_BELT_3_LEFT                       313
+#define IMG_CONVEYOR_BELT_3_LEFT_ACTIVE                        314
+#define IMG_CONVEYOR_BELT_3_RIGHT                      315
+#define IMG_CONVEYOR_BELT_3_RIGHT_ACTIVE               316
+#define IMG_CONVEYOR_BELT_3_SWITCH_LEFT                        317
+#define IMG_CONVEYOR_BELT_3_SWITCH_MIDDLE              318
+#define IMG_CONVEYOR_BELT_3_SWITCH_RIGHT               319
+#define IMG_CONVEYOR_BELT_4_MIDDLE                     320
+#define IMG_CONVEYOR_BELT_4_MIDDLE_ACTIVE              321
+#define IMG_CONVEYOR_BELT_4_LEFT                       322
+#define IMG_CONVEYOR_BELT_4_LEFT_ACTIVE                        323
+#define IMG_CONVEYOR_BELT_4_RIGHT                      324
+#define IMG_CONVEYOR_BELT_4_RIGHT_ACTIVE               325
+#define IMG_CONVEYOR_BELT_4_SWITCH_LEFT                        326
+#define IMG_CONVEYOR_BELT_4_SWITCH_MIDDLE              327
+#define IMG_CONVEYOR_BELT_4_SWITCH_RIGHT               328
+#define IMG_SWITCHGATE_SWITCH_UP                       329
+#define IMG_SWITCHGATE_SWITCH_DOWN                     330
+#define IMG_LIGHT_SWITCH                               331
+#define IMG_LIGHT_SWITCH_ACTIVE                                332
+#define IMG_TIMEGATE_SWITCH                            333
+#define IMG_TIMEGATE_SWITCH_ACTIVE                     334
+#define IMG_ENVELOPE_1                                 335
+#define IMG_ENVELOPE_1_COLLECTING                      336
+#define IMG_ENVELOPE_2                                 337
+#define IMG_ENVELOPE_2_COLLECTING                      338
+#define IMG_ENVELOPE_3                                 339
+#define IMG_ENVELOPE_3_COLLECTING                      340
+#define IMG_ENVELOPE_4                                 341
+#define IMG_ENVELOPE_4_COLLECTING                      342
+#define IMG_SIGN_EXCLAMATION                           343
+#define IMG_SIGN_STOP                                  344
+#define IMG_LANDMINE                                   345
+#define IMG_STEELWALL_SLIPPERY                         346
+#define IMG_EXTRA_TIME                                 347
+#define IMG_SHIELD_NORMAL                              348
+#define IMG_SHIELD_NORMAL_ACTIVE                       349
+#define IMG_SHIELD_DEADLY                              350
+#define IMG_SHIELD_DEADLY_ACTIVE                       351
+#define IMG_SWITCHGATE_CLOSED                          352
+#define IMG_SWITCHGATE_OPENING                         353
+#define IMG_SWITCHGATE_OPEN                            354
+#define IMG_SWITCHGATE_CLOSING                         355
+#define IMG_TIMEGATE_CLOSED                            356
+#define IMG_TIMEGATE_OPENING                           357
+#define IMG_TIMEGATE_OPEN                              358
+#define IMG_TIMEGATE_CLOSING                           359
+#define IMG_PEARL                                      360
+#define IMG_PEARL_BREAKING                             361
+#define IMG_CRYSTAL                                    362
+#define IMG_WALL_PEARL                                 363
+#define IMG_WALL_CRYSTAL                               364
+#define IMG_TUBE_RIGHT_DOWN                            365
+#define IMG_TUBE_HORIZONTAL_DOWN                       366
+#define IMG_TUBE_LEFT_DOWN                             367
+#define IMG_TUBE_HORIZONTAL                            368
+#define IMG_TUBE_VERTICAL_RIGHT                                369
+#define IMG_TUBE_ANY                                   370
+#define IMG_TUBE_VERTICAL_LEFT                         371
+#define IMG_TUBE_VERTICAL                              372
+#define IMG_TUBE_RIGHT_UP                              373
+#define IMG_TUBE_HORIZONTAL_UP                         374
+#define IMG_TUBE_LEFT_UP                               375
+#define IMG_TRAP                                       376
+#define IMG_TRAP_ACTIVE                                        377
+#define IMG_DX_SUPABOMB                                        378
+#define IMG_KEY_1                                      379
+#define IMG_KEY_1_EDITOR                               380
+#define IMG_KEY_2                                      381
+#define IMG_KEY_2_EDITOR                               382
+#define IMG_KEY_3                                      383
+#define IMG_KEY_3_EDITOR                               384
+#define IMG_KEY_4                                      385
+#define IMG_KEY_4_EDITOR                               386
+#define IMG_GATE_1                                     387
+#define IMG_GATE_2                                     388
+#define IMG_GATE_3                                     389
+#define IMG_GATE_4                                     390
+#define IMG_GATE_1_GRAY                                        391
+#define IMG_GATE_1_GRAY_EDITOR                         392
+#define IMG_GATE_2_GRAY                                        393
+#define IMG_GATE_2_GRAY_EDITOR                         394
+#define IMG_GATE_3_GRAY                                        395
+#define IMG_GATE_3_GRAY_EDITOR                         396
+#define IMG_GATE_4_GRAY                                        397
+#define IMG_GATE_4_GRAY_EDITOR                         398
+#define IMG_GAME_OF_LIFE                               399
+#define IMG_BIOMAZE                                    400
+#define IMG_PACMAN                                     401
+#define IMG_PACMAN_RIGHT                               402
+#define IMG_PACMAN_UP                                  403
+#define IMG_PACMAN_LEFT                                        404
+#define IMG_PACMAN_DOWN                                        405
+#define IMG_PACMAN_TURNING_FROM_RIGHT                  406
+#define IMG_PACMAN_TURNING_FROM_UP                     407
+#define IMG_PACMAN_TURNING_FROM_LEFT                   408
+#define IMG_PACMAN_TURNING_FROM_DOWN                   409
+#define IMG_LAMP                                       410
+#define IMG_LAMP_EDITOR                                        411
+#define IMG_LAMP_ACTIVE                                        412
+#define IMG_TIME_ORB_FULL                              413
+#define IMG_TIME_ORB_EMPTY                             414
+#define IMG_EMERALD_YELLOW                             415
+#define IMG_EMERALD_YELLOW_MOVING                      416
+#define IMG_EMERALD_YELLOW_FALLING                     417
+#define IMG_EMERALD_RED                                        418
+#define IMG_EMERALD_RED_MOVING                         419
+#define IMG_EMERALD_RED_FALLING                                420
+#define IMG_EMERALD_PURPLE                             421
+#define IMG_EMERALD_PURPLE_MOVING                      422
+#define IMG_EMERALD_PURPLE_FALLING                     423
+#define IMG_WALL_EMERALD_YELLOW                                424
+#define IMG_WALL_EMERALD_RED                           425
+#define IMG_WALL_EMERALD_PURPLE                                426
+#define IMG_WALL_BD_DIAMOND                            427
+#define IMG_EXPANDABLE_WALL                            428
+#define IMG_EXPANDABLE_WALL_HORIZONTAL                 429
+#define IMG_EXPANDABLE_WALL_HORIZONTAL_EDITOR          430
+#define IMG_EXPANDABLE_WALL_VERTICAL                   431
+#define IMG_EXPANDABLE_WALL_VERTICAL_EDITOR            432
+#define IMG_EXPANDABLE_WALL_ANY                                433
+#define IMG_EXPANDABLE_WALL_ANY_EDITOR                 434
+#define IMG_EXPANDABLE_WALL_GROWING_LEFT               435
+#define IMG_EXPANDABLE_WALL_GROWING_RIGHT              436
+#define IMG_EXPANDABLE_WALL_GROWING_UP                 437
+#define IMG_EXPANDABLE_WALL_GROWING_DOWN               438
+#define IMG_BLACK_ORB                                  439
+#define IMG_SPEED_PILL                                 440
+#define IMG_DARK_YAMYAM                                        441
+#define IMG_DYNABOMB                                   442
+#define IMG_DYNABOMB_ACTIVE                            443
+#define IMG_DYNABOMB_PLAYER_1                          444
+#define IMG_DYNABOMB_PLAYER_1_ACTIVE                   445
+#define IMG_DYNABOMB_PLAYER_2                          446
+#define IMG_DYNABOMB_PLAYER_2_ACTIVE                   447
+#define IMG_DYNABOMB_PLAYER_3                          448
+#define IMG_DYNABOMB_PLAYER_3_ACTIVE                   449
+#define IMG_DYNABOMB_PLAYER_4                          450
+#define IMG_DYNABOMB_PLAYER_4_ACTIVE                   451
+#define IMG_DYNABOMB_INCREASE_NUMBER                   452
+#define IMG_DYNABOMB_INCREASE_SIZE                     453
+#define IMG_DYNABOMB_INCREASE_POWER                    454
+#define IMG_PIG                                                455
+#define IMG_PIG_DOWN                                   456
+#define IMG_PIG_UP                                     457
+#define IMG_PIG_LEFT                                   458
+#define IMG_PIG_RIGHT                                  459
+#define IMG_PIG_MOVING_DOWN                            460
+#define IMG_PIG_MOVING_UP                              461
+#define IMG_PIG_MOVING_LEFT                            462
+#define IMG_PIG_MOVING_RIGHT                           463
+#define IMG_PIG_DIGGING_DOWN                           464
+#define IMG_PIG_DIGGING_UP                             465
+#define IMG_PIG_DIGGING_LEFT                           466
+#define IMG_PIG_DIGGING_RIGHT                          467
+#define IMG_DRAGON                                     468
+#define IMG_DRAGON_DOWN                                        469
+#define IMG_DRAGON_UP                                  470
+#define IMG_DRAGON_LEFT                                        471
+#define IMG_DRAGON_RIGHT                               472
+#define IMG_DRAGON_MOVING_DOWN                         473
+#define IMG_DRAGON_MOVING_UP                           474
+#define IMG_DRAGON_MOVING_LEFT                         475
+#define IMG_DRAGON_MOVING_RIGHT                                476
+#define IMG_DRAGON_ATTACKING_DOWN                      477
+#define IMG_DRAGON_ATTACKING_UP                                478
+#define IMG_DRAGON_ATTACKING_LEFT                      479
+#define IMG_DRAGON_ATTACKING_RIGHT                     480
+#define IMG_MOLE                                       481
+#define IMG_MOLE_DOWN                                  482
+#define IMG_MOLE_UP                                    483
+#define IMG_MOLE_LEFT                                  484
+#define IMG_MOLE_RIGHT                                 485
+#define IMG_MOLE_MOVING_DOWN                           486
+#define IMG_MOLE_MOVING_UP                             487
+#define IMG_MOLE_MOVING_LEFT                           488
+#define IMG_MOLE_MOVING_RIGHT                          489
+#define IMG_MOLE_DIGGING_DOWN                          490
+#define IMG_MOLE_DIGGING_UP                            491
+#define IMG_MOLE_DIGGING_LEFT                          492
+#define IMG_MOLE_DIGGING_RIGHT                         493
+#define IMG_PENGUIN                                    494
+#define IMG_PENGUIN_EDITOR                             495
+#define IMG_PENGUIN_DOWN                               496
+#define IMG_PENGUIN_UP                                 497
+#define IMG_PENGUIN_LEFT                               498
+#define IMG_PENGUIN_RIGHT                              499
+#define IMG_PENGUIN_MOVING_DOWN                                500
+#define IMG_PENGUIN_MOVING_UP                          501
+#define IMG_PENGUIN_MOVING_LEFT                                502
+#define IMG_PENGUIN_MOVING_RIGHT                       503
+#define IMG_SATELLITE                                  504
+#define IMG_FLAMES_1_LEFT                              505
+#define IMG_FLAMES_2_LEFT                              506
+#define IMG_FLAMES_3_LEFT                              507
+#define IMG_FLAMES_1_RIGHT                             508
+#define IMG_FLAMES_2_RIGHT                             509
+#define IMG_FLAMES_3_RIGHT                             510
+#define IMG_FLAMES_1_UP                                        511
+#define IMG_FLAMES_2_UP                                        512
+#define IMG_FLAMES_3_UP                                        513
+#define IMG_FLAMES_1_DOWN                              514
+#define IMG_FLAMES_2_DOWN                              515
+#define IMG_FLAMES_3_DOWN                              516
+#define IMG_STONEBLOCK                                 517
+#define IMG_PLAYER_1                                   518
+#define IMG_PLAYER_1_EDITOR                            519
+#define IMG_PLAYER_1_DOWN                              520
+#define IMG_PLAYER_1_UP                                        521
+#define IMG_PLAYER_1_LEFT                              522
+#define IMG_PLAYER_1_RIGHT                             523
+#define IMG_PLAYER_1_MOVING_DOWN                       524
+#define IMG_PLAYER_1_MOVING_UP                         525
+#define IMG_PLAYER_1_MOVING_LEFT                       526
+#define IMG_PLAYER_1_MOVING_RIGHT                      527
+#define IMG_PLAYER_1_DIGGING_DOWN                      528
+#define IMG_PLAYER_1_DIGGING_UP                                529
+#define IMG_PLAYER_1_DIGGING_LEFT                      530
+#define IMG_PLAYER_1_DIGGING_RIGHT                     531
+#define IMG_PLAYER_1_COLLECTING_DOWN                   532
+#define IMG_PLAYER_1_COLLECTING_UP                     533
+#define IMG_PLAYER_1_COLLECTING_LEFT                   534
+#define IMG_PLAYER_1_COLLECTING_RIGHT                  535
+#define IMG_PLAYER_1_PUSHING_DOWN                      536
+#define IMG_PLAYER_1_PUSHING_UP                                537
+#define IMG_PLAYER_1_PUSHING_LEFT                      538
+#define IMG_PLAYER_1_PUSHING_RIGHT                     539
+#define IMG_PLAYER_1_SNAPPING_DOWN                     540
+#define IMG_PLAYER_1_SNAPPING_UP                       541
+#define IMG_PLAYER_1_SNAPPING_LEFT                     542
+#define IMG_PLAYER_1_SNAPPING_RIGHT                    543
+#define IMG_PLAYER_2                                   544
+#define IMG_PLAYER_2_EDITOR                            545
+#define IMG_PLAYER_2_DOWN                              546
+#define IMG_PLAYER_2_UP                                        547
+#define IMG_PLAYER_2_LEFT                              548
+#define IMG_PLAYER_2_RIGHT                             549
+#define IMG_PLAYER_2_MOVING_DOWN                       550
+#define IMG_PLAYER_2_MOVING_UP                         551
+#define IMG_PLAYER_2_MOVING_LEFT                       552
+#define IMG_PLAYER_2_MOVING_RIGHT                      553
+#define IMG_PLAYER_2_DIGGING_DOWN                      554
+#define IMG_PLAYER_2_DIGGING_UP                                555
+#define IMG_PLAYER_2_DIGGING_LEFT                      556
+#define IMG_PLAYER_2_DIGGING_RIGHT                     557
+#define IMG_PLAYER_2_COLLECTING_DOWN                   558
+#define IMG_PLAYER_2_COLLECTING_UP                     559
+#define IMG_PLAYER_2_COLLECTING_LEFT                   560
+#define IMG_PLAYER_2_COLLECTING_RIGHT                  561
+#define IMG_PLAYER_2_PUSHING_DOWN                      562
+#define IMG_PLAYER_2_PUSHING_UP                                563
+#define IMG_PLAYER_2_PUSHING_LEFT                      564
+#define IMG_PLAYER_2_PUSHING_RIGHT                     565
+#define IMG_PLAYER_2_SNAPPING_DOWN                     566
+#define IMG_PLAYER_2_SNAPPING_UP                       567
+#define IMG_PLAYER_2_SNAPPING_LEFT                     568
+#define IMG_PLAYER_2_SNAPPING_RIGHT                    569
+#define IMG_PLAYER_3                                   570
+#define IMG_PLAYER_3_EDITOR                            571
+#define IMG_PLAYER_3_DOWN                              572
+#define IMG_PLAYER_3_UP                                        573
+#define IMG_PLAYER_3_LEFT                              574
+#define IMG_PLAYER_3_RIGHT                             575
+#define IMG_PLAYER_3_MOVING_DOWN                       576
+#define IMG_PLAYER_3_MOVING_UP                         577
+#define IMG_PLAYER_3_MOVING_LEFT                       578
+#define IMG_PLAYER_3_MOVING_RIGHT                      579
+#define IMG_PLAYER_3_DIGGING_DOWN                      580
+#define IMG_PLAYER_3_DIGGING_UP                                581
+#define IMG_PLAYER_3_DIGGING_LEFT                      582
+#define IMG_PLAYER_3_DIGGING_RIGHT                     583
+#define IMG_PLAYER_3_COLLECTING_DOWN                   584
+#define IMG_PLAYER_3_COLLECTING_UP                     585
+#define IMG_PLAYER_3_COLLECTING_LEFT                   586
+#define IMG_PLAYER_3_COLLECTING_RIGHT                  587
+#define IMG_PLAYER_3_PUSHING_DOWN                      588
+#define IMG_PLAYER_3_PUSHING_UP                                589
+#define IMG_PLAYER_3_PUSHING_LEFT                      590
+#define IMG_PLAYER_3_PUSHING_RIGHT                     591
+#define IMG_PLAYER_3_SNAPPING_DOWN                     592
+#define IMG_PLAYER_3_SNAPPING_UP                       593
+#define IMG_PLAYER_3_SNAPPING_LEFT                     594
+#define IMG_PLAYER_3_SNAPPING_RIGHT                    595
+#define IMG_PLAYER_4                                   596
+#define IMG_PLAYER_4_EDITOR                            597
+#define IMG_PLAYER_4_DOWN                              598
+#define IMG_PLAYER_4_UP                                        599
+#define IMG_PLAYER_4_LEFT                              600
+#define IMG_PLAYER_4_RIGHT                             601
+#define IMG_PLAYER_4_MOVING_DOWN                       602
+#define IMG_PLAYER_4_MOVING_UP                         603
+#define IMG_PLAYER_4_MOVING_LEFT                       604
+#define IMG_PLAYER_4_MOVING_RIGHT                      605
+#define IMG_PLAYER_4_DIGGING_DOWN                      606
+#define IMG_PLAYER_4_DIGGING_UP                                607
+#define IMG_PLAYER_4_DIGGING_LEFT                      608
+#define IMG_PLAYER_4_DIGGING_RIGHT                     609
+#define IMG_PLAYER_4_COLLECTING_DOWN                   610
+#define IMG_PLAYER_4_COLLECTING_UP                     611
+#define IMG_PLAYER_4_COLLECTING_LEFT                   612
+#define IMG_PLAYER_4_COLLECTING_RIGHT                  613
+#define IMG_PLAYER_4_PUSHING_DOWN                      614
+#define IMG_PLAYER_4_PUSHING_UP                                615
+#define IMG_PLAYER_4_PUSHING_LEFT                      616
+#define IMG_PLAYER_4_PUSHING_RIGHT                     617
+#define IMG_PLAYER_4_SNAPPING_DOWN                     618
+#define IMG_PLAYER_4_SNAPPING_UP                       619
+#define IMG_PLAYER_4_SNAPPING_LEFT                     620
+#define IMG_PLAYER_4_SNAPPING_RIGHT                    621
+#define IMG_DEFAULT_EXPLODING                          622
+#define IMG_TWINKLE_BLUE                               623
+#define IMG_TWINKLE_WHITE                              624
+#define IMG_STEELWALL_TOPLEFT                          625
+#define IMG_STEELWALL_TOPRIGHT                         626
+#define IMG_STEELWALL_BOTTOMLEFT                       627
+#define IMG_STEELWALL_BOTTOMRIGHT                      628
+#define IMG_STEELWALL_HORIZONTAL                       629
+#define IMG_STEELWALL_VERTICAL                         630
+#define IMG_STEELWALL_TOPLEFT_EDITOR                   631
+#define IMG_STEELWALL_TOPRIGHT_EDITOR                  632
+#define IMG_STEELWALL_BOTTOMLEFT_EDITOR                        633
+#define IMG_STEELWALL_BOTTOMRIGHT_EDITOR               634
+#define IMG_STEELWALL_HORIZONTAL_EDITOR                        635
+#define IMG_STEELWALL_VERTICAL_EDITOR                  636
+#define IMG_INVISIBLE_STEELWALL_TOPLEFT                        637
+#define IMG_INVISIBLE_STEELWALL_TOPRIGHT               638
+#define IMG_INVISIBLE_STEELWALL_BOTTOMLEFT             639
+#define IMG_INVISIBLE_STEELWALL_BOTTOMRIGHT            640
+#define IMG_INVISIBLE_STEELWALL_HORIZONTAL             641
+#define IMG_INVISIBLE_STEELWALL_VERTICAL               642
+#define IMG_INVISIBLE_STEELWALL_TOPLEFT_EDITOR         643
+#define IMG_INVISIBLE_STEELWALL_TOPRIGHT_EDITOR                644
+#define IMG_INVISIBLE_STEELWALL_BOTTOMLEFT_EDITOR      645
+#define IMG_INVISIBLE_STEELWALL_BOTTOMRIGHT_EDITOR     646
+#define IMG_INVISIBLE_STEELWALL_HORIZONTAL_EDITOR      647
+#define IMG_INVISIBLE_STEELWALL_VERTICAL_EDITOR                648
+#define IMG_ARROW_LEFT                                 649
+#define IMG_ARROW_RIGHT                                        650
+#define IMG_ARROW_UP                                   651
+#define IMG_ARROW_DOWN                                 652
+#define IMG_UNKNOWN                                    653
+#define IMG_TRIGGER_ELEMENT                            654
+#define IMG_TRIGGER_PLAYER                             655
+#define IMG_CHAR_SPACE                                 656
+#define IMG_CHAR_EXCLAM                                        657
+#define IMG_CHAR_QUOTEDBL                              658
+#define IMG_CHAR_NUMBERSIGN                            659
+#define IMG_CHAR_DOLLAR                                        660
+#define IMG_CHAR_PROCENT                               661
+#define IMG_CHAR_AMPERSAND                             662
+#define IMG_CHAR_APOSTROPHE                            663
+#define IMG_CHAR_PARENLEFT                             664
+#define IMG_CHAR_PARENRIGHT                            665
+#define IMG_CHAR_ASTERISK                              666
+#define IMG_CHAR_PLUS                                  667
+#define IMG_CHAR_COMMA                                 668
+#define IMG_CHAR_MINUS                                 669
+#define IMG_CHAR_PERIOD                                        670
+#define IMG_CHAR_SLASH                                 671
+#define IMG_CHAR_0                                     672
+#define IMG_CHAR_1                                     673
+#define IMG_CHAR_2                                     674
+#define IMG_CHAR_3                                     675
+#define IMG_CHAR_4                                     676
+#define IMG_CHAR_5                                     677
+#define IMG_CHAR_6                                     678
+#define IMG_CHAR_7                                     679
+#define IMG_CHAR_8                                     680
+#define IMG_CHAR_9                                     681
+#define IMG_CHAR_COLON                                 682
+#define IMG_CHAR_SEMICOLON                             683
+#define IMG_CHAR_LESS                                  684
+#define IMG_CHAR_EQUAL                                 685
+#define IMG_CHAR_GREATER                               686
+#define IMG_CHAR_QUESTION                              687
+#define IMG_CHAR_AT                                    688
+#define IMG_CHAR_A                                     689
+#define IMG_CHAR_B                                     690
+#define IMG_CHAR_C                                     691
+#define IMG_CHAR_D                                     692
+#define IMG_CHAR_E                                     693
+#define IMG_CHAR_F                                     694
+#define IMG_CHAR_G                                     695
+#define IMG_CHAR_H                                     696
+#define IMG_CHAR_I                                     697
+#define IMG_CHAR_J                                     698
+#define IMG_CHAR_K                                     699
+#define IMG_CHAR_L                                     700
+#define IMG_CHAR_M                                     701
+#define IMG_CHAR_N                                     702
+#define IMG_CHAR_O                                     703
+#define IMG_CHAR_P                                     704
+#define IMG_CHAR_Q                                     705
+#define IMG_CHAR_R                                     706
+#define IMG_CHAR_S                                     707
+#define IMG_CHAR_T                                     708
+#define IMG_CHAR_U                                     709
+#define IMG_CHAR_V                                     710
+#define IMG_CHAR_W                                     711
+#define IMG_CHAR_X                                     712
+#define IMG_CHAR_Y                                     713
+#define IMG_CHAR_Z                                     714
+#define IMG_CHAR_BRACKETLEFT                           715
+#define IMG_CHAR_BACKSLASH                             716
+#define IMG_CHAR_BRACKETRIGHT                          717
+#define IMG_CHAR_ASCIICIRCUM                           718
+#define IMG_CHAR_UNDERSCORE                            719
+#define IMG_CHAR_COPYRIGHT                             720
+#define IMG_CHAR_AUMLAUT                               721
+#define IMG_CHAR_OUMLAUT                               722
+#define IMG_CHAR_UUMLAUT                               723
+#define IMG_CHAR_DEGREE                                        724
+#define IMG_CHAR_TRADEMARK                             725
+#define IMG_CHAR_CURSOR                                        726
+#define IMG_CUSTOM_1                                   727
+#define IMG_CUSTOM_1_EDITOR                            728
+#define IMG_CUSTOM_2                                   729
+#define IMG_CUSTOM_2_EDITOR                            730
+#define IMG_CUSTOM_3                                   731
+#define IMG_CUSTOM_3_EDITOR                            732
+#define IMG_CUSTOM_4                                   733
+#define IMG_CUSTOM_4_EDITOR                            734
+#define IMG_CUSTOM_5                                   735
+#define IMG_CUSTOM_5_EDITOR                            736
+#define IMG_CUSTOM_6                                   737
+#define IMG_CUSTOM_6_EDITOR                            738
+#define IMG_CUSTOM_7                                   739
+#define IMG_CUSTOM_7_EDITOR                            740
+#define IMG_CUSTOM_8                                   741
+#define IMG_CUSTOM_8_EDITOR                            742
+#define IMG_CUSTOM_9                                   743
+#define IMG_CUSTOM_9_EDITOR                            744
+#define IMG_CUSTOM_10                                  745
+#define IMG_CUSTOM_10_EDITOR                           746
+#define IMG_CUSTOM_11                                  747
+#define IMG_CUSTOM_11_EDITOR                           748
+#define IMG_CUSTOM_12                                  749
+#define IMG_CUSTOM_12_EDITOR                           750
+#define IMG_CUSTOM_13                                  751
+#define IMG_CUSTOM_13_EDITOR                           752
+#define IMG_CUSTOM_14                                  753
+#define IMG_CUSTOM_14_EDITOR                           754
+#define IMG_CUSTOM_15                                  755
+#define IMG_CUSTOM_15_EDITOR                           756
+#define IMG_CUSTOM_16                                  757
+#define IMG_CUSTOM_16_EDITOR                           758
+#define IMG_CUSTOM_17                                  759
+#define IMG_CUSTOM_17_EDITOR                           760
+#define IMG_CUSTOM_18                                  761
+#define IMG_CUSTOM_18_EDITOR                           762
+#define IMG_CUSTOM_19                                  763
+#define IMG_CUSTOM_19_EDITOR                           764
+#define IMG_CUSTOM_20                                  765
+#define IMG_CUSTOM_20_EDITOR                           766
+#define IMG_CUSTOM_21                                  767
+#define IMG_CUSTOM_21_EDITOR                           768
+#define IMG_CUSTOM_22                                  769
+#define IMG_CUSTOM_22_EDITOR                           770
+#define IMG_CUSTOM_23                                  771
+#define IMG_CUSTOM_23_EDITOR                           772
+#define IMG_CUSTOM_24                                  773
+#define IMG_CUSTOM_24_EDITOR                           774
+#define IMG_CUSTOM_25                                  775
+#define IMG_CUSTOM_25_EDITOR                           776
+#define IMG_CUSTOM_26                                  777
+#define IMG_CUSTOM_26_EDITOR                           778
+#define IMG_CUSTOM_27                                  779
+#define IMG_CUSTOM_27_EDITOR                           780
+#define IMG_CUSTOM_28                                  781
+#define IMG_CUSTOM_28_EDITOR                           782
+#define IMG_CUSTOM_29                                  783
+#define IMG_CUSTOM_29_EDITOR                           784
+#define IMG_CUSTOM_30                                  785
+#define IMG_CUSTOM_30_EDITOR                           786
+#define IMG_CUSTOM_31                                  787
+#define IMG_CUSTOM_31_EDITOR                           788
+#define IMG_CUSTOM_32                                  789
+#define IMG_CUSTOM_32_EDITOR                           790
+#define IMG_CUSTOM_33                                  791
+#define IMG_CUSTOM_33_EDITOR                           792
+#define IMG_CUSTOM_34                                  793
+#define IMG_CUSTOM_34_EDITOR                           794
+#define IMG_CUSTOM_35                                  795
+#define IMG_CUSTOM_35_EDITOR                           796
+#define IMG_CUSTOM_36                                  797
+#define IMG_CUSTOM_36_EDITOR                           798
+#define IMG_CUSTOM_37                                  799
+#define IMG_CUSTOM_37_EDITOR                           800
+#define IMG_CUSTOM_38                                  801
+#define IMG_CUSTOM_38_EDITOR                           802
+#define IMG_CUSTOM_39                                  803
+#define IMG_CUSTOM_39_EDITOR                           804
+#define IMG_CUSTOM_40                                  805
+#define IMG_CUSTOM_40_EDITOR                           806
+#define IMG_CUSTOM_41                                  807
+#define IMG_CUSTOM_41_EDITOR                           808
+#define IMG_CUSTOM_42                                  809
+#define IMG_CUSTOM_42_EDITOR                           810
+#define IMG_CUSTOM_43                                  811
+#define IMG_CUSTOM_43_EDITOR                           812
+#define IMG_CUSTOM_44                                  813
+#define IMG_CUSTOM_44_EDITOR                           814
+#define IMG_CUSTOM_45                                  815
+#define IMG_CUSTOM_45_EDITOR                           816
+#define IMG_CUSTOM_46                                  817
+#define IMG_CUSTOM_46_EDITOR                           818
+#define IMG_CUSTOM_47                                  819
+#define IMG_CUSTOM_47_EDITOR                           820
+#define IMG_CUSTOM_48                                  821
+#define IMG_CUSTOM_48_EDITOR                           822
+#define IMG_CUSTOM_49                                  823
+#define IMG_CUSTOM_49_EDITOR                           824
+#define IMG_CUSTOM_50                                  825
+#define IMG_CUSTOM_50_EDITOR                           826
+#define IMG_CUSTOM_51                                  827
+#define IMG_CUSTOM_51_EDITOR                           828
+#define IMG_CUSTOM_52                                  829
+#define IMG_CUSTOM_52_EDITOR                           830
+#define IMG_CUSTOM_53                                  831
+#define IMG_CUSTOM_53_EDITOR                           832
+#define IMG_CUSTOM_54                                  833
+#define IMG_CUSTOM_54_EDITOR                           834
+#define IMG_CUSTOM_55                                  835
+#define IMG_CUSTOM_55_EDITOR                           836
+#define IMG_CUSTOM_56                                  837
+#define IMG_CUSTOM_56_EDITOR                           838
+#define IMG_CUSTOM_57                                  839
+#define IMG_CUSTOM_57_EDITOR                           840
+#define IMG_CUSTOM_58                                  841
+#define IMG_CUSTOM_58_EDITOR                           842
+#define IMG_CUSTOM_59                                  843
+#define IMG_CUSTOM_59_EDITOR                           844
+#define IMG_CUSTOM_60                                  845
+#define IMG_CUSTOM_60_EDITOR                           846
+#define IMG_CUSTOM_61                                  847
+#define IMG_CUSTOM_61_EDITOR                           848
+#define IMG_CUSTOM_62                                  849
+#define IMG_CUSTOM_62_EDITOR                           850
+#define IMG_CUSTOM_63                                  851
+#define IMG_CUSTOM_63_EDITOR                           852
+#define IMG_CUSTOM_64                                  853
+#define IMG_CUSTOM_64_EDITOR                           854
+#define IMG_CUSTOM_65                                  855
+#define IMG_CUSTOM_65_EDITOR                           856
+#define IMG_CUSTOM_66                                  857
+#define IMG_CUSTOM_66_EDITOR                           858
+#define IMG_CUSTOM_67                                  859
+#define IMG_CUSTOM_67_EDITOR                           860
+#define IMG_CUSTOM_68                                  861
+#define IMG_CUSTOM_68_EDITOR                           862
+#define IMG_CUSTOM_69                                  863
+#define IMG_CUSTOM_69_EDITOR                           864
+#define IMG_CUSTOM_70                                  865
+#define IMG_CUSTOM_70_EDITOR                           866
+#define IMG_CUSTOM_71                                  867
+#define IMG_CUSTOM_71_EDITOR                           868
+#define IMG_CUSTOM_72                                  869
+#define IMG_CUSTOM_72_EDITOR                           870
+#define IMG_CUSTOM_73                                  871
+#define IMG_CUSTOM_73_EDITOR                           872
+#define IMG_CUSTOM_74                                  873
+#define IMG_CUSTOM_74_EDITOR                           874
+#define IMG_CUSTOM_75                                  875
+#define IMG_CUSTOM_75_EDITOR                           876
+#define IMG_CUSTOM_76                                  877
+#define IMG_CUSTOM_76_EDITOR                           878
+#define IMG_CUSTOM_77                                  879
+#define IMG_CUSTOM_77_EDITOR                           880
+#define IMG_CUSTOM_78                                  881
+#define IMG_CUSTOM_78_EDITOR                           882
+#define IMG_CUSTOM_79                                  883
+#define IMG_CUSTOM_79_EDITOR                           884
+#define IMG_CUSTOM_80                                  885
+#define IMG_CUSTOM_80_EDITOR                           886
+#define IMG_CUSTOM_81                                  887
+#define IMG_CUSTOM_81_EDITOR                           888
+#define IMG_CUSTOM_82                                  889
+#define IMG_CUSTOM_82_EDITOR                           890
+#define IMG_CUSTOM_83                                  891
+#define IMG_CUSTOM_83_EDITOR                           892
+#define IMG_CUSTOM_84                                  893
+#define IMG_CUSTOM_84_EDITOR                           894
+#define IMG_CUSTOM_85                                  895
+#define IMG_CUSTOM_85_EDITOR                           896
+#define IMG_CUSTOM_86                                  897
+#define IMG_CUSTOM_86_EDITOR                           898
+#define IMG_CUSTOM_87                                  899
+#define IMG_CUSTOM_87_EDITOR                           900
+#define IMG_CUSTOM_88                                  901
+#define IMG_CUSTOM_88_EDITOR                           902
+#define IMG_CUSTOM_89                                  903
+#define IMG_CUSTOM_89_EDITOR                           904
+#define IMG_CUSTOM_90                                  905
+#define IMG_CUSTOM_90_EDITOR                           906
+#define IMG_CUSTOM_91                                  907
+#define IMG_CUSTOM_91_EDITOR                           908
+#define IMG_CUSTOM_92                                  909
+#define IMG_CUSTOM_92_EDITOR                           910
+#define IMG_CUSTOM_93                                  911
+#define IMG_CUSTOM_93_EDITOR                           912
+#define IMG_CUSTOM_94                                  913
+#define IMG_CUSTOM_94_EDITOR                           914
+#define IMG_CUSTOM_95                                  915
+#define IMG_CUSTOM_95_EDITOR                           916
+#define IMG_CUSTOM_96                                  917
+#define IMG_CUSTOM_96_EDITOR                           918
+#define IMG_CUSTOM_97                                  919
+#define IMG_CUSTOM_97_EDITOR                           920
+#define IMG_CUSTOM_98                                  921
+#define IMG_CUSTOM_98_EDITOR                           922
+#define IMG_CUSTOM_99                                  923
+#define IMG_CUSTOM_99_EDITOR                           924
+#define IMG_CUSTOM_100                                 925
+#define IMG_CUSTOM_100_EDITOR                          926
+#define IMG_CUSTOM_101                                 927
+#define IMG_CUSTOM_101_EDITOR                          928
+#define IMG_CUSTOM_102                                 929
+#define IMG_CUSTOM_102_EDITOR                          930
+#define IMG_CUSTOM_103                                 931
+#define IMG_CUSTOM_103_EDITOR                          932
+#define IMG_CUSTOM_104                                 933
+#define IMG_CUSTOM_104_EDITOR                          934
+#define IMG_CUSTOM_105                                 935
+#define IMG_CUSTOM_105_EDITOR                          936
+#define IMG_CUSTOM_106                                 937
+#define IMG_CUSTOM_106_EDITOR                          938
+#define IMG_CUSTOM_107                                 939
+#define IMG_CUSTOM_107_EDITOR                          940
+#define IMG_CUSTOM_108                                 941
+#define IMG_CUSTOM_108_EDITOR                          942
+#define IMG_CUSTOM_109                                 943
+#define IMG_CUSTOM_109_EDITOR                          944
+#define IMG_CUSTOM_110                                 945
+#define IMG_CUSTOM_110_EDITOR                          946
+#define IMG_CUSTOM_111                                 947
+#define IMG_CUSTOM_111_EDITOR                          948
+#define IMG_CUSTOM_112                                 949
+#define IMG_CUSTOM_112_EDITOR                          950
+#define IMG_CUSTOM_113                                 951
+#define IMG_CUSTOM_113_EDITOR                          952
+#define IMG_CUSTOM_114                                 953
+#define IMG_CUSTOM_114_EDITOR                          954
+#define IMG_CUSTOM_115                                 955
+#define IMG_CUSTOM_115_EDITOR                          956
+#define IMG_CUSTOM_116                                 957
+#define IMG_CUSTOM_116_EDITOR                          958
+#define IMG_CUSTOM_117                                 959
+#define IMG_CUSTOM_117_EDITOR                          960
+#define IMG_CUSTOM_118                                 961
+#define IMG_CUSTOM_118_EDITOR                          962
+#define IMG_CUSTOM_119                                 963
+#define IMG_CUSTOM_119_EDITOR                          964
+#define IMG_CUSTOM_120                                 965
+#define IMG_CUSTOM_120_EDITOR                          966
+#define IMG_CUSTOM_121                                 967
+#define IMG_CUSTOM_121_EDITOR                          968
+#define IMG_CUSTOM_122                                 969
+#define IMG_CUSTOM_122_EDITOR                          970
+#define IMG_CUSTOM_123                                 971
+#define IMG_CUSTOM_123_EDITOR                          972
+#define IMG_CUSTOM_124                                 973
+#define IMG_CUSTOM_124_EDITOR                          974
+#define IMG_CUSTOM_125                                 975
+#define IMG_CUSTOM_125_EDITOR                          976
+#define IMG_CUSTOM_126                                 977
+#define IMG_CUSTOM_126_EDITOR                          978
+#define IMG_CUSTOM_127                                 979
+#define IMG_CUSTOM_127_EDITOR                          980
+#define IMG_CUSTOM_128                                 981
+#define IMG_CUSTOM_128_EDITOR                          982
+#define IMG_CUSTOM_129                                 983
+#define IMG_CUSTOM_129_EDITOR                          984
+#define IMG_CUSTOM_130                                 985
+#define IMG_CUSTOM_130_EDITOR                          986
+#define IMG_CUSTOM_131                                 987
+#define IMG_CUSTOM_131_EDITOR                          988
+#define IMG_CUSTOM_132                                 989
+#define IMG_CUSTOM_132_EDITOR                          990
+#define IMG_CUSTOM_133                                 991
+#define IMG_CUSTOM_133_EDITOR                          992
+#define IMG_CUSTOM_134                                 993
+#define IMG_CUSTOM_134_EDITOR                          994
+#define IMG_CUSTOM_135                                 995
+#define IMG_CUSTOM_135_EDITOR                          996
+#define IMG_CUSTOM_136                                 997
+#define IMG_CUSTOM_136_EDITOR                          998
+#define IMG_CUSTOM_137                                 999
+#define IMG_CUSTOM_137_EDITOR                          1000
+#define IMG_CUSTOM_138                                 1001
+#define IMG_CUSTOM_138_EDITOR                          1002
+#define IMG_CUSTOM_139                                 1003
+#define IMG_CUSTOM_139_EDITOR                          1004
+#define IMG_CUSTOM_140                                 1005
+#define IMG_CUSTOM_140_EDITOR                          1006
+#define IMG_CUSTOM_141                                 1007
+#define IMG_CUSTOM_141_EDITOR                          1008
+#define IMG_CUSTOM_142                                 1009
+#define IMG_CUSTOM_142_EDITOR                          1010
+#define IMG_CUSTOM_143                                 1011
+#define IMG_CUSTOM_143_EDITOR                          1012
+#define IMG_CUSTOM_144                                 1013
+#define IMG_CUSTOM_144_EDITOR                          1014
+#define IMG_CUSTOM_145                                 1015
+#define IMG_CUSTOM_145_EDITOR                          1016
+#define IMG_CUSTOM_146                                 1017
+#define IMG_CUSTOM_146_EDITOR                          1018
+#define IMG_CUSTOM_147                                 1019
+#define IMG_CUSTOM_147_EDITOR                          1020
+#define IMG_CUSTOM_148                                 1021
+#define IMG_CUSTOM_148_EDITOR                          1022
+#define IMG_CUSTOM_149                                 1023
+#define IMG_CUSTOM_149_EDITOR                          1024
+#define IMG_CUSTOM_150                                 1025
+#define IMG_CUSTOM_150_EDITOR                          1026
+#define IMG_CUSTOM_151                                 1027
+#define IMG_CUSTOM_151_EDITOR                          1028
+#define IMG_CUSTOM_152                                 1029
+#define IMG_CUSTOM_152_EDITOR                          1030
+#define IMG_CUSTOM_153                                 1031
+#define IMG_CUSTOM_153_EDITOR                          1032
+#define IMG_CUSTOM_154                                 1033
+#define IMG_CUSTOM_154_EDITOR                          1034
+#define IMG_CUSTOM_155                                 1035
+#define IMG_CUSTOM_155_EDITOR                          1036
+#define IMG_CUSTOM_156                                 1037
+#define IMG_CUSTOM_156_EDITOR                          1038
+#define IMG_CUSTOM_157                                 1039
+#define IMG_CUSTOM_157_EDITOR                          1040
+#define IMG_CUSTOM_158                                 1041
+#define IMG_CUSTOM_158_EDITOR                          1042
+#define IMG_CUSTOM_159                                 1043
+#define IMG_CUSTOM_159_EDITOR                          1044
+#define IMG_CUSTOM_160                                 1045
+#define IMG_CUSTOM_160_EDITOR                          1046
+#define IMG_CUSTOM_161                                 1047
+#define IMG_CUSTOM_161_EDITOR                          1048
+#define IMG_CUSTOM_162                                 1049
+#define IMG_CUSTOM_162_EDITOR                          1050
+#define IMG_CUSTOM_163                                 1051
+#define IMG_CUSTOM_163_EDITOR                          1052
+#define IMG_CUSTOM_164                                 1053
+#define IMG_CUSTOM_164_EDITOR                          1054
+#define IMG_CUSTOM_165                                 1055
+#define IMG_CUSTOM_165_EDITOR                          1056
+#define IMG_CUSTOM_166                                 1057
+#define IMG_CUSTOM_166_EDITOR                          1058
+#define IMG_CUSTOM_167                                 1059
+#define IMG_CUSTOM_167_EDITOR                          1060
+#define IMG_CUSTOM_168                                 1061
+#define IMG_CUSTOM_168_EDITOR                          1062
+#define IMG_CUSTOM_169                                 1063
+#define IMG_CUSTOM_169_EDITOR                          1064
+#define IMG_CUSTOM_170                                 1065
+#define IMG_CUSTOM_170_EDITOR                          1066
+#define IMG_CUSTOM_171                                 1067
+#define IMG_CUSTOM_171_EDITOR                          1068
+#define IMG_CUSTOM_172                                 1069
+#define IMG_CUSTOM_172_EDITOR                          1070
+#define IMG_CUSTOM_173                                 1071
+#define IMG_CUSTOM_173_EDITOR                          1072
+#define IMG_CUSTOM_174                                 1073
+#define IMG_CUSTOM_174_EDITOR                          1074
+#define IMG_CUSTOM_175                                 1075
+#define IMG_CUSTOM_175_EDITOR                          1076
+#define IMG_CUSTOM_176                                 1077
+#define IMG_CUSTOM_176_EDITOR                          1078
+#define IMG_CUSTOM_177                                 1079
+#define IMG_CUSTOM_177_EDITOR                          1080
+#define IMG_CUSTOM_178                                 1081
+#define IMG_CUSTOM_178_EDITOR                          1082
+#define IMG_CUSTOM_179                                 1083
+#define IMG_CUSTOM_179_EDITOR                          1084
+#define IMG_CUSTOM_180                                 1085
+#define IMG_CUSTOM_180_EDITOR                          1086
+#define IMG_CUSTOM_181                                 1087
+#define IMG_CUSTOM_181_EDITOR                          1088
+#define IMG_CUSTOM_182                                 1089
+#define IMG_CUSTOM_182_EDITOR                          1090
+#define IMG_CUSTOM_183                                 1091
+#define IMG_CUSTOM_183_EDITOR                          1092
+#define IMG_CUSTOM_184                                 1093
+#define IMG_CUSTOM_184_EDITOR                          1094
+#define IMG_CUSTOM_185                                 1095
+#define IMG_CUSTOM_185_EDITOR                          1096
+#define IMG_CUSTOM_186                                 1097
+#define IMG_CUSTOM_186_EDITOR                          1098
+#define IMG_CUSTOM_187                                 1099
+#define IMG_CUSTOM_187_EDITOR                          1100
+#define IMG_CUSTOM_188                                 1101
+#define IMG_CUSTOM_188_EDITOR                          1102
+#define IMG_CUSTOM_189                                 1103
+#define IMG_CUSTOM_189_EDITOR                          1104
+#define IMG_CUSTOM_190                                 1105
+#define IMG_CUSTOM_190_EDITOR                          1106
+#define IMG_CUSTOM_191                                 1107
+#define IMG_CUSTOM_191_EDITOR                          1108
+#define IMG_CUSTOM_192                                 1109
+#define IMG_CUSTOM_192_EDITOR                          1110
+#define IMG_CUSTOM_193                                 1111
+#define IMG_CUSTOM_193_EDITOR                          1112
+#define IMG_CUSTOM_194                                 1113
+#define IMG_CUSTOM_194_EDITOR                          1114
+#define IMG_CUSTOM_195                                 1115
+#define IMG_CUSTOM_195_EDITOR                          1116
+#define IMG_CUSTOM_196                                 1117
+#define IMG_CUSTOM_196_EDITOR                          1118
+#define IMG_CUSTOM_197                                 1119
+#define IMG_CUSTOM_197_EDITOR                          1120
+#define IMG_CUSTOM_198                                 1121
+#define IMG_CUSTOM_198_EDITOR                          1122
+#define IMG_CUSTOM_199                                 1123
+#define IMG_CUSTOM_199_EDITOR                          1124
+#define IMG_CUSTOM_200                                 1125
+#define IMG_CUSTOM_200_EDITOR                          1126
+#define IMG_CUSTOM_201                                 1127
+#define IMG_CUSTOM_201_EDITOR                          1128
+#define IMG_CUSTOM_202                                 1129
+#define IMG_CUSTOM_202_EDITOR                          1130
+#define IMG_CUSTOM_203                                 1131
+#define IMG_CUSTOM_203_EDITOR                          1132
+#define IMG_CUSTOM_204                                 1133
+#define IMG_CUSTOM_204_EDITOR                          1134
+#define IMG_CUSTOM_205                                 1135
+#define IMG_CUSTOM_205_EDITOR                          1136
+#define IMG_CUSTOM_206                                 1137
+#define IMG_CUSTOM_206_EDITOR                          1138
+#define IMG_CUSTOM_207                                 1139
+#define IMG_CUSTOM_207_EDITOR                          1140
+#define IMG_CUSTOM_208                                 1141
+#define IMG_CUSTOM_208_EDITOR                          1142
+#define IMG_CUSTOM_209                                 1143
+#define IMG_CUSTOM_209_EDITOR                          1144
+#define IMG_CUSTOM_210                                 1145
+#define IMG_CUSTOM_210_EDITOR                          1146
+#define IMG_CUSTOM_211                                 1147
+#define IMG_CUSTOM_211_EDITOR                          1148
+#define IMG_CUSTOM_212                                 1149
+#define IMG_CUSTOM_212_EDITOR                          1150
+#define IMG_CUSTOM_213                                 1151
+#define IMG_CUSTOM_213_EDITOR                          1152
+#define IMG_CUSTOM_214                                 1153
+#define IMG_CUSTOM_214_EDITOR                          1154
+#define IMG_CUSTOM_215                                 1155
+#define IMG_CUSTOM_215_EDITOR                          1156
+#define IMG_CUSTOM_216                                 1157
+#define IMG_CUSTOM_216_EDITOR                          1158
+#define IMG_CUSTOM_217                                 1159
+#define IMG_CUSTOM_217_EDITOR                          1160
+#define IMG_CUSTOM_218                                 1161
+#define IMG_CUSTOM_218_EDITOR                          1162
+#define IMG_CUSTOM_219                                 1163
+#define IMG_CUSTOM_219_EDITOR                          1164
+#define IMG_CUSTOM_220                                 1165
+#define IMG_CUSTOM_220_EDITOR                          1166
+#define IMG_CUSTOM_221                                 1167
+#define IMG_CUSTOM_221_EDITOR                          1168
+#define IMG_CUSTOM_222                                 1169
+#define IMG_CUSTOM_222_EDITOR                          1170
+#define IMG_CUSTOM_223                                 1171
+#define IMG_CUSTOM_223_EDITOR                          1172
+#define IMG_CUSTOM_224                                 1173
+#define IMG_CUSTOM_224_EDITOR                          1174
+#define IMG_CUSTOM_225                                 1175
+#define IMG_CUSTOM_225_EDITOR                          1176
+#define IMG_CUSTOM_226                                 1177
+#define IMG_CUSTOM_226_EDITOR                          1178
+#define IMG_CUSTOM_227                                 1179
+#define IMG_CUSTOM_227_EDITOR                          1180
+#define IMG_CUSTOM_228                                 1181
+#define IMG_CUSTOM_228_EDITOR                          1182
+#define IMG_CUSTOM_229                                 1183
+#define IMG_CUSTOM_229_EDITOR                          1184
+#define IMG_CUSTOM_230                                 1185
+#define IMG_CUSTOM_230_EDITOR                          1186
+#define IMG_CUSTOM_231                                 1187
+#define IMG_CUSTOM_231_EDITOR                          1188
+#define IMG_CUSTOM_232                                 1189
+#define IMG_CUSTOM_232_EDITOR                          1190
+#define IMG_CUSTOM_233                                 1191
+#define IMG_CUSTOM_233_EDITOR                          1192
+#define IMG_CUSTOM_234                                 1193
+#define IMG_CUSTOM_234_EDITOR                          1194
+#define IMG_CUSTOM_235                                 1195
+#define IMG_CUSTOM_235_EDITOR                          1196
+#define IMG_CUSTOM_236                                 1197
+#define IMG_CUSTOM_236_EDITOR                          1198
+#define IMG_CUSTOM_237                                 1199
+#define IMG_CUSTOM_237_EDITOR                          1200
+#define IMG_CUSTOM_238                                 1201
+#define IMG_CUSTOM_238_EDITOR                          1202
+#define IMG_CUSTOM_239                                 1203
+#define IMG_CUSTOM_239_EDITOR                          1204
+#define IMG_CUSTOM_240                                 1205
+#define IMG_CUSTOM_240_EDITOR                          1206
+#define IMG_CUSTOM_241                                 1207
+#define IMG_CUSTOM_241_EDITOR                          1208
+#define IMG_CUSTOM_242                                 1209
+#define IMG_CUSTOM_242_EDITOR                          1210
+#define IMG_CUSTOM_243                                 1211
+#define IMG_CUSTOM_243_EDITOR                          1212
+#define IMG_CUSTOM_244                                 1213
+#define IMG_CUSTOM_244_EDITOR                          1214
+#define IMG_CUSTOM_245                                 1215
+#define IMG_CUSTOM_245_EDITOR                          1216
+#define IMG_CUSTOM_246                                 1217
+#define IMG_CUSTOM_246_EDITOR                          1218
+#define IMG_CUSTOM_247                                 1219
+#define IMG_CUSTOM_247_EDITOR                          1220
+#define IMG_CUSTOM_248                                 1221
+#define IMG_CUSTOM_248_EDITOR                          1222
+#define IMG_CUSTOM_249                                 1223
+#define IMG_CUSTOM_249_EDITOR                          1224
+#define IMG_CUSTOM_250                                 1225
+#define IMG_CUSTOM_250_EDITOR                          1226
+#define IMG_CUSTOM_251                                 1227
+#define IMG_CUSTOM_251_EDITOR                          1228
+#define IMG_CUSTOM_252                                 1229
+#define IMG_CUSTOM_252_EDITOR                          1230
+#define IMG_CUSTOM_253                                 1231
+#define IMG_CUSTOM_253_EDITOR                          1232
+#define IMG_CUSTOM_254                                 1233
+#define IMG_CUSTOM_254_EDITOR                          1234
+#define IMG_CUSTOM_255                                 1235
+#define IMG_CUSTOM_255_EDITOR                          1236
+#define IMG_CUSTOM_256                                 1237
+#define IMG_CUSTOM_256_EDITOR                          1238
+#define IMG_GROUP_1                                    1239
+#define IMG_GROUP_1_EDITOR                             1240
+#define IMG_GROUP_2                                    1241
+#define IMG_GROUP_2_EDITOR                             1242
+#define IMG_GROUP_3                                    1243
+#define IMG_GROUP_3_EDITOR                             1244
+#define IMG_GROUP_4                                    1245
+#define IMG_GROUP_4_EDITOR                             1246
+#define IMG_GROUP_5                                    1247
+#define IMG_GROUP_5_EDITOR                             1248
+#define IMG_GROUP_6                                    1249
+#define IMG_GROUP_6_EDITOR                             1250
+#define IMG_GROUP_7                                    1251
+#define IMG_GROUP_7_EDITOR                             1252
+#define IMG_GROUP_8                                    1253
+#define IMG_GROUP_8_EDITOR                             1254
+#define IMG_GROUP_9                                    1255
+#define IMG_GROUP_9_EDITOR                             1256
+#define IMG_GROUP_10                                   1257
+#define IMG_GROUP_10_EDITOR                            1258
+#define IMG_GROUP_11                                   1259
+#define IMG_GROUP_11_EDITOR                            1260
+#define IMG_GROUP_12                                   1261
+#define IMG_GROUP_12_EDITOR                            1262
+#define IMG_GROUP_13                                   1263
+#define IMG_GROUP_13_EDITOR                            1264
+#define IMG_GROUP_14                                   1265
+#define IMG_GROUP_14_EDITOR                            1266
+#define IMG_GROUP_15                                   1267
+#define IMG_GROUP_15_EDITOR                            1268
+#define IMG_GROUP_16                                   1269
+#define IMG_GROUP_16_EDITOR                            1270
+#define IMG_GROUP_17                                   1271
+#define IMG_GROUP_17_EDITOR                            1272
+#define IMG_GROUP_18                                   1273
+#define IMG_GROUP_18_EDITOR                            1274
+#define IMG_GROUP_19                                   1275
+#define IMG_GROUP_19_EDITOR                            1276
+#define IMG_GROUP_20                                   1277
+#define IMG_GROUP_20_EDITOR                            1278
+#define IMG_GROUP_21                                   1279
+#define IMG_GROUP_21_EDITOR                            1280
+#define IMG_GROUP_22                                   1281
+#define IMG_GROUP_22_EDITOR                            1282
+#define IMG_GROUP_23                                   1283
+#define IMG_GROUP_23_EDITOR                            1284
+#define IMG_GROUP_24                                   1285
+#define IMG_GROUP_24_EDITOR                            1286
+#define IMG_GROUP_25                                   1287
+#define IMG_GROUP_25_EDITOR                            1288
+#define IMG_GROUP_26                                   1289
+#define IMG_GROUP_26_EDITOR                            1290
+#define IMG_GROUP_27                                   1291
+#define IMG_GROUP_27_EDITOR                            1292
+#define IMG_GROUP_28                                   1293
+#define IMG_GROUP_28_EDITOR                            1294
+#define IMG_GROUP_29                                   1295
+#define IMG_GROUP_29_EDITOR                            1296
+#define IMG_GROUP_30                                   1297
+#define IMG_GROUP_30_EDITOR                            1298
+#define IMG_GROUP_31                                   1299
+#define IMG_GROUP_31_EDITOR                            1300
+#define IMG_GROUP_32                                   1301
+#define IMG_GROUP_32_EDITOR                            1302
+#define IMG_TOON_1                                     1303
+#define IMG_TOON_2                                     1304
+#define IMG_TOON_3                                     1305
+#define IMG_TOON_4                                     1306
+#define IMG_TOON_5                                     1307
+#define IMG_TOON_6                                     1308
+#define IMG_TOON_7                                     1309
+#define IMG_TOON_8                                     1310
+#define IMG_TOON_9                                     1311
+#define IMG_TOON_10                                    1312
+#define IMG_TOON_11                                    1313
+#define IMG_TOON_12                                    1314
+#define IMG_TOON_13                                    1315
+#define IMG_TOON_14                                    1316
+#define IMG_TOON_15                                    1317
+#define IMG_TOON_16                                    1318
+#define IMG_TOON_17                                    1319
+#define IMG_TOON_18                                    1320
+#define IMG_TOON_19                                    1321
+#define IMG_TOON_20                                    1322
+#define IMG_MENU_CALIBRATE_RED                         1323
+#define IMG_MENU_CALIBRATE_BLUE                                1324
+#define IMG_MENU_CALIBRATE_YELLOW                      1325
+#define IMG_MENU_BUTTON                                        1326
+#define IMG_MENU_BUTTON_ACTIVE                         1327
+#define IMG_MENU_BUTTON_LEFT                           1328
+#define IMG_MENU_BUTTON_RIGHT                          1329
+#define IMG_MENU_BUTTON_UP                             1330
+#define IMG_MENU_BUTTON_DOWN                           1331
+#define IMG_MENU_BUTTON_LEFT_ACTIVE                    1332
+#define IMG_MENU_BUTTON_RIGHT_ACTIVE                   1333
+#define IMG_MENU_BUTTON_UP_ACTIVE                      1334
+#define IMG_MENU_BUTTON_DOWN_ACTIVE                    1335
+#define IMG_MENU_SCROLLBAR                             1336
+#define IMG_MENU_SCROLLBAR_ACTIVE                      1337
+#define IMG_FONT_INITIAL_1                             1338
+#define IMG_FONT_INITIAL_2                             1339
+#define IMG_FONT_INITIAL_3                             1340
+#define IMG_FONT_INITIAL_4                             1341
+#define IMG_FONT_TITLE_1                               1342
+#define IMG_FONT_TITLE_1_LEVELS                                1343
+#define IMG_FONT_TITLE_2                               1344
+#define IMG_FONT_MENU_1                                        1345
+#define IMG_FONT_MENU_2                                        1346
+#define IMG_FONT_TEXT_1                                        1347
+#define IMG_FONT_TEXT_1_LEVELS                         1348
+#define IMG_FONT_TEXT_1_PREVIEW                                1349
+#define IMG_FONT_TEXT_1_SCORES                         1350
+#define IMG_FONT_TEXT_1_ACTIVE_SCORES                  1351
+#define IMG_FONT_TEXT_2                                        1352
+#define IMG_FONT_TEXT_2_LEVELS                         1353
+#define IMG_FONT_TEXT_2_PREVIEW                                1354
+#define IMG_FONT_TEXT_2_SCORES                         1355
+#define IMG_FONT_TEXT_2_ACTIVE_SCORES                  1356
+#define IMG_FONT_TEXT_3                                        1357
+#define IMG_FONT_TEXT_3_LEVELS                         1358
+#define IMG_FONT_TEXT_3_PREVIEW                                1359
+#define IMG_FONT_TEXT_3_SCORES                         1360
+#define IMG_FONT_TEXT_3_ACTIVE_SCORES                  1361
+#define IMG_FONT_TEXT_4                                        1362
+#define IMG_FONT_TEXT_4_LEVELS                         1363
+#define IMG_FONT_TEXT_4_SCORES                         1364
+#define IMG_FONT_TEXT_4_ACTIVE_SCORES                  1365
+#define IMG_FONT_ENVELOPE_1                            1366
+#define IMG_FONT_ENVELOPE_2                            1367
+#define IMG_FONT_ENVELOPE_3                            1368
+#define IMG_FONT_ENVELOPE_4                            1369
+#define IMG_FONT_INPUT_1                               1370
+#define IMG_FONT_INPUT_1_MAIN                          1371
+#define IMG_FONT_INPUT_1_ACTIVE                                1372
+#define IMG_FONT_INPUT_1_ACTIVE_MAIN                   1373
+#define IMG_FONT_INPUT_1_ACTIVE_SETUP                  1374
+#define IMG_FONT_INPUT_2                               1375
+#define IMG_FONT_INPUT_2_ACTIVE                                1376
+#define IMG_FONT_OPTION_OFF                            1377
+#define IMG_FONT_OPTION_ON                             1378
+#define IMG_FONT_VALUE_1                               1379
+#define IMG_FONT_VALUE_2                               1380
+#define IMG_FONT_VALUE_OLD                             1381
+#define IMG_FONT_LEVEL_NUMBER                          1382
+#define IMG_FONT_TAPE_RECORDER                         1383
+#define IMG_FONT_GAME_INFO                             1384
+#define IMG_GLOBAL_BORDER                              1385
+#define IMG_GLOBAL_DOOR                                        1386
+#define IMG_EDITOR_ELEMENT_BORDER                      1387
+#define IMG_EDITOR_ELEMENT_BORDER_INPUT                        1388
+#define IMG_BACKGROUND_ENVELOPE_1                      1389
+#define IMG_BACKGROUND_ENVELOPE_2                      1390
+#define IMG_BACKGROUND_ENVELOPE_3                      1391
+#define IMG_BACKGROUND_ENVELOPE_4                      1392
+#define IMG_BACKGROUND                                 1393
+#define IMG_BACKGROUND_MAIN                            1394
+#define IMG_BACKGROUND_LEVELS                          1395
+#define IMG_BACKGROUND_SCORES                          1396
+#define IMG_BACKGROUND_EDITOR                          1397
+#define IMG_BACKGROUND_INFO                            1398
+#define IMG_BACKGROUND_INFO_ELEMENTS                   1399
+#define IMG_BACKGROUND_SETUP                           1400
+#define IMG_BACKGROUND_DOOR                            1401
 
-#define NUM_IMAGE_FILES                                        1313
+#define NUM_IMAGE_FILES                                        1402
 
 #endif /* CONF_GFX_H */
diff --git a/src/conf_grp.c b/src/conf_grp.c
new file mode 100644 (file)
index 0000000..fa80f98
--- /dev/null
@@ -0,0 +1,278 @@
+/***********************************************************
+* Rocks'n'Diamonds -- McDuffin Strikes Back!               *
+*----------------------------------------------------------*
+* (c) 1995-2002 Artsoft Entertainment                      *
+*               Holger Schemel                             *
+*               Detmolder Strasse 189                      *
+*               33604 Bielefeld                            *
+*               Germany                                    *
+*               e-mail: info@artsoft.org                   *
+*----------------------------------------------------------*
+* conf_grp.c                                               *
+***********************************************************/
+
+/* ----- this file was automatically generated -- do not edit by hand ----- */
+
+#ifndef CONF_GRP_C
+#define CONF_GRP_C
+
+/* values for graphics configuration (group elements) */
+
+  { "group_1",                                 "RocksDC.pcx"           },
+  { "group_1.xpos",                            "4"                     },
+  { "group_1.ypos",                            "15"                    },
+  { "group_1.frames",                          "1"                     },
+  { "group_1.EDITOR",                          "RocksDC.pcx"           },
+  { "group_1.EDITOR.xpos",                     "14"                    },
+  { "group_1.EDITOR.ypos",                     "15"                    },
+
+  { "group_2",                                 "RocksDC.pcx"           },
+  { "group_2.xpos",                            "4"                     },
+  { "group_2.ypos",                            "15"                    },
+  { "group_2.frames",                          "1"                     },
+  { "group_2.EDITOR",                          "RocksDC.pcx"           },
+  { "group_2.EDITOR.xpos",                     "14"                    },
+  { "group_2.EDITOR.ypos",                     "15"                    },
+
+  { "group_3",                                 "RocksDC.pcx"           },
+  { "group_3.xpos",                            "4"                     },
+  { "group_3.ypos",                            "15"                    },
+  { "group_3.frames",                          "1"                     },
+  { "group_3.EDITOR",                          "RocksDC.pcx"           },
+  { "group_3.EDITOR.xpos",                     "14"                    },
+  { "group_3.EDITOR.ypos",                     "15"                    },
+
+  { "group_4",                                 "RocksDC.pcx"           },
+  { "group_4.xpos",                            "4"                     },
+  { "group_4.ypos",                            "15"                    },
+  { "group_4.frames",                          "1"                     },
+  { "group_4.EDITOR",                          "RocksDC.pcx"           },
+  { "group_4.EDITOR.xpos",                     "14"                    },
+  { "group_4.EDITOR.ypos",                     "15"                    },
+
+  { "group_5",                                 "RocksDC.pcx"           },
+  { "group_5.xpos",                            "4"                     },
+  { "group_5.ypos",                            "15"                    },
+  { "group_5.frames",                          "1"                     },
+  { "group_5.EDITOR",                          "RocksDC.pcx"           },
+  { "group_5.EDITOR.xpos",                     "14"                    },
+  { "group_5.EDITOR.ypos",                     "15"                    },
+
+  { "group_6",                                 "RocksDC.pcx"           },
+  { "group_6.xpos",                            "4"                     },
+  { "group_6.ypos",                            "15"                    },
+  { "group_6.frames",                          "1"                     },
+  { "group_6.EDITOR",                          "RocksDC.pcx"           },
+  { "group_6.EDITOR.xpos",                     "14"                    },
+  { "group_6.EDITOR.ypos",                     "15"                    },
+
+  { "group_7",                                 "RocksDC.pcx"           },
+  { "group_7.xpos",                            "4"                     },
+  { "group_7.ypos",                            "15"                    },
+  { "group_7.frames",                          "1"                     },
+  { "group_7.EDITOR",                          "RocksDC.pcx"           },
+  { "group_7.EDITOR.xpos",                     "14"                    },
+  { "group_7.EDITOR.ypos",                     "15"                    },
+
+  { "group_8",                                 "RocksDC.pcx"           },
+  { "group_8.xpos",                            "4"                     },
+  { "group_8.ypos",                            "15"                    },
+  { "group_8.frames",                          "1"                     },
+  { "group_8.EDITOR",                          "RocksDC.pcx"           },
+  { "group_8.EDITOR.xpos",                     "14"                    },
+  { "group_8.EDITOR.ypos",                     "15"                    },
+
+  { "group_9",                                 "RocksDC.pcx"           },
+  { "group_9.xpos",                            "4"                     },
+  { "group_9.ypos",                            "15"                    },
+  { "group_9.frames",                          "1"                     },
+  { "group_9.EDITOR",                          "RocksDC.pcx"           },
+  { "group_9.EDITOR.xpos",                     "14"                    },
+  { "group_9.EDITOR.ypos",                     "15"                    },
+
+  { "group_10",                                        "RocksDC.pcx"           },
+  { "group_10.xpos",                           "4"                     },
+  { "group_10.ypos",                           "15"                    },
+  { "group_10.frames",                         "1"                     },
+  { "group_10.EDITOR",                         "RocksDC.pcx"           },
+  { "group_10.EDITOR.xpos",                    "14"                    },
+  { "group_10.EDITOR.ypos",                    "15"                    },
+
+  { "group_11",                                        "RocksDC.pcx"           },
+  { "group_11.xpos",                           "4"                     },
+  { "group_11.ypos",                           "15"                    },
+  { "group_11.frames",                         "1"                     },
+  { "group_11.EDITOR",                         "RocksDC.pcx"           },
+  { "group_11.EDITOR.xpos",                    "14"                    },
+  { "group_11.EDITOR.ypos",                    "15"                    },
+
+  { "group_12",                                        "RocksDC.pcx"           },
+  { "group_12.xpos",                           "4"                     },
+  { "group_12.ypos",                           "15"                    },
+  { "group_12.frames",                         "1"                     },
+  { "group_12.EDITOR",                         "RocksDC.pcx"           },
+  { "group_12.EDITOR.xpos",                    "14"                    },
+  { "group_12.EDITOR.ypos",                    "15"                    },
+
+  { "group_13",                                        "RocksDC.pcx"           },
+  { "group_13.xpos",                           "4"                     },
+  { "group_13.ypos",                           "15"                    },
+  { "group_13.frames",                         "1"                     },
+  { "group_13.EDITOR",                         "RocksDC.pcx"           },
+  { "group_13.EDITOR.xpos",                    "14"                    },
+  { "group_13.EDITOR.ypos",                    "15"                    },
+
+  { "group_14",                                        "RocksDC.pcx"           },
+  { "group_14.xpos",                           "4"                     },
+  { "group_14.ypos",                           "15"                    },
+  { "group_14.frames",                         "1"                     },
+  { "group_14.EDITOR",                         "RocksDC.pcx"           },
+  { "group_14.EDITOR.xpos",                    "14"                    },
+  { "group_14.EDITOR.ypos",                    "15"                    },
+
+  { "group_15",                                        "RocksDC.pcx"           },
+  { "group_15.xpos",                           "4"                     },
+  { "group_15.ypos",                           "15"                    },
+  { "group_15.frames",                         "1"                     },
+  { "group_15.EDITOR",                         "RocksDC.pcx"           },
+  { "group_15.EDITOR.xpos",                    "14"                    },
+  { "group_15.EDITOR.ypos",                    "15"                    },
+
+  { "group_16",                                        "RocksDC.pcx"           },
+  { "group_16.xpos",                           "4"                     },
+  { "group_16.ypos",                           "15"                    },
+  { "group_16.frames",                         "1"                     },
+  { "group_16.EDITOR",                         "RocksDC.pcx"           },
+  { "group_16.EDITOR.xpos",                    "14"                    },
+  { "group_16.EDITOR.ypos",                    "15"                    },
+
+  { "group_17",                                        "RocksDC.pcx"           },
+  { "group_17.xpos",                           "4"                     },
+  { "group_17.ypos",                           "15"                    },
+  { "group_17.frames",                         "1"                     },
+  { "group_17.EDITOR",                         "RocksDC.pcx"           },
+  { "group_17.EDITOR.xpos",                    "14"                    },
+  { "group_17.EDITOR.ypos",                    "15"                    },
+
+  { "group_18",                                        "RocksDC.pcx"           },
+  { "group_18.xpos",                           "4"                     },
+  { "group_18.ypos",                           "15"                    },
+  { "group_18.frames",                         "1"                     },
+  { "group_18.EDITOR",                         "RocksDC.pcx"           },
+  { "group_18.EDITOR.xpos",                    "14"                    },
+  { "group_18.EDITOR.ypos",                    "15"                    },
+
+  { "group_19",                                        "RocksDC.pcx"           },
+  { "group_19.xpos",                           "4"                     },
+  { "group_19.ypos",                           "15"                    },
+  { "group_19.frames",                         "1"                     },
+  { "group_19.EDITOR",                         "RocksDC.pcx"           },
+  { "group_19.EDITOR.xpos",                    "14"                    },
+  { "group_19.EDITOR.ypos",                    "15"                    },
+
+  { "group_20",                                        "RocksDC.pcx"           },
+  { "group_20.xpos",                           "4"                     },
+  { "group_20.ypos",                           "15"                    },
+  { "group_20.frames",                         "1"                     },
+  { "group_20.EDITOR",                         "RocksDC.pcx"           },
+  { "group_20.EDITOR.xpos",                    "14"                    },
+  { "group_20.EDITOR.ypos",                    "15"                    },
+
+  { "group_21",                                        "RocksDC.pcx"           },
+  { "group_21.xpos",                           "4"                     },
+  { "group_21.ypos",                           "15"                    },
+  { "group_21.frames",                         "1"                     },
+  { "group_21.EDITOR",                         "RocksDC.pcx"           },
+  { "group_21.EDITOR.xpos",                    "14"                    },
+  { "group_21.EDITOR.ypos",                    "15"                    },
+
+  { "group_22",                                        "RocksDC.pcx"           },
+  { "group_22.xpos",                           "4"                     },
+  { "group_22.ypos",                           "15"                    },
+  { "group_22.frames",                         "1"                     },
+  { "group_22.EDITOR",                         "RocksDC.pcx"           },
+  { "group_22.EDITOR.xpos",                    "14"                    },
+  { "group_22.EDITOR.ypos",                    "15"                    },
+
+  { "group_23",                                        "RocksDC.pcx"           },
+  { "group_23.xpos",                           "4"                     },
+  { "group_23.ypos",                           "15"                    },
+  { "group_23.frames",                         "1"                     },
+  { "group_23.EDITOR",                         "RocksDC.pcx"           },
+  { "group_23.EDITOR.xpos",                    "14"                    },
+  { "group_23.EDITOR.ypos",                    "15"                    },
+
+  { "group_24",                                        "RocksDC.pcx"           },
+  { "group_24.xpos",                           "4"                     },
+  { "group_24.ypos",                           "15"                    },
+  { "group_24.frames",                         "1"                     },
+  { "group_24.EDITOR",                         "RocksDC.pcx"           },
+  { "group_24.EDITOR.xpos",                    "14"                    },
+  { "group_24.EDITOR.ypos",                    "15"                    },
+
+  { "group_25",                                        "RocksDC.pcx"           },
+  { "group_25.xpos",                           "4"                     },
+  { "group_25.ypos",                           "15"                    },
+  { "group_25.frames",                         "1"                     },
+  { "group_25.EDITOR",                         "RocksDC.pcx"           },
+  { "group_25.EDITOR.xpos",                    "14"                    },
+  { "group_25.EDITOR.ypos",                    "15"                    },
+
+  { "group_26",                                        "RocksDC.pcx"           },
+  { "group_26.xpos",                           "4"                     },
+  { "group_26.ypos",                           "15"                    },
+  { "group_26.frames",                         "1"                     },
+  { "group_26.EDITOR",                         "RocksDC.pcx"           },
+  { "group_26.EDITOR.xpos",                    "14"                    },
+  { "group_26.EDITOR.ypos",                    "15"                    },
+
+  { "group_27",                                        "RocksDC.pcx"           },
+  { "group_27.xpos",                           "4"                     },
+  { "group_27.ypos",                           "15"                    },
+  { "group_27.frames",                         "1"                     },
+  { "group_27.EDITOR",                         "RocksDC.pcx"           },
+  { "group_27.EDITOR.xpos",                    "14"                    },
+  { "group_27.EDITOR.ypos",                    "15"                    },
+
+  { "group_28",                                        "RocksDC.pcx"           },
+  { "group_28.xpos",                           "4"                     },
+  { "group_28.ypos",                           "15"                    },
+  { "group_28.frames",                         "1"                     },
+  { "group_28.EDITOR",                         "RocksDC.pcx"           },
+  { "group_28.EDITOR.xpos",                    "14"                    },
+  { "group_28.EDITOR.ypos",                    "15"                    },
+
+  { "group_29",                                        "RocksDC.pcx"           },
+  { "group_29.xpos",                           "4"                     },
+  { "group_29.ypos",                           "15"                    },
+  { "group_29.frames",                         "1"                     },
+  { "group_29.EDITOR",                         "RocksDC.pcx"           },
+  { "group_29.EDITOR.xpos",                    "14"                    },
+  { "group_29.EDITOR.ypos",                    "15"                    },
+
+  { "group_30",                                        "RocksDC.pcx"           },
+  { "group_30.xpos",                           "4"                     },
+  { "group_30.ypos",                           "15"                    },
+  { "group_30.frames",                         "1"                     },
+  { "group_30.EDITOR",                         "RocksDC.pcx"           },
+  { "group_30.EDITOR.xpos",                    "14"                    },
+  { "group_30.EDITOR.ypos",                    "15"                    },
+
+  { "group_31",                                        "RocksDC.pcx"           },
+  { "group_31.xpos",                           "4"                     },
+  { "group_31.ypos",                           "15"                    },
+  { "group_31.frames",                         "1"                     },
+  { "group_31.EDITOR",                         "RocksDC.pcx"           },
+  { "group_31.EDITOR.xpos",                    "14"                    },
+  { "group_31.EDITOR.ypos",                    "15"                    },
+
+  { "group_32",                                        "RocksDC.pcx"           },
+  { "group_32.xpos",                           "4"                     },
+  { "group_32.ypos",                           "15"                    },
+  { "group_32.frames",                         "1"                     },
+  { "group_32.EDITOR",                         "RocksDC.pcx"           },
+  { "group_32.EDITOR.xpos",                    "14"                    },
+  { "group_32.EDITOR.ypos",                    "15"                    },
+
+
+#endif /* CONF_GRP_C */
diff --git a/src/conf_grp.h b/src/conf_grp.h
new file mode 100644 (file)
index 0000000..ef1ca99
--- /dev/null
@@ -0,0 +1,54 @@
+/***********************************************************
+* Rocks'n'Diamonds -- McDuffin Strikes Back!               *
+*----------------------------------------------------------*
+* (c) 1995-2002 Artsoft Entertainment                      *
+*               Holger Schemel                             *
+*               Detmolder Strasse 189                      *
+*               33604 Bielefeld                            *
+*               Germany                                    *
+*               e-mail: info@artsoft.org                   *
+*----------------------------------------------------------*
+* conf_grp.h                                               *
+***********************************************************/
+
+/* ----- this file was automatically generated -- do not edit by hand ----- */
+
+#ifndef CONF_GRP_H
+#define CONF_GRP_H
+
+/* values for elements configuration (group elements) */
+
+#define EL_GROUP_1                     (EL_GROUP_START + 0)
+#define EL_GROUP_2                     (EL_GROUP_START + 1)
+#define EL_GROUP_3                     (EL_GROUP_START + 2)
+#define EL_GROUP_4                     (EL_GROUP_START + 3)
+#define EL_GROUP_5                     (EL_GROUP_START + 4)
+#define EL_GROUP_6                     (EL_GROUP_START + 5)
+#define EL_GROUP_7                     (EL_GROUP_START + 6)
+#define EL_GROUP_8                     (EL_GROUP_START + 7)
+#define EL_GROUP_9                     (EL_GROUP_START + 8)
+#define EL_GROUP_10                    (EL_GROUP_START + 9)
+#define EL_GROUP_11                    (EL_GROUP_START + 10)
+#define EL_GROUP_12                    (EL_GROUP_START + 11)
+#define EL_GROUP_13                    (EL_GROUP_START + 12)
+#define EL_GROUP_14                    (EL_GROUP_START + 13)
+#define EL_GROUP_15                    (EL_GROUP_START + 14)
+#define EL_GROUP_16                    (EL_GROUP_START + 15)
+#define EL_GROUP_17                    (EL_GROUP_START + 16)
+#define EL_GROUP_18                    (EL_GROUP_START + 17)
+#define EL_GROUP_19                    (EL_GROUP_START + 18)
+#define EL_GROUP_20                    (EL_GROUP_START + 19)
+#define EL_GROUP_21                    (EL_GROUP_START + 20)
+#define EL_GROUP_22                    (EL_GROUP_START + 21)
+#define EL_GROUP_23                    (EL_GROUP_START + 22)
+#define EL_GROUP_24                    (EL_GROUP_START + 23)
+#define EL_GROUP_25                    (EL_GROUP_START + 24)
+#define EL_GROUP_26                    (EL_GROUP_START + 25)
+#define EL_GROUP_27                    (EL_GROUP_START + 26)
+#define EL_GROUP_28                    (EL_GROUP_START + 27)
+#define EL_GROUP_29                    (EL_GROUP_START + 28)
+#define EL_GROUP_30                    (EL_GROUP_START + 29)
+#define EL_GROUP_31                    (EL_GROUP_START + 30)
+#define EL_GROUP_32                    (EL_GROUP_START + 31)
+
+#endif /* CONF_GRP_C */
index 68cd4cfb8335f26a5e1cbc6b2df26ba58b8d5d66..a7f7eb222856f4c3e079991d7c2f8676bf74182f 100644 (file)
@@ -530,11 +530,11 @@ struct ConfigInfo helptext_config[] =
   },
   {
     "yamyam",
-    "Cruncher: Eats diamonds and you, if you're not careful"
+    "Yam Yam: Eats diamonds and you, if you're not careful"
   },
   {
     "dark_yamyam",
-    "Cruncher (BD style): Eats almost everything"
+    "Dark Yam Yam: Eats almost everything"
   },
   {
     "robot",
index aa6bde03bf82d6520cfe0a15034915b27386b3de..7e962cc66ae8d15e60db268447301c5881e7324c 100644 (file)
@@ -1 +1 @@
-#define COMPILE_DATE_STRING "[2003-12-14 02:31]"
+#define COMPILE_DATE_STRING "[2004-06-07 01:56]"
index 9914b16f83b5a60a81f8ceb500e426bfec6b8b0a..9236f0a910ae59ed43758a5845921672d10bb7c4 100644 (file)
@@ -47,6 +47,8 @@
 #define ED_CTRL1_BUTTONS_GFX_YPOS      236
 #define ED_CTRL2_BUTTONS_GFX_YPOS      236
 #define ED_CTRL3_BUTTONS_GFX_YPOS      324
+#define ED_CTRL4_BUTTONS_GFX_XPOS      44
+#define ED_CTRL4_BUTTONS_GFX_YPOS      214
 #define ED_CTRL1_BUTTONS_ALT_GFX_YPOS  142
 #define ED_CTRL3_BUTTONS_ALT_GFX_YPOS  302
 
 #define ED_CTRL3_BUTTON_YSIZE          22
 #define ED_CTRL3_BUTTONS_XPOS          6
 #define ED_CTRL3_BUTTONS_YPOS          6
+#define ED_CTRL4_BUTTON_XSIZE          22
+#define ED_CTRL4_BUTTON_YSIZE          22
+#define ED_CTRL4_BUTTONS_XPOS          6
+#define ED_CTRL4_BUTTONS_YPOS          6
 
 #define ED_CTRL1_BUTTONS_HORIZ         4
 #define ED_CTRL1_BUTTONS_VERT          4
 #define ED_CTRL2_BUTTONS_VERT          2
 #define ED_CTRL3_BUTTONS_HORIZ         3
 #define ED_CTRL3_BUTTONS_VERT          1
+#define ED_CTRL4_BUTTONS_HORIZ         2
+#define ED_CTRL4_BUTTONS_VERT          1
 
 #define ED_NUM_CTRL1_BUTTONS   (ED_CTRL1_BUTTONS_HORIZ * ED_CTRL1_BUTTONS_VERT)
 #define ED_NUM_CTRL2_BUTTONS   (ED_CTRL2_BUTTONS_HORIZ * ED_CTRL2_BUTTONS_VERT)
 #define ED_NUM_CTRL3_BUTTONS   (ED_CTRL3_BUTTONS_HORIZ * ED_CTRL3_BUTTONS_VERT)
-#define ED_NUM_CTRL1_2_BUTTONS (ED_NUM_CTRL1_BUTTONS + ED_NUM_CTRL2_BUTTONS)
-#define ED_NUM_CTRL_BUTTONS    (ED_NUM_CTRL1_BUTTONS + \
-                               ED_NUM_CTRL2_BUTTONS + \
-                               ED_NUM_CTRL3_BUTTONS)
+#define ED_NUM_CTRL4_BUTTONS   (ED_CTRL4_BUTTONS_HORIZ * ED_CTRL4_BUTTONS_VERT)
+#define ED_NUM_CTRL1_2_BUTTONS (ED_NUM_CTRL1_BUTTONS   + ED_NUM_CTRL2_BUTTONS)
+#define ED_NUM_CTRL1_3_BUTTONS (ED_NUM_CTRL1_2_BUTTONS + ED_NUM_CTRL3_BUTTONS)
+#define ED_NUM_CTRL_BUTTONS    (ED_NUM_CTRL1_BUTTONS + \
+                               ED_NUM_CTRL2_BUTTONS +  \
+                               ED_NUM_CTRL3_BUTTONS +  \
+                               ED_NUM_CTRL4_BUTTONS)
 
 /* values for the element list */
 #define ED_ELEMENTLIST_XPOS            5
@@ -85,7 +96,7 @@
 #define ED_ELEMENTLIST_YSIZE           20
 #define ED_ELEMENTLIST_BUTTONS_HORIZ   4
 #define ED_ELEMENTLIST_BUTTONS_VERT    11
-#define ED_NUM_ELEMENTLIST_BUTTONS     (ED_ELEMENTLIST_BUTTONS_HORIZ * \
+#define ED_NUM_ELEMENTLIST_BUTTONS     (ED_ELEMENTLIST_BUTTONS_HORIZ * \
                                         ED_ELEMENTLIST_BUTTONS_VERT)
 
 /* standard distances */
 
 #define ED_GADGET_DISTANCE             2
 #define ED_GADGET_TEXT_DISTANCE                (2 * ED_GADGET_DISTANCE)
-#define ED_DRAWINGAREA_TEXT_DISTANCE   (ED_GADGET_TEXT_DISTANCE + \
+#define ED_DRAWINGAREA_TEXT_DISTANCE   (ED_GADGET_TEXT_DISTANCE +      \
                                         MINI_TILEX / 2)
 
-/* values for the setting windows */
+/* values for the settings windows */
 #define ED_SETTINGS_XSTART             (3 * MINI_TILEX / 2)
 #define ED_SETTINGS_YSTART             (MINI_TILEY * 10)
 
-#define ED_XOFFSET_CHECKBOX            (ED_CHECKBUTTON_XSIZE + \
+#define ED_XOFFSET_CHECKBOX            (ED_CHECKBUTTON_XSIZE +         \
                                         2 * ED_GADGET_DISTANCE)
 
 #define ED_SETTINGS_XOFFSET            ED_XOFFSET_CHECKBOX
 #define ED_SETTINGS_YOFFSET            (3 * MINI_TILEY / 2)
 
-#define ED_SETTINGS_XPOS(n)            (ED_SETTINGS_XSTART + \
-                                        n * ED_SETTINGS_XOFFSET)
-#define ED_SETTINGS_YPOS(n)            (ED_SETTINGS_YSTART + \
-                                        n * ED_SETTINGS_YOFFSET)
+#define ED_SETTINGS_XPOS(n)            (ED_SETTINGS_XSTART +           \
+                                        (n) * ED_SETTINGS_XOFFSET)
+#define ED_SETTINGS_YPOS(n)            (ED_SETTINGS_YSTART +           \
+                                        (n) * ED_SETTINGS_YOFFSET)
 
 #define ED_SETTINGS1_YPOS              MINI_TILEY
 #define ED_SETTINGS2_XPOS              MINI_TILEX
 /* values for counter gadgets */
 #define ED_COUNTER_YSTART              (ED_SETTINGS1_YPOS + 2 * TILEY)
 #define ED_COUNTER_YDISTANCE           (3 * MINI_TILEY)
-#define ED_COUNTER_YPOS(n)             (ED_COUNTER_YSTART + \
-                                        n * ED_COUNTER_YDISTANCE)
-#define ED_COUNTER2_YPOS(n)            (ED_COUNTER_YSTART + \
-                                        n * ED_COUNTER_YDISTANCE - 2)
+#define ED_COUNTER_YPOS(n)             (ED_COUNTER_YSTART +            \
+                                        (n) * ED_COUNTER_YDISTANCE)
+#define ED_COUNTER2_YPOS(n)            (ED_COUNTER_YSTART +            \
+                                        (n) * ED_COUNTER_YDISTANCE - 2)
 
 /* values for element content drawing areas */
-/* amoeba content */
-#define ED_AREA_ELEM_CONTENT_XPOS      ( 2 * MINI_TILEX)
-#define ED_AREA_ELEM_CONTENT_YPOS      (22 * MINI_TILEY)
-
-/* yamyam content */
-#define ED_AREA_YAMYAM_CONTENT_XPOS(n) (ED_AREA_ELEM_CONTENT_XPOS + \
-                                        5 * (n % 4) * MINI_TILEX)
-#define ED_AREA_YAMYAM_CONTENT_YPOS(n) (ED_AREA_ELEM_CONTENT_YPOS + \
-                                        6 * (n / 4) * MINI_TILEY)
-
-/* custom change target */
-#define ED_AREA_ELEM_CONTENT2_YPOS     (ED_SETTINGS_YPOS(2) + \
-                                        ED_GADGET_DISTANCE)
-/* optional custom graphic */
-#define ED_AREA_ELEM_CONTENT3_YPOS     (ED_SETTINGS_YPOS(1) + \
+#define ED_AREA_1X1_SETTINGS_XPOS(n)   (ED_SETTINGS_XPOS(n))
+#define ED_AREA_1X1_SETTINGS_YPOS(n)   (ED_SETTINGS_YPOS(n) +          \
                                         ED_GADGET_DISTANCE)
-/* custom element content */
-#define ED_AREA_ELEM_CONTENT4_XPOS     (29 * MINI_TILEX)
-#define ED_AREA_ELEM_CONTENT4_YPOS     (ED_SETTINGS_YPOS(12) + \
-                                        ED_GADGET_DISTANCE - MINI_TILEY)
-/* custom change trigger element */
-#define ED_AREA_ELEM_CONTENT5_YPOS     (ED_SETTINGS_YPOS(6) + \
-                                        ED_GADGET_DISTANCE)
-/* extended custom change target */
-#define ED_AREA_ELEM_CONTENT6_XPOS     (29 * MINI_TILEX)
-#define ED_AREA_ELEM_CONTENT6_YPOS     (ED_SETTINGS_YPOS(10) + \
+
+#define ED_AREA_3X3_SETTINGS_XPOS(n)   (ED_SETTINGS_XPOS(n))
+#define ED_AREA_3X3_SETTINGS_YPOS(n)   (ED_SETTINGS_YPOS(n) +          \
                                         ED_GADGET_DISTANCE - MINI_TILEY)
 
-/* values for random placement background drawing area */
-#define ED_AREA_RANDOM_BACKGROUND_YPOS (31 * MINI_TILEY)
+/* 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 +              \
+                                        6 * ((n) / 4) * MINI_TILEY)
 
 /* values for scrolling gadgets for drawing area */
 #define ED_SCROLLBUTTON_XPOS           24
 #define ED_SCROLL_LEFT_YPOS            (SYSIZE - 2 * ED_SCROLLBUTTON_YSIZE)
 #define ED_SCROLL_RIGHT_XPOS           (SXSIZE - 2 * ED_SCROLLBUTTON_XSIZE)
 #define ED_SCROLL_RIGHT_YPOS           ED_SCROLL_LEFT_YPOS
-#define ED_SCROLL_HORIZONTAL_XPOS (ED_SCROLL_LEFT_XPOS + ED_SCROLLBUTTON_XSIZE)
+#define ED_SCROLL_HORIZONTAL_XPOS      (ED_SCROLL_LEFT_XPOS +          \
+                                        ED_SCROLLBUTTON_XSIZE)
 #define ED_SCROLL_HORIZONTAL_YPOS      ED_SCROLL_LEFT_YPOS
 #define ED_SCROLL_HORIZONTAL_XSIZE     (SXSIZE - 3 * ED_SCROLLBUTTON_XSIZE)
 #define ED_SCROLL_HORIZONTAL_YSIZE     ED_SCROLLBUTTON_YSIZE
 #define ED_SCROLL_VERTICAL_XPOS                ED_SCROLL_UP_XPOS
-#define ED_SCROLL_VERTICAL_YPOS          (ED_SCROLL_UP_YPOS + ED_SCROLLBUTTON_YSIZE)
+#define ED_SCROLL_VERTICAL_YPOS                (ED_SCROLL_UP_YPOS +            \
+                                        ED_SCROLLBUTTON_YSIZE)
 #define ED_SCROLL_VERTICAL_XSIZE       ED_SCROLLBUTTON_XSIZE
 #define ED_SCROLL_VERTICAL_YSIZE       (SYSIZE - 4 * ED_SCROLLBUTTON_YSIZE)
 
 #define ED_SCROLL2_UP_XPOS             85
 #define ED_SCROLL2_UP_YPOS             30
 #define ED_SCROLL2_DOWN_XPOS           ED_SCROLL2_UP_XPOS
-#define ED_SCROLL2_DOWN_YPOS           (ED_SCROLL2_UP_YPOS + \
-                                        ED_ELEMENTLIST_BUTTONS_VERT * \
-                                        ED_ELEMENTLIST_YSIZE - \
+#define ED_SCROLL2_DOWN_YPOS           (ED_SCROLL2_UP_YPOS +           \
+                                        ED_ELEMENTLIST_BUTTONS_VERT *  \
+                                        ED_ELEMENTLIST_YSIZE -         \
                                         ED_SCROLLBUTTON2_YSIZE)
 #define ED_SCROLL2_VERTICAL_XPOS       ED_SCROLL2_UP_XPOS
-#define ED_SCROLL2_VERTICAL_YPOS       (ED_SCROLL2_UP_YPOS + \
+#define ED_SCROLL2_VERTICAL_YPOS       (ED_SCROLL2_UP_YPOS +           \
                                         ED_SCROLLBUTTON2_YSIZE)
 #define ED_SCROLL2_VERTICAL_XSIZE      ED_SCROLLBUTTON2_XSIZE
-#define ED_SCROLL2_VERTICAL_YSIZE      (ED_ELEMENTLIST_BUTTONS_VERT * \
-                                        ED_ELEMENTLIST_YSIZE - \
+#define ED_SCROLL2_VERTICAL_YSIZE      (ED_ELEMENTLIST_BUTTONS_VERT *  \
+                                        ED_ELEMENTLIST_YSIZE -         \
                                         2 * ED_SCROLLBUTTON2_YSIZE)
 
 /* values for checkbutton gadgets */
 #define ED_RADIOBUTTON_YPOS            (ED_BUTTON_MINUS_YPOS + 44)
 #define ED_STICKYBUTTON_YPOS           (ED_BUTTON_MINUS_YPOS + 66)
 
-/* some positions in the editor control window */
-#define ED_BUTTON_ELEM_XPOS            6
-#define ED_BUTTON_ELEM_YPOS            30
-#define ED_BUTTON_ELEM_XSIZE           22
-#define ED_BUTTON_ELEM_YSIZE           22
+/* values for some special graphic buttons */
+#define ED_COPY_CHANGE_PAGE_XPOS       25
+#define ED_COPY_CHANGE_PAGE_YPOS       50
+#define ED_PASTE_CHANGE_PAGE_XPOS      25
+#define ED_PASTE_CHANGE_PAGE_YPOS      70
 
 /* some values for text input, selectbox and counter gadgets */
 #define ED_BUTTON_COUNT_YPOS           60
 #define ED_BUTTON_MINUS_YPOS           ED_BUTTON_COUNT_YPOS
 #define ED_BUTTON_MINUS_XSIZE          ED_BUTTON_COUNT_XSIZE
 #define ED_BUTTON_MINUS_YSIZE          ED_BUTTON_COUNT_YSIZE
-#define ED_BUTTON_PLUS_XPOS            (ED_WIN_COUNT_XPOS + \
+#define ED_BUTTON_PLUS_XPOS            (ED_WIN_COUNT_XPOS +            \
                                         ED_WIN_COUNT_XSIZE + 2)
 #define ED_BUTTON_PLUS_YPOS            ED_BUTTON_COUNT_YPOS
 #define ED_BUTTON_PLUS_XSIZE           ED_BUTTON_COUNT_XSIZE
 #define ED_BUTTON_PLUS_YSIZE           ED_BUTTON_COUNT_YSIZE
 
 #define ED_SELECTBOX_XPOS              ED_WIN_COUNT_XPOS
-#define ED_SELECTBOX_YPOS              (ED_WIN_COUNT_YPOS + \
+#define ED_SELECTBOX_YPOS              (ED_WIN_COUNT_YPOS +            \
                                         2 + ED_WIN_COUNT_YSIZE)
 #define ED_SELECTBOX_XSIZE             ED_WIN_COUNT_XSIZE
 #define ED_SELECTBOX_YSIZE             ED_WIN_COUNT_YSIZE
 #define ED_SELECTBOX_BUTTON_XSIZE      14
 
 #define ED_TEXTBUTTON_XPOS             ED_WIN_COUNT_XPOS
-#define ED_TEXTBUTTON_YPOS             (ED_WIN_COUNT_YPOS + \
+#define ED_TEXTBUTTON_YPOS             (ED_WIN_COUNT_YPOS +            \
                                         4 * (2 + ED_WIN_COUNT_YSIZE))
 #define ED_TEXTBUTTON_INACTIVE_YPOS    ED_TEXTBUTTON_YPOS
 
 #define ED_TEXTBUTTON_TAB_XPOS         ED_WIN_COUNT_XPOS
-#define ED_TEXTBUTTON_TAB_YPOS         (ED_WIN_COUNT_YPOS + \
+#define ED_TEXTBUTTON_TAB_YPOS         (ED_WIN_COUNT_YPOS +            \
                                         2 * (2 + ED_WIN_COUNT_YSIZE))
-#define ED_TEXTBUTTON_TAB_INACTIVE_YPOS        (ED_WIN_COUNT_YPOS + \
+#define ED_TEXTBUTTON_TAB_INACTIVE_YPOS        (ED_WIN_COUNT_YPOS +            \
                                         3 * (2 + ED_WIN_COUNT_YSIZE))
 
 #define ED_TEXTBUTTON_XSIZE            ED_WIN_COUNT_XSIZE
 #define GADGET_ID_CUSTOM_COPY_FROM     (GADGET_ID_TOOLBOX_FIRST + 22)
 #define GADGET_ID_CUSTOM_COPY_TO       (GADGET_ID_TOOLBOX_FIRST + 23)
 #define GADGET_ID_CUSTOM_EXCHANGE      (GADGET_ID_TOOLBOX_FIRST + 24)
+#define GADGET_ID_CUSTOM_COPY          (GADGET_ID_TOOLBOX_FIRST + 25)
+#define GADGET_ID_CUSTOM_PASTE         (GADGET_ID_TOOLBOX_FIRST + 26)
 
 /* counter button identifiers */
-#define GADGET_ID_COUNTER_FIRST                (GADGET_ID_TOOLBOX_FIRST + 25)
+#define GADGET_ID_COUNTER_FIRST                (GADGET_ID_TOOLBOX_FIRST + 27)
 
 #define GADGET_ID_SELECT_LEVEL_DOWN    (GADGET_ID_COUNTER_FIRST + 0)
 #define GADGET_ID_SELECT_LEVEL_TEXT    (GADGET_ID_COUNTER_FIRST + 1)
 #define GADGET_ID_PUSH_DELAY_RND_DOWN  (GADGET_ID_COUNTER_FIRST + 42)
 #define GADGET_ID_PUSH_DELAY_RND_TEXT  (GADGET_ID_COUNTER_FIRST + 43)
 #define GADGET_ID_PUSH_DELAY_RND_UP    (GADGET_ID_COUNTER_FIRST + 44)
-#define GADGET_ID_MOVE_DELAY_FIX_DOWN  (GADGET_ID_COUNTER_FIRST + 45)
-#define GADGET_ID_MOVE_DELAY_FIX_TEXT  (GADGET_ID_COUNTER_FIRST + 46)
-#define GADGET_ID_MOVE_DELAY_FIX_UP    (GADGET_ID_COUNTER_FIRST + 47)
-#define GADGET_ID_MOVE_DELAY_RND_DOWN  (GADGET_ID_COUNTER_FIRST + 48)
-#define GADGET_ID_MOVE_DELAY_RND_TEXT  (GADGET_ID_COUNTER_FIRST + 49)
-#define GADGET_ID_MOVE_DELAY_RND_UP    (GADGET_ID_COUNTER_FIRST + 50)
-#define GADGET_ID_CHANGE_DELAY_FIX_DOWN        (GADGET_ID_COUNTER_FIRST + 51)
-#define GADGET_ID_CHANGE_DELAY_FIX_TEXT        (GADGET_ID_COUNTER_FIRST + 52)
-#define GADGET_ID_CHANGE_DELAY_FIX_UP  (GADGET_ID_COUNTER_FIRST + 53)
-#define GADGET_ID_CHANGE_DELAY_RND_DOWN        (GADGET_ID_COUNTER_FIRST + 54)
-#define GADGET_ID_CHANGE_DELAY_RND_TEXT        (GADGET_ID_COUNTER_FIRST + 55)
-#define GADGET_ID_CHANGE_DELAY_RND_UP  (GADGET_ID_COUNTER_FIRST + 56)
-#define GADGET_ID_CHANGE_CONT_RND_DOWN (GADGET_ID_COUNTER_FIRST + 57)
-#define GADGET_ID_CHANGE_CONT_RND_TEXT (GADGET_ID_COUNTER_FIRST + 58)
-#define GADGET_ID_CHANGE_CONT_RND_UP   (GADGET_ID_COUNTER_FIRST + 59)
+#define GADGET_ID_DROP_DELAY_FIX_DOWN  (GADGET_ID_COUNTER_FIRST + 45)
+#define GADGET_ID_DROP_DELAY_FIX_TEXT  (GADGET_ID_COUNTER_FIRST + 46)
+#define GADGET_ID_DROP_DELAY_FIX_UP    (GADGET_ID_COUNTER_FIRST + 47)
+#define GADGET_ID_DROP_DELAY_RND_DOWN  (GADGET_ID_COUNTER_FIRST + 48)
+#define GADGET_ID_DROP_DELAY_RND_TEXT  (GADGET_ID_COUNTER_FIRST + 49)
+#define GADGET_ID_DROP_DELAY_RND_UP    (GADGET_ID_COUNTER_FIRST + 50)
+#define GADGET_ID_MOVE_DELAY_FIX_DOWN  (GADGET_ID_COUNTER_FIRST + 51)
+#define GADGET_ID_MOVE_DELAY_FIX_TEXT  (GADGET_ID_COUNTER_FIRST + 52)
+#define GADGET_ID_MOVE_DELAY_FIX_UP    (GADGET_ID_COUNTER_FIRST + 53)
+#define GADGET_ID_MOVE_DELAY_RND_DOWN  (GADGET_ID_COUNTER_FIRST + 54)
+#define GADGET_ID_MOVE_DELAY_RND_TEXT  (GADGET_ID_COUNTER_FIRST + 55)
+#define GADGET_ID_MOVE_DELAY_RND_UP    (GADGET_ID_COUNTER_FIRST + 56)
+#define GADGET_ID_EXPLOSION_DELAY_DOWN (GADGET_ID_COUNTER_FIRST + 57)
+#define GADGET_ID_EXPLOSION_DELAY_TEXT (GADGET_ID_COUNTER_FIRST + 58)
+#define GADGET_ID_EXPLOSION_DELAY_UP   (GADGET_ID_COUNTER_FIRST + 59)
+#define GADGET_ID_IGNITION_DELAY_DOWN  (GADGET_ID_COUNTER_FIRST + 60)
+#define GADGET_ID_IGNITION_DELAY_TEXT  (GADGET_ID_COUNTER_FIRST + 61)
+#define GADGET_ID_IGNITION_DELAY_UP    (GADGET_ID_COUNTER_FIRST + 62)
+#define GADGET_ID_CHANGE_DELAY_FIX_DOWN        (GADGET_ID_COUNTER_FIRST + 63)
+#define GADGET_ID_CHANGE_DELAY_FIX_TEXT        (GADGET_ID_COUNTER_FIRST + 64)
+#define GADGET_ID_CHANGE_DELAY_FIX_UP  (GADGET_ID_COUNTER_FIRST + 65)
+#define GADGET_ID_CHANGE_DELAY_RND_DOWN        (GADGET_ID_COUNTER_FIRST + 66)
+#define GADGET_ID_CHANGE_DELAY_RND_TEXT        (GADGET_ID_COUNTER_FIRST + 67)
+#define GADGET_ID_CHANGE_DELAY_RND_UP  (GADGET_ID_COUNTER_FIRST + 68)
+#define GADGET_ID_CHANGE_CONT_RND_DOWN (GADGET_ID_COUNTER_FIRST + 69)
+#define GADGET_ID_CHANGE_CONT_RND_TEXT (GADGET_ID_COUNTER_FIRST + 70)
+#define GADGET_ID_CHANGE_CONT_RND_UP   (GADGET_ID_COUNTER_FIRST + 71)
+#define GADGET_ID_GROUP_CONTENT_DOWN   (GADGET_ID_COUNTER_FIRST + 72)
+#define GADGET_ID_GROUP_CONTENT_TEXT   (GADGET_ID_COUNTER_FIRST + 73)
+#define GADGET_ID_GROUP_CONTENT_UP     (GADGET_ID_COUNTER_FIRST + 74)
 
 /* drawing area identifiers */
-#define GADGET_ID_DRAWING_AREA_FIRST   (GADGET_ID_COUNTER_FIRST + 60)
+#define GADGET_ID_DRAWING_AREA_FIRST   (GADGET_ID_COUNTER_FIRST + 75)
 
 #define GADGET_ID_DRAWING_LEVEL                (GADGET_ID_DRAWING_AREA_FIRST + 0)
 #define GADGET_ID_ELEMENT_CONTENT_0    (GADGET_ID_DRAWING_AREA_FIRST + 1)
 #define GADGET_ID_AMOEBA_CONTENT       (GADGET_ID_DRAWING_AREA_FIRST + 9)
 #define GADGET_ID_CUSTOM_GRAPHIC       (GADGET_ID_DRAWING_AREA_FIRST + 10)
 #define GADGET_ID_CUSTOM_CONTENT       (GADGET_ID_DRAWING_AREA_FIRST + 11)
-#define GADGET_ID_CUSTOM_CHANGE_TARGET (GADGET_ID_DRAWING_AREA_FIRST + 12)
-#define GADGET_ID_CUSTOM_CHANGE_CONTENT        (GADGET_ID_DRAWING_AREA_FIRST + 13)
-#define GADGET_ID_CUSTOM_CHANGE_TRIGGER        (GADGET_ID_DRAWING_AREA_FIRST + 14)
-#define GADGET_ID_RANDOM_BACKGROUND    (GADGET_ID_DRAWING_AREA_FIRST + 15)
+#define GADGET_ID_CUSTOM_MOVE_ENTER    (GADGET_ID_DRAWING_AREA_FIRST + 12)
+#define GADGET_ID_CUSTOM_MOVE_LEAVE    (GADGET_ID_DRAWING_AREA_FIRST + 13)
+#define GADGET_ID_CUSTOM_CHANGE_TARGET (GADGET_ID_DRAWING_AREA_FIRST + 14)
+#define GADGET_ID_CUSTOM_CHANGE_CONTENT        (GADGET_ID_DRAWING_AREA_FIRST + 15)
+#define GADGET_ID_CUSTOM_CHANGE_TRIGGER        (GADGET_ID_DRAWING_AREA_FIRST + 16)
+#define GADGET_ID_GROUP_CONTENT                (GADGET_ID_DRAWING_AREA_FIRST + 17)
+#define GADGET_ID_RANDOM_BACKGROUND    (GADGET_ID_DRAWING_AREA_FIRST + 18)
 
 /* text input identifiers */
-#define GADGET_ID_TEXT_INPUT_FIRST     (GADGET_ID_DRAWING_AREA_FIRST + 16)
+#define GADGET_ID_TEXT_INPUT_FIRST     (GADGET_ID_DRAWING_AREA_FIRST + 19)
 
 #define GADGET_ID_LEVEL_NAME           (GADGET_ID_TEXT_INPUT_FIRST + 0)
 #define GADGET_ID_LEVEL_AUTHOR         (GADGET_ID_TEXT_INPUT_FIRST + 1)
 /* selectbox identifiers */
 #define GADGET_ID_SELECTBOX_FIRST      (GADGET_ID_TEXT_AREA_FIRST + 1)
 
-#define GADGET_ID_CUSTOM_WALK_TO_ACTION        (GADGET_ID_SELECTBOX_FIRST + 0)
-#define GADGET_ID_CUSTOM_CONSISTENCY   (GADGET_ID_SELECTBOX_FIRST + 1)
-#define GADGET_ID_CUSTOM_DEADLINESS    (GADGET_ID_SELECTBOX_FIRST + 2)
-#define GADGET_ID_CUSTOM_MOVE_PATTERN  (GADGET_ID_SELECTBOX_FIRST + 3)
-#define GADGET_ID_CUSTOM_MOVE_DIRECTION        (GADGET_ID_SELECTBOX_FIRST + 4)
-#define GADGET_ID_CUSTOM_MOVE_STEPSIZE (GADGET_ID_SELECTBOX_FIRST + 5)
-#define GADGET_ID_CUSTOM_SMASH_TARGETS (GADGET_ID_SELECTBOX_FIRST + 6)
-#define GADGET_ID_CUSTOM_SLIPPERY_TYPE (GADGET_ID_SELECTBOX_FIRST + 7)
-#define GADGET_ID_CUSTOM_ACCESS_TYPE   (GADGET_ID_SELECTBOX_FIRST + 8)
-#define GADGET_ID_CUSTOM_ACCESS_LAYER  (GADGET_ID_SELECTBOX_FIRST + 9)
-#define GADGET_ID_CHANGE_TIME_UNITS    (GADGET_ID_SELECTBOX_FIRST + 10)
-#define GADGET_ID_CHANGE_DIRECT_ACTION (GADGET_ID_SELECTBOX_FIRST + 11)
-#define GADGET_ID_CHANGE_OTHER_ACTION  (GADGET_ID_SELECTBOX_FIRST + 12)
-#define GADGET_ID_CHANGE_SIDES         (GADGET_ID_SELECTBOX_FIRST + 13)
-#define GADGET_ID_CHANGE_POWER         (GADGET_ID_SELECTBOX_FIRST + 14)
-#define GADGET_ID_SELECT_CHANGE_PAGE   (GADGET_ID_SELECTBOX_FIRST + 15)
+#define GADGET_ID_TIME_OR_STEPS                (GADGET_ID_SELECTBOX_FIRST + 0)
+#define GADGET_ID_CUSTOM_WALK_TO_ACTION        (GADGET_ID_SELECTBOX_FIRST + 1)
+#define GADGET_ID_CUSTOM_EXPLOSION_TYPE        (GADGET_ID_SELECTBOX_FIRST + 2)
+#define GADGET_ID_CUSTOM_DEADLINESS    (GADGET_ID_SELECTBOX_FIRST + 3)
+#define GADGET_ID_CUSTOM_MOVE_PATTERN  (GADGET_ID_SELECTBOX_FIRST + 4)
+#define GADGET_ID_CUSTOM_MOVE_DIRECTION        (GADGET_ID_SELECTBOX_FIRST + 5)
+#define GADGET_ID_CUSTOM_MOVE_STEPSIZE (GADGET_ID_SELECTBOX_FIRST + 6)
+#define GADGET_ID_CUSTOM_MOVE_LEAVE_TYPE (GADGET_ID_SELECTBOX_FIRST + 7)
+#define GADGET_ID_CUSTOM_SMASH_TARGETS (GADGET_ID_SELECTBOX_FIRST + 8)
+#define GADGET_ID_CUSTOM_SLIPPERY_TYPE (GADGET_ID_SELECTBOX_FIRST + 9)
+#define GADGET_ID_CUSTOM_ACCESS_TYPE   (GADGET_ID_SELECTBOX_FIRST + 10)
+#define GADGET_ID_CUSTOM_ACCESS_LAYER  (GADGET_ID_SELECTBOX_FIRST + 11)
+#define GADGET_ID_CUSTOM_ACCESS_PROTECTED (GADGET_ID_SELECTBOX_FIRST + 12)
+#define GADGET_ID_CUSTOM_ACCESS_DIRECTION (GADGET_ID_SELECTBOX_FIRST + 13)
+#define GADGET_ID_CHANGE_TIME_UNITS    (GADGET_ID_SELECTBOX_FIRST + 14)
+#define GADGET_ID_CHANGE_DIRECT_ACTION (GADGET_ID_SELECTBOX_FIRST + 15)
+#define GADGET_ID_CHANGE_OTHER_ACTION  (GADGET_ID_SELECTBOX_FIRST + 16)
+#define GADGET_ID_CHANGE_SIDE          (GADGET_ID_SELECTBOX_FIRST + 17)
+#define GADGET_ID_CHANGE_PLAYER                (GADGET_ID_SELECTBOX_FIRST + 18)
+#define GADGET_ID_CHANGE_PAGE          (GADGET_ID_SELECTBOX_FIRST + 19)
+#define GADGET_ID_CHANGE_REPLACE_WHEN  (GADGET_ID_SELECTBOX_FIRST + 20)
+#define GADGET_ID_SELECT_CHANGE_PAGE   (GADGET_ID_SELECTBOX_FIRST + 21)
+#define GADGET_ID_GROUP_CHOICE_MODE    (GADGET_ID_SELECTBOX_FIRST + 22)
 
 /* textbutton identifiers */
-#define GADGET_ID_TEXTBUTTON_FIRST     (GADGET_ID_SELECTBOX_FIRST + 16)
+#define GADGET_ID_TEXTBUTTON_FIRST     (GADGET_ID_SELECTBOX_FIRST + 23)
 
 #define GADGET_ID_PROPERTIES_INFO      (GADGET_ID_TEXTBUTTON_FIRST + 0)
 #define GADGET_ID_PROPERTIES_CONFIG    (GADGET_ID_TEXTBUTTON_FIRST + 1)
-#define GADGET_ID_PROPERTIES_ADVANCED  (GADGET_ID_TEXTBUTTON_FIRST + 2)
-#define GADGET_ID_SAVE_AS_TEMPLATE     (GADGET_ID_TEXTBUTTON_FIRST + 3)
-#define GADGET_ID_ADD_CHANGE_PAGE      (GADGET_ID_TEXTBUTTON_FIRST + 4)
-#define GADGET_ID_DEL_CHANGE_PAGE      (GADGET_ID_TEXTBUTTON_FIRST + 5)
+#define GADGET_ID_PROPERTIES_CONFIG_1  (GADGET_ID_TEXTBUTTON_FIRST + 2)
+#define GADGET_ID_PROPERTIES_CONFIG_2  (GADGET_ID_TEXTBUTTON_FIRST + 3)
+#define GADGET_ID_PROPERTIES_CHANGE    (GADGET_ID_TEXTBUTTON_FIRST + 4)
+#define GADGET_ID_SAVE_AS_TEMPLATE     (GADGET_ID_TEXTBUTTON_FIRST + 5)
+#define GADGET_ID_ADD_CHANGE_PAGE      (GADGET_ID_TEXTBUTTON_FIRST + 6)
+#define GADGET_ID_DEL_CHANGE_PAGE      (GADGET_ID_TEXTBUTTON_FIRST + 7)
 
 /* graphicbutton identifiers */
-#define GADGET_ID_GRAPHICBUTTON_FIRST  (GADGET_ID_TEXTBUTTON_FIRST + 6)
+#define GADGET_ID_GRAPHICBUTTON_FIRST  (GADGET_ID_TEXTBUTTON_FIRST + 8)
 
 #define GADGET_ID_PREV_CHANGE_PAGE     (GADGET_ID_GRAPHICBUTTON_FIRST + 0)
 #define GADGET_ID_NEXT_CHANGE_PAGE     (GADGET_ID_GRAPHICBUTTON_FIRST + 1)
+#define GADGET_ID_COPY_CHANGE_PAGE     (GADGET_ID_GRAPHICBUTTON_FIRST + 2)
+#define GADGET_ID_PASTE_CHANGE_PAGE    (GADGET_ID_GRAPHICBUTTON_FIRST + 3)
 
 /* gadgets for scrolling of drawing area */
-#define GADGET_ID_SCROLLING_FIRST      (GADGET_ID_GRAPHICBUTTON_FIRST + 2)
+#define GADGET_ID_SCROLLING_FIRST      (GADGET_ID_GRAPHICBUTTON_FIRST + 4)
 
 #define GADGET_ID_SCROLL_UP            (GADGET_ID_SCROLLING_FIRST + 0)
 #define GADGET_ID_SCROLL_DOWN          (GADGET_ID_SCROLLING_FIRST + 1)
 #define GADGET_ID_SCROLL_LIST_DOWN     (GADGET_ID_SCROLLING_LIST_FIRST + 1)
 #define GADGET_ID_SCROLL_LIST_VERTICAL (GADGET_ID_SCROLLING_LIST_FIRST + 2)
 
-/* checkbuttons for level/element properties */
+/* checkbuttons/radiobuttons for level/element properties */
 #define GADGET_ID_CHECKBUTTON_FIRST    (GADGET_ID_SCROLLING_LIST_FIRST + 3)
 
 #define GADGET_ID_RANDOM_PERCENTAGE    (GADGET_ID_CHECKBUTTON_FIRST + 0)
 #define GADGET_ID_GRAVITY              (GADGET_ID_CHECKBUTTON_FIRST + 4)
 #define GADGET_ID_STICK_ELEMENT                (GADGET_ID_CHECKBUTTON_FIRST + 5)
 #define GADGET_ID_EM_SLIPPERY_GEMS     (GADGET_ID_CHECKBUTTON_FIRST + 6)
-#define GADGET_ID_CUSTOM_EXPLODE_RESULT        (GADGET_ID_CHECKBUTTON_FIRST + 7)
-#define GADGET_ID_CUSTOM_EXPLODE_FIRE  (GADGET_ID_CHECKBUTTON_FIRST + 8)
-#define GADGET_ID_CUSTOM_EXPLODE_SMASH (GADGET_ID_CHECKBUTTON_FIRST + 9)
-#define GADGET_ID_CUSTOM_EXPLODE_IMPACT        (GADGET_ID_CHECKBUTTON_FIRST + 10)
-#define GADGET_ID_CUSTOM_WALK_TO_OBJECT        (GADGET_ID_CHECKBUTTON_FIRST + 11)
-#define GADGET_ID_CUSTOM_DEADLY                (GADGET_ID_CHECKBUTTON_FIRST + 12)
-#define GADGET_ID_CUSTOM_CAN_MOVE      (GADGET_ID_CHECKBUTTON_FIRST + 13)
-#define GADGET_ID_CUSTOM_CAN_FALL      (GADGET_ID_CHECKBUTTON_FIRST + 14)
-#define GADGET_ID_CUSTOM_CAN_SMASH     (GADGET_ID_CHECKBUTTON_FIRST + 15)
-#define GADGET_ID_CUSTOM_SLIPPERY      (GADGET_ID_CHECKBUTTON_FIRST + 16)
-#define GADGET_ID_CUSTOM_ACCESSIBLE    (GADGET_ID_CHECKBUTTON_FIRST + 17)
-#define GADGET_ID_CUSTOM_USE_GRAPHIC   (GADGET_ID_CHECKBUTTON_FIRST + 18)
-#define GADGET_ID_CUSTOM_USE_TEMPLATE  (GADGET_ID_CHECKBUTTON_FIRST + 19)
-#define GADGET_ID_CUSTOM_CAN_CHANGE    (GADGET_ID_CHECKBUTTON_FIRST + 20)
-#define GADGET_ID_CHANGE_USE_CONTENT   (GADGET_ID_CHECKBUTTON_FIRST + 21)
-#define GADGET_ID_CHANGE_USE_EXPLOSION (GADGET_ID_CHECKBUTTON_FIRST + 22)
-#define GADGET_ID_CHANGE_ONLY_COMPLETE (GADGET_ID_CHECKBUTTON_FIRST + 23)
-#define GADGET_ID_CHANGE_USE_RANDOM    (GADGET_ID_CHECKBUTTON_FIRST + 24)
-#define GADGET_ID_CHANGE_DELAY         (GADGET_ID_CHECKBUTTON_FIRST + 25)
-#define GADGET_ID_CHANGE_BY_DIRECT_ACT (GADGET_ID_CHECKBUTTON_FIRST + 26)
-#define GADGET_ID_CHANGE_BY_OTHER_ACT  (GADGET_ID_CHECKBUTTON_FIRST + 27)
+#define GADGET_ID_USE_SPRING_BUG       (GADGET_ID_CHECKBUTTON_FIRST + 7)
+#define GADGET_ID_GROW_INTO_DIGGABLE   (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)
 
 /* gadgets for buttons in element list */
-#define GADGET_ID_ELEMENTLIST_FIRST    (GADGET_ID_CHECKBUTTON_FIRST + 28)
+#define GADGET_ID_ELEMENTLIST_FIRST    (GADGET_ID_CHECKBUTTON_FIRST + 39)
 #define GADGET_ID_ELEMENTLIST_LAST     (GADGET_ID_ELEMENTLIST_FIRST +  \
                                        ED_NUM_ELEMENTLIST_BUTTONS - 1)
 
 #define ED_COUNTER_ID_CUSTOM_GEMCOUNT  12
 #define ED_COUNTER_ID_PUSH_DELAY_FIX   13
 #define ED_COUNTER_ID_PUSH_DELAY_RND   14
-#define ED_COUNTER_ID_MOVE_DELAY_FIX   15
-#define ED_COUNTER_ID_MOVE_DELAY_RND   16
-#define ED_COUNTER_ID_CHANGE_DELAY_FIX 17
-#define ED_COUNTER_ID_CHANGE_DELAY_RND 18
-#define ED_COUNTER_ID_CHANGE_CONT_RND  19
-
-#define ED_NUM_COUNTERBUTTONS          20
+#define ED_COUNTER_ID_DROP_DELAY_FIX   15
+#define ED_COUNTER_ID_DROP_DELAY_RND   16
+#define ED_COUNTER_ID_MOVE_DELAY_FIX   17
+#define ED_COUNTER_ID_MOVE_DELAY_RND   18
+#define ED_COUNTER_ID_EXPLOSION_DELAY  19
+#define ED_COUNTER_ID_IGNITION_DELAY   20
+#define ED_COUNTER_ID_GROUP_CONTENT    21
+#define ED_COUNTER_ID_CHANGE_DELAY_FIX 22
+#define ED_COUNTER_ID_CHANGE_DELAY_RND 23
+#define ED_COUNTER_ID_CHANGE_CONT_RND  24
+
+#define ED_NUM_COUNTERBUTTONS          25
 
 #define ED_COUNTER_ID_LEVEL_FIRST      ED_COUNTER_ID_LEVEL_XSIZE
 #define ED_COUNTER_ID_LEVEL_LAST       ED_COUNTER_ID_LEVEL_RANDOM
 
-#define ED_COUNTER_ID_CUSTOM_FIRST     ED_COUNTER_ID_CUSTOM_SCORE
-#define ED_COUNTER_ID_CUSTOM_LAST      ED_COUNTER_ID_MOVE_DELAY_RND
+#define ED_COUNTER_ID_CUSTOM1_FIRST    ED_COUNTER_ID_CUSTOM_SCORE
+#define ED_COUNTER_ID_CUSTOM1_LAST     ED_COUNTER_ID_DROP_DELAY_RND
+#define ED_COUNTER_ID_CUSTOM2_FIRST    ED_COUNTER_ID_MOVE_DELAY_FIX
+#define ED_COUNTER_ID_CUSTOM2_LAST     ED_COUNTER_ID_IGNITION_DELAY
+#define ED_COUNTER_ID_CUSTOM_FIRST     ED_COUNTER_ID_CUSTOM1_FIRST
+#define ED_COUNTER_ID_CUSTOM_LAST      ED_COUNTER_ID_CUSTOM2_LAST
 
 #define ED_COUNTER_ID_CHANGE_FIRST     ED_COUNTER_ID_CHANGE_DELAY_FIX
 #define ED_COUNTER_ID_CHANGE_LAST      ED_COUNTER_ID_CHANGE_CONT_RND
 #define ED_TEXTAREA_ID_LEVEL_LAST      ED_TEXTAREA_ID_ENVELOPE
 
 /* values for selectbox gadgets */
-#define ED_SELECTBOX_ID_CUSTOM_ACCESS_TYPE     0
-#define ED_SELECTBOX_ID_CUSTOM_ACCESS_LAYER    1
-#define ED_SELECTBOX_ID_CUSTOM_WALK_TO_ACTION  2
-#define ED_SELECTBOX_ID_CUSTOM_MOVE_PATTERN    3
-#define ED_SELECTBOX_ID_CUSTOM_MOVE_DIRECTION  4
-#define ED_SELECTBOX_ID_CUSTOM_MOVE_STEPSIZE   5
-#define ED_SELECTBOX_ID_CUSTOM_SMASH_TARGETS   6
-#define ED_SELECTBOX_ID_CUSTOM_SLIPPERY_TYPE   7
-#define ED_SELECTBOX_ID_CUSTOM_DEADLINESS      8
-#define ED_SELECTBOX_ID_CUSTOM_CONSISTENCY     9
-#define ED_SELECTBOX_ID_CHANGE_TIME_UNITS      10
-#define ED_SELECTBOX_ID_CHANGE_DIRECT_ACTION   11
-#define ED_SELECTBOX_ID_CHANGE_OTHER_ACTION    12
-#define ED_SELECTBOX_ID_CHANGE_SIDES           13
-#define ED_SELECTBOX_ID_CHANGE_POWER           14
-#define ED_SELECTBOX_ID_SELECT_CHANGE_PAGE     15
-
-#define ED_NUM_SELECTBOX                       16
-
-#define ED_SELECTBOX_ID_CUSTOM_FIRST   ED_SELECTBOX_ID_CUSTOM_ACCESS_TYPE
-#define ED_SELECTBOX_ID_CUSTOM_LAST    ED_SELECTBOX_ID_CUSTOM_CONSISTENCY
+#define ED_SELECTBOX_ID_TIME_OR_STEPS          0
+#define ED_SELECTBOX_ID_CUSTOM_ACCESS_TYPE     1
+#define ED_SELECTBOX_ID_CUSTOM_ACCESS_LAYER    2
+#define ED_SELECTBOX_ID_CUSTOM_ACCESS_PROTECTED        3
+#define ED_SELECTBOX_ID_CUSTOM_ACCESS_DIRECTION        4
+#define ED_SELECTBOX_ID_CUSTOM_WALK_TO_ACTION  5
+#define ED_SELECTBOX_ID_CUSTOM_MOVE_PATTERN    6
+#define ED_SELECTBOX_ID_CUSTOM_MOVE_DIRECTION  7
+#define ED_SELECTBOX_ID_CUSTOM_MOVE_STEPSIZE   8
+#define ED_SELECTBOX_ID_CUSTOM_MOVE_LEAVE_TYPE 9
+#define ED_SELECTBOX_ID_CUSTOM_SMASH_TARGETS   10
+#define ED_SELECTBOX_ID_CUSTOM_SLIPPERY_TYPE   11
+#define ED_SELECTBOX_ID_CUSTOM_DEADLINESS      12
+#define ED_SELECTBOX_ID_CUSTOM_EXPLOSION_TYPE  13
+#define ED_SELECTBOX_ID_CHANGE_TIME_UNITS      14
+#define ED_SELECTBOX_ID_CHANGE_DIRECT_ACTION   15
+#define ED_SELECTBOX_ID_CHANGE_OTHER_ACTION    16
+#define ED_SELECTBOX_ID_CHANGE_SIDE            17
+#define ED_SELECTBOX_ID_CHANGE_PLAYER          18
+#define ED_SELECTBOX_ID_CHANGE_PAGE            19
+#define ED_SELECTBOX_ID_CHANGE_REPLACE_WHEN    20
+#define ED_SELECTBOX_ID_SELECT_CHANGE_PAGE     21
+#define ED_SELECTBOX_ID_GROUP_CHOICE_MODE      22
+
+#define ED_NUM_SELECTBOX                       23
+
+#define ED_SELECTBOX_ID_LEVEL_FIRST    ED_SELECTBOX_ID_TIME_OR_STEPS
+#define ED_SELECTBOX_ID_LEVEL_LAST     ED_SELECTBOX_ID_TIME_OR_STEPS
+
+#define ED_SELECTBOX_ID_CUSTOM1_FIRST  ED_SELECTBOX_ID_CUSTOM_ACCESS_TYPE
+#define ED_SELECTBOX_ID_CUSTOM1_LAST   ED_SELECTBOX_ID_CUSTOM_WALK_TO_ACTION
+#define ED_SELECTBOX_ID_CUSTOM2_FIRST  ED_SELECTBOX_ID_CUSTOM_MOVE_PATTERN
+#define ED_SELECTBOX_ID_CUSTOM2_LAST   ED_SELECTBOX_ID_CUSTOM_EXPLOSION_TYPE
+#define ED_SELECTBOX_ID_CUSTOM_FIRST   ED_SELECTBOX_ID_CUSTOM1_FIRST
+#define ED_SELECTBOX_ID_CUSTOM_LAST    ED_SELECTBOX_ID_CUSTOM2_LAST
 
 #define ED_SELECTBOX_ID_CHANGE_FIRST   ED_SELECTBOX_ID_CHANGE_TIME_UNITS
 #define ED_SELECTBOX_ID_CHANGE_LAST    ED_SELECTBOX_ID_SELECT_CHANGE_PAGE
 /* values for textbutton gadgets */
 #define ED_TEXTBUTTON_ID_PROPERTIES_INFO       0
 #define ED_TEXTBUTTON_ID_PROPERTIES_CONFIG     1
-#define ED_TEXTBUTTON_ID_PROPERTIES_ADVANCED   2
-#define ED_TEXTBUTTON_ID_SAVE_AS_TEMPLATE      3
-#define ED_TEXTBUTTON_ID_ADD_CHANGE_PAGE       4
-#define ED_TEXTBUTTON_ID_DEL_CHANGE_PAGE       5
+#define ED_TEXTBUTTON_ID_PROPERTIES_CONFIG_1   2
+#define ED_TEXTBUTTON_ID_PROPERTIES_CONFIG_2   3
+#define ED_TEXTBUTTON_ID_PROPERTIES_CHANGE     4
+#define ED_TEXTBUTTON_ID_SAVE_AS_TEMPLATE      5
+#define ED_TEXTBUTTON_ID_ADD_CHANGE_PAGE       6
+#define ED_TEXTBUTTON_ID_DEL_CHANGE_PAGE       7
 
-#define ED_NUM_TEXTBUTTONS                     6
+#define ED_NUM_TEXTBUTTONS                     8
 
 #define ED_TEXTBUTTON_ID_PROPERTIES_FIRST ED_TEXTBUTTON_ID_PROPERTIES_INFO
-#define ED_TEXTBUTTON_ID_PROPERTIES_LAST  ED_TEXTBUTTON_ID_PROPERTIES_ADVANCED
+#define ED_TEXTBUTTON_ID_PROPERTIES_LAST  ED_TEXTBUTTON_ID_PROPERTIES_CHANGE
 
-#define ED_TEXTBUTTON_ID_CHANGE_FIRST  ED_TEXTBUTTON_ID_SAVE_AS_TEMPLATE
+#define ED_TEXTBUTTON_ID_CHANGE_FIRST  ED_TEXTBUTTON_ID_ADD_CHANGE_PAGE
 #define ED_TEXTBUTTON_ID_CHANGE_LAST   ED_TEXTBUTTON_ID_DEL_CHANGE_PAGE
 
 /* values for graphicbutton gadgets */
 #define ED_GRAPHICBUTTON_ID_PREV_CHANGE_PAGE   0
 #define ED_GRAPHICBUTTON_ID_NEXT_CHANGE_PAGE   1
+#define ED_GRAPHICBUTTON_ID_COPY_CHANGE_PAGE   2
+#define ED_GRAPHICBUTTON_ID_PASTE_CHANGE_PAGE  3
 
-#define ED_NUM_GRAPHICBUTTONS                  2
+#define ED_NUM_GRAPHICBUTTONS                  4
 
-#define ED_GRAPHICBUTTON_ID_CHANGE_FIRST   ED_GRAPHICBUTTON_ID_PREV_CHANGE_PAGE
-#define ED_GRAPHICBUTTON_ID_CHANGE_LAST    ED_GRAPHICBUTTON_ID_NEXT_CHANGE_PAGE
+#define ED_GRAPHICBUTTON_ID_CHANGE_FIRST  ED_GRAPHICBUTTON_ID_PREV_CHANGE_PAGE
+#define ED_GRAPHICBUTTON_ID_CHANGE_LAST   ED_GRAPHICBUTTON_ID_PASTE_CHANGE_PAGE
 
 /* values for checkbutton gadgets */
 #define ED_CHECKBUTTON_ID_DOUBLE_SPEED         0
 #define ED_CHECKBUTTON_ID_RANDOM_RESTRICTED    2
 #define ED_CHECKBUTTON_ID_STICK_ELEMENT                3
 #define ED_CHECKBUTTON_ID_EM_SLIPPERY_GEMS     4
-#define ED_CHECKBUTTON_ID_CUSTOM_ACCESSIBLE    5
-#define ED_CHECKBUTTON_ID_CUSTOM_WALK_TO_OBJECT        6
-#define ED_CHECKBUTTON_ID_CUSTOM_CAN_MOVE      7
-#define ED_CHECKBUTTON_ID_CUSTOM_CAN_FALL      8
-#define ED_CHECKBUTTON_ID_CUSTOM_CAN_SMASH     9
-#define ED_CHECKBUTTON_ID_CUSTOM_SLIPPERY      10
-#define ED_CHECKBUTTON_ID_CUSTOM_DEADLY                11
-#define ED_CHECKBUTTON_ID_CUSTOM_EXPLODE_RESULT        12
-#define ED_CHECKBUTTON_ID_CUSTOM_EXPLODE_FIRE  13
-#define ED_CHECKBUTTON_ID_CUSTOM_EXPLODE_SMASH 14
-#define ED_CHECKBUTTON_ID_CUSTOM_EXPLODE_IMPACT        15
-#define ED_CHECKBUTTON_ID_CUSTOM_USE_GRAPHIC   16
-#define ED_CHECKBUTTON_ID_CUSTOM_CAN_CHANGE    17
-#define ED_CHECKBUTTON_ID_CHANGE_DELAY         18
-#define ED_CHECKBUTTON_ID_CHANGE_BY_DIRECT_ACT 19
-#define ED_CHECKBUTTON_ID_CHANGE_BY_OTHER_ACT  20
-#define ED_CHECKBUTTON_ID_CHANGE_USE_EXPLOSION 21
-#define ED_CHECKBUTTON_ID_CHANGE_USE_CONTENT   22
-#define ED_CHECKBUTTON_ID_CHANGE_ONLY_COMPLETE 23
-#define ED_CHECKBUTTON_ID_CHANGE_USE_RANDOM    24
-#define ED_CHECKBUTTON_ID_CUSTOM_USE_TEMPLATE  25
-
-#define ED_NUM_CHECKBUTTONS                    26
+#define ED_CHECKBUTTON_ID_USE_SPRING_BUG       5
+#define ED_CHECKBUTTON_ID_GROW_INTO_DIGGABLE   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_DOUBLE_SPEED
 #define ED_CHECKBUTTON_ID_LEVEL_LAST   ED_CHECKBUTTON_ID_RANDOM_RESTRICTED
 
-#define ED_CHECKBUTTON_ID_CUSTOM_FIRST ED_CHECKBUTTON_ID_CUSTOM_ACCESSIBLE
-#define ED_CHECKBUTTON_ID_CUSTOM_LAST  ED_CHECKBUTTON_ID_CUSTOM_EXPLODE_IMPACT
+#define ED_CHECKBUTTON_ID_CUSTOM1_FIRST        ED_CHECKBUTTON_ID_CUSTOM_USE_GRAPHIC
+#define ED_CHECKBUTTON_ID_CUSTOM1_LAST ED_CHECKBUTTON_ID_CUSTOM_INDESTRUCTIBLE
+#define ED_CHECKBUTTON_ID_CUSTOM2_FIRST        ED_CHECKBUTTON_ID_CUSTOM_CAN_MOVE
+#define ED_CHECKBUTTON_ID_CUSTOM2_LAST ED_CHECKBUTTON_ID_CUSTOM_EXPLODE_IMPACT
+#define ED_CHECKBUTTON_ID_CUSTOM_FIRST ED_CHECKBUTTON_ID_CUSTOM1_FIRST
+#define ED_CHECKBUTTON_ID_CUSTOM_LAST  ED_CHECKBUTTON_ID_CUSTOM2_LAST
 
-#define ED_CHECKBUTTON_ID_CHANGE_FIRST ED_CHECKBUTTON_ID_CUSTOM_USE_GRAPHIC
-#define ED_CHECKBUTTON_ID_CHANGE_LAST  ED_CHECKBUTTON_ID_CUSTOM_USE_TEMPLATE
+#define ED_CHECKBUTTON_ID_CHANGE_FIRST ED_CHECKBUTTON_ID_CUSTOM_CAN_CHANGE
+#define ED_CHECKBUTTON_ID_CHANGE_LAST  ED_CHECKBUTTON_ID_CHANGE_USE_RANDOM
 
 /* values for radiobutton gadgets */
 #define ED_RADIOBUTTON_ID_PERCENTAGE   0
 #define ED_DRAWING_ID_AMOEBA_CONTENT           9
 #define ED_DRAWING_ID_CUSTOM_GRAPHIC           10
 #define ED_DRAWING_ID_CUSTOM_CONTENT           11
-#define ED_DRAWING_ID_CUSTOM_CHANGE_TARGET     12
-#define ED_DRAWING_ID_CUSTOM_CHANGE_CONTENT    13
-#define ED_DRAWING_ID_CUSTOM_CHANGE_TRIGGER    14
-#define ED_DRAWING_ID_RANDOM_BACKGROUND                15
+#define ED_DRAWING_ID_CUSTOM_MOVE_ENTER                12
+#define ED_DRAWING_ID_CUSTOM_MOVE_LEAVE                13
+#define ED_DRAWING_ID_CUSTOM_CHANGE_TARGET     14
+#define ED_DRAWING_ID_CUSTOM_CHANGE_CONTENT    15
+#define ED_DRAWING_ID_CUSTOM_CHANGE_TRIGGER    16
+#define ED_DRAWING_ID_GROUP_CONTENT            17
+#define ED_DRAWING_ID_RANDOM_BACKGROUND                18
 
-#define ED_NUM_DRAWING_AREAS                   16
+#define ED_NUM_DRAWING_AREAS                   19
 
 
 /*
 /* sub-screens in the element properties section */
 #define ED_MODE_PROPERTIES_INFO                ED_TEXTBUTTON_ID_PROPERTIES_INFO
 #define ED_MODE_PROPERTIES_CONFIG      ED_TEXTBUTTON_ID_PROPERTIES_CONFIG
-#define ED_MODE_PROPERTIES_ADVANCED    ED_TEXTBUTTON_ID_PROPERTIES_ADVANCED
+#define ED_MODE_PROPERTIES_CONFIG_1    ED_TEXTBUTTON_ID_PROPERTIES_CONFIG_1
+#define ED_MODE_PROPERTIES_CONFIG_2    ED_TEXTBUTTON_ID_PROPERTIES_CONFIG_2
+#define ED_MODE_PROPERTIES_CHANGE      ED_TEXTBUTTON_ID_PROPERTIES_CHANGE
 
 /* how many steps can be cancelled */
 #define NUM_UNDO_STEPS                 (10 + 1)
@@ -784,7 +869,10 @@ static struct
 
   { '\0',      "copy settings from other element"      },
   { '\0',      "copy settings to other element"        },
-  { '\0',      "exchange settings with other element"  },
+  { '\0',      "exchange element with other element"   },
+
+  { '\0',      "copy settings from this element"       },
+  { '\0',      "paste settings to this element"        },
 };
 
 static int random_placement_value = 10;
@@ -795,6 +883,7 @@ static boolean stick_element_properties_window = FALSE;
 static boolean custom_element_properties[NUM_ELEMENT_PROPERTIES];
 static boolean custom_element_change_events[NUM_CHANGE_EVENTS];
 static struct ElementChangeInfo custom_element_change;
+static struct ElementGroupInfo group_element_info;
 static struct ElementInfo custom_element;
 
 static struct
@@ -840,15 +929,15 @@ static struct
     GADGET_ID_LEVEL_GEMSLIMIT_DOWN,    GADGET_ID_LEVEL_GEMSLIMIT_UP,
     GADGET_ID_LEVEL_GEMSLIMIT_TEXT,    GADGET_ID_NONE,
     &level.gems_needed,
-    "number of emeralds to collect:",  NULL, NULL
+    "number of gems to collect:",      NULL, NULL
   },
   {
     ED_SETTINGS_XPOS(0),               ED_COUNTER_YPOS(4),
-    0,                                 999,
+    0,                                 9999,
     GADGET_ID_LEVEL_TIMELIMIT_DOWN,    GADGET_ID_LEVEL_TIMELIMIT_UP,
     GADGET_ID_LEVEL_TIMELIMIT_TEXT,    GADGET_ID_NONE,
     &level.time,
-    "time available to solve level:",  NULL, "(0 => no time limit)"
+    "time or step limit to solve level:", NULL, NULL
   },
   {
     ED_SETTINGS_XPOS(0),               ED_COUNTER_YPOS(5),
@@ -856,7 +945,7 @@ static struct
     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 seconds left:", NULL, NULL
+    "score for each 10 sec/steps left:", NULL, NULL
   },
   {
     ED_SETTINGS_XPOS(0),               ED_COUNTER2_YPOS(8),
@@ -878,7 +967,7 @@ static struct
     NULL,                              NULL, NULL
   },
   {
-    ED_SETTINGS_XPOS(0),               ED_SETTINGS_YPOS(6),
+    ED_SETTINGS_XPOS(0),               ED_SETTINGS_YPOS(3),
     MIN_ELEMENT_CONTENTS,              MAX_ELEMENT_CONTENTS,
     GADGET_ID_ELEMENT_CONTENT_DOWN,    GADGET_ID_ELEMENT_CONTENT_UP,
     GADGET_ID_ELEMENT_CONTENT_TEXT,    GADGET_ID_NONE,
@@ -902,10 +991,10 @@ static struct
     NULL,                              " ", "height",
   },
 
-  /* ---------- element settings: configure (custom elements) ------------- */
+  /* ---------- element settings: configure 1 (custom elements) ------------ */
 
   {
-    ED_SETTINGS_XPOS(1),               ED_SETTINGS_YPOS(3),
+    ED_SETTINGS_XPOS(1),               ED_SETTINGS_YPOS(6),
     MIN_SCORE,                         MAX_SCORE,
     GADGET_ID_CUSTOM_SCORE_DOWN,       GADGET_ID_CUSTOM_SCORE_UP,
     GADGET_ID_CUSTOM_SCORE_TEXT,       GADGET_ID_NONE,
@@ -913,7 +1002,7 @@ static struct
     NULL,                              "score", " "
   },
   {
-    -1,                                        ED_SETTINGS_YPOS(3),
+    -1,                                        ED_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,
@@ -921,23 +1010,42 @@ static struct
     NULL,                              "count", NULL
   },
   {
-    ED_SETTINGS_XPOS(1),               ED_SETTINGS_YPOS(4),
-    0,                                 999,
+    ED_SETTINGS_XPOS(1),               ED_SETTINGS_YPOS(7),
+    0,                                 255,
     GADGET_ID_PUSH_DELAY_FIX_DOWN,     GADGET_ID_PUSH_DELAY_FIX_UP,
     GADGET_ID_PUSH_DELAY_FIX_TEXT,     GADGET_ID_NONE,
     &custom_element.push_delay_fixed,
     NULL,                              "push delay", NULL
   },
   {
-    -1,                                        ED_SETTINGS_YPOS(4),
-    0,                                 999,
+    -1,                                        ED_SETTINGS_YPOS(7),
+    0,                                 255,
     GADGET_ID_PUSH_DELAY_RND_DOWN,     GADGET_ID_PUSH_DELAY_RND_UP,
     GADGET_ID_PUSH_DELAY_RND_TEXT,     GADGET_ID_PUSH_DELAY_FIX_UP,
     &custom_element.push_delay_random,
     NULL,                              "+random", NULL
   },
   {
-    ED_SETTINGS_XPOS(1),               ED_SETTINGS_YPOS(7),
+    ED_SETTINGS_XPOS(1),               ED_SETTINGS_YPOS(8),
+    0,                                 255,
+    GADGET_ID_DROP_DELAY_FIX_DOWN,     GADGET_ID_DROP_DELAY_FIX_UP,
+    GADGET_ID_DROP_DELAY_FIX_TEXT,     GADGET_ID_NONE,
+    &custom_element.drop_delay_fixed,
+    NULL,                              "drop delay", NULL
+  },
+  {
+    -1,                                        ED_SETTINGS_YPOS(8),
+    0,                                 255,
+    GADGET_ID_DROP_DELAY_RND_DOWN,     GADGET_ID_DROP_DELAY_RND_UP,
+    GADGET_ID_DROP_DELAY_RND_TEXT,     GADGET_ID_DROP_DELAY_FIX_UP,
+    &custom_element.drop_delay_random,
+    NULL,                              "+random", NULL
+  },
+
+  /* ---------- element settings: configure 2 (custom elements) ------------ */
+
+  {
+    ED_SETTINGS_XPOS(1),               ED_SETTINGS_YPOS(5),
     0,                                 999,
     GADGET_ID_MOVE_DELAY_FIX_DOWN,     GADGET_ID_MOVE_DELAY_FIX_UP,
     GADGET_ID_MOVE_DELAY_FIX_TEXT,     GADGET_ID_NONE,
@@ -945,18 +1053,45 @@ static struct
     NULL,                              "move delay", NULL
   },
   {
-    -1,                                        ED_SETTINGS_YPOS(7),
+    -1,                                        ED_SETTINGS_YPOS(5),
     0,                                 999,
     GADGET_ID_MOVE_DELAY_RND_DOWN,     GADGET_ID_MOVE_DELAY_RND_UP,
     GADGET_ID_MOVE_DELAY_RND_TEXT,     GADGET_ID_MOVE_DELAY_FIX_UP,
     &custom_element.move_delay_random,
     NULL,                              "+random", NULL
   },
+  {
+    ED_SETTINGS_XPOS(1),               ED_SETTINGS_YPOS(12),
+    0,                                 255,
+    GADGET_ID_EXPLOSION_DELAY_DOWN,    GADGET_ID_EXPLOSION_DELAY_UP,
+    GADGET_ID_EXPLOSION_DELAY_TEXT,    GADGET_ID_NONE,
+    &custom_element.explosion_delay,
+    NULL,                              "explosion delay", NULL
+  },
+  {
+    ED_SETTINGS_XPOS(1),               ED_SETTINGS_YPOS(13),
+    0,                                 255,
+    GADGET_ID_IGNITION_DELAY_DOWN,     GADGET_ID_IGNITION_DELAY_UP,
+    GADGET_ID_IGNITION_DELAY_TEXT,     GADGET_ID_NONE,
+    &custom_element.ignition_delay,
+    NULL,                              "ignition delay", "(by fire)"
+  },
+
+  /* ---------- element settings: configure (group elements) --------------- */
+
+  {
+    ED_SETTINGS_XPOS(0),               ED_SETTINGS_YPOS(5),
+    MIN_ELEMENTS_IN_GROUP,             MAX_ELEMENTS_IN_GROUP,
+    GADGET_ID_GROUP_CONTENT_DOWN,      GADGET_ID_GROUP_CONTENT_UP,
+    GADGET_ID_GROUP_CONTENT_TEXT,      GADGET_ID_NONE,
+    &group_element_info.num_elements,
+    NULL,                              NULL, "number of elements in group"
+  },
 
   /* ---------- element settings: advanced (custom elements) --------------- */
 
   {
-    ED_SETTINGS_XPOS(2),               ED_SETTINGS_YPOS(3),
+    ED_SETTINGS_XPOS(2),               ED_SETTINGS_YPOS(2),
     0,                                 999,
     GADGET_ID_CHANGE_DELAY_FIX_DOWN,   GADGET_ID_CHANGE_DELAY_FIX_UP,
     GADGET_ID_CHANGE_DELAY_FIX_TEXT,   GADGET_ID_NONE,
@@ -964,7 +1099,7 @@ static struct
     NULL,                              "delay", NULL,
   },
   {
-    -1,                                        ED_SETTINGS_YPOS(3),
+    -1,                                        ED_SETTINGS_YPOS(2),
     0,                                 999,
     GADGET_ID_CHANGE_DELAY_RND_DOWN,   GADGET_ID_CHANGE_DELAY_RND_UP,
     GADGET_ID_CHANGE_DELAY_RND_TEXT,   GADGET_ID_CHANGE_DELAY_FIX_UP,
@@ -976,7 +1111,7 @@ static struct
     0,                                 100,
     GADGET_ID_CHANGE_CONT_RND_DOWN,    GADGET_ID_CHANGE_CONT_RND_UP,
     GADGET_ID_CHANGE_CONT_RND_TEXT,    GADGET_ID_NONE,
-    &custom_element_change.random,
+    &custom_element_change.random_percentage,
     NULL,                              "use random replace:", "%"
   },
 };
@@ -1005,7 +1140,7 @@ static struct
     "Author:", "Author"
   },
   {
-    5 * MINI_TILEX,                    5 * MINI_TILEY - ED_BORDER_SIZE,
+    5 * MINI_TILEX - 2,                        5 * MINI_TILEY - ED_BORDER_SIZE + 1,
     GADGET_ID_ELEMENT_NAME,
     MAX_ELEMENT_NAME_LEN - 2,          /* currently 2 chars less editable */
     custom_element.description,
@@ -1031,10 +1166,19 @@ static struct
   }
 };
 
+static struct ValueTextInfo options_time_or_steps[] =
+{
+  { 0,                         "seconds"                       },
+  { 1,                         "steps"                         },
+
+  { -1,                                NULL                            }
+};
+
 static struct ValueTextInfo options_access_type[] =
 {
-  { EP_WALKABLE,               "walk"                          },
-  { EP_PASSABLE,               "pass"                          },
+  { EP_WALKABLE,               "walkable"                      },
+  { EP_PASSABLE,               "passable"                      },
+
   { -1,                                NULL                            }
 };
 
@@ -1043,6 +1187,36 @@ static struct ValueTextInfo options_access_layer[] =
   { EP_ACCESSIBLE_OVER,                "over"                          },
   { EP_ACCESSIBLE_INSIDE,      "inside"                        },
   { EP_ACCESSIBLE_UNDER,       "under"                         },
+
+  { -1,                                NULL                            }
+};
+
+static struct ValueTextInfo options_access_protected[] =
+{
+  { 0,                         "unprotected"                   },
+  { 1,                         "protected"                     },
+
+  { -1,                                NULL                            }
+};
+
+static struct ValueTextInfo options_access_direction[] =
+{
+  { MV_LEFT,                   "left"                          },
+  { MV_RIGHT,                  "right"                         },
+  { MV_UP,                     "up"                            },
+  { MV_DOWN,                   "down"                          },
+  { MV_LEFT  | MV_UP,          "left + up"                     },
+  { MV_LEFT  | MV_DOWN,                "left + down"                   },
+  { MV_RIGHT | MV_UP,          "right + up"                    },
+  { MV_RIGHT | MV_DOWN,                "right + down"                  },
+  { MV_HORIZONTAL,             "horizontal"                    },
+  { MV_VERTICAL,               "vertical"                      },
+  { MV_HORIZONTAL | MV_UP,     "horizontal + up"               },
+  { MV_HORIZONTAL | MV_DOWN,   "horizontal + down"             },
+  { MV_VERTICAL   | MV_LEFT,   "vertical + left"               },
+  { MV_VERTICAL   | MV_RIGHT,  "vertical + right"              },
+  { MV_ALL_DIRECTIONS,         "all directions"                },
+
   { -1,                                NULL                            }
 };
 
@@ -1051,7 +1225,9 @@ static struct ValueTextInfo options_walk_to_action[] =
   { EP_DIGGABLE,               "diggable"                      },
   { EP_COLLECTIBLE_ONLY,       "collectible"                   },
   { EP_DROPPABLE,              "collectible & droppable"       },
+  { EP_THROWABLE,              "collectible & throwable"       },
   { EP_PUSHABLE,               "pushable"                      },
+
   { -1,                                NULL                            }
 };
 
@@ -1070,21 +1246,27 @@ static struct ValueTextInfo options_move_pattern[] =
   { MV_ALONG_RIGHT_SIDE,       "along right side"              },
   { MV_TURNING_LEFT,           "turning left"                  },
   { MV_TURNING_RIGHT,          "turning right"                 },
-  { MV_WHEN_PUSHED,            "when pushed"                   },
-#if 0
+  { MV_TURNING_LEFT_RIGHT,     "turning left, right"           },
+  { MV_TURNING_RIGHT_LEFT,     "turning right, left"           },
+  { MV_TURNING_RANDOM,         "turning random"                },
   { MV_MAZE_RUNNER,            "maze runner style"             },
   { MV_MAZE_HUNTER,            "maze hunter style"             },
-#endif
+  { MV_WHEN_PUSHED,            "when pushed"                   },
+  { MV_WHEN_DROPPED,           "when dropped/thrown"           },
+
   { -1,                                NULL                            }
 };
 
 static struct ValueTextInfo options_move_direction[] =
 {
-  { MV_NO_MOVING,              "automatic"                     },
-  { MV_LEFT,                   "left"                          },
-  { MV_RIGHT,                  "right"                         },
-  { MV_UP,                     "up"                            },
-  { MV_DOWN,                   "down"                          },
+  { MV_START_AUTOMATIC,                "automatic"                     },
+  { MV_START_LEFT,             "left"                          },
+  { MV_START_RIGHT,            "right"                         },
+  { MV_START_UP,               "up"                            },
+  { MV_START_DOWN,             "down"                          },
+  { MV_START_RANDOM,           "random"                        },
+  { MV_START_PREVIOUS,         "previous"                      },
+
   { -1,                                NULL                            }
 };
 
@@ -1095,6 +1277,18 @@ static struct ValueTextInfo options_move_stepsize[] =
   { 4,                         "normal"                        },
   { 8,                         "fast"                          },
   { 16,                                "very fast"                     },
+#if 1
+  { 32,                                "even faster"                   },
+#endif
+
+  { -1,                                NULL                            }
+};
+
+static struct ValueTextInfo options_move_leave_type[] =
+{
+  { LEAVE_TYPE_UNLIMITED,      "leave behind"                  },
+  { LEAVE_TYPE_LIMITED,                "change it to"                  },
+
   { -1,                                NULL                            }
 };
 
@@ -1105,6 +1299,7 @@ static struct ValueTextInfo options_smash_targets[] =
   { EP_CAN_SMASH_ENEMIES,      "enemies"                       },
 #endif
   { EP_CAN_SMASH_EVERYTHING,   "everything"                    },
+
   { -1,                                NULL                            }
 };
 
@@ -1115,6 +1310,7 @@ static struct ValueTextInfo options_slippery_type[] =
   { SLIPPERY_ANY_RIGHT_LEFT,   "right, left"                   },
   { SLIPPERY_ONLY_LEFT,                "only left"                     },
   { SLIPPERY_ONLY_RIGHT,       "only right"                    },
+
   { -1,                                NULL                            }
 };
 
@@ -1123,14 +1319,19 @@ static struct ValueTextInfo options_deadliness[] =
   { EP_DONT_RUN_INTO,          "running into"                  },
   { EP_DONT_COLLIDE_WITH,      "colliding with"                },
   { EP_DONT_TOUCH,             "touching"                      },
+
   { -1,                                NULL                            }
 };
 
-static struct ValueTextInfo options_consistency[] =
+static struct ValueTextInfo options_explosion_type[] =
 {
-  { EP_CAN_EXPLODE_3X3,                "can explode 3x3"               },
-  { EP_CAN_EXPLODE_1X1,                "can explode 1x1"               },
+  { EXPLODES_3X3,              "3x3"                           },
+  { EXPLODES_CROSS,            "3+3"                           },
+  { EXPLODES_1X1,              "1x1"                           },
+#if 0
   { EP_INDESTRUCTIBLE,         "indestructible"                },
+#endif
+
   { -1,                                NULL                            }
 };
 
@@ -1138,67 +1339,128 @@ static struct ValueTextInfo options_time_units[] =
 {
   { 1,                         "frames"                        },
   { FRAMES_PER_SECOND,         "seconds"                       },
+
   { -1,                                NULL                            }
 };
 
 static struct ValueTextInfo options_change_direct_action[] =
 {
-  { CE_TOUCHED_BY_PLAYER,      "touched by player ..."         },
-  { CE_PRESSED_BY_PLAYER,      "pressed 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 by player"             },
-  { CE_SWITCHED,               "switched ..."                  },
-#if 0
-  { CE_COLLISION_ACTIVE,       "hitting something ..."         },
-  { CE_COLLISION_PASSIVE,      "hit by something ..."          },
+  { CE_TOUCHED_BY_PLAYER,      "touched by player"             },
+  { CE_PRESSED_BY_PLAYER,      "pressed 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_COLLISION_ACTIVE,       "collision ..."                 },
+  { CE_HITTING_SOMETHING,      "collision"                     },
+#endif
+#if 1
+  { CE_BLOCKED,                        "blocked"                       },
 #endif
   { CE_IMPACT,                 "impact (on something)"         },
   { CE_SMASHED,                        "smashed (from above)"          },
+
   { -1,                                NULL                            }
 };
 
 static struct ValueTextInfo options_change_other_action[] =
 {
-  { CE_OTHER_GETS_TOUCHED,     "player touches ..."            },
-  { CE_OTHER_GETS_PRESSED,     "player presses ..."            },
-  { CE_OTHER_GETS_PUSHED,      "player pushes ..."             },
-  { CE_OTHER_GETS_ENTERED,     "player enters ..."             },
-  { CE_OTHER_GETS_LEFT,                "player leaves ..."             },
+  { CE_OTHER_GETS_TOUCHED,     "player touches"                },
+  { CE_OTHER_GETS_PRESSED,     "player presses"                },
+  { CE_OTHER_GETS_PUSHED,      "player pushes"                 },
+  { CE_OTHER_GETS_ENTERED,     "player enters"                 },
+  { CE_OTHER_GETS_LEFT,                "player leaves"                 },
   { CE_OTHER_GETS_DIGGED,      "player digs"                   },
   { CE_OTHER_GETS_COLLECTED,   "player collects"               },
-  { CE_OTHER_GETS_DROPPED,     "player drops"                  },
-  { CE_OTHER_IS_TOUCHING,      "touching ..."                  },
-#if 0
-  { CE_OTHER_IS_COLL_ACTIVE,   "hitting ..."                   },
-  { CE_OTHER_IS_COLL_PASSIVE,  "hit by ..."                    },
+  { CE_OTHER_GETS_DROPPED,     "player drops/throws"           },
+  { CE_OTHER_IS_TOUCHING,      "touching"                      },
+#if 1
+  { CE_OTHER_IS_HITTING,       "hitting"                       },
+  { CE_OTHER_GETS_HIT,         "hit by"                        },
 #endif
-  { CE_OTHER_IS_SWITCHING,     "switch of ..."                 },
-  { CE_OTHER_IS_CHANGING,      "change of"                     },
+  { CE_OTHER_IS_SWITCHING,     "switch of"                     },
+  { CE_OTHER_IS_CHANGING,      "change by page of"             },
   { CE_OTHER_IS_EXPLODING,     "explosion of"                  },
+
+  { -1,                                NULL                            }
+};
+
+static struct ValueTextInfo options_change_trigger_side[] =
+{
+  { CH_SIDE_LEFT,              "left"                          },
+  { CH_SIDE_RIGHT,             "right"                         },
+  { CH_SIDE_TOP,               "top"                           },
+  { CH_SIDE_BOTTOM,            "bottom"                        },
+  { CH_SIDE_LEFT_RIGHT,                "left/right"                    },
+  { CH_SIDE_TOP_BOTTOM,                "top/bottom"                    },
+  { CH_SIDE_ANY,               "any"                           },
+
   { -1,                                NULL                            }
 };
 
-static struct ValueTextInfo options_change_sides[] =
+static struct ValueTextInfo options_change_trigger_player[] =
 {
-  { CH_SIDE_LEFT,              "left side"                     },
-  { CH_SIDE_RIGHT,             "right side"                    },
-  { CH_SIDE_TOP,               "top side"                      },
-  { CH_SIDE_BOTTOM,            "bottom side"                   },
-  { CH_SIDE_LEFT_RIGHT,                "left/right side"               },
-  { CH_SIDE_TOP_BOTTOM,                "top/bottom side"               },
-  { CH_SIDE_ANY,               "any side"                      },
+  { CH_PLAYER_1,               "1"                             },
+  { CH_PLAYER_2,               "2"                             },
+  { CH_PLAYER_3,               "3"                             },
+  { CH_PLAYER_4,               "4"                             },
+  { CH_PLAYER_ANY,             "any"                           },
+
+  { -1,                                NULL                            }
+};
+
+static struct ValueTextInfo options_change_trigger_page[] =
+{
+  { (1 << 0),                  "1"                             },
+  { (1 << 1),                  "2"                             },
+  { (1 << 2),                  "3"                             },
+  { (1 << 3),                  "4"                             },
+  { (1 << 4),                  "5"                             },
+  { (1 << 5),                  "6"                             },
+  { (1 << 6),                  "7"                             },
+  { (1 << 7),                  "8"                             },
+  { (1 << 8),                  "9"                             },
+  { (1 << 9),                  "10"                            },
+  { (1 << 10),                 "11"                            },
+  { (1 << 11),                 "12"                            },
+  { (1 << 12),                 "13"                            },
+  { (1 << 13),                 "14"                            },
+  { (1 << 14),                 "15"                            },
+  { (1 << 15),                 "16"                            },
+  { (1 << 16),                 "17"                            },
+  { (1 << 17),                 "18"                            },
+  { (1 << 18),                 "19"                            },
+  { (1 << 19),                 "20"                            },
+  { (1 << 20),                 "21"                            },
+  { (1 << 21),                 "22"                            },
+  { (1 << 22),                 "23"                            },
+  { (1 << 23),                 "24"                            },
+  { (1 << 24),                 "25"                            },
+  { (1 << 25),                 "26"                            },
+  { (1 << 26),                 "27"                            },
+  { (1 << 27),                 "28"                            },
+  { (1 << 28),                 "29"                            },
+  { (1 << 29),                 "30"                            },
+  { (1 << 30),                 "31"                            },
+  { (1 << 31),                 "32"                            },
+  { CH_PAGE_ANY,               "any"                           },
+
   { -1,                                NULL                            }
 };
 
-static struct ValueTextInfo options_change_power[] =
+static struct ValueTextInfo options_change_replace_when[] =
 {
-  { CP_NON_DESTRUCTIVE,                "empty"                         },
-  { CP_HALF_DESTRUCTIVE,       "diggable"                      },
-  { CP_FULL_DESTRUCTIVE,       "destructible"                  },
+  { CP_WHEN_EMPTY,             "empty"                         },
+  { CP_WHEN_WALKABLE,          "walkable"                      },
+  { CP_WHEN_DIGGABLE,          "diggable"                      },
+  { CP_WHEN_COLLECTIBLE,       "collectible"                   },
+  { CP_WHEN_REMOVABLE,         "removable"                     },
+  { CP_WHEN_DESTRUCTIBLE,      "destructible"                  },
+
   { -1,                                NULL                            }
 };
 
@@ -1208,6 +1470,17 @@ static struct ValueTextInfo options_change_page[MAX_CHANGE_PAGES + 1] =
   { -1,                                NULL                            }
 };
 
+static struct ValueTextInfo options_group_choice_mode[] =
+{
+  { ANIM_RANDOM,               "random"                        },
+  { ANIM_LOOP,                 "loop"                          },
+  { ANIM_LINEAR,               "linear"                        },
+  { ANIM_PINGPONG,             "pingpong"                      },
+  { ANIM_PINGPONG2,            "pingpong 2"                    },
+
+  { -1,                                NULL                            }
+};
+
 static struct
 {
   int x, y;
@@ -1219,18 +1492,29 @@ static struct
   char *text_left, *text_right, *infotext;
 } selectbox_info[ED_NUM_SELECTBOX] =
 {
-  /* ---------- element settings: configure (custom elements) ------------- */
+  /* ---------- level and editor settings ---------------------------------- */
 
   {
-    ED_SETTINGS_XPOS(1),               ED_SETTINGS_YPOS(1),
+    -1,                                        ED_COUNTER_YPOS(4),
+    GADGET_ID_TIME_OR_STEPS,           GADGET_ID_LEVEL_TIMELIMIT_UP,
+    -1,
+    options_time_or_steps,
+    &level.use_step_counter,
+    NULL, "(0 => no limit)",           "time or step limit"
+  },
+
+  /* ---------- element settings: configure 1 (custom elements) ----------- */
+
+  {
+    ED_SETTINGS_XPOS(1),               ED_SETTINGS_YPOS(3),
     GADGET_ID_CUSTOM_ACCESS_TYPE,      GADGET_ID_NONE,
     -1,
     options_access_type,
     &custom_element.access_type,
-    "player can", NULL,                        "type of access to this field"
+    NULL, NULL,                                "type of access to this field"
   },
   {
-    -1,                                        ED_SETTINGS_YPOS(1),
+    -1,                                        ED_SETTINGS_YPOS(3),
     GADGET_ID_CUSTOM_ACCESS_LAYER,     GADGET_ID_CUSTOM_ACCESS_TYPE,
     -1,
     options_access_layer,
@@ -1238,23 +1522,42 @@ static struct
     NULL, NULL,                                "layer of access for this field"
   },
   {
-    ED_SETTINGS_XPOS(1),               ED_SETTINGS_YPOS(2),
+    -1,                                        ED_SETTINGS_YPOS(3),
+    GADGET_ID_CUSTOM_ACCESS_PROTECTED, GADGET_ID_CUSTOM_ACCESS_LAYER,
+    -1,
+    options_access_protected,
+    &custom_element.access_protected,
+    NULL, NULL,                                "protected access for this field"
+  },
+  {
+    ED_SETTINGS_XPOS(1),               ED_SETTINGS_YPOS(4),
+    GADGET_ID_CUSTOM_ACCESS_DIRECTION, GADGET_ID_NONE,
+    -1,
+    options_access_direction,
+    &custom_element.access_direction,
+    "from", NULL,                      "access direction for this field"
+  },
+  {
+    ED_SETTINGS_XPOS(1),               ED_SETTINGS_YPOS(5),
     GADGET_ID_CUSTOM_WALK_TO_ACTION,   GADGET_ID_NONE,
     -1,
     options_walk_to_action,
     &custom_element.walk_to_action,
     NULL, NULL,                                "diggable/collectible/pushable"
   },
+
+  /* ---------- element settings: configure 2 (custom elements) ----------- */
+
   {
-    ED_SETTINGS_XPOS(1),               ED_SETTINGS_YPOS(5),
+    ED_SETTINGS_XPOS(1),               ED_SETTINGS_YPOS(1),
     GADGET_ID_CUSTOM_MOVE_PATTERN,     GADGET_ID_NONE,
     -1,
     options_move_pattern,
     &custom_element.move_pattern,
-    "can move", NULL,                  "element move direction"
+    "can move", NULL,                  "element move pattern"
   },
   {
-    ED_SETTINGS_XPOS(1),               ED_SETTINGS_YPOS(6),
+    ED_SETTINGS_XPOS(1),               ED_SETTINGS_YPOS(2),
     GADGET_ID_CUSTOM_MOVE_DIRECTION,   GADGET_ID_NONE,
     -1,
     options_move_direction,
@@ -1262,7 +1565,7 @@ static struct
     "starts moving", NULL,             "initial element move direction"
   },
   {
-    ED_SETTINGS_XPOS(1),               ED_SETTINGS_YPOS(8),
+    ED_SETTINGS_XPOS(1),               ED_SETTINGS_YPOS(4),
     GADGET_ID_CUSTOM_MOVE_STEPSIZE,    GADGET_ID_NONE,
     -1,
     options_move_stepsize,
@@ -1270,7 +1573,15 @@ static struct
     "move/fall speed", NULL,           "speed of element movement"
   },
   {
-    -1,                                        ED_SETTINGS_YPOS(9),
+    ED_SETTINGS_XPOS(1),               ED_SETTINGS_YPOS(3),
+    GADGET_ID_CUSTOM_MOVE_LEAVE_TYPE,  GADGET_ID_NONE,
+    -1,
+    options_move_leave_type,
+    &custom_element.move_leave_type,
+    "can dig:    can", ":",            "leave behind or change element"
+  },
+  {
+    -1,                                        ED_SETTINGS_YPOS(7),
     GADGET_ID_CUSTOM_SMASH_TARGETS,    GADGET_ID_CUSTOM_CAN_SMASH,
     -1,
     options_smash_targets,
@@ -1278,7 +1589,7 @@ static struct
     "can smash", NULL,                 "elements that can be smashed"
   },
   {
-    ED_SETTINGS_XPOS(1),               ED_SETTINGS_YPOS(10),
+    ED_SETTINGS_XPOS(1),               ED_SETTINGS_YPOS(8),
     GADGET_ID_CUSTOM_SLIPPERY_TYPE,    GADGET_ID_NONE,
     -1,
     options_slippery_type,
@@ -1286,7 +1597,7 @@ static struct
     "slippery", NULL,                  "where other elements fall down"
   },
   {
-    ED_SETTINGS_XPOS(1),               ED_SETTINGS_YPOS(11),
+    ED_SETTINGS_XPOS(1),               ED_SETTINGS_YPOS(9),
     GADGET_ID_CUSTOM_DEADLINESS,       GADGET_ID_NONE,
     -1,
     options_deadliness,
@@ -1294,18 +1605,18 @@ static struct
     "deadly when", NULL,               "deadliness of element"
   },
   {
-    ED_SETTINGS_XPOS(1),               ED_SETTINGS_YPOS(12),
-    GADGET_ID_CUSTOM_CONSISTENCY,      GADGET_ID_NONE,
+    ED_SETTINGS_XPOS(1),               ED_SETTINGS_YPOS(10),
+    GADGET_ID_CUSTOM_EXPLOSION_TYPE,   GADGET_ID_NONE,
     -1,
-    options_consistency,
-    &custom_element.consistency,
-    NULL, NULL,                                "consistency/destructibility"
+    options_explosion_type,
+    &custom_element.explosion_type,
+    "can explode", NULL,               "explosion type"
   },
 
   /* ---------- element settings: advanced (custom elements) --------------- */
 
   {
-    ED_SETTINGS_XPOS(2),               ED_SETTINGS_YPOS(4),
+    ED_SETTINGS_XPOS(2),               ED_SETTINGS_YPOS(3),
     GADGET_ID_CHANGE_TIME_UNITS,       GADGET_ID_NONE,
     -1,
     options_time_units,
@@ -1313,7 +1624,7 @@ static struct
     "delay time given in", NULL,       "delay time units for change"
   },
   {
-    ED_SETTINGS_XPOS(2),               ED_SETTINGS_YPOS(5),
+    ED_SETTINGS_XPOS(2),               ED_SETTINGS_YPOS(4),
     GADGET_ID_CHANGE_DIRECT_ACTION,    GADGET_ID_NONE,
     -1,
     options_change_direct_action,
@@ -1321,27 +1632,43 @@ static struct
     NULL, NULL,                                "type of direct action"
   },
   {
-    ED_SETTINGS_XPOS(2),               ED_SETTINGS_YPOS(6),
+    ED_SETTINGS_XPOS(2),               ED_SETTINGS_YPOS(5),
     GADGET_ID_CHANGE_OTHER_ACTION,     GADGET_ID_NONE,
     -1,
     options_change_other_action,
     &custom_element_change.other_action,
     NULL, "element:",                  "type of other element action"
   },
+  {
+    ED_SETTINGS_XPOS(2),               ED_SETTINGS_YPOS(6),
+    GADGET_ID_CHANGE_SIDE,             GADGET_ID_NONE,
+    -1,
+    options_change_trigger_side,
+    &custom_element_change.trigger_side,
+    "at", "side",                      "element side that causes change"
+  },
   {
     ED_SETTINGS_XPOS(2),               ED_SETTINGS_YPOS(7),
-    GADGET_ID_CHANGE_SIDES,            GADGET_ID_NONE,
+    GADGET_ID_CHANGE_PLAYER,           GADGET_ID_NONE,
     -1,
-    options_change_sides,
-    &custom_element_change.sides,
-    "... at", NULL,                    "element side that causes change"
+    options_change_trigger_player,
+    &custom_element_change.trigger_player,
+    "player:", " ",                    "player that causes change"
+  },
+  {
+    ED_SETTINGS_XPOS(2),               ED_SETTINGS_YPOS(7),
+    GADGET_ID_CHANGE_PAGE,             GADGET_ID_CHANGE_PLAYER,
+    -1,
+    options_change_trigger_page,
+    &custom_element_change.trigger_page,
+    "page:", NULL,                     "change page that causes change"
   },
   {
     ED_SETTINGS_XPOS(2),               ED_SETTINGS_YPOS(10),
-    GADGET_ID_CHANGE_POWER,            GADGET_ID_NONE,
+    GADGET_ID_CHANGE_REPLACE_WHEN,     GADGET_ID_NONE,
     -1,
-    options_change_power,
-    &custom_element_change.power,
+    options_change_replace_when,
+    &custom_element_change.replace_when,
     "replace when", NULL,              "which elements can be replaced"
   },
   {
@@ -1350,7 +1677,18 @@ static struct
     3,
     options_change_page,
     &custom_element.current_change_page,
-    NULL, NULL,                                "element config page"
+    NULL, NULL,                                "element change page"
+  },
+
+  /* ---------- element settings: configure (group elements) --------------- */
+
+  {
+    ED_SETTINGS_XPOS(0),               ED_SETTINGS_YPOS(6),
+    GADGET_ID_GROUP_CHOICE_MODE,       GADGET_ID_NONE,
+    -1,
+    options_group_choice_mode,
+    &group_element_info.choice_mode,
+    "choice type:", NULL,              "type of group element choice"
   },
 };
 
@@ -1364,6 +1702,38 @@ static struct
   char *text_left, *text_right, *infotext;
 } textbutton_info[ED_NUM_TEXTBUTTONS] =
 {
+#if 1
+  {
+    ED_SETTINGS_XPOS(0),               ED_COUNTER_YPOS(1),
+    GADGET_ID_PROPERTIES_INFO,         GADGET_ID_NONE,
+    8,                                 "Info",                 
+    NULL, NULL,                                "Show information about element"
+  },
+  {
+    ED_SETTINGS_XPOS(0) + 124,         ED_COUNTER_YPOS(1),
+    GADGET_ID_PROPERTIES_CONFIG,       GADGET_ID_NONE,
+    8,                                 "Config",
+    NULL, NULL,                                "Configure element properties"
+  },
+  {
+    ED_SETTINGS_XPOS(0) + 124,         ED_COUNTER_YPOS(1),
+    GADGET_ID_PROPERTIES_CONFIG_1,     GADGET_ID_NONE,
+    8,                                 "Config 1",
+    NULL, NULL,                                "Configure custom element properties"
+  },
+  {
+    ED_SETTINGS_XPOS(0) + 248,         ED_COUNTER_YPOS(1),
+    GADGET_ID_PROPERTIES_CONFIG_2,     GADGET_ID_NONE,
+    8,                                 "Config 2",
+    NULL, NULL,                                "Configure custom element properties"
+  },
+  {
+    ED_SETTINGS_XPOS(0) + 372,         ED_COUNTER_YPOS(1),
+    GADGET_ID_PROPERTIES_CHANGE,       GADGET_ID_NONE,
+    8,                                 "Change",
+    NULL, NULL,                                "Custom element change configuration"
+  },
+#else
   {
     ED_SETTINGS_XPOS(0),               ED_COUNTER_YPOS(1),
     GADGET_ID_PROPERTIES_INFO,         GADGET_ID_NONE,
@@ -1378,27 +1748,28 @@ static struct
   },
   {
     ED_SETTINGS_XPOS(0) + 332,         ED_COUNTER_YPOS(1),
-    GADGET_ID_PROPERTIES_ADVANCED,     GADGET_ID_NONE,
+    GADGET_ID_PROPERTIES_CHANGE,       GADGET_ID_NONE,
     11,                                        "Advanced",
     NULL, NULL,                                "Advanced element configuration"
   },
+#endif
   {
-    -1,                                        ED_SETTINGS_YPOS(13),
+    -1,                                        ED_SETTINGS_YPOS(2),
     GADGET_ID_SAVE_AS_TEMPLATE,                GADGET_ID_CUSTOM_USE_TEMPLATE,
-    -1,                                        "Save as template",
-    " ", NULL,                         "Save current settings as new template"
+    -1,                                        "Save",
+    " ", "As Template",                        "Save current settings as new template"
   },
   {
     -1,                                        ED_SETTINGS_YPOS(14),
-    GADGET_ID_ADD_CHANGE_PAGE,         GADGET_ID_NEXT_CHANGE_PAGE,
+    GADGET_ID_ADD_CHANGE_PAGE,         GADGET_ID_PASTE_CHANGE_PAGE,
     -1,                                        "New",
-    " ", NULL,                         "Add new config page"
+    NULL, NULL,                                "Add new change page"
   },
   {
     -1,                                        ED_SETTINGS_YPOS(14),
     GADGET_ID_DEL_CHANGE_PAGE,         GADGET_ID_ADD_CHANGE_PAGE,
     -1,                                        "Delete",
-    NULL, NULL,                                "Delete current config page"
+    NULL, NULL,                                "Delete current change page"
   },
 };
 
@@ -1417,14 +1788,28 @@ static struct
     ED_SETTINGS_XPOS(0),               ED_SETTINGS_YPOS(14),
     ED_BUTTON_COUNT_XSIZE,             ED_BUTTON_COUNT_YSIZE,
     GADGET_ID_PREV_CHANGE_PAGE,                GADGET_ID_NONE,
-    NULL, NULL,                                "select previous config page"
+    NULL, NULL,                                "select previous change page"
   },
   {
     ED_BUTTON_PLUS_XPOS,               ED_BUTTON_COUNT_YPOS,
     -1,                                        ED_SETTINGS_YPOS(14),
     ED_BUTTON_COUNT_XSIZE,             ED_BUTTON_COUNT_YSIZE,
     GADGET_ID_NEXT_CHANGE_PAGE,                GADGET_ID_SELECT_CHANGE_PAGE,
-    NULL, "config page",               "select next config page"
+    NULL, "change page",               "select next change page"
+  },
+  {
+    ED_COPY_CHANGE_PAGE_XPOS,          ED_COPY_CHANGE_PAGE_YPOS,
+    -1,                                        ED_SETTINGS_YPOS(14),
+    ED_BUTTON_COUNT_XSIZE,             ED_BUTTON_COUNT_YSIZE,
+    GADGET_ID_COPY_CHANGE_PAGE,                GADGET_ID_NEXT_CHANGE_PAGE,
+    " ", NULL,                         "copy settings from this change page"
+  },
+  {
+    ED_PASTE_CHANGE_PAGE_XPOS,         ED_PASTE_CHANGE_PAGE_YPOS,
+    -1,                                        ED_SETTINGS_YPOS(14),
+    ED_BUTTON_COUNT_XSIZE,             ED_BUTTON_COUNT_YSIZE,
+    GADGET_ID_PASTE_CHANGE_PAGE,       GADGET_ID_COPY_CHANGE_PAGE,
+    NULL, NULL,                                "paste settings to this change page"
   },
 };
 
@@ -1571,86 +1956,180 @@ static struct
   /* ---------- element settings: configure (various elements) ------------- */
 
   {
-    ED_SETTINGS_XPOS(0),               0,      /* set at runtime */
+    ED_SETTINGS_XPOS(0),               ED_SETTINGS_YPOS(0),
     GADGET_ID_STICK_ELEMENT,           GADGET_ID_NONE,
     &stick_element_properties_window,
     NULL,
     "stick this screen to edit content","stick this screen to edit content"
   },
   {
-    ED_SETTINGS_XPOS(0),               ED_COUNTER_YPOS(4),
+    ED_SETTINGS_XPOS(0),               ED_SETTINGS_YPOS(1),
     GADGET_ID_EM_SLIPPERY_GEMS,                GADGET_ID_NONE,
     &level.em_slippery_gems,
     NULL,
     "slip down from certain flat walls","use EM style slipping behaviour"
   },
+  {
+    ED_SETTINGS_XPOS(0),               ED_SETTINGS_YPOS(1),
+    GADGET_ID_USE_SPRING_BUG,          GADGET_ID_NONE,
+    &level.use_spring_bug,
+    NULL,
+    "use spring pushing bug",          "use odd spring pushing behaviour"
+  },
+  {
+    ED_SETTINGS_XPOS(0),               ED_SETTINGS_YPOS(0),
+    GADGET_ID_GROW_INTO_DIGGABLE,      GADGET_ID_NONE,
+    &level.grow_into_diggable,
+    NULL,
+    "can grow into anything diggable", "grow into more than just sand"
+  },
+  {
+    ED_SETTINGS_XPOS(0),               ED_SETTINGS_YPOS(1),
+    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_SETTINGS_XPOS(0),               ED_SETTINGS_YPOS(1),
+    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_SETTINGS_XPOS(0),               ED_SETTINGS_YPOS(2),
+    GADGET_ID_INSTANT_RELOCATION,      GADGET_ID_NONE,
+    &level.instant_relocation,
+    NULL,
+    "no scrolling when relocating",    "player gets relocated without delay"
+  },
+  {
+    ED_SETTINGS_XPOS(0),               ED_SETTINGS_YPOS(3),
+    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_SETTINGS_XPOS(0),               ED_SETTINGS_YPOS(0),
+    GADGET_ID_CAN_FALL_INTO_ACID,      GADGET_ID_NONE,
+    &custom_element_properties[EP_CAN_MOVE_INTO_ACID],
+    NULL,
+    "can fall into acid (with gravity)","player can fall into acid pool"
+  },
+  {
+    ED_SETTINGS_XPOS(0),               ED_SETTINGS_YPOS(0),
+    GADGET_ID_CAN_MOVE_INTO_ACID,      GADGET_ID_NONE,
+    &custom_element_properties[EP_CAN_MOVE_INTO_ACID],
+    NULL,
+    "can move into acid",              "element can move into acid pool"
+  },
+  {
+    ED_SETTINGS_XPOS(0),               ED_SETTINGS_YPOS(1),
+    GADGET_ID_DONT_COLLIDE_WITH,       GADGET_ID_NONE,
+    &custom_element_properties[EP_DONT_COLLIDE_WITH],
+    NULL,
+    "deadly when colliding with",      "element is deadly when hitting player"
+  },
 
-  /* ---------- element settings: configure (custom elements) ------------- */
+  /* ---------- element settings: configure 1 (custom elements) ----------- */
 
   {
     ED_SETTINGS_XPOS(0),               ED_SETTINGS_YPOS(1),
+    GADGET_ID_CUSTOM_USE_GRAPHIC,      GADGET_ID_NONE,
+    &custom_element.use_gfx_element,
+#if 0
+    NULL, "use graphic/sound of element:", "use existing graphic and sound"
+#else
+    NULL, "use graphic of element:",   "use existing element graphic"
+#endif
+  },
+  {
+    ED_SETTINGS_XPOS(0),               ED_SETTINGS_YPOS(2),
+    GADGET_ID_CUSTOM_USE_TEMPLATE,     GADGET_ID_NONE,
+    &level.use_custom_template,
+    NULL, "use template",              "use template for custom properties"
+  },
+  {
+    ED_SETTINGS_XPOS(0),               ED_SETTINGS_YPOS(3),
     GADGET_ID_CUSTOM_ACCESSIBLE,       GADGET_ID_NONE,
     &custom_element_properties[EP_ACCESSIBLE],
     NULL, NULL,                                "player can walk to or pass this field"
   },
   {
-    ED_SETTINGS_XPOS(0),               ED_SETTINGS_YPOS(2),
+    ED_SETTINGS_XPOS(0),               ED_SETTINGS_YPOS(10),
+    GADGET_ID_CUSTOM_GRAV_REACHABLE,   GADGET_ID_NONE,
+    &custom_element_properties[EP_GRAVITY_REACHABLE],
+    NULL, "reachable despite gravity", "player can walk/dig despite gravity"
+  },
+  {
+    ED_SETTINGS_XPOS(0),               ED_SETTINGS_YPOS(5),
     GADGET_ID_CUSTOM_WALK_TO_OBJECT,   GADGET_ID_NONE,
     &custom_element_properties[EP_WALK_TO_OBJECT],
     NULL, NULL,                                "player can dig/collect/push element"
   },
   {
-    ED_SETTINGS_XPOS(0),               ED_SETTINGS_YPOS(5),
+    ED_SETTINGS_XPOS(0),               ED_SETTINGS_YPOS(9),
+    GADGET_ID_CUSTOM_INDESTRUCTIBLE,   GADGET_ID_NONE,
+    &custom_element_properties[EP_INDESTRUCTIBLE],
+    NULL, "indestructible",            "element is indestructible"
+  },
+
+  /* ---------- element settings: configure 2 (custom elements) ----------- */
+
+  {
+    ED_SETTINGS_XPOS(0),               ED_SETTINGS_YPOS(1),
     GADGET_ID_CUSTOM_CAN_MOVE,         GADGET_ID_NONE,
     &custom_element_properties[EP_CAN_MOVE],
-    NULL, NULL,                                "element can move in some direction"
+    NULL, NULL,                                "element can move with some pattern"
   },
   {
-    ED_SETTINGS_XPOS(0),               ED_SETTINGS_YPOS(9),
+    ED_SETTINGS_XPOS(0),               ED_SETTINGS_YPOS(7),
     GADGET_ID_CUSTOM_CAN_FALL,         GADGET_ID_NONE,
     &custom_element_properties[EP_CAN_FALL],
     NULL, "can fall",                  "element can fall down"
   },
   {
-    -1,                                        ED_SETTINGS_YPOS(9),
+    -1,                                        ED_SETTINGS_YPOS(7),
     GADGET_ID_CUSTOM_CAN_SMASH,                GADGET_ID_CUSTOM_CAN_FALL,
     &custom_element_properties[EP_CAN_SMASH],
     " ", NULL,                         "element can smash other elements"
   },
   {
-    ED_SETTINGS_XPOS(0),               ED_SETTINGS_YPOS(10),
+    ED_SETTINGS_XPOS(0),               ED_SETTINGS_YPOS(8),
     GADGET_ID_CUSTOM_SLIPPERY,         GADGET_ID_NONE,
     &custom_element_properties[EP_SLIPPERY],
     NULL, NULL,                                "other elements can fall down from it"
   },
   {
-    ED_SETTINGS_XPOS(0),               ED_SETTINGS_YPOS(11),
+    ED_SETTINGS_XPOS(0),               ED_SETTINGS_YPOS(9),
     GADGET_ID_CUSTOM_DEADLY,           GADGET_ID_NONE,
     &custom_element_properties[EP_DEADLY],
     NULL, NULL,                                "element can kill the player"
   },
   {
-    ED_SETTINGS_XPOS(0),               ED_SETTINGS_YPOS(12),
-    GADGET_ID_CUSTOM_EXPLODE_RESULT,   GADGET_ID_NONE,
-    &custom_element_properties[EP_EXPLODE_RESULT],
-    NULL, NULL,                                "set consistency/destructibility"
+    ED_SETTINGS_XPOS(0),               ED_SETTINGS_YPOS(10),
+    GADGET_ID_CUSTOM_CAN_EXPLODE,      GADGET_ID_NONE,
+    &custom_element_properties[EP_CAN_EXPLODE],
+    NULL, NULL,                                "element can explode"
   },
   {
-    ED_SETTINGS_XPOS(1),               ED_SETTINGS_YPOS(13),
+    ED_SETTINGS_XPOS(1),               ED_SETTINGS_YPOS(11),
     GADGET_ID_CUSTOM_EXPLODE_FIRE,     GADGET_ID_NONE,
-    &custom_element.can_explode_by_fire,
+    &custom_element_properties[EP_EXPLODES_BY_FIRE],
     NULL, "by fire",                   "element can explode by fire/explosion"
   },
   {
-    -1,                                        ED_SETTINGS_YPOS(13),
+    -1,                                        ED_SETTINGS_YPOS(11),
     GADGET_ID_CUSTOM_EXPLODE_SMASH,    GADGET_ID_CUSTOM_EXPLODE_FIRE,
-    &custom_element.can_explode_smashed,
+    &custom_element_properties[EP_EXPLODES_SMASHED],
     " ", "smashed",                    "element can explode when smashed"
   },
   {
-    -1,                                        ED_SETTINGS_YPOS(13),
+    -1,                                        ED_SETTINGS_YPOS(11),
     GADGET_ID_CUSTOM_EXPLODE_IMPACT,   GADGET_ID_CUSTOM_EXPLODE_SMASH,
-    &custom_element.can_explode_impact,
+    &custom_element_properties[EP_EXPLODES_IMPACT],
     " ", "impact",                     "element can explode on impact"
   },
 
@@ -1658,30 +2137,24 @@ static struct
 
   {
     ED_SETTINGS_XPOS(0),               ED_SETTINGS_YPOS(1),
-    GADGET_ID_CUSTOM_USE_GRAPHIC,      GADGET_ID_NONE,
-    &custom_element.use_gfx_element,
-    NULL, "use graphic of element:",   "use graphic for custom element"
-  },
-  {
-    ED_SETTINGS_XPOS(0),               ED_SETTINGS_YPOS(2),
     GADGET_ID_CUSTOM_CAN_CHANGE,       GADGET_ID_NONE,
     &custom_element_change.can_change,
     NULL, "element changes to:",       "element can change to other element"
   },
   {
-    ED_SETTINGS_XPOS(1),               ED_SETTINGS_YPOS(3),
+    ED_SETTINGS_XPOS(1),               ED_SETTINGS_YPOS(2),
     GADGET_ID_CHANGE_DELAY,            GADGET_ID_NONE,
     &custom_element_change_events[CE_DELAY],
     NULL, NULL,                                "element changes after delay"
   },
   {
-    ED_SETTINGS_XPOS(1),               ED_SETTINGS_YPOS(5),
+    ED_SETTINGS_XPOS(1),               ED_SETTINGS_YPOS(4),
     GADGET_ID_CHANGE_BY_DIRECT_ACT,    GADGET_ID_NONE,
     &custom_element_change_events[CE_BY_DIRECT_ACTION],
     NULL, NULL,                                "element changes by direct action"
   },
   {
-    ED_SETTINGS_XPOS(1),               ED_SETTINGS_YPOS(6),
+    ED_SETTINGS_XPOS(1),               ED_SETTINGS_YPOS(5),
     GADGET_ID_CHANGE_BY_OTHER_ACT,     GADGET_ID_NONE,
     &custom_element_change_events[CE_BY_OTHER_ACTION],
     NULL, NULL,                                "element changes by other element"
@@ -1695,27 +2168,21 @@ static struct
   {
     ED_SETTINGS_XPOS(1),               ED_SETTINGS_YPOS(9),
     GADGET_ID_CHANGE_USE_CONTENT,      GADGET_ID_NONE,
-    &custom_element_change.use_content,
+    &custom_element_change.use_target_content,
     NULL, "use extended change target:","element changes to more elements"
   },
   {
     ED_SETTINGS_XPOS(2),               ED_SETTINGS_YPOS(11),
     GADGET_ID_CHANGE_ONLY_COMPLETE,    GADGET_ID_NONE,
-    &custom_element_change.only_complete,
+    &custom_element_change.only_if_complete,
     NULL, "replace all or nothing",    "only replace when all can be changed"
   },
   {
     ED_SETTINGS_XPOS(2),               ED_SETTINGS_YPOS(12),
     GADGET_ID_CHANGE_USE_RANDOM,       GADGET_ID_NONE,
-    &custom_element_change.use_random_change,
+    &custom_element_change.use_random_replace,
     NULL, NULL,                                "use percentage for random replace"
   },
-  {
-    ED_SETTINGS_XPOS(0),               ED_SETTINGS_YPOS(13),
-    GADGET_ID_CUSTOM_USE_TEMPLATE,     GADGET_ID_NONE,
-    &level.use_custom_template,
-    NULL, "use template",              "use template for custom properties"
-  },
 };
 
 static struct
@@ -1790,34 +2257,55 @@ static struct
   /* ---------- amoeba content --------------------------------------------- */
 
   {
-    ED_AREA_ELEM_CONTENT_XPOS,         ED_AREA_ELEM_CONTENT_YPOS,
+    ED_AREA_1X1_SETTINGS_XPOS(0),      ED_AREA_1X1_SETTINGS_YPOS(3),
     1, 1,
     GADGET_ID_AMOEBA_CONTENT,          GADGET_ID_NONE,
-    NULL, "content of amoeba",         NULL
+    "content:", NULL,                  NULL
   },
 
+  /* ---------- element settings: configure 1 (custom elements) ----------- */
+
   /* ---------- custom graphic --------------------------------------------- */
 
   {
-    -1,                                        ED_AREA_ELEM_CONTENT3_YPOS,
+    -1,                                        ED_AREA_1X1_SETTINGS_YPOS(1),
     1, 1,
     GADGET_ID_CUSTOM_GRAPHIC,          GADGET_ID_CUSTOM_USE_GRAPHIC,
     NULL, NULL,                                NULL
   },
 
+  /* ---------- element settings: configure 2 (custom elements) ----------- */
+
   /* ---------- custom content (when exploding) ---------------------------- */
 
   {
-    ED_AREA_ELEM_CONTENT4_XPOS,                ED_AREA_ELEM_CONTENT4_YPOS,
+    -1,                                        ED_AREA_3X3_SETTINGS_YPOS(10),
     3, 3,
     GADGET_ID_CUSTOM_CONTENT,          GADGET_ID_NONE, /* align three rows */
     "content:", 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
+  },
+  {
+    -1,                                        ED_AREA_1X1_SETTINGS_YPOS(3),
+    1, 1,
+    GADGET_ID_CUSTOM_MOVE_LEAVE,       GADGET_ID_CUSTOM_MOVE_LEAVE_TYPE,
+    NULL, NULL,                                NULL
+  },
+
+  /* ---------- element settings: advanced (custom elements) --------------- */
+
   /* ---------- custom change target --------------------------------------- */
 
   {
-    -1,                                        ED_AREA_ELEM_CONTENT2_YPOS,
+    -1,                                        ED_AREA_1X1_SETTINGS_YPOS(1),
     1, 1,
     GADGET_ID_CUSTOM_CHANGE_TARGET,    GADGET_ID_CUSTOM_CAN_CHANGE,
     NULL, "after/when:",               NULL
@@ -1826,7 +2314,7 @@ static struct
   /* ---------- custom change content (extended change target) ------------- */
 
   {
-    ED_AREA_ELEM_CONTENT6_XPOS,                ED_AREA_ELEM_CONTENT6_YPOS,
+    -1,                                        ED_AREA_3X3_SETTINGS_YPOS(10),
     3, 3,
     GADGET_ID_CUSTOM_CHANGE_CONTENT,   GADGET_ID_NONE, /* align three rows */
     NULL, NULL,                                NULL
@@ -1835,16 +2323,25 @@ static struct
   /* ---------- custom change trigger (element causing change) ------------- */
 
   {
-    -1,                                        ED_AREA_ELEM_CONTENT5_YPOS,
+    -1,                                        ED_AREA_1X1_SETTINGS_YPOS(5),
     1, 1,
     GADGET_ID_CUSTOM_CHANGE_TRIGGER,   GADGET_ID_CHANGE_OTHER_ACTION,
     NULL, NULL,                                NULL
   },
 
+  /* ---------- 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
+  },
+
   /* ---------- random background (for random painting) -------------------- */
 
   {
-    -1,                                        ED_AREA_RANDOM_BACKGROUND_YPOS,
+    -1,                                        ED_SETTINGS_YPOS(14),
     1, 1,
     GADGET_ID_RANDOM_BACKGROUND,       GADGET_ID_RANDOM_RESTRICTED,
     NULL, NULL,                                NULL
@@ -1880,13 +2377,14 @@ static int new_element3 = EL_SAND;
 static void ModifyEditorCounter(int, int);
 static void ModifyEditorCounterLimits(int, int, int);
 static void ModifyEditorSelectbox(int, int);
+static void ModifyEditorDrawingArea(int, int, int);
 static void ModifyEditorElementList();
 static void RedrawDrawingElements();
 static void DrawDrawingWindow();
 static void DrawLevelInfoWindow();
 static void DrawPropertiesWindow();
 static void UpdateCustomElementGraphicGadgets();
-static boolean checkPropertiesConfig();
+static boolean checkPropertiesConfig(int);
 static void CopyLevelToUndoBuffer(int);
 static void HandleDrawingAreas(struct GadgetInfo *);
 static void HandleCounterButtons(struct GadgetInfo *);
@@ -2146,11 +2644,7 @@ static int editor_el_more[] =
   EL_BD_FIREFLY,
 
   EL_MOLE_LEFT,
-#if 0
-  EL_MAZE_RUNNER,
-#else
   EL_EMPTY,
-#endif
   EL_MOLE_RIGHT,
   EL_PACMAN,
 
@@ -2207,7 +2701,7 @@ static int editor_el_sokoban[] =
   EL_SOKOBAN_OBJECT,
   EL_SOKOBAN_FIELD_EMPTY,
   EL_SOKOBAN_FIELD_FULL,
-  EL_STEELWALL,
+  EL_SOKOBAN_FIELD_PLAYER,
 };
 static int *editor_hl_sokoban_ptr = editor_hl_sokoban;
 static int *editor_el_sokoban_ptr = editor_el_sokoban;
@@ -2899,6 +3393,103 @@ 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_special[] =
+{
+};
+
+static int editor_el_custom_special[] =
+{
+  EL_TRIGGER_ELEMENT,
+  EL_TRIGGER_PLAYER,
+  EL_EMPTY,
+  EL_EMPTY
+};
+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_group[] =
+{
+  EL_CHAR('G'),
+  EL_CHAR('R'),
+  EL_CHAR('O'),
+  EL_CHAR('U'),
+
+  EL_CHAR('P'),
+  EL_CHAR(' '),
+  EL_CHAR(' '),
+  EL_CHAR(' '),
+
+  EL_CHAR('E'),
+  EL_CHAR('L'),
+  EL_CHAR('E'),
+  EL_CHAR('M'),
+
+  EL_CHAR('E'),
+  EL_CHAR('N'),
+  EL_CHAR('T'),
+  EL_CHAR('S'),
+};
+
+static int editor_el_group[] =
+{
+  EL_GROUP_START + 0,
+  EL_GROUP_START + 1,
+  EL_GROUP_START + 2,
+  EL_GROUP_START + 3,
+
+  EL_GROUP_START + 4,
+  EL_GROUP_START + 5,
+  EL_GROUP_START + 6,
+  EL_GROUP_START + 7,
+
+  EL_GROUP_START + 8,
+  EL_GROUP_START + 9,
+  EL_GROUP_START + 10,
+  EL_GROUP_START + 11,
+
+  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);
+
+static int editor_hl_group_more[] =
+{
+};
+
+static int editor_el_group_more[] =
+{
+  EL_GROUP_START + 16,
+  EL_GROUP_START + 17,
+  EL_GROUP_START + 18,
+  EL_GROUP_START + 19,
+
+  EL_GROUP_START + 20,
+  EL_GROUP_START + 21,
+  EL_GROUP_START + 22,
+  EL_GROUP_START + 23,
+
+  EL_GROUP_START + 24,
+  EL_GROUP_START + 25,
+  EL_GROUP_START + 26,
+  EL_GROUP_START + 27,
+
+  EL_GROUP_START + 28,
+  EL_GROUP_START + 29,
+  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_user_defined[] =
 {
   EL_CHAR('U'),
@@ -2999,6 +3590,21 @@ editor_elements_info[] =
     &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.el_custom,
+    &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,
     &editor_hl_user_defined_ptr,       &num_editor_hl_user_defined,
@@ -3016,6 +3622,209 @@ editor_elements_info[] =
   }
 };
 
+#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
+
 
 /*
   -----------------------------------------------------------------------------
@@ -3220,8 +4029,8 @@ static void DrawElementBorder(int dest_x, int dest_y, int width, int height,
     (input ? IMG_EDITOR_ELEMENT_BORDER_INPUT : IMG_EDITOR_ELEMENT_BORDER);
   Bitmap *src_bitmap;
   int src_x, src_y;
-  int num_mini_tilex = width / MINI_TILEX + 1;
-  int num_mini_tiley = width / MINI_TILEY + 1;
+  int num_mini_tilex = width  / MINI_TILEX + 1;
+  int num_mini_tiley = height / MINI_TILEY + 1;
   int x, y;
 
   getMiniGraphicSource(border_graphic, &src_bitmap, &src_x, &src_y);
@@ -3254,6 +4063,12 @@ static void DrawDrawingArea(int id)
        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));
@@ -3262,10 +4077,14 @@ static void DrawDrawingArea(int id)
       for (x = 0; x < 3; x++)
        DrawMiniGraphicExt(drawto,
                           gi->x + x * MINI_TILEX, gi->y + y * MINI_TILEY,
-                          el2edimg(custom_element_change.content[x][y]));
+                          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_ELEMENT_CONTENT_0 &&
           id <= ED_DRAWING_ID_ELEMENT_CONTENT_7)
   {
@@ -3368,7 +4187,7 @@ static void CreateControlButtons()
 
       gd_xoffset = ED_CTRL1_BUTTONS_XPOS + x * ED_CTRL1_BUTTON_XSIZE;
       gd_yoffset = ED_CTRL1_BUTTONS_YPOS + y * ED_CTRL1_BUTTON_YSIZE;
-      width = ED_CTRL1_BUTTON_XSIZE;
+      width  = ED_CTRL1_BUTTON_XSIZE;
       height = ED_CTRL1_BUTTON_YSIZE;
 
       gd_x1 = DOOR_GFX_PAGEX8 + gd_xoffset;
@@ -3383,7 +4202,7 @@ static void CreateControlButtons()
 
       gd_xoffset = ED_CTRL2_BUTTONS_XPOS + x * ED_CTRL2_BUTTON_XSIZE;
       gd_yoffset = ED_CTRL2_BUTTONS_YPOS + y * ED_CTRL2_BUTTON_YSIZE;
-      width = ED_CTRL2_BUTTON_XSIZE;
+      width  = ED_CTRL2_BUTTON_XSIZE;
       height = ED_CTRL2_BUTTON_YSIZE;
 
       gd_x1 = DOOR_GFX_PAGEX8 + gd_xoffset;
@@ -3391,14 +4210,14 @@ static void CreateControlButtons()
       gd_y1 = DOOR_GFX_PAGEY1 + ED_CTRL2_BUTTONS_GFX_YPOS + gd_yoffset;
       gd_y2 = 0;       /* no alternative graphic for these buttons */
     }
-    else
+    else if (id < ED_NUM_CTRL1_3_BUTTONS)
     {
       int x = (i - ED_NUM_CTRL1_2_BUTTONS) % ED_CTRL3_BUTTONS_HORIZ + 1;
       int y = (i - ED_NUM_CTRL1_2_BUTTONS) / ED_CTRL3_BUTTONS_HORIZ;
 
       gd_xoffset = ED_CTRL3_BUTTONS_XPOS + x * ED_CTRL3_BUTTON_XSIZE;
       gd_yoffset = ED_CTRL3_BUTTONS_YPOS + y * ED_CTRL3_BUTTON_YSIZE;
-      width = ED_CTRL3_BUTTON_XSIZE;
+      width  = ED_CTRL3_BUTTON_XSIZE;
       height = ED_CTRL3_BUTTON_YSIZE;
 
       gd_x1 = DOOR_GFX_PAGEX6 + gd_xoffset;
@@ -3406,6 +4225,21 @@ static void CreateControlButtons()
       gd_y1 = DOOR_GFX_PAGEY1 + ED_CTRL3_BUTTONS_GFX_YPOS     + gd_yoffset;
       gd_y2 = DOOR_GFX_PAGEY1 + ED_CTRL3_BUTTONS_ALT_GFX_YPOS + gd_yoffset;
     }
+    else
+    {
+      int x = (i - ED_NUM_CTRL1_3_BUTTONS) % ED_CTRL4_BUTTONS_HORIZ;
+      int y = (i - ED_NUM_CTRL1_3_BUTTONS) / ED_CTRL4_BUTTONS_HORIZ + 3;
+
+      gd_xoffset = ED_CTRL4_BUTTONS_XPOS + x * ED_CTRL4_BUTTON_XSIZE;
+      gd_yoffset = ED_CTRL4_BUTTONS_YPOS + y * ED_CTRL4_BUTTON_YSIZE;
+      width  = ED_CTRL4_BUTTON_XSIZE;
+      height = ED_CTRL4_BUTTON_YSIZE;
+
+      gd_x1 = DOOR_GFX_PAGEX6 + ED_CTRL4_BUTTONS_GFX_XPOS + gd_xoffset;
+      gd_x2 = DOOR_GFX_PAGEX5 + ED_CTRL4_BUTTONS_GFX_XPOS + gd_xoffset;
+      gd_y1 = DOOR_GFX_PAGEY1 + ED_CTRL4_BUTTONS_GFX_YPOS + gd_yoffset;
+      gd_y2 = 0;       /* no alternative graphic for these buttons */
+    }
 
     gi = CreateGadget(GDI_CUSTOM_ID, id,
                      GDI_CUSTOM_TYPE_ID, i,
@@ -3670,7 +4504,7 @@ static void CreateCounterButtons()
                          GDI_NUMBER_VALUE, 0,
                          GDI_NUMBER_MIN, counterbutton_info[i].min_value,
                          GDI_NUMBER_MAX, counterbutton_info[i].max_value,
-                         GDI_TEXT_SIZE, 3,
+                         GDI_TEXT_SIZE, 3,     /* minimal counter text size */
                          GDI_TEXT_FONT, font_type,
                          GDI_TEXT_FONT_ACTIVE, font_type_active,
                          GDI_DESIGN_UNPRESSED, gd_bitmap, gd_x, gd_y,
@@ -3938,7 +4772,7 @@ static void CreateTextbuttonGadgets()
 
     event_mask = GD_EVENT_RELEASED;
 
-    if (id >= GADGET_ID_PROPERTIES_INFO && id <= GADGET_ID_PROPERTIES_ADVANCED)
+    if (id >= GADGET_ID_PROPERTIES_INFO && id <= GADGET_ID_PROPERTIES_CHANGE)
     {
       gd_x1 = DOOR_GFX_PAGEX4 + ED_TEXTBUTTON_TAB_XPOS;
       gd_x2 = DOOR_GFX_PAGEX3 + ED_TEXTBUTTON_TAB_XPOS;
@@ -4012,10 +4846,20 @@ static void CreateGraphicbuttonGadgets()
 
     event_mask = GD_EVENT_PRESSED | GD_EVENT_REPEATED;
 
-    gd_x1 = DOOR_GFX_PAGEX4 + graphicbutton_info[i].gd_x;
-    gd_x2 = DOOR_GFX_PAGEX3 + graphicbutton_info[i].gd_x;
-    gd_y1 = DOOR_GFX_PAGEY1 + graphicbutton_info[i].gd_y;
-    gd_y2 = gd_y1;
+    if (i <= ED_GRAPHICBUTTON_ID_NEXT_CHANGE_PAGE)
+    {
+      gd_x1 = DOOR_GFX_PAGEX4 + graphicbutton_info[i].gd_x;
+      gd_y1 = DOOR_GFX_PAGEY1 + graphicbutton_info[i].gd_y;
+      gd_x2 = DOOR_GFX_PAGEX3 + graphicbutton_info[i].gd_x;
+      gd_y2 = gd_y1;
+    }
+    else       /* (i <= ED_GRAPHICBUTTON_ID_PASTE_CHANGE_PAGE) */
+    {
+      gd_x1 = DOOR_GFX_PAGEX6 + graphicbutton_info[i].gd_x;
+      gd_y1 = DOOR_GFX_PAGEY1 + graphicbutton_info[i].gd_y;
+      gd_x2 = gd_x1 - ED_BUTTON_COUNT_XSIZE;
+      gd_y2 = gd_y1;
+    }
 
     /* determine horizontal position to the right of specified gadget */
     if (graphicbutton_info[i].gadget_id_align != GADGET_ID_NONE)
@@ -4283,8 +5127,10 @@ void FreeLevelEditorGadgets()
 static void MapCounterButtons(int id)
 {
   int gadget_id_down = counterbutton_info[id].gadget_id_down;
+  int gadget_id_text = counterbutton_info[id].gadget_id_text;
   int gadget_id_up   = counterbutton_info[id].gadget_id_up;
   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];
@@ -4302,9 +5148,19 @@ static void MapCounterButtons(int id)
   int x_right = gi_up->x + gi_up->width + xoffset_right;
   int y_above = gi_down->y - yoffset_above;
   int x = gi_down->x;
-  int y = gi_up->y + yoffset;
+  int y;       /* set after gadget position was modified */
 #endif
 
+  /* set position for "score" counter gadget */
+  if (id == ED_COUNTER_ID_ELEMENT_SCORE)
+  {
+    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);
+  }
+
+  y = gi_up->y + yoffset;
+
   if (counterbutton_info[id].text_above)
     DrawText(x, y_above, counterbutton_info[id].text_above, FONT_TEXT_1);
 
@@ -4316,9 +5172,9 @@ static void MapCounterButtons(int id)
 
   ModifyEditorCounter(id, *counterbutton_info[id].value);
 
-  MapGadget(level_editor_gadget[counterbutton_info[id].gadget_id_down]);
-  MapGadget(level_editor_gadget[counterbutton_info[id].gadget_id_text]);
-  MapGadget(level_editor_gadget[counterbutton_info[id].gadget_id_up]);
+  MapGadget(gi_down);
+  MapGadget(gi_text);
+  MapGadget(gi_up);
 }
 
 static void MapControlButtons()
@@ -4503,13 +5359,15 @@ static void MapCheckbuttonGadget(int id)
   int xoffset_left = getTextWidthForGadget(checkbutton_info[id].text_left);
   int xoffset_right = ED_GADGET_TEXT_DISTANCE;
   int yoffset = ED_BORDER_SIZE;
-  int x_left = gi->x - xoffset_left;
-  int x_right = gi->x + gi->width + xoffset_right;
-  int y = gi->y + yoffset;
+  int x_left, x_right, y;      /* set after gadget position was modified */
 
-  /* special case needed for "sticky" gadget */
-  ModifyGadget(gi, GDI_CHECKED, *checkbutton_info[id].value,
-              GDI_Y, SY + checkbutton_info[id].y, GDI_END);
+  /* set position for gadgets with dynamically determined position */
+  if (checkbutton_info[id].x != -1)    /* do not change dynamic positions */
+    ModifyGadget(gi, GDI_X, SX + checkbutton_info[id].x, GDI_END);
+  ModifyGadget(gi, GDI_Y, SY + checkbutton_info[id].y, GDI_END);
+
+  x_left = gi->x - xoffset_left;
+  x_right = gi->x + gi->width + xoffset_right;
   y = gi->y + yoffset;
 
   if (checkbutton_info[id].text_left)
@@ -4518,6 +5376,8 @@ static void MapCheckbuttonGadget(int id)
   if (checkbutton_info[id].text_right)
     DrawText(x_right, y, checkbutton_info[id].text_right, FONT_TEXT_1);
 
+  ModifyGadget(gi, GDI_CHECKED, *checkbutton_info[id].value, GDI_END);
+
   MapGadget(gi);
 }
 
@@ -4560,7 +5420,9 @@ static void MapOrUnmapLevelEditorToolboxCustomGadgets(boolean map)
   {
     if (i == GADGET_ID_CUSTOM_COPY_FROM ||
         i == GADGET_ID_CUSTOM_COPY_TO ||
-        i == GADGET_ID_CUSTOM_EXCHANGE)
+        i == GADGET_ID_CUSTOM_EXCHANGE ||
+        i == GADGET_ID_CUSTOM_COPY ||
+        i == GADGET_ID_CUSTOM_PASTE)
     {
       if (map)
        MapGadget(level_editor_gadget[i]);
@@ -4622,7 +5484,7 @@ static void UnmapLevelEditorToolboxDrawingGadgets()
 
 static void UnmapDrawingArea(int id)
 {
-  UnmapGadget(level_editor_gadget[id]);
+  UnmapGadget(level_editor_gadget[drawingarea_info[id].gadget_id]);
 }
 
 static void UnmapLevelEditorWindowGadgets()
@@ -4716,6 +5578,40 @@ static int setSelectboxValue(int selectbox_id, int new_value)
 
 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;
+
+#else
+
   struct ElementInfo *ei_from = &element_info[element_from];
   struct ElementInfo *ei_to = &element_info[element_to];
   int i, x, y;
@@ -4724,7 +5620,7 @@ static void copy_custom_element_settings(int element_from, int element_to)
   for (i = 0; i < MAX_ELEMENT_NAME_LEN + 1; i++)
     ei_to->description[i] = ei_from->description[i];
 
-  /* ---------- copy element properties ---------- */
+  /* ---------- copy element base properties ---------- */
   Properties[element_to][EP_BITFIELD_BASE] =
     Properties[element_from][EP_BITFIELD_BASE];
 
@@ -4733,11 +5629,15 @@ static void copy_custom_element_settings(int element_from, int element_to)
   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 = ei_from->collect_score;
   ei_to->collect_count = ei_from->collect_count;
 
   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;
 
@@ -4745,49 +5645,35 @@ static void copy_custom_element_settings(int element_from, int element_to)
   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;
 
   for (y = 0; y < 3; y++)
-    for (x = 0; x < 3; x++)
-      ei_to->content[x][y] = ei_from->content[x][y];
-
-  ei_to->num_change_pages = ei_from->num_change_pages;
-  setElementChangePages(ei_to, ei_to->num_change_pages);
-
-  for (i=0; i < ei_to->num_change_pages; i++)
-  {
-    struct ElementChangeInfo *change_to = &ei_to->change_page[i];
-    struct ElementChangeInfo *change_from = &ei_from->change_page[i];
-
-    /* always start with reliable default values */
-    setElementChangeInfoToDefaults(change_to);
-
-    change_to->events = change_from->events;
-
-    change_to->target_element = change_from->target_element;
+    for (x = 0; x < 3; x++)
+      ei_to->content[x][y] = ei_from->content[x][y];
 
-    change_to->delay_fixed = change_from->delay_fixed;
-    change_to->delay_random = change_from->delay_random;
-    change_to->delay_frames = change_from->delay_frames;
+  ei_to->explosion_type = ei_from->explosion_type;
+  ei_to->explosion_delay = ei_from->explosion_delay;
+  ei_to->ignition_delay = ei_from->ignition_delay;
 
-    change_to->trigger_element = change_from->trigger_element;
+  /* ---------- reinitialize and copy change pages ---------- */
 
-    change_to->explode = change_from->explode;
-    change_to->use_content = change_from->use_content;
-    change_to->only_complete = change_from->only_complete;
-    change_to->use_random_change = change_from->use_random_change;
+  ei_to->num_change_pages = ei_from->num_change_pages;
+  ei_to->current_change_page = ei_from->current_change_page;
 
-    change_to->random = change_from->random;
-    change_to->power = change_from->power;
+  setElementChangePages(ei_to, ei_to->num_change_pages);
 
-    for (y = 0; y < 3; y++)
-      for (x = 0; x < 3; x++)
-       change_to->content[x][y] = change_from->content[x][y];
+  for (i=0; i < ei_to->num_change_pages; i++)
+    ei_to->change_page[i] = ei_from->change_page[i];
 
-    change_to->can_change = change_from->can_change;
+  /* ---------- copy group element info ---------- */
+  if (ei_from->group != NULL && ei_to->group != NULL)  /* group or internal */
+    *ei_to->group = *ei_from->group;
 
-    change_to->sides = change_from->sides;
-  }
+#endif
 
   /* mark this custom element as modified */
   ei_to->modified_settings = TRUE;
@@ -4807,7 +5693,7 @@ static void replace_custom_element_in_settings(int element_from,
        if (ei->content[x][y] == element_from)
          ei->content[x][y] = element_to;
 
-    for (j=0; j < ei->num_change_pages; j++)
+    for (j = 0; j < ei->num_change_pages; j++)
     {
       struct ElementChangeInfo *change = &ei->change_page[j];
 
@@ -4819,9 +5705,14 @@ static void replace_custom_element_in_settings(int element_from,
 
       for (y = 0; y < 3; y++)
        for (x = 0; x < 3; x++)
-         if (change->content[x][y] == element_from)
-           change->content[x][y] = element_to;
+         if (change->target_content[x][y] == element_from)
+           change->target_content[x][y] = element_to;
     }
+
+    if (ei->group != NULL)                             /* group or internal */
+      for (j = 0; j < MAX_ELEMENTS_IN_GROUP; j++)
+       if (ei->group->element[j] == element_from)
+         ei->group->element[j] = element_to;
   }
 }
 
@@ -4836,8 +5727,34 @@ static void replace_custom_element_in_playfield(int element_from,
        Feld[x][y] = element_to;
 }
 
-static void CopyCustomElement(int element_old, int element_new, int copy_mode)
+static boolean CopyCustomElement(int element_old, int element_new,
+                                int copy_mode)
 {
+  if (copy_mode == GADGET_ID_CUSTOM_COPY)
+  {
+    element_new = (IS_CUSTOM_ELEMENT(element_old) ?
+                  EL_INTERNAL_CLIPBOARD_CUSTOM : EL_INTERNAL_CLIPBOARD_GROUP);
+    copy_mode = GADGET_ID_CUSTOM_COPY_TO;
+  }
+  else if (copy_mode == GADGET_ID_CUSTOM_PASTE)
+  {
+    element_old = (IS_CUSTOM_ELEMENT(element_new) ?
+                  EL_INTERNAL_CLIPBOARD_CUSTOM : EL_INTERNAL_CLIPBOARD_GROUP);
+    copy_mode = GADGET_ID_CUSTOM_COPY_TO;
+  }
+  else if (IS_CUSTOM_ELEMENT(element_old) && !IS_CUSTOM_ELEMENT(element_new))
+  {
+    Request("Please choose custom element !", REQ_CONFIRM);
+
+    return FALSE;
+  }
+  else if (IS_GROUP_ELEMENT(element_old) && !IS_GROUP_ELEMENT(element_new))
+  {
+    Request("Please choose group element !", REQ_CONFIRM);
+
+    return FALSE;
+  }
+
   if (copy_mode == GADGET_ID_CUSTOM_COPY_FROM)
   {
     copy_custom_element_settings(element_new, element_old);
@@ -4848,21 +5765,23 @@ static void CopyCustomElement(int element_old, int element_new, int copy_mode)
   }
   else if (copy_mode == GADGET_ID_CUSTOM_EXCHANGE)
   {
-    copy_custom_element_settings(element_old, EL_DUMMY);
+    copy_custom_element_settings(element_old, EL_INTERNAL_DUMMY);
     copy_custom_element_settings(element_new, element_old);
-    copy_custom_element_settings(EL_DUMMY, element_new);
+    copy_custom_element_settings(EL_INTERNAL_DUMMY, element_new);
 
-    replace_custom_element_in_settings(element_old, EL_DUMMY);
+    replace_custom_element_in_settings(element_old, EL_INTERNAL_DUMMY);
     replace_custom_element_in_settings(element_new, element_old);
-    replace_custom_element_in_settings(EL_DUMMY, element_new);
+    replace_custom_element_in_settings(EL_INTERNAL_DUMMY, element_new);
 
-    replace_custom_element_in_playfield(element_old, EL_DUMMY);
+    replace_custom_element_in_playfield(element_old, EL_INTERNAL_DUMMY);
     replace_custom_element_in_playfield(element_new, element_old);
-    replace_custom_element_in_playfield(EL_DUMMY, element_new);
+    replace_custom_element_in_playfield(EL_INTERNAL_DUMMY, element_new);
   }
 
   UpdateCustomElementGraphicGadgets();
   DrawPropertiesWindow();
+
+  return TRUE;
 }
 
 static void CopyCustomElementPropertiesToEditor(int element)
@@ -4913,6 +5832,8 @@ static void CopyCustomElementPropertiesToEditor(int element)
      IS_ACCESSIBLE_INSIDE(element) ? EP_ACCESSIBLE_INSIDE :
      IS_ACCESSIBLE_UNDER(element) ? EP_ACCESSIBLE_UNDER :
      custom_element.access_layer);
+  custom_element.access_protected =
+    (IS_PROTECTED(element) ? 1 : 0);
   custom_element_properties[EP_ACCESSIBLE] =
     (IS_ACCESSIBLE_OVER(element) ||
      IS_ACCESSIBLE_INSIDE(element) ||
@@ -4923,12 +5844,14 @@ static void CopyCustomElementPropertiesToEditor(int element)
     (IS_DIGGABLE(element) ? EP_DIGGABLE :
      IS_COLLECTIBLE_ONLY(element) ? EP_COLLECTIBLE_ONLY :
      IS_DROPPABLE(element) ? EP_DROPPABLE :
+     IS_THROWABLE(element) ? EP_THROWABLE :
      IS_PUSHABLE(element) ? EP_PUSHABLE :
      custom_element.walk_to_action);
   custom_element_properties[EP_WALK_TO_OBJECT] =
     (IS_DIGGABLE(element) ||
      IS_COLLECTIBLE_ONLY(element) ||
      IS_DROPPABLE(element) ||
+     IS_THROWABLE(element) ||
      IS_PUSHABLE(element));
 
   /* set smash targets selectbox help value */
@@ -4953,24 +5876,42 @@ static void CopyCustomElementPropertiesToEditor(int element)
      DONT_COLLIDE_WITH(element) ||
      DONT_RUN_INTO(element));
 
-  /* set consistency selectbox help value */
-  custom_element.consistency =
-    (IS_INDESTRUCTIBLE(element) ? EP_INDESTRUCTIBLE :
+#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 :
-     custom_element.consistency);
-  custom_element_properties[EP_EXPLODE_RESULT] =
-    (IS_INDESTRUCTIBLE(element) ||
+     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_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) --------------- */
 
@@ -4983,8 +5924,9 @@ static void CopyCustomElementPropertiesToEditor(int element)
      HAS_CHANGE_EVENT(element, CE_LEFT_BY_PLAYER) ? CE_LEFT_BY_PLAYER :
      HAS_CHANGE_EVENT(element, CE_DROPPED_BY_PLAYER) ? CE_DROPPED_BY_PLAYER :
      HAS_CHANGE_EVENT(element, CE_SWITCHED) ? CE_SWITCHED :
-     HAS_CHANGE_EVENT(element, CE_COLLISION_ACTIVE) ? CE_COLLISION_ACTIVE :
-     HAS_CHANGE_EVENT(element, CE_COLLISION_PASSIVE) ? CE_COLLISION_PASSIVE :
+     HAS_CHANGE_EVENT(element, CE_HITTING_SOMETHING) ? CE_HITTING_SOMETHING :
+     HAS_CHANGE_EVENT(element, CE_HIT_BY_SOMETHING) ? CE_HIT_BY_SOMETHING :
+     HAS_CHANGE_EVENT(element, CE_BLOCKED) ? CE_BLOCKED :
      HAS_CHANGE_EVENT(element, CE_IMPACT) ? CE_IMPACT :
      HAS_CHANGE_EVENT(element, CE_SMASHED) ? CE_SMASHED :
      custom_element_change.direct_action);
@@ -5000,18 +5942,60 @@ static void CopyCustomElementPropertiesToEditor(int element)
      HAS_CHANGE_EVENT(element, CE_OTHER_GETS_COLLECTED) ? CE_OTHER_GETS_COLLECTED :
      HAS_CHANGE_EVENT(element, CE_OTHER_GETS_DROPPED) ? CE_OTHER_GETS_DROPPED :
      HAS_CHANGE_EVENT(element, CE_OTHER_IS_TOUCHING) ? CE_OTHER_IS_TOUCHING :
-     HAS_CHANGE_EVENT(element, CE_OTHER_IS_COLL_ACTIVE) ? CE_OTHER_IS_COLL_ACTIVE :
-     HAS_CHANGE_EVENT(element, CE_OTHER_IS_COLL_PASSIVE) ? CE_OTHER_IS_COLL_PASSIVE :
+     HAS_CHANGE_EVENT(element, CE_OTHER_IS_HITTING) ? CE_OTHER_IS_HITTING :
+     HAS_CHANGE_EVENT(element, CE_OTHER_GETS_HIT) ? CE_OTHER_GETS_HIT :
      HAS_CHANGE_EVENT(element, CE_OTHER_IS_SWITCHING) ? CE_OTHER_IS_SWITCHING :
      HAS_CHANGE_EVENT(element, CE_OTHER_IS_CHANGING) ? CE_OTHER_IS_CHANGING :
      HAS_CHANGE_EVENT(element, CE_OTHER_IS_EXPLODING) ? CE_OTHER_IS_EXPLODING :
      custom_element_change.other_action);
 }
 
+static void CopyGroupElementPropertiesToEditor(int element)
+{
+  group_element_info = *element_info[element].group;
+  custom_element = element_info[element];      /* needed for description */
+}
+
+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);
+
+  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)
+{
+  if (IS_CUSTOM_ELEMENT(element))
+    CopyCustomElementPropertiesToEditor(element);
+  else if (IS_GROUP_ELEMENT(element))
+    CopyGroupElementPropertiesToEditor(element);
+  else
+    CopyClassicElementPropertiesToEditor(element);
+}
+
 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;
@@ -5049,11 +6033,15 @@ static void CopyCustomElementPropertiesToGame(int element)
                           (custom_element.access_layer - EP_ACCESSIBLE_OVER));
   custom_element_properties[access_type_and_layer] =
     custom_element_properties[EP_ACCESSIBLE];
+  custom_element_properties[EP_PROTECTED] =
+    (custom_element.access_protected != 0 &&
+     custom_element_properties[EP_ACCESSIBLE]);
 
   /* set walk-to-object property from checkbox and selectbox */
   custom_element_properties[EP_DIGGABLE] = FALSE;
   custom_element_properties[EP_COLLECTIBLE_ONLY] = FALSE;
   custom_element_properties[EP_DROPPABLE] = FALSE;
+  custom_element_properties[EP_THROWABLE] = FALSE;
   custom_element_properties[EP_PUSHABLE] = FALSE;
   custom_element_properties[custom_element.walk_to_action] =
     custom_element_properties[EP_WALK_TO_OBJECT];
@@ -5072,19 +6060,37 @@ static void CopyCustomElementPropertiesToGame(int element)
   custom_element_properties[custom_element.deadliness] =
     custom_element_properties[EP_DEADLY];
 
-  /* set consistency property from checkbox and selectbox */
+#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.consistency] =
-    custom_element_properties[EP_EXPLODE_RESULT];
+  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 (custom_element_properties[EP_CAN_EXPLODE_3X3] ||
-      custom_element_properties[EP_CAN_EXPLODE_1X1])
+#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;
@@ -5093,6 +6099,8 @@ static void CopyCustomElementPropertiesToGame(int element)
     custom_element_properties[EP_CAN_EXPLODE_IMPACT] =
       custom_element.can_explode_impact;
   }
+#endif
+#endif
 
   /* ---------- element settings: advanced (custom elements) --------------- */
 
@@ -5104,8 +6112,9 @@ static void CopyCustomElementPropertiesToGame(int element)
   custom_element_change_events[CE_LEFT_BY_PLAYER] = FALSE;
   custom_element_change_events[CE_DROPPED_BY_PLAYER] = FALSE;
   custom_element_change_events[CE_SWITCHED] = FALSE;
-  custom_element_change_events[CE_COLLISION_ACTIVE] = FALSE;
-  custom_element_change_events[CE_COLLISION_PASSIVE] = FALSE;
+  custom_element_change_events[CE_HITTING_SOMETHING] = FALSE;
+  custom_element_change_events[CE_HIT_BY_SOMETHING] = FALSE;
+  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[custom_element_change.direct_action] =
@@ -5121,8 +6130,8 @@ static void CopyCustomElementPropertiesToGame(int element)
   custom_element_change_events[CE_OTHER_GETS_COLLECTED] = FALSE;
   custom_element_change_events[CE_OTHER_GETS_DROPPED] = FALSE;
   custom_element_change_events[CE_OTHER_IS_TOUCHING] = FALSE;
-  custom_element_change_events[CE_OTHER_IS_COLL_ACTIVE] = FALSE;
-  custom_element_change_events[CE_OTHER_IS_COLL_PASSIVE] = FALSE;
+  custom_element_change_events[CE_OTHER_IS_HITTING] = FALSE;
+  custom_element_change_events[CE_OTHER_GETS_HIT] = FALSE;
   custom_element_change_events[CE_OTHER_IS_SWITCHING] = FALSE;
   custom_element_change_events[CE_OTHER_IS_CHANGING] = FALSE;
   custom_element_change_events[CE_OTHER_IS_EXPLODING] = FALSE;
@@ -5140,6 +6149,52 @@ static void CopyCustomElementPropertiesToGame(int element)
   custom_element_change = *element_info[element].change;
 }
 
+static void CopyGroupElementPropertiesToGame(int element)
+{
+  element_info[element] = custom_element;
+  *element_info[element].group = group_element_info;
+
+  /* mark that this group element has been modified */
+  element_info[element].modified_settings = TRUE;
+}
+
+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]);
+
+  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)
+{
+  if (IS_CUSTOM_ELEMENT(element))
+    CopyCustomElementPropertiesToGame(element);
+  else if (IS_GROUP_ELEMENT(element))
+    CopyGroupElementPropertiesToGame(element);
+  else
+    CopyClassicElementPropertiesToGame(element);
+}
+
 void DrawLevelEd()
 {
   CloseDoor(DOOR_CLOSE_ALL);
@@ -5181,7 +6236,7 @@ void DrawLevelEd()
 
   redraw_mask |= REDRAW_ALL;
 
-  ReinitializeElementListButtons();    /* only needed after setup changes */
+  ReinitializeElementListButtons();    /* custom element may look different */
 #if 0
   ModifyEditorElementList();           /* may be needed for custom elements */
 #endif
@@ -5331,6 +6386,14 @@ static void ModifyEditorSelectbox(int selectbox_id, int new_value)
   ModifyGadget(gi, GDI_SELECTBOX_INDEX, new_index_value, 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];
+
+  ModifyGadget(gi, GDI_AREA_SIZE, xsize, ysize, GDI_END);
+}
+
 static void ModifyEditorElementList()
 {
   int i;
@@ -5426,6 +6489,10 @@ static void DrawLevelInfoWindow()
   for (i = ED_COUNTER_ID_LEVEL_FIRST; i <= ED_COUNTER_ID_LEVEL_LAST; i++)
     MapCounterButtons(i);
 
+  /* draw selectbox gadgets */
+  for (i = ED_SELECTBOX_ID_LEVEL_FIRST; i <= ED_SELECTBOX_ID_LEVEL_LAST; i++)
+    MapSelectboxGadget(i);
+
   /* draw checkbutton gadgets */
   for (i=ED_CHECKBUTTON_ID_LEVEL_FIRST; i <= ED_CHECKBUTTON_ID_LEVEL_LAST; i++)
     MapCheckbuttonGadget(i);
@@ -5447,7 +6514,7 @@ static void DrawCustomContentArea()
   int id = ED_DRAWING_ID_CUSTOM_CONTENT;
   struct GadgetInfo *gi = level_editor_gadget[drawingarea_info[id].gadget_id];
   int x1 = right_gadget_border[GADGET_ID_CUSTOM_DEADLINESS];
-  int x2 = right_gadget_border[GADGET_ID_CUSTOM_CONSISTENCY];
+  int x2 = right_gadget_border[GADGET_ID_CUSTOM_EXPLOSION_TYPE];
   int x3 = right_gadget_border[GADGET_ID_CUSTOM_EXPLODE_IMPACT];
   int xoffset = ED_DRAWINGAREA_TEXT_DISTANCE;
 
@@ -5464,7 +6531,7 @@ static void DrawCustomChangeContentArea()
   int id = ED_DRAWING_ID_CUSTOM_CHANGE_CONTENT;
   struct GadgetInfo *gi = level_editor_gadget[drawingarea_info[id].gadget_id];
   int x1 = right_gadget_border[GADGET_ID_CHANGE_USE_CONTENT];
-  int x2 = right_gadget_border[GADGET_ID_CHANGE_POWER];
+  int x2 = right_gadget_border[GADGET_ID_CHANGE_REPLACE_WHEN];
   int x3 = right_gadget_border[GADGET_ID_CHANGE_ONLY_COMPLETE];
   int xoffset = ED_DRAWINGAREA_TEXT_DISTANCE;
 
@@ -5497,7 +6564,7 @@ static void DrawElementContentAreas()
       DrawBackground(SX + drawingarea_info[id].x - MINI_TILEX / 2,
                     SY + drawingarea_info[id].y - MINI_TILEY / 2,
                     4 * MINI_TILEX,
-                    4 * MINI_TILEX + ED_GADGET_TEXT_DISTANCE + font_height);
+                    4 * MINI_TILEY + ED_GADGET_TEXT_DISTANCE + font_height);
     }
   }
 
@@ -5506,6 +6573,28 @@ static void DrawElementContentAreas()
   DrawText(x, y + 2 * MINI_TILEY, "smashed", FONT_TEXT_1);
 }
 
+static void DrawGroupElementArea(int element)
+{
+  int num_elements = group_element_info.num_elements;
+  int id = ED_DRAWING_ID_GROUP_CONTENT;
+  int sx = SX + drawingarea_info[id].x - MINI_TILEX / 2;
+  int sy = SY + drawingarea_info[id].y - MINI_TILEY / 2;
+  int xsize = MAX_ELEMENTS_IN_GROUP;
+  int ysize = 1;
+
+  if (drawingarea_info[id].text_left != NULL)
+    sx += getTextWidthForDrawingArea(drawingarea_info[id].text_left);
+
+  UnmapDrawingArea(id);
+
+  ModifyEditorDrawingArea(id, num_elements, 1);
+
+  /* delete content areas in case of reducing number of them */
+  DrawBackground(sx, sy, (xsize + 1) * MINI_TILEX, (ysize + 1) * MINI_TILEY);
+
+  MapDrawingArea(id);
+}
+
 static void DrawEnvelopeTextArea(int envelope_nr)
 {
   int id = ED_TEXTAREA_ID_ENVELOPE_INFO;
@@ -5686,11 +6775,12 @@ static void DrawPropertiesTabulatorGadgets()
   Pixel tab_color = GetPixel(gd->bitmap, gd_x, gd_y);
   int id_first = ED_TEXTBUTTON_ID_PROPERTIES_INFO;
   int id_last  = ED_TEXTBUTTON_ID_PROPERTIES_CONFIG;
+  int max_tabs = 4;
   int i;
 
   /* draw additional "advanced" tabulator for custom elements */
   if (IS_CUSTOM_ELEMENT(properties_element))
-    id_last = ED_TEXTBUTTON_ID_PROPERTIES_ADVANCED;
+    id_last = ED_TEXTBUTTON_ID_PROPERTIES_CHANGE;
 
   for (i = id_first; i <= id_last; i++)
   {
@@ -5698,6 +6788,11 @@ static void DrawPropertiesTabulatorGadgets()
     struct GadgetInfo *gi = level_editor_gadget[gadget_id];
     boolean active = (i != edit_mode_properties);
 
+    /* use "config 1" and "config 2" instead of "config" */
+    if (i == ED_TEXTBUTTON_ID_PROPERTIES_CONFIG &&
+       IS_CUSTOM_ELEMENT(properties_element))
+      continue;
+
     /* draw background line below tabulator button */
     ClearRectangleOnBackground(drawto, gi->x, gi->y + gi->height, gi->width,1);
 
@@ -5712,7 +6807,7 @@ static void DrawPropertiesTabulatorGadgets()
   /* draw little border line below tabulator buttons */
   if (tab_color != BLACK_PIXEL)                        /* black => transparent */
     FillRectangle(drawto, gd_gi->x, gd_gi->y + gd_gi->height + 1,
-                 3 * gd_gi->width + 2 * ED_GADGET_DISTANCE,
+                 max_tabs * gd_gi->width + (max_tabs -1) * ED_GADGET_DISTANCE,
                  ED_GADGET_DISTANCE, tab_color);
 }
 
@@ -5733,14 +6828,16 @@ static void DrawPropertiesInfo()
     { EP_PASSABLE_OVER,                "- player can pass over it"             },
     { EP_PASSABLE_INSIDE,      "- player can pass through it"          },
     { EP_PASSABLE_UNDER,       "- player can pass under it"            },
+    { EP_PROTECTED,            "- player is protected by it"           },
 
     { EP_DIGGABLE,             "- can be digged away"                  },
     { EP_COLLECTIBLE,          "- can be collected"                    },
     { EP_DROPPABLE,            "- can be dropped after collecting"     },
+    { EP_THROWABLE,            "- can be thrown after collecting"      },
     { EP_PUSHABLE,             "- can be pushed"                       },
 
-    { EP_CAN_MOVE,             "- can move"                            },
     { EP_CAN_FALL,             "- can fall"                            },
+    { EP_CAN_MOVE,             "- can move"                            },
 
     { EP_CAN_SMASH_PLAYER,     "- can smash player"                    },
 #if 0
@@ -5748,7 +6845,7 @@ static void DrawPropertiesInfo()
 #endif
     { EP_CAN_SMASH_EVERYTHING, "- can smash everything smashable"      },
 
-    { EP_SLIPPERY,             "- slippery for falling objects"        },
+    { EP_SLIPPERY,             "- slippery for falling elements"       },
     { EP_EM_SLIPPERY_WALL,     "- slippery for some gems (EM style)"   },
 
     { EP_DONT_RUN_INTO,                "- deadly when running into"            },
@@ -5765,6 +6862,7 @@ 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"          },
 
     { -1,                      NULL                                    }
@@ -5791,6 +6889,12 @@ static void DrawPropertiesInfo()
              "[Custom Element %d]", properties_element - EL_CUSTOM_START + 1);
     screen_line++;
   }
+  else if (IS_GROUP_ELEMENT(properties_element))
+  {
+    DrawTextF(pad_x, pad_y + screen_line++ * font2_height, FONT_TEXT_3,
+             "[Group Element %d]", properties_element - EL_GROUP_START + 1);
+    screen_line++;
+  }
 #endif
 
   /* ----- print number of elements / percentage of this element in level */
@@ -5860,19 +6964,23 @@ static struct
   { EL_DIAMOND,                &level.score[SC_DIAMOND],       TEXT_COLLECTING },
   { EL_CRYSTAL,                &level.score[SC_CRYSTAL],       TEXT_COLLECTING },
   { EL_PEARL,          &level.score[SC_PEARL],         TEXT_COLLECTING },
+  { EL_BUG,            &level.score[SC_BUG],           TEXT_SMASHING   },
   { EL_BUG_RIGHT,      &level.score[SC_BUG],           TEXT_SMASHING   },
   { EL_BUG_UP,         &level.score[SC_BUG],           TEXT_SMASHING   },
   { EL_BUG_LEFT,       &level.score[SC_BUG],           TEXT_SMASHING   },
   { EL_BUG_DOWN,       &level.score[SC_BUG],           TEXT_SMASHING   },
+  { EL_BD_BUTTERFLY,   &level.score[SC_BUG],           TEXT_SMASHING   },
   { EL_BD_BUTTERFLY_RIGHT,&level.score[SC_BUG],                TEXT_SMASHING   },
   { EL_BD_BUTTERFLY_UP,   &level.score[SC_BUG],                TEXT_SMASHING   },
   { EL_BD_BUTTERFLY_LEFT, &level.score[SC_BUG],                TEXT_SMASHING   },
   { EL_BD_BUTTERFLY_DOWN, &level.score[SC_BUG],                TEXT_SMASHING   },
   { EL_SP_ELECTRON,    &level.score[SC_BUG],           TEXT_SMASHING   },
+  { EL_SPACESHIP,      &level.score[SC_SPACESHIP],     TEXT_SMASHING   },
   { EL_SPACESHIP_RIGHT,        &level.score[SC_SPACESHIP],     TEXT_SMASHING   },
   { EL_SPACESHIP_UP,   &level.score[SC_SPACESHIP],     TEXT_SMASHING   },
   { EL_SPACESHIP_LEFT, &level.score[SC_SPACESHIP],     TEXT_SMASHING   },
   { EL_SPACESHIP_DOWN, &level.score[SC_SPACESHIP],     TEXT_SMASHING   },
+  { EL_BD_FIREFLY,     &level.score[SC_SPACESHIP],     TEXT_SMASHING   },
   { EL_BD_FIREFLY_RIGHT,&level.score[SC_SPACESHIP],    TEXT_SMASHING   },
   { EL_BD_FIREFLY_UP,  &level.score[SC_SPACESHIP],     TEXT_SMASHING   },
   { EL_BD_FIREFLY_LEFT, &level.score[SC_SPACESHIP],    TEXT_SMASHING   },
@@ -5881,6 +6989,7 @@ static struct
   { EL_YAMYAM,         &level.score[SC_YAMYAM],        TEXT_SMASHING   },
   { EL_DARK_YAMYAM,    &level.score[SC_YAMYAM],        TEXT_SMASHING   },
   { EL_ROBOT,          &level.score[SC_ROBOT],         TEXT_SMASHING   },
+  { EL_PACMAN,         &level.score[SC_PACMAN],        TEXT_SMASHING   },
   { EL_PACMAN_RIGHT,   &level.score[SC_PACMAN],        TEXT_SMASHING   },
   { EL_PACMAN_UP,      &level.score[SC_PACMAN],        TEXT_SMASHING   },
   { EL_PACMAN_LEFT,    &level.score[SC_PACMAN],        TEXT_SMASHING   },
@@ -5917,18 +7026,23 @@ static struct
   { -1,                        NULL,                           NULL            }
 };
 
-static boolean checkPropertiesConfig()
+static boolean checkPropertiesConfig(int element)
 {
   int i;
 
-  if (IS_GEM(properties_element) ||
-      IS_CUSTOM_ELEMENT(properties_element) ||
-      IS_ENVELOPE(properties_element) ||
-      HAS_CONTENT(properties_element))
+  if (IS_GEM(element) ||
+      IS_CUSTOM_ELEMENT(element) ||
+      IS_GROUP_ELEMENT(element) ||
+      IS_ENVELOPE(element) ||
+      ELEM_IS_PLAYER(element) ||
+      HAS_CONTENT(element) ||
+      CAN_GROW(element) ||
+      COULD_MOVE_INTO_ACID(element) ||
+      MAYBE_DONT_COLLIDE_WITH(element))
     return TRUE;
   else
     for (i = 0; elements_with_counter[i].element != -1; i++)
-      if (elements_with_counter[i].element == properties_element)
+      if (elements_with_counter[i].element == element)
        return TRUE;
 
   return FALSE;
@@ -5938,7 +7052,7 @@ static void DrawPropertiesConfig()
 {
   int i;
 
-  if (!checkPropertiesConfig())
+  if (!checkPropertiesConfig(properties_element))
   {
     PrintInfoText("No configuration options available.", FONT_TEXT_1, 0);
 
@@ -5952,8 +7066,15 @@ static void DrawPropertiesConfig()
     {
       int counter_id = ED_COUNTER_ID_ELEMENT_SCORE;
 
+      counterbutton_info[counter_id].y =
+       ED_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));
+
       counterbutton_info[counter_id].value = elements_with_counter[i].value;
       counterbutton_info[counter_id].text_right= elements_with_counter[i].text;
+
       MapCounterButtons(counter_id);
 
       break;
@@ -5963,9 +7084,7 @@ static void DrawPropertiesConfig()
   if (HAS_CONTENT(properties_element))
   {
     /* draw stickybutton gadget */
-    i = ED_CHECKBUTTON_ID_STICK_ELEMENT;
-    checkbutton_info[i].y = ED_COUNTER_YPOS(4);
-    MapCheckbuttonGadget(i);
+    MapCheckbuttonGadget(ED_CHECKBUTTON_ID_STICK_ELEMENT);
 
     if (IS_AMOEBOID(properties_element))
       MapDrawingArea(ED_DRAWING_ID_AMOEBA_CONTENT);
@@ -5973,9 +7092,48 @@ static void DrawPropertiesConfig()
       DrawElementContentAreas();
   }
 
+  if (ELEM_IS_PLAYER(properties_element))
+  {
+    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_INSTANT_RELOCATION);
+    MapCheckbuttonGadget(ED_CHECKBUTTON_ID_CAN_PASS_TO_WALKABLE);
+  }
+
   if (IS_GEM(properties_element))
     MapCheckbuttonGadget(ED_CHECKBUTTON_ID_EM_SLIPPERY_GEMS);
 
+  if (COULD_MOVE_INTO_ACID(properties_element) &&
+      !ELEM_IS_PLAYER(properties_element) &&
+      (!IS_CUSTOM_ELEMENT(properties_element) ||
+       edit_mode_properties == ED_MODE_PROPERTIES_CONFIG_2))
+  {
+    /* set position for checkbutton for "can move into acid" */
+    checkbutton_info[ED_CHECKBUTTON_ID_CAN_MOVE_INTO_ACID].x =
+      ED_SETTINGS_XPOS(IS_CUSTOM_ELEMENT(properties_element) ? 1 : 0);
+    checkbutton_info[ED_CHECKBUTTON_ID_CAN_MOVE_INTO_ACID].y =
+      ED_SETTINGS_YPOS(IS_CUSTOM_ELEMENT(properties_element) ? 6 :
+                      HAS_CONTENT(properties_element) ? 1 : 0);
+
+    MapCheckbuttonGadget(ED_CHECKBUTTON_ID_CAN_MOVE_INTO_ACID);
+  }
+
+  if (MAYBE_DONT_COLLIDE_WITH(properties_element))
+    MapCheckbuttonGadget(ED_CHECKBUTTON_ID_DONT_COLLIDE_WITH);
+
+  if (properties_element == EL_SPRING)
+    MapCheckbuttonGadget(ED_CHECKBUTTON_ID_USE_SPRING_BUG);
+
+  if (CAN_GROW(properties_element))
+  {
+    checkbutton_info[ED_CHECKBUTTON_ID_GROW_INTO_DIGGABLE].y =
+      ED_SETTINGS_YPOS(HAS_CONTENT(properties_element) ? 1 : 0);
+
+    MapCheckbuttonGadget(ED_CHECKBUTTON_ID_GROW_INTO_DIGGABLE);
+  }
+
   if (IS_ENVELOPE(properties_element))
   {
     int counter1_id = ED_COUNTER_ID_ENVELOPE_XSIZE;
@@ -5995,50 +7153,105 @@ static void DrawPropertiesConfig()
   if (IS_CUSTOM_ELEMENT(properties_element))
   {
     /* draw stickybutton gadget */
-    i = ED_CHECKBUTTON_ID_STICK_ELEMENT;
-    checkbutton_info[i].y = ED_SETTINGS_YPOS(0);
-    MapCheckbuttonGadget(i);
+    MapCheckbuttonGadget(ED_CHECKBUTTON_ID_STICK_ELEMENT);
+
+    if (edit_mode_properties == ED_MODE_PROPERTIES_CONFIG_1)
+    {
+      /* draw checkbutton gadgets */
+      for (i =  ED_CHECKBUTTON_ID_CUSTOM1_FIRST;
+          i <= ED_CHECKBUTTON_ID_CUSTOM1_LAST; i++)
+       MapCheckbuttonGadget(i);
+
+      /* draw counter gadgets */
+      for (i =  ED_COUNTER_ID_CUSTOM1_FIRST;
+          i <= ED_COUNTER_ID_CUSTOM1_LAST; i++)
+       MapCounterButtons(i);
+
+      /* draw selectbox gadgets */
+      for (i =  ED_SELECTBOX_ID_CUSTOM1_FIRST;
+          i <= ED_SELECTBOX_ID_CUSTOM1_LAST; i++)
+       MapSelectboxGadget(i);
+
+      /* draw textbutton gadgets */
+      MapTextbuttonGadget(ED_TEXTBUTTON_ID_SAVE_AS_TEMPLATE);
+
+      /* draw text input gadgets */
+      MapTextInputGadget(ED_TEXTINPUT_ID_ELEMENT_NAME);
+
+      /* draw drawing area gadgets */
+      MapDrawingArea(ED_DRAWING_ID_CUSTOM_GRAPHIC);
+    }
+    else if (edit_mode_properties == ED_MODE_PROPERTIES_CONFIG_2)
+    {
+      /* draw checkbutton gadgets */
+      for (i =  ED_CHECKBUTTON_ID_CUSTOM2_FIRST;
+          i <= ED_CHECKBUTTON_ID_CUSTOM2_LAST; i++)
+       MapCheckbuttonGadget(i);
+
+      /* draw counter gadgets */
+      for (i =  ED_COUNTER_ID_CUSTOM2_FIRST;
+          i <= ED_COUNTER_ID_CUSTOM2_LAST; i++)
+       MapCounterButtons(i);
+
+      /* draw selectbox gadgets */
+      for (i =  ED_SELECTBOX_ID_CUSTOM2_FIRST;
+          i <= ED_SELECTBOX_ID_CUSTOM2_LAST; i++)
+       MapSelectboxGadget(i);
+
+      /* draw drawing area gadgets */
+      MapDrawingArea(ED_DRAWING_ID_CUSTOM_MOVE_ENTER);
+      MapDrawingArea(ED_DRAWING_ID_CUSTOM_MOVE_LEAVE);
+      DrawCustomContentArea();
+    }
+  }
+  else if (IS_GROUP_ELEMENT(properties_element))
+  {
+    /* draw stickybutton gadget */
+    MapCheckbuttonGadget(ED_CHECKBUTTON_ID_STICK_ELEMENT);
 
     /* draw checkbutton gadgets */
-    for (i =  ED_CHECKBUTTON_ID_CUSTOM_FIRST;
-        i <= ED_CHECKBUTTON_ID_CUSTOM_LAST; i++)
-      MapCheckbuttonGadget(i);
+    MapCheckbuttonGadget(ED_CHECKBUTTON_ID_CUSTOM_USE_GRAPHIC);
+    MapCheckbuttonGadget(ED_CHECKBUTTON_ID_CUSTOM_USE_TEMPLATE);
 
     /* draw counter gadgets */
-    for (i = ED_COUNTER_ID_CUSTOM_FIRST; i <= ED_COUNTER_ID_CUSTOM_LAST; i++)
-      MapCounterButtons(i);
+    MapCounterButtons(ED_COUNTER_ID_GROUP_CONTENT);
 
     /* draw selectbox gadgets */
-    for (i=ED_SELECTBOX_ID_CUSTOM_FIRST; i <= ED_SELECTBOX_ID_CUSTOM_LAST; i++)
-      MapSelectboxGadget(i);
+    MapSelectboxGadget(ED_SELECTBOX_ID_GROUP_CHOICE_MODE);
+
+    /* draw textbutton gadgets */
+    MapTextbuttonGadget(ED_TEXTBUTTON_ID_SAVE_AS_TEMPLATE);
 
     /* draw drawing area gadgets */
-    DrawCustomContentArea();
+    DrawGroupElementArea(properties_element);
 
     /* draw text input gadgets */
     MapTextInputGadget(ED_TEXTINPUT_ID_ELEMENT_NAME);
+
+    /* draw drawing area gadgets */
+    MapDrawingArea(ED_DRAWING_ID_CUSTOM_GRAPHIC);
   }
 }
 
-static void DrawPropertiesAdvancedDrawingAreas()
+static void DrawPropertiesChangeDrawingAreas()
 {
-  MapDrawingArea(ED_DRAWING_ID_CUSTOM_GRAPHIC);
-  MapDrawingArea(ED_DRAWING_ID_CUSTOM_CHANGE_TARGET);
-  MapDrawingArea(ED_DRAWING_ID_CUSTOM_CHANGE_TRIGGER);
+  if (IS_CUSTOM_ELEMENT(properties_element))
+  {
+    MapDrawingArea(ED_DRAWING_ID_CUSTOM_CHANGE_TARGET);
+    MapDrawingArea(ED_DRAWING_ID_CUSTOM_CHANGE_TRIGGER);
 
-  DrawCustomChangeContentArea();
+    DrawCustomChangeContentArea();
+  }
 
   redraw_mask |= REDRAW_FIELD;
 }
 
-static void DrawPropertiesAdvanced()
+static void DrawPropertiesChange()
 {
   int i;
 
   /* draw stickybutton gadget */
-  i = ED_CHECKBUTTON_ID_STICK_ELEMENT;
-  checkbutton_info[i].y = ED_SETTINGS_YPOS(0);
-  MapCheckbuttonGadget(i);
+  MapCheckbuttonGadget(ED_CHECKBUTTON_ID_STICK_ELEMENT);
 
   /* draw checkbutton gadgets */
   for (i =  ED_CHECKBUTTON_ID_CHANGE_FIRST;
@@ -6046,15 +7259,18 @@ static void DrawPropertiesAdvanced()
     MapCheckbuttonGadget(i);
 
   /* draw counter gadgets */
-  for (i = ED_COUNTER_ID_CHANGE_FIRST; i <= ED_COUNTER_ID_CHANGE_LAST; i++)
+  for (i =  ED_COUNTER_ID_CHANGE_FIRST;
+       i <= ED_COUNTER_ID_CHANGE_LAST; i++)
     MapCounterButtons(i);
 
   /* draw selectbox gadgets */
-  for (i = ED_SELECTBOX_ID_CHANGE_FIRST; i <= ED_SELECTBOX_ID_CHANGE_LAST; i++)
+  for (i =  ED_SELECTBOX_ID_CHANGE_FIRST;
+       i <= ED_SELECTBOX_ID_CHANGE_LAST; i++)
     MapSelectboxGadget(i);
 
   /* draw textbutton gadgets */
-  for (i=ED_TEXTBUTTON_ID_CHANGE_FIRST; i <= ED_TEXTBUTTON_ID_CHANGE_LAST; i++)
+  for (i =  ED_TEXTBUTTON_ID_CHANGE_FIRST;
+       i <= ED_TEXTBUTTON_ID_CHANGE_LAST; i++)
     MapTextbuttonGadget(i);
 
   /* draw graphicbutton gadgets */
@@ -6063,7 +7279,7 @@ static void DrawPropertiesAdvanced()
     MapGraphicbuttonGadget(i);
 
   /* draw drawing area gadgets */
-  DrawPropertiesAdvancedDrawingAreas();
+  DrawPropertiesChangeDrawingAreas();
 }
 
 static void DrawElementName(int x, int y, int element)
@@ -6119,18 +7335,22 @@ static void DrawPropertiesWindow()
   stick_element_properties_window = FALSE;
 
   /* make sure that previous properties edit mode exists for this element */
-  if (edit_mode_properties == ED_MODE_PROPERTIES_ADVANCED &&
+  if (edit_mode_properties > ED_MODE_PROPERTIES_CONFIG &&
       !IS_CUSTOM_ELEMENT(properties_element))
     edit_mode_properties = ED_MODE_PROPERTIES_CONFIG;
 
-  if (IS_CUSTOM_ELEMENT(properties_element))
-    CopyCustomElementPropertiesToEditor(properties_element);
+  if (edit_mode_properties == ED_MODE_PROPERTIES_CONFIG &&
+      IS_CUSTOM_ELEMENT(properties_element))
+    edit_mode_properties = ED_MODE_PROPERTIES_CONFIG_1;
+
+  CopyElementPropertiesToEditor(properties_element);
 
   UnmapLevelEditorWindowGadgets();
   UnmapLevelEditorToolboxDrawingGadgets();
   UnmapLevelEditorToolboxCustomGadgets();
 
-  if (IS_CUSTOM_ELEMENT(properties_element))
+  if (IS_CUSTOM_ELEMENT(properties_element) ||
+      IS_GROUP_ELEMENT(properties_element))
     MapLevelEditorToolboxCustomGadgets();
 
   SetMainBackgroundImage(IMG_BACKGROUND_EDITOR);
@@ -6149,27 +7369,34 @@ static void DrawPropertiesWindow()
 
   FrameCounter = 0;    /* restart animation frame counter */
 
-  DrawElementName((xstart + 3) * MINI_TILEX, (ystart + 1) * MINI_TILEY,
+  DrawElementName((xstart + 3) * MINI_TILEX + 1, (ystart + 1) * MINI_TILEY + 1,
                  properties_element);
 
   DrawPropertiesTabulatorGadgets();
 
   if (edit_mode_properties == ED_MODE_PROPERTIES_INFO)
     DrawPropertiesInfo();
-  else if (edit_mode_properties == ED_MODE_PROPERTIES_CONFIG)
+  else if (edit_mode_properties == ED_MODE_PROPERTIES_CHANGE)
+    DrawPropertiesChange();
+  else /* (edit_mode_properties == ED_MODE_PROPERTIES_CONFIG[_1|_2]) */
     DrawPropertiesConfig();
-  else /* edit_mode_properties == ED_MODE_PROPERTIES_ADVANCED */
-    DrawPropertiesAdvanced();
 }
 
 static void UpdateCustomElementGraphicGadgets()
 {
+  int i;
+
   ModifyEditorElementList();
   RedrawDrawingElements();
 
-  if (edit_mode == ED_MODE_PROPERTIES &&
-      edit_mode_properties == ED_MODE_PROPERTIES_ADVANCED)
-    DrawPropertiesAdvancedDrawingAreas();
+  /* force redraw of all mapped drawing area gadgets */
+  for (i = 0; i < ED_NUM_DRAWING_AREAS; i++)
+  {
+    struct GadgetInfo *gi = level_editor_gadget[drawingarea_info[i].gadget_id];
+
+    if (gi->mapped)
+      MapDrawingArea(i);
+  }
 }
 
 static void DrawLineElement(int sx, int sy, int element, boolean change_level)
@@ -6376,6 +7603,7 @@ static void SelectArea(int from_x, int from_y, int to_x, int to_y,
 #define CB_BRUSH_TO_CURSOR     1
 #define CB_BRUSH_TO_LEVEL      2
 #define CB_DELETE_OLD_CURSOR   3
+#define CB_DUMP_BRUSH          4
 
 static void CopyBrushExt(int from_x, int from_y, int to_x, int to_y,
                         int button, int mode)
@@ -6387,6 +7615,66 @@ static void CopyBrushExt(int from_x, int from_y, int to_x, int to_y,
   int new_element = BUTTON_ELEMENT(button);
   int x, y;
 
+  if (mode == CB_DUMP_BRUSH)
+  {
+    if (!draw_with_brush)
+    {
+      Error(ERR_WARN, "no brush selected");
+
+      return;
+    }
+
+    for (y = 0; y < brush_height; y++)
+    {
+      for (x = 0; x < brush_width; x++)
+      {
+       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 (element > EL_ENVELOPE_4)
+         element_mapped = EL_CHAR_QUESTION;    /* change to EL_UNKNOWN ... */
+
+       printf("`%03d", element_mapped);
+#endif
+      }
+
+      printf("\n");
+    }
+
+    return;
+  }
+
   if (mode == CB_DELETE_OLD_CURSOR && !delete_old_brush)
     return;
 
@@ -6501,6 +7789,11 @@ static void DeleteBrushFromCursor()
   CopyBrushExt(0, 0, 0, 0, 0, CB_DELETE_OLD_CURSOR);
 }
 
+void DumpBrush()
+{
+  CopyBrushExt(0, 0, 0, 0, 0, CB_DUMP_BRUSH);
+}
+
 static void FloodFill(int from_x, int from_y, int fill_element)
 {
   int i,x,y;
@@ -6910,7 +8203,7 @@ static void HandleDrawingAreas(struct GadgetInfo *gi)
          new_element = GFX_ELEMENT(new_element);
          custom_element.gfx_element = new_element;
 
-         CopyCustomElementPropertiesToGame(properties_element);
+         CopyElementPropertiesToGame(properties_element);
 
          UpdateCustomElementGraphicGadgets();
 
@@ -6922,6 +8215,18 @@ static void HandleDrawingAreas(struct GadgetInfo *gi)
 
          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;
@@ -6930,7 +8235,7 @@ static void HandleDrawingAreas(struct GadgetInfo *gi)
        }
        else if (id == GADGET_ID_CUSTOM_CHANGE_CONTENT)
        {
-         custom_element_change.content[sx][sy] = new_element;
+         custom_element_change.target_content[sx][sy] = new_element;
 
          CopyCustomElementPropertiesToGame(properties_element);
        }
@@ -6940,6 +8245,12 @@ static void HandleDrawingAreas(struct GadgetInfo *gi)
 
          CopyCustomElementPropertiesToGame(properties_element);
        }
+       else if (id == GADGET_ID_GROUP_CONTENT)
+       {
+         group_element_info.element[sx] = new_element;
+
+         CopyGroupElementPropertiesToGame(properties_element);
+       }
        else if (id == GADGET_ID_RANDOM_BACKGROUND)
          random_placement_background_element = new_element;
        else if (id >= GADGET_ID_ELEMENT_CONTENT_0 &&
@@ -7050,12 +8361,18 @@ static void HandleDrawingAreas(struct GadgetInfo *gi)
        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.content[sx][sy]);
+       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_ELEMENT_CONTENT_0 &&
@@ -7111,6 +8428,11 @@ static void HandleCounterButtons(struct GadgetInfo *gi)
       DrawElementContentAreas();
       break;
 
+    case ED_COUNTER_ID_GROUP_CONTENT:
+      DrawGroupElementArea(properties_element);
+      CopyGroupElementPropertiesToGame(properties_element);
+      break;
+
     case ED_COUNTER_ID_ENVELOPE_XSIZE:
     case ED_COUNTER_ID_ENVELOPE_YSIZE:
       DrawEnvelopeTextArea(-1);
@@ -7137,7 +8459,7 @@ static void HandleCounterButtons(struct GadgetInfo *gi)
        counter_id <= ED_COUNTER_ID_CUSTOM_LAST) ||
       (counter_id >= ED_COUNTER_ID_CHANGE_FIRST &&
        counter_id <= ED_COUNTER_ID_CHANGE_LAST))
-    CopyCustomElementPropertiesToGame(properties_element);
+    CopyElementPropertiesToGame(properties_element);
 }
 
 static void HandleTextInputGadgets(struct GadgetInfo *gi)
@@ -7148,7 +8470,7 @@ static void HandleTextInputGadgets(struct GadgetInfo *gi)
 
   if (type_id == ED_TEXTINPUT_ID_ELEMENT_NAME)
   {
-    CopyCustomElementPropertiesToGame(properties_element);
+    CopyElementPropertiesToGame(properties_element);
 
     ModifyEditorElementList(); /* update changed button info text */
   }
@@ -7177,8 +8499,9 @@ static void HandleSelectboxGadgets(struct GadgetInfo *gi)
   else if ((type_id >= ED_SELECTBOX_ID_CUSTOM_FIRST &&
            type_id <= ED_SELECTBOX_ID_CUSTOM_LAST) ||
           (type_id >= ED_SELECTBOX_ID_CHANGE_FIRST &&
-           type_id <= ED_SELECTBOX_ID_CHANGE_LAST))
-    CopyCustomElementPropertiesToGame(properties_element);
+           type_id <= ED_SELECTBOX_ID_CHANGE_LAST) ||
+          (type_id == ED_SELECTBOX_ID_GROUP_CHOICE_MODE))
+    CopyElementPropertiesToGame(properties_element);
 }
 
 static void HandleTextbuttonGadgets(struct GadgetInfo *gi)
@@ -7195,7 +8518,8 @@ static void HandleTextbuttonGadgets(struct GadgetInfo *gi)
   }
   else if (type_id == ED_TEXTBUTTON_ID_SAVE_AS_TEMPLATE)
   {
-    boolean new_template = (!LevelFileExists(-1));
+    char *template_filename = getDefaultLevelFilename(-1);
+    boolean new_template = !fileExists(template_filename);
 
     if (new_template ||
        Request("Save this template and kill the old ?", REQ_ASK))
@@ -7254,6 +8578,21 @@ static void HandleGraphicbuttonGadgets(struct GadgetInfo *gi)
 
     DrawPropertiesWindow();
   }
+  else if (type_id == ED_GRAPHICBUTTON_ID_COPY_CHANGE_PAGE ||
+          type_id == ED_GRAPHICBUTTON_ID_PASTE_CHANGE_PAGE)
+  {
+    struct ElementInfo *ei = &element_info[properties_element];
+    int current_change_page = ei->current_change_page;
+
+    if (type_id == ED_GRAPHICBUTTON_ID_COPY_CHANGE_PAGE)
+      element_info[EL_INTERNAL_CLIPBOARD_CHANGE].change_page[0] =
+       ei->change_page[current_change_page];
+    else if (type_id == ED_GRAPHICBUTTON_ID_PASTE_CHANGE_PAGE)
+      ei->change_page[current_change_page] =
+       element_info[EL_INTERNAL_CLIPBOARD_CHANGE].change_page[0];
+
+    DrawPropertiesWindow();
+  }
 }
 
 static void HandleRadiobuttons(struct GadgetInfo *gi)
@@ -7268,13 +8607,16 @@ static void HandleCheckbuttons(struct GadgetInfo *gi)
 
   *checkbutton_info[type_id].value ^= TRUE;
 
-  if ((type_id >= ED_CHECKBUTTON_ID_CUSTOM_FIRST &&
-       type_id <= ED_CHECKBUTTON_ID_CUSTOM_LAST) ||
-      (type_id >= ED_CHECKBUTTON_ID_CHANGE_FIRST &&
-       type_id <= ED_CHECKBUTTON_ID_CHANGE_LAST &&
+  if (type_id == ED_CHECKBUTTON_ID_CAN_FALL_INTO_ACID ||
+      type_id == ED_CHECKBUTTON_ID_CAN_MOVE_INTO_ACID ||
+      type_id == ED_CHECKBUTTON_ID_DONT_COLLIDE_WITH ||
+      (((type_id >= ED_CHECKBUTTON_ID_CUSTOM_FIRST &&
+        type_id <= ED_CHECKBUTTON_ID_CUSTOM_LAST) ||
+       (type_id >= ED_CHECKBUTTON_ID_CHANGE_FIRST &&
+        type_id <= ED_CHECKBUTTON_ID_CHANGE_LAST)) &&
        type_id != ED_CHECKBUTTON_ID_CUSTOM_USE_TEMPLATE))
   {
-    CopyCustomElementPropertiesToGame(properties_element);
+    CopyElementPropertiesToGame(properties_element);
   }
 
   if (type_id == ED_CHECKBUTTON_ID_CUSTOM_USE_GRAPHIC)
@@ -7283,7 +8625,9 @@ static void HandleCheckbuttons(struct GadgetInfo *gi)
   }
   else if (type_id == ED_CHECKBUTTON_ID_CUSTOM_USE_TEMPLATE)
   {
-    if (level.use_custom_template && !LevelFileExists(-1))
+    char *template_filename = getDefaultLevelFilename(-1);
+
+    if (level.use_custom_template && !fileExists(template_filename))
     {
       Request("No level template found !", REQ_CONFIRM);
 
@@ -7325,6 +8669,10 @@ static void HandleControlButtons(struct GadgetInfo *gi)
     edit_mode = ED_MODE_DRAWING;
   }
 
+  /* element copy mode active, but no element button pressed => deactivate */
+  if (last_custom_copy_mode != -1 && id < ED_NUM_CTRL_BUTTONS)
+    last_custom_copy_mode = -1;
+
   switch (id)
   {
     case GADGET_ID_SCROLL_LEFT:
@@ -7501,6 +8849,14 @@ static void HandleControlButtons(struct GadgetInfo *gi)
       last_drawing_function = drawing_function;
       break;
 
+    case GADGET_ID_CUSTOM_COPY:
+      CopyCustomElement(properties_element, -1, id);
+      break;
+
+    case GADGET_ID_CUSTOM_PASTE:
+      CopyCustomElement(-1, properties_element, id);
+      break;
+
     case GADGET_ID_UNDO:
       if (undo_buffer_steps == 0)
       {
@@ -7566,7 +8922,8 @@ static void HandleControlButtons(struct GadgetInfo *gi)
        Request("No Level without Gregor Mc Duffin please !", REQ_CONFIRM);
       else
       {
-       boolean new_level = (!LevelFileExists(level_nr));
+       char *level_filename = getDefaultLevelFilename(level_nr);
+       boolean new_level = !fileExists(level_filename);
 
        if (new_level ||
            Request("Save this level and kill the old ?", REQ_ASK))
@@ -7622,13 +8979,14 @@ static void HandleControlButtons(struct GadgetInfo *gi)
 
        if (last_custom_copy_mode != -1)
        {
-         CopyCustomElement(properties_element, new_element,
-                           last_custom_copy_mode);
-
-         ClickOnGadget(level_editor_gadget[last_drawing_function],
-                       MB_LEFTBUTTON);
+         if (CopyCustomElement(properties_element, new_element,
+                               last_custom_copy_mode))
+         {
+           ClickOnGadget(level_editor_gadget[last_drawing_function],
+                         MB_LEFTBUTTON);
 
-         last_custom_copy_mode = -1;
+           last_custom_copy_mode = -1;
+         }
 
          break;
        }
@@ -7711,7 +9069,15 @@ void HandleLevelEditorKeyInput(Key key)
        {
          RequestExitLevelEditor(setup.ask_on_escape);
        }
-        else
+        else if (edit_mode == ED_MODE_INFO)
+       {
+         HandleControlButtons(level_editor_gadget[GADGET_ID_INFO]);
+       }
+        else if (edit_mode == ED_MODE_PROPERTIES)
+       {
+         HandleControlButtons(level_editor_gadget[GADGET_ID_PROPERTIES]);
+       }
+       else            /* should never happen */
        {
          DrawDrawingWindow();
          edit_mode = ED_MODE_DRAWING;
@@ -7816,7 +9182,6 @@ void HandleEditorGadgetInfoText(void *ptr)
 static void HandleDrawingAreaInfo(struct GadgetInfo *gi)
 {
   static int start_lx, start_ly;
-  char *infotext;
   int id = gi->custom_id;
   int sx = gi->event.x;
   int sy = gi->event.y;
@@ -7826,6 +9191,11 @@ static void HandleDrawingAreaInfo(struct GadgetInfo *gi)
   int max_sx = gi->drawing.area_xsize - 1;
   int max_sy = gi->drawing.area_ysize - 1;
   int actual_drawing_function = drawing_function;
+  int max_infotext_len = getMaxInfoTextLength();
+  char infotext[MAX_OUTPUT_LINESIZE + 1];
+  char *text;
+
+  infotext[0] = '\0';          /* start with empty info text */
 
   /* pressed Control key: simulate picking element */
   if (GetKeyModState() & KMOD_Control)
@@ -7873,41 +9243,48 @@ static void HandleDrawingAreaInfo(struct GadgetInfo *gi)
        switch (actual_drawing_function)
        {
          case GADGET_ID_SINGLE_ITEMS:
-           infotext = "Drawing single items";
+           text = "Drawing single items";
            break;
          case GADGET_ID_CONNECTED_ITEMS:
-           infotext = "Drawing connected items";
+           text = "Drawing connected items";
            break;
          case GADGET_ID_LINE:
-           infotext = "Drawing line";
+           text = "Drawing line";
            break;
          case GADGET_ID_ARC:
-           infotext = "Drawing arc";
+           text = "Drawing arc";
            break;
          case GADGET_ID_TEXT:
-           infotext = "Setting text cursor";
+           text = "Setting text cursor";
            break;
          case GADGET_ID_RECTANGLE:
-           infotext = "Drawing rectangle";
+           text = "Drawing rectangle";
            break;
          case GADGET_ID_FILLED_BOX:
-           infotext = "Drawing filled box";
+           text = "Drawing filled box";
            break;
          case GADGET_ID_FLOOD_FILL:
-           infotext = "Flood fill";
+           text = "Flood fill";
            break;
          case GADGET_ID_GRAB_BRUSH:
-           infotext = "Grabbing brush";
+           text = "Grabbing brush";
            break;
          case GADGET_ID_PICK_ELEMENT:
-           infotext = "Picking element";
+           text = "Picking element";
            break;
 
          default:
-           infotext = "Drawing position";
+           text = "Drawing position";
            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);
@@ -7915,13 +9292,21 @@ static void HandleDrawingAreaInfo(struct GadgetInfo *gi)
          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 */
@@ -7935,65 +9320,66 @@ 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)
-      DrawTextF(INFOTEXT_XPOS - SX, INFOTEXT_YPOS - SY, FONT_TEXT_2, "%s",
-               getElementInfoText(level.amoeba_content));
+      element = level.amoeba_content;
     else if (id == GADGET_ID_CUSTOM_GRAPHIC)
-      DrawTextF(INFOTEXT_XPOS - SX, INFOTEXT_YPOS - SY, FONT_TEXT_2, "%s",
-               getElementInfoText(custom_element.gfx_element));
+      element = custom_element.gfx_element;
     else if (id == GADGET_ID_CUSTOM_CONTENT)
-      DrawTextF(INFOTEXT_XPOS - SX, INFOTEXT_YPOS - SY, FONT_TEXT_2, "%s",
-               getElementInfoText(custom_element.content[sx][sy]));
+      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)
-      DrawTextF(INFOTEXT_XPOS - SX, INFOTEXT_YPOS - SY, FONT_TEXT_2, "%s",
-               getElementInfoText(custom_element_change.target_element));
+      element = custom_element_change.target_element;
     else if (id == GADGET_ID_CUSTOM_CHANGE_CONTENT)
-      DrawTextF(INFOTEXT_XPOS - SX, INFOTEXT_YPOS - SY, FONT_TEXT_2, "%s",
-               getElementInfoText(custom_element_change.content[sx][sy]));
+      element = custom_element_change.target_content[sx][sy];
     else if (id == GADGET_ID_CUSTOM_CHANGE_TRIGGER)
-      DrawTextF(INFOTEXT_XPOS - SX, INFOTEXT_YPOS - SY, FONT_TEXT_2, "%s",
-               getElementInfoText(custom_element_change.trigger_element));
+      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)
-      DrawTextF(INFOTEXT_XPOS - SX, INFOTEXT_YPOS - SY, FONT_TEXT_2, "%s",
-               getElementInfoText(random_placement_background_element));
+      element = random_placement_background_element;
     else if (id >= GADGET_ID_ELEMENT_CONTENT_0 &&
             id <= GADGET_ID_ELEMENT_CONTENT_7)
-    {
-      int i = id - GADGET_ID_ELEMENT_CONTENT_0;
+      element = level.yamyam_content[id - GADGET_ID_ELEMENT_CONTENT_0][sx][sy];
 
-      DrawTextF(INFOTEXT_XPOS - SX, INFOTEXT_YPOS - SY, FONT_TEXT_2, "%s",
-               getElementInfoText(level.yamyam_content[i][sx][sy]));
-    }
+    strncpy(infotext, getElementInfoText(element), max_infotext_len);
   }
   else
   {
     if (id == GADGET_ID_AMOEBA_CONTENT)
-      DrawTextS(INFOTEXT_XPOS - SX, INFOTEXT_YPOS - SY, FONT_TEXT_2,
-               "Amoeba content");
+      strcpy(infotext, "Amoeba content");
     else if (id == GADGET_ID_CUSTOM_GRAPHIC)
-      DrawTextS(INFOTEXT_XPOS - SX, INFOTEXT_YPOS - SY, FONT_TEXT_2,
-               "Custom graphic element");
+      strcpy(infotext, "Custom graphic element");
     else if (id == GADGET_ID_CUSTOM_CONTENT)
-      DrawTextF(INFOTEXT_XPOS - SX, INFOTEXT_YPOS - SY, FONT_TEXT_2,
-               "Custom element content position: %d, %d", sx, sy);
+      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)
-      DrawTextS(INFOTEXT_XPOS - SX, INFOTEXT_YPOS - SY, FONT_TEXT_2,
-               "New element after change");
+      strcpy(infotext, "New element after change");
     else if (id == GADGET_ID_CUSTOM_CHANGE_CONTENT)
-      DrawTextS(INFOTEXT_XPOS - SX, INFOTEXT_YPOS - SY, FONT_TEXT_2,
-               "New extended elements after change");
+      strcpy(infotext, "New extended elements after change");
     else if (id == GADGET_ID_CUSTOM_CHANGE_TRIGGER)
-      DrawTextS(INFOTEXT_XPOS - SX, INFOTEXT_YPOS - SY, FONT_TEXT_2,
-               "Other element triggering change");
+      strcpy(infotext, "Other element triggering change");
+    else if (id == GADGET_ID_GROUP_CONTENT)
+      sprintf(infotext, "Group element position: %d", sx + 1);
     else if (id == GADGET_ID_RANDOM_BACKGROUND)
-      DrawTextS(INFOTEXT_XPOS - SX, INFOTEXT_YPOS - SY, FONT_TEXT_2,
-               "Random placement background");
+      strcpy(infotext, "Random placement background");
     else if (id >= GADGET_ID_ELEMENT_CONTENT_0 &&
             id <= GADGET_ID_ELEMENT_CONTENT_7)
-      DrawTextF(INFOTEXT_XPOS - SX, INFOTEXT_YPOS - SY, FONT_TEXT_2,
-               "Content area %d position: %d, %d",
-               id - GADGET_ID_ELEMENT_CONTENT_0 + 1, sx, sy);
+      sprintf(infotext, "Content area %d position: %d, %d",
+             id - GADGET_ID_ELEMENT_CONTENT_0 + 1, sx, sy);
   }
+
+  infotext[max_infotext_len] = '\0';
+
+  if (strlen(infotext) > 0)
+    DrawTextS(INFOTEXT_XPOS - SX, INFOTEXT_YPOS - SY, FONT_TEXT_2, infotext);
 }
 
 void RequestExitLevelEditor(boolean ask_if_level_has_changed)
index 3844a2c83d29d7f9c87a139daa0c2bb7e56e6091..f1f44184b847dc13e1ccd0e2b8153fcc9cb2fd07 100644 (file)
@@ -34,4 +34,6 @@ void HandleEditorGadgetInfoText(void *ptr);
 void RequestExitLevelEditor(boolean);
 void PrintEditorElementList();
 
+void DumpBrush();
+
 #endif
index 19c47763e05236c491659fbd15d9b772ecf204f1..fdb4b6cecdb41334606fdd8669dad338f12372dc 100644 (file)
@@ -85,7 +85,7 @@ void EventLoop(void)
     {
       Event event;
 
-      if (NextValidEvent(&event))
+      while (NextValidEvent(&event))
       {
        switch(event.type)
        {
@@ -112,7 +112,7 @@ void EventLoop(void)
     else
     {
       /* when playing, display a special mouse pointer inside the playfield */
-      if (game_status == GAME_MODE_PLAYING)
+      if (game_status == GAME_MODE_PLAYING && !tape.pausing)
       {
        if (!playfield_cursor_set && cursor_inside_playfield &&
            DelayReached(&playfield_cursor_delay, 1000))
@@ -411,36 +411,8 @@ void HandleButton(int mx, int my, int button)
 
     case GAME_MODE_PLAYING:
 #ifdef DEBUG
-      if (button == MB_RELEASED)
-      {
-       if (IN_GFX_SCREEN(mx, my))
-       {
-         int sx = (mx - SX) / TILEX;
-         int sy = (my - SY) / TILEY;
-         int x = LEVELX(sx);
-         int y = LEVELY(sy);
-
-         printf("INFO: SCREEN(%d, %d), LEVEL(%d, %d)\n", sx, sy, x, y);
-
-         if (!IN_LEV_FIELD(x, y))
-           break;
-
-         printf("      Feld[%d][%d] == %d ('%s')\n", x,y, Feld[x][y],
-                element_info[Feld[x][y]].token_name);
-         printf("      Back[%d][%d] == %d\n", x,y, Back[x][y]);
-         printf("      Store[%d][%d] == %d\n", x,y, Store[x][y]);
-         printf("      Store2[%d][%d] == %d\n", x,y, Store2[x][y]);
-         printf("      StorePlayer[%d][%d] == %d\n", x,y, StorePlayer[x][y]);
-         printf("      MovPos[%d][%d] == %d\n", x,y, MovPos[x][y]);
-         printf("      MovDir[%d][%d] == %d\n", x,y, MovDir[x][y]);
-         printf("      MovDelay[%d][%d] == %d\n", x,y, MovDelay[x][y]);
-         printf("      ChangeDelay[%d][%d] == %d\n", x,y, ChangeDelay[x][y]);
-         printf("      GfxElement[%d][%d] == %d\n", x,y, GfxElement[x][y]);
-         printf("      GfxAction[%d][%d] == %d\n", x,y, GfxAction[x][y]);
-         printf("      GfxFrame[%d][%d] == %d\n", x,y, GfxFrame[x][y]);
-         printf("\n");
-       }
-      }
+      if (button == MB_PRESSED && !motion_status && IN_GFX_SCREEN(mx, my))
+       DumpTile(LEVELX((mx - SX) / TILEX), LEVELY((my - SY) / TILEY));
 #endif
       break;
 
@@ -462,7 +434,7 @@ static boolean is_string_suffix(char *string, char *suffix)
 
 #define MAX_CHEAT_INPUT_LEN    32
 
-static void HandleKeysCheating(Key key)
+static void HandleKeysSpecial(Key key)
 {
   static char cheat_input[2 * MAX_CHEAT_INPUT_LEN + 1] = "";
   char letter = getCharFromKey(key);
@@ -487,23 +459,68 @@ static void HandleKeysCheating(Key key)
   printf("::: '%s' [%d]\n", cheat_input, cheat_input_len);
 #endif
 
-#if 1
-  if (is_string_suffix(cheat_input, ":insert solution tape"))
-    InsertSolutionTape();
-#else
-  if (is_string_suffix(cheat_input, ":ist"))
-    InsertSolutionTape();
-#endif
-
+  if (game_status == GAME_MODE_MAIN)
+  {
+    if (is_string_suffix(cheat_input, ":insert-solution-tape") ||
+       is_string_suffix(cheat_input, ":ist"))
+    {
+      InsertSolutionTape();
+    }
+    else if (is_string_suffix(cheat_input, ":reload-graphics") ||
+            is_string_suffix(cheat_input, ":rg"))
+    {
+      ReloadCustomArtwork(1 << ARTWORK_TYPE_GRAPHICS);
+      DrawMainMenu();
+    }
+    else if (is_string_suffix(cheat_input, ":reload-sounds") ||
+            is_string_suffix(cheat_input, ":rs"))
+    {
+      ReloadCustomArtwork(1 << ARTWORK_TYPE_SOUNDS);
+      DrawMainMenu();
+    }
+    else if (is_string_suffix(cheat_input, ":reload-music") ||
+            is_string_suffix(cheat_input, ":rm"))
+    {
+      ReloadCustomArtwork(1 << ARTWORK_TYPE_MUSIC);
+      DrawMainMenu();
+    }
+    else if (is_string_suffix(cheat_input, ":reload-artwork") ||
+            is_string_suffix(cheat_input, ":ra"))
+    {
+      ReloadCustomArtwork(1 << ARTWORK_TYPE_GRAPHICS |
+                         1 << ARTWORK_TYPE_SOUNDS |
+                         1 << ARTWORK_TYPE_MUSIC);
+      DrawMainMenu();
+    }
+    else if (is_string_suffix(cheat_input, ":dump-level") ||
+            is_string_suffix(cheat_input, ":dl"))
+    {
+      DumpLevel(&level);
+    }
+    else if (is_string_suffix(cheat_input, ":dump-tape") ||
+            is_string_suffix(cheat_input, ":dt"))
+    {
+      DumpTape(&tape);
+    }
+  }
+  else if (game_status == GAME_MODE_PLAYING)
+  {
 #ifdef DEBUG
-  else if (is_string_suffix(cheat_input, ":dump tape"))
-    DumpTape(&tape);
-  else 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;
+    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;
 #endif
+  }
+  else if (game_status == GAME_MODE_EDITOR)
+  {
+    if (is_string_suffix(cheat_input, ":dump-brush") ||
+       is_string_suffix(cheat_input, ":DB"))
+    {
+      DumpBrush();
+    }
+  }
 }
 
 void HandleKey(Key key, int key_status)
@@ -523,14 +540,14 @@ void HandleKey(Key key, int key_status)
     { &custom_key.up,    DEFAULT_KEY_UP,    JOY_UP       },
     { &custom_key.down,  DEFAULT_KEY_DOWN,  JOY_DOWN     },
     { &custom_key.snap,  DEFAULT_KEY_SNAP,  JOY_BUTTON_1 },
-    { &custom_key.bomb,  DEFAULT_KEY_BOMB,  JOY_BUTTON_2 }
+    { &custom_key.drop,  DEFAULT_KEY_DROP,  JOY_BUTTON_2 }
   };
 
   if (game_status == GAME_MODE_PLAYING)
   {
     /* only needed for single-step tape recording mode */
     static boolean clear_button_2[MAX_PLAYERS] = { FALSE,FALSE,FALSE,FALSE };
-    static boolean bomb_placed[MAX_PLAYERS] = { FALSE,FALSE,FALSE,FALSE };
+    static boolean element_dropped[MAX_PLAYERS] = { FALSE,FALSE,FALSE,FALSE };
     int pnr;
 
     for (pnr = 0; pnr < MAX_PLAYERS; pnr++)
@@ -568,13 +585,13 @@ void HandleKey(Key key, int key_status)
          if (key_action & KEY_MOTION)
          {
            if (stored_player[pnr].action & KEY_BUTTON_2)
-             bomb_placed[pnr] = TRUE;
+             element_dropped[pnr] = TRUE;
          }
        }
        else if (key_status == KEY_RELEASED &&
                 (key_action & KEY_BUTTON_2))
        {
-         if (!bomb_placed[pnr])
+         if (!element_dropped[pnr])
          {
            TapeTogglePause(TAPE_TOGGLE_AUTOMATIC);
 
@@ -582,7 +599,7 @@ void HandleKey(Key key, int key_status)
            clear_button_2[pnr] = TRUE;
          }
 
-         bomb_placed[pnr] = FALSE;
+         element_dropped[pnr] = FALSE;
        }
       }
       else if (tape.recording && tape.pausing && (key_action & KEY_ACTION))
@@ -614,16 +631,35 @@ void HandleKey(Key key, int key_status)
   if (key_status == KEY_RELEASED)
     return;
 
-  if ((key == KSYM_Return || key == setup.shortcut.toggle_pause) &&
-      game_status == GAME_MODE_PLAYING && AllPlayersGone)
+  if (game_status == GAME_MODE_PLAYING && AllPlayersGone &&
+      (key == KSYM_Return || key == setup.shortcut.toggle_pause))
   {
     CloseDoor(DOOR_CLOSE_1);
     game_status = GAME_MODE_MAIN;
     DrawMainMenu();
+
+    return;
+  }
+
+  if (game_status == GAME_MODE_MAIN && key == setup.shortcut.toggle_pause)
+  {
+    if (setup.autorecord)
+      TapeStartRecording();
+
+#if defined(NETWORK_AVALIABLE)
+    if (options.network)
+      SendToServer_StartPlaying();
+    else
+#endif
+    {
+      game_status = GAME_MODE_PLAYING;
+      StopAnimation();
+      InitGame();
+    }
+
     return;
   }
 
-  /* special key shortcuts */
   if (game_status == GAME_MODE_MAIN || game_status == GAME_MODE_PLAYING)
   {
     if (key == setup.shortcut.save_game)
@@ -632,10 +668,10 @@ void HandleKey(Key key, int key_status)
       TapeQuickLoad();
     else if (key == setup.shortcut.toggle_pause)
       TapeTogglePause(TAPE_TOGGLE_MANUAL);
-
-    HandleKeysCheating(key);
   }
 
+  HandleKeysSpecial(key);
+
   if (HandleGadgetsKeyInput(key))
   {
     if (key != KSYM_Escape)    /* always allow ESC key to be handled */
@@ -654,6 +690,7 @@ void HandleKey(Key key, int key_status)
     case GAME_MODE_INFO:
       switch(key)
       {
+       case KSYM_space:
        case KSYM_Return:
          if (game_status == GAME_MODE_MAIN)
            HandleMainMenu(0,0, 0,0, MB_MENU_CHOICE);
@@ -700,6 +737,7 @@ void HandleKey(Key key, int key_status)
     case GAME_MODE_SCORES:
       switch(key)
       {
+       case KSYM_space:
        case KSYM_Return:
        case KSYM_Escape:
          game_status = GAME_MODE_MAIN;
@@ -881,7 +919,7 @@ void HandleNoEvent()
     return;
   }
 
-#if defined(PLATFORM_UNIX)
+#if defined(NETWORK_AVALIABLE)
   if (options.network)
     HandleNetworking();
 #endif
index 929ce3348b305dee810dcb66aab779fb13c73b7f..3d4670f0b0f76bedc515645cd3e1a7e234839bb7 100644 (file)
 #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    13      /* unused level header bytes  */
+#define LEVEL_HEADER_UNUSED    1       /* 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_CHUNK_CNT3_UNUSED        10      /* unused CNT3 chunk bytes    */
 #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)
 
 #define TAPE_COOKIE_TMPL       "ROCKSNDIAMONDS_TAPE_FILE_VERSION_x.x"
 #define SCORE_COOKIE           "ROCKSNDIAMONDS_SCORE_FILE_VERSION_1.2"
 
+/* values for level file type identifier */
+#define LEVEL_FILE_TYPE_UNKNOWN                0
+#define LEVEL_FILE_TYPE_RND            1
+#define LEVEL_FILE_TYPE_BD             2
+#define LEVEL_FILE_TYPE_EM             3
+#define LEVEL_FILE_TYPE_SP             4
+#define LEVEL_FILE_TYPE_DX             5
+#define LEVEL_FILE_TYPE_SB             6
+#define LEVEL_FILE_TYPE_DC             7
+
+#define LEVEL_FILE_TYPE_RND_PACKED     (10 + LEVEL_FILE_TYPE_RND)
+#define LEVEL_FILE_TYPE_EM_PACKED      (10 + LEVEL_FILE_TYPE_EM)
+
+#define IS_SINGLE_LEVEL_FILE(x)                (x < 10)
+#define IS_PACKED_LEVEL_FILE(x)                (x > 10)
+
 
 /* ========================================================================= */
 /* level file functions                                                      */
@@ -74,7 +92,10 @@ void setElementChangeInfoToDefaults(struct ElementChangeInfo *change)
   change->can_change = FALSE;
 
   change->events = CE_BITMASK_DEFAULT;
-  change->sides = CH_SIDE_ANY;
+
+  change->trigger_player = CH_PLAYER_ANY;
+  change->trigger_side = CH_SIDE_ANY;
+  change->trigger_page = CH_PAGE_ANY;
 
   change->target_element = EL_EMPTY_SPACE;
 
@@ -85,15 +106,15 @@ void setElementChangeInfoToDefaults(struct ElementChangeInfo *change)
   change->trigger_element = EL_EMPTY_SPACE;
 
   change->explode = FALSE;
-  change->use_content = FALSE;
-  change->only_complete = FALSE;
-  change->use_random_change = FALSE;
-  change->random = 100;
-  change->power = CP_NON_DESTRUCTIVE;
+  change->use_target_content = FALSE;
+  change->only_if_complete = FALSE;
+  change->use_random_replace = FALSE;
+  change->random_percentage = 100;
+  change->replace_when = CP_WHEN_EMPTY;
 
   for (x = 0; x < 3; x++)
     for (y = 0; y < 3; y++)
-      change->content[x][y] = EL_EMPTY_SPACE;
+      change->target_content[x][y] = EL_EMPTY_SPACE;
 
   change->direct_action = 0;
   change->other_action = 0;
@@ -105,6 +126,8 @@ void setElementChangeInfoToDefaults(struct ElementChangeInfo *change)
 
 static void setLevelInfoToDefaults(struct LevelInfo *level)
 {
+  static boolean clipboard_elements_initialized = FALSE;
+
   int i, j, x, y;
 
   level->file_version = FILE_VERSION_ACTUAL;
@@ -123,15 +146,30 @@ static void setLevelInfoToDefaults(struct LevelInfo *level)
 
   level->time = 100;
   level->gems_needed = 0;
+
   level->amoeba_speed = 10;
+
   level->time_magic_wall = 10;
   level->time_wheel = 10;
   level->time_light = 10;
   level->time_timegate = 10;
+
   level->amoeba_content = EL_DIAMOND;
+
   level->double_speed = FALSE;
   level->initial_gravity = FALSE;
   level->em_slippery_gems = FALSE;
+  level->block_last_field = FALSE;
+  level->sp_block_last_field = TRUE;
+  level->instant_relocation = FALSE;
+  level->can_pass_to_walkable = FALSE;
+  level->grow_into_diggable = TRUE;
+
+  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_step_counter = FALSE;
 
   level->use_custom_template = FALSE;
 
@@ -165,67 +203,112 @@ static void setLevelInfoToDefaults(struct LevelInfo *level)
 
   for (i = 0; i < MAX_NUM_ELEMENTS; i++)
   {
-    setElementChangePages(&element_info[i], 1);
-    setElementChangeInfoToDefaults(element_info[i].change);
-  }
+    int element = i;
 
-  for (i = 0; i < NUM_CUSTOM_ELEMENTS; i++)
-  {
-    int element = EL_CUSTOM_START + i;
+    /* never initialize clipboard elements after the very first time */
+    if (IS_CLIPBOARD_ELEMENT(element) && clipboard_elements_initialized)
+      continue;
 
-    for (j = 0; j < MAX_ELEMENT_NAME_LEN + 1; j++)
-      element_info[element].description[j] = '\0';
-    if (element_info[element].custom_description != NULL)
-      strncpy(element_info[element].description,
-             element_info[element].custom_description, MAX_ELEMENT_NAME_LEN);
-    else
-      strcpy(element_info[element].description,
-            element_info[element].editor_description);
+    setElementChangePages(&element_info[element], 1);
+    setElementChangeInfoToDefaults(element_info[element].change);
 
-    element_info[element].use_gfx_element = FALSE;
-    element_info[element].gfx_element = EL_EMPTY_SPACE;
+    if (IS_CUSTOM_ELEMENT(element) ||
+       IS_GROUP_ELEMENT(element) ||
+       IS_INTERNAL_ELEMENT(element))
+    {
+      for (j = 0; j < MAX_ELEMENT_NAME_LEN + 1; j++)
+       element_info[element].description[j] = '\0';
 
-    element_info[element].collect_score = 10;          /* special default */
-    element_info[element].collect_count = 1;           /* special default */
+      if (element_info[element].custom_description != NULL)
+       strncpy(element_info[element].description,
+               element_info[element].custom_description,MAX_ELEMENT_NAME_LEN);
+      else
+       strcpy(element_info[element].description,
+              element_info[element].editor_description);
 
-    element_info[element].push_delay_fixed = -1;       /* initialize later */
-    element_info[element].push_delay_random = -1;      /* initialize later */
-    element_info[element].move_delay_fixed = 0;
-    element_info[element].move_delay_random = 0;
+      element_info[element].use_gfx_element = FALSE;
+      element_info[element].gfx_element = EL_EMPTY_SPACE;
 
-    element_info[element].move_pattern = MV_ALL_DIRECTIONS;
-    element_info[element].move_direction_initial = MV_NO_MOVING;
-    element_info[element].move_stepsize = TILEX / 8;
+      element_info[element].modified_settings = FALSE;
+    }
 
-    element_info[element].slippery_type = SLIPPERY_ANY_RANDOM;
+    if (IS_CUSTOM_ELEMENT(element) ||
+       IS_INTERNAL_ELEMENT(element))
+    {
+      element_info[element].access_direction = MV_ALL_DIRECTIONS;
 
-    for (x = 0; x < 3; x++)
-      for (y = 0; y < 3; y++)
-       element_info[element].content[x][y] = EL_EMPTY_SPACE;
+      element_info[element].collect_score = 10;                /* special default */
+      element_info[element].collect_count = 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;
+
+      element_info[element].move_pattern = MV_ALL_DIRECTIONS;
+      element_info[element].move_direction_initial = MV_START_AUTOMATIC;
+      element_info[element].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;
+
+      element_info[element].slippery_type = SLIPPERY_ANY_RANDOM;
 
-    element_info[element].access_type = 0;
-    element_info[element].access_layer = 0;
-    element_info[element].walk_to_action = 0;
-    element_info[element].smash_targets = 0;
-    element_info[element].deadliness = 0;
-    element_info[element].consistency = 0;
+      element_info[element].explosion_type = EXPLODES_3X3;
+      element_info[element].explosion_delay = 16;
+      element_info[element].ignition_delay = 8;
 
-    element_info[element].can_explode_by_fire = FALSE;
-    element_info[element].can_explode_smashed = FALSE;
-    element_info[element].can_explode_impact = FALSE;
+      for (x = 0; x < 3; x++)
+       for (y = 0; y < 3; y++)
+         element_info[element].content[x][y] = EL_EMPTY_SPACE;
+
+      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;
+
+      element_info[element].can_explode_by_fire = FALSE;
+      element_info[element].can_explode_smashed = FALSE;
+      element_info[element].can_explode_impact = FALSE;
+
+      element_info[element].current_change_page = 0;
+
+      /* start with no properties at all */
+      for (j = 0; j < NUM_EP_BITFIELDS; j++)
+       Properties[element][j] = EP_BITMASK_DEFAULT;
+
+      /* now set default properties */
+      SET_PROPERTY(element, EP_CAN_MOVE_INTO_ACID, TRUE);
+    }
+
+    if (IS_GROUP_ELEMENT(element) ||
+       IS_INTERNAL_ELEMENT(element))
+    {
+      /* initialize memory for list of elements in group */
+      if (element_info[element].group == NULL)
+       element_info[element].group =
+         checked_malloc(sizeof(struct ElementGroupInfo));
 
-    element_info[element].current_change_page = 0;
+      for (j = 0; j < MAX_ELEMENTS_IN_GROUP; j++)
+       element_info[element].group->element[j] = EL_EMPTY_SPACE;
 
-    /* start with no properties at all */
-    for (j = 0; j < NUM_EP_BITFIELDS; j++)
-      Properties[element][j] = EP_BITMASK_DEFAULT;
+      /* default: only one element in group */
+      element_info[element].group->num_elements = 1;
 
-    element_info[element].modified_settings = FALSE;
+      element_info[element].group->choice_mode = ANIM_RANDOM;
+    }
   }
 
+  clipboard_elements_initialized = TRUE;
+
   BorderElement = EL_STEELWALL;
 
-  level->no_level_file = FALSE;
+  level->no_valid_file = FALSE;
 
   if (leveldir_current == NULL)                /* only when dumping level */
     return;
@@ -261,6 +344,15 @@ static void setLevelInfoToDefaults(struct LevelInfo *level)
   }
 }
 
+static void setFileInfoToDefaults(struct LevelFileInfo *level_file_info)
+{
+  level_file_info->nr = 0;
+  level_file_info->type = LEVEL_FILE_TYPE_UNKNOWN;
+  level_file_info->packed = FALSE;
+  level_file_info->basename = NULL;
+  level_file_info->filename = NULL;
+}
+
 static void ActivateLevelTemplate()
 {
   /* Currently there is no special action needed to activate the template
@@ -268,16 +360,215 @@ static void ActivateLevelTemplate()
      level data, while all other variables do not change. */
 }
 
-boolean LevelFileExists(int level_nr)
+static char *getLevelFilenameFromBasename(char *basename)
+{
+  static char *filename = NULL;
+
+  checked_free(filename);
+
+  filename = getPath2(getCurrentLevelDir(), basename);
+
+  return filename;
+}
+
+static int getFileTypeFromBasename(char *basename)
+{
+  static char *filename = NULL;
+  struct stat file_status;
+
+  /* ---------- try to determine file type from filename ---------- */
+
+  /* check for typical filename of a Supaplex level package file */
+  if (strlen(basename) == 10 && (strncmp(basename, "levels.d", 8) == 0 ||
+                                strncmp(basename, "LEVELS.D", 8) == 0))
+    return LEVEL_FILE_TYPE_SP;
+
+  /* ---------- try to determine file type from filesize ---------- */
+
+  checked_free(filename);
+  filename = getPath2(getCurrentLevelDir(), basename);
+
+  if (stat(filename, &file_status) == 0)
+  {
+    /* check for typical filesize of a Supaplex level package file */
+    if (file_status.st_size == 170496)
+      return LEVEL_FILE_TYPE_SP;
+  }
+
+  return LEVEL_FILE_TYPE_UNKNOWN;
+}
+
+static char *getSingleLevelBasename(int nr, int type)
+{
+  static char basename[MAX_FILENAME_LEN];
+  char *level_filename = getStringCopy(leveldir_current->level_filename);
+
+  if (level_filename == NULL)
+    level_filename = getStringCat2("%03d.", LEVELFILE_EXTENSION);
+
+  switch (type)
+  {
+    case LEVEL_FILE_TYPE_RND:
+      if (nr < 0)
+       sprintf(basename, "template.%s", LEVELFILE_EXTENSION);
+      else
+       sprintf(basename, "%03d.%s", nr, LEVELFILE_EXTENSION);
+      break;
+
+    case LEVEL_FILE_TYPE_EM:
+      sprintf(basename, "%d", nr);
+      break;
+
+    case LEVEL_FILE_TYPE_UNKNOWN:
+    default:
+      sprintf(basename, level_filename, nr);
+      break;
+  }
+
+  free(level_filename);
+
+  return basename;
+}
+
+static char *getPackedLevelBasename(int type)
+{
+  static char basename[MAX_FILENAME_LEN];
+  char *directory = getCurrentLevelDir();
+  DIR *dir;
+  struct dirent *dir_entry;
+
+  strcpy(basename, UNDEFINED_FILENAME);                /* default: undefined file */
+
+  if ((dir = opendir(directory)) == NULL)
+  {
+    Error(ERR_WARN, "cannot read current level directory '%s'", directory);
+
+    return basename;
+  }
+
+  while ((dir_entry = readdir(dir)) != NULL)   /* loop until last dir entry */
+  {
+    char *entry_basename = dir_entry->d_name;
+    int entry_type = getFileTypeFromBasename(entry_basename);
+
+    if (entry_type != LEVEL_FILE_TYPE_UNKNOWN) /* found valid level package */
+    {
+      if (type == LEVEL_FILE_TYPE_UNKNOWN ||
+         type == entry_type)
+      {
+       strcpy(basename, entry_basename);
+
+       break;
+      }
+    }
+  }
+
+  closedir(dir);
+
+  return basename;
+}
+
+static char *getSingleLevelFilename(int nr, int type)
+{
+  return getLevelFilenameFromBasename(getSingleLevelBasename(nr, type));
+}
+
+#if 0
+static char *getPackedLevelFilename(int type)
+{
+  return getLevelFilenameFromBasename(getPackedLevelBasename(type));
+}
+#endif
+
+char *getDefaultLevelFilename(int nr)
+{
+  return getSingleLevelFilename(nr, LEVEL_FILE_TYPE_RND);
+}
+
+static void setLevelFileInfo_SingleLevelFilename(struct LevelFileInfo *lfi,
+                                                int type)
+{
+  lfi->type = type;
+  lfi->packed = FALSE;
+  lfi->basename = getSingleLevelBasename(lfi->nr, lfi->type);
+  lfi->filename = getLevelFilenameFromBasename(lfi->basename);
+}
+
+static void setLevelFileInfo_PackedLevelFilename(struct LevelFileInfo *lfi,
+                                                int type)
+{
+  lfi->type = type;
+  lfi->packed = TRUE;
+  lfi->basename = getPackedLevelBasename(lfi->type);
+  lfi->filename = getLevelFilenameFromBasename(lfi->basename);
+}
+
+static void 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)
+  {
+    /* check for file name/pattern specified in "levelinfo.conf" */
+    setLevelFileInfo_SingleLevelFilename(lfi, LEVEL_FILE_TYPE_UNKNOWN);
+    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);
+}
+
+static void determineLevelFileInfo_Filetype(struct LevelFileInfo *lfi)
 {
-  char *filename = getLevelFilename(level_nr);
+  if (lfi->type == LEVEL_FILE_TYPE_UNKNOWN)
+    lfi->type = getFileTypeFromBasename(lfi->basename);
+}
+
+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 (access(filename, F_OK) == 0);
+  return &level_file_info;
 }
 
-static int checkLevelElement(int element)
+
+/* ------------------------------------------------------------------------- */
+/* functions for loading R'n'D level                                         */
+/* ------------------------------------------------------------------------- */
+
+int getMappedElement(int element)
 {
-  /* map some (historic, now obsolete) elements */
+  /* remap some (historic, now obsolete) elements */
 
 #if 1
   switch (element)
@@ -318,7 +609,7 @@ static int checkLevelElement(int element)
       {
        Error(ERR_WARN, "invalid level element %d", element);
 
-       element = EL_CHAR_QUESTION;
+       element = EL_UNKNOWN;
       }
       break;
   }
@@ -327,7 +618,7 @@ static int checkLevelElement(int element)
   {
     Error(ERR_WARN, "invalid level element %d", element);
 
-    element = EL_CHAR_QUESTION;
+    element = EL_UNKNOWN;
   }
   else if (element == EL_PLAYER_OBSOLETE)
     element = EL_PLAYER_1;
@@ -338,6 +629,32 @@ static int checkLevelElement(int element)
   return element;
 }
 
+int getMappedElementByVersion(int element, int game_version)
+{
+  /* remap some elements due to certain game version */
+
+  if (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 (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);
+  }
+
+  return element;
+}
+
 static int LoadLevel_VERS(FILE *file, int chunk_size, struct LevelInfo *level)
 {
   level->file_version = getFileVersion(file);
@@ -367,12 +684,12 @@ 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] = checkLevelElement(getFile8Bit(file));
+       level->yamyam_content[i][x][y] = getMappedElement(getFile8Bit(file));
 
   level->amoeba_speed          = getFile8Bit(file);
   level->time_magic_wall       = getFile8Bit(file);
   level->time_wheel            = getFile8Bit(file);
-  level->amoeba_content                = checkLevelElement(getFile8Bit(file));
+  level->amoeba_content                = getMappedElement(getFile8Bit(file));
   level->double_speed          = (getFile8Bit(file) == 1 ? TRUE : FALSE);
   level->initial_gravity       = (getFile8Bit(file) == 1 ? TRUE : FALSE);
   level->encoding_16bit_field  = (getFile8Bit(file) == 1 ? TRUE : FALSE);
@@ -380,6 +697,18 @@ static int LoadLevel_HEAD(FILE *file, int chunk_size, struct LevelInfo *level)
 
   level->use_custom_template   = (getFile8Bit(file) == 1 ? TRUE : FALSE);
 
+  level->block_last_field      = (getFile8Bit(file) == 1 ? TRUE : FALSE);
+  level->sp_block_last_field   = (getFile8Bit(file) == 1 ? TRUE : FALSE);
+  level->can_move_into_acid_bits = getFile32BitBE(file);
+  level->dont_collide_with_bits = getFile8Bit(file);
+
+  level->use_spring_bug                = (getFile8Bit(file) == 1 ? TRUE : FALSE);
+  level->use_step_counter      = (getFile8Bit(file) == 1 ? TRUE : FALSE);
+
+  level->instant_relocation    = (getFile8Bit(file) == 1 ? TRUE : FALSE);
+  level->can_pass_to_walkable  = (getFile8Bit(file) == 1 ? TRUE : FALSE);
+  level->grow_into_diggable    = (getFile8Bit(file) == 1 ? TRUE : FALSE);
+
   ReadUnusedBytesFromFile(file, LEVEL_HEADER_UNUSED);
 
   return chunk_size;
@@ -418,8 +747,8 @@ static int LoadLevel_BODY(FILE *file, int chunk_size, struct LevelInfo *level)
   for (y = 0; y < level->fieldy; y++)
     for (x = 0; x < level->fieldx; x++)
       level->field[x][y] =
-       checkLevelElement(level->encoding_16bit_field ? getFile16BitBE(file) :
-                         getFile8Bit(file));
+       getMappedElement(level->encoding_16bit_field ? getFile16BitBE(file) :
+                        getFile8Bit(file));
   return chunk_size;
 }
 
@@ -458,8 +787,8 @@ static int LoadLevel_CONT(FILE *file, int chunk_size, struct LevelInfo *level)
     for (y = 0; y < 3; y++)
       for (x = 0; x < 3; x++)
        level->yamyam_content[i][x][y] =
-         checkLevelElement(level->encoding_16bit_field ?
-                           getFile16BitBE(file) : getFile8Bit(file));
+         getMappedElement(level->encoding_16bit_field ?
+                          getFile16BitBE(file) : getFile8Bit(file));
   return chunk_size;
 }
 
@@ -470,7 +799,7 @@ static int LoadLevel_CNT2(FILE *file, int chunk_size, struct LevelInfo *level)
   int num_contents, content_xsize, content_ysize;
   int content_array[MAX_ELEMENT_CONTENTS][3][3];
 
-  element = checkLevelElement(getFile16BitBE(file));
+  element = getMappedElement(getFile16BitBE(file));
   num_contents = getFile8Bit(file);
   content_xsize = getFile8Bit(file);
   content_ysize = getFile8Bit(file);
@@ -480,7 +809,7 @@ static int LoadLevel_CNT2(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++)
-       content_array[i][x][y] = checkLevelElement(getFile16BitBE(file));
+       content_array[i][x][y] = getMappedElement(getFile16BitBE(file));
 
   /* correct invalid number of content fields -- should never happen */
   if (num_contents < 1 || num_contents > MAX_ELEMENT_CONTENTS)
@@ -515,7 +844,7 @@ static int LoadLevel_CNT3(FILE *file, int chunk_size, struct LevelInfo *level)
   int envelope_len;
   int chunk_size_expected;
 
-  element = checkLevelElement(getFile16BitBE(file));
+  element = getMappedElement(getFile16BitBE(file));
   if (!IS_ENVELOPE(element))
     element = EL_ENVELOPE_1;
 
@@ -528,8 +857,7 @@ static int LoadLevel_CNT3(FILE *file, int chunk_size, struct LevelInfo *level)
 
   ReadUnusedBytesFromFile(file, LEVEL_CHUNK_CNT3_UNUSED);
 
-  chunk_size_expected = LEVEL_CHUNK_CNT3_HEADER + envelope_len;
-
+  chunk_size_expected = LEVEL_CHUNK_CNT3_SIZE(envelope_len);
   if (chunk_size_expected != chunk_size)
   {
     ReadUnusedBytesFromFile(file, chunk_size - LEVEL_CHUNK_CNT3_HEADER);
@@ -614,7 +942,7 @@ static int LoadLevel_CUS3(FILE *file, int chunk_size, struct LevelInfo *level)
     {
       Error(ERR_WARN, "invalid custom element number %d", element);
 
-      element = EL_DUMMY;
+      element = EL_INTERNAL_DUMMY;
     }
 
     for (j = 0; j < MAX_ELEMENT_NAME_LEN; j++)
@@ -628,7 +956,7 @@ static int LoadLevel_CUS3(FILE *file, int chunk_size, struct LevelInfo *level)
 
     element_info[element].use_gfx_element = getFile8Bit(file);
     element_info[element].gfx_element =
-      checkLevelElement(getFile16BitBE(file));
+      getMappedElement(getFile16BitBE(file));
 
     element_info[element].collect_score = getFile8Bit(file);
     element_info[element].collect_count = getFile8Bit(file);
@@ -645,32 +973,32 @@ static int LoadLevel_CUS3(FILE *file, int chunk_size, struct LevelInfo *level)
     for (y = 0; y < 3; y++)
       for (x = 0; x < 3; x++)
        element_info[element].content[x][y] =
-         checkLevelElement(getFile16BitBE(file));
+         getMappedElement(getFile16BitBE(file));
 
     element_info[element].change->events = getFile32BitBE(file);
 
     element_info[element].change->target_element =
-      checkLevelElement(getFile16BitBE(file));
+      getMappedElement(getFile16BitBE(file));
 
     element_info[element].change->delay_fixed = getFile16BitBE(file);
     element_info[element].change->delay_random = getFile16BitBE(file);
     element_info[element].change->delay_frames = getFile16BitBE(file);
 
     element_info[element].change->trigger_element =
-      checkLevelElement(getFile16BitBE(file));
+      getMappedElement(getFile16BitBE(file));
 
     element_info[element].change->explode = getFile8Bit(file);
-    element_info[element].change->use_content = getFile8Bit(file);
-    element_info[element].change->only_complete = getFile8Bit(file);
-    element_info[element].change->use_random_change = getFile8Bit(file);
+    element_info[element].change->use_target_content = getFile8Bit(file);
+    element_info[element].change->only_if_complete = getFile8Bit(file);
+    element_info[element].change->use_random_replace = getFile8Bit(file);
 
-    element_info[element].change->random = getFile8Bit(file);
-    element_info[element].change->power = getFile8Bit(file);
+    element_info[element].change->random_percentage = getFile8Bit(file);
+    element_info[element].change->replace_when = getFile8Bit(file);
 
     for (y = 0; y < 3; y++)
       for (x = 0; x < 3; x++)
-       element_info[element].change->content[x][y] =
-         checkLevelElement(getFile16BitBE(file));
+       element_info[element].change->target_content[x][y] =
+         getMappedElement(getFile16BitBE(file));
 
     element_info[element].slippery_type = getFile8Bit(file);
 
@@ -697,7 +1025,8 @@ static int LoadLevel_CUS4(FILE *file, int chunk_size, struct LevelInfo *level)
   {
     Error(ERR_WARN, "invalid custom element number %d", element);
 
-    element = EL_DUMMY;
+    ReadUnusedBytesFromFile(file, chunk_size - 2);
+    return chunk_size;
   }
 
   ei = &element_info[element];
@@ -724,16 +1053,19 @@ static int LoadLevel_CUS4(FILE *file, int chunk_size, struct LevelInfo *level)
   /* read custom property values */
 
   ei->use_gfx_element = getFile8Bit(file);
-  ei->gfx_element = checkLevelElement(getFile16BitBE(file));
+  ei->gfx_element = getMappedElement(getFile16BitBE(file));
 
   ei->collect_score = getFile8Bit(file);
   ei->collect_count = getFile8Bit(file);
 
-  ei->push_delay_fixed = getFile16BitBE(file);
-  ei->push_delay_random = getFile16BitBE(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);
@@ -742,10 +1074,23 @@ static int LoadLevel_CUS4(FILE *file, int chunk_size, struct LevelInfo *level)
 
   for (y = 0; y < 3; y++)
     for (x = 0; x < 3; x++)
-      ei->content[x][y] = checkLevelElement(getFile16BitBE(file));
+      ei->content[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, 12);
+  ReadUnusedBytesFromFile(file, 1);
 
   /* read change property values */
 
@@ -760,35 +1105,45 @@ static int LoadLevel_CUS4(FILE *file, int chunk_size, struct LevelInfo *level)
 
     change->events = getFile32BitBE(file);
 
-    change->target_element = checkLevelElement(getFile16BitBE(file));
+    change->target_element = getMappedElement(getFile16BitBE(file));
 
     change->delay_fixed = getFile16BitBE(file);
     change->delay_random = getFile16BitBE(file);
     change->delay_frames = getFile16BitBE(file);
 
-    change->trigger_element = checkLevelElement(getFile16BitBE(file));
+    change->trigger_element = getMappedElement(getFile16BitBE(file));
 
     change->explode = getFile8Bit(file);
-    change->use_content = getFile8Bit(file);
-    change->only_complete = getFile8Bit(file);
-    change->use_random_change = getFile8Bit(file);
+    change->use_target_content = getFile8Bit(file);
+    change->only_if_complete = getFile8Bit(file);
+    change->use_random_replace = getFile8Bit(file);
 
-    change->random = getFile8Bit(file);
-    change->power = 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->content[x][y] = checkLevelElement(getFile16BitBE(file));
+       change->target_content[x][y] = getMappedElement(getFile16BitBE(file));
 
     change->can_change = getFile8Bit(file);
 
-    change->sides = getFile8Bit(file);
+    change->trigger_side = getFile8Bit(file);
+
+#if 1
+    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));
+
+    /* some free bytes for future change property values and padding */
+    ReadUnusedBytesFromFile(file, 6);
 
-    if (change->sides == CH_SIDE_NONE) /* correct empty sides field */
-      change->sides = CH_SIDE_ANY;
+#else
 
     /* some free bytes for future change property values and padding */
     ReadUnusedBytesFromFile(file, 8);
+#endif
   }
 
   /* mark this custom element as modified */
@@ -797,22 +1152,65 @@ static int LoadLevel_CUS4(FILE *file, int chunk_size, struct LevelInfo *level)
   return chunk_size;
 }
 
-void LoadLevelFromFilename(struct LevelInfo *level, char *filename)
+static int LoadLevel_GRP1(FILE *file, int chunk_size, struct LevelInfo *level)
 {
+  struct ElementInfo *ei;
+  struct ElementGroupInfo *group;
+  int element;
+  int i;
+
+  element = 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 void LoadLevelFromFileInfo_RND(struct LevelInfo *level,
+                                     struct LevelFileInfo *level_file_info)
+{
+  char *filename = level_file_info->filename;
   char cookie[MAX_LINE_LEN];
   char chunk_name[CHUNK_ID_LEN + 1];
   int chunk_size;
   FILE *file;
 
-  /* always start with reliable default values */
-  setLevelInfoToDefaults(level);
-
   if (!(file = fopen(filename, MODE_READ)))
   {
-    level->no_level_file = TRUE;
+    level->no_valid_file = TRUE;
 
     if (level != &level_template)
-      Error(ERR_WARN, "cannot read level '%s' - creating new level", filename);
+      Error(ERR_WARN, "cannot read level '%s' -- using empty level", filename);
 
     return;
   }
@@ -825,6 +1223,8 @@ void LoadLevelFromFilename(struct LevelInfo *level, char *filename)
     getFileChunkBE(file, chunk_name, NULL);
     if (strcmp(chunk_name, "CAVE") != 0)
     {
+      level->no_valid_file = TRUE;
+
       Error(ERR_WARN, "unknown format of level file '%s'", filename);
       fclose(file);
       return;
@@ -839,6 +1239,8 @@ void LoadLevelFromFilename(struct LevelInfo *level, char *filename)
 
     if (!checkCookieString(cookie, LEVEL_COOKIE_TMPL))
     {
+      level->no_valid_file = TRUE;
+
       Error(ERR_WARN, "unknown format of level file '%s'", filename);
       fclose(file);
       return;
@@ -846,6 +1248,8 @@ void LoadLevelFromFilename(struct LevelInfo *level, char *filename)
 
     if ((level->file_version = getFileVersionFromCookieString(cookie)) == -1)
     {
+      level->no_valid_file = TRUE;
+
       Error(ERR_WARN, "unsupported version of level file '%s'", filename);
       fclose(file);
       return;
@@ -871,60 +1275,870 @@ void LoadLevelFromFilename(struct LevelInfo *level, char *filename)
     }
     chunk_info[] =
     {
-      { "VERS", FILE_VERS_CHUNK_SIZE,  LoadLevel_VERS },
-      { "HEAD", LEVEL_HEADER_SIZE,     LoadLevel_HEAD },
-      { "AUTH", MAX_LEVEL_AUTHOR_LEN,  LoadLevel_AUTH },
-      { "BODY", -1,                    LoadLevel_BODY },
-      { "CONT", -1,                    LoadLevel_CONT },
-      { "CNT2", LEVEL_CHUNK_CNT2_SIZE, LoadLevel_CNT2 },
-      { "CNT3", -1,                    LoadLevel_CNT3 },
-      { "CUS1", -1,                    LoadLevel_CUS1 },
-      { "CUS2", -1,                    LoadLevel_CUS2 },
-      { "CUS3", -1,                    LoadLevel_CUS3 },
-      { "CUS4", -1,                    LoadLevel_CUS4 },
-      {  NULL,  0,                     NULL }
-    };
+      { "VERS", FILE_VERS_CHUNK_SIZE,  LoadLevel_VERS },
+      { "HEAD", LEVEL_HEADER_SIZE,     LoadLevel_HEAD },
+      { "AUTH", MAX_LEVEL_AUTHOR_LEN,  LoadLevel_AUTH },
+      { "BODY", -1,                    LoadLevel_BODY },
+      { "CONT", -1,                    LoadLevel_CONT },
+      { "CNT2", LEVEL_CHUNK_CNT2_SIZE, LoadLevel_CNT2 },
+      { "CNT3", -1,                    LoadLevel_CNT3 },
+      { "CUS1", -1,                    LoadLevel_CUS1 },
+      { "CUS2", -1,                    LoadLevel_CUS2 },
+      { "CUS3", -1,                    LoadLevel_CUS3 },
+      { "CUS4", -1,                    LoadLevel_CUS4 },
+      { "GRP1", -1,                    LoadLevel_GRP1 },
+      {  NULL,  0,                     NULL }
+    };
+
+    while (getFileChunkBE(file, chunk_name, &chunk_size))
+    {
+      int i = 0;
+
+      while (chunk_info[i].name != NULL &&
+            strcmp(chunk_name, chunk_info[i].name) != 0)
+       i++;
+
+      if (chunk_info[i].name == NULL)
+      {
+       Error(ERR_WARN, "unknown chunk '%s' in level file '%s'",
+             chunk_name, filename);
+       ReadUnusedBytesFromFile(file, chunk_size);
+      }
+      else if (chunk_info[i].size != -1 &&
+              chunk_info[i].size != chunk_size)
+      {
+       Error(ERR_WARN, "wrong size (%d) of chunk '%s' in level file '%s'",
+             chunk_size, chunk_name, filename);
+       ReadUnusedBytesFromFile(file, chunk_size);
+      }
+      else
+      {
+       /* call function to load this level chunk */
+       int chunk_size_expected =
+         (chunk_info[i].loader)(file, chunk_size, level);
+
+       /* the size of some chunks cannot be checked before reading other
+          chunks first (like "HEAD" and "BODY") that contain some header
+          information, so check them here */
+       if (chunk_size_expected != chunk_size)
+       {
+         Error(ERR_WARN, "wrong size (%d) of chunk '%s' in level file '%s'",
+               chunk_size, chunk_name, filename);
+       }
+      }
+    }
+  }
+
+  fclose(file);
+}
+
+/* ------------------------------------------------------------------------- */
+/* functions for loading EM level                                            */
+/* ------------------------------------------------------------------------- */
+
+static int map_em_element_yam(int element)
+{
+  switch (element)
+  {
+    case 0x00: return EL_EMPTY;
+    case 0x01: return EL_EMERALD;
+    case 0x02: return EL_DIAMOND;
+    case 0x03: return EL_ROCK;
+    case 0x04: return EL_ROBOT;
+    case 0x05: return EL_SPACESHIP_UP;
+    case 0x06: return EL_BOMB;
+    case 0x07: return EL_BUG_UP;
+    case 0x08: return EL_AMOEBA_DROP;
+    case 0x09: return EL_NUT;
+    case 0x0a: return EL_YAMYAM;
+    case 0x0b: return EL_QUICKSAND_FULL;
+    case 0x0c: return EL_SAND;
+    case 0x0d: return EL_WALL_SLIPPERY;
+    case 0x0e: return EL_STEELWALL;
+    case 0x0f: return EL_WALL;
+    case 0x10: return EL_EM_KEY_1;
+    case 0x11: return EL_EM_KEY_2;
+    case 0x12: return EL_EM_KEY_4;
+    case 0x13: return EL_EM_KEY_3;
+    case 0x14: return EL_MAGIC_WALL;
+    case 0x15: return EL_ROBOT_WHEEL;
+    case 0x16: return EL_DYNAMITE;
+
+    case 0x17: return EL_EM_KEY_1;                     /* EMC */
+    case 0x18: return EL_BUG_UP;                       /* EMC */
+    case 0x1a: return EL_DIAMOND;                      /* EMC */
+    case 0x1b: return EL_EMERALD;                      /* EMC */
+    case 0x25: return EL_NUT;                          /* EMC */
+    case 0x80: return EL_EMPTY;                        /* EMC */
+    case 0x85: return EL_EM_KEY_1;                     /* EMC */
+    case 0x86: return EL_EM_KEY_2;                     /* EMC */
+    case 0x87: return EL_EM_KEY_4;                     /* EMC */
+    case 0x88: return EL_EM_KEY_3;                     /* EMC */
+    case 0x94: return EL_QUICKSAND_EMPTY;              /* EMC */
+    case 0x9a: return EL_AMOEBA_WET;                   /* EMC */
+    case 0xaf: return EL_DYNAMITE;                     /* EMC */
+    case 0xbd: return EL_SAND;                         /* EMC */
+
+    default:
+      Error(ERR_WARN, "invalid level element %d", element);
+      return EL_UNKNOWN;
+  }
+}
+
+static int map_em_element_field(int element)
+{
+  if (element >= 0xc8 && element <= 0xe1)
+    return EL_CHAR_A + (element - 0xc8);
+  else if (element >= 0xe2 && element <= 0xeb)
+    return EL_CHAR_0 + (element - 0xe2);
+
+  switch (element)
+  {
+    case 0x00: return EL_ROCK;
+    case 0x01: return EL_ROCK;                         /* EMC */
+    case 0x02: return EL_DIAMOND;
+    case 0x03: return EL_DIAMOND;
+    case 0x04: return EL_ROBOT;
+    case 0x05: return EL_ROBOT;                        /* EMC */
+    case 0x06: return EL_EMPTY_SPACE;                  /* EMC */
+    case 0x07: return EL_EMPTY_SPACE;                  /* EMC */
+    case 0x08: return EL_SPACESHIP_UP;
+    case 0x09: return EL_SPACESHIP_RIGHT;
+    case 0x0a: return EL_SPACESHIP_DOWN;
+    case 0x0b: return EL_SPACESHIP_LEFT;
+    case 0x0c: return EL_SPACESHIP_UP;
+    case 0x0d: return EL_SPACESHIP_RIGHT;
+    case 0x0e: return EL_SPACESHIP_DOWN;
+    case 0x0f: return EL_SPACESHIP_LEFT;
+
+    case 0x10: return EL_BOMB;
+    case 0x11: return EL_BOMB;                         /* EMC */
+    case 0x12: return EL_EMERALD;
+    case 0x13: return EL_EMERALD;
+    case 0x14: return EL_BUG_UP;
+    case 0x15: return EL_BUG_RIGHT;
+    case 0x16: return EL_BUG_DOWN;
+    case 0x17: return EL_BUG_LEFT;
+    case 0x18: return EL_BUG_UP;
+    case 0x19: return EL_BUG_RIGHT;
+    case 0x1a: return EL_BUG_DOWN;
+    case 0x1b: return EL_BUG_LEFT;
+    case 0x1c: return EL_AMOEBA_DROP;
+    case 0x1d: return EL_AMOEBA_DROP;                  /* EMC */
+    case 0x1e: return EL_AMOEBA_DROP;                  /* EMC */
+    case 0x1f: return EL_AMOEBA_DROP;                  /* EMC */
+
+    case 0x20: return EL_ROCK;
+    case 0x21: return EL_BOMB;                         /* EMC */
+    case 0x22: return EL_DIAMOND;                      /* EMC */
+    case 0x23: return EL_EMERALD;                      /* EMC */
+    case 0x24: return EL_MAGIC_WALL;
+    case 0x25: return EL_NUT;
+    case 0x26: return EL_NUT;                          /* EMC */
+    case 0x27: return EL_NUT;                          /* EMC */
+
+      /* looks like magic wheel, but is _always_ activated */
+    case 0x28: return EL_ROBOT_WHEEL;                  /* EMC */
+
+    case 0x29: return EL_YAMYAM;       /* up */
+    case 0x2a: return EL_YAMYAM;       /* down */
+    case 0x2b: return EL_YAMYAM;       /* left */      /* EMC */
+    case 0x2c: return EL_YAMYAM;       /* right */     /* EMC */
+    case 0x2d: return EL_QUICKSAND_FULL;
+    case 0x2e: return EL_EMPTY_SPACE;                  /* EMC */
+    case 0x2f: return EL_EMPTY_SPACE;                  /* EMC */
+
+    case 0x30: return EL_EMPTY_SPACE;                  /* EMC */
+    case 0x31: return EL_SAND;                         /* EMC */
+    case 0x32: return EL_SAND;                         /* EMC */
+    case 0x33: return EL_SAND;                         /* EMC */
+    case 0x34: return EL_QUICKSAND_FULL;               /* EMC */
+    case 0x35: return EL_QUICKSAND_FULL;               /* EMC */
+    case 0x36: return EL_QUICKSAND_FULL;               /* EMC */
+    case 0x37: return EL_SAND;                         /* EMC */
+    case 0x38: return EL_ROCK;                         /* EMC */
+    case 0x39: return EL_EXPANDABLE_WALL_HORIZONTAL;   /* EMC */
+    case 0x3a: return EL_EXPANDABLE_WALL_VERTICAL;     /* EMC */
+    case 0x3b: return EL_DYNAMITE_ACTIVE;      /* 1 */
+    case 0x3c: return EL_DYNAMITE_ACTIVE;      /* 2 */
+    case 0x3d: return EL_DYNAMITE_ACTIVE;      /* 3 */
+    case 0x3e: return EL_DYNAMITE_ACTIVE;      /* 4 */
+    case 0x3f: return EL_ACID_POOL_BOTTOM;
+
+    case 0x40: return EL_EXIT_OPEN;    /* 1 */
+    case 0x41: return EL_EXIT_OPEN;    /* 2 */
+    case 0x42: return EL_EXIT_OPEN;    /* 3 */
+    case 0x43: return EL_BALLOON;                      /* EMC */
+    case 0x44: return EL_UNKNOWN;                      /* EMC ("plant") */
+    case 0x45: return EL_SPRING;                       /* EMC */
+    case 0x46: return EL_SPRING;       /* falling */   /* EMC */
+    case 0x47: return EL_SPRING;       /* left */      /* EMC */
+    case 0x48: return EL_SPRING;       /* right */     /* EMC */
+    case 0x49: return EL_UNKNOWN;                      /* EMC ("ball 1") */
+    case 0x4a: return EL_UNKNOWN;                      /* EMC ("ball 2") */
+    case 0x4b: return EL_UNKNOWN;                      /* EMC ("android") */
+    case 0x4c: return EL_EMPTY_SPACE;                  /* EMC */
+    case 0x4d: return EL_UNKNOWN;                      /* EMC ("android") */
+    case 0x4e: return EL_INVISIBLE_WALL;               /* EMC (? "android") */
+    case 0x4f: return EL_UNKNOWN;                      /* EMC ("android") */
+
+    case 0x50: return EL_UNKNOWN;                      /* EMC ("android") */
+    case 0x51: return EL_UNKNOWN;                      /* EMC ("android") */
+    case 0x52: return EL_UNKNOWN;                      /* EMC ("android") */
+    case 0x53: return EL_UNKNOWN;                      /* EMC ("android") */
+    case 0x54: return EL_UNKNOWN;                      /* EMC ("android") */
+    case 0x55: return EL_EMPTY_SPACE;                  /* EMC */
+    case 0x56: return EL_EMPTY_SPACE;                  /* EMC */
+    case 0x57: return EL_EMPTY_SPACE;                  /* EMC */
+    case 0x58: return EL_EMPTY_SPACE;                  /* EMC */
+    case 0x59: return EL_EMPTY_SPACE;                  /* EMC */
+    case 0x5a: return EL_EMPTY_SPACE;                  /* EMC */
+    case 0x5b: return EL_EMPTY_SPACE;                  /* EMC */
+    case 0x5c: return EL_EMPTY_SPACE;                  /* EMC */
+    case 0x5d: return EL_EMPTY_SPACE;                  /* EMC */
+    case 0x5e: return EL_EMPTY_SPACE;                  /* EMC */
+    case 0x5f: return EL_EMPTY_SPACE;                  /* EMC */
+
+    case 0x60: return EL_EMPTY_SPACE;                  /* EMC */
+    case 0x61: return EL_EMPTY_SPACE;                  /* EMC */
+    case 0x62: return EL_EMPTY_SPACE;                  /* EMC */
+    case 0x63: return EL_SPRING;       /* left */      /* EMC */
+    case 0x64: return EL_SPRING;       /* right */     /* EMC */
+    case 0x65: return EL_ACID;         /* 1 */         /* EMC */
+    case 0x66: return EL_ACID;         /* 2 */         /* EMC */
+    case 0x67: return EL_ACID;         /* 3 */         /* EMC */
+    case 0x68: return EL_ACID;         /* 4 */         /* EMC */
+    case 0x69: return EL_ACID;         /* 5 */         /* EMC */
+    case 0x6a: return EL_ACID;         /* 6 */         /* EMC */
+    case 0x6b: return EL_ACID;         /* 7 */         /* EMC */
+    case 0x6c: return EL_ACID;         /* 8 */         /* EMC */
+    case 0x6d: return EL_EMPTY_SPACE;                  /* EMC */
+    case 0x6e: return EL_EMPTY_SPACE;                  /* EMC */
+    case 0x6f: return EL_EMPTY_SPACE;                  /* EMC */
+
+    case 0x70: return EL_EMPTY_SPACE;                  /* EMC */
+    case 0x71: return EL_EMPTY_SPACE;                  /* EMC */
+    case 0x72: return EL_NUT;          /* left */      /* EMC */
+    case 0x73: return EL_SAND;                         /* EMC (? "nut") */
+    case 0x74: return EL_STEELWALL;
+    case 0x75: return EL_EMPTY_SPACE;                  /* EMC */
+    case 0x76: return EL_EMPTY_SPACE;                  /* EMC */
+    case 0x77: return EL_BOMB;         /* left */      /* EMC */
+    case 0x78: return EL_BOMB;         /* right */     /* EMC */
+    case 0x79: return EL_ROCK;         /* left */      /* EMC */
+    case 0x7a: return EL_ROCK;         /* right */     /* EMC */
+    case 0x7b: return EL_ACID;                         /* (? EMC "blank") */
+    case 0x7c: return EL_EMPTY_SPACE;                  /* EMC */
+    case 0x7d: return EL_EMPTY_SPACE;                  /* EMC */
+    case 0x7e: return EL_EMPTY_SPACE;                  /* EMC */
+    case 0x7f: return EL_EMPTY_SPACE;                  /* EMC */
+
+    case 0x80: return EL_EMPTY;
+    case 0x81: return EL_WALL_SLIPPERY;
+    case 0x82: return EL_SAND;
+    case 0x83: return EL_STEELWALL;
+    case 0x84: return EL_WALL;
+    case 0x85: return EL_EM_KEY_1;
+    case 0x86: return EL_EM_KEY_2;
+    case 0x87: return EL_EM_KEY_4;
+    case 0x88: return EL_EM_KEY_3;
+    case 0x89: return EL_EM_GATE_1;
+    case 0x8a: return EL_EM_GATE_2;
+    case 0x8b: return EL_EM_GATE_4;
+    case 0x8c: return EL_EM_GATE_3;
+    case 0x8d: return EL_INVISIBLE_WALL;               /* EMC (? "dripper") */
+    case 0x8e: return EL_EM_GATE_1_GRAY;
+    case 0x8f: return EL_EM_GATE_2_GRAY;
+
+    case 0x90: return EL_EM_GATE_4_GRAY;
+    case 0x91: return EL_EM_GATE_3_GRAY;
+    case 0x92: return EL_MAGIC_WALL;
+    case 0x93: return EL_ROBOT_WHEEL;
+    case 0x94: return EL_QUICKSAND_EMPTY;              /* (? EMC "sand") */
+    case 0x95: return EL_ACID_POOL_TOPLEFT;
+    case 0x96: return EL_ACID_POOL_TOPRIGHT;
+    case 0x97: return EL_ACID_POOL_BOTTOMLEFT;
+    case 0x98: return EL_ACID_POOL_BOTTOMRIGHT;
+    case 0x99: return EL_ACID;                 /* (? EMC "fake blank") */
+    case 0x9a: return EL_AMOEBA_DEAD;          /* 1 */
+    case 0x9b: return EL_AMOEBA_DEAD;          /* 2 */
+    case 0x9c: return EL_AMOEBA_DEAD;          /* 3 */
+    case 0x9d: return EL_AMOEBA_DEAD;          /* 4 */
+    case 0x9e: return EL_EXIT_CLOSED;
+    case 0x9f: return EL_CHAR_LESS;            /* arrow left */
+
+      /* looks like normal sand, but behaves like wall */
+    case 0xa0: return EL_UNKNOWN;              /* EMC ("fake grass") */
+    case 0xa1: return EL_UNKNOWN;              /* EMC ("lenses") */
+    case 0xa2: return EL_UNKNOWN;              /* EMC ("magnify") */
+    case 0xa3: return EL_UNKNOWN;              /* EMC ("fake blank") */
+    case 0xa4: return EL_UNKNOWN;              /* EMC ("fake grass") */
+    case 0xa5: return EL_UNKNOWN;              /* EMC ("switch") */
+    case 0xa6: return EL_UNKNOWN;              /* EMC ("switch") */
+    case 0xa7: return EL_EMPTY_SPACE;                  /* EMC */
+    case 0xa8: return EL_EMC_WALL_1;                   /* EMC ("decor 8") */
+    case 0xa9: return EL_EMC_WALL_2;                   /* EMC ("decor 9") */
+    case 0xaa: return EL_EMC_WALL_3;                   /* EMC ("decor 10") */
+    case 0xab: return EL_EMC_WALL_7;                   /* EMC ("decor 5") */
+    case 0xac: return EL_CHAR_COMMA;                   /* EMC */
+    case 0xad: return EL_CHAR_QUOTEDBL;                /* EMC */
+    case 0xae: return EL_CHAR_MINUS;                   /* EMC */
+    case 0xaf: return EL_DYNAMITE;
+
+    case 0xb0: return EL_EMC_STEELWALL_1;              /* EMC ("steel 3") */
+    case 0xb1: return EL_EMC_WALL_8;                   /* EMC ("decor 6") */
+    case 0xb2: return EL_UNKNOWN;                      /* EMC ("decor 7") */
+    case 0xb3: return EL_STEELWALL;            /* 2 */ /* EMC */
+    case 0xb4: return EL_WALL_SLIPPERY;        /* 2 */ /* EMC */
+    case 0xb5: return EL_EMC_WALL_6;                   /* EMC ("decor 2") */
+    case 0xb6: return EL_EMC_WALL_5;                   /* EMC ("decor 4") */
+    case 0xb7: return EL_EMC_WALL_4;                   /* EMC ("decor 3") */
+    case 0xb8: return EL_BALLOON_SWITCH_ANY;           /* EMC */
+    case 0xb9: return EL_BALLOON_SWITCH_RIGHT;         /* EMC */
+    case 0xba: return EL_BALLOON_SWITCH_DOWN;          /* EMC */
+    case 0xbb: return EL_BALLOON_SWITCH_LEFT;          /* EMC */
+    case 0xbc: return EL_BALLOON_SWITCH_UP;            /* EMC */
+    case 0xbd: return EL_SAND;                         /* EMC ("dirt") */
+    case 0xbe: return EL_UNKNOWN;                      /* EMC ("plant") */
+    case 0xbf: return EL_UNKNOWN;                      /* EMC ("key 5") */
+
+    case 0xc0: return EL_UNKNOWN;                      /* EMC ("key 6") */
+    case 0xc1: return EL_UNKNOWN;                      /* EMC ("key 7") */
+    case 0xc2: return EL_UNKNOWN;                      /* EMC ("key 8") */
+    case 0xc3: return EL_UNKNOWN;                      /* EMC ("door 5") */
+    case 0xc4: return EL_UNKNOWN;                      /* EMC ("door 6") */
+    case 0xc5: return EL_UNKNOWN;                      /* EMC ("door 7") */
+    case 0xc6: return EL_UNKNOWN;                      /* EMC ("door 8") */
+    case 0xc7: return EL_UNKNOWN;                      /* EMC ("bumper") */
+
+      /* characters: see above */
+
+    case 0xec: return EL_CHAR_PERIOD;
+    case 0xed: return EL_CHAR_EXCLAM;
+    case 0xee: return EL_CHAR_COLON;
+    case 0xef: return EL_CHAR_QUESTION;
+
+    case 0xf0: return EL_CHAR_GREATER;                 /* arrow right */
+    case 0xf1: return EL_CHAR_COPYRIGHT;               /* EMC: "decor 1" */
+    case 0xf2: return EL_UNKNOWN;              /* EMC ("fake door 5") */
+    case 0xf3: return EL_UNKNOWN;              /* EMC ("fake door 6") */
+    case 0xf4: return EL_UNKNOWN;              /* EMC ("fake door 7") */
+    case 0xf5: return EL_UNKNOWN;              /* EMC ("fake door 8") */
+    case 0xf6: return EL_EMPTY_SPACE;                  /* EMC */
+    case 0xf7: return EL_EMPTY_SPACE;                  /* EMC */
+
+    case 0xf8: return EL_EMPTY_SPACE;                  /* EMC */
+    case 0xf9: return EL_EMPTY_SPACE;                  /* EMC */
+    case 0xfa: return EL_EMPTY_SPACE;                  /* EMC */
+    case 0xfb: return EL_EMPTY_SPACE;                  /* EMC */
+    case 0xfc: return EL_EMPTY_SPACE;                  /* EMC */
+    case 0xfd: return EL_EMPTY_SPACE;                  /* EMC */
+
+    case 0xfe: return EL_PLAYER_1;                     /* EMC: "blank" */
+    case 0xff: return EL_PLAYER_2;                     /* EMC: "blank" */
+
+    default:
+      /* should never happen (all 8-bit value cases should be handled) */
+      Error(ERR_WARN, "invalid level element %d", element);
+      return EL_UNKNOWN;
+  }
+}
+
+#define EM_LEVEL_SIZE                  2106
+#define EM_LEVEL_XSIZE                 64
+#define EM_LEVEL_YSIZE                 32
+
+static void LoadLevelFromFileInfo_EM(struct LevelInfo *level,
+                                    struct LevelFileInfo *level_file_info)
+{
+  char *filename = level_file_info->filename;
+  FILE *file;
+  unsigned char leveldata[EM_LEVEL_SIZE];
+  unsigned char *header = &leveldata[EM_LEVEL_XSIZE * EM_LEVEL_YSIZE];
+  unsigned char code0 = 0x65;
+  unsigned char code1 = 0x11;
+  boolean level_is_crypted = FALSE;
+  int nr = level_file_info->nr;
+  int i, x, y;
+
+  if (!(file = fopen(filename, MODE_READ)))
+  {
+    level->no_valid_file = TRUE;
+
+    Error(ERR_WARN, "cannot read level '%s' -- using empty level", filename);
+
+    return;
+  }
+
+  for(i = 0; i < EM_LEVEL_SIZE; i++)
+    leveldata[i] = fgetc(file);
+
+  fclose(file);
+
+  /* check if level data is crypted by testing against known starting bytes
+     of the few existing crypted level files (from Emerald Mine 1 + 2) */
+
+  if ((leveldata[0] == 0xf1 ||
+       leveldata[0] == 0xf5) && leveldata[2] == 0xe7 && leveldata[3] == 0xee)
+  {
+    level_is_crypted = TRUE;
+
+    if (leveldata[0] == 0xf5)  /* error in crypted Emerald Mine 2 levels */
+      leveldata[0] = 0xf1;
+  }
+
+  if (level_is_crypted)                /* decode crypted level data */
+  {
+    for(i = 0; i < EM_LEVEL_SIZE; i++)
+    {
+      leveldata[i] ^= code0;
+      leveldata[i] -= code1;
+
+      code0  = (code0 + 7) & 0xff;
+    }
+  }
+
+  level->fieldx        = EM_LEVEL_XSIZE;
+  level->fieldy        = EM_LEVEL_YSIZE;
+
+  level->time          = header[46] * 10;
+  level->gems_needed   = header[47];
+
+  /* The original Emerald Mine levels have their level number stored
+     at the second byte of the level file...
+     Do not trust this information at other level files, e.g. EMC,
+     but correct it anyway (normally the first row is completely
+     steel wall, so the correction does not hurt anyway). */
+
+  if (leveldata[1] == nr)
+    leveldata[1] = leveldata[2];       /* correct level number field */
+
+  sprintf(level->name, "Level %d", nr);                /* set level name */
+
+  level->score[SC_EMERALD]     = header[36];
+  level->score[SC_DIAMOND]     = header[37];
+  level->score[SC_ROBOT]       = header[38];
+  level->score[SC_SPACESHIP]   = header[39];
+  level->score[SC_BUG]         = header[40];
+  level->score[SC_YAMYAM]      = header[41];
+  level->score[SC_NUT]         = header[42];
+  level->score[SC_DYNAMITE]    = header[43];
+  level->score[SC_TIME_BONUS]  = header[44];
+
+  level->num_yamyam_contents = 4;
+
+  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] =
+         map_em_element_yam(header[i * 9 + y * 3 + x]);
+
+  level->amoeba_speed          = (header[52] * 256 + header[53]) % 256;
+  level->time_magic_wall       = (header[54] * 256 + header[55]) * 16 / 100;
+  level->time_wheel            = (header[56] * 256 + header[57]) * 16 / 100;
+  level->amoeba_content                = EL_DIAMOND;
+
+  for (y = 0; y < level->fieldy; y++) for (x = 0; x < level->fieldx; x++)
+  {
+    int new_element = map_em_element_field(leveldata[y * EM_LEVEL_XSIZE + x]);
+
+    if (new_element == EL_AMOEBA_DEAD && level->amoeba_speed)
+      new_element = EL_AMOEBA_WET;
+
+    level->field[x][y] = new_element;
+  }
+
+  x = (header[48] * 256 + header[49]) % EM_LEVEL_XSIZE;
+  y = (header[48] * 256 + header[49]) / EM_LEVEL_XSIZE;
+  level->field[x][y] = EL_PLAYER_1;
+
+  x = (header[50] * 256 + header[51]) % EM_LEVEL_XSIZE;
+  y = (header[50] * 256 + header[51]) / EM_LEVEL_XSIZE;
+  level->field[x][y] = EL_PLAYER_2;
+}
+
+/* ------------------------------------------------------------------------- */
+/* functions for loading SP level                                            */
+/* ------------------------------------------------------------------------- */
+
+#define NUM_SUPAPLEX_LEVELS_PER_PACKAGE        111
+#define SP_LEVEL_SIZE                  1536
+#define SP_LEVEL_XSIZE                 60
+#define SP_LEVEL_YSIZE                 24
+#define SP_LEVEL_NAME_LEN              23
+
+static void LoadLevelFromFileStream_SP(FILE *file, struct LevelInfo *level,
+                                      int nr)
+{
+  int num_special_ports;
+  int i, x, y;
+
+  /* for details of the Supaplex level format, see Herman Perk's Supaplex
+     documentation file "SPFIX63.DOC" from his Supaplex "SpeedFix" package */
+
+  /* read level body (width * height == 60 * 24 tiles == 1440 bytes) */
+  for (y = 0; y < SP_LEVEL_YSIZE; y++)
+  {
+    for (x = 0; x < SP_LEVEL_XSIZE; x++)
+    {
+      int element_old = fgetc(file);
+      int element_new;
+
+      if (element_old <= 0x27)
+       element_new = getMappedElement(EL_SP_START + element_old);
+      else if (element_old == 0x28)
+       element_new = EL_INVISIBLE_WALL;
+      else
+      {
+       Error(ERR_WARN, "in level %d, at position %d, %d:", nr, x, y);
+       Error(ERR_WARN, "invalid level element %d", element_old);
+
+       element_new = EL_UNKNOWN;
+      }
+
+      level->field[x][y] = element_new;
+    }
+  }
+
+  ReadUnusedBytesFromFile(file, 4);    /* (not used by Supaplex engine) */
+
+  /* initial gravity: 1 == "on", anything else (0) == "off" */
+  level->initial_gravity = (fgetc(file) == 1 ? TRUE : FALSE);
+
+  ReadUnusedBytesFromFile(file, 1);    /* (not used by Supaplex engine) */
+
+  /* level title in uppercase letters, padded with dashes ("-") (23 bytes) */
+  for (i = 0; i < SP_LEVEL_NAME_LEN; i++)
+    level->name[i] = fgetc(file);
+  level->name[SP_LEVEL_NAME_LEN] = '\0';
+
+  /* initial "freeze zonks": 2 == "on", anything else (0, 1) == "off" */
+  ReadUnusedBytesFromFile(file, 1);    /* (not used by R'n'D engine) */
+
+  /* number of infotrons needed; 0 means that Supaplex will count the total
+     amount of infotrons in the level and use the low byte of that number
+     (a multiple of 256 infotrons will result in "0 infotrons needed"!) */
+  level->gems_needed = fgetc(file);
+
+  /* number of special ("gravity") port entries below (maximum 10 allowed) */
+  num_special_ports = fgetc(file);
+
+  /* database of properties of up to 10 special ports (6 bytes per port) */
+  for (i = 0; i < 10; i++)
+  {
+    int port_location, port_x, port_y, port_element;
+    int gravity;
+
+    /* high and low byte of the location of a special port; if (x, y) are the
+       coordinates of a port in the field and (0, 0) is the top-left corner,
+       the 16 bit value here calculates as 2 * (x + (y * 60)) (this is twice
+       of what may be expected: Supaplex works with a game field in memory
+       which is 2 bytes per tile) */
+    port_location = getFile16BitBE(file);
+
+    /* change gravity: 1 == "turn on", anything else (0) == "turn off" */
+    gravity = fgetc(file);
+
+    /* "freeze zonks": 2 == "turn on", anything else (0, 1) == "turn off" */
+    ReadUnusedBytesFromFile(file, 1);  /* (not used by R'n'D engine) */
+
+    /* "freeze enemies": 1 == "turn on", anything else (0) == "turn off" */
+    ReadUnusedBytesFromFile(file, 1);  /* (not used by R'n'D engine) */
+
+    ReadUnusedBytesFromFile(file, 1);  /* (not used by Supaplex engine) */
+
+    if (i >= num_special_ports)
+      continue;
+
+    port_x = (port_location / 2) % SP_LEVEL_XSIZE;
+    port_y = (port_location / 2) / SP_LEVEL_XSIZE;
+
+    if (port_x < 0 || port_x >= SP_LEVEL_XSIZE ||
+       port_y < 0 || port_y >= SP_LEVEL_YSIZE)
+    {
+      Error(ERR_WARN, "special port position (%d, %d) out of bounds",
+           port_x, port_y);
+
+      continue;
+    }
+
+    port_element = level->field[port_x][port_y];
+
+    if (port_element < EL_SP_GRAVITY_PORT_RIGHT ||
+       port_element > EL_SP_GRAVITY_PORT_UP)
+    {
+      Error(ERR_WARN, "no special port at position (%d, %d)", port_x, port_y);
+
+      continue;
+    }
+
+    /* change previous (wrong) gravity inverting special port to either
+       gravity enabling special port or gravity disabling special port */
+    level->field[port_x][port_y] +=
+      (gravity == 1 ? EL_SP_GRAVITY_ON_PORT_RIGHT :
+       EL_SP_GRAVITY_OFF_PORT_RIGHT) - EL_SP_GRAVITY_PORT_RIGHT;
+  }
+
+  ReadUnusedBytesFromFile(file, 4);    /* (not used by Supaplex engine) */
+
+  /* change special gravity ports without database entries to normal ports */
+  for (y = 0; y < SP_LEVEL_YSIZE; y++)
+    for (x = 0; x < SP_LEVEL_XSIZE; x++)
+      if (level->field[x][y] >= EL_SP_GRAVITY_PORT_RIGHT &&
+         level->field[x][y] <= EL_SP_GRAVITY_PORT_UP)
+       level->field[x][y] += EL_SP_PORT_RIGHT - EL_SP_GRAVITY_PORT_RIGHT;
+
+  /* auto-determine number of infotrons if it was stored as "0" -- see above */
+  if (level->gems_needed == 0)
+  {
+    for (y = 0; y < SP_LEVEL_YSIZE; y++)
+      for (x = 0; x < SP_LEVEL_XSIZE; x++)
+       if (level->field[x][y] == EL_SP_INFOTRON)
+         level->gems_needed++;
+
+    level->gems_needed &= 0xff;                /* only use low byte -- see above */
+  }
+
+  level->fieldx = SP_LEVEL_XSIZE;
+  level->fieldy = SP_LEVEL_YSIZE;
+
+  level->time = 0;                     /* no time limit */
+  level->amoeba_speed = 0;
+  level->time_magic_wall = 0;
+  level->time_wheel = 0;
+  level->amoeba_content = EL_EMPTY;
+
+  for(i = 0; i < LEVEL_SCORE_ELEMENTS; i++)
+    level->score[i] = 0;               /* !!! CORRECT THIS !!! */
+
+  /* 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;
+}
+
+static void LoadLevelFromFileInfo_SP(struct LevelInfo *level,
+                                    struct LevelFileInfo *level_file_info)
+{
+  char *filename = level_file_info->filename;
+  FILE *file;
+  int nr = level_file_info->nr - leveldir_current->first_level;
+  int i, l, x, y;
+  char name_first, name_last;
+  struct LevelInfo multipart_level;
+  int multipart_xpos, multipart_ypos;
+  boolean is_multipart_level;
+  boolean is_first_part;
+  boolean reading_multipart_level = FALSE;
+  boolean use_empty_level = FALSE;
+
+  if (!(file = fopen(filename, MODE_READ)))
+  {
+    level->no_valid_file = TRUE;
+
+    Error(ERR_WARN, "cannot read level '%s' -- using empty level", filename);
+
+    return;
+  }
+
+  /* position file stream to the requested level inside the level package */
+  if (fseek(file, nr * SP_LEVEL_SIZE, SEEK_SET) != 0)
+  {
+    level->no_valid_file = TRUE;
+
+    Error(ERR_WARN, "cannot fseek level '%s' -- using empty level", filename);
+
+    return;
+  }
+
+  /* there exist Supaplex level package files with multi-part levels which
+     can be detected as follows: instead of leading and trailing dashes ('-')
+     to pad the level name, they have leading and trailing numbers which are
+     the x and y coordinations of the current part of the multi-part level;
+     if there are '?' characters instead of numbers on the left or right side
+     of the level name, the multi-part level consists of only horizontal or
+     vertical parts */
+
+  for (l = nr; l < NUM_SUPAPLEX_LEVELS_PER_PACKAGE; l++)
+  {
+    LoadLevelFromFileStream_SP(file, level, l);
+
+    /* check if this level is a part of a bigger multi-part level */
+
+    name_first = level->name[0];
+    name_last  = level->name[SP_LEVEL_NAME_LEN - 1];
+
+    is_multipart_level =
+      ((name_first == '?' || (name_first >= '0' && name_first <= '9')) &&
+       (name_last  == '?' || (name_last  >= '0' && name_last  <= '9')));
+
+    is_first_part =
+      ((name_first == '?' || name_first == '1') &&
+       (name_last  == '?' || name_last  == '1'));
+
+    /* correct leading multipart level meta information in level name */
+    for (i = 0; i < SP_LEVEL_NAME_LEN && level->name[i] == name_first; i++)
+      level->name[i] = '-';
+
+    /* correct trailing multipart level meta information in level name */
+    for (i = SP_LEVEL_NAME_LEN - 1; i>=0 && level->name[i] == name_last; i--)
+      level->name[i] = '-';
+
+    /* ---------- check for normal single level ---------- */
+
+    if (!reading_multipart_level && !is_multipart_level)
+    {
+      /* the current level is simply a normal single-part level, and we are
+        not reading a multi-part level yet, so return the level as it is */
+
+      break;
+    }
+
+    /* ---------- check for empty level (unused multi-part) ---------- */
+
+    if (!reading_multipart_level && is_multipart_level && !is_first_part)
+    {
+      /* this is a part of a multi-part level, but not the first part
+        (and we are not already reading parts of a multi-part level);
+        in this case, use an empty level instead of the single part */
+
+      use_empty_level = TRUE;
+
+      break;
+    }
+
+    /* ---------- check for finished multi-part level ---------- */
+
+    if (reading_multipart_level &&
+       (!is_multipart_level ||
+        strcmp(level->name, multipart_level.name) != 0))
+    {
+      /* 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
+        level; in both cases, the multi-part level seems to be complete */
+
+      break;
+    }
+
+    /* ---------- here we have one part of a multi-part level ---------- */
+
+    reading_multipart_level = TRUE;
+
+    if (is_first_part) /* start with first part of new multi-part level */
+    {
+      /* copy level info structure from first part */
+      multipart_level = *level;
 
-    while (getFileChunkBE(file, chunk_name, &chunk_size))
+      /* clear playfield of new multi-part level */
+      for (y = 0; y < MAX_LEV_FIELDY; y++)
+       for (x = 0; x < MAX_LEV_FIELDX; x++)
+         multipart_level.field[x][y] = EL_EMPTY;
+    }
+
+    if (name_first == '?')
+      name_first = '1';
+    if (name_last == '?')
+      name_last = '1';
+
+    multipart_xpos = (int)(name_first - '0');
+    multipart_ypos = (int)(name_last  - '0');
+
+#if 0
+    printf("----------> part (%d/%d) of multi-part level '%s'\n",
+          multipart_xpos, multipart_ypos, multipart_level.name);
+#endif
+
+    if (multipart_xpos * SP_LEVEL_XSIZE > MAX_LEV_FIELDX ||
+       multipart_ypos * SP_LEVEL_YSIZE > MAX_LEV_FIELDY)
     {
-      int i = 0;
+      Error(ERR_WARN, "multi-part level is too big -- ignoring part of it");
 
-      while (chunk_info[i].name != NULL &&
-            strcmp(chunk_name, chunk_info[i].name) != 0)
-       i++;
+      break;
+    }
 
-      if (chunk_info[i].name == NULL)
-      {
-       Error(ERR_WARN, "unknown chunk '%s' in level file '%s'",
-             chunk_name, filename);
-       ReadUnusedBytesFromFile(file, chunk_size);
-      }
-      else if (chunk_info[i].size != -1 &&
-              chunk_info[i].size != chunk_size)
-      {
-       Error(ERR_WARN, "wrong size (%d) of chunk '%s' in level file '%s'",
-             chunk_size, chunk_name, filename);
-       ReadUnusedBytesFromFile(file, chunk_size);
-      }
-      else
+    multipart_level.fieldx = MAX(multipart_level.fieldx,
+                                multipart_xpos * SP_LEVEL_XSIZE);
+    multipart_level.fieldy = MAX(multipart_level.fieldy,
+                                multipart_ypos * SP_LEVEL_YSIZE);
+
+    /* copy level part at the right position of multi-part level */
+    for (y = 0; y < SP_LEVEL_YSIZE; y++)
+    {
+      for (x = 0; x < SP_LEVEL_XSIZE; x++)
       {
-       /* call function to load this level chunk */
-       int chunk_size_expected =
-         (chunk_info[i].loader)(file, chunk_size, level);
+       int start_x = (multipart_xpos - 1) * SP_LEVEL_XSIZE;
+       int start_y = (multipart_ypos - 1) * SP_LEVEL_YSIZE;
 
-       /* the size of some chunks cannot be checked before reading other
-          chunks first (like "HEAD" and "BODY") that contain some header
-          information, so check them here */
-       if (chunk_size_expected != chunk_size)
-       {
-         Error(ERR_WARN, "wrong size (%d) of chunk '%s' in level file '%s'",
-               chunk_size, chunk_name, filename);
-       }
+       multipart_level.field[start_x + x][start_y + y] = level->field[x][y];
       }
     }
   }
 
   fclose(file);
+
+  if (use_empty_level)
+  {
+    setLevelInfoToDefaults(level);
+
+    level->fieldx = SP_LEVEL_XSIZE;
+    level->fieldy = SP_LEVEL_YSIZE;
+
+    for (y = 0; y < SP_LEVEL_YSIZE; y++)
+      for (x = 0; x < SP_LEVEL_XSIZE; x++)
+       level->field[x][y] = EL_EMPTY;
+
+    strcpy(level->name, "-------- EMPTY --------");
+
+    Error(ERR_WARN, "single part of multi-part level -- using empty level");
+  }
+
+  if (reading_multipart_level)
+    *level = multipart_level;
+}
+
+/* ------------------------------------------------------------------------- */
+/* functions for loading generic level                                       */
+/* ------------------------------------------------------------------------- */
+
+void LoadLevelFromFileInfo(struct LevelInfo *level,
+                          struct LevelFileInfo *level_file_info)
+{
+  /* always start with reliable default values */
+  setLevelInfoToDefaults(level);
+
+  switch (level_file_info->type)
+  {
+    case LEVEL_FILE_TYPE_RND:
+      LoadLevelFromFileInfo_RND(level, level_file_info);
+      break;
+
+    case LEVEL_FILE_TYPE_EM:
+      LoadLevelFromFileInfo_EM(level, level_file_info);
+      break;
+
+    case LEVEL_FILE_TYPE_SP:
+      LoadLevelFromFileInfo_SP(level, level_file_info);
+      break;
+
+    default:
+      LoadLevelFromFileInfo_RND(level, level_file_info);
+      break;
+  }
+}
+
+void LoadLevelFromFilename(struct LevelInfo *level, char *filename)
+{
+  static struct LevelFileInfo level_file_info;
+
+  /* always start with reliable default values */
+  setFileInfoToDefaults(&level_file_info);
+
+  level_file_info.nr = 0;                      /* unknown level number */
+  level_file_info.type = LEVEL_FILE_TYPE_RND;  /* no others supported yet */
+  level_file_info.filename = filename;
+
+  LoadLevelFromFileInfo(level, &level_file_info);
 }
 
 static void LoadLevel_InitVersion(struct LevelInfo *level, char *filename)
@@ -963,6 +2177,11 @@ static void LoadLevel_InitVersion(struct LevelInfo *level, char *filename)
        pre-2.0 levels, where the game version is still taken from the
        file format version used to store the level -- see above). */
 
+#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)
     {
@@ -972,10 +2191,44 @@ static void LoadLevel_InitVersion(struct LevelInfo *level, char *filename)
       /* player was faster than monsters in (pre-)1.0 levels */
       level->double_speed = TRUE;
     }
+#endif
 
-    /* Default behaviour for EM style gems was "slippery" only in 2.0.1 */
+    /* 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;
+
+    if (level->game_version < VERSION_IDENT(2,2,0,0))
+      level->use_spring_bug = TRUE;
+
+    if (level->game_version < VERSION_IDENT(3,1,0,0))
+    {
+      int i, j;
+
+      level->can_move_into_acid_bits = 0; /* nothing can move into acid */
+      level->dont_collide_with_bits = 0; /* nothing is deadly when colliding */
+
+      setMoveIntoAcidProperty(level, EL_ROBOT,     TRUE);
+      setMoveIntoAcidProperty(level, EL_SATELLITE, TRUE);
+      setMoveIntoAcidProperty(level, EL_PENGUIN,   TRUE);
+      setMoveIntoAcidProperty(level, EL_BALLOON,   TRUE);
+
+      for (i = 0; i < NUM_CUSTOM_ELEMENTS; i++)
+       SET_PROPERTY(EL_CUSTOM_START + i, EP_CAN_MOVE_INTO_ACID, TRUE);
+
+      for (i = 0; i < NUM_CUSTOM_ELEMENTS; i++)
+      {
+       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];
+
+         change->trigger_player = CH_PLAYER_ANY;
+         change->trigger_page = CH_PAGE_ANY;
+       }
+      }
+    }
   }
   else
   {
@@ -1021,7 +2274,7 @@ static void LoadLevel_InitVersion(struct LevelInfo *level, char *filename)
 
 static void LoadLevel_InitElements(struct LevelInfo *level, char *filename)
 {
-  int i, j;
+  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) */
@@ -1042,7 +2295,7 @@ static void LoadLevel_InitElements(struct LevelInfo *level, char *filename)
       }
 
       /* order of checking and copying events to be mapped is important */
-      for (j = CE_OTHER_GETS_COLLECTED; j >= CE_COLLISION_ACTIVE; j--)
+      for (j = CE_OTHER_GETS_COLLECTED; j >= CE_HITTING_SOMETHING; j--)
       {
        if (HAS_CHANGE_EVENT(element, j - 1))
        {
@@ -1080,6 +2333,40 @@ 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++)
+  {
+    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;
+
+    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;
+    }
+  }
+
+  /* initialize "can_explode" field for old levels which did not store this */
+  if (level->game_version <= VERSION_IDENT(3,1,0,0))
+  {
+    for (i = 0; i < NUM_CUSTOM_ELEMENTS; i++)
+    {
+      int element = EL_CUSTOM_START + i;
+
+      if (EXPLODES_1X1_OLD(element))
+       element_info[element].explosion_type = EXPLODES_1X1;
+
+      SET_PROPERTY(element, EP_CAN_EXPLODE, (EXPLODES_BY_FIRE(element) ||
+                                            EXPLODES_SMASHED(element) ||
+                                            EXPLODES_IMPACT(element)));
+    }
+  }
+
 #if 0
   /* set default push delay values (corrected since version 3.0.7-1) */
   if (level->game_version < VERSION_IDENT(3,0,7,1))
@@ -1105,6 +2392,16 @@ static void LoadLevel_InitElements(struct LevelInfo *level, char *filename)
   }
 #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->game_version);
+
   /* initialize element properties for level editor etc. */
   InitElementPropertiesEngine(level->game_version);
 }
@@ -1120,6 +2417,9 @@ static void LoadLevel_InitPlayfield(struct LevelInfo *level, char *filename)
     {
       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 */
@@ -1138,6 +2438,7 @@ static void LoadLevel_InitPlayfield(struct LevelInfo *level, char *filename)
                   element == EL_SP_GRAVITY_PORT_DOWN  ? EL_SP_PORT_DOWN  :
                   element);
       }
+#endif
 
       level->field[x][y] = element;
     }
@@ -1156,11 +2457,18 @@ static void LoadLevel_InitPlayfield(struct LevelInfo *level, char *filename)
   SetBorderElement();
 }
 
-void LoadLevelTemplate(int level_nr)
+void LoadLevelTemplate(int nr)
 {
-  char *filename = getLevelFilename(level_nr);
+#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(&level_template, filename);
+  LoadLevelFromFilename_RND(&level_template, filename);
+#endif
 
   LoadLevel_InitVersion(&level, filename);
   LoadLevel_InitElements(&level, filename);
@@ -1168,11 +2476,18 @@ void LoadLevelTemplate(int level_nr)
   ActivateLevelTemplate();
 }
 
-void LoadLevel(int level_nr)
+void LoadLevel(int nr)
 {
-  char *filename = getLevelFilename(level_nr);
+#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(&level, filename);
+  LoadLevelFromFilename_RND(&level, filename);
+#endif
 
   if (level.use_custom_template)
     LoadLevelTemplate(-1);
@@ -1225,6 +2540,18 @@ static void SaveLevel_HEAD(FILE *file, struct LevelInfo *level)
 
   putFile8Bit(file, (level->use_custom_template ? 1 : 0));
 
+  putFile8Bit(file, (level->block_last_field ? 1 : 0));
+  putFile8Bit(file, (level->sp_block_last_field ? 1 : 0));
+  putFile32BitBE(file, level->can_move_into_acid_bits);
+  putFile8Bit(file, level->dont_collide_with_bits);
+
+  putFile8Bit(file, (level->use_spring_bug ? 1 : 0));
+  putFile8Bit(file, (level->use_step_counter ? 1 : 0));
+
+  putFile8Bit(file, (level->instant_relocation ? 1 : 0));
+  putFile8Bit(file, (level->can_pass_to_walkable ? 1 : 0));
+  putFile8Bit(file, (level->grow_into_diggable ? 1 : 0));
+
   WriteUnusedBytesToFile(file, LEVEL_HEADER_UNUSED);
 }
 
@@ -1450,12 +2777,12 @@ static void SaveLevel_CUS3(FILE *file, struct LevelInfo *level,
        putFile16BitBE(file, element_info[element].change->trigger_element);
 
        putFile8Bit(file, element_info[element].change->explode);
-       putFile8Bit(file, element_info[element].change->use_content);
-       putFile8Bit(file, element_info[element].change->only_complete);
-       putFile8Bit(file, element_info[element].change->use_random_change);
+       putFile8Bit(file, element_info[element].change->use_target_content);
+       putFile8Bit(file, element_info[element].change->only_if_complete);
+       putFile8Bit(file, element_info[element].change->use_random_replace);
 
-       putFile8Bit(file, element_info[element].change->random);
-       putFile8Bit(file, element_info[element].change->power);
+       putFile8Bit(file, element_info[element].change->random_percentage);
+       putFile8Bit(file, element_info[element].change->replace_when);
 
        for (y = 0; y < 3; y++)
          for (x = 0; x < 3; x++)
@@ -1502,12 +2829,15 @@ static void SaveLevel_CUS4(FILE *file, struct LevelInfo *level, int element)
   putFile8Bit(file, ei->collect_score);
   putFile8Bit(file, ei->collect_count);
 
-  putFile16BitBE(file, ei->push_delay_fixed);
-  putFile16BitBE(file, ei->push_delay_random);
+  putFile8Bit(file, ei->drop_delay_fixed);
+  putFile8Bit(file, ei->push_delay_fixed);
+  putFile8Bit(file, ei->drop_delay_random);
+  putFile8Bit(file, ei->push_delay_random);
   putFile16BitBE(file, ei->move_delay_fixed);
   putFile16BitBE(file, ei->move_delay_random);
 
-  putFile16BitBE(file, ei->move_pattern);
+  /* bits 0 - 15 of "move_pattern" ... */
+  putFile16BitBE(file, ei->move_pattern & 0xffff);
   putFile8Bit(file, ei->move_direction_initial);
   putFile8Bit(file, ei->move_stepsize);
 
@@ -1517,8 +2847,21 @@ static void SaveLevel_CUS4(FILE *file, struct LevelInfo *level, int element)
     for (x = 0; x < 3; x++)
       putFile16BitBE(file, ei->content[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);
+
+  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, 12);
+  WriteUnusedBytesToFile(file, 1);
 
   /* write change property values */
 
@@ -1537,26 +2880,62 @@ static void SaveLevel_CUS4(FILE *file, struct LevelInfo *level, int element)
     putFile16BitBE(file, change->trigger_element);
 
     putFile8Bit(file, change->explode);
-    putFile8Bit(file, change->use_content);
-    putFile8Bit(file, change->only_complete);
-    putFile8Bit(file, change->use_random_change);
+    putFile8Bit(file, change->use_target_content);
+    putFile8Bit(file, change->only_if_complete);
+    putFile8Bit(file, change->use_random_replace);
 
-    putFile8Bit(file, change->random);
-    putFile8Bit(file, change->power);
+    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->content[x][y]);
+       putFile16BitBE(file, change->target_content[x][y]);
 
     putFile8Bit(file, change->can_change);
 
-    putFile8Bit(file, change->sides);
+    putFile8Bit(file, change->trigger_side);
+
+#if 1
+    putFile8Bit(file, change->trigger_player);
+    putFile8Bit(file, (change->trigger_page == CH_PAGE_ANY ? CH_PAGE_ANY_FILE :
+                      log_2(change->trigger_page)));
+
+    /* some free bytes for future change property values and padding */
+    WriteUnusedBytesToFile(file, 6);
+
+#else
 
     /* some free bytes for future change property values and padding */
     WriteUnusedBytesToFile(file, 8);
+#endif
   }
 }
 
+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]);
+}
+
 static void SaveLevelFromFilename(struct LevelInfo *level, char *filename)
 {
   int body_chunk_size;
@@ -1631,7 +3010,7 @@ static void SaveLevelFromFilename(struct LevelInfo *level, char *filename)
     {
       int envelope_len = strlen(level->envelope_text[i]) + 1;
 
-      putFileChunkBE(file, "CNT3", LEVEL_CHUNK_CNT3_HEADER + envelope_len);
+      putFileChunkBE(file, "CNT3", LEVEL_CHUNK_CNT3_SIZE(envelope_len));
       SaveLevel_CNT3(file, level, EL_ENVELOPE_1 + i);
     }
   }
@@ -1653,50 +3032,76 @@ static void SaveLevelFromFilename(struct LevelInfo *level, char *filename)
     }
   }
 
+  /* 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;
+
+      if (element_info[element].modified_settings)
+      {
+       putFileChunkBE(file, "GRP1", LEVEL_CHUNK_GRP1_SIZE);
+       SaveLevel_GRP1(file, level, element);
+      }
+    }
+  }
+
   fclose(file);
 
   SetFilePermissions(filename, PERMS_PRIVATE);
 }
 
-void SaveLevel(int level_nr)
+void SaveLevel(int nr)
 {
-  char *filename = getLevelFilename(level_nr);
+  char *filename = getDefaultLevelFilename(nr);
 
   SaveLevelFromFilename(&level, filename);
 }
 
 void SaveLevelTemplate()
 {
-  char *filename = getLevelFilename(-1);
+  char *filename = getDefaultLevelFilename(-1);
 
   SaveLevelFromFilename(&level, filename);
 }
 
 void DumpLevel(struct LevelInfo *level)
 {
+  if (level->no_valid_file)
+  {
+    Error(ERR_WARN, "cannot dump -- no valid level file found");
+
+    return;
+  }
+
   printf_line("-", 79);
   printf("Level xxx (file version %08d, game version %08d)\n",
         level->file_version, level->game_version);
   printf_line("-", 79);
 
-  printf("Level Author: '%s'\n", level->author);
-  printf("Level Title:  '%s'\n", level->name);
+  printf("Level author: '%s'\n", level->author);
+  printf("Level title:  '%s'\n", level->name);
   printf("\n");
-  printf("Playfield Size: %d x %d\n", level->fieldx, level->fieldy);
+  printf("Playfield size: %d x %d\n", level->fieldx, level->fieldy);
   printf("\n");
-  printf("Level Time:  %d seconds\n", level->time);
+  printf("Level time:  %d seconds\n", level->time);
   printf("Gems needed: %d\n", level->gems_needed);
   printf("\n");
-  printf("Time for Magic Wall: %d seconds\n", level->time_magic_wall);
-  printf("Time for Wheel:      %d seconds\n", level->time_wheel);
-  printf("Time for Light:      %d seconds\n", level->time_light);
-  printf("Time for Timegate:   %d seconds\n", level->time_timegate);
+  printf("Time for magic wall: %d seconds\n", level->time_magic_wall);
+  printf("Time for wheel:      %d seconds\n", level->time_wheel);
+  printf("Time for light:      %d seconds\n", level->time_light);
+  printf("Time for timegate:   %d seconds\n", level->time_timegate);
   printf("\n");
-  printf("Amoeba Speed: %d\n", level->amoeba_speed);
+  printf("Amoeba speed: %d\n", level->amoeba_speed);
   printf("\n");
-  printf("Gravity:                %s\n", (level->initial_gravity ? "yes" : "no"));
-  printf("Double Speed Movement:  %s\n", (level->double_speed ? "yes" : "no"));
-  printf("EM style slippery gems: %s\n", (level->em_slippery_gems ? "yes" : "no"));
+  printf("Initial gravity:             %s\n", (level->initial_gravity ? "yes" : "no"));
+  printf("Double speed movement:       %s\n", (level->double_speed ? "yes" : "no"));
+  printf("EM style slippery gems:      %s\n", (level->em_slippery_gems ? "yes" : "no"));
+  printf("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"));
+  printf("use spring bug: %s\n", (level->use_spring_bug ? "yes" : "no"));
+  printf("use step counter: %s\n", (level->use_step_counter ? "yes" : "no"));
 
   printf_line("-", 79);
 }
@@ -1728,6 +3133,8 @@ static void setTapeInfoToDefaults()
   tape.recording = FALSE;
   tape.playing = FALSE;
   tape.pausing = FALSE;
+
+  tape.no_valid_file = FALSE;
 }
 
 static int LoadTape_VERS(FILE *file, int chunk_size, struct TapeInfo *tape)
@@ -1892,7 +3299,15 @@ void LoadTapeFromFilename(char *filename)
   setTapeInfoToDefaults();
 
   if (!(file = fopen(filename, MODE_READ)))
+  {
+    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)
@@ -1902,6 +3317,8 @@ void LoadTapeFromFilename(char *filename)
     getFileChunkBE(file, chunk_name, NULL);
     if (strcmp(chunk_name, "TAPE") != 0)
     {
+      tape.no_valid_file = TRUE;
+
       Error(ERR_WARN, "unknown format of tape file '%s'", filename);
       fclose(file);
       return;
@@ -1916,6 +3333,8 @@ void LoadTapeFromFilename(char *filename)
 
     if (!checkCookieString(cookie, TAPE_COOKIE_TMPL))
     {
+      tape.no_valid_file = TRUE;
+
       Error(ERR_WARN, "unknown format of tape file '%s'", filename);
       fclose(file);
       return;
@@ -1923,6 +3342,8 @@ void LoadTapeFromFilename(char *filename)
 
     if ((tape.file_version = getFileVersionFromCookieString(cookie)) == -1)
     {
+      tape.no_valid_file = TRUE;
+
       Error(ERR_WARN, "unsupported version of tape file '%s'", filename);
       fclose(file);
       return;
@@ -2004,16 +3425,16 @@ void LoadTapeFromFilename(char *filename)
 #endif
 }
 
-void LoadTape(int level_nr)
+void LoadTape(int nr)
 {
-  char *filename = getTapeFilename(level_nr);
+  char *filename = getTapeFilename(nr);
 
   LoadTapeFromFilename(filename);
 }
 
-void LoadSolutionTape(int level_nr)
+void LoadSolutionTape(int nr)
 {
-  char *filename = getSolutionTapeFilename(level_nr);
+  char *filename = getSolutionTapeFilename(nr);
 
   LoadTapeFromFilename(filename);
 }
@@ -2073,9 +3494,9 @@ static void SaveTape_BODY(FILE *file, struct TapeInfo *tape)
   }
 }
 
-void SaveTape(int level_nr)
+void SaveTape(int nr)
 {
-  char *filename = getTapeFilename(level_nr);
+  char *filename = getTapeFilename(nr);
   FILE *file;
   boolean new_tape = TRUE;
   int num_participating_players = 0;
@@ -2083,7 +3504,7 @@ void SaveTape(int level_nr)
   int body_chunk_size;
   int i;
 
-  InitTapeDirectory(leveldir_current->filename);
+  InitTapeDirectory(leveldir_current->subdir);
 
   /* if a tape still exists, ask to overwrite it */
   if (access(filename, F_OK) == 0)
@@ -2139,11 +3560,21 @@ void DumpTape(struct TapeInfo *tape)
 {
   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",
@@ -2186,10 +3617,10 @@ void DumpTape(struct TapeInfo *tape)
 /* score file functions                                                      */
 /* ========================================================================= */
 
-void LoadScore(int level_nr)
+void LoadScore(int nr)
 {
   int i;
-  char *filename = getScoreFilename(level_nr);
+  char *filename = getScoreFilename(nr);
   char cookie[MAX_LINE_LEN];
   char line[MAX_LINE_LEN];
   char *line_ptr;
@@ -2239,17 +3670,17 @@ void LoadScore(int level_nr)
   fclose(file);
 }
 
-void SaveScore(int level_nr)
+void SaveScore(int nr)
 {
   int i;
-  char *filename = getScoreFilename(level_nr);
+  char *filename = getScoreFilename(nr);
   FILE *file;
 
-  InitScoreDirectory(leveldir_current->filename);
+  InitScoreDirectory(leveldir_current->subdir);
 
   if (!(file = fopen(filename, MODE_WRITE)))
   {
-    Error(ERR_WARN, "cannot save score for level %d", level_nr);
+    Error(ERR_WARN, "cannot save score for level %d", nr);
     return;
   }
 
@@ -2329,13 +3760,13 @@ void SaveScore(int level_nr)
 #define SETUP_TOKEN_PLAYER_JOY_YMIDDLE         6
 #define SETUP_TOKEN_PLAYER_JOY_YLOWER          7
 #define SETUP_TOKEN_PLAYER_JOY_SNAP            8
-#define SETUP_TOKEN_PLAYER_JOY_BOMB            9
+#define SETUP_TOKEN_PLAYER_JOY_DROP            9
 #define SETUP_TOKEN_PLAYER_KEY_LEFT            10
 #define SETUP_TOKEN_PLAYER_KEY_RIGHT           11
 #define SETUP_TOKEN_PLAYER_KEY_UP              12
 #define SETUP_TOKEN_PLAYER_KEY_DOWN            13
 #define SETUP_TOKEN_PLAYER_KEY_SNAP            14
-#define SETUP_TOKEN_PLAYER_KEY_BOMB            15
+#define SETUP_TOKEN_PLAYER_KEY_DROP            15
 
 #define NUM_PLAYER_SETUP_TOKENS                        16
 
@@ -2418,13 +3849,13 @@ static struct TokenInfo player_setup_tokens[] =
   { TYPE_INTEGER, &sii.joy.ymiddle,    ".joy.ymiddle"                  },
   { TYPE_INTEGER, &sii.joy.ylower,     ".joy.ylower"                   },
   { TYPE_INTEGER, &sii.joy.snap,       ".joy.snap_field"               },
-  { TYPE_INTEGER, &sii.joy.bomb,       ".joy.place_bomb"               },
+  { TYPE_INTEGER, &sii.joy.drop,       ".joy.place_bomb"               },
   { TYPE_KEY_X11, &sii.key.left,       ".key.move_left"                },
   { TYPE_KEY_X11, &sii.key.right,      ".key.move_right"               },
   { 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.bomb,       ".key.place_bomb"               }
+  { TYPE_KEY_X11, &sii.key.drop,       ".key.place_bomb"               }
 };
 
 static struct TokenInfo system_setup_tokens[] =
@@ -2513,13 +3944,13 @@ static void setSetupInfoToDefaults(struct SetupInfo *si)
     si->input[i].joy.ymiddle = JOYSTICK_YMIDDLE;
     si->input[i].joy.ylower  = JOYSTICK_YLOWER;
     si->input[i].joy.snap  = (i == 0 ? JOY_BUTTON_1 : 0);
-    si->input[i].joy.bomb  = (i == 0 ? JOY_BUTTON_2 : 0);
+    si->input[i].joy.drop  = (i == 0 ? JOY_BUTTON_2 : 0);
     si->input[i].key.left  = (i == 0 ? DEFAULT_KEY_LEFT  : KSYM_UNDEFINED);
     si->input[i].key.right = (i == 0 ? DEFAULT_KEY_RIGHT : KSYM_UNDEFINED);
     si->input[i].key.up    = (i == 0 ? DEFAULT_KEY_UP    : KSYM_UNDEFINED);
     si->input[i].key.down  = (i == 0 ? DEFAULT_KEY_DOWN  : KSYM_UNDEFINED);
     si->input[i].key.snap  = (i == 0 ? DEFAULT_KEY_SNAP  : KSYM_UNDEFINED);
-    si->input[i].key.bomb  = (i == 0 ? DEFAULT_KEY_BOMB  : KSYM_UNDEFINED);
+    si->input[i].key.drop  = (i == 0 ? DEFAULT_KEY_DROP  : KSYM_UNDEFINED);
   }
 
   si->system.sdl_audiodriver = getStringCopy(ARG_DEFAULT);
@@ -3040,6 +4471,7 @@ void LoadMusicInfo()
     boolean music_already_used = FALSE;
     int i;
 
+    /* skip all music files that are configured in music config file */
     for (i = 0; i < num_music; i++)
     {
       music = getMusicListEntry(i);
@@ -3389,3 +4821,117 @@ void LoadHelpTextInfo()
   END_HASH_ITERATION(hash, itr)
 #endif
 }
+
+
+/* ------------------------------------------------------------------------- *
+ * convert levels
+ * ------------------------------------------------------------------------- */
+
+#define MAX_NUM_CONVERT_LEVELS         1000
+
+void ConvertLevels()
+{
+  static LevelDirTree *convert_leveldir = NULL;
+  static int convert_level_nr = -1;
+  static int num_levels_handled = 0;
+  static int num_levels_converted = 0;
+  static boolean levels_failed[MAX_NUM_CONVERT_LEVELS];
+  int i;
+
+  convert_leveldir = getTreeInfoFromIdentifier(leveldir_first,
+                                              global.convert_leveldir);
+
+  if (convert_leveldir == NULL)
+    Error(ERR_EXIT, "no such level identifier: '%s'",
+         global.convert_leveldir);
+
+  leveldir_current = convert_leveldir;
+
+  if (global.convert_level_nr != -1)
+  {
+    convert_leveldir->first_level = global.convert_level_nr;
+    convert_leveldir->last_level  = global.convert_level_nr;
+  }
+
+  convert_level_nr = convert_leveldir->first_level;
+
+  printf_line("=", 79);
+  printf("Converting levels\n");
+  printf_line("-", 79);
+  printf("Level series identifier: '%s'\n", convert_leveldir->identifier);
+  printf("Level series name:       '%s'\n", convert_leveldir->name);
+  printf("Level series author:     '%s'\n", convert_leveldir->author);
+  printf("Number of levels:        %d\n",   convert_leveldir->levels);
+  printf_line("=", 79);
+  printf("\n");
+
+  for (i = 0; i < MAX_NUM_CONVERT_LEVELS; i++)
+    levels_failed[i] = FALSE;
+
+  while (convert_level_nr <= convert_leveldir->last_level)
+  {
+    char *level_filename;
+    boolean new_level;
+
+    level_nr = convert_level_nr++;
+
+    printf("Level %03d: ", level_nr);
+
+    LoadLevel(level_nr);
+    if (level.no_valid_file)
+    {
+      printf("(no level)\n");
+      continue;
+    }
+
+    printf("converting level ... ");
+
+    level_filename = getDefaultLevelFilename(level_nr);
+    new_level = !fileExists(level_filename);
+
+    if (new_level)
+    {
+      SaveLevel(level_nr);
+
+      num_levels_converted++;
+
+      printf("converted.\n");
+    }
+    else
+    {
+      if (level_nr >= 0 && level_nr < MAX_NUM_CONVERT_LEVELS)
+       levels_failed[level_nr] = TRUE;
+
+      printf("NOT CONVERTED -- LEVEL ALREADY EXISTS.\n");
+    }
+
+    num_levels_handled++;
+  }
+
+  printf("\n");
+  printf_line("=", 79);
+  printf("Number of levels handled: %d\n", num_levels_handled);
+  printf("Number of levels converted: %d (%d%%)\n", num_levels_converted,
+        (num_levels_handled ?
+         num_levels_converted * 100 / num_levels_handled : 0));
+  printf_line("-", 79);
+  printf("Summary (for automatic parsing by scripts):\n");
+  printf("LEVELDIR '%s', CONVERTED %d/%d (%d%%)",
+        convert_leveldir->identifier, num_levels_converted,
+        num_levels_handled,
+        (num_levels_handled ?
+         num_levels_converted * 100 / num_levels_handled : 0));
+
+  if (num_levels_handled != num_levels_converted)
+  {
+    printf(", FAILED:");
+    for (i = 0; i < MAX_NUM_CONVERT_LEVELS; i++)
+      if (levels_failed[i])
+       printf(" %03d", i);
+  }
+
+  printf("\n");
+  printf_line("=", 79);
+
+  CloseAllAndExit(0);
+}
index aa9c03e3c0d50e02cf9421b99dec9759a2f5f945..1dffbe610ef77a0af56582303f241aab4d088e72 100644 (file)
@@ -19,7 +19,8 @@
 void setElementChangePages(struct ElementInfo *, int);
 void setElementChangeInfoToDefaults(struct ElementChangeInfo *);
 
-boolean LevelFileExists(int);
+char *getDefaultLevelFilename(int);
+
 void LoadLevelFromFilename(struct LevelInfo *, char *);
 void LoadLevel(int);
 void LoadLevelTemplate(int);
@@ -46,4 +47,6 @@ void LoadMusicInfo();
 void LoadHelpAnimInfo();
 void LoadHelpTextInfo();
 
+void ConvertLevels(void);
+
 #endif /* FILES_H */
index 05e65026508d942835b1e28bd9c464b7fa2d2e8c..762035dc5656bc5479fc3158d263620b0675cb1c 100644 (file)
 
 /* for Explode() */
 #define EX_PHASE_START         0
-#define EX_NO_EXPLOSION                0
-#define EX_NORMAL              1
-#define EX_CENTER              2
-#define EX_BORDER              3
+#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_SINGLE_TILE    (EX_TYPE_CENTER | EX_TYPE_BORDER)
 
 /* special positions in the game control window (relative to control window) */
 #define XX_LEVEL               37
@@ -59,7 +61,8 @@
 #define YY_KEYS                        123
 #define XX_SCORE               15
 #define YY_SCORE               159
-#define XX_TIME                        29
+#define XX_TIME1               29
+#define XX_TIME2               30
 #define YY_TIME                        194
 
 /* special positions in the game control window (relative to main window) */
@@ -73,7 +76,8 @@
 #define DY_KEYS                        (DY + YY_KEYS)
 #define DX_SCORE               (DX + XX_SCORE)
 #define DY_SCORE               (DY + YY_SCORE)
-#define DX_TIME                        (DX + XX_TIME)
+#define DX_TIME1               (DX + XX_TIME1)
+#define DX_TIME2               (DX + XX_TIME2)
 #define DY_TIME                        (DY + YY_TIME)
 
 /* values for initial player move delay (initial delay counter value) */
 /* values for other actions */
 #define MOVE_STEPSIZE_NORMAL   (TILEX / MOVE_DELAY_NORMAL_SPEED)
 
+#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)
+
 #define        INIT_GFX_RANDOM()       (SimpleRND(1000000))
 
 #define GET_NEW_PUSH_DELAY(e)  (   (element_info[e].push_delay_fixed) + \
                                 RND(element_info[e].push_delay_random))
+#define GET_NEW_DROP_DELAY(e)  (   (element_info[e].drop_delay_fixed) + \
+                                RND(element_info[e].drop_delay_random))
 #define GET_NEW_MOVE_DELAY(e)  (   (element_info[e].move_delay_fixed) + \
                                 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 ELEMENT_CAN_ENTER_FIELD_GENERIC(e, x, y, condition)            \
+#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)
+
+#define CAN_GROW_INTO(e)                                               \
+       ((e) == EL_SAND || (IS_DIGGABLE(e) && level.grow_into_diggable))
+
+#define ELEMENT_CAN_ENTER_FIELD_BASE_X(x, y, condition)                        \
+               (IN_LEV_FIELD(x, y) && (IS_FREE(x, y) ||                \
+                                       (condition)))
+
+#define ELEMENT_CAN_ENTER_FIELD_BASE_2(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 ELEMENT_CAN_ENTER_FIELD_BASE_3(e, x, y, condition)             \
+               (IN_LEV_FIELD(x, y) && (IS_FREE_OR_PLAYER(x, y) ||      \
+                                       (CAN_MOVE_INTO_ACID(e) &&       \
+                                        Feld[x][y] == EL_ACID) ||      \
+                                       (condition)))
+
+#define ELEMENT_CAN_ENTER_FIELD_BASE_4(e, x, y, condition)             \
                (IN_LEV_FIELD(x, y) && (IS_FREE(x, y) ||                \
                                        (condition) ||                  \
+                                       (CAN_MOVE_INTO_ACID(e) &&       \
+                                        Feld[x][y] == EL_ACID) ||      \
                                        (DONT_COLLIDE_WITH(e) &&        \
-                                        IS_FREE_OR_PLAYER(x, y))))
+                                        IS_PLAYER(x, y) &&             \
+                                        !PLAYER_ENEMY_PROTECTED(x, y))))
 
-#define ELEMENT_CAN_ENTER_FIELD_GENERIC_2(x, y, condition)             \
+#if 0
+#define ELEMENT_CAN_ENTER_FIELD_GENERIC(e, x, y, condition)            \
                (IN_LEV_FIELD(x, y) && (IS_FREE(x, y) ||                \
-                                       (condition)))
+                                       (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_GENERIC(e, x, y, 0)
+       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 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 DARK_YAMYAM_CAN_ENTER_FIELD(e, x, y)                           \
+       ELEMENT_CAN_ENTER_FIELD_BASE_3(e, x,y, IS_FOOD_DARK_YAMYAM(Feld[x][y]))
 
-#define ELEMENT_CAN_ENTER_FIELD_OR_ACID(e, x, y)                       \
-       ELEMENT_CAN_ENTER_FIELD_GENERIC(e, x, y, (Feld[x][y] == EL_ACID))
+#define PACMAN_CAN_ENTER_FIELD(e, x, y)                                        \
+       ELEMENT_CAN_ENTER_FIELD_BASE_3(e, x, y, IS_AMOEBOID(Feld[x][y]))
 
-#define ELEMENT_CAN_ENTER_FIELD_OR_ACID_2(x, y)                                \
-       ELEMENT_CAN_ENTER_FIELD_GENERIC_2(x, y, (Feld[x][y] == EL_ACID))
+#define PIG_CAN_ENTER_FIELD(e, x, y)                                   \
+       ELEMENT_CAN_ENTER_FIELD_BASE_2(e, x, y, IS_FOOD_PIG(Feld[x][y]))
 
-#define ENEMY_CAN_ENTER_FIELD(x, y) (IN_LEV_FIELD(x, y) && IS_FREE(x, y))
+#define PENGUIN_CAN_ENTER_FIELD(e, x, y)                               \
+       ELEMENT_CAN_ENTER_FIELD_BASE_2(e, x, y, (Feld[x][y] == EL_EXIT_OPEN ||\
+                                                IS_FOOD_PENGUIN(Feld[x][y])))
+#define DRAGON_CAN_ENTER_FIELD(e, x, y)                                        \
+       ELEMENT_CAN_ENTER_FIELD_BASE_2(e, x, y, 0)
 
-#define YAMYAM_CAN_ENTER_FIELD(x, y)                                   \
+#define MOLE_CAN_ENTER_FIELD(e, x, y, condition)                       \
+       ELEMENT_CAN_ENTER_FIELD_BASE_2(e, x, y, (condition))
+
+#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(x, y)                              \
+#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(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(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(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 ||   \
-                                       Feld[x][y] == EL_ACID))
+                                       Feld[x][y] == EL_EXIT_OPEN))
 
-#define MAZE_RUNNER_CAN_ENTER_FIELD(x, y)                              \
+#define DRAGON_CAN_ENTER_FIELD(e, x, y)                                        \
                (IN_LEV_FIELD(x, y) && (IS_FREE(x, y) ||                \
-                                       IS_FOOD_DARK_YAMYAM(Feld[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 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))
+
+#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 MOLE_CAN_ENTER_FIELD(x, y, condition)                          \
-               (IN_LEV_FIELD(x, y) && (IS_FREE(x, y) || (condition)))
+#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))
 
 #define IN_LEV_FIELD_AND_IS_FREE(x, y)  (IN_LEV_FIELD(x, y) &&  IS_FREE(x, y))
 #define IN_LEV_FIELD_AND_NOT_FREE(x, y) (IN_LEV_FIELD(x, y) && !IS_FREE(x, y))
 
+#define ACCESS_FROM(e, d)              (element_info[e].access_direction &(d))
+#define IS_WALKABLE_FROM(e, d)         (IS_WALKABLE(e)   && ACCESS_FROM(e, d))
+#define IS_PASSABLE_FROM(e, d)         (IS_PASSABLE(e)   && ACCESS_FROM(e, d))
+#define IS_ACCESSIBLE_FROM(e, d)       (IS_ACCESSIBLE(e) && ACCESS_FROM(e, d))
+
 /* game button identifiers */
 #define GAME_CTRL_ID_STOP              0
 #define GAME_CTRL_ID_PAUSE             1
@@ -172,19 +297,45 @@ static boolean MovePlayer(struct PlayerInfo *, int, int);
 static void ScrollPlayer(struct PlayerInfo *, int);
 static void ScrollScreen(struct PlayerInfo *, int);
 
+int DigField(struct PlayerInfo *, int, int, int, int, int, int, int);
+
 static void InitBeltMovement(void);
 static void CloseAllOpenTimegates(void);
 static void CheckGravityMovement(struct PlayerInfo *);
-static void KillHeroUnlessProtected(int, int);
+static void CheckGravityMovementWhenNotMoving(struct PlayerInfo *);
+static void KillHeroUnlessEnemyProtected(int, int);
+static void KillHeroUnlessExplosionProtected(int, int);
 
 static void TestIfPlayerTouchesCustomElement(int, int);
 static void TestIfElementTouchesCustomElement(int, int);
+static void TestIfElementHitsCustomElement(int, int, int);
+#if 0
+static void TestIfElementSmashesCustomElement(int, int, int);
+#endif
 
 static void ChangeElement(int, int, int);
-static boolean CheckTriggeredElementSideChange(int, int, int, int, int);
-static boolean CheckTriggeredElementChange(int, int, int, int);
-static boolean CheckElementSideChange(int, int, int, int, int, int);
-static boolean CheckElementChange(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)
+#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)
+
+static boolean CheckElementChangeExt(int, 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)
+#define CheckElementChangeByPlayer(x, y, e, ev, p, s)                  \
+       CheckElementChangeExt(x, y, e, EL_EMPTY, ev, p, s, CH_PAGE_ANY)
+#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)
 
 static void PlayLevelSound(int, int, int);
 static void PlayLevelSoundNearest(int, int, int);
@@ -454,6 +605,48 @@ collect_count_list[] =
   { EL_UNDEFINED,              0 },
 };
 
+struct
+{
+  int element;
+  int direction;
+}
+access_direction_list[] =
+{
+  { 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 },
+
+  { EL_SP_PORT_LEFT,                             MV_RIGHT                   },
+  { EL_SP_PORT_RIGHT,                  MV_LEFT                              },
+  { EL_SP_PORT_UP,                                                  MV_DOWN },
+  { EL_SP_PORT_DOWN,                                        MV_UP           },
+  { EL_SP_PORT_HORIZONTAL,             MV_LEFT | MV_RIGHT                   },
+  { EL_SP_PORT_VERTICAL,                                    MV_UP | MV_DOWN },
+  { EL_SP_PORT_ANY,                    MV_LEFT | MV_RIGHT | MV_UP | MV_DOWN },
+  { EL_SP_GRAVITY_PORT_LEFT,                     MV_RIGHT                   },
+  { EL_SP_GRAVITY_PORT_RIGHT,          MV_LEFT                              },
+  { EL_SP_GRAVITY_PORT_UP,                                          MV_DOWN },
+  { EL_SP_GRAVITY_PORT_DOWN,                                MV_UP           },
+  { EL_SP_GRAVITY_ON_PORT_LEFT,                          MV_RIGHT                   },
+  { EL_SP_GRAVITY_ON_PORT_RIGHT,       MV_LEFT                              },
+  { EL_SP_GRAVITY_ON_PORT_UP,                                       MV_DOWN },
+  { EL_SP_GRAVITY_ON_PORT_DOWN,                                     MV_UP           },
+  { EL_SP_GRAVITY_OFF_PORT_LEFT,                 MV_RIGHT                   },
+  { EL_SP_GRAVITY_OFF_PORT_RIGHT,      MV_LEFT                              },
+  { EL_SP_GRAVITY_OFF_PORT_UP,                                      MV_DOWN },
+  { EL_SP_GRAVITY_OFF_PORT_DOWN,                            MV_UP           },
+
+  { EL_UNDEFINED,                      MV_NO_MOVING                         }
+};
+
 static unsigned long trigger_events[MAX_NUM_ELEMENTS];
 
 #define IS_AUTO_CHANGING(e)    (element_info[e].change_events & \
@@ -564,6 +757,10 @@ static void InitPlayerField(int x, int y, int element, boolean init_game)
 
     player->present = TRUE;
 
+    player->block_last_field = (element == EL_SP_MURPHY ?
+                               level.sp_block_last_field :
+                               level.block_last_field);
+
     if (!options.network || player->connected)
     {
       player->active = TRUE;
@@ -584,6 +781,7 @@ static void InitPlayerField(int x, int y, int element, boolean init_game)
     }
 
     Feld[x][y] = EL_EMPTY;
+
     player->jx = player->last_jx = x;
     player->jy = player->last_jy = y;
   }
@@ -603,6 +801,18 @@ static void InitField(int x, int y, boolean init_game)
       InitPlayerField(x, y, element, init_game);
       break;
 
+    case EL_SOKOBAN_FIELD_PLAYER:
+      element = Feld[x][y] = EL_PLAYER_1;
+      InitField(x, y, init_game);
+
+      element = Feld[x][y] = EL_SOKOBAN_FIELD_EMPTY;
+      InitField(x, y, init_game);
+      break;
+
+    case EL_SOKOBAN_FIELD_EMPTY:
+      local_player->sokobanfields_still_needed++;
+      break;
+
     case EL_STONEBLOCK:
       if (x < lev_fieldx-1 && Feld[x+1][y] == EL_ACID)
        Feld[x][y] = EL_ACID_POOL_TOPLEFT;
@@ -668,6 +878,11 @@ static void InitField(int x, int y, boolean init_game)
       break;
 
     case EL_DYNAMITE_ACTIVE:
+    case EL_SP_DISK_RED_ACTIVE:
+    case EL_DYNABOMB_PLAYER_1_ACTIVE:
+    case EL_DYNABOMB_PLAYER_2_ACTIVE:
+    case EL_DYNABOMB_PLAYER_3_ACTIVE:
+    case EL_DYNABOMB_PLAYER_4_ACTIVE:
       MovDelay[x][y] = 96;
       break;
 
@@ -675,10 +890,6 @@ static void InitField(int x, int y, boolean init_game)
       local_player->lights_still_needed++;
       break;
 
-    case EL_SOKOBAN_FIELD_EMPTY:
-      local_player->sokobanfields_still_needed++;
-      break;
-
     case EL_PENGUIN:
       local_player->friends_still_needed++;
       break;
@@ -752,28 +963,188 @@ static void InitField(int x, int y, boolean init_game)
     default:
       if (IS_CUSTOM_ELEMENT(element) && CAN_MOVE(element))
        InitMovDir(x, y);
+      else 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++;
+
+       Feld[x][y] = group->element_resolved[element_pos];
+
+       InitField(x, y, init_game);
+      }
       break;
   }
 }
 
+static inline void InitField_WithBug1(int x, int y, boolean init_game)
+{
+  InitField(x, y, init_game);
+
+  /* not needed to call InitMovDir() -- already done by InitField()! */
+  if (game.engine_version < VERSION_IDENT(3,1,0,0) &&
+      CAN_MOVE(Feld[x][y]))
+    InitMovDir(x, y);
+}
+
+static inline void InitField_WithBug2(int x, int y, boolean init_game)
+{
+  int old_element = Feld[x][y];
+
+  InitField(x, y, init_game);
+
+  /* not needed to call InitMovDir() -- already done by InitField()! */
+  if (game.engine_version < VERSION_IDENT(3,1,0,0) &&
+      CAN_MOVE(old_element) &&
+      (old_element < EL_MOLE_LEFT || old_element > EL_MOLE_DOWN))
+    InitMovDir(x, y);
+
+  /* this case is in fact a combination of not less than three bugs:
+     first, it calls InitMovDir() for elements that can move, although this is
+     already done by InitField(); then, it checks the element that was at this
+     field _before_ the call to InitField() (which can change it); lastly, it
+     was not called for "mole with direction" elements, which were treated as
+     "cannot move" due to (fixed) wrong element initialization in "src/init.c"
+  */
+}
+
+inline void DrawGameValue_Emeralds(int value)
+{
+  DrawText(DX_EMERALDS, 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);
+}
+
+inline void DrawGameValue_Keys(struct PlayerInfo *player)
+{
+  int i;
+
+  for (i = 0; i < MAX_KEYS; i++)
+    if (player->key[i])
+      DrawMiniGraphicExt(drawto, DX_KEYS + i * MINI_TILEX, DY_KEYS,
+                        el2edimg(EL_KEY_1 + i));
+}
+
+inline void DrawGameValue_Score(int value)
+{
+  DrawText(DX_SCORE, DY_SCORE, int2str(value, 5), FONT_TEXT_2);
+}
+
+inline void DrawGameValue_Time(int value)
+{
+  if (value < 1000)
+    DrawText(DX_TIME1, DY_TIME, int2str(value, 3), FONT_TEXT_2);
+  else
+    DrawText(DX_TIME2, DY_TIME, int2str(value, 4), FONT_LEVEL_NUMBER);
+}
+
+inline void DrawGameValue_Level(int value)
+{
+  if (level_nr < 100)
+    DrawText(DX_LEVEL, DY_LEVEL, int2str(value, 2), FONT_TEXT_2);
+  else
+  {
+    /* misuse area for displaying emeralds to draw bigger level number */
+    DrawTextExt(drawto, DX_EMERALDS, DY_EMERALDS,
+               int2str(value, 3), FONT_LEVEL_NUMBER, BLIT_OPAQUE);
+
+    /* now copy it to the area for displaying level number */
+    BlitBitmap(drawto, drawto,
+              DX_EMERALDS, DY_EMERALDS + 1,
+              getFontWidth(FONT_LEVEL_NUMBER) * 3,
+              getFontHeight(FONT_LEVEL_NUMBER) - 1,
+              DX_LEVEL - 1, DY_LEVEL + 1);
+
+    /* restore the area for displaying emeralds */
+    DrawGameValue_Emeralds(local_player->gems_still_needed);
+
+    /* yes, this is all really ugly :-) */
+  }
+}
+
 void DrawGameDoorValues()
 {
-  int i, j;
+  int i;
+
+  DrawGameValue_Level(level_nr);
 
   for (i = 0; i < MAX_PLAYERS; i++)
-    for (j = 0; j < 4; j++)
-      if (stored_player[i].key[j])
-       DrawMiniGraphicExt(drawto, DX_KEYS + j * MINI_TILEX, DY_KEYS,
-                          el2edimg(EL_KEY_1 + j));
+    DrawGameValue_Keys(&stored_player[i]);
+
+  DrawGameValue_Emeralds(local_player->gems_still_needed);
+  DrawGameValue_Dynamite(local_player->inventory_size);
+  DrawGameValue_Score(local_player->score);
+  DrawGameValue_Time(TimeLeft);
+}
+
+static void resolve_group_element(int group_element, int recursion_depth)
+{
+  static int group_nr;
+  static struct ElementGroupInfo *group;
+  struct ElementGroupInfo *actual_group = element_info[group_element].group;
+  int i;
+
+  if (recursion_depth > NUM_GROUP_ELEMENTS)    /* recursion too deep */
+  {
+    Error(ERR_WARN, "recursion too deep when resolving group element %d",
+         group_element - EL_GROUP_START + 1);
+
+    /* replace element which caused too deep recursion by question mark */
+    group->element_resolved[group->num_elements_resolved++] = EL_UNKNOWN;
+
+    return;
+  }
 
-  DrawText(DX + XX_EMERALDS, DY + YY_EMERALDS,
-          int2str(local_player->gems_still_needed, 3), FONT_TEXT_2);
-  DrawText(DX + XX_DYNAMITE, DY + YY_DYNAMITE,
-          int2str(local_player->inventory_size, 3), FONT_TEXT_2);
-  DrawText(DX + XX_SCORE, DY + YY_SCORE,
-          int2str(local_player->score, 5), FONT_TEXT_2);
-  DrawText(DX + XX_TIME, DY + YY_TIME,
-          int2str(TimeLeft, 3), FONT_TEXT_2);
+  if (recursion_depth == 0)                    /* initialization */
+  {
+    group = element_info[group_element].group;
+    group_nr = group_element - EL_GROUP_START;
+
+    group->num_elements_resolved = 0;
+    group->choice_pos = 0;
+  }
+
+  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;
+    }
+  }
+
+#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
 }
 
 
@@ -804,6 +1175,15 @@ static void InitGameEngine()
   printf("       => game.engine_version == %06d\n", game.engine_version);
 #endif
 
+  /* ---------- recursively resolve group elements ------------------------- */
+
+  for (i = 0; i < MAX_NUM_ELEMENTS; i++)
+    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);
+
   /* ---------- initialize player's initial move delay --------------------- */
 
   /* dynamically adjust player properties according to game engine version */
@@ -861,6 +1241,10 @@ static void InitGameEngine()
     ei->change->post_change_function = ch_delay->post_change_function;
 
     ei->change_events |= CH_EVENT_BIT(CE_DELAY);
+
+#if 1
+    SET_PROPERTY(ch_delay->element, EP_CAN_CHANGE, TRUE);
+#endif
   }
 
 #if 1
@@ -901,6 +1285,19 @@ static void InitGameEngine()
   }
 #endif
 
+  /* ---------- initialize run-time trigger player and element ------------- */
+
+  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].actual_trigger_element = EL_EMPTY;
+      ei->change_page[j].actual_trigger_player = EL_PLAYER_1;
+    }
+  }
+
   /* ---------- initialize trigger events ---------------------------------- */
 
   /* initialize trigger events information */
@@ -922,7 +1319,16 @@ static void InitGameEngine()
       {
        int trigger_element = ei->change_page[j].trigger_element;
 
-       trigger_events[trigger_element] |= ei->change_page[j].events;
+       if (IS_GROUP_ELEMENT(trigger_element))
+       {
+         struct ElementGroupInfo *group = element_info[trigger_element].group;
+
+         for (k = 0; k < group->num_elements_resolved; k++)
+           trigger_events[group->element_resolved[k]]
+             |= ei->change_page[j].events;
+       }
+       else
+         trigger_events[trigger_element] |= ei->change_page[j].events;
       }
     }
   }
@@ -955,6 +1361,19 @@ static void InitGameEngine()
     element_info[e].push_delay_random = push_delay_list[i].push_delay_random;
   }
 
+  /* set push delay value for Supaplex elements for newer engine versions */
+  if (game.engine_version >= VERSION_IDENT(3,1,0,0))
+  {
+    for (i = 0; i < MAX_NUM_ELEMENTS; i++)
+    {
+      if (IS_SP_ELEMENT(i))
+      {
+       element_info[i].push_delay_fixed  = 6;  /* just enough to escape ... */
+       element_info[i].push_delay_random = 0;  /* ... from falling zonk     */
+      }
+    }
+  }
+
   /* ---------- initialize move stepsize ----------------------------------- */
 
   /* initialize move stepsize values to default */
@@ -970,6 +1389,16 @@ static void InitGameEngine()
     element_info[e].move_stepsize = move_stepsize_list[i].move_stepsize;
   }
 
+#if 0
+  /* ---------- initialize move dig/leave ---------------------------------- */
+
+  for (i = 0; i < MAX_NUM_ELEMENTS; i++)
+  {
+    element_info[i].can_leave_element = FALSE;
+    element_info[i].can_leave_element_last = FALSE;
+  }
+#endif
+
   /* ---------- initialize gem count --------------------------------------- */
 
   /* initialize gem count values for each element */
@@ -981,6 +1410,18 @@ static void InitGameEngine()
   for (i = 0; collect_count_list[i].element != EL_UNDEFINED; i++)
     element_info[collect_count_list[i].element].collect_count =
       collect_count_list[i].count;
+
+  /* ---------- initialize access direction -------------------------------- */
+
+  /* initialize access direction values to default (access from every side) */
+  for (i = 0; i < MAX_NUM_ELEMENTS; i++)
+    if (!IS_CUSTOM_ELEMENT(i))
+      element_info[i].access_direction = MV_ALL_DIRECTIONS;
+
+  /* set access direction value for certain elements from pre-defined list */
+  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;
 }
 
 
@@ -1019,6 +1460,7 @@ void InitGame()
     struct PlayerInfo *player = &stored_player[i];
 
     player->index_nr = i;
+    player->index_bit = (1 << i);
     player->element_nr = EL_PLAYER_1 + i;
 
     player->present = FALSE;
@@ -1034,7 +1476,7 @@ void InitGame()
     player->lights_still_needed = 0;
     player->friends_still_needed = 0;
 
-    for (j = 0; j < 4; j++)
+    for (j = 0; j < MAX_KEYS; j++)
       player->key[j] = FALSE;
 
     player->dynabomb_count = 0;
@@ -1052,6 +1494,9 @@ void InitGame()
 
     player->use_murphy_graphic = FALSE;
 
+    player->block_last_field = FALSE;
+    player->can_fall_into_acid = CAN_MOVE_INTO_ACID(player->element_nr);
+
     player->actual_frame_counter = 0;
 
     player->step_counter = 0;
@@ -1060,11 +1505,13 @@ void InitGame()
 
     player->is_waiting = FALSE;
     player->is_moving = FALSE;
+    player->is_auto_moving = FALSE;
     player->is_digging = FALSE;
     player->is_snapping = FALSE;
     player->is_collecting = FALSE;
     player->is_pushing = FALSE;
     player->is_switching = FALSE;
+    player->is_dropping = FALSE;
 
     player->is_bored = FALSE;
     player->is_sleeping = FALSE;
@@ -1121,18 +1568,23 @@ void InitGame()
     player->move_delay       = game.initial_move_delay;
     player->move_delay_value = game.initial_move_delay_value;
 
+    player->move_delay_reset_counter = 0;
+
     player->push_delay = 0;
     player->push_delay_value = game.initial_push_delay_value;
 
+    player->drop_delay = 0;
+
     player->last_jx = player->last_jy = 0;
     player->jx = player->jy = 0;
 
     player->shield_normal_time_left = 0;
     player->shield_deadly_time_left = 0;
 
+    player->inventory_infinite_element = EL_UNDEFINED;
     player->inventory_size = 0;
 
-    DigField(player, 0, 0, 0, 0, DF_NO_PUSH);
+    DigField(player, 0, 0, 0, 0, 0, 0, DF_NO_PUSH);
     SnapField(player, 0, 0);
 
     player->LevelSolved = FALSE;
@@ -1141,7 +1593,7 @@ void InitGame()
 
   network_player_action_received = FALSE;
 
-#if defined(PLATFORM_UNIX)
+#if defined(NETWORK_AVALIABLE)
   /* initial null action */
   if (network_playing)
     SendToServer_MovePlayer(MV_NO_MOVING);
@@ -1153,6 +1605,7 @@ void InitGame()
   TimeFrames = 0;
   TimePlayed = 0;
   TimeLeft = level.time;
+  TapeTime = 0;
 
   ScreenMovDir = MV_NO_MOVING;
   ScreenMovPos = 0;
@@ -1174,7 +1627,7 @@ void InitGame()
 
   game.envelope_active = FALSE;
 
-  for (i = 0; i < 4; i++)
+  for (i = 0; i < NUM_BELTS; i++)
   {
     game.belt_dir[i] = MV_NO_MOVING;
     game.belt_dir_nr[i] = 3;           /* not moving, next moving left */
@@ -1195,6 +1648,7 @@ void InitGame()
       AmoebaNr[x][y] = 0;
       WasJustMoving[x][y] = 0;
       WasJustFalling[x][y] = 0;
+      CheckCollision[x][y] = 0;
       Stop[x][y] = FALSE;
       Pushed[x][y] = FALSE;
 
@@ -1202,7 +1656,8 @@ void InitGame()
       ChangeEvent[x][y] = CE_BITMASK_DEFAULT;
 
       ExplodePhase[x][y] = 0;
-      ExplodeField[x][y] = EX_NO_EXPLOSION;
+      ExplodeDelay[x][y] = 0;
+      ExplodeField[x][y] = EX_TYPE_NONE;
 
       RunnerVisit[x][y] = 0;
       PlayerVisit[x][y] = 0;
@@ -1236,8 +1691,41 @@ void InitGame()
                    emulate_sb ? EMU_SOKOBAN :
                    emulate_sp ? EMU_SUPAPLEX : EMU_NONE);
 
+  /* initialize explosion and ignition delay */
+  for (i = 0; i < MAX_NUM_ELEMENTS; i++)
+  {
+    if (!IS_CUSTOM_ELEMENT(i))
+    {
+      int num_phase = 8;
+      int delay = (((IS_SP_ELEMENT(i) && i != EL_EMPTY_SPACE) &&
+                   game.engine_version >= VERSION_IDENT(3,1,0,0)) ||
+                  game.emulation == EMU_SUPAPLEX ? 3 : 2);
+      int last_phase = (num_phase + 1) * delay;
+      int half_phase = (num_phase / 2) * delay;
+
+      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
+    if (element_info[i].explosion_delay < 1)   /* !!! check again !!! */
+      element_info[i].explosion_delay = 1;
+
+    if (element_info[i].ignition_delay < 1)    /* !!! check again !!! */
+      element_info[i].ignition_delay = 1;
+#endif
+  }
+
   /* correct non-moving belts to start moving left */
-  for (i = 0; i < 4; i++)
+  for (i = 0; i < NUM_BELTS; i++)
     if (game.belt_dir[i] == MV_NO_MOVING)
       game.belt_dir_nr[i] = 3;         /* not moving, next moving left */
 
@@ -1258,7 +1746,13 @@ void InitGame()
        {
          player->present = TRUE;
          player->active = TRUE;
+
          some_player->present = FALSE;
+         some_player->active = FALSE;
+
+#if 0
+         player->element_nr = some_player->element_nr;
+#endif
 
          StorePlayer[jx][jy] = player->element_nr;
          player->jx = player->last_jx = jx;
@@ -1272,7 +1766,7 @@ void InitGame()
 
   if (tape.playing)
   {
-    /* when playing a tape, eliminate all players who do not participate */
+    /* when playing a tape, eliminate all players which do not participate */
 
     for (i = 0; i < MAX_PLAYERS; i++)
     {
@@ -1303,6 +1797,8 @@ void InitGame()
            int jx = player->jx, jy = player->jy;
 
            player->active = FALSE;
+           player->present = FALSE;
+
            StorePlayer[jx][jy] = 0;
            Feld[jx][jy] = EL_EMPTY;
          }
@@ -1411,7 +1907,7 @@ void InitGame()
 
        for (i = 0; i < element_info[element].num_change_pages; i++)
        {
-         content = element_info[element].change_page[i].content[xx][yy];
+         content= element_info[element].change_page[i].target_content[xx][yy];
          is_player = ELEM_IS_PLAYER(content);
 
          if (is_player && (found_rating < 1 || element < found_element))
@@ -1477,19 +1973,6 @@ void InitGame()
   BlitBitmap(graphic_info[IMG_GLOBAL_DOOR].bitmap, drawto,
             DOOR_GFX_PAGEX5, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE, DX, DY);
 
-  if (level_nr < 100)
-    DrawText(DX + XX_LEVEL, DY + YY_LEVEL, int2str(level_nr, 2), FONT_TEXT_2);
-  else
-  {
-    DrawTextExt(drawto, DX + XX_EMERALDS, DY + YY_EMERALDS,
-               int2str(level_nr, 3), FONT_LEVEL_NUMBER, BLIT_OPAQUE);
-    BlitBitmap(drawto, drawto,
-              DX + XX_EMERALDS, DY + YY_EMERALDS + 1,
-              getFontWidth(FONT_LEVEL_NUMBER) * 3,
-              getFontHeight(FONT_LEVEL_NUMBER) - 1,
-              DX + XX_LEVEL - 1, DY + YY_LEVEL + 1);
-  }
-
   DrawGameDoorValues();
 
   UnmapGameButtons();
@@ -1515,7 +1998,7 @@ void InitGame()
 
   if (options.debug)
   {
-    for (i = 0; i < 4; i++)
+    for (i = 0; i < MAX_PLAYERS; i++)
       printf("Player %d %sactive.\n",
             i + 1, (stored_player[i].active ? "" : "not "));
   }
@@ -1603,29 +2086,52 @@ void InitMovDir(int x, int y)
     default:
       if (IS_CUSTOM_ELEMENT(element))
       {
-       if (element_info[element].move_direction_initial != MV_NO_MOVING)
-         MovDir[x][y] = element_info[element].move_direction_initial;
-       else if (element_info[element].move_pattern == MV_ALL_DIRECTIONS ||
-                element_info[element].move_pattern == MV_TURNING_LEFT ||
-                element_info[element].move_pattern == MV_TURNING_RIGHT)
+       struct ElementInfo *ei = &element_info[element];
+       int move_direction_initial = ei->move_direction_initial;
+       int move_pattern = ei->move_pattern;
+
+       if (move_direction_initial == MV_START_PREVIOUS)
+       {
+         if (MovDir[x][y] != MV_NO_MOVING)
+           return;
+
+         move_direction_initial = MV_START_AUTOMATIC;
+       }
+
+       if (move_direction_initial == MV_START_RANDOM)
+         MovDir[x][y] = 1 << RND(4);
+       else if (move_direction_initial & MV_ANY_DIRECTION)
+         MovDir[x][y] = move_direction_initial;
+       else if (move_pattern == MV_ALL_DIRECTIONS ||
+                move_pattern == MV_TURNING_LEFT ||
+                move_pattern == MV_TURNING_RIGHT ||
+                move_pattern == MV_TURNING_LEFT_RIGHT ||
+                move_pattern == MV_TURNING_RIGHT_LEFT ||
+                move_pattern == MV_TURNING_RANDOM)
          MovDir[x][y] = 1 << RND(4);
-       else if (element_info[element].move_pattern == MV_HORIZONTAL)
+       else if (move_pattern == MV_HORIZONTAL)
          MovDir[x][y] = (RND(2) ? MV_LEFT : MV_RIGHT);
-       else if (element_info[element].move_pattern == MV_VERTICAL)
+       else if (move_pattern == MV_VERTICAL)
          MovDir[x][y] = (RND(2) ? MV_UP : MV_DOWN);
-       else if (element_info[element].move_pattern & MV_ANY_DIRECTION)
+       else if (move_pattern & MV_ANY_DIRECTION)
          MovDir[x][y] = element_info[element].move_pattern;
-       else if (element_info[element].move_pattern == MV_ALONG_LEFT_SIDE ||
-                element_info[element].move_pattern == MV_ALONG_RIGHT_SIDE)
+       else if (move_pattern == MV_ALONG_LEFT_SIDE ||
+                move_pattern == MV_ALONG_RIGHT_SIDE)
        {
-         for (i = 0; i < 4; i++)
+#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++)
          {
            int x1 = x + xy[i][0];
            int y1 = y + xy[i][1];
 
            if (!IN_LEV_FIELD(x1, y1) || !IS_FREE(x1, y1))
            {
-             if (element_info[element].move_pattern == MV_ALONG_RIGHT_SIDE)
+             if (move_pattern == MV_ALONG_RIGHT_SIDE)
                MovDir[x][y] = direction[0][i];
              else
                MovDir[x][y] = direction[1][i];
@@ -1645,7 +2151,7 @@ void InitMovDir(int x, int y)
            element != EL_BD_FIREFLY)
          break;
 
-       for (i = 0; i < 4; i++)
+       for (i = 0; i < NUM_DIRECTIONS; i++)
        {
          int x1 = x + xy[i][0];
          int y1 = y + xy[i][1];
@@ -1730,7 +2236,9 @@ void GameWon()
        TimeLeft -= 10;
       else
        TimeLeft--;
-      DrawText(DX_TIME, DY_TIME, int2str(TimeLeft, 3), FONT_TEXT_2);
+
+      DrawGameValue_Time(TimeLeft);
+
       BackToFront();
 
       if (!tape.playing)
@@ -1756,7 +2264,9 @@ void GameWon()
        TimePlayed += 10;
       else
        TimePlayed++;
-      DrawText(DX_TIME, DY_TIME, int2str(TimePlayed, 3), FONT_TEXT_2);
+
+      DrawGameValue_Time(TimePlayed);
+
       BackToFront();
 
       if (!tape.playing)
@@ -2024,6 +2534,10 @@ static void RemoveField(int x, int y)
   ChangePage[x][y] = -1;
   Pushed[x][y] = FALSE;
 
+#if 0
+  ExplodeField[x][y] = EX_TYPE_NONE;
+#endif
+
   GfxElement[x][y] = EL_UNDEFINED;
   GfxAction[x][y] = ACTION_DEFAULT;
   GfxDir[x][y] = MV_NO_MOVING;
@@ -2041,11 +2555,28 @@ 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 (element == EL_BLOCKED)
-  {
+#else
+    if (Feld[newx][newy] != EL_BLOCKED)
+    {
+      /* element is moving, but target field is not free (blocked), but
+        already occupied by something different (example: acid pool);
+        in this case, only remove the moving field, but not the target */
+
+      RemoveField(oldx, oldy);
+
+      Store[oldx][oldy] = Store2[oldx][oldy] = 0;
+
+      DrawLevelField(oldx, oldy);
+
+      return;
+    }
+#endif
+  }
+  else if (element == EL_BLOCKED)
+  {
     Blocked2Moving(x, y, &oldx, &oldy);
     if (!IS_MOVING(oldx, oldy))
       return;
@@ -2132,42 +2663,120 @@ void CheckDynamite(int x, int y)
   Bang(x, y);
 }
 
-void RelocatePlayer(int x, int y, int element)
+void DrawRelocatePlayer(struct PlayerInfo *player)
 {
-  struct PlayerInfo *player = &stored_player[element - EL_PLAYER_1];
+  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 1
-  RemoveField(x, y);           /* temporarily remove newly placed player */
-  DrawLevelField(x, y);
-#endif
+    int offset = (setup.scroll_delay ? 3 : 0);
 
-  if (player->present)
-  {
-    while (player->MovPos)
+    if (!IN_VIS_FIELD(SCREENX(jx), SCREENY(jy)))
     {
-      ScrollPlayer(player, SCROLL_GO_ON);
-      ScrollScreen(NULL, SCROLL_GO_ON);
-      FrameCounter++;
+      scroll_x = (local_player->jx < SBX_Left  + MIDPOSX ? SBX_Left :
+                 local_player->jx > SBX_Right + MIDPOSX ? SBX_Right :
+                 local_player->jx - MIDPOSX);
 
-      DrawPlayer(player);
+      scroll_y = (local_player->jy < SBY_Upper + MIDPOSY ? SBY_Upper :
+                 local_player->jy > SBY_Lower + MIDPOSY ? SBY_Lower :
+                 local_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);
 
-      BackToFront();
-      Delay(GAME_FRAME_DELAY);
+      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);
     }
+#else
+    scroll_x += (local_player->jx - old_jx);
+    scroll_y += (local_player->jy - old_jy);
 
-    DrawPlayer(player);                /* needed here only to cleanup last field */
-    DrawLevelField(player->jx, player->jy);    /* remove player graphic */
+    /* 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);
 
-    player->is_moving = FALSE;
+    /* 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;
 
-  Feld[x][y] = element;
-  InitPlayerField(x, y, element, TRUE);
+    ScrollScreen(NULL, SCROLL_GO_ON);  /* scroll last frame to full tile */
 
-  if (player == local_player)
-  {
+    while (scroll_xx != scroll_x || scroll_yy != scroll_y)
+    {
+      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;
+
+      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);
+    }
+#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;
@@ -2184,6 +2793,14 @@ void RelocatePlayer(int x, int y, int element)
       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;
 
@@ -2196,23 +2813,176 @@ void RelocatePlayer(int x, int y, int element)
       /* scroll in two steps of half tile size to make things smoother */
       BlitBitmap(drawto_field, window, fx, fy, SXSIZE, SYSIZE, SX, SY);
       FlushDisplay();
-      Delay(GAME_FRAME_DELAY);
+      Delay(wait_delay_value);
 
       /* scroll second step to align at full tile size */
       BackToFront();
-      Delay(GAME_FRAME_DELAY);
+      Delay(wait_delay_value);
+    }
+#endif
+
+    DrawPlayer(player);
+    BackToFront();
+    Delay(wait_delay_value);
+  }
+}
+
+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];
+  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 old_jx = player->jx;
+  int old_jy = player->jy;
+  int old_element = Feld[old_jx][old_jy];
+  int element = Feld[jx][jy];
+  boolean player_relocated = (old_jx != jx || old_jy != jy);
+
+  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;
+
+  if (player->GameOver)                /* do not reanimate dead player */
+    return;
+
+  if (!player_relocated)       /* no need to relocate the player */
+    return;
+
+  if (IS_PLAYER(jx, jy))       /* player already placed at new position */
+  {
+    RemoveField(jx, jy);       /* temporarily remove newly placed player */
+    DrawLevelField(jx, jy);
+  }
+
+  if (player->present)
+  {
+    while (player->MovPos)
+    {
+      ScrollPlayer(player, SCROLL_GO_ON);
+      ScrollScreen(NULL, SCROLL_GO_ON);
+      FrameCounter++;
+
+      DrawPlayer(player);
+
+      BackToFront();
+      Delay(wait_delay_value);
     }
+
+    DrawPlayer(player);                /* needed here only to cleanup last field */
+    DrawLevelField(player->jx, player->jy);    /* remove player graphic */
+
+    player->is_moving = FALSE;
+  }
+
+#if 1
+  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_OTHER_GETS_LEFT,
+                                     player->index_bit, leave_side);
+#endif
+
+  Feld[jx][jy] = el_player;
+  InitPlayerField(jx, jy, el_player, TRUE);
+
+  if (!ELEM_IS_PLAYER(element))        /* player may be set on walkable element */
+  {
+    Feld[jx][jy] = element;
+    InitField(jx, jy, FALSE);
   }
+
+#if 1
+  if (player == local_player)  /* only visually relocate local player */
+    DrawRelocatePlayer(player);
+#endif
+
+#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) */
+#else
+  /* needed to allow change of walkable custom element by entering player */
+  Changed[jx][jy] = 0;         /* allow another change */
+#endif
+#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
+
+#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_OTHER_GETS_ENTERED,
+                                     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
+
+  /* !!! 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)
   {
@@ -2224,15 +2994,20 @@ void Explode(int ex, int ey, int phase, int mode)
   {
     int center_element = Feld[ex][ey];
 
+#if 0
+    printf("::: start explosion %d,%d [%d]\n", ex, ey, FrameCounter);
+#endif
+
 #if 0
     /* --- This is only really needed (and now handled) in "Impact()". --- */
     /* do not explode moving elements that left the explode field in time */
     if (game.engine_version >= VERSION_IDENT(2,2,0,7) &&
-       center_element == EL_EMPTY && (mode == EX_NORMAL || mode == EX_CENTER))
+       center_element == EL_EMPTY &&
+       (mode == EX_TYPE_NORMAL || mode == EX_TYPE_CENTER))
       return;
 #endif
 
-    if (mode == EX_NORMAL || mode == EX_CENTER)
+    if (mode == EX_TYPE_NORMAL || mode == EX_TYPE_CENTER)
       PlayLevelSoundAction(ex, ey, ACTION_EXPLODING);
 
     /* remove things displayed in background while burning dynamite */
@@ -2247,16 +3022,43 @@ void Explode(int ex, int ey, int phase, int mode)
       Feld[ex][ey] = center_element;
     }
 
+#if 1
+
+#if 1
+    last_phase = element_info[center_element].explosion_delay + 1;
+#else
+    last_phase = element_info[center_element].explosion_delay;
+#endif
+
+#if 0
+    printf("::: %d -> %d\n", center_element, last_phase);
+#endif
+#endif
+
     for (y = ey - 1; y <= ey + 1; y++) for (x = ex - 1; x <= ex + 1; x++)
     {
       int xx = x - ex + 1;
       int yy = y - ey + 1;
       int element;
 
+#if 1
+#if 1
       if (!IN_LEV_FIELD(x, y) ||
-         ((mode != EX_NORMAL || center_element == EL_AMOEBA_TO_DIAMOND) &&
+         (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];
 
@@ -2275,10 +3077,17 @@ void Explode(int ex, int ey, int phase, int mode)
        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) &&
@@ -2288,13 +3097,30 @@ void Explode(int ex, int ey, int phase, int mode)
        continue;
 #endif
 
+#if 1
+      if (IS_PLAYER(x, y) && SHIELD_ON(PLAYERINFO(x, y)) &&
+         (game.engine_version < VERSION_IDENT(3,1,0,0) ||
+          (x == ex && y == ey && mode != EX_TYPE_BORDER)))
+#else
       if (IS_PLAYER(x, y) && SHIELD_ON(PLAYERINFO(x, y)))
+#endif
       {
        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;
@@ -2304,9 +3130,21 @@ void Explode(int ex, int ey, int phase, int mode)
 #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 */
@@ -2326,27 +3164,32 @@ void Explode(int ex, int ey, int phase, int mode)
       RemoveField(x, y);
 #endif
 
-      if (IS_PLAYER(ex, ey) && !PLAYER_PROTECTED(ex, ey))
+      if (IS_PLAYER(ex, ey) && !PLAYER_EXPLOSION_PROTECTED(ex, ey))
       {
        switch(StorePlayer[ex][ey])
        {
          case EL_PLAYER_2:
-           Store[x][y] = EL_EMERALD_RED;
+           Store[x][y] = EL_PLAYER_IS_EXPLODING_2;
            break;
          case EL_PLAYER_3:
-           Store[x][y] = EL_EMERALD;
+           Store[x][y] = EL_PLAYER_IS_EXPLODING_3;
            break;
          case EL_PLAYER_4:
-           Store[x][y] = EL_EMERALD_PURPLE;
+           Store[x][y] = EL_PLAYER_IS_EXPLODING_4;
            break;
          case EL_PLAYER_1:
          default:
-           Store[x][y] = EL_EMERALD_YELLOW;
+           Store[x][y] = EL_PLAYER_IS_EXPLODING_1;
            break;
        }
 
+#if 1
+       if (PLAYERINFO(ex, ey)->use_murphy_graphic)
+         Store[x][y] = EL_EMPTY;
+#else
        if (game.emulation == EMU_SUPAPLEX)
          Store[x][y] = EL_EMPTY;
+#endif
       }
       else if (center_element == EL_MOLE)
        Store[x][y] = EL_EMERALD_RED;
@@ -2386,10 +3229,15 @@ void Explode(int ex, int ey, int phase, int mode)
       else
        Store[x][y] = EL_EMPTY;
 
-      if (x != ex || y != ey ||
-         center_element == EL_AMOEBA_TO_DIAMOND || mode == EX_BORDER)
+      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
+
 #if 0
       if (AmoebaNr[x][y] &&
          (element == EL_AMOEBA_FULL ||
@@ -2417,6 +3265,18 @@ void Explode(int ex, int ey, int phase, int mode)
 #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;
     }
 
@@ -2424,6 +3284,11 @@ 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;
   }
 
@@ -2433,25 +3298,125 @@ 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);
 
 #ifdef DEBUG
 
-  /* activate this even in non-DEBUG version until cause for crash in
-     getGraphicAnimationFrame() (see below) is found and eliminated */
+  /* activate this even in non-DEBUG version until cause for crash in
+     getGraphicAnimationFrame() (see below) is found and eliminated */
+#endif
+#if 1
+
+  if (GfxElement[x][y] == EL_UNDEFINED)
+  {
+    printf("\n\n");
+    printf("Explode(): x = %d, y = %d: GfxElement == EL_UNDEFINED\n", x, y);
+    printf("Explode(): This should never happen!\n");
+    printf("\n\n");
+
+    GfxElement[x][y] = EL_EMPTY;
+  }
+#endif
+
+#if 1
+
+  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);
+      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
-#if 1
+    }
+    else if (border_element == EL_AMOEBA_TO_DIAMOND)
+    {
+      AmoebeUmwandeln(x, y);
+      Store2[x][y] = 0;
+      border_explosion = TRUE;
 
-  if (GfxElement[x][y] == EL_UNDEFINED)
-  {
-    printf("\n\n");
-    printf("Explode(): x = %d, y = %d: GfxElement == EL_UNDEFINED\n", x, y);
-    printf("Explode(): This should never happen!\n");
-    printf("\n\n");
+#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
+    }
 
-    GfxElement[x][y] = EL_EMPTY;
-  }
+#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)
   {
@@ -2469,8 +3434,8 @@ void Explode(int ex, int ey, int phase, int mode)
     int element = Store2[x][y];
 
     if (IS_PLAYER(x, y))
-      KillHeroUnlessProtected(x, y);
-    else if (CAN_EXPLODE_BY_FIRE(element))
+      KillHeroUnlessExplosionProtected(x, y);
+    else if (CAN_EXPLODE_BY_EXPLOSION(element))
     {
       Feld[x][y] = Store2[x][y];
       Store2[x][y] = 0;
@@ -2479,15 +3444,35 @@ void Explode(int ex, int ey, int phase, int mode)
     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;
 
+    /* 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);
+
+    /* restore probably existing indestructible background element */
     if (Back[x][y] && IS_INDESTRUCTIBLE(Back[x][y]))
       element = Feld[x][y] = Back[x][y];
     Back[x][y] = 0;
@@ -2497,9 +3482,22 @@ void Explode(int ex, int ey, int phase, int mode)
     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
+#endif
     DrawLevelField(x, y);
 
     TestIfElementTouchesCustomElement(x, y);
@@ -2507,13 +3505,17 @@ void Explode(int ex, int ey, int phase, int mode)
     if (GFX_CRUMBLED(element))
       DrawLevelFieldCrumbledSandNeighbours(x, y);
 
-    if (IS_PLAYER(x, y) && !PLAYERINFO(x,y)->present)
+    if (IS_PLAYER(x, y) && !PLAYERINFO(x, y)->present)
       StorePlayer[x][y] = 0;
 
     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);
@@ -2523,7 +3525,26 @@ void Explode(int ex, int ey, int phase, int mode)
                   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);
@@ -2546,6 +3567,7 @@ void Explode(int ex, int ey, int phase, int mode)
 void DynaExplode(int ex, int ey)
 {
   int i, j;
+  int dynabomb_element = Feld[ex][ey];
   int dynabomb_size = 1;
   boolean dynabomb_xl = FALSE;
   struct PlayerInfo *player;
@@ -2557,22 +3579,22 @@ void DynaExplode(int ex, int ey)
     { 0, +1 }
   };
 
-  if (IS_ACTIVE_BOMB(Feld[ex][ey]))
+  if (IS_ACTIVE_BOMB(dynabomb_element))
   {
-    player = &stored_player[Feld[ex][ey] - EL_DYNABOMB_PLAYER_1_ACTIVE];
+    player = &stored_player[dynabomb_element - EL_DYNABOMB_PLAYER_1_ACTIVE];
     dynabomb_size = player->dynabomb_size;
     dynabomb_xl = player->dynabomb_xl;
     player->dynabombs_left++;
   }
 
-  Explode(ex, ey, EX_PHASE_START, EX_CENTER);
+  Explode(ex, ey, EX_PHASE_START, EX_TYPE_CENTER);
 
-  for (i = 0; i < 4; i++)
+  for (i = 0; i < NUM_DIRECTIONS; i++)
   {
     for (j = 1; j <= dynabomb_size; j++)
     {
-      int x = ex + j * xy[i % 4][0];
-      int y = ey + j * xy[i % 4][1];
+      int x = ex + j * xy[i][0];
+      int y = ey + j * xy[i][1];
       int element;
 
       if (!IN_LEV_FIELD(x, y) || IS_INDESTRUCTIBLE(Feld[x][y]))
@@ -2584,14 +3606,24 @@ void DynaExplode(int ex, int ey)
       if (element == EL_EXPLOSION && IS_ACTIVE_BOMB(Store2[x][y]))
        continue;
 
-      Explode(x, y, EX_PHASE_START, EX_BORDER);
+      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_SAND &&
-         element != EL_EXPLOSION &&
-         !dynabomb_xl)
+      if (element != EL_EMPTY && element != EL_EXPLOSION &&
+         element != EL_SAND && !dynabomb_xl)
        break;
+#endif
     }
   }
 }
@@ -2605,7 +3637,7 @@ void Bang(int x, int y)
 #endif
 
 #if 1
-  if (IS_PLAYER(x, y) && !PLAYER_PROTECTED(x, y))
+  if (IS_PLAYER(x, y) && !PLAYER_EXPLOSION_PROTECTED(x, y))
 #else
   if (IS_PLAYER(x, y))
 #endif
@@ -2644,7 +3676,7 @@ void Bang(int x, int y)
     case EL_PACMAN:
     case EL_MOLE:
       RaiseScoreElement(element);
-      Explode(x, y, EX_PHASE_START, EX_NORMAL);
+      Explode(x, y, EX_PHASE_START, EX_TYPE_NORMAL);
       break;
     case EL_DYNABOMB_PLAYER_1_ACTIVE:
     case EL_DYNABOMB_PLAYER_2_ACTIVE:
@@ -2658,16 +3690,33 @@ void Bang(int x, int y)
     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_NORMAL);
+       Explode(x, y, EX_PHASE_START, EX_TYPE_NORMAL);
       else
-       Explode(x, y, EX_PHASE_START, EX_CENTER);
+       Explode(x, y, EX_PHASE_START, EX_TYPE_CENTER);
       break;
     default:
-      if (CAN_EXPLODE_1X1(element))
-       Explode(x, y, EX_PHASE_START, EX_CENTER);
+#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
+      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_NORMAL);
+       Explode(x, y, EX_PHASE_START, EX_TYPE_NORMAL);
       break;
   }
 
@@ -2676,23 +3725,42 @@ void Bang(int x, int y)
 
 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))))
+    Feld[x - 1][y - 1] = EL_ACID_SPLASH_LEFT;
+
+  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))))
+    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_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;
+    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()
@@ -2715,11 +3783,11 @@ static void InitBeltMovement()
   int x, y, i, j;
 
   /* set frame order for belt animation graphic according to belt direction */
-  for (i = 0; i < 4; i++)
+  for (i = 0; i < NUM_BELTS; i++)
   {
     int belt_nr = i;
 
-    for (j = 0; j < 3; j++)
+    for (j = 0; j < NUM_BELT_PARTS; j++)
     {
       int element = belt_base_active_element[belt_nr] + j;
       int graphic = el2img(element);
@@ -2737,7 +3805,7 @@ static void InitBeltMovement()
     {
       int element = Feld[x][y];
 
-      for (i = 0; i < 4; i++)
+      for (i = 0; i < NUM_BELTS; i++)
       {
        if (IS_BELT(element) && game.belt_dir[i] != MV_NO_MOVING)
        {
@@ -2803,7 +3871,7 @@ static void ToggleBeltSwitch(int x, int y)
     belt_dir_nr = 1;
 
   /* set frame order for belt animation graphic according to belt direction */
-  for (i = 0; i < 3; i++)
+  for (i = 0; i < NUM_BELT_PARTS; i++)
   {
     int element = belt_base_active_element[belt_nr] + i;
     int graphic = el2img(element);
@@ -3017,11 +4085,19 @@ inline static int getElementMoveStepsize(int x, int y)
   /* special values for move stepsize for spring and things on conveyor belt */
   if (horiz_move)
   {
+#if 0
+    if (element == EL_SPRING)
+      step = sign * MOVE_STEPSIZE_NORMAL * 2;
+    else if (CAN_FALL(element) && !CAN_MOVE(element) &&
+            y < lev_fieldy - 1 && IS_BELT_ACTIVE(Feld[x][y + 1]))
+      step = sign * MOVE_STEPSIZE_NORMAL / 2;
+#else
     if (CAN_FALL(element) &&
        y < lev_fieldy - 1 && IS_BELT_ACTIVE(Feld[x][y + 1]))
       step = sign * MOVE_STEPSIZE_NORMAL / 2;
     else if (element == EL_SPRING)
       step = sign * MOVE_STEPSIZE_NORMAL * 2;
+#endif
   }
 
   return step;
@@ -3033,7 +4109,7 @@ void Impact(int x, int y)
   boolean object_hit = FALSE;
   boolean impact = (lastline || object_hit);
   int element = Feld[x][y];
-  int smashed = EL_UNDEFINED;
+  int smashed = EL_STEELWALL;
 
   if (!lastline)       /* check if element below was hit */
   {
@@ -3044,6 +4120,10 @@ 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)
@@ -3057,10 +4137,11 @@ void Impact(int x, int y)
 
   if (!lastline && smashed == EL_ACID) /* element falls into acid */
   {
-    SplashAcid(x, y);
+    SplashAcid(x, y + 1);
     return;
   }
 
+  /* !!! not sufficient for all cases -- see EL_PEARL below !!! */
   /* only reset graphic animation if graphic really changes after impact */
   if (impact &&
       el_act_dir2img(element, GfxAction[x][y], MV_DOWN) != el2img(element))
@@ -3076,11 +4157,13 @@ void Impact(int x, int y)
   }
   else if (impact && element == EL_PEARL)
   {
+    ResetGfxAnimation(x, y);
+
     Feld[x][y] = EL_PEARL_BREAKING;
     PlayLevelSound(x, y, SND_PEARL_BREAKING);
     return;
   }
-  else if (impact && CheckElementChange(x, y, element, CE_IMPACT))
+  else if (impact && CheckElementChange(x, y, element, smashed, CE_IMPACT))
   {
     PlayLevelSoundElementAction(x, y, element, ACTION_IMPACT);
 
@@ -3090,7 +4173,7 @@ void Impact(int x, int y)
   if (impact && element == EL_AMOEBA_DROP)
   {
     if (object_hit && IS_PLAYER(x, y + 1))
-      KillHeroUnlessProtected(x, y + 1);
+      KillHeroUnlessEnemyProtected(x, y + 1);
     else if (object_hit && smashed == EL_PENGUIN)
       Bang(x, y + 1);
     else
@@ -3132,7 +4215,7 @@ void Impact(int x, int y)
     {
       if (CAN_SMASH_PLAYER(element))
       {
-       KillHeroUnlessProtected(x, y + 1);
+       KillHeroUnlessEnemyProtected(x, y + 1);
        return;
       }
     }
@@ -3152,11 +4235,13 @@ void Impact(int x, int y)
        return;
       }
     }
-    else if ((element == EL_SP_INFOTRON ||
-             element == EL_SP_ZONK) &&
-            (smashed == EL_SP_SNIKSNAK ||
-             smashed == EL_SP_ELECTRON ||
-             smashed == EL_SP_DISK_ORANGE))
+    else if (((element == EL_SP_INFOTRON ||
+              element == EL_SP_ZONK) &&
+             (smashed == EL_SP_SNIKSNAK ||
+              smashed == EL_SP_ELECTRON ||
+              smashed == EL_SP_DISK_ORANGE)) ||
+            (element == EL_SP_INFOTRON &&
+             smashed == EL_SP_DISK_YELLOW))
     {
       Bang(x, y + 1);
       return;
@@ -3193,6 +4278,8 @@ void Impact(int x, int y)
        }
        else if (smashed == EL_PEARL)
        {
+         ResetGfxAnimation(x, y);
+
          Feld[x][y + 1] = EL_PEARL_BREAKING;
          PlayLevelSound(x, y, SND_PEARL_BREAKING);
          return;
@@ -3219,17 +4306,29 @@ void Impact(int x, int y)
        }
        else
        {
-         CheckElementChange(x, y + 1, smashed, CE_SMASHED);
+#if 0
+         TestIfElementSmashesCustomElement(x, y, MV_DOWN);
+#endif
+
+         CheckElementChange(x, y + 1, smashed, element, CE_SMASHED);
 
-         CheckTriggeredElementSideChange(x, y + 1, smashed, CH_SIDE_TOP,
-                                         CE_OTHER_IS_SWITCHING);
-         CheckElementSideChange(x, y + 1, smashed, CH_SIDE_TOP,
-                                CE_SWITCHED, -1);
+#if 1
+         /* !!! TEST ONLY !!! */
+         CheckElementChangeBySide(x, y + 1, smashed, element,
+                                  CE_SWITCHED, CH_SIDE_TOP);
+         CheckTriggeredElementChangeBySide(x, y + 1, smashed,
+                                           CE_OTHER_IS_SWITCHING,CH_SIDE_TOP);
+#else
+         CheckTriggeredElementChangeBySide(x, y + 1, smashed,
+                                           CE_OTHER_IS_SWITCHING,CH_SIDE_TOP);
+         CheckElementChangeBySide(x, y + 1, smashed, element,
+                                  CE_SWITCHED, CH_SIDE_TOP);
+#endif
        }
       }
       else
       {
-       CheckElementChange(x, y + 1, smashed, CE_SMASHED);
+       CheckElementChange(x, y + 1, smashed, element, CE_SMASHED);
       }
     }
   }
@@ -3306,9 +4405,9 @@ inline static void TurnRoundExt(int x, int y)
   {
     TestIfBadThingTouchesOtherBadThing(x, y);
 
-    if (ENEMY_CAN_ENTER_FIELD(right_x, right_y))
+    if (ENEMY_CAN_ENTER_FIELD(element, right_x, right_y))
       MovDir[x][y] = right_dir;
-    else if (!ENEMY_CAN_ENTER_FIELD(move_x, move_y))
+    else if (!ENEMY_CAN_ENTER_FIELD(element, move_x, move_y))
       MovDir[x][y] = left_dir;
 
     if (element == EL_BUG && MovDir[x][y] != old_move_dir)
@@ -3316,14 +4415,15 @@ 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(left_x, left_y))
+    if (ENEMY_CAN_ENTER_FIELD(element, left_x, left_y))
       MovDir[x][y] = left_dir;
-    else if (!ENEMY_CAN_ENTER_FIELD(move_x, move_y))
+    else if (!ENEMY_CAN_ENTER_FIELD(element, move_x, move_y))
       MovDir[x][y] = right_dir;
 
     if ((element == EL_SPACESHIP ||
@@ -3334,10 +4434,38 @@ inline static void TurnRoundExt(int x, int y)
     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);
+
+    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        && 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 if (element == EL_SP_SNIKSNAK || element == EL_SP_ELECTRON)
+  {
+    TestIfBadThingTouchesOtherBadThing(x, y);
+
+    if (ELEMENT_CAN_ENTER_FIELD_BASE_4(element, left_x, left_y, 0))
+      MovDir[x][y] = left_dir;
+    else if (!ELEMENT_CAN_ENTER_FIELD_BASE_4(element, move_x, move_y, 0))
+      MovDir[x][y] = right_dir;
+
+    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(left_x, left_y);
-    boolean can_turn_right = YAMYAM_CAN_ENTER_FIELD(right_x, right_y);
+    boolean can_turn_left  = YAMYAM_CAN_ENTER_FIELD(element, left_x, left_y);
+    boolean can_turn_right = YAMYAM_CAN_ENTER_FIELD(element, right_x, right_y);
 
     if (can_turn_left && can_turn_right)
       MovDir[x][y] = (RND(3) ? (RND(2) ? left_dir : right_dir) : back_dir);
@@ -3352,8 +4480,10 @@ inline static void TurnRoundExt(int x, int y)
   }
   else if (element == EL_DARK_YAMYAM)
   {
-    boolean can_turn_left  = DARK_YAMYAM_CAN_ENTER_FIELD(left_x, left_y);
-    boolean can_turn_right = DARK_YAMYAM_CAN_ENTER_FIELD(right_x, right_y);
+    boolean can_turn_left  = DARK_YAMYAM_CAN_ENTER_FIELD(element,
+                                                        left_x, left_y);
+    boolean can_turn_right = DARK_YAMYAM_CAN_ENTER_FIELD(element,
+                                                        right_x, right_y);
 
     if (can_turn_left && can_turn_right)
       MovDir[x][y] = (RND(3) ? (RND(2) ? left_dir : right_dir) : back_dir);
@@ -3368,8 +4498,8 @@ inline static void TurnRoundExt(int x, int y)
   }
   else if (element == EL_PACMAN)
   {
-    boolean can_turn_left  = PACMAN_CAN_ENTER_FIELD(left_x, left_y);
-    boolean can_turn_right = PACMAN_CAN_ENTER_FIELD(right_x, right_y);
+    boolean can_turn_left  = PACMAN_CAN_ENTER_FIELD(element, left_x, left_y);
+    boolean can_turn_right = PACMAN_CAN_ENTER_FIELD(element, right_x, right_y);
 
     if (can_turn_left && can_turn_right)
       MovDir[x][y] = (RND(3) ? (RND(2) ? left_dir : right_dir) : back_dir);
@@ -3384,9 +4514,9 @@ inline static void TurnRoundExt(int x, int y)
   }
   else if (element == EL_PIG)
   {
-    boolean can_turn_left  = PIG_CAN_ENTER_FIELD(left_x, left_y);
-    boolean can_turn_right = PIG_CAN_ENTER_FIELD(right_x, right_y);
-    boolean can_move_on    = PIG_CAN_ENTER_FIELD(move_x, move_y);
+    boolean can_turn_left  = PIG_CAN_ENTER_FIELD(element, left_x, left_y);
+    boolean can_turn_right = PIG_CAN_ENTER_FIELD(element, right_x, right_y);
+    boolean can_move_on    = PIG_CAN_ENTER_FIELD(element, move_x, move_y);
     boolean should_turn_left, should_turn_right, should_move_on;
     int rnd_value = 24;
     int rnd = RND(rnd_value);
@@ -3447,9 +4577,9 @@ inline static void TurnRoundExt(int x, int y)
   }
   else if (element == EL_DRAGON)
   {
-    boolean can_turn_left  = IN_LEV_FIELD_AND_IS_FREE(left_x, left_y);
-    boolean can_turn_right = IN_LEV_FIELD_AND_IS_FREE(right_x, right_y);
-    boolean can_move_on    = IN_LEV_FIELD_AND_IS_FREE(move_x, move_y);
+    boolean can_turn_left  = DRAGON_CAN_ENTER_FIELD(element, left_x, left_y);
+    boolean can_turn_right = DRAGON_CAN_ENTER_FIELD(element, right_x, right_y);
+    boolean can_move_on    = DRAGON_CAN_ENTER_FIELD(element, move_x, move_y);
     int rnd_value = 24;
     int rnd = RND(rnd_value);
 
@@ -3497,17 +4627,17 @@ inline static void TurnRoundExt(int x, int y)
   else if (element == EL_MOLE)
   {
     boolean can_move_on =
-      (MOLE_CAN_ENTER_FIELD(move_x, move_y,
+      (MOLE_CAN_ENTER_FIELD(element, move_x, move_y,
                            IS_AMOEBOID(Feld[move_x][move_y]) ||
                            Feld[move_x][move_y] == EL_AMOEBA_SHRINKING));
     if (!can_move_on)
     {
       boolean can_turn_left =
-       (MOLE_CAN_ENTER_FIELD(left_x, left_y,
+       (MOLE_CAN_ENTER_FIELD(element, left_x, left_y,
                              IS_AMOEBOID(Feld[left_x][left_y])));
 
       boolean can_turn_right =
-       (MOLE_CAN_ENTER_FIELD(right_x, right_y,
+       (MOLE_CAN_ENTER_FIELD(element, right_x, right_y,
                              IS_AMOEBOID(Feld[right_x][right_y])));
 
       if (can_turn_left && can_turn_right)
@@ -3528,10 +4658,16 @@ inline static void TurnRoundExt(int x, int y)
   }
   else if (element == EL_SPRING)
   {
+#if 0
     if (MovDir[x][y] & MV_HORIZONTAL &&
-       (!IN_LEV_FIELD_AND_IS_FREE(move_x, move_y) ||
-        IN_LEV_FIELD_AND_IS_FREE(x, y + 1)))
+       !SPRING_CAN_ENTER_FIELD(element, move_x, move_y))
       MovDir[x][y] = MV_NO_MOVING;
+#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;
+#endif
 
     MovDelay[x][y] = 0;
   }
@@ -3567,7 +4703,13 @@ 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;
@@ -3584,10 +4726,10 @@ inline static void TurnRoundExt(int x, int y)
        { 0, +1 }
       };
 
-      for (i = 0; i < 4; i++)
+      for (i = 0; i < NUM_DIRECTIONS; i++)
       {
-       int ex = x + xy[i % 4][0];
-       int ey = y + xy[i % 4][1];
+       int ex = x + xy[i][0];
+       int ey = y + xy[i][1];
 
        if (IN_LEV_FIELD(ex, ey) && Feld[ex][ey] == EL_EXIT_OPEN)
        {
@@ -3636,14 +4778,14 @@ 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(newx, newy))
+       if (PENGUIN_CAN_ENTER_FIELD(EL_PENGUIN, 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(newx, newy))
+       if (PENGUIN_CAN_ENTER_FIELD(EL_PENGUIN, newx, newy))
          return;
 
        MovDir[x][y] = old_move_dir;
@@ -3665,14 +4807,14 @@ inline static void TurnRoundExt(int x, int y)
          new_move_dir & (first_horiz ? MV_HORIZONTAL : MV_VERTICAL);
        Moving2Blocked(x, y, &newx, &newy);
 
-       if (ELEMENT_CAN_ENTER_FIELD_OR_ACID_2(newx, newy))
+       if (SATELLITE_CAN_ENTER_FIELD(newx, newy))
          return;
 
        MovDir[x][y] =
          new_move_dir & (!first_horiz ? MV_HORIZONTAL : MV_VERTICAL);
        Moving2Blocked(x, y, &newx, &newy);
 
-       if (ELEMENT_CAN_ENTER_FIELD_OR_ACID_2(newx, newy))
+       if (SATELLITE_CAN_ENTER_FIELD(newx, newy))
          return;
 
        MovDir[x][y] = old_move_dir;
@@ -3680,17 +4822,30 @@ inline static void TurnRoundExt(int x, int y)
       }
     }
   }
-  else if (move_pattern == MV_ALL_DIRECTIONS ||
-          move_pattern == MV_TURNING_LEFT ||
-          move_pattern == MV_TURNING_RIGHT)
+  else if (move_pattern == MV_TURNING_LEFT ||
+          move_pattern == MV_TURNING_RIGHT ||
+          move_pattern == MV_TURNING_LEFT_RIGHT ||
+          move_pattern == MV_TURNING_RIGHT_LEFT ||
+          move_pattern == MV_TURNING_RANDOM ||
+          move_pattern == MV_ALL_DIRECTIONS)
   {
-    boolean can_turn_left  = ELEMENT_CAN_ENTER_FIELD(element, left_x, left_y);
-    boolean can_turn_right = ELEMENT_CAN_ENTER_FIELD(element, right_x,right_y);
+    boolean can_turn_left =
+      CUSTOM_ELEMENT_CAN_ENTER_FIELD(element, left_x, left_y);
+    boolean can_turn_right =
+      CUSTOM_ELEMENT_CAN_ENTER_FIELD(element, right_x,right_y);
 
     if (move_pattern == MV_TURNING_LEFT)
       MovDir[x][y] = left_dir;
     else if (move_pattern == MV_TURNING_RIGHT)
       MovDir[x][y] = right_dir;
+    else if (move_pattern == MV_TURNING_LEFT_RIGHT)
+      MovDir[x][y] = (can_turn_left || !can_turn_right ? left_dir : right_dir);
+    else if (move_pattern == MV_TURNING_RIGHT_LEFT)
+      MovDir[x][y] = (can_turn_right || !can_turn_left ? right_dir : left_dir);
+    else if (move_pattern == MV_TURNING_RANDOM)
+      MovDir[x][y] = (can_turn_left && !can_turn_right ? left_dir :
+                     can_turn_right && !can_turn_left ? right_dir :
+                     RND(2) ? left_dir : right_dir);
     else if (can_turn_left && can_turn_right)
       MovDir[x][y] = (RND(3) ? (RND(2) ? left_dir : right_dir) : back_dir);
     else if (can_turn_left)
@@ -3721,9 +4876,9 @@ inline static void TurnRoundExt(int x, int y)
   }
   else if (move_pattern == MV_ALONG_LEFT_SIDE)
   {
-    if (ELEMENT_CAN_ENTER_FIELD(element, left_x, left_y))
+    if (CUSTOM_ELEMENT_CAN_ENTER_FIELD(element, left_x, left_y))
       MovDir[x][y] = left_dir;
-    else if (!ELEMENT_CAN_ENTER_FIELD(element, move_x, move_y))
+    else if (!CUSTOM_ELEMENT_CAN_ENTER_FIELD(element, move_x, move_y))
       MovDir[x][y] = right_dir;
 
     if (MovDir[x][y] != old_move_dir)
@@ -3731,9 +4886,9 @@ inline static void TurnRoundExt(int x, int y)
   }
   else if (move_pattern == MV_ALONG_RIGHT_SIDE)
   {
-    if (ELEMENT_CAN_ENTER_FIELD(element, right_x, right_y))
+    if (CUSTOM_ELEMENT_CAN_ENTER_FIELD(element, right_x, right_y))
       MovDir[x][y] = right_dir;
-    else if (!ELEMENT_CAN_ENTER_FIELD(element, move_x, move_y))
+    else if (!CUSTOM_ELEMENT_CAN_ENTER_FIELD(element, move_x, move_y))
       MovDir[x][y] = left_dir;
 
     if (MovDir[x][y] != old_move_dir)
@@ -3793,28 +4948,28 @@ inline static void TurnRoundExt(int x, int y)
        new_move_dir & (first_horiz ? MV_HORIZONTAL : MV_VERTICAL);
       Moving2Blocked(x, y, &newx, &newy);
 
-      if (ELEMENT_CAN_ENTER_FIELD_OR_ACID(element, newx, newy))
+      if (CUSTOM_ELEMENT_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 (ELEMENT_CAN_ENTER_FIELD_OR_ACID(element, newx, newy))
+      if (CUSTOM_ELEMENT_CAN_ENTER_FIELD(element, newx, newy))
        return;
 
       MovDir[x][y] = old_move_dir;
     }
   }
-  else if (move_pattern == MV_WHEN_PUSHED)
+  else if (move_pattern == MV_WHEN_PUSHED ||
+          move_pattern == MV_WHEN_DROPPED)
   {
-    if (!IN_LEV_FIELD_AND_IS_FREE(move_x, move_y))
+    if (!CUSTOM_ELEMENT_CAN_ENTER_FIELD(element, move_x, move_y))
       MovDir[x][y] = MV_NO_MOVING;
 
     MovDelay[x][y] = 0;
   }
-  else if (move_pattern & MV_MAZE_RUNNER_STYLE ||
-          element == EL_MAZE_RUNNER)
+  else if (move_pattern & MV_MAZE_RUNNER_STYLE)
   {
     static int test_xy[7][2] =
     {
@@ -3842,7 +4997,7 @@ inline static void TurnRoundExt(int x, int y)
     int start_test = RND(4);
     int i;
 
-    for (i = 0; i < 4; i++)
+    for (i = 0; i < NUM_DIRECTIONS; i++)
     {
       int move_dir = test_dir[start_test + i];
       int move_dir_preference;
@@ -3858,7 +5013,7 @@ inline static void TurnRoundExt(int x, int y)
        break;
       }
 
-      if (!MAZE_RUNNER_CAN_ENTER_FIELD(xx, yy))
+      if (!CUSTOM_ELEMENT_CAN_ENTER_FIELD(element, xx, yy))
        continue;
 
       move_dir_preference = -1 * RunnerVisit[xx][yy];
@@ -3935,7 +5090,9 @@ 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];
 
@@ -3953,8 +5110,8 @@ void StartMoving(int x, int y)
 
   if (CAN_FALL(element) && y < lev_fieldy - 1)
   {
-    if ((x > 0 && IS_PLAYER(x - 1, y)) ||
-       (x < lev_fieldx-1 && IS_PLAYER(x + 1, y)))
+    if ((x > 0              && IS_PLAYER(x - 1, y)) ||
+       (x < lev_fieldx - 1 && IS_PLAYER(x + 1, y)))
       if (JustBeingPushed(x, y))
        return;
 
@@ -4084,7 +5241,7 @@ void StartMoving(int x, int y)
     else if (CAN_FALL(element) && Feld[x][y + 1] == EL_ACID)
 #endif
     {
-      SplashAcid(x, y);
+      SplashAcid(x, y + 1);
 
       InitMovingField(x, y, MV_DOWN);
       started_moving = TRUE;
@@ -4096,12 +5253,16 @@ void StartMoving(int x, int y)
 #endif
     }
 #if 1
-    else if ((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)) ||
+    else if ((game.engine_version >= VERSION_IDENT(3,1,0,0) &&
+             CheckCollision[x][y] && !IS_FREE(x, y + 1)) ||
+
             (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))))
+             (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)))
 
 #else
 #if 1
@@ -4125,9 +5286,16 @@ 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;
+
       Impact(x, y);
     }
-    else if (IS_FREE(x, y + 1) && element == EL_SPRING && use_spring_bug)
+    else if (IS_FREE(x, y + 1) && element == EL_SPRING && level.use_spring_bug)
     {
       if (MovDir[x][y] == MV_NO_MOVING)
       {
@@ -4203,7 +5371,11 @@ void StartMoving(int x, int y)
        started_moving = TRUE;
       }
     }
+#if 0
+    else if (IS_BELT_ACTIVE(Feld[x][y + 1]) && !CAN_MOVE(element))
+#else
     else if (IS_BELT_ACTIVE(Feld[x][y + 1]))
+#endif
     {
       boolean left_is_free  = (x > 0 && IS_FREE(x - 1, y));
       boolean right_is_free = (x < lev_fieldx - 1 && IS_FREE(x + 1, y));
@@ -4213,20 +5385,50 @@ 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;
       }
+      else
+      {
+       MovDir[x][y] = 0;       /* if element was moving, stop it */
+      }
     }
   }
 
   /* 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)
+#else
   if (CAN_MOVE(element) && !started_moving)
+#endif
   {
     int move_pattern = element_info[element].move_pattern;
     int newx, newy;
 
+#if 0
+#if DEBUG
+    if (MovDir[x][y] == MV_NO_MOVING)
+    {
+      printf("StartMoving(): %d,%d: element %d ['%s'] not moving\n",
+            x, y, element, element_info[element].token_name);
+      printf("StartMoving(): This should never happen!\n");
+    }
+#endif
+#endif
+
+    Moving2Blocked(x, y, &newx, &newy);
+
 #if 1
     if (IS_PUSHABLE(element) && JustBeingPushed(x, y))
       return;
@@ -4238,6 +5440,51 @@ void StartMoving(int x, int 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_OTHER_IS_HITTING),
+            HAS_ANY_CHANGE_EVENT(element, CE_OTHER_GETS_HIT));
+#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)
@@ -4267,7 +5514,10 @@ void StartMoving(int x, int y)
          element != EL_PACMAN &&
          !(move_pattern & MV_ANY_DIRECTION) &&
          move_pattern != MV_TURNING_LEFT &&
-         move_pattern != MV_TURNING_RIGHT)
+         move_pattern != MV_TURNING_RIGHT &&
+         move_pattern != MV_TURNING_LEFT_RIGHT &&
+         move_pattern != MV_TURNING_RIGHT_LEFT &&
+         move_pattern != MV_TURNING_RANDOM)
       {
        TurnRound(x, y);
 
@@ -4369,11 +5619,30 @@ void StartMoving(int x, int y)
          {
            int flamed = MovingOrBlocked2Element(xx, yy);
 
-           if (IS_CLASSIC_ENEMY(flamed) || CAN_EXPLODE_BY_FIRE(flamed))
+           /* !!! */
+#if 0
+           if (IS_CLASSIC_ENEMY(flamed) || CAN_EXPLODE_BY_DRAGONFIRE(flamed))
+             Bang(xx, yy);
+           else if (IS_MOVING(xx, yy) || IS_BLOCKED(xx, yy))
+             RemoveMovingField(xx, yy);
+           else
+             RemoveField(xx, yy);
+#else
+           if (IS_CLASSIC_ENEMY(flamed) || CAN_EXPLODE_BY_DRAGONFIRE(flamed))
              Bang(xx, yy);
            else
              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))
            {
@@ -4411,10 +5680,11 @@ void StartMoving(int x, int y)
 
     if (DONT_COLLIDE_WITH(element) &&
        IN_LEV_FIELD(newx, newy) && IS_PLAYER(newx, newy) &&
-       !PLAYER_PROTECTED(newx, newy))
+       !PLAYER_ENEMY_PROTECTED(newx, newy))
     {
 #if 1
       TestIfBadThingRunsIntoHero(x, y, MovDir[x][y]);
+
       return;
 #else
       /* player killed by element which is deadly when colliding with */
@@ -4424,6 +5694,18 @@ void StartMoving(int x, int y)
 #endif
 
     }
+#if 1
+#if 1
+    else if (CAN_MOVE_INTO_ACID(element) &&
+            IN_LEV_FIELD(newx, newy) && Feld[newx][newy] == EL_ACID &&
+            (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 ||
@@ -4431,16 +5713,22 @@ void StartMoving(int x, int y)
              IS_CUSTOM_ELEMENT(element)) &&
             IN_LEV_FIELD(newx, newy) &&
             MovDir[x][y] == MV_DOWN && Feld[newx][newy] == EL_ACID)
+#endif
     {
-      SplashAcid(x, y);
+      SplashAcid(newx, newy);
       Store[x][y] = EL_ACID;
     }
     else if (element == EL_PENGUIN && IN_LEV_FIELD(newx, newy))
     {
       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)))
@@ -4455,7 +5743,7 @@ void StartMoving(int x, int y)
       }
       else if (IS_FOOD_PENGUIN(Feld[newx][newy]))
       {
-       if (DigField(local_player, newx, newy, 0, 0, DF_DIG) == MF_MOVING)
+       if (DigField(local_player, x, y, newx, newy, 0,0, DF_DIG) == MF_MOVING)
          DrawLevelField(newx, newy);
        else
          GfxDir[x][y] = MovDir[x][y] = MV_NO_MOVING;
@@ -4468,6 +5756,7 @@ void StartMoving(int x, int y)
          DrawPlayerField(x, y);
        else
          DrawLevelField(x, y);
+
        return;
       }
     }
@@ -4491,38 +5780,96 @@ void StartMoving(int x, int y)
          DrawPlayerField(x, y);
        else
          DrawLevelField(x, y);
+
        return;
       }
     }
-    else if ((move_pattern & MV_MAZE_RUNNER_STYLE ||
-             element == EL_MAZE_RUNNER) && IN_LEV_FIELD(newx, newy))
+
+#if 1
+
+    /*
+    else if (move_pattern & MV_MAZE_RUNNER_STYLE && IN_LEV_FIELD(newx, newy))
+    */
+
+    else if (IS_CUSTOM_ELEMENT(element) &&
+            CUSTOM_ELEMENT_CAN_ENTER_FIELD(element, newx, newy)
+
+#if 0
+ &&
+            !IS_FREE(newx, newy)
+#endif
+
+)
     {
-      if (IS_FOOD_DARK_YAMYAM(Feld[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 :
+                     IS_COLLECTIBLE(new_element) ? ACTION_COLLECTING :
+                     ACTION_BREAKING);
+
+       /* no element can dig solid indestructible elements */
+       if (IS_INDESTRUCTIBLE(new_element) &&
+           !IS_DIGGABLE(new_element) &&
+           !IS_COLLECTIBLE(new_element))
+         return;
+
+       if (AmoebaNr[newx][newy] &&
+           (new_element == EL_AMOEBA_FULL ||
+            new_element == EL_BD_AMOEBA ||
+            new_element == EL_AMOEBA_GROWING))
+       {
+         AmoebaCnt[AmoebaNr[newx][newy]]--;
+         AmoebaCnt2[AmoebaNr[newx][newy]]--;
+       }
+
        if (IS_MOVING(newx, newy))
          RemoveMovingField(newx, newy);
        else
        {
-         Feld[newx][newy] = EL_EMPTY;
+         RemoveField(newx, newy);
          DrawLevelField(newx, newy);
        }
 
-       PlayLevelSound(x, y, SND_DARK_YAMYAM_DIGGING);
+       /* if digged element was about to explode, prevent the explosion */
+       ExplodeField[newx][newy] = EX_TYPE_NONE;
+
+       PlayLevelSoundAction(x, y, action);
       }
-      else if (!IS_FREE(newx, newy))
-      {
-#if 0
-       if (IS_PLAYER(x, y))
-         DrawPlayerField(x, y);
-       else
-         DrawLevelField(x, y);
+
+#if 1
+#if 1
+      Store[newx][newy] = EL_EMPTY;
+      if (IS_EQUAL_OR_IN_GROUP(new_element, MOVE_ENTER_EL(element)))
+       Store[newx][newy] = element_info[element].move_leave_element;
+#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
-       return;
-      }
 
-      RunnerVisit[x][y] = FrameCounter;
-      PlayerVisit[x][y] /= 8;          /* expire player visit path */
+      if (move_pattern & MV_MAZE_RUNNER_STYLE)
+      {
+       RunnerVisit[x][y] = FrameCounter;
+       PlayerVisit[x][y] /= 8;         /* expire player visit path */
+      }
     }
+
+#endif
+
     else if (element == EL_DRAGON && IN_LEV_FIELD(newx, newy))
     {
       if (!IS_FREE(newx, newy))
@@ -4565,11 +5912,25 @@ void StartMoving(int x, int y)
 
          MovDelay[x][y] = 50;
 
+         /* !!! */
+#if 0
+         RemoveField(newx, newy);
+#endif
          Feld[newx][newy] = EL_FLAMES;
          if (IN_LEV_FIELD(newx1, newy1) && Feld[newx1][newy1] == EL_EMPTY)
+         {
+#if 0
+           RemoveField(newx1, newy1);
+#endif
            Feld[newx1][newy1] = EL_FLAMES;
+         }
          if (IN_LEV_FIELD(newx2, newy2) && Feld[newx2][newy2] == EL_EMPTY)
+         {
+#if 0
+           RemoveField(newx2, newy2);
+#endif
            Feld[newx2][newy2] = EL_FLAMES;
+         }
 
          return;
        }
@@ -4599,8 +5960,15 @@ void StartMoving(int x, int y)
          AmoebaCnt[AmoebaNr[newx][newy]]--;
       }
 
+#if 0
+      /* !!! test !!! */
+      if (IS_MOVING(newx, newy) || IS_BLOCKED(newx, newy))
+#else
       if (IS_MOVING(newx, newy))
+#endif
+      {
        RemoveMovingField(newx, newy);
+      }
       else
       {
        Feld[newx][newy] = EL_EMPTY;
@@ -4630,6 +5998,7 @@ void StartMoving(int x, int y)
        DrawLevelField(x, y);
 
        MovDelay[newx][newy] = 0;       /* start amoeba shrinking delay */
+
        return;                         /* wait for shrinking amoeba */
       }
       else     /* element == EL_PACMAN */
@@ -4652,6 +6021,27 @@ void StartMoving(int x, int y)
 
       TurnRound(x, y);
 
+#if 0
+      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]);
+
+       element = Feld[x][y];   /* element might have changed */
+      }
+#endif
+
 #if 1
       if (GFX_ELEMENT(element) != EL_SAND)     /* !!! FIX THIS (crumble) !!! */
        DrawLevelElementAnimation(x, y, element);
@@ -4693,17 +6083,34 @@ void StartMoving(int x, int y)
 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;
-  boolean pushed = Pushed[x][y];
+#endif
+#if 1
+  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
 
   MovPos[x][y] += getElementMoveStepsize(x, y);
 
-  if (pushed)          /* special case: moving object pushed by player */
+#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)
   {
@@ -4718,7 +6125,13 @@ void ContinueMoving(int x, int y)
   Feld[newx][newy] = element;
   MovPos[x][y] = 0;    /* force "not moving" for "crumbled sand" */
 
-  if (element == EL_MOLE)
+#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;
 
@@ -4777,20 +6190,40 @@ 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] = 0;
+  Store[x][y] = EL_EMPTY;
   MovPos[x][y] = MovDir[x][y] = MovDelay[x][y] = 0;
   MovDelay[newx][newy] = 0;
 
-  /* copy element change control values to new field */
-  ChangeDelay[newx][newy] = ChangeDelay[x][y];
-  ChangePage[newx][newy] = ChangePage[x][y];
-  Changed[newx][newy] = Changed[x][y];
-  ChangeEvent[newx][newy] = ChangeEvent[x][y];
+  if (CAN_CHANGE(element))
+  {
+    /* 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];
+    ChangeEvent[newx][newy] = ChangeEvent[x][y];
+  }
 
   ChangeDelay[x][y] = 0;
   ChangePage[x][y] = -1;
@@ -4807,6 +6240,49 @@ void ContinueMoving(int x, int y)
 
   ResetGfxAnimation(x, y);     /* reset animation values for old field */
 
+#if 1
+  /* some elements can leave other elements behind after moving */
+#if 1
+  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_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))
+#endif
+  {
+    int move_leave_element = ei->move_leave_element;
+
+    Feld[x][y] = move_leave_element;
+    InitField(x, y, FALSE);
+
+    if (GFX_CRUMBLED(Feld[x][y]))
+      DrawLevelFieldCrumbledSandNeighbours(x, 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 0
   /* 2.1.1 (does not work correctly for spring) */
   if (!CAN_MOVE(element))
@@ -4824,9 +6300,18 @@ void ContinueMoving(int x, int y)
     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
@@ -4837,17 +6322,39 @@ void ContinueMoving(int x, int y)
   Stop[newx][newy] = TRUE;     /* ignore this element until the next frame */
 
   /* prevent pushed element from moving on in pushed direction */
-  if (pushed && CAN_MOVE(element) &&
+  if (pushed_by_player && CAN_MOVE(element) &&
       element_info[element].move_pattern & MV_ANY_DIRECTION &&
       !(element_info[element].move_pattern & direction))
     TurnRound(newx, newy);
 
-  if (!pushed) /* special case: moving object pushed by player */
+#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;
 
     if (CAN_FALL(element) && direction == MV_DOWN)
       WasJustFalling[newx][newy] = 3;
+
+    if ((!CAN_FALL(element) || direction == MV_DOWN) && check_collision_again)
+      CheckCollision[newx][newy] = 2;
   }
 
   if (DONT_TOUCH(element))     /* object may be nasty to player or others */
@@ -4866,7 +6373,31 @@ void ContinueMoving(int x, int y)
     Impact(x, newy);
 
 #if 1
-  TestIfElementTouchesCustomElement(x, y);             /* for empty space */
+  if (pushed_by_player)
+  {
+#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
+    struct PlayerInfo *player = PLAYERINFO(x, y);
+
+    CheckElementChangeByPlayer(newx, newy, element, CE_PUSHED_BY_PLAYER,
+                              player->index_bit, dig_side);
+    CheckTriggeredElementChangeByPlayer(newx,newy,element,CE_OTHER_GETS_PUSHED,
+                                       player->index_bit, dig_side);
+  }
+#endif
+
+#if 1
+  TestIfElementTouchesCustomElement(x, y);     /* empty or new element */
 #endif
 
 #if 0
@@ -4874,27 +6405,26 @@ void ContinueMoving(int x, int y)
     ChangeElement(newx, newy, ChangePage[newx][newy]);
 #endif
 
+#if 1
+
+  TestIfElementHitsCustomElement(newx, newy, direction);
+
+#else
+
   if (!IN_LEV_FIELD(nextx, nexty) || !IS_FREE(nextx, nexty))
   {
+    int hitting_element = Feld[newx][newy];
+
     /* !!! fix side (direction) orientation here and elsewhere !!! */
-    CheckElementSideChange(newx, newy, Feld[newx][newy],
-                          direction, CE_COLLISION_ACTIVE, -1);
+    CheckElementChangeBySide(newx, newy, hitting_element, CE_HITTING_SOMETHING,
+                            direction);
 
 #if 0
     if (IN_LEV_FIELD(nextx, nexty))
     {
-      static int opposite_directions[] =
-      {
-       MV_RIGHT,
-       MV_LEFT,
-       MV_DOWN,
-       MV_UP
-      };
-      int move_dir_bit = MV_DIR_BIT(direction);
-      int opposite_direction = opposite_directions[move_dir_bit];
+      int opposite_direction = MV_DIR_OPPOSITE(direction);
       int hitting_side = direction;
       int touched_side = opposite_direction;
-      int hitting_element = Feld[newx][newy];
       int touched_element = MovingOrBlocked2Element(nextx, nexty);
       boolean object_hit = (!IS_MOVING(nextx, nexty) ||
                            MovDir[nextx][nexty] != direction ||
@@ -4904,11 +6434,11 @@ void ContinueMoving(int x, int y)
       {
        int i;
 
-       CheckElementSideChange(nextx, nexty, Feld[nextx][nexty],
-                              opposite_direction, CE_COLLISION_PASSIVE, -1);
+       CheckElementChangeBySide(nextx, nexty, touched_element,
+                                CE_HIT_BY_SOMETHING, opposite_direction);
 
        if (IS_CUSTOM_ELEMENT(hitting_element) &&
-           HAS_ANY_CHANGE_EVENT(hitting_element, CE_OTHER_IS_COLL_ACTIVE))
+           HAS_ANY_CHANGE_EVENT(hitting_element, CE_OTHER_IS_HITTING))
        {
          for (i = 0; i < element_info[hitting_element].num_change_pages; i++)
          {
@@ -4916,19 +6446,19 @@ void ContinueMoving(int x, int y)
              &element_info[hitting_element].change_page[i];
 
            if (change->can_change &&
-               change->events & CH_EVENT_BIT(CE_OTHER_IS_COLL_ACTIVE) &&
-               change->sides & touched_side &&
+               change->events & CH_EVENT_BIT(CE_OTHER_IS_HITTING) &&
+               change->trigger_side & touched_side &&
                change->trigger_element == touched_element)
            {
-             CheckElementSideChange(newx, newy, hitting_element,
-                                    CH_SIDE_ANY, CE_OTHER_IS_COLL_ACTIVE, i);
+             CheckElementChangeByPage(newx, newy, hitting_element,
+                                      touched_element, CE_OTHER_IS_HITTING,i);
              break;
            }
          }
        }
 
        if (IS_CUSTOM_ELEMENT(touched_element) &&
-           HAS_ANY_CHANGE_EVENT(touched_element, CE_OTHER_IS_COLL_PASSIVE))
+           HAS_ANY_CHANGE_EVENT(touched_element, CE_OTHER_GETS_HIT))
        {
          for (i = 0; i < element_info[touched_element].num_change_pages; i++)
          {
@@ -4936,12 +6466,12 @@ void ContinueMoving(int x, int y)
              &element_info[touched_element].change_page[i];
 
            if (change->can_change &&
-               change->events & CH_EVENT_BIT(CE_OTHER_IS_COLL_PASSIVE) &&
-               change->sides & hitting_side &&
+               change->events & CH_EVENT_BIT(CE_OTHER_GETS_HIT) &&
+               change->trigger_side & hitting_side &&
                change->trigger_element == hitting_element)
            {
-             CheckElementSideChange(nextx, nexty, touched_element,
-                                    CH_SIDE_ANY, CE_OTHER_IS_COLL_PASSIVE, i);
+             CheckElementChangeByPage(nextx, nexty, touched_element,
+                                      hitting_element, CE_OTHER_GETS_HIT, i);
              break;
            }
          }
@@ -4950,6 +6480,7 @@ void ContinueMoving(int x, int y)
     }
 #endif
   }
+#endif
 
   TestIfPlayerTouchesCustomElement(newx, newy);
   TestIfElementTouchesCustomElement(newx, newy);
@@ -4968,7 +6499,7 @@ int AmoebeNachbarNr(int ax, int ay)
     { 0, +1 }
   };
 
-  for (i = 0; i < 4; i++)
+  for (i = 0; i < NUM_DIRECTIONS; i++)
   {
     int x = ax + xy[i][0];
     int y = ay + xy[i][1];
@@ -4998,7 +6529,7 @@ void AmoebenVereinigen(int ax, int ay)
   if (new_group_nr == 0)
     return;
 
-  for (i = 0; i < 4; i++)
+  for (i = 0; i < NUM_DIRECTIONS; i++)
   {
     x = ax + xy[i][0];
     y = ay + xy[i][1];
@@ -5076,7 +6607,7 @@ void AmoebeUmwandeln(int ax, int ay)
       { 0, +1 }
     };
 
-    for (i = 0; i < 4; i++)
+    for (i = 0; i < NUM_DIRECTIONS; i++)
     {
       x = ax + xy[i][0];
       y = ay + xy[i][1];
@@ -5256,6 +6787,15 @@ 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)
+    {
+      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)
@@ -5263,6 +6803,7 @@ void AmoebeAbleger(int ax, int ay)
       newax = x;
       neway = y;
     }
+#endif
 
     if (newax == ax && neway == ay)
       return;
@@ -5272,7 +6813,7 @@ void AmoebeAbleger(int ax, int ay)
     int start = RND(4);
     boolean waiting_for_player = FALSE;
 
-    for (i = 0; i < 4; i++)
+    for (i = 0; i < NUM_DIRECTIONS; i++)
     {
       int j = (start + i) % 4;
       int x = ax + xy[j][0];
@@ -5281,6 +6822,16 @@ 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)
+      {
+       newax = x;
+       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)
@@ -5289,13 +6840,18 @@ void AmoebeAbleger(int ax, int ay)
        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);
@@ -5426,6 +6982,20 @@ 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 */
@@ -5439,6 +7009,7 @@ void Life(int ax, int ay)
        changed = TRUE;
       }
     }
+#endif
   }
 
   if (changed)
@@ -5464,7 +7035,12 @@ 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)
@@ -5754,11 +7330,11 @@ void CheckForDragon(int x, int y)
     { 0, +1 }
   };
 
-  for (i = 0; i < 4; i++)
+  for (i = 0; i < NUM_DIRECTIONS; i++)
   {
     for (j = 0; j < 4; j++)
     {
-      int xx = x + j*xy[i][0], yy = y + j*xy[i][1];
+      int xx = x + j * xy[i][0], yy = y + j * xy[i][1];
 
       if (IN_LEV_FIELD(xx, yy) &&
          (Feld[xx][yy] == EL_FLAMES || Feld[xx][yy] == EL_DRAGON))
@@ -5773,11 +7349,11 @@ void CheckForDragon(int x, int y)
 
   if (!dragon_found)
   {
-    for (i = 0; i < 4; i++)
+    for (i = 0; i < NUM_DIRECTIONS; i++)
     {
       for (j = 0; j < 3; j++)
       {
-       int xx = x + j*xy[i][0], yy = y + j*xy[i][1];
+       int xx = x + j * xy[i][0], yy = y + j * xy[i][1];
   
        if (IN_LEV_FIELD(xx, yy) && Feld[xx][yy] == EL_FLAMES)
        {
@@ -5816,7 +7392,7 @@ static void WarnBuggyBase(int x, int y)
     { 0, +1 }
   };
 
-  for (i = 0; i < 4; i++)
+  for (i = 0; i < NUM_DIRECTIONS; i++)
   {
     int xx = x + xy[i][0], yy = y + xy[i][1];
 
@@ -5850,48 +7426,108 @@ static void ChangeActiveTrap(int x, int y)
 
 static void ChangeElementNowExt(int x, int y, int target_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
+
   /* 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_PROTECTED(x, y) &&
+  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
+
     Bang(x, y);
     return;
   }
 
-  RemoveField(x, y);
-  Feld[x][y] = target_element;
+#if 1
+  if (!add_player)
+#endif
+  {
+#if 1
+    if (IS_MOVING(x, y) || IS_BLOCKED(x, y))
+      RemoveMovingField(x, y);
+    else
+      RemoveField(x, y);
 
-  Changed[x][y] |= ChangeEvent[x][y];  /* ignore same changes in this frame */
+    Feld[x][y] = target_element;
+#else
+    RemoveField(x, y);
+    Feld[x][y] = target_element;
+#endif
 
-  ResetGfxAnimation(x, y);
-  ResetRandomAnimationValue(x, y);
+    ResetGfxAnimation(x, y);
+    ResetRandomAnimationValue(x, y);
 
-  InitField(x, y, FALSE);
-  if (CAN_MOVE(Feld[x][y]))
-    InitMovDir(x, y);
+    if (element_info[Feld[x][y]].move_direction_initial == MV_START_PREVIOUS)
+      MovDir[x][y] = previous_move_direction;
 
-  DrawLevelField(x, y);
+#if 1
+    InitField_WithBug1(x, y, FALSE);
+#else
+    InitField(x, y, FALSE);
+    if (CAN_MOVE(Feld[x][y]))
+      InitMovDir(x, y);
+#endif
 
-  if (GFX_CRUMBLED(Feld[x][y]))
-    DrawLevelFieldCrumbledSandNeighbours(x, y);
+    DrawLevelField(x, y);
+
+    if (GFX_CRUMBLED(Feld[x][y]))
+      DrawLevelFieldCrumbledSandNeighbours(x, y);
+  }
 
+#if 0
+  Changed[x][y] |= ChangeEvent[x][y];  /* ignore same changes in this frame */
+#endif
+
+#if 0
   TestIfBadThingTouchesHero(x, y);
   TestIfPlayerTouchesCustomElement(x, y);
   TestIfElementTouchesCustomElement(x, y);
+#endif
 
+  /* "Changed[][]" not set yet to allow "entered by player" change one time */
   if (ELEM_IS_PLAYER(target_element))
     RelocatePlayer(x, y, target_element);
+
+#if 1
+  Changed[x][y] |= ChangeEvent[x][y];  /* ignore same changes in this frame */
+#endif
+
+#if 1
+  TestIfBadThingTouchesHero(x, y);
+  TestIfPlayerTouchesCustomElement(x, y);
+  TestIfElementTouchesCustomElement(x, y);
+#endif
 }
 
 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];
 
   /* always use default change event to prevent running into a loop */
   if (ChangeEvent[x][y] == CE_BITMASK_DEFAULT)
     ChangeEvent[x][y] = CH_EVENT_BIT(CE_DELAY);
 
+  if (ChangeEvent[x][y] == CH_EVENT_BIT(CE_DELAY))
+  {
+    /* reset actual trigger element and player */
+    change->actual_trigger_element = EL_EMPTY;
+    change->actual_trigger_player = EL_PLAYER_1;
+  }
+
   /* do not change already changed elements with same change event */
 #if 0
   if (Changed[x][y] & ChangeEvent[x][y])
@@ -5903,7 +7539,10 @@ static boolean ChangeElementNow(int x, int y, int element, int page)
 
   Changed[x][y] |= ChangeEvent[x][y];  /* ignore same changes in this frame */
 
-  CheckTriggeredElementChange(x, y, Feld[x][y], CE_OTHER_IS_CHANGING);
+#if 0
+  /* !!! indirect change before direct change !!! */
+  CheckTriggeredElementChangeByPage(x,y,Feld[x][y], CE_OTHER_IS_CHANGING,page);
+#endif
 
   if (change->explode)
   {
@@ -5912,77 +7551,141 @@ static boolean ChangeElementNow(int x, int y, int element, int page)
     return TRUE;
   }
 
-  if (change->use_content)
+  if (change->use_target_content)
   {
-    boolean complete_change = TRUE;
-    boolean can_change[3][3];
+    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 half_destructible;
+      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;
 
-      can_change[xx][yy] = TRUE;
+      can_replace[xx][yy] = TRUE;
 
       if (ex == x && ey == y)  /* do not check changing element itself */
        continue;
 
-      if (change->content[xx][yy] == EL_EMPTY_SPACE)
+      if (content_element == EL_EMPTY_SPACE)
       {
-       can_change[xx][yy] = FALSE;     /* do not change empty borders */
+       can_replace[xx][yy] = FALSE;    /* do not replace border with space */
 
        continue;
       }
 
       if (!IN_LEV_FIELD(ex, ey))
       {
-       can_change[xx][yy] = FALSE;
-       complete_change = FALSE;
+       can_replace[xx][yy] = FALSE;
+       complete_replace = FALSE;
+
+       continue;
+      }
+
+#if 0
+      if (Changed[ex][ey])     /* do not change already changed elements */
+      {
+       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);
 
+#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)));
+#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)));
+#endif
+
+#endif
+
+      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;
+#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));
+#else
       half_destructible = (IS_FREE(ex, ey) || IS_DIGGABLE(e));
+#endif
 
-      if ((change->power <= CP_NON_DESTRUCTIVE  && !IS_FREE(ex, ey)) ||
-         (change->power <= CP_HALF_DESTRUCTIVE && !half_destructible) ||
-         (change->power <= CP_FULL_DESTRUCTIVE && IS_INDESTRUCTIBLE(e)))
+      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)))
       {
-       can_change[xx][yy] = FALSE;
-       complete_change = FALSE;
+       can_replace[xx][yy] = FALSE;
+       complete_replace = FALSE;
       }
+#endif
     }
 
-    if (!change->only_complete || complete_change)
+    if (!change->only_if_complete || complete_replace)
     {
       boolean something_has_changed = FALSE;
 
-      if (change->only_complete && change->use_random_change &&
-         RND(100) < change->random)
+      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_change[xx][yy] && (!change->use_random_change ||
-                                  RND(100) < change->random))
+       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];
 
-         ChangeElementNowExt(ex, ey, change->content[xx][yy]);
+         content_element = change->target_content[xx][yy];
+         target_element = GET_TARGET_ELEMENT(content_element, change);
+
+         ChangeElementNowExt(ex, ey, target_element);
 
          something_has_changed = TRUE;
 
@@ -5998,11 +7701,18 @@ static boolean ChangeElementNow(int x, int y, int element, int page)
   }
   else
   {
-    ChangeElementNowExt(x, y, change->target_element);
+    target_element = GET_TARGET_ELEMENT(change->target_element, change);
+
+    ChangeElementNowExt(x, y, target_element);
 
     PlayLevelSoundElementAction(x, y, element, ACTION_CHANGING);
   }
 
+#if 1
+  /* this uses direct change before indirect change */
+  CheckTriggeredElementChangeByPage(x,y,old_element,CE_OTHER_IS_CHANGING,page);
+#endif
+
   return TRUE;
 }
 
@@ -6012,9 +7722,8 @@ static void ChangeElement(int x, int y, int page)
   struct ElementInfo *ei = &element_info[element];
   struct ElementChangeInfo *change = &ei->change_page[page];
 
-#if 0
 #ifdef DEBUG
-  if (!CAN_CHANGE(element))
+  if (!CAN_CHANGE(element) && !CAN_CHANGE(Back[x][y]))
   {
     printf("\n\n");
     printf("ChangeElement(): %d,%d: element = %d ('%s')\n",
@@ -6022,8 +7731,18 @@ static void ChangeElement(int x, int y, int page)
     printf("ChangeElement(): This should never happen!\n");
     printf("\n\n");
   }
-#endif
-#endif
+#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 */
   {
@@ -6055,9 +7774,15 @@ static void ChangeElement(int x, int y, int page)
     {
       page = ChangePage[x][y];
       ChangePage[x][y] = -1;
+
+      change = &ei->change_page[page];
     }
 
+#if 0
+    if (IS_MOVING(x, y) && !change->explode)
+#else
     if (IS_MOVING(x, y))               /* never change a running system ;-) */
+#endif
     {
       ChangeDelay[x][y] = 1;           /* try change after next move step */
       ChangePage[x][y] = page;         /* remember page to use for change */
@@ -6073,12 +7798,15 @@ static void ChangeElement(int x, int y, int page)
   }
 }
 
-static boolean CheckTriggeredElementSideChange(int lx, int ly,
-                                              int trigger_element,
-                                              int trigger_side,
-                                              int trigger_event)
+static boolean CheckTriggeredElementChangeExt(int lx, int ly,
+                                             int trigger_element,
+                                             int trigger_event,
+                                             int trigger_player,
+                                             int trigger_side,
+                                             int trigger_page)
 {
   int i, j, x, y;
+  int trigger_page_bits = (trigger_page < 0 ? CH_PAGE_ANY : 1 << trigger_page);
 
   if (!(trigger_events[trigger_element] & CH_EVENT_BIT(trigger_event)))
     return FALSE;
@@ -6098,11 +7826,11 @@ static boolean CheckTriggeredElementSideChange(int lx, int ly,
       struct ElementChangeInfo *change = &element_info[element].change_page[j];
 
       if (change->can_change &&
-#if 1
          change->events & CH_EVENT_BIT(trigger_event) &&
-#endif
-         change->sides & trigger_side &&
-         change->trigger_element == trigger_element)
+         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->events & CH_EVENT_BIT(trigger_event)))
@@ -6113,6 +7841,9 @@ static boolean CheckTriggeredElementSideChange(int lx, int ly,
        change_element = TRUE;
        page = j;
 
+       change->actual_trigger_element = trigger_element;
+       change->actual_trigger_player = EL_PLAYER_1 + log_2(trigger_player);
+
        break;
       }
     }
@@ -6139,15 +7870,13 @@ static boolean CheckTriggeredElementSideChange(int lx, int ly,
   return TRUE;
 }
 
-static boolean CheckTriggeredElementChange(int lx, int ly, int trigger_element,
-                                          int trigger_event)
-{
-  return CheckTriggeredElementSideChange(lx, ly, trigger_element, CH_SIDE_ANY,
-                                        trigger_event);
-}
-
-static boolean CheckElementSideChange(int x, int y, int element, int side,
-                                     int trigger_event, int page)
+static boolean CheckElementChangeExt(int x, int y,
+                                    int element,
+                                    int trigger_element,
+                                    int trigger_event,
+                                    int trigger_player,
+                                    int trigger_side,
+                                    int trigger_page)
 {
   if (!CAN_CHANGE(element) || !HAS_ANY_CHANGE_EVENT(element, trigger_event))
     return FALSE;
@@ -6158,24 +7887,75 @@ static boolean CheckElementSideChange(int x, int y, int element, int side,
     element = Feld[x][y];
   }
 
-  if (page < 0)
-    page = element_info[element].event_page_nr[trigger_event];
+#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
+
+    return FALSE;
+  }
+#endif
+
+#if 1
+  if (trigger_page < 0)
+  {
+    boolean change_element = FALSE;
+    int i;
+
+    for (i = 0; i < element_info[element].num_change_pages; i++)
+    {
+      struct ElementChangeInfo *change = &element_info[element].change_page[i];
+
+      if (change->can_change &&
+         change->events & CH_EVENT_BIT(trigger_event) &&
+         change->trigger_side & trigger_side &&
+         change->trigger_player & trigger_player)
+      {
+       change_element = TRUE;
+       trigger_page = i;
+
+       change->actual_trigger_element = trigger_element;
+       change->actual_trigger_player = EL_PLAYER_1 + log_2(trigger_player);
+
+       break;
+      }
+    }
+
+    if (!change_element)
+      return FALSE;
+  }
+  else
+  {
+    struct ElementInfo *ei = &element_info[element];
+    struct ElementChangeInfo *change = &ei->change_page[trigger_page];
+
+    change->actual_trigger_element = trigger_element;
+    change->actual_trigger_player = EL_PLAYER_1;       /* unused */
+  }
+
+#else
+
+  /* !!! this check misses pages with same event, but different side !!! */
 
-  if (!(element_info[element].change_page[page].sides & 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;
+#endif
 
   ChangeDelay[x][y] = 1;
   ChangeEvent[x][y] = CH_EVENT_BIT(trigger_event);
-  ChangeElement(x, y, page);
+  ChangeElement(x, y, trigger_page);
 
   return TRUE;
 }
 
-static boolean CheckElementChange(int x, int y, int element, int trigger_event)
-{
-  return CheckElementSideChange(x, y, element, CH_SIDE_ANY, trigger_event, -1);
-}
-
 static void PlayPlayerSound(struct PlayerInfo *player)
 {
   int jx = player->jx, jy = player->jy;
@@ -6367,12 +8147,22 @@ static byte PlayerActions(struct PlayerInfo *player, byte player_action)
   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
@@ -6408,9 +8198,9 @@ static byte PlayerActions(struct PlayerInfo *player, byte player_action)
 
     /* no actions for this player (no input at player's configured device) */
 
-    DigField(player, 0, 0, 0, 0, DF_NO_PUSH);
+    DigField(player, 0, 0, 0, 0, 0, 0, DF_NO_PUSH);
     SnapField(player, 0, 0);
-    CheckGravityMovement(player);
+    CheckGravityMovementWhenNotMoving(player);
 
     if (player->MovPos == 0)
       SetPlayerWaiting(player, TRUE);
@@ -6418,6 +8208,8 @@ static byte PlayerActions(struct PlayerInfo *player, byte player_action)
     if (player->MovPos == 0)   /* needed for tape.playing */
       player->is_moving = FALSE;
 
+    player->is_dropping = FALSE;
+
     return 0;
   }
 
@@ -6487,9 +8279,9 @@ static void PlayerActions(struct PlayerInfo *player, byte player_action)
 
     /* no actions for this player (no input at player's configured device) */
 
-    DigField(player, 0, 0, 0, 0, DF_NO_PUSH);
+    DigField(player, 0, 0, 0, 0, 0, 0, DF_NO_PUSH);
     SnapField(player, 0, 0);
-    CheckGravityMovement(player);
+    CheckGravityMovementWhenNotMoving(player);
 
     if (player->MovPos == 0)
       InitPlayerGfxAnimation(player, ACTION_DEFAULT, player->MovDir);
@@ -6526,7 +8318,7 @@ void GameActions()
   action_delay_value =
     (tape.playing && tape.fast_forward ? FfwdFrameDelay : GameFrameDelay);
 
-  if (tape.playing && tape.index_search && !tape.pausing)
+  if (tape.playing && tape.warp_forward && !tape.pausing)
     action_delay_value = 0;
 
   /* ---------- main game synchronization point ---------- */
@@ -6541,7 +8333,7 @@ void GameActions()
 #endif
     */
 
-#if defined(PLATFORM_UNIX)
+#if defined(NETWORK_AVALIABLE)
     /* last chance to get network player actions without main loop delay */
     HandleNetworking();
 #endif
@@ -6569,6 +8361,21 @@ void GameActions()
 
   recorded_player_action = (tape.playing ? TapePlayAction() : NULL);
 
+#if 1
+  if (recorded_player_action == NULL && tape.pausing)
+    return;
+#endif
+
+#if 0
+  printf("::: %d\n", stored_player[0].action);
+#endif
+
+#if 0
+  if (recorded_player_action != NULL)
+    for (i = 0; i < MAX_PLAYERS; i++)
+      stored_player[i].action = recorded_player_action[i];
+#endif
+
   for (i = 0; i < MAX_PLAYERS; i++)
   {
     summarized_player_action |= stored_player[i].action;
@@ -6577,7 +8384,7 @@ void GameActions()
       stored_player[i].effective_action = stored_player[i].action;
   }
 
-#if defined(PLATFORM_UNIX)
+#if defined(NETWORK_AVALIABLE)
   if (network_playing)
     SendToServer_MovePlayer(summarized_player_action);
 #endif
@@ -6585,25 +8392,91 @@ void GameActions()
   if (!options.network && !setup.team_mode)
     local_player->effective_action = summarized_player_action;
 
+#if 1
+  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;
+
+    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);
+#endif
+
   for (i = 0; i < MAX_PLAYERS; i++)
   {
     int actual_player_action = stored_player[i].effective_action;
 
+#if 1
+    /* !!! THIS BREAKS THE FOLLOWING TAPES: !!!
+       - rnd_equinox_tetrachloride 048
+       - rnd_equinox_tetrachloride_ii 096
+       - rnd_emanuel_schmieg 002
+       - doctor_sloan_ww 001, 020
+    */
+    if (stored_player[i].MovPos == 0)
+      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);
+#else
     tape_action[i] = PlayerActions(&stored_player[i], actual_player_action);
 
     if (tape.recording && tape_action[i] && !tape.player_participates[i])
       tape.player_participates[i] = TRUE;    /* player just appeared from CE */
+#endif
 
     ScrollPlayer(&stored_player[i], SCROLL_GO_ON);
   }
 
-#if 1
+#if 0
   if (tape.recording)
     TapeRecordAction(tape_action);
 #endif
@@ -6621,7 +8494,19 @@ void GameActions()
 #endif
 
 #if 1
+  /* for downwards 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
+     same game frame, which is bad); this code is also needed to use the famous
+     "spring push bug" which is used in older levels and might be wanted to be
+     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++)
     {
@@ -6629,8 +8514,15 @@ 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);
 
@@ -6664,6 +8556,8 @@ void GameActions()
       WasJustMoving[x][y]--;
     if (WasJustFalling[x][y] > 0)
       WasJustFalling[x][y]--;
+    if (CheckCollision[x][y] > 0)
+      CheckCollision[x][y]--;
 
     GfxFrame[x][y]++;
 
@@ -6759,6 +8653,7 @@ void GameActions()
       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)
@@ -6809,7 +8704,7 @@ void GameActions()
       CheckDynamite(x, y);
 #if 0
     else if (element == EL_EXPLOSION && !game.explosions_delayed)
-      Explode(x, y, ExplodePhase[x][y], EX_NORMAL);
+      Explode(x, y, ExplodePhase[x][y], EX_TYPE_NORMAL);
 #endif
     else if (element == EL_AMOEBA_GROWING)
       AmoebeWaechst(x, y);
@@ -6892,6 +8787,21 @@ void GameActions()
 #endif
       element = Feld[x][y];
 
+#if 1
+      if (!IS_PLAYER(x,y) &&
+         (element == EL_EMPTY ||
+          CAN_GROW_INTO(element) ||
+          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;
+      }
+#else
       /* !!! extend EL_SAND to anything diggable (but maybe not SP_BASE) !!! */
       if (!IS_PLAYER(x,y) &&
          (element == EL_EMPTY ||
@@ -6906,6 +8816,7 @@ void GameActions()
            (IN_LEV_FIELD(x, y+1) && Feld[x][y+1] == EL_AMOEBA_WET))
          Feld[x][y] = EL_AMOEBA_DROP;
       }
+#endif
 
       random = random * 129 + 1;
     }
@@ -6925,9 +8836,9 @@ void GameActions()
       if (ExplodeField[x][y])
        Explode(x, y, EX_PHASE_START, ExplodeField[x][y]);
       else if (element == EL_EXPLOSION)
-       Explode(x, y, ExplodePhase[x][y], EX_NORMAL);
+       Explode(x, y, ExplodePhase[x][y], EX_TYPE_NORMAL);
 
-      ExplodeField[x][y] = EX_NO_EXPLOSION;
+      ExplodeField[x][y] = EX_TYPE_NONE;
     }
 
     game.explosions_delayed = TRUE;
@@ -7007,7 +8918,7 @@ void GameActions()
   if (TimeFrames >= FRAMES_PER_SECOND)
   {
     TimeFrames = 0;
-    TimePlayed++;
+    TapeTime++;
 
     for (i = 0; i < MAX_PLAYERS; i++)
     {
@@ -7022,24 +8933,29 @@ void GameActions()
       }
     }
 
-    if (tape.recording || tape.playing)
-      DrawVideoDisplay(VIDEO_STATE_TIME_ON, TimePlayed);
-
-    if (TimeLeft > 0)
+    if (!level.use_step_counter)
     {
-      TimeLeft--;
+      TimePlayed++;
+
+      if (TimeLeft > 0)
+      {
+       TimeLeft--;
 
-      if (TimeLeft <= 10 && setup.time_limit)
-       PlaySoundStereo(SND_GAME_RUNNING_OUT_OF_TIME, SOUND_MIDDLE);
+       if (TimeLeft <= 10 && setup.time_limit)
+         PlaySoundStereo(SND_GAME_RUNNING_OUT_OF_TIME, SOUND_MIDDLE);
 
-      DrawText(DX_TIME, DY_TIME, int2str(TimeLeft, 3), FONT_TEXT_2);
+       DrawGameValue_Time(TimeLeft);
 
-      if (!TimeLeft && setup.time_limit)
-       for (i = 0; i < MAX_PLAYERS; i++)
-         KillHero(&stored_player[i]);
+       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);
     }
-    else if (level.time == 0 && !AllPlayersGone) /* level without time limit */
-      DrawText(DX_TIME, DY_TIME, int2str(TimePlayed, 3), FONT_TEXT_2);
+
+    if (tape.recording || tape.playing)
+      DrawVideoDisplay(VIDEO_STATE_TIME_ON, TapeTime);
   }
 
   DrawAllPlayers();
@@ -7088,6 +9004,9 @@ void GameActions()
 
     if (stored_player[i].MovPos != 0)
       stored_player[i].StepFrame += move_frames;
+
+    if (stored_player[i].drop_delay > 0)
+      stored_player[i].drop_delay--;
   }
 #endif
 
@@ -7170,31 +9089,246 @@ 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) ||
+          (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]));
+}
+
+static boolean canPassField(int x, int y, int move_dir)
+{
+  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 nextx = x + dx;
+  int nexty = y + dy;
+  int element = Feld[x][y];
+
+  return (IS_PASSABLE_FROM(element, opposite_dir) &&
+         !CAN_MOVE(element) &&
+         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)));
+}
+
+static boolean canMoveToValidFieldWithGravity(int x, int y, int move_dir)
+{
+  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 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 (game.gravity && !player->programmed_action)
   {
-    int move_dir_vertical = player->action & (MV_UP | MV_DOWN);
-    int move_dir_horizontal = player->action & (MV_LEFT | MV_RIGHT);
+#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_LEFT | MV_RIGHT) ?
+      (player->last_move_dir & MV_HORIZONTAL ?
        (move_dir_vertical ? move_dir_vertical : move_dir_horizontal) :
        (move_dir_horizontal ? move_dir_horizontal : move_dir_vertical));
-    int jx = player->jx, jy = player->jy;
+#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 (game.gravity && !player->programmed_action)
+  {
+    int jx = player->jx, jy = player->jy;
     boolean field_under_player_is_free =
       (IN_LEV_FIELD(jx, jy + 1) && IS_FREE(jx, jy + 1));
-    boolean player_is_moving_to_valid_field =
-      (IN_LEV_FIELD(new_jx, new_jy) &&
-       (Feld[new_jx][new_jy] == EL_SP_BASE ||
-       Feld[new_jx][new_jy] == EL_SAND));
-    /* !!! extend EL_SAND to anything diggable !!! */
+    boolean player_is_standing_on_valid_field =
+      (IS_WALKABLE_INSIDE(Feld[jx][jy]) ||
+       (IS_WALKABLE(Feld[jx][jy]) &&
+       !(element_info[Feld[jx][jy]].access_direction & MV_DOWN)));
 
-    if (field_under_player_is_free &&
-       !player_is_moving_to_valid_field &&
-       !IS_WALKABLE_INSIDE(Feld[jx][jy]))
+    if (field_under_player_is_free && !player_is_standing_on_valid_field)
       player->programmed_action = MV_DOWN;
   }
 }
@@ -7210,7 +9344,7 @@ boolean MovePlayerOneStep(struct PlayerInfo *player,
                          int dx, int dy, int real_dx, int real_dy)
 {
 #if 0
-  static int change_sides[4][2] =
+  static int trigger_sides[4][2] =
   {
     /* enter side        leave side */
     { CH_SIDE_RIGHT,   CH_SIDE_LEFT    },      /* moving left  */
@@ -7222,8 +9356,8 @@ boolean MovePlayerOneStep(struct PlayerInfo *player,
                        dx == +1 ? MV_RIGHT :
                        dy == -1 ? MV_UP :
                        dy == +1 ? MV_DOWN : MV_NO_MOVING);
-  int enter_side = change_sides[MV_DIR_BIT(move_direction)][0];
-  int leave_side = change_sides[MV_DIR_BIT(move_direction)][1];
+  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;
@@ -7254,7 +9388,7 @@ boolean MovePlayerOneStep(struct PlayerInfo *player,
   {
     if (element == EL_ACID && dx == 0 && dy == 1)
     {
-      SplashAcid(jx, jy);
+      SplashAcid(new_jx, new_jy);
       Feld[jx][jy] = EL_PLAYER_1;
       InitMovingField(jx, jy, MV_DOWN);
       Store[jx][jy] = EL_ACID;
@@ -7267,7 +9401,7 @@ boolean MovePlayerOneStep(struct PlayerInfo *player,
     return MF_MOVING;
   }
 
-  can_move = DigField(player, new_jx, new_jy, real_dx, real_dy, DF_DIG);
+  can_move = DigField(player, jx, jy, new_jx, new_jy, real_dx,real_dy, DF_DIG);
   if (can_move != MF_MOVING)
     return can_move;
 
@@ -7287,6 +9421,10 @@ boolean MovePlayerOneStep(struct PlayerInfo *player,
 
   player->step_counter++;
 
+#if 0
+  player->drop_delay = 0;
+#endif
+
   PlayerVisit[jx][jy] = FrameCounter;
 
   ScrollPlayer(player, SCROLL_INIT);
@@ -7294,18 +9432,17 @@ boolean MovePlayerOneStep(struct PlayerInfo *player,
 #if 0
   if (IS_CUSTOM_ELEMENT(Feld[jx][jy]))
   {
-    CheckTriggeredElementSideChange(jx, jy, Feld[jx][jy], leave_side,
-                                   CE_OTHER_GETS_LEFT);
-    CheckElementSideChange(jx, jy, Feld[jx][jy], leave_side,
-                          CE_LEFT_BY_PLAYER, -1);
+    CheckTriggeredElementChangeBySide(jx, jy, Feld[jx][jy], CE_OTHER_GETS_LEFT,
+                                     leave_side);
+    CheckElementChangeBySide(jx,jy, Feld[jx][jy],CE_LEFT_BY_PLAYER,leave_side);
   }
 
   if (IS_CUSTOM_ELEMENT(Feld[new_jx][new_jy]))
   {
-    CheckTriggeredElementSideChange(new_jx, new_jy, Feld[new_jx][new_jy],
-                                   enter_side, CE_OTHER_GETS_ENTERED);
-    CheckElementSideChange(new_jx, new_jy, Feld[new_jx][new_jy], enter_side,
-                          CE_ENTERED_BY_PLAYER, -1);
+    CheckTriggeredElementChangeBySide(new_jx, new_jy, Feld[new_jx][new_jy],
+                                     CE_OTHER_GETS_ENTERED, enter_side);
+    CheckElementChangeBySide(new_jx, new_jy, Feld[new_jx][new_jy],
+                            CE_ENTERED_BY_PLAYER, enter_side);
   }
 #endif
 
@@ -7318,19 +9455,48 @@ boolean MovePlayer(struct PlayerInfo *player, int dx, int dy)
   int old_jx = jx, old_jy = jy;
   int moved = MF_NO_ACTION;
 
+#if 1
+  if (!player->active)
+    return FALSE;
+
+  if (!dx && !dy)
+  {
+    if (player->MovPos == 0)
+    {
+      player->is_moving = FALSE;
+      player->is_digging = FALSE;
+      player->is_collecting = FALSE;
+      player->is_snapping = FALSE;
+      player->is_pushing = FALSE;
+    }
+
+    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 (!FrameReached(&player->move_delay, player->move_delay_value))
+    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
+
+  /* store if player is automatically moved to next field */
+  player->is_auto_moving = (player->programmed_action != MV_NO_MOVING);
+
   /* remove the last programmed player action */
   player->programmed_action = 0;
 
@@ -7361,7 +9527,7 @@ boolean MovePlayer(struct PlayerInfo *player, int dx, int dy)
     player->move_delay_value = original_move_delay_value;
   }
 
-  if (player->last_move_dir & (MV_LEFT | MV_RIGHT))
+  if (player->last_move_dir & MV_HORIZONTAL)
   {
     if (!(moved |= MovePlayerOneStep(player, 0, dy, dx, dy)))
       moved |= MovePlayerOneStep(player, dx, 0, dx, dy);
@@ -7393,7 +9559,7 @@ boolean MovePlayer(struct PlayerInfo *player, int dx, int dy)
     {
       if (jx != old_jx)                /* player has moved horizontally */
       {
-       if ((player->MovDir == MV_LEFT && scroll_x > jx - MIDPOSX + offset) ||
+       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);
 
@@ -7405,13 +9571,13 @@ boolean MovePlayer(struct PlayerInfo *player, int dx, int dy)
        scroll_x = old_scroll_x + SIGN(scroll_x - old_scroll_x);
 
        /* don't scroll against the player's moving direction */
-       if ((player->MovDir == MV_LEFT && scroll_x > old_scroll_x) ||
+       if ((player->MovDir == MV_LEFT  && scroll_x > old_scroll_x) ||
            (player->MovDir == MV_RIGHT && scroll_x < old_scroll_x))
          scroll_x = old_scroll_x;
       }
       else                     /* player has moved vertically */
       {
-       if ((player->MovDir == MV_UP && scroll_y > jy - MIDPOSY + 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);
 
@@ -7423,7 +9589,7 @@ boolean MovePlayer(struct PlayerInfo *player, int dx, int dy)
        scroll_y = old_scroll_y + SIGN(scroll_y - old_scroll_y);
 
        /* don't scroll against the player's moving direction */
-       if ((player->MovDir == MV_UP && scroll_y > old_scroll_y) ||
+       if ((player->MovDir == MV_UP   && scroll_y > old_scroll_y) ||
            (player->MovDir == MV_DOWN && scroll_y < old_scroll_y))
          scroll_y = old_scroll_y;
       }
@@ -7474,10 +9640,22 @@ boolean MovePlayer(struct PlayerInfo *player, int dx, int dy)
     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
     {
-      static int change_sides[4][2] =
+      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  */
@@ -7485,26 +9663,30 @@ boolean MovePlayer(struct PlayerInfo *player, int dx, int dy)
        { CH_SIDE_BOTTOM,       CH_SIDE_TOP     },      /* moving up    */
        { CH_SIDE_TOP,          CH_SIDE_BOTTOM  }       /* moving down  */
       };
-      int move_direction = player->MovDir;
-      int enter_side = change_sides[MV_DIR_BIT(move_direction)][0];
-      int leave_side = change_sides[MV_DIR_BIT(move_direction)][1];
+      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
-      if (IS_CUSTOM_ELEMENT(Feld[old_jx][old_jy]))
-      {
-       CheckTriggeredElementSideChange(old_jx, old_jy, Feld[old_jx][old_jy],
-                                       leave_side, CE_OTHER_GETS_LEFT);
-       CheckElementSideChange(old_jx, old_jy, Feld[old_jx][old_jy],
-                              leave_side, CE_LEFT_BY_PLAYER, -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);
 
-      if (IS_CUSTOM_ELEMENT(Feld[jx][jy]))
-      {
-       CheckTriggeredElementSideChange(jx, jy, Feld[jx][jy],
-                                       enter_side, CE_OTHER_GETS_ENTERED);
-       CheckElementSideChange(jx, jy, Feld[jx][jy],
-                              enter_side, CE_ENTERED_BY_PLAYER, -1);
-      }
+      CheckTriggeredElementChangeByPlayer(old_jx, old_jy, old_element,
+                                         CE_OTHER_GETS_LEFT,
+                                         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_OTHER_GETS_ENTERED,
+                                         player->index_bit, enter_side);
 #endif
 
     }
@@ -7514,7 +9696,7 @@ boolean MovePlayer(struct PlayerInfo *player, int dx, int dy)
   }
   else
   {
-    CheckGravityMovement(player);
+    CheckGravityMovementWhenNotMoving(player);
 
     /*
     player->last_move_dir = MV_NO_MOVING;
@@ -7554,6 +9736,7 @@ void ScrollPlayer(struct PlayerInfo *player, int mode)
 #if 0
     DrawPlayer(player);
 #endif
+
     return;
   }
   else if (!FrameReached(&player->actual_frame_counter, 1))
@@ -7562,7 +9745,8 @@ void ScrollPlayer(struct PlayerInfo *player, int mode)
   player->MovPos += (player->MovPos > 0 ? -1 : 1) * move_stepsize;
   player->GfxPos = move_stepsize * (player->MovPos / move_stepsize);
 
-  if (Feld[last_jx][last_jy] == EL_PLAYER_IS_LEAVING)
+  if (!player->block_last_field &&
+      Feld[last_jx][last_jy] == EL_PLAYER_IS_LEAVING)
     Feld[last_jx][last_jy] = EL_EMPTY;
 
   /* before DrawPlayer() to draw correct player graphic for this case */
@@ -7575,6 +9759,21 @@ void ScrollPlayer(struct PlayerInfo *player, int mode)
 
   if (player->MovPos == 0)     /* player reached destination field */
   {
+#if 1
+    if (player->move_delay_reset_counter > 0)
+    {
+      player->move_delay_reset_counter--;
+
+      if (player->move_delay_reset_counter == 0)
+      {
+       /* 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;
+      }
+    }
+#else
     if (IS_PASSABLE(Feld[last_jx][last_jy]))
     {
       /* continue with normal speed after quickly moving through gate */
@@ -7583,6 +9782,11 @@ void ScrollPlayer(struct PlayerInfo *player, int mode)
       /* be able to make the next move without delay */
       player->move_delay = 0;
     }
+#endif
+
+    if (player->block_last_field &&
+       Feld[last_jx][last_jy] == EL_PLAYER_IS_LEAVING)
+      Feld[last_jx][last_jy] = EL_EMPTY;
 
     player->last_jx = jx;
     player->last_jy = jy;
@@ -7599,18 +9803,97 @@ void ScrollPlayer(struct PlayerInfo *player, int mode)
        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,
+                                  player->index_bit, leave_side);
+
+      CheckTriggeredElementChangeByPlayer(old_jx, old_jy, old_element,
+                                         CE_OTHER_GETS_LEFT,
+                                         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_OTHER_GETS_ENTERED,
+                                         player->index_bit, enter_side);
+#endif
+
+    }
+#endif
+
     if (game.engine_version >= VERSION_IDENT(3,0,7,0))
     {
       TestIfHeroTouchesBadThing(jx, jy);
       TestIfPlayerTouchesCustomElement(jx, jy);
 #if 1
-      TestIfElementTouchesCustomElement(jx, jy);       /* for empty space */
+#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);
     }
 
+    if (level.use_step_counter)
+    {
+      int i;
+
+      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.single_step && tape.recording && !tape.pausing &&
        !player->programmed_action)
       TapeTogglePause(TAPE_TOGGLE_AUTOMATIC);
@@ -7654,7 +9937,7 @@ void TestIfPlayerTouchesCustomElement(int x, int y)
     { +1, 0 },
     { 0, +1 }
   };
-  static int change_sides[4][2] =
+  static int trigger_sides[4][2] =
   {
     /* center side       border side */
     { CH_SIDE_TOP,     CH_SIDE_BOTTOM  },      /* check top    */
@@ -7672,12 +9955,12 @@ void TestIfPlayerTouchesCustomElement(int x, int y)
   int center_element = Feld[x][y];     /* should always be non-moving! */
   int i;
 
-  for (i = 0; i < 4; i++)
+  for (i = 0; i < NUM_DIRECTIONS; i++)
   {
     int xx = x + xy[i][0];
     int yy = y + xy[i][1];
-    int center_side = change_sides[i][0];
-    int border_side = change_sides[i][1];
+    int center_side = trigger_sides[i][0];
+    int border_side = trigger_sides[i][1];
     int border_element;
 
     if (!IN_LEV_FIELD(xx, yy))
@@ -7685,6 +9968,8 @@ void TestIfPlayerTouchesCustomElement(int x, int y)
 
     if (IS_PLAYER(x, y))
     {
+      struct PlayerInfo *player = PLAYERINFO(x, y);
+
       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))
@@ -7694,25 +9979,45 @@ void TestIfPlayerTouchesCustomElement(int x, int y)
       else
        continue;               /* center and border element do not touch */
 
-      CheckTriggeredElementSideChange(xx, yy, border_element, border_side,
-                                     CE_OTHER_GETS_TOUCHED);
-      CheckElementSideChange(xx, yy, border_element, border_side,
-                            CE_TOUCHED_BY_PLAYER, -1);
+#if 1
+      /* !!! TEST ONLY !!! */
+      CheckElementChangeByPlayer(xx, yy, border_element, CE_TOUCHED_BY_PLAYER,
+                                player->index_bit, border_side);
+      CheckTriggeredElementChangeByPlayer(xx, yy, border_element,
+                                         CE_OTHER_GETS_TOUCHED,
+                                         player->index_bit, border_side);
+#else
+      CheckTriggeredElementChangeByPlayer(xx, yy, border_element,
+                                         CE_OTHER_GETS_TOUCHED,
+                                         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))
     {
+      struct PlayerInfo *player = PLAYERINFO(xx, yy);
+
       if (game.engine_version >= VERSION_IDENT(3,0,7,0))
       {
-       struct PlayerInfo *player = PLAYERINFO(xx, yy);
-
        if (player->MovPos != 0 && !(player->MovDir & touch_dir[i]))
          continue;             /* center and border element do not touch */
       }
 
-      CheckTriggeredElementSideChange(x, y, center_element, center_side,
-                                     CE_OTHER_GETS_TOUCHED);
-      CheckElementSideChange(x, y, center_element, center_side,
-                            CE_TOUCHED_BY_PLAYER, -1);
+#if 1
+      /* !!! TEST ONLY !!! */
+      CheckElementChangeByPlayer(x, y, center_element, CE_TOUCHED_BY_PLAYER,
+                                player->index_bit, center_side);
+      CheckTriggeredElementChangeByPlayer(x, y, center_element,
+                                         CE_OTHER_GETS_TOUCHED,
+                                         player->index_bit, center_side);
+#else
+      CheckTriggeredElementChangeByPlayer(x, y, center_element,
+                                         CE_OTHER_GETS_TOUCHED,
+                                         player->index_bit, center_side);
+      CheckElementChangeByPlayer(x, y, center_element, CE_TOUCHED_BY_PLAYER,
+                                player->index_bit, center_side);
+#endif
 
       break;
     }
@@ -7728,7 +10033,7 @@ void TestIfElementTouchesCustomElement(int x, int y)
     { +1, 0 },
     { 0, +1 }
   };
-  static int change_sides[4][2] =
+  static int trigger_sides[4][2] =
   {
     /* center side     border side */
     { CH_SIDE_TOP,     CH_SIDE_BOTTOM  },      /* check top    */
@@ -7746,14 +10051,15 @@ void TestIfElementTouchesCustomElement(int x, int y)
   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;
 
-  for (i = 0; i < 4; i++)
+  for (i = 0; i < NUM_DIRECTIONS; i++)
   {
     int xx = x + xy[i][0];
     int yy = y + xy[i][1];
-    int center_side = change_sides[i][0];
-    int border_side = change_sides[i][1];
+    int center_side = trigger_sides[i][0];
+    int border_side = trigger_sides[i][1];
     int border_element;
 
     if (!IN_LEV_FIELD(xx, yy))
@@ -7780,11 +10086,17 @@ void TestIfElementTouchesCustomElement(int x, int y)
 
        if (change->can_change &&
            change->events & CH_EVENT_BIT(CE_OTHER_IS_TOUCHING) &&
-           change->sides & border_side &&
-           change->trigger_element == border_element)
+           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;
        }
@@ -7802,11 +10114,20 @@ void TestIfElementTouchesCustomElement(int x, int y)
 
        if (change->can_change &&
            change->events & CH_EVENT_BIT(CE_OTHER_IS_TOUCHING) &&
-           change->sides & center_side &&
-           change->trigger_element == center_element)
+           change->trigger_side & center_side &&
+#if 1
+           IS_EQUAL_OR_IN_GROUP(center_element, change->trigger_element)
+#else
+           change->trigger_element == center_element
+#endif
+           )
        {
-         CheckElementSideChange(xx, yy, border_element, CH_SIDE_ANY,
-                                CE_OTHER_IS_TOUCHING, j);
+#if 0
+         printf("::: border_element %d, %d\n", x, y);
+#endif
+
+         CheckElementChangeByPage(xx, yy, border_element, center_element,
+                                  CE_OTHER_IS_TOUCHING, j);
          break;
        }
       }
@@ -7814,13 +10135,234 @@ void TestIfElementTouchesCustomElement(int x, int y)
   }
 
   if (change_center_element)
-    CheckElementSideChange(x, y, center_element, CH_SIDE_ANY,
-                          CE_OTHER_IS_TOUCHING, center_element_change_page);
+  {
+#if 0
+    printf("::: center_element %d, %d\n", x, y);
+#endif
+
+    CheckElementChangeByPage(x, y, center_element, border_trigger_element,
+                            CE_OTHER_IS_TOUCHING, center_element_change_page);
+  }
+}
+
+void TestIfElementHitsCustomElement(int x, int y, int direction)
+{
+  int dx = (direction == MV_LEFT ? -1 : direction == MV_RIGHT ? +1 : 0);
+  int dy = (direction == MV_UP   ? -1 : direction == MV_DOWN  ? +1 : 0);
+  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);
+
+  CheckElementChangeBySide(x, y, hitting_element, touched_element,
+                          CE_HITTING_SOMETHING, direction);
+
+  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;
+
+      CheckElementChangeBySide(hitx, hity, touched_element, hitting_element,
+                              CE_HIT_BY_SOMETHING, opposite_direction);
+
+      if (IS_CUSTOM_ELEMENT(hitting_element) &&
+         HAS_ANY_CHANGE_EVENT(hitting_element, CE_OTHER_IS_HITTING))
+      {
+       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->events & CH_EVENT_BIT(CE_OTHER_IS_HITTING) &&
+             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_HITTING, i);
+           break;
+         }
+       }
+      }
+
+      if (IS_CUSTOM_ELEMENT(touched_element) &&
+         HAS_ANY_CHANGE_EVENT(touched_element, CE_OTHER_GETS_HIT))
+      {
+       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->events & CH_EVENT_BIT(CE_OTHER_GETS_HIT) &&
+             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_HIT, i);
+           break;
+         }
+       }
+      }
+    }
+  }
+}
+
+#if 0
+void TestIfElementSmashesCustomElement(int x, int y, int direction)
+{
+  int dx = (direction == MV_LEFT ? -1 : direction == MV_RIGHT ? +1 : 0);
+  int dy = (direction == MV_UP   ? -1 : direction == MV_DOWN  ? +1 : 0);
+  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);
+
+  CheckElementChangeBySide(x, y, hitting_element, touched_element,
+                          EP_CAN_SMASH_EVERYTHING, direction);
+
+  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;
+
+      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->events & CH_EVENT_BIT(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];
+
+         if (change->can_change &&
+             change->events & CH_EVENT_BIT(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;
+         }
+       }
+      }
+    }
+  }
 }
+#endif
 
 void TestIfGoodThingHitsBadThing(int good_x, int good_y, int good_move_dir)
 {
   int i, kill_x = -1, kill_y = -1;
+  int bad_element = -1;
   static int test_xy[4][2] =
   {
     { 0, -1 },
@@ -7836,12 +10378,13 @@ void TestIfGoodThingHitsBadThing(int good_x, int good_y, int good_move_dir)
     MV_DOWN
   };
 
-  for (i = 0; i < 4; i++)
+  for (i = 0; i < NUM_DIRECTIONS; i++)
   {
     int test_x, test_y, test_move_dir, test_element;
 
     test_x = good_x + test_xy[i][0];
     test_y = good_y + test_xy[i][1];
+
     if (!IN_LEV_FIELD(test_x, test_y))
       continue;
 
@@ -7862,6 +10405,8 @@ void TestIfGoodThingHitsBadThing(int good_x, int good_y, int good_move_dir)
     {
       kill_x = test_x;
       kill_y = test_y;
+      bad_element = test_element;
+
       break;
     }
   }
@@ -7872,10 +10417,18 @@ 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_PROTECTED(good_x, good_y))
+      else if (!PLAYER_ENEMY_PROTECTED(good_x, good_y))
        KillHero(player);
+#endif
     }
     else
       Bang(good_x, good_y);
@@ -7911,7 +10464,7 @@ void TestIfBadThingHitsGoodThing(int bad_x, int bad_y, int bad_move_dir)
   if (bad_element == EL_EXPLOSION)     /* skip just exploding bad things */
     return;
 
-  for (i = 0; i < 4; i++)
+  for (i = 0; i < NUM_DIRECTIONS; i++)
   {
     int test_x, test_y, test_move_dir, test_element;
 
@@ -7964,10 +10517,18 @@ 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_PROTECTED(kill_x, kill_y))
+      else if (!PLAYER_ENEMY_PROTECTED(kill_x, kill_y))
        KillHero(player);
+#endif
     }
     else
       Bang(kill_x, kill_y);
@@ -8015,7 +10576,7 @@ void TestIfBadThingTouchesOtherBadThing(int bad_x, int bad_y)
     { 0, +1 }
   };
 
-  for (i = 0; i < 4; i++)
+  for (i = 0; i < NUM_DIRECTIONS; i++)
   {
     int x, y, element;
 
@@ -8056,9 +10617,15 @@ void KillHero(struct PlayerInfo *player)
   BuryHero(player);
 }
 
-static void KillHeroUnlessProtected(int x, int y)
+static void KillHeroUnlessEnemyProtected(int x, int y)
 {
-  if (!PLAYER_PROTECTED(x, y))
+  if (!PLAYER_ENEMY_PROTECTED(x, y))
+    KillHero(PLAYERINFO(x, y));
+}
+
+static void KillHeroUnlessExplosionProtected(int x, int y)
+{
+  if (!PLAYER_EXPLOSION_PROTECTED(x, y))
     KillHero(PLAYERINFO(x, y));
 }
 
@@ -8140,46 +10707,62 @@ static boolean checkDiagonalPushing(struct PlayerInfo *player,
 */
 
 int DigField(struct PlayerInfo *player,
-            int x, int y, int real_dx, int real_dy, int mode)
+            int oldx, int oldy, int x, int y,
+            int real_dx, int real_dy, int mode)
 {
-  static int change_sides[4] =
-  {
-    CH_SIDE_RIGHT,     /* moving left  */
-    CH_SIDE_LEFT,      /* moving right */
-    CH_SIDE_BOTTOM,    /* moving up    */
-    CH_SIDE_TOP,       /* moving down  */
-  };
+#if 0
   boolean use_spring_bug = (game.engine_version < VERSION_IDENT(2,2,0,0));
-  int jx = player->jx, jy = player->jy;
+#endif
+  boolean is_player = (IS_PLAYER(oldx, oldy) || mode != DF_DIG);
+  boolean player_was_pushing = player->is_pushing;
+  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 :
                        dx == +1 ? MV_RIGHT :
                        dy == -1 ? MV_UP :
                        dy == +1 ? MV_DOWN : MV_NO_MOVING);
-  int dig_side = change_sides[MV_DIR_BIT(move_direction)];
+  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];
   int element;
 
-  if (player->MovPos == 0)
+  if (is_player)               /* function can also be called by EL_PENGUIN */
   {
-    player->is_digging = FALSE;
-    player->is_collecting = FALSE;
-  }
+    if (player->MovPos == 0)
+    {
+      player->is_digging = FALSE;
+      player->is_collecting = FALSE;
+    }
 
-  if (player->MovPos == 0)     /* last pushing move finished */
-    player->is_pushing = FALSE;
+    if (player->MovPos == 0)   /* last pushing move finished */
+      player->is_pushing = FALSE;
 
-  if (mode == DF_NO_PUSH)      /* player just stopped pushing */
-  {
-    player->is_switching = FALSE;
-    player->push_delay = 0;
+    if (mode == DF_NO_PUSH)    /* player just stopped pushing */
+    {
+      player->is_switching = FALSE;
+      player->push_delay = 0;
 
-    return MF_NO_ACTION;
+      return MF_NO_ACTION;
+    }
   }
 
   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
@@ -8216,14 +10799,45 @@ int DigField(struct PlayerInfo *player,
       return MF_NO_ACTION;     /* tube has no opening in this direction */
   }
 
+#else
+
+  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
+
+#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 0
     case EL_SP_PORT_LEFT:
     case EL_SP_PORT_RIGHT:
     case EL_SP_PORT_UP:
@@ -8235,6 +10849,10 @@ int DigField(struct PlayerInfo *player,
     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 &&
@@ -8258,6 +10876,7 @@ int DigField(struct PlayerInfo *player,
          !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 ||
@@ -8267,11 +10886,28 @@ int DigField(struct PlayerInfo *player,
 
       /* 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:
@@ -8314,19 +10950,37 @@ int DigField(struct PlayerInfo *player,
        PlayLevelSound(x, y, SND_CLASS_TUBE_WALKING);
       }
       break;
+#endif
 
     default:
 
+#if 1
+      if (IS_WALKABLE(element) && ACCESS_FROM(element, opposite_direction))
+#else
       if (IS_WALKABLE(element))
+#endif
       {
+       int sound_element = SND_ELEMENT(element);
        int sound_action = ACTION_WALKING;
 
-       if (element >= EL_GATE_1 && element <= EL_GATE_4)
+#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 (IS_GATE(element))
        {
          if (!player->key[element - EL_GATE_1])
            return MF_NO_ACTION;
        }
-       else if (element >= EL_GATE_1_GRAY && element <= EL_GATE_4_GRAY)
+       else if (IS_GATE_GRAY(element))
        {
          if (!player->key[element - EL_GATE_1_GRAY])
            return MF_NO_ACTION;
@@ -8343,37 +10997,95 @@ int DigField(struct PlayerInfo *player,
        }
 
        /* play sound from background or player, whatever is available */
-       if (element_info[element].sound[sound_action] != SND_UNDEFINED)
-         PlayLevelSoundElementAction(x, y, element, sound_action);
+       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);
 
        break;
       }
+#if 1
+      else if (IS_PASSABLE(element) && canPassField(x, y, move_direction))
+#else
       else if (IS_PASSABLE(element))
+#endif
       {
+#if 0
+       if (!canPassField(x, y, move_direction))
+         return MF_NO_ACTION;
+#else
+
+#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;
+#endif
+#endif
+
+#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 */
+#endif
 
 #if 1
        if (CAN_MOVE(element))  /* only fixed elements can be passed! */
          return MF_NO_ACTION;
 #endif
 
-       if (element >= EL_EM_GATE_1 && element <= EL_EM_GATE_4)
+#endif
+
+       if (IS_EM_GATE(element))
        {
          if (!player->key[element - EL_EM_GATE_1])
            return MF_NO_ACTION;
        }
-       else if (element >= EL_EM_GATE_1_GRAY && element <= EL_EM_GATE_4_GRAY)
+       else if (IS_EM_GATE_GRAY(element))
        {
          if (!player->key[element - EL_EM_GATE_1_GRAY])
            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;
+       }
 
        /* 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
 
        PlayLevelSoundAction(x, y, ACTION_PASSING);
 
@@ -8396,7 +11108,8 @@ int DigField(struct PlayerInfo *player,
 
        PlayLevelSoundElementAction(x, y, element, ACTION_DIGGING);
 
-       CheckTriggeredElementChange(x, y, element, CE_OTHER_GETS_DIGGED);
+       CheckTriggeredElementChangeByPlayer(x, y, element,CE_OTHER_GETS_DIGGED,
+                                           player->index_bit, dig_side);
 
 #if 1
        if (mode == DF_SNAP)
@@ -8409,7 +11122,7 @@ int DigField(struct PlayerInfo *player,
       {
        RemoveField(x, y);
 
-       if (mode != DF_SNAP)
+       if (is_player && mode != DF_SNAP)
        {
          GfxElement[x][y] = element;
          player->is_collecting = TRUE;
@@ -8420,7 +11133,7 @@ int DigField(struct PlayerInfo *player,
        else if (element == EL_EXTRA_TIME && level.time > 0)
        {
          TimeLeft += 10;
-         DrawText(DX_TIME, DY_TIME, int2str(TimeLeft, 3), FONT_TEXT_2);
+         DrawGameValue_Time(TimeLeft);
        }
        else if (element == EL_SHIELD_NORMAL || element == EL_SHIELD_DEADLY)
        {
@@ -8433,8 +11146,7 @@ int DigField(struct PlayerInfo *player,
          if (player->inventory_size < MAX_INVENTORY_SIZE)
            player->inventory_element[player->inventory_size++] = element;
 
-         DrawText(DX_DYNAMITE, DY_DYNAMITE,
-                  int2str(local_player->inventory_size, 3), FONT_TEXT_2);
+         DrawGameValue_Dynamite(local_player->inventory_size);
        }
        else if (element == EL_DYNABOMB_INCREASE_NUMBER)
        {
@@ -8457,8 +11169,8 @@ int DigField(struct PlayerInfo *player,
 
          player->key[key_nr] = TRUE;
 
-         DrawMiniGraphicExt(drawto, DX_KEYS + key_nr * MINI_TILEX, DY_KEYS,
-                            el2edimg(EL_KEY_1 + key_nr));
+         DrawGameValue_Keys(player);
+
          redraw_mask |= REDRAW_DOOR_1;
        }
        else if (IS_ENVELOPE(element))
@@ -8469,16 +11181,19 @@ int DigField(struct PlayerInfo *player,
          ShowEnvelope(element - EL_ENVELOPE_1);
 #endif
        }
-       else if (IS_DROPPABLE(element)) /* can be collected and dropped */
+       else if (IS_DROPPABLE(element) ||
+                IS_THROWABLE(element)) /* can be collected and dropped */
        {
          int i;
 
-         for (i = 0; i < element_info[element].collect_count; i++)
-           if (player->inventory_size < MAX_INVENTORY_SIZE)
-             player->inventory_element[player->inventory_size++] = element;
+         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;
 
-         DrawText(DX_DYNAMITE, DY_DYNAMITE,
-                  int2str(local_player->inventory_size, 3), FONT_TEXT_2);
+         DrawGameValue_Dynamite(local_player->inventory_size);
        }
        else if (element_info[element].collect_count > 0)
        {
@@ -8487,14 +11202,16 @@ int DigField(struct PlayerInfo *player,
          if (local_player->gems_still_needed < 0)
            local_player->gems_still_needed = 0;
 
-         DrawText(DX_EMERALDS, DY_EMERALDS,
-                  int2str(local_player->gems_still_needed, 3), FONT_TEXT_2);
+         DrawGameValue_Emeralds(local_player->gems_still_needed);
        }
 
        RaiseScoreElement(element);
        PlayLevelSoundElementAction(x, y, element, ACTION_COLLECTING);
 
-       CheckTriggeredElementChange(x, y, element, CE_OTHER_GETS_COLLECTED);
+       if (is_player)
+         CheckTriggeredElementChangeByPlayer(x, y, element,
+                                             CE_OTHER_GETS_COLLECTED,
+                                             player->index_bit, dig_side);
 
 #if 1
        if (mode == DF_SNAP)
@@ -8512,7 +11229,7 @@ int DigField(struct PlayerInfo *player,
          return MF_NO_ACTION;
 
        if (CAN_FALL(element) && IN_LEV_FIELD(x, y + 1) && IS_FREE(x, y + 1) &&
-           !(element == EL_SPRING && use_spring_bug))
+           !(element == EL_SPRING && level.use_spring_bug))
          return MF_NO_ACTION;
 
 #if 1
@@ -8541,11 +11258,25 @@ int DigField(struct PlayerInfo *player,
 #endif
 
 #if 1
-       if (game.engine_version >= VERSION_IDENT(3,0,7,1))
+
+#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);
        }
+#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);
+       }
+#endif
        else if (game.engine_version >= VERSION_IDENT(2,2,0,7))
        {
          if (!player->is_pushing)
@@ -8565,9 +11296,12 @@ int DigField(struct PlayerInfo *player,
 #endif
 
 #if 0
-       printf("::: push delay: %ld [%d, %d] [%d]\n",
-              player->push_delay_value, FrameCounter, game.engine_version,
-              player->is_pushing);
+       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
 
        player->is_pushing = TRUE;
@@ -8650,17 +11384,36 @@ int DigField(struct PlayerInfo *player,
        else
          player->push_delay_value = -1;        /* get new value later */
 
-       CheckTriggeredElementSideChange(x, y, element, dig_side,
-                                       CE_OTHER_GETS_PUSHED);
-       CheckElementSideChange(x, y, element, dig_side,
-                              CE_PUSHED_BY_PLAYER, -1);
+#if 1
+       /* check for element change _after_ element has been pushed! */
+#else
+
+#if 1
+      /* !!! TEST ONLY !!! */
+       CheckElementChangeByPlayer(x, y, element, CE_PUSHED_BY_PLAYER,
+                                  player->index_bit, dig_side);
+       CheckTriggeredElementChangeByPlayer(x, y, element,CE_OTHER_GETS_PUSHED,
+                                           player->index_bit, dig_side);
+#else
+       CheckTriggeredElementChangeByPlayer(x, y, element,CE_OTHER_GETS_PUSHED,
+                                           player->index_bit, dig_side);
+       CheckElementChangeByPlayer(x, y, element, CE_PUSHED_BY_PLAYER,
+                                  player->index_bit, dig_side);
+#endif
+#endif
 
        break;
       }
       else if (IS_SWITCHABLE(element))
       {
        if (PLAYER_SWITCHING(player, x, y))
+       {
+         CheckTriggeredElementChangeByPlayer(x,y, element,
+                                             CE_OTHER_GETS_PRESSED,
+                                             player->index_bit, dig_side);
+
          return MF_ACTION;
+       }
 
        player->is_switching = TRUE;
        player->switch_x = x;
@@ -8738,7 +11491,7 @@ int DigField(struct PlayerInfo *player,
        {
          Feld[x][y] = EL_TIME_ORB_EMPTY;
          TimeLeft += 10;
-         DrawText(DX_TIME, DY_TIME, int2str(TimeLeft, 3), FONT_TEXT_2);
+         DrawGameValue_Time(TimeLeft);
 
          DrawLevelField(x, y);
 
@@ -8747,6 +11500,13 @@ int DigField(struct PlayerInfo *player,
 #endif
        }
 
+       CheckTriggeredElementChangeByPlayer(x, y, element,
+                                           CE_OTHER_IS_SWITCHING,
+                                           player->index_bit, dig_side);
+
+       CheckTriggeredElementChangeByPlayer(x,y, element,CE_OTHER_GETS_PRESSED,
+                                           player->index_bit, dig_side);
+
        return MF_ACTION;
       }
       else
@@ -8757,15 +11517,34 @@ int DigField(struct PlayerInfo *player,
          player->switch_x = x;
          player->switch_y = y;
 
-         CheckTriggeredElementSideChange(x, y, element, dig_side,
-                                         CE_OTHER_IS_SWITCHING);
-         CheckElementSideChange(x, y, element, dig_side, CE_SWITCHED, -1);
+#if 1
+         /* !!! TEST ONLY !!! */
+         CheckElementChangeByPlayer(x, y, element, CE_SWITCHED,
+                                    player->index_bit, dig_side);
+         CheckTriggeredElementChangeByPlayer(x, y, element,
+                                             CE_OTHER_IS_SWITCHING,
+                                             player->index_bit, dig_side);
+#else
+         CheckTriggeredElementChangeByPlayer(x, y, element,
+                                             CE_OTHER_IS_SWITCHING,
+                                             player->index_bit, dig_side);
+         CheckElementChangeByPlayer(x, y, element, CE_SWITCHED,
+                                    player->index_bit, dig_side);
+#endif
        }
 
-       CheckTriggeredElementSideChange(x, y, element, dig_side,
-                                       CE_OTHER_GETS_PRESSED);
-       CheckElementSideChange(x, y, element, dig_side,
-                              CE_PRESSED_BY_PLAYER, -1);
+#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_OTHER_GETS_PRESSED,
+                                           player->index_bit, dig_side);
+#else
+       CheckTriggeredElementChangeByPlayer(x,y, element,CE_OTHER_GETS_PRESSED,
+                                           player->index_bit, dig_side);
+       CheckElementChangeByPlayer(x, y, element, CE_PRESSED_BY_PLAYER,
+                                  player->index_bit, dig_side);
+#endif
       }
 
       return MF_NO_ACTION;
@@ -8788,8 +11567,13 @@ boolean SnapField(struct PlayerInfo *player, int dx, int dy)
                        dy == -1 ? MV_UP :
                        dy == +1 ? MV_DOWN : MV_NO_MOVING);
 
-  if (player->MovPos && game.engine_version >= VERSION_IDENT(2,2,0,0))
+#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;
@@ -8819,91 +11603,267 @@ boolean SnapField(struct PlayerInfo *player, int dx, int dy)
 
   player->MovDir = snap_direction;
 
-  player->is_moving = FALSE;
-  player->is_digging = FALSE;
-  player->is_collecting = FALSE;
+#if 1
+  if (player->MovPos == 0)
+#endif
+  {
+    player->is_moving = FALSE;
+    player->is_digging = FALSE;
+    player->is_collecting = FALSE;
+  }
+
+  player->is_dropping = FALSE;
 
-  if (DigField(player, x, y, 0, 0, DF_SNAP) == MF_NO_ACTION)
+  if (DigField(player, jx, jy, x, y, 0, 0, DF_SNAP) == MF_NO_ACTION)
     return FALSE;
 
   player->is_snapping = TRUE;
 
-  player->is_moving = FALSE;
-  player->is_digging = FALSE;
-  player->is_collecting = FALSE;
+#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;
 }
 
 boolean DropElement(struct PlayerInfo *player)
 {
-  int jx = player->jx, jy = player->jy;
-  int old_element;
+  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 ?
+                     player->inventory_infinite_element :
+                     player->dynabombs_left > 0 ?
+                     EL_DYNABOMB_PLAYER_1_ACTIVE + player->index_nr :
+                     EL_UNDEFINED);
 
-  if (!player->active || player->MovPos)
-    return FALSE;
+  if (IS_THROWABLE(drop_element))
+  {
+    dropx += GET_DX_FROM_DIR(drop_direction);
+    dropy += GET_DY_FROM_DIR(drop_direction);
+
+    if (!IN_LEV_FIELD(dropx, dropy))
+      return FALSE;
+  }
 
-  old_element = Feld[jx][jy];
+  old_element = Feld[dropx][dropy];    /* old element at dropping position */
+  new_element = drop_element;          /* default: no change when dropping */
+
+  /* check if player is active, not moving and ready to drop */
+  if (!player->active || player->MovPos || player->drop_delay > 0)
+    return FALSE;
 
   /* check if player has anything that can be dropped */
-  if (player->inventory_size == 0 && player->dynabombs_left == 0)
+#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)
     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[jx][jy] = old_element;                /* store old element on this field */
+    Back[dropx][dropy] = old_element;  /* store old element on this field */
 
-  MovDelay[jx][jy] = 96;
+  ResetGfxAnimation(dropx, dropy);
+  ResetRandomAnimationValue(dropx, dropy);
 
-  ResetGfxAnimation(jx, jy);
-  ResetRandomAnimationValue(jx, jy);
-
-  if (player->inventory_size > 0)
+  if (player->inventory_size > 0 ||
+      player->inventory_infinite_element != EL_UNDEFINED)
   {
-    int new_element = player->inventory_element[--player->inventory_size];
+    if (player->inventory_size > 0)
+    {
+      player->inventory_size--;
+
+#if 0
+      new_element = player->inventory_element[player->inventory_size];
+#endif
+
+      DrawGameValue_Dynamite(local_player->inventory_size);
 
-    Feld[jx][jy] = (new_element == EL_DYNAMITE ? EL_DYNAMITE_ACTIVE :
-                   new_element == EL_SP_DISK_RED ? EL_SP_DISK_RED_ACTIVE :
-                   new_element);
+      if (new_element == EL_DYNAMITE)
+       new_element = EL_DYNAMITE_ACTIVE;
+      else if (new_element == EL_SP_DISK_RED)
+       new_element = EL_SP_DISK_RED_ACTIVE;
+    }
+
+    Feld[dropx][dropy] = new_element;
 
-    DrawText(DX_DYNAMITE, DY_DYNAMITE,
-            int2str(local_player->inventory_size, 3), FONT_TEXT_2);
+    if (IN_SCR_FIELD(SCREENX(dropx), SCREENY(dropy)))
+      DrawGraphicThruMask(SCREENX(dropx), SCREENY(dropy),
+                         el2img(Feld[dropx][dropy]), 0);
 
-    if (IN_SCR_FIELD(SCREENX(jx), SCREENY(jy)))
-      DrawGraphicThruMask(SCREENX(jx), SCREENY(jy), el2img(Feld[jx][jy]), 0);
+    PlayLevelSoundAction(dropx, dropy, ACTION_DROPPING);
 
-    PlayLevelSoundAction(jx, jy, ACTION_DROPPING);
+#if 1
+    /* needed if previous element just changed to "empty" in the last frame */
+    Changed[dropx][dropy] = 0;         /* allow another change */
+#endif
 
-    CheckTriggeredElementChange(jx, jy, new_element, CE_OTHER_GETS_DROPPED);
-    CheckElementChange(jx, jy, new_element, CE_DROPPED_BY_PLAYER);
+#if 1
+    /* !!! TEST ONLY !!! */
+    CheckElementChangeByPlayer(dropx, dropy, new_element, CE_DROPPED_BY_PLAYER,
+                              player->index_bit, drop_side);
+    CheckTriggeredElementChangeByPlayer(dropx, dropy, new_element,
+                                       CE_OTHER_GETS_DROPPED,
+                                       player->index_bit, drop_side);
+#else
+    CheckTriggeredElementChangeByPlayer(dropx, dropy, new_element,
+                                       CE_OTHER_GETS_DROPPED,
+                                       player->index_bit, drop_side);
+    CheckElementChangeByPlayer(dropx, dropy, new_element, CE_DROPPED_BY_PLAYER,
+                              player->index_bit, drop_side);
+#endif
 
-    TestIfElementTouchesCustomElement(jx, jy);
+    TestIfElementTouchesCustomElement(dropx, dropy);
   }
   else         /* player is dropping a dyna bomb */
   {
     player->dynabombs_left--;
 
-    Feld[jx][jy] =
-      EL_DYNABOMB_PLAYER_1_ACTIVE + (player->element_nr - EL_PLAYER_1);
+#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)))
+      DrawGraphicThruMask(SCREENX(dropx), SCREENY(dropy),
+                         el2img(Feld[dropx][dropy]), 0);
+
+    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)
+      MovDir[dropx][dropy] = drop_direction;
+
+    move_direction = MovDir[dropx][dropy];
+    nextx = dropx + GET_DX_FROM_DIR(move_direction);
+    nexty = dropy + GET_DY_FROM_DIR(move_direction);
+
+#if 1
+    Changed[dropx][dropy] = 0;         /* 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] = 0;       /* 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
 
-    if (IN_SCR_FIELD(SCREENX(jx), SCREENY(jy)))
-      DrawGraphicThruMask(SCREENX(jx), SCREENY(jy), el2img(Feld[jx][jy]), 0);
+#endif
 
-    PlayLevelSoundAction(jx, jy, ACTION_DROPPING);
+#if 0
+    player->drop_delay = 2 * TILEX / move_stepsize + 1;
+#endif
   }
 
+#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;
+
+
   return TRUE;
 }
 
@@ -8986,7 +11946,7 @@ static void PlayLevelSoundAction(int x, int y, int action)
 
 static void PlayLevelSoundElementAction(int x, int y, int element, int action)
 {
-  int sound_effect = element_info[element].sound[action];
+  int sound_effect = element_info[SND_ELEMENT(element)].sound[action];
 
   if (sound_effect != SND_UNDEFINED)
     PlayLevelSound(x, y, sound_effect);
@@ -8995,7 +11955,7 @@ static void PlayLevelSoundElementAction(int x, int y, int element, int action)
 static void PlayLevelSoundElementActionIfLoop(int x, int y, int element,
                                              int action)
 {
-  int sound_effect = element_info[element].sound[action];
+  int sound_effect = element_info[SND_ELEMENT(element)].sound[action];
 
   if (sound_effect != SND_UNDEFINED && IS_LOOP_SOUND(sound_effect))
     PlayLevelSound(x, y, sound_effect);
@@ -9003,7 +11963,7 @@ static void PlayLevelSoundElementActionIfLoop(int x, int y, int element,
 
 static void PlayLevelSoundActionIfLoop(int x, int y, int action)
 {
-  int sound_effect = element_info[Feld[x][y]].sound[action];
+  int sound_effect = element_info[SND_ELEMENT(Feld[x][y])].sound[action];
 
   if (sound_effect != SND_UNDEFINED && IS_LOOP_SOUND(sound_effect))
     PlayLevelSound(x, y, sound_effect);
@@ -9011,7 +11971,7 @@ static void PlayLevelSoundActionIfLoop(int x, int y, int action)
 
 static void StopLevelSoundActionIfLoop(int x, int y, int action)
 {
-  int sound_effect = element_info[Feld[x][y]].sound[action];
+  int sound_effect = element_info[SND_ELEMENT(Feld[x][y])].sound[action];
 
   if (sound_effect != SND_UNDEFINED && IS_LOOP_SOUND(sound_effect))
     StopSound(sound_effect);
@@ -9028,7 +11988,8 @@ static void PlayLevelMusic()
 void RaiseScore(int value)
 {
   local_player->score += value;
-  DrawText(DX_SCORE, DY_SCORE, int2str(local_player->score, 5), FONT_TEXT_2);
+
+  DrawGameValue_Score(local_player->score);
 }
 
 void RaiseScoreElement(int element)
@@ -9109,7 +12070,7 @@ void RequestQuitGame(boolean ask_if_really_quit)
       Request("Do you really want to quit the game ?",
              REQ_ASK | REQ_STAY_CLOSED))
   {
-#if defined(PLATFORM_UNIX)
+#if defined(NETWORK_AVALIABLE)
     if (options.network)
       SendToServer_StopPlaying();
     else
@@ -9121,7 +12082,19 @@ 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
+
   }
 }
 
@@ -9288,7 +12261,7 @@ static void HandleGameButtons(struct GadgetInfo *gi)
     case GAME_CTRL_ID_PAUSE:
       if (options.network)
       {
-#if defined(PLATFORM_UNIX)
+#if defined(NETWORK_AVALIABLE)
        if (tape.pausing)
          SendToServer_ContinuePlaying();
        else
@@ -9302,7 +12275,7 @@ static void HandleGameButtons(struct GadgetInfo *gi)
     case GAME_CTRL_ID_PLAY:
       if (tape.pausing)
       {
-#if defined(PLATFORM_UNIX)
+#if defined(NETWORK_AVALIABLE)
        if (options.network)
          SendToServer_ContinuePlaying();
        else
index 40470ea723b0c30d559c982ac2d2cb2b965aef9e..ba51836515b64bcb36dda560b81aa80201a53fb8 100644 (file)
 
 #include "main.h"
 
-/* score for elements (also used by editor.c) */
-#define SC_EMERALD             0
-#define SC_DIAMOND             1
-#define SC_BUG                 2
-#define SC_SPACESHIP           3
-#define SC_YAMYAM              4
-#define SC_ROBOT               5
-#define SC_PACMAN              6
-#define SC_NUT                 7
-#define SC_DYNAMITE            8
-#define SC_KEY                 9
-#define SC_TIME_BONUS          10
-#define SC_CRYSTAL             11
-#define SC_PEARL               12
-#define SC_SHIELD              13
-
 void GetPlayerConfig(void);
 void DrawGameDoorValues(void);
 void InitGameSound();
@@ -88,7 +72,6 @@ void TestIfBadThingTouchesOtherBadThing(int, int);
 void KillHero(struct PlayerInfo *);
 void BuryHero(struct PlayerInfo *);
 void RemoveHero(struct PlayerInfo *);
-int DigField(struct PlayerInfo *, int, int, int, int, int);
 boolean SnapField(struct PlayerInfo *, int, int);
 boolean DropElement(struct PlayerInfo *);
 
index 9871ed6cd8c3f0c5c0c4dc1ed5ad04a3edeb5837..02b29cdc66275026b1f57773c30654ef56a791c0 100644 (file)
@@ -413,6 +413,9 @@ void InitElementGraphicInfo()
   int num_property_mappings = getImageListPropertyMappingSize();
   int i, act, dir;
 
+  if (graphic_info == NULL)            /* still at startup phase */
+    return;
+
   /* set values to -1 to identify later as "uninitialized" values */
   for (i = 0; i < MAX_NUM_ELEMENTS; i++)
   {
@@ -437,14 +440,15 @@ void InitElementGraphicInfo()
     int direction    = element_to_graphic[i].direction;
     boolean crumbled = element_to_graphic[i].crumbled;
     int graphic      = element_to_graphic[i].graphic;
+    int base_graphic = el2baseimg(element);
 
     if (graphic_info[graphic].bitmap == NULL)
       continue;
 
     if ((action > -1 || direction > -1 || crumbled == TRUE) &&
-       el2img(element) != -1)
+       base_graphic != -1)
     {
-      boolean base_redefined = getImageListEntry(el2img(element))->redefined;
+      boolean base_redefined = getImageListEntry(base_graphic)->redefined;
       boolean act_dir_redefined = getImageListEntry(graphic)->redefined;
 
       /* if the base graphic ("emerald", for example) has been redefined,
@@ -595,7 +599,7 @@ void InitElementGraphicInfo()
     int default_direction_crumbled[NUM_DIRECTIONS];
 
     if (default_graphic == -1)
-      default_graphic = IMG_CHAR_QUESTION;
+      default_graphic = IMG_UNKNOWN;
     if (default_crumbled == -1)
       default_crumbled = IMG_EMPTY;
 
@@ -614,9 +618,9 @@ void InitElementGraphicInfo()
 
     for (act = 0; act < NUM_ACTIONS; act++)
     {
-      boolean act_remove = (act == ACTION_DIGGING ||
-                           act == ACTION_SNAPPING ||
-                           act == ACTION_COLLECTING);
+      boolean act_remove = ((IS_DIGGABLE(i)    && act == ACTION_DIGGING)  ||
+                           (IS_SNAPPABLE(i)   && act == ACTION_SNAPPING) ||
+                           (IS_COLLECTIBLE(i) && act == ACTION_COLLECTING));
       boolean act_turning = (act == ACTION_TURNING_FROM_LEFT ||
                             act == ACTION_TURNING_FROM_RIGHT ||
                             act == ACTION_TURNING_FROM_UP ||
@@ -641,6 +645,15 @@ void InitElementGraphicInfo()
       if (IS_SB_ELEMENT(i) && element_info[EL_SB_DEFAULT].crumbled[act] != -1)
        default_action_crumbled = element_info[EL_SB_DEFAULT].crumbled[act];
 
+#if 1
+      /* !!! make this better !!! */
+      if (i == EL_EMPTY_SPACE)
+      {
+       default_action_graphic = element_info[EL_DEFAULT].graphic[act];
+       default_action_crumbled = element_info[EL_DEFAULT].crumbled[act];
+      }
+#endif
+
       if (default_action_graphic == -1)
        default_action_graphic = default_graphic;
       if (default_action_crumbled == -1)
@@ -720,8 +733,8 @@ void InitElementGraphicInfo()
   if (options.verbose)
   {
     for (i = 0; i < MAX_NUM_ELEMENTS; i++)
-      if (element_info[i].graphic[ACTION_DEFAULT] == IMG_CHAR_QUESTION &&
-         i != EL_CHAR_QUESTION)
+      if (element_info[i].graphic[ACTION_DEFAULT] == IMG_UNKNOWN &&
+         i != EL_UNKNOWN)
        Error(ERR_RETURN, "warning: no graphic for element '%s' (%d)",
              element_info[i].token_name, i);
   }
@@ -747,7 +760,8 @@ void InitElementSpecialGraphicInfo()
     int element = element_to_special_graphic[i].element;
     int special = element_to_special_graphic[i].special;
     int graphic = element_to_special_graphic[i].graphic;
-    boolean base_redefined = getImageListEntry(el2img(element))->redefined;
+    int base_graphic = el2baseimg(element);
+    boolean base_redefined = getImageListEntry(base_graphic)->redefined;
     boolean special_redefined = getImageListEntry(graphic)->redefined;
 
     /* if the base graphic ("emerald", for example) has been redefined,
@@ -1557,6 +1571,158 @@ static void ReinitializeMusic()
   InitGameModeMusicInfo();     /* game mode music mapping */
 }
 
+static int get_special_property_bit(int element, int property_bit_nr)
+{
+  struct PropertyBitInfo
+  {
+    int element;
+    int bit_nr;
+  };
+
+  static struct PropertyBitInfo pb_can_move_into_acid[] =
+  {
+    /* the player may be able fall into acid when gravity is activated */
+    { EL_PLAYER_1,             0       },
+    { EL_PLAYER_2,             0       },
+    { EL_PLAYER_3,             0       },
+    { EL_PLAYER_4,             0       },
+    { EL_SP_MURPHY,            0       },
+    { EL_SOKOBAN_FIELD_PLAYER, 0       },
+
+    /* all element that can move may be able to also move into acid */
+    { EL_BUG,                  1       },
+    { EL_BUG_LEFT,             1       },
+    { EL_BUG_RIGHT,            1       },
+    { EL_BUG_UP,               1       },
+    { EL_BUG_DOWN,             1       },
+    { EL_SPACESHIP,            2       },
+    { EL_SPACESHIP_LEFT,       2       },
+    { EL_SPACESHIP_RIGHT,      2       },
+    { EL_SPACESHIP_UP,         2       },
+    { EL_SPACESHIP_DOWN,       2       },
+    { EL_BD_BUTTERFLY,         3       },
+    { EL_BD_BUTTERFLY_LEFT,    3       },
+    { EL_BD_BUTTERFLY_RIGHT,   3       },
+    { EL_BD_BUTTERFLY_UP,      3       },
+    { EL_BD_BUTTERFLY_DOWN,    3       },
+    { EL_BD_FIREFLY,           4       },
+    { EL_BD_FIREFLY_LEFT,      4       },
+    { EL_BD_FIREFLY_RIGHT,     4       },
+    { EL_BD_FIREFLY_UP,                4       },
+    { EL_BD_FIREFLY_DOWN,      4       },
+    { EL_YAMYAM,               5       },
+    { EL_DARK_YAMYAM,          6       },
+    { EL_ROBOT,                        7       },
+    { EL_PACMAN,               8       },
+    { EL_PACMAN_LEFT,          8       },
+    { EL_PACMAN_RIGHT,         8       },
+    { EL_PACMAN_UP,            8       },
+    { EL_PACMAN_DOWN,          8       },
+    { EL_MOLE,                 9       },
+    { EL_MOLE_LEFT,            9       },
+    { EL_MOLE_RIGHT,           9       },
+    { EL_MOLE_UP,              9       },
+    { EL_MOLE_DOWN,            9       },
+    { EL_PENGUIN,              10      },
+    { EL_PIG,                  11      },
+    { EL_DRAGON,               12      },
+    { EL_SATELLITE,            13      },
+    { EL_SP_SNIKSNAK,          14      },
+    { EL_SP_ELECTRON,          15      },
+    { EL_BALLOON,              16      },
+    { EL_SPRING,               17      },
+
+    { -1,                      -1      },
+  };
+
+  static struct PropertyBitInfo pb_dont_collide_with[] =
+  {
+    { EL_SP_SNIKSNAK,          0       },
+    { EL_SP_ELECTRON,          1       },
+
+    { -1,                      -1      },
+  };
+
+  static struct
+  {
+    int bit_nr;
+    struct PropertyBitInfo *pb_info;
+  } pb_definition[] =
+  {
+    { EP_CAN_MOVE_INTO_ACID,   pb_can_move_into_acid   },
+    { EP_DONT_COLLIDE_WITH,    pb_dont_collide_with    },
+
+    { -1,                      NULL                    },
+  };
+
+  struct PropertyBitInfo *pb_info = NULL;
+  int i;
+
+  for (i = 0; pb_definition[i].bit_nr != -1; i++)
+    if (pb_definition[i].bit_nr == property_bit_nr)
+      pb_info = pb_definition[i].pb_info;
+
+  if (pb_info == NULL)
+    return -1;
+
+  for (i = 0; pb_info[i].element != -1; i++)
+    if (pb_info[i].element == element)
+      return pb_info[i].bit_nr;
+
+  return -1;
+}
+
+#if 1
+void setBitfieldProperty(int *bitfield, int property_bit_nr, int element,
+                        boolean property_value)
+{
+  int bit_nr = get_special_property_bit(element, property_bit_nr);
+
+  if (bit_nr > -1)
+  {
+    if (property_value)
+      *bitfield |=  (1 << bit_nr);
+    else
+      *bitfield &= ~(1 << bit_nr);
+  }
+}
+
+boolean getBitfieldProperty(int *bitfield, int property_bit_nr, int element)
+{
+  int bit_nr = get_special_property_bit(element, property_bit_nr);
+
+  if (bit_nr > -1)
+    return ((*bitfield & (1 << bit_nr)) != 0);
+
+  return FALSE;
+}
+
+#else
+
+void setMoveIntoAcidProperty(struct LevelInfo *level, int element, boolean set)
+{
+  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 (set)
+      level->can_move_into_acid_bits |= (1 << bit_nr);
+  }
+}
+
+boolean getMoveIntoAcidProperty(struct LevelInfo *level, int element)
+{
+  int bit_nr = get_special_property_bit(element, EP_CAN_MOVE_INTO_ACID);
+
+  if (bit_nr > -1)
+    return ((level->can_move_into_acid_bits & (1 << bit_nr)) != 0);
+
+  return FALSE;
+}
+#endif
+
 void InitElementPropertiesStatic()
 {
   static int ep_diggable[] =
@@ -1570,6 +1736,7 @@ void InitElementPropertiesStatic()
     EL_INVISIBLE_SAND_ACTIVE,
 
     /* !!! currently not diggable, but handled by 'ep_dont_run_into' !!! */
+    /* (if amoeba can grow into anything diggable, maybe keep these out) */
 #if 0
     EL_LANDMINE,
     EL_TRAP_ACTIVE,
@@ -1814,6 +1981,7 @@ void InitElementPropertiesStatic()
 
   static int ep_can_move[] =
   {
+    /* same elements as in 'pb_can_move_into_acid' */
     EL_BUG,
     EL_SPACESHIP,
     EL_BD_BUTTERFLY,
@@ -1831,7 +1999,6 @@ void InitElementPropertiesStatic()
     EL_SP_ELECTRON,
     EL_BALLOON,
     EL_SPRING,
-    EL_MAZE_RUNNER,
     -1
   };
 
@@ -1904,14 +2071,14 @@ void InitElementPropertiesStatic()
     -1
   };
 
-  static int ep_can_explode_by_fire[] =
+  static int ep_explodes_by_fire[] =
   {
-    /* same elements as in 'ep_can_explode_impact' */
+    /* same elements as in 'ep_explodes_impact' */
     EL_BOMB,
     EL_SP_DISK_ORANGE,
     EL_DX_SUPABOMB,
 
-    /* same elements as in 'ep_can_explode_smashed' */
+    /* same elements as in 'ep_explodes_smashed' */
     EL_SATELLITE,
     EL_PIG,
     EL_DRAGON,
@@ -1934,12 +2101,15 @@ void InitElementPropertiesStatic()
     EL_SP_DISK_YELLOW,
     EL_SP_SNIKSNAK,
     EL_SP_ELECTRON,
+#if 0
+    EL_BLACK_ORB,
+#endif
     -1
   };
 
-  static int ep_can_explode_smashed[] =
+  static int ep_explodes_smashed[] =
   {
-    /* same elements as in 'ep_can_explode_impact' */
+    /* same elements as in 'ep_explodes_impact' */
     EL_BOMB,
     EL_SP_DISK_ORANGE,
     EL_DX_SUPABOMB,
@@ -1952,7 +2122,7 @@ void InitElementPropertiesStatic()
     -1
   };
 
-  static int ep_can_explode_impact[] =
+  static int ep_explodes_impact[] =
   {
     EL_BOMB,
     EL_SP_DISK_ORANGE,
@@ -2031,6 +2201,14 @@ void InitElementPropertiesStatic()
     EL_SP_GRAVITY_PORT_RIGHT,
     EL_SP_GRAVITY_PORT_UP,
     EL_SP_GRAVITY_PORT_DOWN,
+    EL_SP_GRAVITY_ON_PORT_LEFT,
+    EL_SP_GRAVITY_ON_PORT_RIGHT,
+    EL_SP_GRAVITY_ON_PORT_UP,
+    EL_SP_GRAVITY_ON_PORT_DOWN,
+    EL_SP_GRAVITY_OFF_PORT_LEFT,
+    EL_SP_GRAVITY_OFF_PORT_RIGHT,
+    EL_SP_GRAVITY_OFF_PORT_UP,
+    EL_SP_GRAVITY_OFF_PORT_DOWN,
     -1
   };
 
@@ -2044,7 +2222,7 @@ void InitElementPropertiesStatic()
     -1
   };
 
-  static int ep_can_explode_1x1[] =
+  static int ep_explodes_1x1_old[] =
   {
     -1
   };
@@ -2068,6 +2246,131 @@ void InitElementPropertiesStatic()
     -1
   };
 
+  static int ep_explodes_cross_old[] =
+  {
+    -1
+  };
+
+  static int ep_protected[] =
+  {
+    /* same elements as in 'ep_walkable_inside' */
+    EL_TUBE_ANY,
+    EL_TUBE_VERTICAL,
+    EL_TUBE_HORIZONTAL,
+    EL_TUBE_VERTICAL_LEFT,
+    EL_TUBE_VERTICAL_RIGHT,
+    EL_TUBE_HORIZONTAL_UP,
+    EL_TUBE_HORIZONTAL_DOWN,
+    EL_TUBE_LEFT_UP,
+    EL_TUBE_LEFT_DOWN,
+    EL_TUBE_RIGHT_UP,
+    EL_TUBE_RIGHT_DOWN,
+
+    /* same elements as in 'ep_passable_over' */
+    EL_EM_GATE_1,
+    EL_EM_GATE_2,
+    EL_EM_GATE_3,
+    EL_EM_GATE_4,
+    EL_EM_GATE_1_GRAY,
+    EL_EM_GATE_2_GRAY,
+    EL_EM_GATE_3_GRAY,
+    EL_EM_GATE_4_GRAY,
+    EL_SWITCHGATE_OPEN,
+    EL_TIMEGATE_OPEN,
+
+    /* same elements as in 'ep_passable_inside' */
+    EL_SP_PORT_LEFT,
+    EL_SP_PORT_RIGHT,
+    EL_SP_PORT_UP,
+    EL_SP_PORT_DOWN,
+    EL_SP_PORT_HORIZONTAL,
+    EL_SP_PORT_VERTICAL,
+    EL_SP_PORT_ANY,
+    EL_SP_GRAVITY_PORT_LEFT,
+    EL_SP_GRAVITY_PORT_RIGHT,
+    EL_SP_GRAVITY_PORT_UP,
+    EL_SP_GRAVITY_PORT_DOWN,
+    EL_SP_GRAVITY_ON_PORT_LEFT,
+    EL_SP_GRAVITY_ON_PORT_RIGHT,
+    EL_SP_GRAVITY_ON_PORT_UP,
+    EL_SP_GRAVITY_ON_PORT_DOWN,
+    EL_SP_GRAVITY_OFF_PORT_LEFT,
+    EL_SP_GRAVITY_OFF_PORT_RIGHT,
+    EL_SP_GRAVITY_OFF_PORT_UP,
+    EL_SP_GRAVITY_OFF_PORT_DOWN,
+    -1
+  };
+
+  static int ep_throwable[] =
+  {
+    -1
+  };
+
+  static int ep_can_explode[] =
+  {
+    /* same elements as in 'ep_explodes_impact' */
+    EL_BOMB,
+    EL_SP_DISK_ORANGE,
+    EL_DX_SUPABOMB,
+
+    /* same elements as in 'ep_explodes_smashed' */
+    EL_SATELLITE,
+    EL_PIG,
+    EL_DRAGON,
+    EL_MOLE,
+
+    /* elements that can explode by explosion or by dragonfire */
+    EL_DYNAMITE_ACTIVE,
+    EL_DYNAMITE,
+    EL_DYNABOMB_PLAYER_1_ACTIVE,
+    EL_DYNABOMB_PLAYER_2_ACTIVE,
+    EL_DYNABOMB_PLAYER_3_ACTIVE,
+    EL_DYNABOMB_PLAYER_4_ACTIVE,
+    EL_DYNABOMB_INCREASE_NUMBER,
+    EL_DYNABOMB_INCREASE_SIZE,
+    EL_DYNABOMB_INCREASE_POWER,
+    EL_SP_DISK_RED_ACTIVE,
+    EL_BUG,
+    EL_PENGUIN,
+    EL_SP_DISK_RED,
+    EL_SP_DISK_YELLOW,
+    EL_SP_SNIKSNAK,
+    EL_SP_ELECTRON,
+
+    /* elements that can explode only by explosion */
+    EL_BLACK_ORB,
+    -1
+  };
+
+  static int ep_gravity_reachable[] =
+  {
+    EL_SAND,
+    EL_SP_BASE,
+    EL_TRAP,
+    EL_INVISIBLE_SAND,
+    EL_INVISIBLE_SAND_ACTIVE,
+    EL_SP_PORT_LEFT,
+    EL_SP_PORT_RIGHT,
+    EL_SP_PORT_UP,
+    EL_SP_PORT_DOWN,
+    EL_SP_PORT_HORIZONTAL,
+    EL_SP_PORT_VERTICAL,
+    EL_SP_PORT_ANY,
+    EL_SP_GRAVITY_PORT_LEFT,
+    EL_SP_GRAVITY_PORT_RIGHT,
+    EL_SP_GRAVITY_PORT_UP,
+    EL_SP_GRAVITY_PORT_DOWN,
+    EL_SP_GRAVITY_ON_PORT_LEFT,
+    EL_SP_GRAVITY_ON_PORT_RIGHT,
+    EL_SP_GRAVITY_ON_PORT_UP,
+    EL_SP_GRAVITY_ON_PORT_DOWN,
+    EL_SP_GRAVITY_OFF_PORT_LEFT,
+    EL_SP_GRAVITY_OFF_PORT_RIGHT,
+    EL_SP_GRAVITY_OFF_PORT_UP,
+    EL_SP_GRAVITY_OFF_PORT_DOWN,
+    -1
+  };
+
   static int ep_player[] =
   {
     EL_PLAYER_1,
@@ -2075,6 +2378,8 @@ void InitElementPropertiesStatic()
     EL_PLAYER_3,
     EL_PLAYER_4,
     EL_SP_MURPHY,
+    EL_SOKOBAN_FIELD_PLAYER,
+    EL_TRIGGER_PLAYER,
     -1
   };
 
@@ -2136,6 +2441,9 @@ void InitElementPropertiesStatic()
     EL_EXIT_OPEN,
     EL_STEELWALL,
     EL_PLAYER_1,
+    EL_PLAYER_2,
+    EL_PLAYER_3,
+    EL_PLAYER_4,
     EL_BD_FIREFLY,
     EL_BD_FIREFLY_1,
     EL_BD_FIREFLY_2,
@@ -2148,6 +2456,7 @@ void InitElementPropertiesStatic()
     EL_BD_BUTTERFLY_4,
     EL_BD_AMOEBA,
     EL_CHAR_QUESTION,
+    EL_UNKNOWN,
     -1
   };
 
@@ -2156,6 +2465,7 @@ void InitElementPropertiesStatic()
     /* should always be valid */
     EL_EMPTY,
 
+    /* standard classic Supaplex elements */
     EL_SP_EMPTY,
     EL_SP_ZONK,
     EL_SP_BASE,
@@ -2197,11 +2507,24 @@ void InitElementPropertiesStatic()
     EL_SP_HARDWARE_BASE_6,
     EL_SP_CHIP_TOP,
     EL_SP_CHIP_BOTTOM,
+
     /* additional elements that appeared in newer Supaplex levels */
     EL_INVISIBLE_WALL,
-    /* more than one murphy in a level results in an inactive clone */
+
+    /* additional gravity port elements (not switching, but setting gravity) */
+    EL_SP_GRAVITY_ON_PORT_LEFT,
+    EL_SP_GRAVITY_ON_PORT_RIGHT,
+    EL_SP_GRAVITY_ON_PORT_UP,
+    EL_SP_GRAVITY_ON_PORT_DOWN,
+    EL_SP_GRAVITY_OFF_PORT_LEFT,
+    EL_SP_GRAVITY_OFF_PORT_RIGHT,
+    EL_SP_GRAVITY_OFF_PORT_UP,
+    EL_SP_GRAVITY_OFF_PORT_DOWN,
+
+    /* more than one Murphy in a level results in an inactive clone */
     EL_SP_MURPHY_CLONE,
-    /* runtime elements*/
+
+    /* runtime Supaplex elements */
     EL_SP_DISK_RED_ACTIVE,
     EL_SP_TERMINAL_ACTIVE,
     EL_SP_BUGGY_BASE_ACTIVATING,
@@ -2218,7 +2541,11 @@ void InitElementPropertiesStatic()
     EL_SOKOBAN_OBJECT,
     EL_SOKOBAN_FIELD_EMPTY,
     EL_SOKOBAN_FIELD_FULL,
+    EL_SOKOBAN_FIELD_PLAYER,
     EL_PLAYER_1,
+    EL_PLAYER_2,
+    EL_PLAYER_3,
+    EL_PLAYER_4,
     EL_INVISIBLE_STEELWALL,
     -1
   };
@@ -2643,6 +2970,24 @@ void InitElementPropertiesStatic()
     -1
   };
 
+  static int ep_can_turn_each_move[] =
+  {
+    /* !!! do something with this one !!! */
+    -1
+  };
+
+  static int ep_can_grow[] =
+  {
+    EL_BD_AMOEBA,
+    EL_AMOEBA_DROP,
+    EL_AMOEBA_WET,
+    EL_AMOEBA_DRY,
+    EL_AMOEBA_FULL,
+    EL_GAME_OF_LIFE,
+    EL_BIOMAZE,
+    -1
+  };
+
   static int ep_active_bomb[] =
   {
     EL_DYNAMITE_ACTIVE,
@@ -2754,6 +3099,14 @@ void InitElementPropertiesStatic()
     EL_SP_HARDWARE_BASE_4,
     EL_SP_HARDWARE_BASE_5,
     EL_SP_HARDWARE_BASE_6,
+    EL_SP_GRAVITY_ON_PORT_LEFT,
+    EL_SP_GRAVITY_ON_PORT_RIGHT,
+    EL_SP_GRAVITY_ON_PORT_UP,
+    EL_SP_GRAVITY_ON_PORT_DOWN,
+    EL_SP_GRAVITY_OFF_PORT_LEFT,
+    EL_SP_GRAVITY_OFF_PORT_RIGHT,
+    EL_SP_GRAVITY_OFF_PORT_UP,
+    EL_SP_GRAVITY_OFF_PORT_DOWN,
     EL_CONVEYOR_BELT_1_SWITCH_LEFT,
     EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
     EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
@@ -2827,9 +3180,9 @@ void InitElementPropertiesStatic()
     { ep_can_smash_player,     EP_CAN_SMASH_PLAYER     },
     { ep_can_smash_enemies,    EP_CAN_SMASH_ENEMIES    },
     { ep_can_smash_everything, EP_CAN_SMASH_EVERYTHING },
-    { ep_can_explode_by_fire,  EP_CAN_EXPLODE_BY_FIRE  },
-    { ep_can_explode_smashed,  EP_CAN_EXPLODE_SMASHED  },
-    { ep_can_explode_impact,   EP_CAN_EXPLODE_IMPACT   },
+    { ep_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       },
@@ -2837,8 +3190,13 @@ void InitElementPropertiesStatic()
     { ep_passable_inside,      EP_PASSABLE_INSIDE      },
     { ep_passable_under,       EP_PASSABLE_UNDER       },
     { ep_droppable,            EP_DROPPABLE            },
-    { ep_can_explode_1x1,      EP_CAN_EXPLODE_1X1      },
+    { 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  },
@@ -2861,6 +3219,8 @@ void InitElementPropertiesStatic()
     { 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             },
 
@@ -2898,6 +3258,11 @@ void InitElementPropertiesStatic()
       EL_PACMAN_LEFT,          EL_PACMAN_RIGHT,
       EL_PACMAN_UP,            EL_PACMAN_DOWN
     },
+    {
+      EL_MOLE,
+      EL_MOLE_LEFT,            EL_MOLE_RIGHT,
+      EL_MOLE_UP,              EL_MOLE_DOWN
+    },
     {
       -1,
       -1, -1, -1, -1
@@ -2942,7 +3307,7 @@ void InitElementPropertiesEngine(int engine_version)
     EP_DONT_TOUCH,
     EP_DONT_RUN_INTO,
     EP_GEM,
-    EP_CAN_EXPLODE_BY_FIRE,
+    EP_EXPLODES_BY_FIRE,
     EP_PUSHABLE,
     EP_PLAYER,
     EP_HAS_CONTENT,
@@ -2984,6 +3349,7 @@ void InitElementPropertiesEngine(int engine_version)
     EP_ACTIVE_BOMB,
 
     EP_ACCESSIBLE,
+
     -1
   };
 
@@ -2993,6 +3359,12 @@ void InitElementPropertiesEngine(int engine_version)
   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 */
   for (i = 0; i < MAX_NUM_ELEMENTS; i++)
   {
@@ -3002,8 +3374,7 @@ void InitElementPropertiesEngine(int engine_version)
 #endif
 
     /* ---------- INACTIVE ------------------------------------------------- */
-    if (i >= EL_CHAR_START && i <= EL_CHAR_END)
-      SET_PROPERTY(i, EP_INACTIVE, TRUE);
+    SET_PROPERTY(i, EP_INACTIVE, (i >= EL_CHAR_START && i <= EL_CHAR_END));
 
     /* ---------- WALKABLE, PASSABLE, ACCESSIBLE --------------------------- */
     SET_PROPERTY(i, EP_WALKABLE, (IS_WALKABLE_OVER(i) ||
@@ -3028,7 +3399,8 @@ void InitElementPropertiesEngine(int engine_version)
 
     /* ---------- COLLECTIBLE ---------------------------------------------- */
     SET_PROPERTY(i, EP_COLLECTIBLE, (IS_COLLECTIBLE_ONLY(i) ||
-                                    IS_DROPPABLE(i)));
+                                    IS_DROPPABLE(i) ||
+                                    IS_THROWABLE(i)));
 
     /* ---------- SNAPPABLE ------------------------------------------------ */
     SET_PROPERTY(i, EP_SNAPPABLE, (IS_DIGGABLE(i) ||
@@ -3055,6 +3427,12 @@ 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)
@@ -3069,12 +3447,25 @@ 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))
     {
+      /* these are additional properties which are initially false when set */
+
       /* ---------- DONT_COLLIDE_WITH / DONT_RUN_INTO ---------------------- */
       if (DONT_TOUCH(i))
        SET_PROPERTY(i, EP_DONT_COLLIDE_WITH, TRUE);
@@ -3093,14 +3484,66 @@ 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_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)));
+
+    /* ---------- CAN_EXPLODE_SMASHED -------------------------------------- */
+    SET_PROPERTY(i, EP_CAN_EXPLODE_SMASHED, (CAN_EXPLODE(i) &&
+                                            EXPLODES_SMASHED(i)));
+
+    /* ---------- CAN_EXPLODE_IMPACT --------------------------------------- */
+    SET_PROPERTY(i, EP_CAN_EXPLODE_IMPACT, (CAN_EXPLODE(i) &&
+                                           EXPLODES_IMPACT(i)));
+
+    /* ---------- CAN_EXPLODE_BY_DRAGONFIRE -------------------------------- */
+    SET_PROPERTY(i, EP_CAN_EXPLODE_BY_DRAGONFIRE, CAN_EXPLODE_BY_FIRE(i));
+
+    /* ---------- CAN_EXPLODE_BY_EXPLOSION --------------------------------- */
+    SET_PROPERTY(i, EP_CAN_EXPLODE_BY_EXPLOSION, (CAN_EXPLODE_BY_FIRE(i) ||
+                                                 i == EL_BLACK_ORB));
+
+    /* ---------- COULD_MOVE_INTO_ACID ------------------------------------- */
+    SET_PROPERTY(i, EP_COULD_MOVE_INTO_ACID, (ELEM_IS_PLAYER(i) ||
+                                             CAN_MOVE(i) ||
+                                             IS_CUSTOM_ELEMENT(i)));
+
+    /* ---------- MAYBE_DONT_COLLIDE_WITH ---------------------------------- */
+    SET_PROPERTY(i, EP_MAYBE_DONT_COLLIDE_WITH, (i == EL_SP_SNIKSNAK ||
+                                                i == EL_SP_ELECTRON));
+
+    /* ---------- CAN_MOVE_INTO_ACID --------------------------------------- */
+    if (COULD_MOVE_INTO_ACID(i) && !IS_CUSTOM_ELEMENT(i))
+      SET_PROPERTY(i, EP_CAN_MOVE_INTO_ACID,
+                  getMoveIntoAcidProperty(&level, i));
+
+    /* ---------- DONT_COLLIDE_WITH ---------------------------------------- */
+    if (MAYBE_DONT_COLLIDE_WITH(i))
+      SET_PROPERTY(i, EP_DONT_COLLIDE_WITH,
+                  getDontCollideWithProperty(&level, i));
+
+    /* ---------- SP_PORT -------------------------------------------------- */
+    SET_PROPERTY(i, EP_SP_PORT, (IS_SP_ELEMENT(i) &&
+                                IS_PASSABLE_INSIDE(i)));
 
     /* ---------- CAN_CHANGE ----------------------------------------------- */
     SET_PROPERTY(i, EP_CAN_CHANGE, FALSE);     /* default: cannot change */
@@ -3179,12 +3622,41 @@ void InitElementPropertiesEngine(int engine_version)
     if (element_info[element].push_delay_random == -1)
       element_info[element].push_delay_random = game.default_push_delay_random;
   }
+
+  /* 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;
+    }
+  }
+
+#if 0
+  /* set element properties that were handled incorrectly in older levels */
+  if (engine_version < VERSION_IDENT(3,1,0,0))
+  {
+    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 */
+  if (game_status == GAME_MODE_PLAYING)
+    InitElementGraphicInfo();
 }
 
 static void InitGlobal()
 {
   global.autoplay_leveldir = NULL;
+  global.convert_leveldir = NULL;
 
   global.frames_per_second = 0;
   global.fps_slowdown = FALSE;
@@ -3320,6 +3792,20 @@ void Execute_Command(char *command)
       global.autoplay_level_nr = atoi(str_ptr);        /* get level_nr value */
     }
   }
+  else if (strncmp(command, "convert ", 8) == 0)
+  {
+    char *str_copy = getStringCopy(&command[8]);
+    char *str_ptr = strchr(str_copy, ' ');
+
+    global.convert_leveldir = str_copy;
+    global.convert_level_nr = -1;
+
+    if (str_ptr != NULL)
+    {
+      *str_ptr++ = '\0';                       /* terminate leveldir string */
+      global.convert_level_nr = atoi(str_ptr); /* get level_nr value */
+    }
+  }
   else
   {
     Error(ERR_EXIT_HELP, "unrecognized command '%s'", command);
@@ -3661,14 +4147,14 @@ static void InitMusic(char *identifier)
 
 void InitNetworkServer()
 {
-#if defined(PLATFORM_UNIX)
+#if defined(NETWORK_AVALIABLE)
   int nr_wanted;
 #endif
 
   if (!options.network)
     return;
 
-#if defined(PLATFORM_UNIX)
+#if defined(NETWORK_AVALIABLE)
   nr_wanted = Request("Choose player", REQ_PLAYER | REQ_STAY_CLOSED);
 
   if (!ConnectToServer(options.server_host, options.server_port))
@@ -3795,14 +4281,17 @@ static char *getNewArtworkIdentifier(int type)
   return artwork_new_identifier;
 }
 
-void ReloadCustomArtwork()
+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);
+  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;
 
-  if (gfx_new_identifier != NULL)
+  if (gfx_new_identifier != NULL || force_reload_gfx)
   {
 #if 0
     printf("RELOADING GRAPHICS '%s' -> '%s' ['%s', '%s']\n",
@@ -3827,7 +4316,7 @@ void ReloadCustomArtwork()
     redraw_screen = TRUE;
   }
 
-  if (snd_new_identifier != NULL)
+  if (snd_new_identifier != NULL || force_reload_snd)
   {
     ClearRectangle(window, 0, 0, WIN_XSIZE, WIN_YSIZE);
 
@@ -3836,7 +4325,7 @@ void ReloadCustomArtwork()
     redraw_screen = TRUE;
   }
 
-  if (mus_new_identifier != NULL)
+  if (mus_new_identifier != NULL || force_reload_mus)
   {
     ClearRectangle(window, 0, 0, WIN_XSIZE, WIN_YSIZE);
 
@@ -3922,6 +4411,11 @@ void OpenAll()
     AutoPlayTape();
     return;
   }
+  else if (global.convert_leveldir)
+  {
+    ConvertLevels();
+    return;
+  }
 
   game_status = GAME_MODE_MAIN;
 
@@ -3940,6 +4434,11 @@ void CloseAllAndExit(int exit_value)
   FreeAllImages();
   FreeTileClipmasks();
 
+#if defined(TARGET_SDL)
+  if (network_server)  /* terminate network server */
+    SDL_KillThread(server_thread);
+#endif
+
   CloseVideoDisplay();
   ClosePlatformDependentStuff();
 
index 67fc835d5d3f17545b6d99456f79a84e36c25eaf..ca22ef6e1662a2c7acd76fb2accae3b710fd36b2 100644 (file)
 
 #include "main.h"
 
+#if 1
+#define setMoveIntoAcidProperty(l, e, v)       \
+       (setBitfieldProperty(&(l)->can_move_into_acid_bits,     \
+                            EP_CAN_MOVE_INTO_ACID, e, v))
+#define getMoveIntoAcidProperty(l, e)          \
+       (getBitfieldProperty(&(l)->can_move_into_acid_bits,     \
+                            EP_CAN_MOVE_INTO_ACID, e))
+#define setDontCollideWithProperty(l, e, v)    \
+       (setBitfieldProperty(&(l)->can_move_into_acid_bits,     \
+                            EP_DONT_COLLIDE_WITH, e, v))
+#define getDontCollideWithProperty(l, e)       \
+       (getBitfieldProperty(&(l)->can_move_into_acid_bits,     \
+                            EP_DONT_COLLIDE_WITH, e))
+
+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 ReloadCustomArtwork(void);
+void ReloadCustomArtwork(int);
 
 void KeyboardAutoRepeatOffUnlessAutoplay();
 
index ddc5ac6016e98877dade4bc05699ed682fc4ad05..8601256cbf3ed1b2da04be5a9422d40f62bf6efd 100644 (file)
@@ -552,15 +552,15 @@ static void DrawGadget(struct GadgetInfo *gi, boolean pressed, boolean direct)
        {
          gi->selectbox.open = FALSE;
 
-         /* redraw closed selectbox */
-         DrawGadget(gi, FALSE, FALSE);
-
          /* restore background under selectbox */
          BlitBitmap(gfx.field_save_buffer, drawto,
                     gi->selectbox.x,     gi->selectbox.y,
                     gi->selectbox.width, gi->selectbox.height,
                     gi->selectbox.x,     gi->selectbox.y);
 
+         /* redraw closed selectbox */
+         DrawGadget(gi, FALSE, FALSE);
+
          redraw_selectbox = TRUE;
        }
       }
@@ -681,6 +681,22 @@ static void DrawGadget(struct GadgetInfo *gi, boolean pressed, boolean direct)
                    gi->y > gfx.vy ? REDRAW_DOOR_2 : REDRAW_DOOR_3);
 }
 
+static int get_minimal_size_for_numeric_input(int minmax_value)
+{
+  int min_size = 1;    /* value needs at least one digit */
+  int i;
+
+  /* add number of digits needed for absolute value */
+  for (i = 10; i <= ABS(minmax_value); i *= 10)
+    min_size++;
+
+  /* if min/max value is negative, add one digit for minus sign */
+  if (minmax_value < 0)
+    min_size++;
+
+  return min_size;
+}
+
 static void HandleGadgetTags(struct GadgetInfo *gi, int first_tag, va_list ap)
 {
   int tag = first_tag;
@@ -985,6 +1001,19 @@ static void HandleGadgetTags(struct GadgetInfo *gi, int first_tag, va_list ap)
     int border_xsize = gi->border.xsize;
     int border_ysize = gi->border.ysize;
 
+    if (gi->type == GD_TYPE_TEXT_INPUT_NUMERIC)
+    {
+      int number_min = gi->textinput.number_min;
+      int number_max = gi->textinput.number_max;
+      int min_size_min = get_minimal_size_for_numeric_input(number_min);
+      int min_size_max = get_minimal_size_for_numeric_input(number_max);
+      int min_size = MAX(min_size_min, min_size_max);
+
+      /* expand gadget text input size, if maximal value is too large */
+      if (gi->textinput.size < min_size)
+       gi->textinput.size = min_size;
+    }
+
     gi->width  = 2 * border_xsize + (gi->textinput.size + 1) * font_width;
     gi->height = 2 * border_ysize + font_height;
   }
@@ -1282,6 +1311,22 @@ static boolean anySelectboxGadgetActive()
   return (last_gi && (last_gi->type & GD_TYPE_SELECTBOX) && last_gi->mapped);
 }
 
+static boolean insideSelectboxLine(struct GadgetInfo *gi, int mx, int my)
+{
+  return(gi != NULL &&
+        gi->type & GD_TYPE_SELECTBOX &&
+        mx >= gi->x && mx < gi->x + gi->width &&
+        my >= gi->y && my < gi->y + gi->height);
+}
+
+static boolean insideSelectboxArea(struct GadgetInfo *gi, int mx, int my)
+{
+  return(gi != NULL &&
+        gi->type & GD_TYPE_SELECTBOX &&
+        mx >= gi->selectbox.x && mx < gi->selectbox.x + gi->selectbox.width &&
+        my >= gi->selectbox.y && my < gi->selectbox.y + gi->selectbox.height);
+}
+
 boolean anyTextGadgetActive()
 {
   return (anyTextInputGadgetActive() ||
@@ -1308,13 +1353,19 @@ boolean HandleGadgets(int mx, int my, int button)
   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;
   int scrollbar_mouse_pos = 0;
   struct GadgetInfo *new_gi, *gi;
   boolean press_event;
   boolean release_event;
   boolean mouse_moving;
+  boolean mouse_inside_select_line;
+  boolean mouse_inside_select_area;
+  boolean mouse_released_where_pressed;
   boolean gadget_pressed;
   boolean gadget_pressed_repeated;
+  boolean gadget_pressed_off_borders;
+  boolean gadget_pressed_inside_select_line;
   boolean gadget_moving;
   boolean gadget_moving_inside;
   boolean gadget_moving_off_borders;
@@ -1349,9 +1400,34 @@ boolean HandleGadgets(int mx, int my, int button)
   last_mx = mx;
   last_my = my;
 
+  if (press_event && new_gi != last_gi)
+  {
+    pressed_mx = mx;
+    pressed_my = my;
+  }
+
+  mouse_released_where_pressed =
+    (release_event && mx == pressed_mx && my == pressed_my);
+
+  mouse_inside_select_line = insideSelectboxLine(new_gi, mx, my);
+  mouse_inside_select_area = insideSelectboxArea(new_gi, mx, my);
+
+  gadget_pressed_off_borders = (press_event && new_gi != last_gi);
+
+  gadget_pressed_inside_select_line =
+    (press_event && new_gi != NULL &&
+     new_gi->type & GD_TYPE_SELECTBOX && new_gi->selectbox.open &&
+     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
   {
     CheckRangeOfNumericInputGadget(last_gi);   /* in case of numeric gadget */
 
@@ -1363,6 +1439,9 @@ boolean HandleGadgets(int mx, int my, int button)
       last_gi->callback_action(last_gi);
 
     last_gi = NULL;
+
+    if (gadget_pressed_inside_select_line)
+      new_gi = NULL;
   }
 
   gadget_pressed =
@@ -1383,12 +1462,17 @@ boolean HandleGadgets(int mx, int my, int button)
   {
     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
   }
   else
   {
@@ -1411,12 +1495,23 @@ boolean HandleGadgets(int mx, int my, int button)
   /* if mouse button released, no gadget needs to be handled anymore */
   if (gadget_released)
   {
-    if (last_gi->type & GD_TYPE_SELECTBOX &&
+#if 1
+    if (gi->type & GD_TYPE_SELECTBOX &&
+       (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;
-    else if (!(last_gi->type & GD_TYPE_TEXT_INPUT ||
-              last_gi->type & GD_TYPE_TEXT_AREA))  /* text input stays open */
+#endif
+    else if (!(gi->type & GD_TYPE_TEXT_INPUT ||
+              gi->type & GD_TYPE_TEXT_AREA))       /* text input stays open */
       last_gi = NULL;
   }
 
@@ -1470,7 +1565,7 @@ 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)
+    else if (gi->type & GD_TYPE_SELECTBOX && gi->selectbox.open)
     {
       int old_index = gi->selectbox.current_index;
 
@@ -1689,9 +1784,15 @@ boolean HandleGadgets(int mx, int my, int button)
 
     if (gi->type & GD_TYPE_SELECTBOX)
     {
+#if 1
+      if (mouse_released_where_pressed ||
+         !gadget_released_inside_select_area)       /* selectbox stays open */
+       deactivate_gadget = FALSE;
+#else
       if (gadget_released_inside_select_line ||
-         gadget_released_off_borders)              /* selectbox stays open */
+         gadget_released_off_borders)               /* selectbox stays open */
        deactivate_gadget = FALSE;
+#endif
       else
        gi->selectbox.index = gi->selectbox.current_index;
     }
index e267fd8099604e7005ea4144be13746c60d66f86..108fd39c3fc4d80033e2748b64170bc1ee5f88a1 100644 (file)
@@ -560,7 +560,7 @@ XImageInfo *Image_to_Pixmap(Display *display, int screen, Visual *visual,
   XPutImage(ximageinfo->display, ximageinfo->pixmap, gc,
            ximage, 0, 0, 0, 0, ximage->width, ximage->height);
 
-  XDestroyImage(ximage);
+  X11DestroyImage(ximage);
 
   return ximageinfo;
 }
@@ -621,8 +621,8 @@ void ZoomPixmap(Display *display, GC gc, Pixmap src_pixmap, Pixmap dst_pixmap,
            dst_width, dst_height);
 
   /* free temporary images */
-  XDestroyImage(src_ximage);
-  XDestroyImage(dst_ximage);
+  X11DestroyImage(src_ximage);
+  X11DestroyImage(dst_ximage);
 }
 
 void freeXImage(Image *image, XImageInfo *ximageinfo)
@@ -730,7 +730,7 @@ static void *Load_PCX(char *filename)
 
   if ((img_info->bitmap = LoadImage(filename)) == NULL)
   {
-    Error(ERR_WARN, "cannot read image file '%s': LoadImage() failed: %s",
+    Error(ERR_WARN, "cannot load image file '%s': LoadImage() failed: %s",
          filename, GetError());
     free(img_info);
     return NULL;
index 06ca9357c65f87d792349e44d0fcacaf074098c7..ba3796259bf2e02bd579dee4fba25d6593434e09 100644 (file)
@@ -52,6 +52,7 @@ void printf_line(char *line_string, int line_length)
   fprintf_line(stdout, line_string, line_length);
 }
 
+
 /* int2str() returns a number converted to a string;
    the used memory is static, but will be overwritten by later calls,
    so if you want to save the result, copy it to a private string buffer;
@@ -82,6 +83,7 @@ char *int2str(int number, int size)
   }
 }
 
+
 /* something similar to "int2str()" above, but allocates its own memory
    and has a different interface; we cannot use "itoa()", because this
    seems to be already defined when cross-compiling to the win32 target */
@@ -103,6 +105,23 @@ char *i_to_a(unsigned int i)
 }
 
 
+/* calculate base-2 logarithm of argument (rounded down to integer;
+   this function returns the number of the highest bit set in argument) */
+
+int log_2(unsigned int x)
+{
+  int e = 0;
+
+  while ((1 << e) < x)
+  {
+    x -= (1 << e);     /* for rounding down (rounding up: remove this line) */
+    e++;
+  }
+
+  return e;
+}
+
+
 /* ------------------------------------------------------------------------- */
 /* counter functions                                                         */
 /* ------------------------------------------------------------------------- */
@@ -596,9 +615,17 @@ void GetOptions(char *argv[], void (*print_usage_function)(void))
       if (option_arg == next_option)
        options_left++;
 
-      /* adjust path for level directory accordingly */
+      /* adjust paths for sub-directories in base directory accordingly */
       options.level_directory =
        getPath2(options.ro_base_directory, LEVELS_DIRECTORY);
+      options.graphics_directory =
+       getPath2(options.ro_base_directory, GRAPHICS_DIRECTORY);
+      options.sounds_directory =
+       getPath2(options.ro_base_directory, SOUNDS_DIRECTORY);
+      options.music_directory =
+       getPath2(options.ro_base_directory, MUSIC_DIRECTORY);
+      options.docs_directory =
+       getPath2(options.ro_base_directory, DOCS_DIRECTORY);
     }
     else if (strncmp(option, "-levels", option_len) == 0)
     {
@@ -660,6 +687,11 @@ void GetOptions(char *argv[], void (*print_usage_function)(void))
       options.execute_command = option_arg;
       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 == '-')
     {
@@ -850,27 +882,27 @@ inline void swap_number_pairs(int *x1, int *y1, int *x2, int *y2)
   *y2 = help_y;
 }
 
-short getFile16BitInteger(FILE *file, int byte_order)
+int getFile16BitInteger(FILE *file, int byte_order)
 {
   if (byte_order == BYTE_ORDER_BIG_ENDIAN)
-    return ((fgetc(file) <<  8) |
-           (fgetc(file) <<  0));
+    return ((fgetc(file) << 8) |
+           (fgetc(file) << 0));
   else          /* BYTE_ORDER_LITTLE_ENDIAN */
-    return ((fgetc(file) <<  0) |
-           (fgetc(file) <<  8));
+    return ((fgetc(file) << 0) |
+           (fgetc(file) << 8));
 }
 
-void putFile16BitInteger(FILE *file, short value, int byte_order)
+void 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);
+    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 >> 0) & 0xff, file);
+    fputc((value >> 8) & 0xff, file);
   }
 }
 
@@ -1208,7 +1240,7 @@ void translate_keyname(Key *keysym, char **x11name, char **name, int mode)
       char c = name_ptr[6];
 
       if (c >= '0' && c <= '9')
-       key = KSYM_0 + (Key)(c - '0');
+       key = KSYM_KP_0 + (Key)(c - '0');
     }
     else if (strncmp(name_ptr, "XK_F", 4) == 0 && strlen(name_ptr) <= 6)
     {
@@ -1880,6 +1912,7 @@ static void add_dynamic_file_list_entry(struct FileInfo **list,
   new_list_entry = &(*list)[*num_list_entries - 1];
 
   new_list_entry->token = getStringCopy(token);
+  new_list_entry->default_filename = NULL;
   new_list_entry->filename = NULL;
   new_list_entry->parameter = checked_calloc(parameter_array_size);
 
@@ -2549,9 +2582,17 @@ void ReloadCustomArtworkList(struct ArtworkListInfo *artwork_info)
 #endif
 
   for (i = 0; i < num_dynamic_file_list_entries; i++)
+  {
     LoadArtworkToList(artwork_info, &artwork_info->dynamic_artwork_list[i],
                      dynamic_file_list[i].filename, i);
 
+#if 0
+    printf("::: '%s', '0x%08x'\n",
+          dynamic_file_list[i].filename,
+          dynamic_file_list[i].default_filename);
+#endif
+  }
+
 #if 0
   dumpList(artwork_info->content_list);
 #endif
index af65d4ca98343f432654b389432a3ccfdaaa68cd..2f3a957ab5097fb06c0972a3869b591fc5a74d2f 100644 (file)
@@ -71,6 +71,7 @@ void fprintf_line(FILE *, char *, int);
 void printf_line(char *, int);
 char *int2str(int, int);
 char *i_to_a(unsigned int);
+int log_2(unsigned int);
 
 void InitCounter(void);
 unsigned long Counter(void);
@@ -114,8 +115,8 @@ void checked_free(void *);
 inline void swap_numbers(int *, int *);
 inline void swap_number_pairs(int *, int *, int *, int *);
 
-short getFile16BitInteger(FILE *, int);
-void putFile16BitInteger(FILE *, short, int);
+int getFile16BitInteger(FILE *, int);
+void putFile16BitInteger(FILE *, int, int);
 int getFile32BitInteger(FILE *, int);
 void putFile32BitInteger(FILE *, int, int);
 boolean getFileChunk(FILE *, char *, int *, int);
index 61ab27f6a59d9b365b87b7b85eaceb0621524579..5e1683619d8053a003a5273eabf58e15d2c3a165 100644 (file)
@@ -26,6 +26,7 @@
 #define PLATFORM_UNIX
 #endif
 
+
 /* ========================================================================= */
 /* define additional keywords for MS-DOS platform                            */
 /* ========================================================================= */
@@ -42,6 +43,7 @@
 
 #endif
 
+
 /* ========================================================================= */
 /* define additional keywords for several Unix platforms                     */
 /* ========================================================================= */
 #define PLATFORM_MACOSX
 #endif
 
+#if defined(NeXT)
+#define PLATFORM_NEXT
+#endif
+
 /* detecting HP-UX by the following compiler keyword definitions:
    - in K&R mode (the default), the HP C compiler defines "hpux"
    - in ANSI mode (-Aa or -Ae), the HP C compiler defines "__hpux"
 #define PLATFORM_HPUX
 #endif
 
+
+/* ========================================================================= */
+/* this should better go into "system.h" or "features.h" (yet to be created) */
+/* ========================================================================= */
+
+#if defined(PLATFORM_UNIX) || defined(TARGET_SDL)
+#define NETWORK_AVALIABLE
+#endif
+
+
 #endif /* PLATFORM_H */
index 8ad6308bc823dc1d368246615685852facd22689..fc05cb7063ad22ebbe4d8c88c66ab51b8a7d62d9 100644 (file)
@@ -17,6 +17,8 @@
 #include "SDL.h"
 #include "SDL_image.h"
 #include "SDL_mixer.h"
+#include "SDL_net.h"
+#include "SDL_thread.h"
 
 
 /* definitions needed for "system.c" */
index 905c890ed0761d45229bdc3cf4834bf657a3079f..dc01ad4c9ecdbdcbffec3c9cf9a7117909d9877b 100644 (file)
@@ -154,7 +154,7 @@ static char *getLevelDirFromTreeInfo(TreeInfo *node)
   return level_dir;
 }
 
-static char *getCurrentLevelDir()
+char *getCurrentLevelDir()
 {
   return getLevelDirFromTreeInfo(leveldir_current);
 }
@@ -349,23 +349,6 @@ inline static char *getLevelArtworkDir(int type)
   return LEVELDIR_ARTWORK_PATH(leveldir_current, type);
 }
 
-char *getLevelFilename(int nr)
-{
-  static char *filename = NULL;
-  char basename[MAX_FILENAME_LEN];
-
-  checked_free(filename);
-
-  if (nr < 0)
-    sprintf(basename, "template.%s", LEVELFILE_EXTENSION);
-  else
-    sprintf(basename, "%03d.%s", nr, LEVELFILE_EXTENSION);
-
-  filename = getPath2(getCurrentLevelDir(), basename);
-
-  return filename;
-}
-
 char *getTapeFilename(int nr)
 {
   static char *filename = NULL;
@@ -374,7 +357,7 @@ char *getTapeFilename(int nr)
   checked_free(filename);
 
   sprintf(basename, "%03d.%s", nr, TAPEFILE_EXTENSION);
-  filename = getPath2(getTapeDir(leveldir_current->filename), basename);
+  filename = getPath2(getTapeDir(leveldir_current->subdir), basename);
 
   return filename;
 }
@@ -400,7 +383,7 @@ char *getScoreFilename(int nr)
   checked_free(filename);
 
   sprintf(basename, "%03d.%s", nr, SCOREFILE_EXTENSION);
-  filename = getPath2(getScoreDir(leveldir_current->filename), basename);
+  filename = getPath2(getScoreDir(leveldir_current->subdir), basename);
 
   return filename;
 }
@@ -945,11 +928,11 @@ void dumpTreeInfo(TreeInfo *node, int depth)
       printf(" ");
 
 #if 1
-    printf("filename == '%s' ['%s', '%s'] [%d])\n",
-          node->filename, node->fullpath, node->basepath, node->user_defined);
+    printf("subdir == '%s' ['%s', '%s'] [%d])\n",
+          node->subdir, node->fullpath, node->basepath, node->user_defined);
 #else
-    printf("filename == '%s' (%s) [%s] (%d)\n",
-          node->filename, node->name, node->identifier, node->sort_priority);
+    printf("subdir == '%s' (%s) [%s] (%d)\n",
+          node->subdir, node->name, node->identifier, node->sort_priority);
 #endif
 
     if (node->node_group != NULL)
@@ -1599,28 +1582,34 @@ void checkSetupFileHashIdentifier(SetupFileHash *setup_file_hash,
 #define LEVELINFO_TOKEN_GRAPHICS_SET   11
 #define LEVELINFO_TOKEN_SOUNDS_SET     12
 #define LEVELINFO_TOKEN_MUSIC_SET      13
+#define LEVELINFO_TOKEN_FILENAME       14
+#define LEVELINFO_TOKEN_FILETYPE       15
+#define LEVELINFO_TOKEN_HANDICAP       16
 
-#define NUM_LEVELINFO_TOKENS           14
+#define NUM_LEVELINFO_TOKENS           17
 
 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_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.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_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"      }
 };
 
 static void setTreeInfoToDefaults(TreeInfo *ldi, int type)
@@ -1640,7 +1629,7 @@ static void setTreeInfoToDefaults(TreeInfo *ldi, int type)
   ldi->cl_first = -1;
   ldi->cl_cursor = -1;
 
-  ldi->filename = NULL;
+  ldi->subdir = NULL;
   ldi->fullpath = NULL;
   ldi->basepath = NULL;
   ldi->identifier = NULL;
@@ -1666,12 +1655,16 @@ static void setTreeInfoToDefaults(TreeInfo *ldi, int type)
     ldi->sounds_path = getStringCopy(UNDEFINED_FILENAME);
     ldi->music_path = getStringCopy(UNDEFINED_FILENAME);
 
+    ldi->level_filename = NULL;
+    ldi->level_filetype = NULL;
+
     ldi->levels = 0;
     ldi->first_level = 0;
     ldi->last_level = 0;
     ldi->level_group = FALSE;
     ldi->handicap_level = 0;
     ldi->readonly = TRUE;
+    ldi->handicap = TRUE;
   }
 }
 
@@ -1699,7 +1692,7 @@ static void setTreeInfoToDefaultsFromParent(TreeInfo *ldi, TreeInfo *parent)
   ldi->cl_first = -1;
   ldi->cl_cursor = -1;
 
-  ldi->filename = NULL;
+  ldi->subdir = NULL;
   ldi->fullpath = NULL;
   ldi->basepath = NULL;
   ldi->identifier = NULL;
@@ -1725,15 +1718,18 @@ static void setTreeInfoToDefaultsFromParent(TreeInfo *ldi, TreeInfo *parent)
     ldi->sounds_path = getStringCopy(UNDEFINED_FILENAME);
     ldi->music_path = getStringCopy(UNDEFINED_FILENAME);
 
+    ldi->level_filename = NULL;
+    ldi->level_filetype = NULL;
+
     ldi->levels = 0;
     ldi->first_level = 0;
     ldi->last_level = 0;
     ldi->level_group = FALSE;
     ldi->handicap_level = 0;
     ldi->readonly = TRUE;
+    ldi->handicap = TRUE;
   }
 
-
 #else
 
   /* first copy all values from the parent structure ... */
@@ -1746,7 +1742,7 @@ static void setTreeInfoToDefaultsFromParent(TreeInfo *ldi, TreeInfo *parent)
      other structure's pointer may point to them!
   */
 
-  ldi->filename = NULL;
+  ldi->subdir = NULL;
   ldi->fullpath = NULL;
   ldi->basepath = NULL;
   ldi->identifier = NULL;
@@ -1777,7 +1773,7 @@ static void setTreeInfoToDefaultsFromParent(TreeInfo *ldi, TreeInfo *parent)
 
 static void freeTreeInfo(TreeInfo *ldi)
 {
-  checked_free(ldi->filename);
+  checked_free(ldi->subdir);
   checked_free(ldi->fullpath);
   checked_free(ldi->basepath);
   checked_free(ldi->identifier);
@@ -1790,6 +1786,8 @@ static void freeTreeInfo(TreeInfo *ldi)
 
   if (ldi->type == TREE_TYPE_LEVEL_DIR)
   {
+    checked_free(ldi->imported_from);
+
     checked_free(ldi->graphics_set);
     checked_free(ldi->sounds_set);
     checked_free(ldi->music_set);
@@ -1797,6 +1795,9 @@ static void freeTreeInfo(TreeInfo *ldi)
     checked_free(ldi->graphics_path);
     checked_free(ldi->sounds_path);
     checked_free(ldi->music_path);
+
+    checked_free(ldi->level_filename);
+    checked_free(ldi->level_filetype);
   }
 }
 
@@ -1895,7 +1896,7 @@ static void createParentTreeInfoNode(TreeInfo *node_parent)
   setString(&ti_new->name, ".. (parent directory)");
   setString(&ti_new->name_sorting, ti_new->name);
 
-  setString(&ti_new->filename, "..");
+  setString(&ti_new->subdir, "..");
   setString(&ti_new->fullpath, node_parent->fullpath);
 
   ti_new->sort_priority = node_parent->sort_priority;
@@ -1907,7 +1908,7 @@ static void createParentTreeInfoNode(TreeInfo *node_parent)
   ti_new->name = ".. (parent directory)";
   ti_new->name_sorting = getStringCopy(ti_new->name);
 
-  ti_new->filename = "..";
+  ti_new->subdir = "..";
   ti_new->fullpath = getStringCopy(node_parent->fullpath);
 
   ti_new->sort_priority = node_parent->sort_priority;
@@ -1950,7 +1951,7 @@ static boolean LoadLevelInfoFromLevelConf(TreeInfo **node_first,
   else
     setTreeInfoToDefaults(leveldir_new, TREE_TYPE_LEVEL_DIR);
 
-  leveldir_new->filename = getStringCopy(directory_name);
+  leveldir_new->subdir = getStringCopy(directory_name);
 
   checkSetupFileHashIdentifier(setup_file_hash, getCookie("LEVELINFO"));
 
@@ -1963,19 +1964,19 @@ static boolean LoadLevelInfoFromLevelConf(TreeInfo **node_first,
 
 #if 1
   if (strcmp(leveldir_new->name, ANONYMOUS_NAME) == 0)
-    setString(&leveldir_new->name, leveldir_new->filename);
+    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->filename);
+    leveldir_new->name = getStringCopy(leveldir_new->subdir);
   }
 #endif
 
   DrawInitText(leveldir_new->name, 150, FC_YELLOW);
 
   if (leveldir_new->identifier == NULL)
-    leveldir_new->identifier = getStringCopy(leveldir_new->filename);
+    leveldir_new->identifier = getStringCopy(leveldir_new->subdir);
 
   if (leveldir_new->name_sorting == NULL)
     leveldir_new->name_sorting = getStringCopy(leveldir_new->name);
@@ -1983,7 +1984,7 @@ static boolean LoadLevelInfoFromLevelConf(TreeInfo **node_first,
   if (node_parent == NULL)             /* top level group */
   {
     leveldir_new->basepath = getStringCopy(level_directory);
-    leveldir_new->fullpath = getStringCopy(leveldir_new->filename);
+    leveldir_new->fullpath = getStringCopy(leveldir_new->subdir);
   }
   else                                 /* sub level group */
   {
@@ -2013,9 +2014,8 @@ static boolean LoadLevelInfoFromLevelConf(TreeInfo **node_first,
 #endif
 
   leveldir_new->handicap_level =       /* set handicap to default value */
-    (leveldir_new->user_defined ?
-     leveldir_new->last_level :
-     leveldir_new->first_level);
+    (leveldir_new->user_defined || !leveldir_new->handicap ?
+     leveldir_new->last_level : leveldir_new->first_level);
 
   pushTreeInfo(node_first, leveldir_new);
 
@@ -2176,7 +2176,7 @@ static boolean LoadArtworkInfoFromArtworkConf(TreeInfo **node_first,
   else
     setTreeInfoToDefaults(artwork_new, type);
 
-  artwork_new->filename = getStringCopy(directory_name);
+  artwork_new->subdir = getStringCopy(directory_name);
 
   if (setup_file_hash) /* (before defining ".color" and ".class_desc") */
   {
@@ -2193,12 +2193,12 @@ static boolean LoadArtworkInfoFromArtworkConf(TreeInfo **node_first,
 
 #if 1
     if (strcmp(artwork_new->name, ANONYMOUS_NAME) == 0)
-      setString(&artwork_new->name, artwork_new->filename);
+      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->filename);
+      artwork_new->name = getStringCopy(artwork_new->subdir);
     }
 #endif
 
@@ -2207,7 +2207,7 @@ static boolean LoadArtworkInfoFromArtworkConf(TreeInfo **node_first,
 #endif
 
     if (artwork_new->identifier == NULL)
-      artwork_new->identifier = getStringCopy(artwork_new->filename);
+      artwork_new->identifier = getStringCopy(artwork_new->subdir);
 
     if (artwork_new->name_sorting == NULL)
       artwork_new->name_sorting = getStringCopy(artwork_new->name);
@@ -2216,7 +2216,7 @@ static boolean LoadArtworkInfoFromArtworkConf(TreeInfo **node_first,
   if (node_parent == NULL)             /* top level group */
   {
     artwork_new->basepath = getStringCopy(base_directory);
-    artwork_new->fullpath = getStringCopy(artwork_new->filename);
+    artwork_new->fullpath = getStringCopy(artwork_new->subdir);
   }
   else                                 /* sub level group */
   {
@@ -2258,7 +2258,7 @@ static boolean LoadArtworkInfoFromArtworkConf(TreeInfo **node_first,
     }
 #endif
 
-    if (strcmp(artwork_new->filename, ".") == 0)
+    if (strcmp(artwork_new->subdir, ".") == 0)
     {
       if (artwork_new->user_defined)
       {
@@ -2291,9 +2291,9 @@ static boolean LoadArtworkInfoFromArtworkConf(TreeInfo **node_first,
     else
     {
 #if 1
-      setString(&artwork_new->identifier, artwork_new->filename);
+      setString(&artwork_new->identifier, artwork_new->subdir);
 #else
-      artwork_new->identifier = getStringCopy(artwork_new->filename);
+      artwork_new->identifier = getStringCopy(artwork_new->subdir);
 #endif
     }
 
@@ -2382,7 +2382,7 @@ static TreeInfo *getDummyArtworkInfo(int type)
   setTreeInfoToDefaults(artwork_new, type);
 
 #if 1
-  setString(&artwork_new->filename, UNDEFINED_FILENAME);
+  setString(&artwork_new->subdir,   UNDEFINED_FILENAME);
   setString(&artwork_new->fullpath, UNDEFINED_FILENAME);
   setString(&artwork_new->basepath, UNDEFINED_FILENAME);
 
@@ -2390,7 +2390,7 @@ static TreeInfo *getDummyArtworkInfo(int type)
   setString(&artwork_new->name,         UNDEFINED_FILENAME);
   setString(&artwork_new->name_sorting, UNDEFINED_FILENAME);
 #else
-  artwork_new->filename = getStringCopy(UNDEFINED_FILENAME);
+  artwork_new->subdir   = getStringCopy(UNDEFINED_FILENAME);
   artwork_new->fullpath = getStringCopy(UNDEFINED_FILENAME);
   artwork_new->basepath = getStringCopy(UNDEFINED_FILENAME);
 
@@ -2495,7 +2495,7 @@ void LoadArtworkInfoFromLevelInfo(ArtworkDirTree **artwork_node,
 #if 0
     if (!level_node->parent_link)
       printf("CHECKING '%s' ['%s', '%s'] ...\n", path,
-            level_node->filename, level_node->name);
+            level_node->subdir, level_node->name);
 #endif
 
     if (!level_node->parent_link)
@@ -2511,7 +2511,7 @@ void LoadArtworkInfoFromLevelInfo(ArtworkDirTree **artwork_node,
        free((*artwork_node)->name);
        free((*artwork_node)->name_sorting);
 
-       (*artwork_node)->identifier   = getStringCopy(level_node->filename);
+       (*artwork_node)->identifier   = getStringCopy(level_node->subdir);
        (*artwork_node)->name         = getStringCopy(level_node->name);
        (*artwork_node)->name_sorting = getStringCopy(level_node->name);
 
@@ -2633,7 +2633,9 @@ static void SaveUserLevelInfo()
   for (i = 0; i < NUM_LEVELINFO_TOKENS; i++)
     if (i != LEVELINFO_TOKEN_IDENTIFIER &&
        i != LEVELINFO_TOKEN_NAME_SORTING &&
-       i != LEVELINFO_TOKEN_IMPORTED_FROM)
+       i != LEVELINFO_TOKEN_IMPORTED_FROM &&
+       i != LEVELINFO_TOKEN_FILENAME &&
+       i != LEVELINFO_TOKEN_FILETYPE)
       fprintf(file, "%s\n", getSetupLine(levelinfo_tokens, "", i));
 
   fclose(file);
@@ -2766,7 +2768,7 @@ void SaveLevelSetup_LastSeries()
   /* ----------------------------------------------------------------------- */
 
   char *filename = getPath2(getSetupDir(), LEVELSETUP_FILENAME);
-  char *level_subdir = leveldir_current->filename;
+  char *level_subdir = leveldir_current->subdir;
   FILE *file;
 
   InitUserDataDirectory();
@@ -2845,7 +2847,7 @@ void LoadLevelSetup_SeriesInfo()
 {
   char *filename;
   SetupFileHash *level_setup_hash = NULL;
-  char *level_subdir = leveldir_current->filename;
+  char *level_subdir = leveldir_current->subdir;
 
   /* always start with reliable default values */
   level_nr = leveldir_current->first_level;
@@ -2856,7 +2858,7 @@ void LoadLevelSetup_SeriesInfo()
   /* ~/.<program>/levelsetup/<level series>/levelsetup.conf                  */
   /* ----------------------------------------------------------------------- */
 
-  level_subdir = leveldir_current->filename;
+  level_subdir = leveldir_current->subdir;
 
   filename = getPath2(getLevelSetupDir(level_subdir), LEVELSETUP_FILENAME);
 
@@ -2887,7 +2889,7 @@ void LoadLevelSetup_SeriesInfo()
       if (level_nr > leveldir_current->last_level + 1)
        level_nr = leveldir_current->last_level;
 
-      if (leveldir_current->user_defined)
+      if (leveldir_current->user_defined || !leveldir_current->handicap)
        level_nr = leveldir_current->last_level;
 
       leveldir_current->handicap_level = level_nr;
@@ -2906,7 +2908,7 @@ void LoadLevelSetup_SeriesInfo()
 void SaveLevelSetup_SeriesInfo()
 {
   char *filename;
-  char *level_subdir = leveldir_current->filename;
+  char *level_subdir = leveldir_current->subdir;
   char *level_nr_str = int2str(level_nr, 0);
   char *handicap_level_str = int2str(leveldir_current->handicap_level, 0);
   FILE *file;
index 1f46cc201aa30621b9c96fc368557277b13792af..6e0636ea2a0d99f035f82722866d904cf3c2cec5 100644 (file)
@@ -194,7 +194,6 @@ typedef struct hashtable     SetupFileHash;
 
 
 char *setLevelArtworkDir(TreeInfo *);
-char *getLevelFilename(int);
 char *getTapeFilename(int);
 char *getSolutionTapeFilename(int);
 char *getScoreFilename(int);
@@ -234,6 +233,8 @@ void sortTreeInfo(TreeInfo **,
 char *getUserDataDir(void);
 char *getCommonDataDir(void);
 char *getSetupDir(void);
+char *getCurrentLevelDir(void);
+
 void createDirectory(char *, char *, int);
 void InitUserDataDirectory(void);
 void SetFilePermissions(char *, int);
index a70ea3accf9018ed7c264f76b6bc06f61a89f5b6..b9fd88c66a460dd72e58300cba60644236440794 100644 (file)
@@ -1911,6 +1911,7 @@ void LoadCustomMusic_NoConf(void)
     boolean music_already_used = FALSE;
     int i;
 
+    /* skip all music files that are configured in music config file */
     for (i = 0; i < num_music; i++)
     {
       struct FileInfo *music = getMusicListEntry(i);
@@ -1959,10 +1960,6 @@ void LoadCustomMusic_NoConf(void)
   closedir(dir);
 
   draw_init_text = FALSE;
-
-  if (num_music_noconf == 0)
-    Error(ERR_WARN, "cannot find any valid music files in directory '%s'",
-         music_directory);
 }
 
 int getSoundListSize()
index 9934650f753173d935459d8b13dc00f7b83a9d09..8f26dc77fb97e7933f5ed2f24c71d453b0dfd5d9 100644 (file)
@@ -117,6 +117,8 @@ void InitPlatformDependentStuff(void)
 #if defined(TARGET_SDL)
   if (SDL_Init(SDL_INIT_EVENTTHREAD | SDL_INIT_NOPARACHUTE) < 0)
     Error(ERR_EXIT, "SDL_Init() failed: %s", SDL_GetError());
+
+  SDLNet_Init();
 #endif
 }
 
@@ -868,6 +870,31 @@ static const char *cursor_image_playfield[] =
   ". c #ffffff",
   "  c None",
 
+#if 1
+  /* some people complained about a "white dot" on the screen and thought it
+     was a graphical error... OK, let's just remove the whole pointer :-) */
+
+  /* pixels */
+  "                ",
+  "                ",
+  "                ",
+  "                ",
+  "                ",
+  "                ",
+  "                ",
+  "                ",
+  "                ",
+  "                ",
+  "                ",
+  "                ",
+  "                ",
+  "                ",
+  "                ",
+  "                ",
+
+  /* hot spot */
+  "0,0"
+#else
   /* pixels */
   " X              ",
   "X.X             ",
@@ -888,6 +915,7 @@ static const char *cursor_image_playfield[] =
 
   /* hot spot */
   "1,1"
+#endif
 };
 
 #if defined(TARGET_SDL)
index d05943775b1e7de7aba3bf502239588bbae01ae4..74a74a67e150ce4cd9baaaa8c709f675d730e4a6 100644 (file)
 #define DEFAULT_KEY_DOWN       KSYM_Down
 #if defined(PLATFORM_MACOSX)
 #define DEFAULT_KEY_SNAP       KSYM_Control_L
-#define DEFAULT_KEY_BOMB       KSYM_KP_Enter
+#define DEFAULT_KEY_DROP       KSYM_KP_Enter
 #else
-#define DEFAULT_KEY_SNAP       KSYM_Shift_L
-#define DEFAULT_KEY_BOMB       KSYM_Shift_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
                                 (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)
+
 
 /* values for animation mode (frame order and direction) */
 #define ANIM_NONE              0
 #define SETUP_FILENAME         "setup.cnf"
 #define LEVELSETUP_FILENAME    "lvlsetup.cnf"
 #define EDITORSETUP_FILENAME   "edsetup.cnf"
-#define HELPANIM_FILENAME      "helpanim.conf"
-#define HELPTEXT_FILENAME      "helptext.conf"
+#define HELPANIM_FILENAME      "helpanim.cnf"
+#define HELPTEXT_FILENAME      "helptext.cnf"
 #define LEVELINFO_FILENAME     "lvlinfo.cnf"
 #define GRAPHICSINFO_FILENAME  "gfxinfo.cnf"
 #define SOUNDSINFO_FILENAME    "sndinfo.cnf"
    PAGEX3: buffer for animations
 */
 
-#define DOOR_GFX_PAGESIZE      (gfx.dxsize)
+/* these values are hard-coded to be able to use them in initialization */
+#define DOOR_GFX_PAGE_WIDTH    100     /* should be set to "gfx.dxsize" */
+#define DOOR_GFX_PAGE_HEIGHT   280     /* should be set to "gfx.dysize" */
+
+#define DOOR_GFX_PAGESIZE      (DOOR_GFX_PAGE_WIDTH)
 #define DOOR_GFX_PAGEX1                (0 * DOOR_GFX_PAGESIZE)
 #define DOOR_GFX_PAGEX2                (1 * DOOR_GFX_PAGESIZE)
 #define DOOR_GFX_PAGEX3                (2 * DOOR_GFX_PAGESIZE)
 #define DOOR_GFX_PAGEX7                (6 * DOOR_GFX_PAGESIZE)
 #define DOOR_GFX_PAGEX8                (7 * DOOR_GFX_PAGESIZE)
 #define DOOR_GFX_PAGEY1                (0)
-#define DOOR_GFX_PAGEY2                (gfx.dysize)
+#define DOOR_GFX_PAGEY2                (DOOR_GFX_PAGE_HEIGHT)
 
 
 /* macros for version handling */
@@ -521,18 +530,13 @@ struct SetupJoystickInfo
 
   int xleft, xmiddle, xright;
   int yupper, ymiddle, ylower;
-  int snap;
-  int bomb;
+  int snap, drop;
 };
 
 struct SetupKeyboardInfo
 {
-  Key left;
-  Key right;
-  Key up;
-  Key down;
-  Key snap;
-  Key bomb;
+  Key left, right, up, down;
+  Key snap, drop;
 };
 
 struct SetupInputInfo
@@ -622,7 +626,7 @@ struct TreeInfo
 
   /* fields for "type == TREE_TYPE_LEVEL_DIR" */
 
-  char *filename;      /* tree info sub-directory basename (may be ".") */
+  char *subdir;                /* tree info sub-directory basename (may be ".") */
   char *fullpath;      /* complete path relative to tree base directory */
   char *basepath;      /* absolute base path of tree base directory */
   char *identifier;    /* identifier string for configuration files */
@@ -638,6 +642,9 @@ struct TreeInfo
   char *sounds_path;   /* path to optional custom sounds set (level only) */
   char *music_path;    /* path to optional custom music set (level only) */
 
+  char *level_filename;        /* filename of level file (for packed level file) */
+  char *level_filetype;        /* type of levels in level directory or level file */
+
   int levels;          /* number of levels in level series */
   int first_level;     /* first level number (to allow start with 0 or 1) */
   int last_level;      /* last level number (automatically calculated) */
@@ -649,6 +656,7 @@ struct TreeInfo
   boolean parent_link; /* entry links back to parent directory */
   boolean user_defined;        /* user defined levels are stored in home directory */
   boolean readonly;    /* readonly levels can not be changed with editor */
+  boolean handicap;    /* level set has no handicap when set to "false" */
 
   int color;           /* color to use on selection screen for this level */
   char *class_desc;    /* description of level series class */
index ce520f6452ed70613d8fc664aec436669293541e..6d5cb0a9ffe513e25af43487da2dad744eb53aff 100644 (file)
@@ -399,7 +399,7 @@ inline Pixel X11GetPixel(Bitmap *bitmap, int x, int y)
                          AllPlanes, ZPixmap);
   pixel_value = XGetPixel(pixel_image, 0, 0);
 
-  XDestroyImage(pixel_image);
+  X11DestroyImage(pixel_image);
 
   return pixel_value;
 }
@@ -423,6 +423,20 @@ inline Pixel X11GetPixelFromRGB(unsigned int color_r, unsigned int color_g,
 }
 #endif /* TARGET_X11_NATIVE */
 
+inline void X11DestroyImage(XImage *ximage)
+{
+#if defined(TARGET_X11_NATIVE)
+  /* this seems to be needed for OS/2, but does not hurt on other platforms */
+  if (ximage->data != NULL)
+  {
+    free(ximage->data);
+    ximage->data = NULL;
+  }
+#endif /* TARGET_X11_NATIVE */
+
+  XDestroyImage(ximage);
+}
+
 
 /* ------------------------------------------------------------------------- */
 /* mouse pointer functions                                                   */
index 99dc4c9cf6cdb0f4f909a5ab64f67cd6a492bd00..7c69a323c0cd6f67a92c2c6973956d948e25f435 100644 (file)
@@ -347,6 +347,7 @@ 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 *);
 
 #if defined(TARGET_X11_NATIVE)
 void X11SetMouseCursor(struct MouseCursorInfo *);
index 7e73ba2b388ba5f089d6b20c04b5048f75f93d6d..81319ed6b8899c868f75dea121e7f51b0d9b6b44 100644 (file)
@@ -34,6 +34,11 @@ int                  game_status = -1;
 boolean                        level_editor_test_game = FALSE;
 boolean                        network_playing = FALSE;
 
+#if defined(TARGET_SDL)
+boolean                        network_server = FALSE;
+SDL_Thread            *server_thread;
+#endif
+
 int                    key_joystick_mapping = 0;
 
 boolean                        redraw[MAX_BUF_XSIZE][MAX_BUF_YSIZE];
@@ -55,11 +60,13 @@ unsigned long               Changed[MAX_LEV_FIELDX][MAX_LEV_FIELDY];
 unsigned long          ChangeEvent[MAX_LEV_FIELDX][MAX_LEV_FIELDY];
 short                  WasJustMoving[MAX_LEV_FIELDX][MAX_LEV_FIELDY];
 short                  WasJustFalling[MAX_LEV_FIELDX][MAX_LEV_FIELDY];
+short                  CheckCollision[MAX_LEV_FIELDX][MAX_LEV_FIELDY];
 short                  AmoebaNr[MAX_LEV_FIELDX][MAX_LEV_FIELDY];
 short                  AmoebaCnt[MAX_NUM_AMOEBA];
 short                  AmoebaCnt2[MAX_NUM_AMOEBA];
-short                  ExplodePhase[MAX_LEV_FIELDX][MAX_LEV_FIELDY];
 short                  ExplodeField[MAX_LEV_FIELDX][MAX_LEV_FIELDY];
+short                  ExplodePhase[MAX_LEV_FIELDX][MAX_LEV_FIELDY];
+short                  ExplodeDelay[MAX_LEV_FIELDX][MAX_LEV_FIELDY];
 int                    RunnerVisit[MAX_LEV_FIELDX][MAX_LEV_FIELDY];
 int                    PlayerVisit[MAX_LEV_FIELDX][MAX_LEV_FIELDY];
 
@@ -89,7 +96,7 @@ int                   ZX, ZY;
 int                    ExitX, ExitY;
 int                    AllPlayersGone;
 
-int                    TimeFrames, TimePlayed, TimeLeft;
+int                    TimeFrames, TimePlayed, TimeLeft, TapeTime;
 
 boolean                        network_player_action_received = FALSE;
 
@@ -436,9 +443,9 @@ struct ElementInfo element_info[MAX_NUM_ELEMENTS + 1] =
     "invisible steel wall"
   },
   {
-    "maze_runner",
-    "maze_runner",
-    "maze runner"
+    "sokoban_field_player",
+    "sokoban",
+    "sokoban field with player"
   },
   {
     "dynabomb_increase_number",
@@ -657,7 +664,7 @@ struct ElementInfo element_info[MAX_NUM_ELEMENTS + 1] =
   {
     "black_orb",
     "black_orb",
-    "bomb"
+    "black orb bomb"
   },
   {
     "amoeba_to_diamond",
@@ -3234,6 +3241,221 @@ struct ElementInfo element_info[MAX_NUM_ELEMENTS + 1] =
     "envelope",
     "mail envelope 4"
   },
+  {
+    "group_1",
+    "group",
+    "group element 1"
+  },
+  {
+    "group_2",
+    "group",
+    "group element 2"
+  },
+  {
+    "group_3",
+    "group",
+    "group element 3"
+  },
+  {
+    "group_4",
+    "group",
+    "group element 4"
+  },
+  {
+    "group_5",
+    "group",
+    "group element 5"
+  },
+  {
+    "group_6",
+    "group",
+    "group element 6"
+  },
+  {
+    "group_7",
+    "group",
+    "group element 7"
+  },
+  {
+    "group_8",
+    "group",
+    "group element 8"
+  },
+  {
+    "group_9",
+    "group",
+    "group element 9"
+  },
+  {
+    "group_10",
+    "group",
+    "group element 10"
+  },
+  {
+    "group_11",
+    "group",
+    "group element 11"
+  },
+  {
+    "group_12",
+    "group",
+    "group element 12"
+  },
+  {
+    "group_13",
+    "group",
+    "group element 13"
+  },
+  {
+    "group_14",
+    "group",
+    "group element 14"
+  },
+  {
+    "group_15",
+    "group",
+    "group element 15"
+  },
+  {
+    "group_16",
+    "group",
+    "group element 16"
+  },
+  {
+    "group_17",
+    "group",
+    "group element 17"
+  },
+  {
+    "group_18",
+    "group",
+    "group element 18"
+  },
+  {
+    "group_19",
+    "group",
+    "group element 19"
+  },
+  {
+    "group_20",
+    "group",
+    "group element 20"
+  },
+  {
+    "group_21",
+    "group",
+    "group element 21"
+  },
+  {
+    "group_22",
+    "group",
+    "group element 22"
+  },
+  {
+    "group_23",
+    "group",
+    "group element 23"
+  },
+  {
+    "group_24",
+    "group",
+    "group element 24"
+  },
+  {
+    "group_25",
+    "group",
+    "group element 25"
+  },
+  {
+    "group_26",
+    "group",
+    "group element 26"
+  },
+  {
+    "group_27",
+    "group",
+    "group element 27"
+  },
+  {
+    "group_28",
+    "group",
+    "group element 28"
+  },
+  {
+    "group_29",
+    "group",
+    "group element 29"
+  },
+  {
+    "group_30",
+    "group",
+    "group element 30"
+  },
+  {
+    "group_31",
+    "group",
+    "group element 31"
+  },
+  {
+    "group_32",
+    "group",
+    "group element 32"
+  },
+  {
+    "unknown",
+    "unknown",
+    "unknown element"
+  },
+  {
+    "trigger_element",
+    "trigger",
+    "element triggering change"
+  },
+  {
+    "trigger_player",
+    "trigger",
+    "player triggering change"
+  },
+  {
+    "sp_gravity_on_port_right",
+    "sp_port",
+    "gravity on port (leading right)"
+  },
+  {
+    "sp_gravity_on_port_down",
+    "sp_port",
+    "gravity on port (leading down)"
+  },
+  {
+    "sp_gravity_on_port_left",
+    "sp_port",
+    "gravity on port (leading left)"
+  },
+  {
+    "sp_gravity_on_port_up",
+    "sp_port",
+    "gravity on port (leading up)"
+  },
+  {
+    "sp_gravity_off_port_right",
+    "sp_port",
+    "gravity off port (leading right)"
+  },
+  {
+    "sp_gravity_off_port_down",
+    "sp_port",
+    "gravity off port (leading down)"
+  },
+  {
+    "sp_gravity_off_port_left",
+    "sp_port",
+    "gravity off port (leading left)"
+  },
+  {
+    "sp_gravity_off_port_up",
+    "sp_port",
+    "gravity off port (leading up)"
+  },
 
   /* ----------------------------------------------------------------------- */
   /* "real" (and therefore drawable) runtime elements                        */
@@ -3524,6 +3746,26 @@ struct ElementInfo element_info[MAX_NUM_ELEMENTS + 1] =
     "-",
     "-"
   },
+  {
+    "player_is_exploding_1",
+    "-",
+    "-"
+  },
+  {
+    "player_is_exploding_2",
+    "-",
+    "-"
+  },
+  {
+    "player_is_exploding_3",
+    "-",
+    "-"
+  },
+  {
+    "player_is_exploding_4",
+    "-",
+    "-"
+  },
   {
     "quicksand.filling",
     "quicksand",
@@ -3670,8 +3912,23 @@ struct ElementInfo element_info[MAX_NUM_ELEMENTS + 1] =
     "-"
   },
   {
-    "dummy",
-    "dummy",
+    "internal_clipboard_custom",
+    "internal",
+    "empty custom element"
+  },
+  {
+    "internal_clipboard_change",
+    "internal",
+    "empty change page"
+  },
+  {
+    "internal_clipboard_group",
+    "internal",
+    "empty group element"
+  },
+  {
+    "internal_dummy",
+    "internal",
     "-"
   },
 
@@ -3894,7 +4151,7 @@ static void print_usage()
         "      --serveronly                 only start network server\n"
         "  -v, --verbose                    verbose mode\n"
         "      --debug                      display debugging information\n"
-        "  -e, --execute COMMAND            execute batch COMMAND:\n"
+        "  -e, --execute COMMAND            execute batch COMMAND\n"
         "\n"
         "Valid commands for '--execute' option:\n"
         "  \"print graphicsinfo.conf\"        print default graphics config\n"
@@ -3905,7 +4162,8 @@ static void print_usage()
         "  \"print helptext.conf\"            print default helptext config\n"
         "  \"dump level FILE\"                dump level data from FILE\n"
         "  \"dump tape FILE\"                 dump tape data from FILE\n"
-        "  \"autoplay LEVELDIR\"              play level tapes for LEVELDIR\n"
+        "  \"autoplay LEVELDIR [NR]\"         play level tapes for LEVELDIR\n"
+        "  \"convert LEVELDIR [NR]\"          convert levels in LEVELDIR\n"
         "\n",
         program.command_basename);
 }
index 9484a5c6a90c9f4eb9f12dab53007840e732a057..0bf9a3656e22650716758a556dfda283bb39f93b 100644 (file)
@@ -74,9 +74,9 @@
 #define EP_CAN_SMASH_PLAYER    10
 #define EP_CAN_SMASH_ENEMIES   11
 #define EP_CAN_SMASH_EVERYTHING        12
-#define EP_CAN_EXPLODE_BY_FIRE 13
-#define EP_CAN_EXPLODE_SMASHED 14
-#define EP_CAN_EXPLODE_IMPACT  15
+#define EP_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_INSIDE     20
 #define EP_PASSABLE_UNDER      21
 #define EP_DROPPABLE           22
-#define EP_CAN_EXPLODE_1X1     23
+#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_AMOEBOID            50
 #define EP_AMOEBALIVE          51
 #define EP_HAS_CONTENT         52
-#define EP_ACTIVE_BOMB         53
-#define EP_INACTIVE            54
+#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    55
+#define EP_EM_SLIPPERY_WALL    57
 
 /* values for special graphics properties (no effect on game engine) */
-#define EP_GFX_CRUMBLED                56
+#define EP_GFX_CRUMBLED                58
 
 /* values for derived properties (determined from properties above) */
-#define EP_ACCESSIBLE_OVER     57
-#define EP_ACCESSIBLE_INSIDE   58
-#define EP_ACCESSIBLE_UNDER    59
-#define EP_WALKABLE            60
-#define EP_PASSABLE            61
-#define EP_ACCESSIBLE          62
-#define EP_COLLECTIBLE         63
-#define EP_SNAPPABLE           64
-#define EP_WALL                        65
-#define EP_SOLID_FOR_PUSHING   66
-#define EP_DRAGONFIRE_PROOF    67
-#define EP_EXPLOSION_PROOF     68
-#define EP_CAN_SMASH           69
-#define EP_CAN_EXPLODE         70
-#define EP_CAN_EXPLODE_3X3     71
+#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
 
 /* values for internal purpose only (level editor) */
-#define EP_EXPLODE_RESULT      72
-#define EP_WALK_TO_OBJECT      73
-#define EP_DEADLY              74
+#define EP_WALK_TO_OBJECT      81
+#define EP_DEADLY              82
 
-#define NUM_ELEMENT_PROPERTIES 75
+#define NUM_ELEMENT_PROPERTIES 83
 
 #define NUM_EP_BITFIELDS       ((NUM_ELEMENT_PROPERTIES + 31) / 32)
 #define EP_BITFIELD_BASE       0
 #define CE_PRESSED_BY_PLAYER   2
 #define CE_PUSHED_BY_PLAYER    3
 #define CE_DROPPED_BY_PLAYER   4
-#define CE_COLLISION_ACTIVE    5
+#define CE_HITTING_SOMETHING   5
 #define CE_IMPACT              6
 #define CE_SMASHED             7
 #define CE_OTHER_IS_TOUCHING   8
 #define CE_OTHER_GETS_LEFT     24
 #define CE_SWITCHED            25
 #define CE_OTHER_IS_SWITCHING  26
-#define CE_COLLISION_PASSIVE   27
-#define CE_OTHER_IS_COLL_ACTIVE        28
-#define CE_OTHER_IS_COLL_PASSIVE 29
+#define CE_HIT_BY_SOMETHING    27
+#define CE_OTHER_IS_HITTING    28
+#define CE_OTHER_GETS_HIT      29
+#define CE_BLOCKED             30
 
-#define NUM_CHANGE_EVENTS      30
+#define NUM_CHANGE_EVENTS      31
 
 #define CE_BITMASK_DEFAULT     0
 
                                  (CH_EVENT_VAR(e) |=  CH_EVENT_BIT(c)) : \
                                  (CH_EVENT_VAR(e) &= ~CH_EVENT_BIT(c))) : 0)
 
-/* values for change sides for custom elements */
+/* 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_BOTTOM     MV_VERTICAL
 #define CH_SIDE_ANY            MV_ANY_DIRECTION
 
-/* values for change power for custom elements */
-#define CP_NON_DESTRUCTIVE     0
-#define CP_HALF_DESTRUCTIVE    1
-#define CP_FULL_DESTRUCTIVE    2
+/* 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)
+
+/* values for change page for custom elements */
+#define CH_PAGE_ANY_FILE       (0xff)
+#define CH_PAGE_ANY            (0xffffffff)
 
-/* values for special move patterns (bits 0-3: basic move directions) */
+/* 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
+
+/* 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_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
 
-/* values for special move patterns for custom elements */
+/* values for custom move patterns */
 #define MV_HORIZONTAL          (MV_LEFT | MV_RIGHT)
-#define MV_VERTICAL            (MV_UP | MV_DOWN)
-#define MV_ALL_DIRECTIONS      (MV_HORIZONTAL | MV_VERTICAL)
+#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_TOWARDS_PLAYER      (1 << MV_BIT_TOWARDS_PLAYER)
 #define MV_AWAY_FROM_PLAYER    (1 << MV_BIT_AWAY_FROM_PLAYER)
 #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
+
+/* 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)
+
+/* values for elements left behind by custom elements */
+#define LEAVE_TYPE_UNLIMITED   0
+#define LEAVE_TYPE_LIMITED     1
 
 /* values for slippery property for custom elements */
 #define SLIPPERY_ANY_RANDOM    0
 #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
+
 /* macros for configurable properties */
 #define IS_DIGGABLE(e)         HAS_PROPERTY(e, EP_DIGGABLE)
 #define IS_COLLECTIBLE_ONLY(e) HAS_PROPERTY(e, EP_COLLECTIBLE_ONLY)
 #define CAN_SMASH_PLAYER(e)    HAS_PROPERTY(e, EP_CAN_SMASH_PLAYER)
 #define CAN_SMASH_ENEMIES(e)   HAS_PROPERTY(e, EP_CAN_SMASH_ENEMIES)
 #define CAN_SMASH_EVERYTHING(e)        HAS_PROPERTY(e, EP_CAN_SMASH_EVERYTHING)
-#define CAN_EXPLODE_BY_FIRE(e) HAS_PROPERTY(e, EP_CAN_EXPLODE_BY_FIRE)
-#define CAN_EXPLODE_SMASHED(e) HAS_PROPERTY(e, EP_CAN_EXPLODE_SMASHED)
-#define CAN_EXPLODE_IMPACT(e)  HAS_PROPERTY(e, EP_CAN_EXPLODE_IMPACT)
+#define EXPLODES_BY_FIRE(e)    HAS_PROPERTY(e, EP_EXPLODES_BY_FIRE)
+#define EXPLODES_SMASHED(e)    HAS_PROPERTY(e, EP_EXPLODES_SMASHED)
+#define EXPLODES_IMPACT(e)     HAS_PROPERTY(e, EP_EXPLODES_IMPACT)
 #define IS_WALKABLE_OVER(e)    HAS_PROPERTY(e, EP_WALKABLE_OVER)
 #define IS_WALKABLE_INSIDE(e)  HAS_PROPERTY(e, EP_WALKABLE_INSIDE)
 #define IS_WALKABLE_UNDER(e)   HAS_PROPERTY(e, EP_WALKABLE_UNDER)
 #define IS_PASSABLE_INSIDE(e)  HAS_PROPERTY(e, EP_PASSABLE_INSIDE)
 #define IS_PASSABLE_UNDER(e)   HAS_PROPERTY(e, EP_PASSABLE_UNDER)
 #define IS_DROPPABLE(e)                HAS_PROPERTY(e, EP_DROPPABLE)
-#define CAN_EXPLODE_1X1(e)     HAS_PROPERTY(e, EP_CAN_EXPLODE_1X1)
+#define EXPLODES_1X1_OLD(e)    HAS_PROPERTY(e, EP_EXPLODES_1X1_OLD)
 #define IS_PUSHABLE(e)         HAS_PROPERTY(e, EP_PUSHABLE)
+#define EXPLODES_CROSS_OLD(e)  HAS_PROPERTY(e, EP_EXPLODES_CROSS_OLD)
+#define IS_PROTECTED(e)                HAS_PROPERTY(e, EP_PROTECTED)
+#define CAN_MOVE_INTO_ACID(e)  HAS_PROPERTY(e, EP_CAN_MOVE_INTO_ACID)
+#define IS_THROWABLE(e)                HAS_PROPERTY(e, EP_THROWABLE)
+#define CAN_EXPLODE(e)         HAS_PROPERTY(e, EP_CAN_EXPLODE)
+#define IS_GRAVITY_REACHABLE(e)        HAS_PROPERTY(e, EP_GRAVITY_REACHABLE)
 
 /* macros for special configurable properties */
 #define IS_EM_SLIPPERY_WALL(e) HAS_PROPERTY(e, EP_EM_SLIPPERY_WALL)
 #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 CAN_TURN_EACH_MOVE(e)  HAS_PROPERTY(e, EP_CAN_TURN_EACH_MOVE)
+#define CAN_GROW(e)            HAS_PROPERTY(e, EP_CAN_GROW)
 #define IS_ACTIVE_BOMB(e)      HAS_PROPERTY(e, EP_ACTIVE_BOMB)
 #define IS_INACTIVE(e)         HAS_PROPERTY(e, EP_INACTIVE)
 
 #define IS_DRAGONFIRE_PROOF(e) HAS_PROPERTY(e, EP_DRAGONFIRE_PROOF)
 #define IS_EXPLOSION_PROOF(e)  HAS_PROPERTY(e, EP_EXPLOSION_PROOF)
 #define CAN_SMASH(e)           HAS_PROPERTY(e, EP_CAN_SMASH)
-#define CAN_EXPLODE(e)         HAS_PROPERTY(e, EP_CAN_EXPLODE)
-#define CAN_EXPLODE_3X3(e)     HAS_PROPERTY(e, EP_CAN_EXPLODE_3X3)
+#define EXPLODES_3X3_OLD(e)    HAS_PROPERTY(e, EP_EXPLODES_3X3_OLD)
+#define CAN_EXPLODE_BY_FIRE(e) HAS_PROPERTY(e, EP_CAN_EXPLODE_BY_FIRE)
+#define CAN_EXPLODE_SMASHED(e) HAS_PROPERTY(e, EP_CAN_EXPLODE_SMASHED)
+#define CAN_EXPLODE_IMPACT(e)  HAS_PROPERTY(e, EP_CAN_EXPLODE_IMPACT)
+#define IS_SP_PORT(e)          HAS_PROPERTY(e, EP_SP_PORT)
+#define CAN_EXPLODE_BY_DRAGONFIRE(e)   \
+                               HAS_PROPERTY(e, EP_CAN_EXPLODE_BY_DRAGONFIRE)
+#define CAN_EXPLODE_BY_EXPLOSION(e)    \
+                               HAS_PROPERTY(e, EP_CAN_EXPLODE_BY_EXPLOSION)
+#define COULD_MOVE_INTO_ACID(e)        HAS_PROPERTY(e, EP_COULD_MOVE_INTO_ACID)
+#define MAYBE_DONT_COLLIDE_WITH(e) HAS_PROPERTY(e, EP_MAYBE_DONT_COLLIDE_WITH)
 
 /* special macros used in game engine */
 #define IS_CUSTOM_ELEMENT(e)   ((e) >= EL_CUSTOM_START &&              \
                                 (e) <= EL_CUSTOM_END)
 
+#define IS_GROUP_ELEMENT(e)    ((e) >= EL_GROUP_START &&               \
+                                (e) <= EL_GROUP_END)
+
+#define IS_CLIPBOARD_ELEMENT(e)        ((e) >= EL_INTERNAL_CLIPBOARD_START &&  \
+                                (e) <= EL_INTERNAL_CLIPBOARD_END)
+
+#define IS_INTERNAL_ELEMENT(e) ((e) >= EL_INTERNAL_START &&            \
+                                (e) <= EL_INTERNAL_END)
+
 #define IS_ENVELOPE(e)         ((e) >= EL_ENVELOPE_1 &&                \
                                 (e) <= EL_ENVELOPE_4)
 
+#define IS_GATE(e)             ((e) >= EL_GATE_1 &&                    \
+                                (e) <= EL_GATE_4)
+
+#define IS_GATE_GRAY(e)                ((e) >= EL_GATE_1_GRAY &&               \
+                                (e) <= EL_GATE_4_GRAY)
+
+#define IS_EM_GATE(e)          ((e) >= EL_EM_GATE_1 &&                 \
+                                (e) <= EL_EM_GATE_4)
+
+#define IS_EM_GATE_GRAY(e)     ((e) >= EL_EM_GATE_1_GRAY &&            \
+                                (e) <= EL_EM_GATE_4_GRAY)
+
 #define GFX_ELEMENT(e)         (element_info[e].use_gfx_element ?      \
                                 element_info[e].gfx_element : e)
 
-#define IS_PLAYER(x,y)         (ELEM_IS_PLAYER(StorePlayer[x][y]))
+/* !!! "use sound" deactivated due to problems with level "bug machine" !!! */
+/* (solution: add separate "use sound of element" to level file and editor) */
+#if 0
+#define SND_ELEMENT(e)         GFX_ELEMENT(e)
+#else
+#define SND_ELEMENT(e)         (e)
+#endif
 
-#define IS_FREE(x,y)           (Feld[x][y] == EL_EMPTY && !IS_PLAYER(x,y))
-#define IS_FREE_OR_PLAYER(x,y) (Feld[x][y] == EL_EMPTY)
+#define IS_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_FREE_OR_PLAYER(x, y)        (Feld[x][y] == EL_EMPTY)
 
 #define IS_MOVING(x,y)         (MovPos[x][y] != 0)
 #define IS_FALLING(x,y)                (MovPos[x][y] != 0 && MovDir[x][y] == MV_DOWN)
 
 #define 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_ENEMY_PROTECTED(x,y)     (SHIELD_ON(PLAYERINFO(x, y)) ||           \
+                                        ENEMY_PROTECTED_FIELD(x, y))
+#define PLAYER_EXPLOSION_PROTECTED(x,y) (SHIELD_ON(PLAYERINFO(x, y)) ||           \
+                                        EXPLOSION_PROTECTED_FIELD(x, y))
+
+#else
+
 #define PROTECTED_FIELD(x,y)   (IS_ACCESSIBLE_INSIDE(Feld[x][y]) &&    \
                                 IS_INDESTRUCTIBLE(Feld[x][y]))
-#define PLAYER_PROTECTED(x,y)  (SHIELD_ON(PLAYERINFO(x, y)) ||         \
+#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))
 
 
 /* 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      (1000 / GAME_FRAME_DELAY)
+#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_SCORE_ENTRIES      100
 #define MAX_NUM_AMOEBA         100
 #define MAX_INVENTORY_SIZE     1000
+#define MAX_KEYS               4
+#define NUM_BELTS              4
+#define NUM_BELT_PARTS         3
 #define MIN_ENVELOPE_XSIZE     1
 #define MIN_ENVELOPE_YSIZE     1
 #define MAX_ENVELOPE_XSIZE     30
 #define MAX_ENVELOPE_YSIZE     20
 #define MAX_ENVELOPE_TEXT_LEN  (MAX_ENVELOPE_XSIZE * MAX_ENVELOPE_YSIZE)
 #define MIN_CHANGE_PAGES       1
-#define MAX_CHANGE_PAGES       16
+#define MAX_CHANGE_PAGES       32
+#define MIN_ELEMENTS_IN_GROUP  1
+#define MAX_ELEMENTS_IN_GROUP  16
 
 /* values for elements with content */
 #define MIN_ELEMENT_CONTENTS   1
 #define MICROLABEL_YPOS                (MICROLEV_YPOS + MICROLEV_YSIZE + 7)
 
 
+/* score for elements */
+#define SC_EMERALD             0
+#define SC_DIAMOND             1
+#define SC_BUG                 2
+#define SC_SPACESHIP           3
+#define SC_YAMYAM              4
+#define SC_ROBOT               5
+#define SC_PACMAN              6
+#define SC_NUT                 7
+#define SC_DYNAMITE            8
+#define SC_KEY                 9
+#define SC_TIME_BONUS          10
+#define SC_CRYSTAL             11
+#define SC_PEARL               12
+#define SC_SHIELD              13
+
+
 /* "real" level file elements */
 #define EL_UNDEFINED                   -1
 
 #define EL_DARK_YAMYAM                 60
 #define EL_BD_MAGIC_WALL               61
 #define EL_INVISIBLE_STEELWALL         62
-
-#define EL_MAZE_RUNNER                 63
-
+#define EL_SOKOBAN_FIELD_PLAYER                63
 #define EL_DYNABOMB_INCREASE_NUMBER    64
 #define EL_DYNABOMB_INCREASE_SIZE      65
 #define EL_DYNABOMB_INCREASE_POWER     66
 #define EL_ENVELOPE_3                  622
 #define EL_ENVELOPE_4                  623
 
-#define NUM_FILE_ELEMENTS              624
+/* ---------- begin of group elements section ------------------------------ */
+#define EL_GROUP_START                 624
+
+#include "conf_grp.h"  /* include auto-generated data structure definitions */
+
+#define NUM_GROUP_ELEMENTS             32
+#define EL_GROUP_END                   655
+/* ---------- end of custom elements section ------------------------------- */
+
+#define EL_UNKNOWN                     656
+#define EL_TRIGGER_ELEMENT             657
+#define EL_TRIGGER_PLAYER              658
+
+#define EL_SP_GRAVITY_ON_PORT_RIGHT    659
+#define EL_SP_GRAVITY_ON_PORT_DOWN     660
+#define EL_SP_GRAVITY_ON_PORT_LEFT     661
+#define EL_SP_GRAVITY_ON_PORT_UP       662
+#define EL_SP_GRAVITY_OFF_PORT_RIGHT   663
+#define EL_SP_GRAVITY_OFF_PORT_DOWN    664
+#define EL_SP_GRAVITY_OFF_PORT_LEFT    665
+#define EL_SP_GRAVITY_OFF_PORT_UP      666
+
+#define NUM_FILE_ELEMENTS              667
 
 
 /* "real" (and therefore drawable) runtime elements */
 #define EL_EXPANDABLE_WALL_GROWING     (EL_FIRST_RUNTIME_UNREAL + 8)
 #define EL_FLAMES                      (EL_FIRST_RUNTIME_UNREAL + 9)
 #define EL_PLAYER_IS_LEAVING           (EL_FIRST_RUNTIME_UNREAL + 10)
-#define EL_QUICKSAND_FILLING           (EL_FIRST_RUNTIME_UNREAL + 11)
-#define EL_MAGIC_WALL_FILLING          (EL_FIRST_RUNTIME_UNREAL + 12)
-#define EL_BD_MAGIC_WALL_FILLING       (EL_FIRST_RUNTIME_UNREAL + 13)
+#define EL_PLAYER_IS_EXPLODING_1       (EL_FIRST_RUNTIME_UNREAL + 11)
+#define EL_PLAYER_IS_EXPLODING_2       (EL_FIRST_RUNTIME_UNREAL + 12)
+#define EL_PLAYER_IS_EXPLODING_3       (EL_FIRST_RUNTIME_UNREAL + 13)
+#define EL_PLAYER_IS_EXPLODING_4       (EL_FIRST_RUNTIME_UNREAL + 14)
+#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)
 
 /* dummy elements (never used as game elements, only used as graphics) */
-#define EL_FIRST_DUMMY                 (EL_FIRST_RUNTIME_UNREAL + 14)
+#define EL_FIRST_DUMMY                 (EL_FIRST_RUNTIME_UNREAL + 18)
 
 #define EL_STEELWALL_TOPLEFT                   (EL_FIRST_DUMMY + 0)
 #define EL_STEELWALL_TOPRIGHT                  (EL_FIRST_DUMMY + 1)
 #define EL_BD_DEFAULT                          (EL_FIRST_DUMMY + 22)
 #define EL_SP_DEFAULT                          (EL_FIRST_DUMMY + 23)
 #define EL_SB_DEFAULT                          (EL_FIRST_DUMMY + 24)
-#define EL_DUMMY                               (EL_FIRST_DUMMY + 25)
 
-#define MAX_NUM_ELEMENTS                       (EL_FIRST_DUMMY + 26)
+/* internal elements (only used for internal purposes like copying) */
+#define EL_FIRST_INTERNAL                      (EL_FIRST_DUMMY + 25)
+
+#define EL_INTERNAL_CLIPBOARD_CUSTOM           (EL_FIRST_INTERNAL + 0)
+#define EL_INTERNAL_CLIPBOARD_CHANGE           (EL_FIRST_INTERNAL + 1)
+#define EL_INTERNAL_CLIPBOARD_GROUP            (EL_FIRST_INTERNAL + 2)
+#define EL_INTERNAL_DUMMY                      (EL_FIRST_INTERNAL + 3)
+
+#define EL_INTERNAL_CLIPBOARD_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 MAX_NUM_ELEMENTS                       (EL_FIRST_INTERNAL + 4)
 
 
 /* values for graphics/sounds action types */
 /* program information and versioning definitions */
 
 #define PROGRAM_VERSION_MAJOR  3
-#define PROGRAM_VERSION_MINOR  0
-#define PROGRAM_VERSION_PATCH  8
-#define PROGRAM_VERSION_BUILD  3
+#define PROGRAM_VERSION_MINOR  1
+#define PROGRAM_VERSION_PATCH  0
+#define PROGRAM_VERSION_BUILD  5
 
 #define PROGRAM_TITLE_STRING   "Rocks'n'Diamonds"
 #define PROGRAM_AUTHOR_STRING  "Holger Schemel"
-#define PROGRAM_COPYRIGHT_STRING "Copyright ©1995-2003 by Holger Schemel"
+#define PROGRAM_COPYRIGHT_STRING "Copyright ©1995-2004 by Holger Schemel"
 
 #define ICON_TITLE_STRING      PROGRAM_TITLE_STRING
 #define COOKIE_PREFIX          "ROCKSNDIAMONDS"
@@ -1177,9 +1358,12 @@ struct PlayerInfo
 {
   boolean present;             /* player present in level playfield */
   boolean connected;           /* player connected (locally or via network) */
-  boolean active;              /* player (present && connected) */
+  boolean active;              /* player present and connected */
 
-  int index_nr, client_nr, element_nr;
+  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
@@ -1196,17 +1380,22 @@ struct PlayerInfo
 
   boolean use_murphy_graphic;
 
+  boolean block_last_field;
+  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;
@@ -1231,11 +1420,15 @@ struct PlayerInfo
   unsigned long move_delay;
   int move_delay_value;
 
+  int move_delay_reset_counter;
+
   unsigned long push_delay;
   unsigned long push_delay_value;
 
   unsigned long actual_frame_counter;
 
+  int drop_delay;
+
   int step_counter;
 
   int score;
@@ -1249,6 +1442,7 @@ struct PlayerInfo
   int shield_deadly_time_left;
 
   int inventory_element[MAX_INVENTORY_SIZE];
+  int inventory_infinite_element;
   int inventory_size;
 };
 
@@ -1257,6 +1451,15 @@ struct LevelSetInfo
   int music[MAX_LEVELS];
 };
 
+struct LevelFileInfo
+{
+  int nr;
+  int type;
+  boolean packed;
+  char *basename;
+  char *filename;
+};
+
 struct LevelInfo
 {
   int file_version;    /* file format version the level is stored with    */
@@ -1267,30 +1470,50 @@ struct LevelInfo
   boolean encoding_16bit_amoeba;       /* amoeba contains 16-bit elements */
 
   int fieldx, fieldy;
+
   int time;
   int gems_needed;
+
   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];
+
   int score[LEVEL_SCORE_ELEMENTS];
+
   int yamyam_content[MAX_ELEMENT_CONTENTS][3][3];
   int num_yamyam_contents;
+
   int amoeba_speed;
   int amoeba_content;
+
   int time_magic_wall;
   int time_wheel;
   int time_light;
   int time_timegate;
+
+  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;
   boolean em_slippery_gems;    /* EM style "gems slip from wall" behaviour */
+  boolean block_last_field;    /* player blocks previous field while moving */
+  boolean sp_block_last_field; /* player blocks previous field while moving */
+  boolean use_spring_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 */
+
+  /* ('int' instead of 'boolean' because used as selectbox value in editor) */
+  int use_step_counter;                /* count steps instead of seconds for level */
 
   short field[MAX_LEV_FIELDX][MAX_LEV_FIELDY];
 
   boolean use_custom_template; /* use custom properties from template file */
 
-  boolean no_level_file;       /* set for currently undefined levels */
+  boolean no_valid_file;       /* set when level file missing or invalid */
 };
 
 struct TapeInfo
@@ -1310,7 +1533,8 @@ struct TapeInfo
   boolean pause_before_death;
   boolean recording, playing, pausing;
   boolean fast_forward;
-  boolean index_search;
+  boolean warp_forward;
+  boolean deactivate_display;
   boolean auto_play;
   boolean auto_play_level_solved;
   boolean quick_resume;
@@ -1324,6 +1548,8 @@ struct TapeInfo
     byte action[MAX_PLAYERS];
     byte delay;
   } pos[MAX_TAPELEN];
+
+  boolean no_valid_file;       /* set when tape file missing or invalid */
 };
 
 struct GameInfo
@@ -1365,6 +1591,9 @@ struct GlobalInfo
   char *autoplay_leveldir;
   int autoplay_level_nr;
 
+  char *convert_leveldir;
+  int convert_level_nr;
+
   int num_toons;
 
   float frames_per_second;
@@ -1377,7 +1606,10 @@ struct ElementChangeInfo
   boolean can_change;          /* use or ignore this change info */
 
   unsigned long events;                /* change events */
-  int sides;                   /* change sides */
+
+  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 */
 
@@ -1385,29 +1617,51 @@ struct ElementChangeInfo
   int delay_random;            /* added frame delay before changed (random) */
   int delay_frames;            /* either 1 (frames) or 50 (seconds; 50 fps) */
 
-  short trigger_element;       /* custom element triggering change */
+  short trigger_element;       /* element triggering change */
 
-  int content[3][3];           /* new elements after extended change */
-  boolean use_content;         /* use extended change content */
-  boolean only_complete;       /* only use complete content */
-  boolean use_random_change;   /* use random value for setting content */
-  int random;                  /* random value for setting content */
-  int power;                   /* power of extended change */
+  int target_content[3][3];    /* elements for extended change target */
+  boolean use_target_content;  /* use extended change target */
+  boolean only_if_complete;    /* only use complete target content */
+  boolean use_random_replace;  /* use random value for replacing elements */
+  int random_percentage;       /* random value for replacing elements */
+  int replace_when;            /* type of elements that can be replaced */
 
   boolean explode;             /* explode instead of change */
 
+  /* ---------- internal values used at runtime when playing ---------- */
+
   /* functions that are called before, while and after the change of an
      element -- currently only used for non-custom elements */
   void (*pre_change_function)(int x, int y);
   void (*change_function)(int x, int y);
   void (*post_change_function)(int x, int y);
 
+  short actual_trigger_element;        /* element that actually triggered change */
+  int actual_trigger_player;   /* player which actually triggered change */
+
   /* ---------- internal values used in level editor ---------- */
 
   int direct_action;           /* change triggered by actions on element */
   int other_action;            /* change triggered by other element actions */
 };
 
+struct ElementGroupInfo
+{
+  int num_elements;                    /* number of elements in this group */
+  short element[MAX_ELEMENTS_IN_GROUP];        /* list of elements in this group */
+
+  int choice_mode;             /* how to choose element from group */
+
+  /* ---------- internal values used at runtime when playing ---------- */
+
+  /* the following is the same as above, but with recursively resolved group
+     elements (group elements may also contain further group elements!) */
+  int num_elements_resolved;
+  short element_resolved[NUM_FILE_ELEMENTS];
+
+  int choice_pos;              /* current element choice position */
+};
+
 struct ElementInfo
 {
   /* ---------- token and description strings ---------- */
@@ -1416,7 +1670,7 @@ struct ElementInfo
   char *class_name;            /* element class used in config files */
   char *editor_description;    /* pre-defined description for level editor */
   char *custom_description;    /* alternative description from config file */
-  char description[MAX_ELEMENT_NAME_LEN + 1];  /* for custom elements */
+  char description[MAX_ELEMENT_NAME_LEN + 1];  /* for custom/group elements */
 
   /* ---------- graphic and sound definitions ---------- */
 
@@ -1438,28 +1692,42 @@ struct ElementInfo
   boolean use_gfx_element;     /* use custom graphic element */
   short 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 push_delay_fixed;                /* constant frame delay for pushing */
-  int push_delay_random;       /* additional random frame delay for pushing */
-  int move_delay_fixed;                /* constant frame delay for moving */
-  int move_delay_random;       /* additional random frame delay for moving */
+  int push_delay_fixed;                /* constant delay before pushing */
+  int push_delay_random;       /* additional random delay before pushing */
+  int drop_delay_fixed;                /* constant delay after dropping */
+  int drop_delay_random;       /* additional random delay after dropping */
+  int move_delay_fixed;                /* constant delay after moving */
+  int move_delay_random;       /* additional random delay after moving */
 
   int move_pattern;            /* direction movable element moves to */
   int move_direction_initial;  /* initial direction element moves to */
   int move_stepsize;           /* step size element moves with */
 
+  int move_enter_element;      /* element that can be entered (and removed) */
+  int move_leave_element;      /* element that can be left behind */
+  int move_leave_type;         /* change (limited) or leave (unlimited) */
+
   int slippery_type;           /* how/where other elements slip away */
 
   int content[3][3];           /* new elements after explosion */
 
+  int explosion_type;          /* type of explosion, like 3x3, 3+3 or 1x1 */
+  int explosion_delay;         /* duration of explosion of this element */
+  int ignition_delay;          /* delay for explosion by other explosion */
+
   struct ElementChangeInfo *change_page; /* actual list of change pages */
   struct ElementChangeInfo *change;     /* pointer to current change page */
 
   int num_change_pages;                /* actual number of change pages */
   int current_change_page;     /* currently edited change page */
 
+  struct ElementGroupInfo *group;      /* pointer to element group info */
+
   /* ---------- internal values used at runtime when playing ---------- */
 
   unsigned long change_events; /* bitfield for combined change events */
@@ -1467,14 +1735,21 @@ struct ElementInfo
   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
+
   /* ---------- internal values used in level editor ---------- */
 
   int access_type;             /* walkable or passable */
   int access_layer;            /* accessible over/inside/under */
+  int access_protected;                /* protection against deadly elements */
   int walk_to_action;          /* diggable/collectible/pushable */
   int smash_targets;           /* can smash player/enemies/everything */
   int deadliness;              /* deadly when running/colliding/touching */
-  int consistency;             /* indestructible/can explode */
 
   boolean can_explode_by_fire; /* element explodes by fire */
   boolean can_explode_smashed; /* element explodes when smashed */
@@ -1607,6 +1882,11 @@ extern int                       game_status;
 extern boolean                 level_editor_test_game;
 extern boolean                 network_playing;
 
+#if defined(TARGET_SDL)
+extern boolean                 network_server;
+extern SDL_Thread             *server_thread;
+#endif
+
 extern int                     key_joystick_mapping;
 
 extern boolean                 redraw[MAX_BUF_XSIZE][MAX_BUF_YSIZE];
@@ -1628,11 +1908,13 @@ extern unsigned long            Changed[MAX_LEV_FIELDX][MAX_LEV_FIELDY];
 extern unsigned long           ChangeEvent[MAX_LEV_FIELDX][MAX_LEV_FIELDY];
 extern short                   WasJustMoving[MAX_LEV_FIELDX][MAX_LEV_FIELDY];
 extern short                   WasJustFalling[MAX_LEV_FIELDX][MAX_LEV_FIELDY];
+extern short                   CheckCollision[MAX_LEV_FIELDX][MAX_LEV_FIELDY];
 extern short                   AmoebaNr[MAX_LEV_FIELDX][MAX_LEV_FIELDY];
 extern short                   AmoebaCnt[MAX_NUM_AMOEBA];
 extern short                   AmoebaCnt2[MAX_NUM_AMOEBA];
-extern short                   ExplodePhase[MAX_LEV_FIELDX][MAX_LEV_FIELDY];
 extern short                   ExplodeField[MAX_LEV_FIELDX][MAX_LEV_FIELDY];
+extern short                   ExplodePhase[MAX_LEV_FIELDX][MAX_LEV_FIELDY];
+extern short                   ExplodeDelay[MAX_LEV_FIELDX][MAX_LEV_FIELDY];
 extern int                     RunnerVisit[MAX_LEV_FIELDX][MAX_LEV_FIELDY];
 extern int                     PlayerVisit[MAX_LEV_FIELDX][MAX_LEV_FIELDY];
 
@@ -1661,7 +1943,7 @@ extern int                        ZX, ZY;
 extern int                     ExitX, ExitY;
 extern int                     AllPlayersGone;
 
-extern int                     TimeFrames, TimePlayed, TimeLeft;
+extern int                     TimeFrames, TimePlayed, TimeLeft, TapeTime;
 extern boolean                 SiebAktiv;
 extern int                     SiebCount;
 
index 71834c3b1f17dbc8be3a778149e0db9ea569570e..692265338b597df45b8b62510eb2bb736da08919 100644 (file)
@@ -8,22 +8,28 @@
 *               Germany                                    *
 *               e-mail: info@artsoft.org                   *
 *----------------------------------------------------------*
-* network.c                                                *
+* netserv.c                                                *
 ***********************************************************/
 
 #include "libgame/platform.h"
 
-#if defined(PLATFORM_UNIX)
+#if defined(NETWORK_AVALIABLE)
 
 #include <fcntl.h>
 #include <sys/time.h>
 #include <signal.h>
-#include <sys/socket.h>
 #include <errno.h>
+
+#if defined(TARGET_SDL)
+#include "main.h"
+#else
+#include <sys/socket.h>
 #include <netinet/in.h>
 #include <netinet/tcp.h>
 #include <arpa/inet.h>
 #include <netdb.h>
+#include <sys/select.h>                        /* apparently needed for OS/2 port */
+#endif
 
 #include "libgame/libgame.h"
 
@@ -34,7 +40,12 @@ static int onceonly = 0;
 
 struct NetworkServerPlayerInfo
 {
+#if defined(TARGET_SDL)
+  TCPsocket fd;
+#else
   int fd;
+#endif
+
   char player_name[16];
   unsigned char number;
   struct NetworkServerPlayerInfo *next;
@@ -51,17 +62,23 @@ static struct NetworkServerPlayerInfo *first_player = NULL;
 
 #define NEXT(player) ((player)->next ? (player)->next : first_player)
 
+#if defined(TARGET_SDL)
+/* TODO: peer address */
+static TCPsocket lfd;          /* listening socket */
+static SDLNet_SocketSet fds;   /* socket set */
+#else
 static struct sockaddr_in saddr;
-static int lfd;
+static int lfd;                        /* listening socket */
+static fd_set fds;             /* socket set */
+static int tcp = -1;
+#endif
+
 static unsigned char realbuffer[512], *buffer = realbuffer + 4;
 
 static int interrupt;
-static int tcp = -1;
 
 static unsigned long ServerFrameCounter = 0;
 
-static fd_set fds;
-
 static void addtobuffer(struct NetworkServerPlayerInfo *player,
                        unsigned char *b, int len)
 {
@@ -77,7 +94,11 @@ static void flushuser(struct NetworkServerPlayerInfo *player)
 {
   if (player->nwrite)
   {
+#if defined(TARGET_SDL)
+    SDLNet_TCP_Send(player->fd, player->writbuffer, player->nwrite);
+#else
     write(player->fd, player->writbuffer, player->nwrite);
+#endif
     player->nwrite = 0;
   }
 }
@@ -123,7 +144,13 @@ static void RemovePlayer(struct NetworkServerPlayerInfo *player)
       }
     }
   }
+
+#if defined(TARGET_SDL)
+  SDLNet_TCP_DelSocket(fds, player->fd);
+  SDLNet_TCP_Close(player->fd);
+#else
   close(player->fd);
+#endif
 
   if (player->introduced)
   {
@@ -146,7 +173,11 @@ static void RemovePlayer(struct NetworkServerPlayerInfo *player)
   }
 }
 
+#if defined(TARGET_SDL)
+static void AddPlayer(TCPsocket fd)
+#else
 static void AddPlayer(int fd)
+#endif
 {
   struct NetworkServerPlayerInfo *player, *v;
   unsigned char nxn;
@@ -164,6 +195,10 @@ static void AddPlayer(int fd)
   player->action = 0;
   player->action_received = FALSE;
 
+#if defined(TARGET_SDL)
+  SDLNet_TCP_AddSocket(fds, fd);
+#endif
+
   first_player = player;
 
   nxn = 1;
@@ -201,9 +236,11 @@ static void AddPlayer(int fd)
 #endif
 
   player->number = nxn;
+#if !defined(TARGET_SDL)
   if (options.verbose)
     Error(ERR_NETWORK_SERVER, "client %d connecting from %s",
          nxn, inet_ntoa(saddr.sin_addr));
+#endif
   clients++;
 
   buffer[0] = 0;
@@ -447,18 +484,35 @@ static void Handle_OP_MOVE_PLAYER(struct NetworkServerPlayerInfo *player)
   ServerFrameCounter++;
 }
 
+#if defined(TARGET_SDL)
+/* the following is not used for a standalone server;
+   the pointer points to an integer containing the port-number */
+int NetworkServerThread(void *ptr)
+{
+  NetworkServer(*((int *) ptr), 0);
+
+  /* should never be reached */
+  return 0;
+}
+#endif
+
 void NetworkServer(int port, int serveronly)
 {
-  int i, sl, on;
+  int sl;
   struct NetworkServerPlayerInfo *player;
-  int mfd;
   int r; 
   unsigned int len;
+#if defined(TARGET_SDL)
+  IPaddress ip;
+#else
+  int i, on;
+  int is_daemon = 0;
   struct protoent *tcpproto;
   struct timeval tv;
-  int is_daemon = 0;
+  int mfd;
+#endif
 
-#ifndef NeXT
+#if defined(PLATFORM_UNIX) && !defined(PLATFORM_NEXT)
   struct sigaction sact;
 #endif
 
@@ -468,10 +522,13 @@ void NetworkServer(int port, int serveronly)
   if (!serveronly)
     onceonly = 1;
 
+#if !defined(TARGET_SDL)
   if ((tcpproto = getprotobyname("tcp")) != NULL)
     tcp = tcpproto->p_proto;
+#endif
 
-#ifdef NeXT
+#if defined(PLATFORM_UNIX)
+#if defined(PLATFORM_NEXT)
   signal(SIGPIPE, SIG_IGN);
 #else
   sact.sa_handler = SIG_IGN;
@@ -479,7 +536,28 @@ void NetworkServer(int port, int serveronly)
   sact.sa_flags = 0;
   sigaction(SIGPIPE, &sact, NULL);
 #endif
+#endif
+
+#if defined(TARGET_SDL)
+
+  /* assume that SDL is already initialized */
+#if 0
+  if (SDLNet_Init() == -1)
+    Error(ERR_EXIT_NETWORK_SERVER, "SDLNet_Init() failed");
+  atexit(SDLNet_Quit);
+#endif
+
+  if (SDLNet_ResolveHost(&ip, NULL, port) == -1)
+    Error(ERR_EXIT_NETWORK_SERVER, "SDLNet_ResolveHost() failed");
 
+  lfd = SDLNet_TCP_Open(&ip);
+  if (!lfd)
+    Error(ERR_EXIT_NETWORK_SERVER, "SDLNet_TCP_Open() failed");
+
+  fds = SDLNet_AllocSocketSet(MAX_PLAYERS+1);
+  SDLNet_TCP_AddSocket(fds, lfd);
+
+#else
 
   if ((lfd = socket(PF_INET, SOCK_STREAM, 0)) < 0)
     Error(ERR_EXIT_NETWORK_SERVER, "socket() failed");
@@ -495,7 +573,9 @@ void NetworkServer(int port, int serveronly)
     Error(ERR_EXIT_NETWORK_SERVER, "bind() failed");
 
   listen(lfd, 5);
+#endif
 
+#if !defined(TARGET_SDL)
   if (is_daemon)
   {
     /* become a daemon, breaking all ties with the controlling terminal */
@@ -518,6 +598,7 @@ void NetworkServer(int port, int serveronly)
     open("/dev/null", O_WRONLY);
     open("/dev/null", O_WRONLY);
   }
+#endif
 
   if (options.verbose)
   {
@@ -533,6 +614,15 @@ void NetworkServer(int port, int serveronly)
     for (player = first_player; player; player = player->next)
       flushuser(player);
 
+#if defined(TARGET_SDL)
+    if ((sl = SDLNet_CheckSockets(fds, 500000)) < 1)
+    {
+      Error(ERR_NETWORK_SERVER, SDLNet_GetError());
+      perror("SDLNet_CheckSockets");
+    }
+
+#else
+
     FD_ZERO(&fds);
     mfd = lfd;
     player = first_player;
@@ -553,6 +643,7 @@ void NetworkServer(int port, int serveronly)
       else
        continue;
     }
+#endif
 
     if (sl < 0)
       continue;
@@ -560,6 +651,20 @@ void NetworkServer(int port, int serveronly)
     if (sl == 0)
       continue;
 
+    /* accept incoming connections */
+#if defined(TARGET_SDL)
+    if (SDLNet_SocketReady(lfd))
+    {
+      TCPsocket newsock;
+
+      newsock = SDLNet_TCP_Accept(lfd);
+
+      if (newsock)
+       AddPlayer(newsock);
+    }
+
+#else
+
     if (FD_ISSET(lfd, &fds))
     {
       int newfd, slen;
@@ -582,14 +687,27 @@ void NetworkServer(int port, int serveronly)
       }
       continue;
     }
+#endif
 
     player = first_player;
 
     do
     {
+#if defined(TARGET_SDL)
+      if (SDLNet_SocketReady(player->fd))
+#else
       if (FD_ISSET(player->fd, &fds))
+#endif
       {
-       r = read(player->fd, player->readbuffer + player->nread, MAX_BUFFER_SIZE - player->nread);
+#if defined(TARGET_SDL)
+       /* read only 1 byte, because SDLNet blocks when we want more than is
+          in the buffer */
+       r = SDLNet_TCP_Recv(player->fd, player->readbuffer + player->nread, 1);
+#else
+       r = read(player->fd, player->readbuffer + player->nread,
+                MAX_BUFFER_SIZE - player->nread);
+#endif
+
        if (r <= 0)
        {
          if (options.verbose)
@@ -685,4 +803,4 @@ void NetworkServer(int port, int serveronly)
   }
 }
 
-#endif /* PLATFORM_UNIX */
+#endif /* NETWORK_AVALIABLE */
index 5805fa24aabbef50ac5f3458b3fe57bd7d22468c..5efcb80339f8055386c60f4257d0ee3efbc7ea06 100644 (file)
 
 #define MAX_BUFFER_SIZE                4096
 
+#if defined(TARGET_SDL)
+int NetworkServerThread(void *);
+#endif
+
 void NetworkServer(int, int);
 
 #endif
index 73a13b1f8ab3032962e7b46a57fa048452fce944..575e846b38fe3c49fc001528be157055738da28b 100644 (file)
 
 #include "libgame/platform.h"
 
-#if defined(PLATFORM_UNIX)
+#if defined(NETWORK_AVALIABLE)
 
 #include <signal.h>
 #include <sys/time.h>
+
+#if defined(TARGET_SDL)
+#include "main.h"
+#else
 #include <sys/wait.h>
 #include <sys/socket.h>
 #include <netinet/in.h>
 #include <netinet/tcp.h>
 #include <arpa/inet.h>
 #include <netdb.h>
+#endif
 
 #include "libgame/libgame.h"
 
@@ -50,7 +55,13 @@ static struct NetworkClientPlayerInfo first_player =
 
 /* server stuff */
 
-static int sfd;
+#if defined(TARGET_SDL)
+static TCPsocket sfd;          /* server socket */
+static SDLNet_SocketSet rfds;  /* socket set */
+#else
+static int sfd;                        /* server socket */
+#endif
+
 static byte realbuffer[512];
 static byte readbuffer[MAX_BUFFER_SIZE], writbuffer[MAX_BUFFER_SIZE];
 static byte *buffer = realbuffer + 4;
@@ -72,7 +83,11 @@ static void SendBufferToServer(int size)
   nwrite += 4 + size;
 
   /* directly send the buffer to the network server */
+#if defined(TARGET_SDL)
+  SDLNet_TCP_Send(sfd, writbuffer, nwrite);
+#else
   write(sfd, writbuffer, nwrite);
+#endif
   nwrite = 0;
 }
 
@@ -109,6 +124,15 @@ char *getNetworkPlayerName(int player_nr)
 
 static void StartNetworkServer(int port)
 {
+#if defined(TARGET_SDL)
+  static int p;
+
+  p = port;
+  server_thread = SDL_CreateThread(NetworkServerThread, &p);
+  network_server = TRUE;
+
+#else
+
   switch (fork())
   {
     case 0:
@@ -127,8 +151,68 @@ static void StartNetworkServer(int port)
       /* we are parent process -- resume normal operation */
       return;
   }
+#endif
 }
 
+#if defined(TARGET_SDL)
+boolean ConnectToServer(char *hostname, int port)
+{
+  IPaddress ip;
+  int i;
+
+  if (port == 0)
+    port = DEFAULT_SERVER_PORT;
+
+  rfds = SDLNet_AllocSocketSet(1);
+
+  if (hostname)
+  {
+    SDLNet_ResolveHost(&ip, hostname, port);
+    if (ip.host == INADDR_NONE)
+      Error(ERR_EXIT, "cannot locate host '%s'", hostname);
+  }
+  else
+  {
+    SDLNet_Write32(0x7f000001, &ip.host);      /* 127.0.0.1 */
+    SDLNet_Write16(port, &ip.port);
+  }
+
+  sfd = SDLNet_TCP_Open(&ip);
+
+  if (sfd)
+  {
+    SDLNet_TCP_AddSocket(rfds, sfd);
+    return TRUE;
+  }
+  else
+  {
+    printf("SDLNet_TCP_Open(): %s\n", SDLNet_GetError());
+  }
+
+  if (hostname)                        /* connect to specified server failed */
+    return FALSE;
+
+  printf("No rocksndiamonds server on localhost -- starting up one ...\n");
+  StartNetworkServer(port);
+
+  /* wait for server to start up and try connecting several times */
+  for (i = 0; i < 6; i++)
+  {
+    Delay(500);                        /* wait 500 ms == 0.5 seconds */
+
+    if ((sfd = SDLNet_TCP_Open(&ip)))          /* connected */
+    {
+      SDLNet_TCP_AddSocket(rfds, sfd);
+      return TRUE;
+    }
+  }
+
+  /* when reaching this point, connect to newly started server has failed */
+  return FALSE;
+}
+
+#else
+
 boolean ConnectToServer(char *hostname, int port)
 {
   struct sockaddr_in s;
@@ -169,7 +253,7 @@ boolean ConnectToServer(char *hostname, int port)
   if (hostname)        /* connect to specified server failed */
     return FALSE;
 
-  printf("No rocksndiamonds server on localhost - starting up one ...\n");
+  printf("No rocksndiamonds server on localhost -- starting up one ...\n");
   StartNetworkServer(port);
 
   /* wait for server to start up and try connecting several times */
@@ -191,6 +275,7 @@ boolean ConnectToServer(char *hostname, int port)
   /* when reaching this point, connect to newly started server has failed */
   return FALSE;
 }
+#endif /* defined(TARGET_SDL) */
 
 void SendToServer_PlayerName(char *player_name)
 {
@@ -300,7 +385,7 @@ static void Handle_OP_YOUR_NUMBER()
   }
 
   if (first_player.nr > MAX_PLAYERS)
-    Error(ERR_EXIT, "sorry - no more than %d players", MAX_PLAYERS);
+    Error(ERR_EXIT, "sorry, more than %d players not allowed", MAX_PLAYERS);
 
   Error(ERR_NETWORK_CLIENT, "you get client # %d", new_client_nr);
 }
@@ -583,39 +668,60 @@ static void HandleNetworkingMessages()
   fflush(stdout);
 }
 
+/* TODO */
+
 void HandleNetworking()
 {
+#if !defined(TARGET_SDL)
   static struct timeval tv = { 0, 0 };
   fd_set rfds;
+#endif
   int r = 0;
 
-  FD_ZERO(&rfds);
-  FD_SET(sfd, &rfds);
-
-  r = select(sfd + 1, &rfds, NULL, NULL, &tv);
+  do
+  {
+#if defined(TARGET_SDL)
+    if ((r = SDLNet_CheckSockets(rfds, 1)) < 0)
+      Error(ERR_EXIT, "HandleNetworking(): SDLNet_CheckSockets() failed");
 
-  if (r < 0 && errno != EINTR)
-    Error(ERR_EXIT, "HandleNetworking(): select() failed");
+#else
 
-  if (r < 0)
     FD_ZERO(&rfds);
+    FD_SET(sfd, &rfds);
 
-  if (FD_ISSET(sfd, &rfds))
-  {
-    int r;
+    r = select(sfd + 1, &rfds, NULL, NULL, &tv);
 
-    r = read(sfd, readbuffer + nread, MAX_BUFFER_SIZE - nread);
+    if (r < 0 && errno != EINTR)
+      Error(ERR_EXIT, "HandleNetworking(): select() failed");
 
     if (r < 0)
-      Error(ERR_EXIT, "error reading from network server");
+      FD_ZERO(&rfds);
+#endif
+
+#if defined(TARGET_SDL)
+    if (r > 0)
+#else
+    if (FD_ISSET(sfd, &rfds))
+#endif
+    {
+#if defined(TARGET_SDL)
+      r = SDLNet_TCP_Recv(sfd, readbuffer + nread, 1);
+#else
+      r = read(sfd, readbuffer + nread, MAX_BUFFER_SIZE - nread);
+#endif
+
+      if (r < 0)
+       Error(ERR_EXIT, "error reading from network server");
 
-    if (r == 0)
-      Error(ERR_EXIT, "connection to network server lost");
+      if (r == 0)
+       Error(ERR_EXIT, "connection to network server lost");
 
-    nread += r;
+      nread += r;
 
-    HandleNetworkingMessages();
+      HandleNetworkingMessages();
+    }
   }
+  while (r > 0);
 }
 
 #endif /* PLATFORM_UNIX */
index 079745e98a5cb7d0a2e98b1bf1ddcb8e927d8978..12901f035f76b63fdb3e47d1217f3da7afe9e6bd 100644 (file)
@@ -270,7 +270,7 @@ void DrawMainMenu()
   leveldir_last_valid = leveldir_current;
 
   /* needed if last screen (level choice) changed graphics, sounds or music */
-  ReloadCustomArtwork();
+  ReloadCustomArtwork(0);
 
 #ifdef TARGET_SDL
   SetDrawtoField(DRAW_BACKBUFFER);
@@ -495,7 +495,7 @@ void HandleMainMenu(int mx, int my, int dx, int dy, int button)
        if (setup.autorecord)
          TapeStartRecording();
 
-#if defined(PLATFORM_UNIX)
+#if defined(NETWORK_AVALIABLE)
        if (options.network)
          SendToServer_StartPlaying();
        else
@@ -1869,7 +1869,7 @@ static void execSetupArtwork()
   setup.music_set = artwork.mus_current->identifier;
 
   /* needed if last screen (setup choice) changed graphics, sounds or music */
-  ReloadCustomArtwork();
+  ReloadCustomArtwork(0);
 
   /* needed for displaying artwork name instead of artwork identifier */
   graphics_set_name = artwork.gfx_current->name;
@@ -2395,7 +2395,7 @@ static void drawPlayerSetupInputInfo(int player_nr)
     { &custom_key.up,    "Joystick Up"    },
     { &custom_key.down,  "Joystick Down"  },
     { &custom_key.snap,  "Button 1"       },
-    { &custom_key.bomb,  "Button 2"       }
+    { &custom_key.drop,  "Button 2"       }
   };
   static char *joystick_name[MAX_PLAYERS] =
   {
@@ -2409,6 +2409,8 @@ static void drawPlayerSetupInputInfo(int player_nr)
 
   DrawText(mSX+11*32, mSY+2*32, int2str(player_nr +1, 1), FONT_INPUT_1_ACTIVE);
 #if 1
+  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
@@ -2440,7 +2442,7 @@ static void drawPlayerSetupInputInfo(int player_nr)
   DrawText(mSX+2*32, mSY+8*32, ":", FONT_VALUE_OLD);
   DrawText(mSX+2*32, mSY+9*32, ":", FONT_VALUE_OLD);
   DrawText(mSX+32, mSY+10*32, "Snap Field:", FONT_VALUE_OLD);
-  DrawText(mSX+32, mSY+12*32, "Place Bomb:", FONT_VALUE_OLD);
+  DrawText(mSX+32, mSY+12*32, "Drop Element:", FONT_VALUE_OLD);
 
   for (i = 0; i < 6; i++)
   {
@@ -2586,12 +2588,12 @@ void CustomizeKeyboard(int player_nr)
     char *text;
   } customize_step[] =
   {
-    { &custom_key.left,  "Move Left"  },
-    { &custom_key.right, "Move Right" },
-    { &custom_key.up,    "Move Up"    },
-    { &custom_key.down,  "Move Down"  },
-    { &custom_key.snap,  "Snap Field" },
-    { &custom_key.bomb,  "Place Bomb" }
+    { &custom_key.left,  "Move Left"   },
+    { &custom_key.right, "Move Right"  },
+    { &custom_key.up,    "Move Up"     },
+    { &custom_key.down,  "Move Down"   },
+    { &custom_key.snap,  "Snap Field"  },
+    { &custom_key.drop,  "Drop Element"        }
   };
 
   /* read existing key bindings from player setup */
index 51dcd8a2e0d85e4b47f12267cba9fef24ae118f2..66ca33c035107081a8ae9274c113ad9323db5794 100644 (file)
 #include "cartoons.h"
 
 /* tape button identifiers */
-#define TAPE_CTRL_ID_EJECT             0
-#define TAPE_CTRL_ID_INDEX             1
-#define TAPE_CTRL_ID_STOP              2
-#define TAPE_CTRL_ID_PAUSE             3
-#define TAPE_CTRL_ID_RECORD            4
-#define TAPE_CTRL_ID_PLAY              5
+#define TAPE_CTRL_ID_EJECT                     0
+#define TAPE_CTRL_ID_EXTRA                     1
+#define TAPE_CTRL_ID_STOP                      2
+#define TAPE_CTRL_ID_PAUSE                     3
+#define TAPE_CTRL_ID_RECORD                    4
+#define TAPE_CTRL_ID_PLAY                      5
 
-#define NUM_TAPE_BUTTONS               6
+#define NUM_TAPE_BUTTONS                       6
 
 /* values for tape handling */
 #define TAPE_PAUSE_SECONDS_BEFORE_DEATH                5
 
 /* forward declaration for internal use */
 static void HandleTapeButtons(struct GadgetInfo *);
-static void TapeStopIndexSearch();
+static void TapeStopWarpForward();
 
 static struct GadgetInfo *tape_gadget[NUM_TAPE_BUTTONS];
 
@@ -46,80 +46,140 @@ static struct GadgetInfo *tape_gadget[NUM_TAPE_BUTTONS];
 /* ========================================================================= */
 
 /* some positions in the video tape control window */
-#define VIDEO_DATE_LABEL_XPOS  (VIDEO_DISPLAY1_XPOS)
-#define VIDEO_DATE_LABEL_YPOS  (VIDEO_DISPLAY1_YPOS)
-#define VIDEO_DATE_LABEL_XSIZE (VIDEO_DISPLAY_XSIZE)
-#define VIDEO_DATE_LABEL_YSIZE (VIDEO_DISPLAY_YSIZE)
-#define VIDEO_DATE_XPOS                (VIDEO_DISPLAY1_XPOS + 2)
-#define VIDEO_DATE_YPOS                (VIDEO_DISPLAY1_YPOS + 14)
-#define VIDEO_DATE_XSIZE       (VIDEO_DISPLAY_XSIZE)
-#define VIDEO_DATE_YSIZE       16
-#define VIDEO_REC_LABEL_XPOS   (VIDEO_DISPLAY2_XPOS)
-#define VIDEO_REC_LABEL_YPOS   (VIDEO_DISPLAY2_YPOS)
-#define VIDEO_REC_LABEL_XSIZE  20
-#define VIDEO_REC_LABEL_YSIZE  12
-#define VIDEO_REC_SYMBOL_XPOS  (VIDEO_DISPLAY2_XPOS + 20)
-#define VIDEO_REC_SYMBOL_YPOS  (VIDEO_DISPLAY2_YPOS)
-#define VIDEO_REC_SYMBOL_XSIZE 16
-#define VIDEO_REC_SYMBOL_YSIZE 16
-#define VIDEO_PLAY_LABEL_XPOS  (VIDEO_DISPLAY2_XPOS + 65)
-#define VIDEO_PLAY_LABEL_YPOS  (VIDEO_DISPLAY2_YPOS)
-#define VIDEO_PLAY_LABEL_XSIZE 22
-#define VIDEO_PLAY_LABEL_YSIZE 12
-#define VIDEO_PLAY_SYMBOL_XPOS (VIDEO_DISPLAY2_XPOS + 52)
-#define VIDEO_PLAY_SYMBOL_YPOS (VIDEO_DISPLAY2_YPOS)
-#define VIDEO_PLAY_SYMBOL_XSIZE        11
-#define VIDEO_PLAY_SYMBOL_YSIZE        13
-#define VIDEO_PAUSE_LABEL_XPOS (VIDEO_DISPLAY2_XPOS)
-#define VIDEO_PAUSE_LABEL_YPOS (VIDEO_DISPLAY2_YPOS + 20)
-#define VIDEO_PAUSE_LABEL_XSIZE        35
-#define VIDEO_PAUSE_LABEL_YSIZE        8
-#define VIDEO_PAUSE_SYMBOL_XPOS        (VIDEO_DISPLAY2_XPOS + 35)
-#define VIDEO_PAUSE_SYMBOL_YPOS        (VIDEO_DISPLAY2_YPOS)
-#define VIDEO_PAUSE_SYMBOL_XSIZE 17
-#define VIDEO_PAUSE_SYMBOL_YSIZE 13
-#define VIDEO_TIME_XPOS                (VIDEO_DISPLAY2_XPOS + 39)
-#define VIDEO_TIME_YPOS                (VIDEO_DISPLAY2_YPOS + 14)
-#define VIDEO_TIME_XSIZE       50
-#define VIDEO_TIME_YSIZE       16
-
-/* special */
-#define VIDEO_PBEND_LABEL_XPOS 5
-#define VIDEO_PBEND_LABEL_YPOS 220
-#define VIDEO_PBEND_LABEL_XSIZE        35
-#define VIDEO_PBEND_LABEL_YSIZE        30
-
-#define VIDEO_STATE_OFF                (VIDEO_STATE_PLAY_OFF   |       \
-                                VIDEO_STATE_REC_OFF    |       \
-                                VIDEO_STATE_PAUSE_OFF  |       \
-                                VIDEO_STATE_FFWD_OFF   |       \
-                                VIDEO_STATE_PBEND_OFF  |       \
-                                VIDEO_STATE_DATE_OFF   |       \
-                                VIDEO_STATE_TIME_OFF)
-#define VIDEO_PRESS_OFF                (VIDEO_PRESS_PLAY_OFF   |       \
-                                VIDEO_PRESS_REC_OFF    |       \
-                                VIDEO_PRESS_PAUSE_OFF  |       \
-                                VIDEO_PRESS_STOP_OFF   |       \
-                                VIDEO_PRESS_EJECT_OFF)
-#define VIDEO_ALL_OFF          (VIDEO_STATE_OFF | VIDEO_PRESS_OFF)
-
-#define VIDEO_STATE_ON         (VIDEO_STATE_PLAY_ON    |       \
-                                VIDEO_STATE_REC_ON     |       \
-                                VIDEO_STATE_PAUSE_ON   |       \
-                                VIDEO_STATE_FFWD_ON    |       \
-                                VIDEO_STATE_PBEND_ON   |       \
-                                VIDEO_STATE_DATE_ON    |       \
-                                VIDEO_STATE_TIME_ON)
-#define VIDEO_PRESS_ON         (VIDEO_PRESS_PLAY_ON    |       \
-                                VIDEO_PRESS_REC_ON     |       \
-                                VIDEO_PRESS_PAUSE_ON   |       \
-                                VIDEO_PRESS_STOP_ON    |       \
-                                VIDEO_PRESS_EJECT_ON)
-#define VIDEO_ALL_ON           (VIDEO_STATE_ON | VIDEO_PRESS_ON)
-
-#define VIDEO_STATE            (VIDEO_STATE_ON | VIDEO_STATE_OFF)
-#define VIDEO_PRESS            (VIDEO_PRESS_ON | VIDEO_PRESS_OFF)
-#define VIDEO_ALL              (VIDEO_ALL_ON | VIDEO_ALL_OFF)
+#define VIDEO_DATE_LABEL_XPOS          (VIDEO_DISPLAY1_XPOS)
+#define VIDEO_DATE_LABEL_YPOS          (VIDEO_DISPLAY1_YPOS)
+#define VIDEO_DATE_LABEL_XSIZE         (VIDEO_DISPLAY_XSIZE)
+#define VIDEO_DATE_LABEL_YSIZE         (VIDEO_DISPLAY_YSIZE)
+#define VIDEO_DATE_XPOS                        (VIDEO_DISPLAY1_XPOS + 2)
+#define VIDEO_DATE_YPOS                        (VIDEO_DISPLAY1_YPOS + 14)
+#define VIDEO_DATE_XSIZE               (VIDEO_DISPLAY_XSIZE)
+#define VIDEO_DATE_YSIZE               16
+#define VIDEO_REC_LABEL_XPOS           (VIDEO_DISPLAY2_XPOS)
+#define VIDEO_REC_LABEL_YPOS           (VIDEO_DISPLAY2_YPOS)
+#define VIDEO_REC_LABEL_XSIZE          20
+#define VIDEO_REC_LABEL_YSIZE          12
+#define VIDEO_REC_SYMBOL_XPOS          (VIDEO_DISPLAY2_XPOS + 20)
+#define VIDEO_REC_SYMBOL_YPOS          (VIDEO_DISPLAY2_YPOS)
+#define VIDEO_REC_SYMBOL_XSIZE         16
+#define VIDEO_REC_SYMBOL_YSIZE         16
+#define VIDEO_PLAY_LABEL_XPOS          (VIDEO_DISPLAY2_XPOS + 65)
+#define VIDEO_PLAY_LABEL_YPOS          (VIDEO_DISPLAY2_YPOS)
+#define VIDEO_PLAY_LABEL_XSIZE         22
+#define VIDEO_PLAY_LABEL_YSIZE         12
+#define VIDEO_PLAY_SYMBOL_XPOS         (VIDEO_DISPLAY2_XPOS + 52)
+#define VIDEO_PLAY_SYMBOL_YPOS         (VIDEO_DISPLAY2_YPOS)
+#define VIDEO_PLAY_SYMBOL_XSIZE                11
+#define VIDEO_PLAY_SYMBOL_YSIZE                13
+#define VIDEO_PAUSE_LABEL_XPOS         (VIDEO_DISPLAY2_XPOS)
+#define VIDEO_PAUSE_LABEL_YPOS         (VIDEO_DISPLAY2_YPOS + 20)
+#define VIDEO_PAUSE_LABEL_XSIZE                35
+#define VIDEO_PAUSE_LABEL_YSIZE                8
+#define VIDEO_PAUSE_SYMBOL_XPOS                (VIDEO_DISPLAY2_XPOS + 35)
+#define VIDEO_PAUSE_SYMBOL_YPOS                (VIDEO_DISPLAY2_YPOS)
+#define VIDEO_PAUSE_SYMBOL_XSIZE       17
+#define VIDEO_PAUSE_SYMBOL_YSIZE       13
+#define VIDEO_TIME_XPOS                        (VIDEO_DISPLAY2_XPOS + 39)
+#define VIDEO_TIME_YPOS                        (VIDEO_DISPLAY2_YPOS + 14)
+#define VIDEO_TIME_XSIZE               50
+#define VIDEO_TIME_YSIZE               16
+
+/* some default values for tape labels and symbols */
+#define VIDEO_LABEL_XPOS               5
+#define VIDEO_LABEL_YPOS               42
+#define VIDEO_LABEL_XSIZE              40
+#define VIDEO_LABEL_YSIZE              28
+#define VIDEO_SYMBOL_XPOS              39
+#define VIDEO_SYMBOL_YPOS              42
+#define VIDEO_SYMBOL_XSIZE             56
+#define VIDEO_SYMBOL_YSIZE             13
+
+/* values for certain tape labels and symbols */
+#define VIDEO_FFWD_LABEL_XPOS          VIDEO_LABEL_XPOS
+#define VIDEO_FFWD_LABEL_YPOS          193
+#define VIDEO_FFWD_LABEL_XSIZE         VIDEO_LABEL_XSIZE
+#define VIDEO_FFWD_LABEL_YSIZE         VIDEO_LABEL_YSIZE
+#define VIDEO_FFWD_SYMBOL_XPOS         VIDEO_SYMBOL_XPOS
+#define VIDEO_FFWD_SYMBOL_YPOS         193
+#define VIDEO_FFWD_SYMBOL_XSIZE                27
+#define VIDEO_FFWD_SYMBOL_YSIZE                VIDEO_SYMBOL_YSIZE
+
+#define VIDEO_PBEND_LABEL_XPOS         VIDEO_LABEL_XPOS
+#define VIDEO_PBEND_LABEL_YPOS         221
+#define VIDEO_PBEND_LABEL_XSIZE                VIDEO_LABEL_XSIZE
+#define VIDEO_PBEND_LABEL_YSIZE                VIDEO_LABEL_YSIZE
+#define VIDEO_PBEND_SYMBOL_XPOS                VIDEO_SYMBOL_XPOS
+#define VIDEO_PBEND_SYMBOL_YPOS                221
+#define VIDEO_PBEND_SYMBOL_XSIZE       27
+#define VIDEO_PBEND_SYMBOL_YSIZE       VIDEO_SYMBOL_YSIZE
+
+#define VIDEO_WARP_LABEL_XPOS          VIDEO_LABEL_XPOS
+#define VIDEO_WARP_LABEL_YPOS          165
+#define VIDEO_WARP_LABEL_XSIZE         VIDEO_LABEL_XSIZE
+#define VIDEO_WARP_LABEL_YSIZE         VIDEO_LABEL_YSIZE
+#define VIDEO_WARP_SYMBOL_XPOS         VIDEO_SYMBOL_XPOS
+#define VIDEO_WARP_SYMBOL_YPOS         165
+#define VIDEO_WARP_SYMBOL_XSIZE                27
+#define VIDEO_WARP_SYMBOL_YSIZE                VIDEO_SYMBOL_YSIZE
+#define VIDEO_WARP2_SYMBOL_XPOS                VIDEO_SYMBOL_XPOS
+#define VIDEO_WARP2_SYMBOL_YPOS                152
+#define VIDEO_WARP2_SYMBOL_XSIZE       27
+#define VIDEO_WARP2_SYMBOL_YSIZE       VIDEO_SYMBOL_YSIZE
+
+#define VIDEO_1STEP_SYMBOL_XPOS                (VIDEO_SYMBOL_XPOS + 18)
+#define VIDEO_1STEP_SYMBOL_YPOS                139
+#define VIDEO_1STEP_SYMBOL_XSIZE       (VIDEO_SYMBOL_XSIZE - 18)
+#define VIDEO_1STEP_SYMBOL_YSIZE       VIDEO_SYMBOL_YSIZE
+
+#define PG_X3(x)                       (DOOR_GFX_PAGEX3 + (x))
+#define PG_X4(x)                       (DOOR_GFX_PAGEX4 + (x))
+#define PG_X5(x)                       (DOOR_GFX_PAGEX5 + (x))
+#define PG_X6(x)                       (DOOR_GFX_PAGEX6 + (x))
+
+#define PG_Y1(y)                       (DOOR_GFX_PAGEY1 + (y))
+#define PG_Y2(y)                       (DOOR_GFX_PAGEY2 + (y))
+
+#define VIDEO_INFO_OFF                 (VIDEO_STATE_DATE_OFF   |       \
+                                        VIDEO_STATE_TIME_OFF)
+#define VIDEO_STATE_OFF                        (VIDEO_STATE_PLAY_OFF   |       \
+                                        VIDEO_STATE_REC_OFF    |       \
+                                        VIDEO_STATE_PAUSE_OFF  |       \
+                                        VIDEO_STATE_FFWD_OFF   |       \
+                                        VIDEO_STATE_PBEND_OFF  |       \
+                                        VIDEO_STATE_1STEP_OFF)
+#define VIDEO_PRESS_OFF                        (VIDEO_PRESS_PLAY_OFF   |       \
+                                        VIDEO_PRESS_REC_OFF    |       \
+                                        VIDEO_PRESS_PAUSE_OFF  |       \
+                                        VIDEO_PRESS_STOP_OFF   |       \
+                                        VIDEO_PRESS_EJECT_OFF)
+#define VIDEO_ALL_OFF                  (VIDEO_INFO_OFF         |       \
+                                        VIDEO_STATE_OFF        |       \
+                                        VIDEO_PRESS_OFF)
+
+#define VIDEO_INFO_ON                  (VIDEO_STATE_DATE_ON    |       \
+                                        VIDEO_STATE_TIME_ON)
+#define VIDEO_STATE_ON                 (VIDEO_STATE_PLAY_ON    |       \
+                                        VIDEO_STATE_REC_ON     |       \
+                                        VIDEO_STATE_PAUSE_ON   |       \
+                                        VIDEO_STATE_FFWD_ON    |       \
+                                        VIDEO_STATE_PBEND_ON   |       \
+                                        VIDEO_STATE_1STEP_ON)
+#define VIDEO_PRESS_ON                 (VIDEO_PRESS_PLAY_ON    |       \
+                                        VIDEO_PRESS_REC_ON     |       \
+                                        VIDEO_PRESS_PAUSE_ON   |       \
+                                        VIDEO_PRESS_STOP_ON    |       \
+                                        VIDEO_PRESS_EJECT_ON)
+#define VIDEO_ALL_ON                   (VIDEO_INFO_ON          |       \
+                                        VIDEO_STATE_ON         |       \
+                                        VIDEO_PRESS_ON)
+
+#define VIDEO_INFO                     (VIDEO_INFO_ON | VIDEO_INFO_OFF)
+#define VIDEO_STATE                    (VIDEO_STATE_ON | VIDEO_STATE_OFF)
+#define VIDEO_PRESS                    (VIDEO_PRESS_ON | VIDEO_PRESS_OFF)
+#define VIDEO_ALL                      (VIDEO_ALL_ON | VIDEO_ALL_OFF)
+
+#define NUM_TAPE_FUNCTIONS             10
+#define NUM_TAPE_FUNCTION_PARTS                2
+#define NUM_TAPE_FUNCTION_STATES       2
 
 
 /* ========================================================================= */
@@ -128,44 +188,230 @@ static struct GadgetInfo *tape_gadget[NUM_TAPE_BUTTONS];
 
 void DrawVideoDisplay(unsigned long state, unsigned long value)
 {
-  int i;
-  int part_label = 0, part_symbol = 1;
-  int xpos = 0, ypos = 1, xsize = 2, ysize = 3;
+  int i, j, k;
   static char *monatsname[12] =
   {
     "JAN", "FEB", "MAR", "APR", "MAY", "JUN",
     "JUL", "AUG", "SEP", "OCT", "NOV", "DEC"
   };
-  static int video_pos[5][2][4] =
+  static struct
+  {
+    int gd_x1, gd_y1;
+    int gd_x2, gd_y2;
+    int x, y;
+    int width, height;
+  }
+  video_pos[NUM_TAPE_FUNCTIONS][NUM_TAPE_FUNCTION_PARTS] =
   {
-    {{ VIDEO_PLAY_LABEL_XPOS, VIDEO_PLAY_LABEL_YPOS,
-       VIDEO_PLAY_LABEL_XSIZE,VIDEO_PLAY_LABEL_YSIZE },
-     { VIDEO_PLAY_SYMBOL_XPOS, VIDEO_PLAY_SYMBOL_YPOS,
-       VIDEO_PLAY_SYMBOL_XSIZE,VIDEO_PLAY_SYMBOL_YSIZE }},
-
-    {{ VIDEO_REC_LABEL_XPOS, VIDEO_REC_LABEL_YPOS,
-       VIDEO_REC_LABEL_XSIZE,VIDEO_REC_LABEL_YSIZE },
-     { VIDEO_REC_SYMBOL_XPOS, VIDEO_REC_SYMBOL_YPOS,
-       VIDEO_REC_SYMBOL_XSIZE,VIDEO_REC_SYMBOL_YSIZE }},
-
-    {{ VIDEO_PAUSE_LABEL_XPOS, VIDEO_PAUSE_LABEL_YPOS,
-       VIDEO_PAUSE_LABEL_XSIZE,VIDEO_PAUSE_LABEL_YSIZE },
-     { VIDEO_PAUSE_SYMBOL_XPOS, VIDEO_PAUSE_SYMBOL_YPOS,
-       VIDEO_PAUSE_SYMBOL_XSIZE,VIDEO_PAUSE_SYMBOL_YSIZE }},
-
-    {{ VIDEO_DATE_LABEL_XPOS, VIDEO_DATE_LABEL_YPOS,
-       VIDEO_DATE_LABEL_XSIZE,VIDEO_DATE_LABEL_YSIZE },
-     { VIDEO_DATE_XPOS, VIDEO_DATE_YPOS,
-       VIDEO_DATE_XSIZE,VIDEO_DATE_YSIZE }},
-
-    {{ 0,0,
-       0,0 },
-     { VIDEO_TIME_XPOS, VIDEO_TIME_YPOS,
-       VIDEO_TIME_XSIZE,VIDEO_TIME_YSIZE }}
+    {
+      {
+       PG_X4(VIDEO_PLAY_LABEL_XPOS),   PG_Y2(VIDEO_PLAY_LABEL_YPOS),
+       PG_X3(VIDEO_PLAY_LABEL_XPOS),   PG_Y2(VIDEO_PLAY_LABEL_YPOS),
+       VIDEO_PLAY_LABEL_XPOS,          VIDEO_PLAY_LABEL_YPOS,
+       VIDEO_PLAY_LABEL_XSIZE,         VIDEO_PLAY_LABEL_YSIZE
+      },
+      {
+       PG_X4(VIDEO_PLAY_SYMBOL_XPOS),  PG_Y2(VIDEO_PLAY_SYMBOL_YPOS),
+       PG_X3(VIDEO_PLAY_SYMBOL_XPOS),  PG_Y2(VIDEO_PLAY_SYMBOL_YPOS),
+       VIDEO_PLAY_SYMBOL_XPOS,         VIDEO_PLAY_SYMBOL_YPOS,
+       VIDEO_PLAY_SYMBOL_XSIZE,        VIDEO_PLAY_SYMBOL_YSIZE
+      }
+    },
+    {
+      {
+       PG_X4(VIDEO_REC_LABEL_XPOS),    PG_Y2(VIDEO_REC_LABEL_YPOS),
+       PG_X3(VIDEO_REC_LABEL_XPOS),    PG_Y2(VIDEO_REC_LABEL_YPOS),
+       VIDEO_REC_LABEL_XPOS,           VIDEO_REC_LABEL_YPOS,
+       VIDEO_REC_LABEL_XSIZE,          VIDEO_REC_LABEL_YSIZE
+      },
+      {
+       PG_X4(VIDEO_REC_SYMBOL_XPOS),   PG_Y2(VIDEO_REC_SYMBOL_YPOS),
+       PG_X3(VIDEO_REC_SYMBOL_XPOS),   PG_Y2(VIDEO_REC_SYMBOL_YPOS),
+       VIDEO_REC_SYMBOL_XPOS,          VIDEO_REC_SYMBOL_YPOS,
+       VIDEO_REC_SYMBOL_XSIZE,         VIDEO_REC_SYMBOL_YSIZE
+      }
+    },
+    {
+      {
+       PG_X4(VIDEO_PAUSE_LABEL_XPOS),  PG_Y2(VIDEO_PAUSE_LABEL_YPOS),
+       PG_X3(VIDEO_PAUSE_LABEL_XPOS),  PG_Y2(VIDEO_PAUSE_LABEL_YPOS),
+       VIDEO_PAUSE_LABEL_XPOS,         VIDEO_PAUSE_LABEL_YPOS,
+       VIDEO_PAUSE_LABEL_XSIZE,        VIDEO_PAUSE_LABEL_YSIZE
+      },
+      {
+       PG_X4(VIDEO_PAUSE_SYMBOL_XPOS), PG_Y2(VIDEO_PAUSE_SYMBOL_YPOS),
+       PG_X3(VIDEO_PAUSE_SYMBOL_XPOS), PG_Y2(VIDEO_PAUSE_SYMBOL_YPOS),
+       VIDEO_PAUSE_SYMBOL_XPOS,        VIDEO_PAUSE_SYMBOL_YPOS,
+       VIDEO_PAUSE_SYMBOL_XSIZE,       VIDEO_PAUSE_SYMBOL_YSIZE
+      }
+    },
+    {
+      {
+       PG_X4(VIDEO_DATE_LABEL_XPOS),   PG_Y2(VIDEO_DATE_LABEL_YPOS),
+       PG_X3(VIDEO_DATE_LABEL_XPOS),   PG_Y2(VIDEO_DATE_LABEL_YPOS),
+       VIDEO_DATE_LABEL_XPOS,          VIDEO_DATE_LABEL_YPOS,
+       VIDEO_DATE_LABEL_XSIZE,         VIDEO_DATE_LABEL_YSIZE
+      },
+      {
+       PG_X4(VIDEO_DATE_XPOS),         PG_Y2(VIDEO_DATE_YPOS),
+       PG_X3(VIDEO_DATE_XPOS),         PG_Y2(VIDEO_DATE_YPOS),
+       VIDEO_DATE_XPOS,                VIDEO_DATE_YPOS,
+       VIDEO_DATE_XSIZE,               VIDEO_DATE_YSIZE
+      }
+    },
+    {
+      {
+       -1,                             -1,
+       -1,                             -1,
+       -1,                             -1,
+       -1,                             -1
+      },
+      {
+       PG_X4(VIDEO_TIME_XPOS),         PG_Y2(VIDEO_TIME_YPOS),
+       PG_X3(VIDEO_TIME_XPOS),         PG_Y2(VIDEO_TIME_YPOS),
+       VIDEO_TIME_XPOS,                VIDEO_TIME_YPOS,
+       VIDEO_TIME_XSIZE,               VIDEO_TIME_YSIZE
+      }
+    },
+    {
+      {
+       PG_X6(VIDEO_FFWD_LABEL_XPOS),   PG_Y1(VIDEO_FFWD_LABEL_YPOS),
+       PG_X3(VIDEO_LABEL_XPOS),        PG_Y2(VIDEO_LABEL_YPOS),
+       VIDEO_LABEL_XPOS,               VIDEO_LABEL_YPOS,
+       VIDEO_LABEL_XSIZE,              VIDEO_LABEL_YSIZE
+      },
+      {
+       PG_X6(VIDEO_FFWD_SYMBOL_XPOS),  PG_Y1(VIDEO_FFWD_SYMBOL_YPOS),
+       PG_X3(VIDEO_FFWD_SYMBOL_XPOS),  PG_Y2(VIDEO_SYMBOL_YPOS),
+       VIDEO_SYMBOL_XPOS,              VIDEO_SYMBOL_YPOS,
+       VIDEO_FFWD_SYMBOL_XSIZE,        VIDEO_FFWD_SYMBOL_YSIZE
+      }
+    },
+    {
+      {
+       PG_X6(VIDEO_PBEND_LABEL_XPOS),  PG_Y1(VIDEO_PBEND_LABEL_YPOS),
+       PG_X3(VIDEO_LABEL_XPOS),        PG_Y2(VIDEO_LABEL_YPOS),
+       VIDEO_LABEL_XPOS,               VIDEO_LABEL_YPOS,
+       VIDEO_LABEL_XSIZE,              VIDEO_LABEL_YSIZE
+      },
+      {
+       PG_X6(VIDEO_PBEND_SYMBOL_XPOS), PG_Y1(VIDEO_PBEND_SYMBOL_YPOS),
+       PG_X3(VIDEO_PBEND_SYMBOL_XPOS), PG_Y2(VIDEO_SYMBOL_YPOS),
+       VIDEO_SYMBOL_XPOS,              VIDEO_SYMBOL_YPOS,
+       VIDEO_PBEND_SYMBOL_XSIZE,       VIDEO_PBEND_SYMBOL_YSIZE
+      }
+    },
+    {
+      {
+       PG_X6(VIDEO_WARP_LABEL_XPOS),   PG_Y1(VIDEO_WARP_LABEL_YPOS),
+       PG_X3(VIDEO_LABEL_XPOS),        PG_Y2(VIDEO_LABEL_YPOS),
+       VIDEO_LABEL_XPOS,               VIDEO_LABEL_YPOS,
+       VIDEO_LABEL_XSIZE,              VIDEO_LABEL_YSIZE
+      },
+      {
+       PG_X6(VIDEO_WARP_SYMBOL_XPOS),  PG_Y1(VIDEO_WARP_SYMBOL_YPOS),
+       PG_X3(VIDEO_WARP_SYMBOL_XPOS),  PG_Y2(VIDEO_SYMBOL_YPOS),
+       VIDEO_SYMBOL_XPOS,              VIDEO_SYMBOL_YPOS,
+       VIDEO_WARP_SYMBOL_XSIZE,        VIDEO_WARP_SYMBOL_YSIZE
+      }
+    },
+    {
+      {
+       -1,                             -1,
+       -1,                             -1,
+       -1,                             -1,
+       -1,                             -1
+      },
+      {
+       PG_X6(VIDEO_WARP2_SYMBOL_XPOS), PG_Y1(VIDEO_WARP2_SYMBOL_YPOS),
+       PG_X3(VIDEO_WARP2_SYMBOL_XPOS), PG_Y2(VIDEO_SYMBOL_YPOS),
+       VIDEO_SYMBOL_XPOS,              VIDEO_SYMBOL_YPOS,
+       VIDEO_WARP2_SYMBOL_XSIZE,       VIDEO_WARP2_SYMBOL_YSIZE
+      }
+    },
+    {
+      {
+       -1,                             -1,
+       -1,                             -1,
+       -1,                             -1,
+       -1,                             -1
+      },
+      {
+       PG_X6(VIDEO_1STEP_SYMBOL_XPOS), PG_Y1(VIDEO_1STEP_SYMBOL_YPOS),
+       PG_X3(VIDEO_1STEP_SYMBOL_XPOS), PG_Y2(VIDEO_SYMBOL_YPOS),
+       VIDEO_1STEP_SYMBOL_XPOS,        VIDEO_SYMBOL_YPOS,
+       VIDEO_1STEP_SYMBOL_XSIZE,       VIDEO_1STEP_SYMBOL_YSIZE
+      }
+    },
   };
 
+#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,
@@ -175,40 +421,88 @@ void DrawVideoDisplay(unsigned long state, unsigned long value)
               VIDEO_PBEND_LABEL_YSIZE,
               VX + VIDEO_REC_LABEL_XPOS,
               VY + VIDEO_REC_LABEL_YPOS);
+#endif
   }
+#endif
 
-  for (i = 0; i < 10; i++)
+#if 0
+  if (state & VIDEO_STATE_1STEP_OFF)
   {
-    if (state & (1<<i))
-    {
-      int pos = i/2, cx, cy = DOOR_GFX_PAGEY2;
+    int cx = DOOR_GFX_PAGEX3, cy = DOOR_GFX_PAGEY2;
 
-      if (i%2)                 /* i ungerade => STATE_ON / PRESS_OFF */
-       cx = DOOR_GFX_PAGEX4;
-      else
-       cx = DOOR_GFX_PAGEX3;   /* i gerade => STATE_OFF / PRESS_ON */
-
-      if (video_pos[pos][part_label][0] && value != VIDEO_DISPLAY_SYMBOL_ONLY)
-       BlitBitmap(graphic_info[IMG_GLOBAL_DOOR].bitmap, drawto,
-                  cx + video_pos[pos][part_label][xpos],
-                  cy + video_pos[pos][part_label][ypos],
-                  video_pos[pos][part_label][xsize],
-                  video_pos[pos][part_label][ysize],
-                  VX + video_pos[pos][part_label][xpos],
-                  VY + video_pos[pos][part_label][ypos]);
-      if (video_pos[pos][part_symbol][0] && value != VIDEO_DISPLAY_LABEL_ONLY)
-       BlitBitmap(graphic_info[IMG_GLOBAL_DOOR].bitmap, drawto,
-                  cx + video_pos[pos][part_symbol][xpos],
-                  cy + video_pos[pos][part_symbol][ypos],
-                  video_pos[pos][part_symbol][xsize],
-                  video_pos[pos][part_symbol][ysize],
-                  VX + video_pos[pos][part_symbol][xpos],
-                  VY + video_pos[pos][part_symbol][ypos]);
+    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, ... */
+    {
+      for (j = 0; j < NUM_TAPE_FUNCTION_PARTS; j++)    /* label or symbol */
+      {
+       if (state & (1 << (i * 2 + k)))
+       {
+         int gd_x, gd_y;
+         int skip_value =
+           (j == 0 ? VIDEO_DISPLAY_SYMBOL_ONLY : VIDEO_DISPLAY_LABEL_ONLY);
+
+         if (k == 1)           /* on */
+         {
+           gd_x = video_pos[i][j].gd_x1;
+           gd_y = video_pos[i][j].gd_y1;
+         }
+         else                  /* off */
+         {
+           gd_x = video_pos[i][j].gd_x2;
+           gd_y = video_pos[i][j].gd_y2;
+         }
+
+         if (video_pos[i][j].x != -1 && value != skip_value)
+           BlitBitmap(graphic_info[IMG_GLOBAL_DOOR].bitmap, drawto,
+                      gd_x, gd_y,
+                      video_pos[i][j].width,
+                      video_pos[i][j].height,
+                      VX + video_pos[i][j].x,
+                      VY + video_pos[i][j].y);
+       }
+      }
     }
   }
 
+#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,
@@ -218,10 +512,37 @@ void DrawVideoDisplay(unsigned long state, unsigned long value)
               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,
@@ -231,7 +552,25 @@ void DrawVideoDisplay(unsigned long state, unsigned long value)
               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)
   {
@@ -258,12 +597,16 @@ 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()
@@ -288,15 +631,39 @@ void DrawCompleteVideoDisplay()
             DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2);
 }
 
+void TapeDeactivateDisplayOn()
+{
+  SetDrawDeactivationMask(REDRAW_FIELD);
+  audio.sound_deactivated = TRUE;
+}
+
+void TapeDeactivateDisplayOff(boolean redraw_display)
+{
+  SetDrawDeactivationMask(REDRAW_NONE);
+  audio.sound_deactivated = FALSE;
+
+  if (redraw_display)
+  {
+    RedrawPlayfield(TRUE, 0,0,0,0);
+    DrawGameDoorValues();
+  }
+}
+
 
 /* ========================================================================= */
 /* tape control functions                                                    */
 /* ========================================================================= */
 
-void TapeErase()
+static void TapeSetDate()
 {
   time_t epoch_seconds = time(NULL);
-  struct tm *time = localtime(&epoch_seconds);
+  struct tm *now = localtime(&epoch_seconds);
+
+  tape.date = 10000 * (now->tm_year % 100) + 100 * now->tm_mon + now->tm_mday;
+}
+
+void TapeErase()
+{
   int i;
 
   tape.length = 0;
@@ -309,13 +676,14 @@ void TapeErase()
   tape.pos[tape.counter].delay = 0;
   tape.changed = TRUE;
 
-  tape.date = 10000*(time->tm_year % 100) + 100*time->tm_mon + time->tm_mday;
   tape.random_seed = InitRND(NEW_RANDOMIZE);
 
   tape.file_version = FILE_VERSION_ACTUAL;
   tape.game_version = GAME_VERSION_ACTUAL;
   tape.engine_version = level.game_version;
 
+  TapeSetDate();
+
 #if 0
   printf("::: tape.engine_version = level.game_version = %d \n",
         level.game_version);
@@ -333,7 +701,8 @@ static void TapeRewind()
   tape.recording = FALSE;
   tape.playing = FALSE;
   tape.fast_forward = FALSE;
-  tape.index_search = FALSE;
+  tape.warp_forward = FALSE;
+  tape.deactivate_display = FALSE;
   tape.auto_play = (global.autoplay_leveldir != NULL);
   tape.auto_play_level_solved = FALSE;
   tape.quick_resume = FALSE;
@@ -355,7 +724,7 @@ void TapeStartRecording()
   DrawVideoDisplay(VIDEO_STATE_REC_ON, 0);
   DrawVideoDisplay(VIDEO_STATE_DATE_ON, tape.date);
   DrawVideoDisplay(VIDEO_STATE_TIME_ON, 0);
-  MapTapeIndexButton();
+  MapTapeWarpButton();
 
   SetDrawDeactivationMask(REDRAW_NONE);
   audio.sound_deactivated = FALSE;
@@ -365,7 +734,7 @@ static void TapeStartGameRecording()
 {
   TapeStartRecording();
 
-#if defined(PLATFORM_UNIX)
+#if defined(NETWORK_AVALIABLE)
   if (options.network)
     SendToServer_StartPlaying();
   else
@@ -387,7 +756,10 @@ static void TapeAppendRecording()
   tape.recording = TRUE;
   tape.changed = TRUE;
 
-  DrawVideoDisplay(VIDEO_STATE_PLAY_OFF | VIDEO_STATE_REC_ON,0);
+  TapeSetDate();
+
+  DrawVideoDisplay(VIDEO_STATE_DATE_ON, tape.date);
+  DrawVideoDisplay(VIDEO_STATE_PLAY_OFF | VIDEO_STATE_REC_ON, 0);
 }
 
 void TapeHaltRecording()
@@ -420,8 +792,13 @@ void TapeRecordAction(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)
     return;
+#endif
 
   if (tape.counter >= MAX_TAPELEN - 1)
   {
@@ -429,6 +806,10 @@ void TapeRecordAction(byte action[MAX_PLAYERS])
     return;
   }
 
+#if 0
+  printf("::: %05d: recording action: %d\n", FrameCounter, action[0]);
+#endif
+
   if (tape.pos[tape.counter].delay > 0)                /* already stored action */
   {
     boolean changed_events = FALSE;
@@ -448,6 +829,11 @@ 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];
 
@@ -457,13 +843,18 @@ void TapeRecordAction(byte action[MAX_PLAYERS])
 
 void TapeTogglePause(boolean toggle_manual)
 {
-  unsigned long state;
+  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)
+    state |= VIDEO_STATE_FFWD_OFF;
+
   tape.pausing = !tape.pausing;
   tape.fast_forward = FALSE;
   tape.pause_before_death = FALSE;
@@ -471,22 +862,31 @@ void TapeTogglePause(boolean toggle_manual)
   if (tape.single_step && toggle_manual)
     tape.single_step = FALSE;
 
-  state = (tape.pausing ? VIDEO_STATE_PAUSE_ON : VIDEO_STATE_PAUSE_OFF);
+  state |= (tape.pausing ? VIDEO_STATE_PAUSE_ON : VIDEO_STATE_PAUSE_OFF);
   if (tape.playing)
-    state |= VIDEO_STATE_PBEND_OFF;
+    state |= VIDEO_STATE_PLAY_ON;
+  else
+    state |= (tape.single_step ? VIDEO_STATE_1STEP_ON : VIDEO_STATE_1STEP_OFF);
 
   DrawVideoDisplay(state, 0);
 
-  if (tape.index_search)
+#if 0
+  if (tape.pausing)
+    DrawVideoDisplay(VIDEO_STATE_PAUSE_ON, 0);
+#endif
+
+  if (tape.warp_forward)
   {
-    TapeStopIndexSearch();
+    TapeStopWarpForward();
 
     if (tape.quick_resume)
     {
       tape.quick_resume = FALSE;
 
       TapeAppendRecording();
+#if 0
       TapeTogglePause(toggle_manual);
+#endif
     }
   }
 }
@@ -506,7 +906,7 @@ void TapeStartPlaying()
   DrawVideoDisplay(VIDEO_STATE_PLAY_ON, 0);
   DrawVideoDisplay(VIDEO_STATE_DATE_ON, tape.date);
   DrawVideoDisplay(VIDEO_STATE_TIME_ON, 0);
-  MapTapeIndexButton();
+  MapTapeWarpButton();
 
   SetDrawDeactivationMask(REDRAW_NONE);
   audio.sound_deactivated = FALSE;
@@ -529,8 +929,8 @@ void TapeStopPlaying()
   tape.playing = FALSE;
   tape.pausing = FALSE;
 
-  if (tape.index_search)
-    TapeStopIndexSearch();
+  if (tape.warp_forward)
+    TapeStopWarpForward();
 
   DrawVideoDisplay(VIDEO_STATE_PLAY_OFF, 0);
   MapTapeEjectButton();
@@ -554,16 +954,51 @@ byte *TapePlayAction()
        DrawVideoDisplay(VIDEO_STATE_PBEND_OFF, VIDEO_DISPLAY_LABEL_ONLY);
     }
 
-    if (TimePlayed > tape.length_seconds - TAPE_PAUSE_SECONDS_BEFORE_DEATH)
+    if (tape.warp_forward)
+    {
+      if (tape.deactivate_display)
+       DrawVideoDisplay(VIDEO_STATE_WARP_ON, VIDEO_DISPLAY_SYMBOL_ONLY);
+      else
+       DrawVideoDisplay(VIDEO_STATE_WARP2_ON, VIDEO_DISPLAY_SYMBOL_ONLY);
+    }
+
+    if (TapeTime > tape.length_seconds - TAPE_PAUSE_SECONDS_BEFORE_DEATH)
     {
       TapeTogglePause(TAPE_TOGGLE_MANUAL);
       return NULL;
     }
   }
+  else if (tape.fast_forward)
+  {
+    if ((FrameCounter / 20) % 2)
+      DrawVideoDisplay(VIDEO_STATE_FFWD_ON, VIDEO_DISPLAY_LABEL_ONLY);
+    else
+      DrawVideoDisplay(VIDEO_STATE_FFWD_OFF, VIDEO_DISPLAY_LABEL_ONLY);
+
+    if (tape.warp_forward)
+    {
+      if (tape.deactivate_display)
+       DrawVideoDisplay(VIDEO_STATE_WARP_ON, VIDEO_DISPLAY_SYMBOL_ONLY);
+      else
+       DrawVideoDisplay(VIDEO_STATE_WARP2_ON, VIDEO_DISPLAY_SYMBOL_ONLY);
+    }
+  }
+#if 0
+  /* !!! this makes things much slower !!! */
+  else if (tape.warp_forward)
+  {
+    if ((FrameCounter / 20) % 2)
+      DrawVideoDisplay(VIDEO_STATE_WARP_ON, VIDEO_DISPLAY_LABEL_ONLY);
+    else
+      DrawVideoDisplay(VIDEO_STATE_WARP_OFF, VIDEO_DISPLAY_LABEL_ONLY);
+
+    DrawVideoDisplay(VIDEO_STATE_WARP_ON, VIDEO_DISPLAY_SYMBOL_ONLY);
+  }
+#endif
 
   if (tape.counter >= tape.length)     /* end of tape reached */
   {
-    if (tape.index_search && !tape.auto_play)
+    if (tape.warp_forward && !tape.auto_play)
       TapeTogglePause(TAPE_TOGGLE_MANUAL);
     else
       TapeStop();
@@ -581,15 +1016,27 @@ 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();
 
-  DrawVideoDisplay(VIDEO_STATE_PAUSE_OFF,0);
+  DrawVideoDisplay(VIDEO_STATE_OFF, 0);
+
   if (tape.date && tape.length)
   {
     DrawVideoDisplay(VIDEO_STATE_DATE_ON, tape.date);
@@ -616,28 +1063,61 @@ unsigned int GetTapeLength()
   return(tape_length * GAME_FRAME_DELAY / 1000);
 }
 
-static void TapeStartIndexSearch()
+static void TapeStartWarpForward()
 {
-  tape.index_search = TRUE;
+  tape.warp_forward = TRUE;
 
+#if 1
+  if (!tape.fast_forward && !tape.pause_before_death)
+  {
+    tape.pausing = FALSE;
+    tape.deactivate_display = TRUE;
+
+    TapeDeactivateDisplayOn();
+  }
+#else
   if (!tape.fast_forward || tape.pause_before_death)
   {
     tape.pausing = FALSE;
+    tape.deactivate_display = TRUE;
 
-    SetDrawDeactivationMask(REDRAW_FIELD);
-    audio.sound_deactivated = TRUE;
+    TapeDeactivateDisplayOn();
   }
+#endif
+
+  if (tape.fast_forward || tape.pause_before_death)
+    DrawVideoDisplay(VIDEO_STATE_WARP_ON, VIDEO_DISPLAY_SYMBOL_ONLY);
+  else
+    DrawVideoDisplay(VIDEO_STATE_WARP_ON, 0);
 }
 
-static void TapeStopIndexSearch()
+static void TapeStopWarpForward()
 {
-  tape.index_search = FALSE;
+  int state = (tape.pausing ? VIDEO_STATE_PAUSE_ON : VIDEO_STATE_PAUSE_OFF);
 
-  SetDrawDeactivationMask(REDRAW_NONE);
-  audio.sound_deactivated = FALSE;
+  tape.warp_forward = FALSE;
+  tape.deactivate_display = FALSE;
+
+  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
 
-  RedrawPlayfield(TRUE, 0,0,0,0);
-  DrawGameDoorValues();
+  if (tape.pause_before_death)
+    state |= VIDEO_STATE_WARP_OFF | VIDEO_STATE_PBEND_ON;
+  else if (tape.fast_forward)
+    state |= VIDEO_STATE_WARP_OFF | VIDEO_STATE_FFWD_ON;
+  else
+    state |= VIDEO_STATE_WARP_OFF | VIDEO_STATE_PLAY_ON;
+
+  DrawVideoDisplay(state, 0);
 }
 
 static void TapeSingleStep()
@@ -649,6 +1129,9 @@ static void TapeSingleStep()
     TapeTogglePause(TAPE_TOGGLE_MANUAL);
 
   tape.single_step = !tape.single_step;
+
+  DrawVideoDisplay((tape.single_step ? VIDEO_STATE_1STEP_ON :
+                   VIDEO_STATE_1STEP_OFF), 0);
 }
 
 void TapeQuickSave()
@@ -669,6 +1152,17 @@ void TapeQuickSave()
 
 void TapeQuickLoad()
 {
+  if (tape.recording && !Request("Stop recording and load tape ?",
+                                REQ_ASK | REQ_STAY_CLOSED))
+  {
+    BlitBitmap(bitmap_db_door, bitmap_db_door,
+              DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE,
+              DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
+    OpenDoor(DOOR_OPEN_1);
+
+    return;
+  }
+
   if (game_status == GAME_MODE_PLAYING || game_status == GAME_MODE_MAIN)
   {
     TapeStop();
@@ -678,7 +1172,7 @@ void TapeQuickLoad()
     if (!TAPE_IS_EMPTY(tape))
     {
       TapeStartGamePlaying();
-      TapeStartIndexSearch();
+      TapeStartWarpForward();
 
       tape.quick_resume = TRUE;
     }
@@ -775,14 +1269,18 @@ void AutoPlayTape()
     printf("Level %03d: ", level_nr);
 
     LoadLevel(level_nr);
-    if (level.no_level_file)
+    if (level.no_valid_file)
     {
       printf("(no level)\n");
       continue;
     }
 
     LoadSolutionTape(level_nr);
+#if 1
+    if (tape.no_valid_file)
+#else
     if (TAPE_IS_EMPTY(tape))
+#endif
     {
       printf("(no tape)\n");
       continue;
@@ -791,7 +1289,7 @@ void AutoPlayTape()
     printf("playing tape ... ");
 
     TapeStartGamePlaying();
-    TapeStartIndexSearch();
+    TapeStartWarpForward();
 
     return;
   }
@@ -806,6 +1304,7 @@ void AutoPlayTape()
   printf("LEVELDIR '%s', SOLVED %d/%d (%d%%)",
         autoplay_leveldir->identifier, num_levels_solved, num_levels_played,
         (num_levels_played ? num_levels_solved * 100 / num_levels_played :0));
+
   if (num_levels_played != num_levels_solved)
   {
     printf(", FAILED:");
@@ -813,6 +1312,7 @@ void AutoPlayTape()
       if (levels_failed[i])
        printf(" %03d", i);
   }
+
   printf("\n");
   printf_line("=", 79);
 
@@ -829,7 +1329,7 @@ void AutoPlayTape()
 #define TAPE_BUTTON_YPOS       77
 
 #define TAPE_BUTTON_EJECT_XPOS (TAPE_BUTTON_XPOS + 0 * TAPE_BUTTON_XSIZE)
-#define TAPE_BUTTON_INDEX_XPOS (TAPE_BUTTON_XPOS + 0 * TAPE_BUTTON_XSIZE)
+#define TAPE_BUTTON_EXTRA_XPOS (TAPE_BUTTON_XPOS + 0 * TAPE_BUTTON_XSIZE)
 #define TAPE_BUTTON_STOP_XPOS  (TAPE_BUTTON_XPOS + 1 * TAPE_BUTTON_XSIZE)
 #define TAPE_BUTTON_PAUSE_XPOS (TAPE_BUTTON_XPOS + 2 * TAPE_BUTTON_XSIZE)
 #define TAPE_BUTTON_RECORD_XPOS        (TAPE_BUTTON_XPOS + 3 * TAPE_BUTTON_XSIZE)
@@ -848,9 +1348,9 @@ static struct
     "eject tape"
   },
   {
-    TAPE_BUTTON_INDEX_XPOS,    TAPE_BUTTON_YPOS,
-    TAPE_CTRL_ID_INDEX,
-    "index mark"
+    TAPE_BUTTON_EXTRA_XPOS,    TAPE_BUTTON_YPOS,
+    TAPE_CTRL_ID_EXTRA,
+    "extra functions"
   },
   {
     TAPE_BUTTON_STOP_XPOS,     TAPE_BUTTON_YPOS,
@@ -892,7 +1392,7 @@ void CreateTapeButtons()
     gd_x2 = DOOR_GFX_PAGEX3 + gd_xoffset;
     gd_y  = DOOR_GFX_PAGEY2 + gd_yoffset;
 
-    if (i == TAPE_CTRL_ID_INDEX)
+    if (i == TAPE_CTRL_ID_EXTRA)
     {
       gd_x1 = DOOR_GFX_PAGEX6 + gd_xoffset;
       gd_x2 = DOOR_GFX_PAGEX5 + gd_xoffset;
@@ -929,14 +1429,14 @@ void FreeTapeButtons()
 
 void MapTapeEjectButton()
 {
-  UnmapGadget(tape_gadget[TAPE_CTRL_ID_INDEX]);
+  UnmapGadget(tape_gadget[TAPE_CTRL_ID_EXTRA]);
   MapGadget(tape_gadget[TAPE_CTRL_ID_EJECT]);
 }
 
-void MapTapeIndexButton()
+void MapTapeWarpButton()
 {
   UnmapGadget(tape_gadget[TAPE_CTRL_ID_EJECT]);
-  MapGadget(tape_gadget[TAPE_CTRL_ID_INDEX]);
+  MapGadget(tape_gadget[TAPE_CTRL_ID_EXTRA]);
 }
 
 void MapTapeButtons()
@@ -944,11 +1444,11 @@ void MapTapeButtons()
   int i;
 
   for (i = 0; i < NUM_TAPE_BUTTONS; i++)
-    if (i != TAPE_CTRL_ID_INDEX)
+    if (i != TAPE_CTRL_ID_EXTRA)
       MapGadget(tape_gadget[i]);
 
   if (tape.recording || tape.playing)
-    MapTapeIndexButton();
+    MapTapeWarpButton();
 }
 
 void UnmapTapeButtons()
@@ -985,9 +1485,27 @@ static void HandleTapeButtons(struct GadgetInfo *gi)
       DrawCompleteVideoDisplay();
       break;
 
-    case TAPE_CTRL_ID_INDEX:
+    case TAPE_CTRL_ID_EXTRA:
       if (tape.playing)
-       TapeStartIndexSearch();
+      {
+       if (!tape.warp_forward)                 /* PLAY -> WARP FORWARD PLAY */
+       {
+         TapeStartWarpForward();
+       }
+       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)
        TapeSingleStep();
       break;
@@ -1005,7 +1523,7 @@ static void HandleTapeButtons(struct GadgetInfo *gi)
        TapeStartGameRecording();
       else if (tape.pausing)
       {
-       if (tape.playing)       /* PLAYING -> PAUSING -> RECORDING */
+       if (tape.playing)                       /* PLAY -> PAUSE -> RECORD */
          TapeAppendRecording();
        else
          TapeTogglePause(TAPE_TOGGLE_MANUAL);
@@ -1034,13 +1552,28 @@ 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 03cc3d24812d87fd7037deffb81c5b5d4e7b9b42..4bddf23b6497305256d276882e0c380a7bbf587f 100644 (file)
 #define VIDEO_CONTROL_YSIZE    VIDEO_BUTTON_YSIZE
 
 /* values for video tape control */
-#define VIDEO_STATE_PLAY_OFF   (1L << 0)
-#define VIDEO_STATE_PLAY_ON    (1L << 1)
+#define VIDEO_STATE_PLAY_OFF   (1 << 0)
+#define VIDEO_STATE_PLAY_ON    (1 << 1)
 #define VIDEO_STATE_PLAY       (VIDEO_STATE_PLAY_OFF   | VIDEO_STATE_PLAY_ON)
-#define VIDEO_STATE_REC_OFF    (1L << 2)
-#define VIDEO_STATE_REC_ON     (1L << 3)
+#define VIDEO_STATE_REC_OFF    (1 << 2)
+#define VIDEO_STATE_REC_ON     (1 << 3)
 #define VIDEO_STATE_REC                (VIDEO_STATE_REC_OFF    | VIDEO_STATE_REC_ON)
-#define VIDEO_STATE_PAUSE_OFF  (1L << 4)
-#define VIDEO_STATE_PAUSE_ON   (1L << 5)
+#define VIDEO_STATE_PAUSE_OFF  (1 << 4)
+#define VIDEO_STATE_PAUSE_ON   (1 << 5)
 #define VIDEO_STATE_PAUSE      (VIDEO_STATE_PAUSE_OFF  | VIDEO_STATE_PAUSE_ON)
-#define VIDEO_STATE_DATE_OFF   (1L << 6)
-#define VIDEO_STATE_DATE_ON    (1L << 7)
+#define VIDEO_STATE_DATE_OFF   (1 << 6)
+#define VIDEO_STATE_DATE_ON    (1 << 7)
 #define VIDEO_STATE_DATE       (VIDEO_STATE_DATE_OFF   | VIDEO_STATE_DATE_ON)
-#define VIDEO_STATE_TIME_OFF   (1L << 8)
-#define VIDEO_STATE_TIME_ON    (1L << 9)
+#define VIDEO_STATE_TIME_OFF   (1 << 8)
+#define VIDEO_STATE_TIME_ON    (1 << 9)
 #define VIDEO_STATE_TIME       (VIDEO_STATE_TIME_OFF   | VIDEO_STATE_TIME_ON)
-#define VIDEO_PRESS_PLAY_ON    (1L << 10)
-#define VIDEO_PRESS_PLAY_OFF   (1L << 11)
+
+#define VIDEO_STATE_FFWD_OFF   (1 << 10)
+#define VIDEO_STATE_FFWD_ON    (1 << 11)
+#define VIDEO_STATE_FFWD       (VIDEO_STATE_FFWD_OFF   | VIDEO_STATE_FFWD_ON)
+#define VIDEO_STATE_PBEND_OFF  (1 << 12)
+#define VIDEO_STATE_PBEND_ON   (1 << 13)
+#define VIDEO_STATE_PBEND      (VIDEO_STATE_PBEND_OFF  | VIDEO_STATE_PBEND_ON)
+#define VIDEO_STATE_WARP_OFF   (1 << 14)
+#define VIDEO_STATE_WARP_ON    (1 << 15)
+#define VIDEO_STATE_WARP       (VIDEO_STATE_WARP_OFF   | VIDEO_STATE_WARP_ON)
+#define VIDEO_STATE_WARP2_OFF  (1 << 16)
+#define VIDEO_STATE_WARP2_ON   (1 << 17)
+#define VIDEO_STATE_WARP2      (VIDEO_STATE_WARP_OFF   | VIDEO_STATE_WARP_ON)
+#define VIDEO_STATE_1STEP_OFF  (1 << 18)
+#define VIDEO_STATE_1STEP_ON   (1 << 19)
+#define VIDEO_STATE_1STEP      (VIDEO_STATE_1STEP_OFF  | VIDEO_STATE_1STEP_ON)
+
+#define VIDEO_PRESS_PLAY_ON    (1 << 20)
+#define VIDEO_PRESS_PLAY_OFF   (1 << 21)
 #define VIDEO_PRESS_PLAY       (VIDEO_PRESS_PLAY_OFF   | VIDEO_PRESS_PLAY_ON)
-#define VIDEO_PRESS_REC_ON     (1L << 12)
-#define VIDEO_PRESS_REC_OFF    (1L << 13)
+#define VIDEO_PRESS_REC_ON     (1 << 22)
+#define VIDEO_PRESS_REC_OFF    (1 << 23)
 #define VIDEO_PRESS_REC                (VIDEO_PRESS_REC_OFF    | VIDEO_PRESS_REC_ON)
-#define VIDEO_PRESS_PAUSE_ON   (1L << 14)
-#define VIDEO_PRESS_PAUSE_OFF  (1L << 15)
+#define VIDEO_PRESS_PAUSE_ON   (1 << 24)
+#define VIDEO_PRESS_PAUSE_OFF  (1 << 25)
 #define VIDEO_PRESS_PAUSE      (VIDEO_PRESS_PAUSE_OFF  | VIDEO_PRESS_PAUSE_ON)
-#define VIDEO_PRESS_STOP_ON    (1L << 16)
-#define VIDEO_PRESS_STOP_OFF   (1L << 17)
+#define VIDEO_PRESS_STOP_ON    (1 << 26)
+#define VIDEO_PRESS_STOP_OFF   (1 << 27)
 #define VIDEO_PRESS_STOP       (VIDEO_PRESS_STOP_OFF   | VIDEO_PRESS_STOP_ON)
-#define VIDEO_PRESS_EJECT_ON   (1L << 18)
-#define VIDEO_PRESS_EJECT_OFF  (1L << 19)
+#define VIDEO_PRESS_EJECT_ON   (1 << 28)
+#define VIDEO_PRESS_EJECT_OFF  (1 << 29)
 #define VIDEO_PRESS_EJECT      (VIDEO_PRESS_EJECT_OFF  | VIDEO_PRESS_EJECT_ON)
 
-/* special */
-#define VIDEO_STATE_FFWD_OFF   ((1L << 20) | VIDEO_STATE_PAUSE_OFF)
-#define VIDEO_STATE_FFWD_ON    (1L << 21)
-#define VIDEO_STATE_FFWD       (VIDEO_STATE_FFWD_OFF   | VIDEO_STATE_FFWD_ON)
-#define VIDEO_STATE_PBEND_OFF  (1L << 22)
-#define VIDEO_STATE_PBEND_ON   (1L << 23)
-#define VIDEO_STATE_PBEND      (VIDEO_STATE_PBEND_OFF  | VIDEO_STATE_PBEND_ON)
-
 /* tags to draw video display labels or symbols only */
 /* (negative values to prevent misinterpretation in DrawVideoDisplay(), where
    the variable "value" is also used for tape length -- better fix this) */
@@ -86,6 +95,9 @@
 void DrawVideoDisplay(unsigned long, unsigned long);
 void DrawCompleteVideoDisplay(void);
 
+void TapeDeactivateDisplayOn();
+void TapeDeactivateDisplayOff(boolean);
+
 void TapeStartRecording(void);
 void TapeHaltRecording(void);
 void TapeStopRecording(void);
@@ -106,7 +118,7 @@ void AutoPlayTape(void);
 void CreateTapeButtons();
 void FreeTapeButtons();
 void MapTapeEjectButton();
-void MapTapeIndexButton();
+void MapTapeWarpButton();
 void MapTapeButtons();
 void UnmapTapeButtons();
 
index 6b8ae64696af23dee2a8be92a643ba4a6bae91e0..68bac2efc88e6a42384e0569bc558ae04d0238ba 100644 (file)
@@ -40,6 +40,57 @@ static int el_act2crm(int, int);
 static struct GadgetInfo *tool_gadget[NUM_TOOL_BUTTONS];
 static int request_gadget_id = -1;
 
+static char *print_if_not_empty(int element)
+{
+  static char *s = NULL;
+  char *token_name = element_info[element].token_name;
+
+  if (s != NULL)
+    free(s);
+
+  s = checked_malloc(strlen(token_name) + 10 + 1);
+
+  if (element != EL_EMPTY)
+    sprintf(s, "%d\t['%s']", element, token_name);
+  else
+    sprintf(s, "%d", element);
+
+  return s;
+}
+
+void DumpTile(int x, int y)
+{
+  int sx = SCREENX(x);
+  int sy = SCREENY(y);
+
+  printf_line("-", 79);
+  printf("Field Info: SCREEN(%d, %d), LEVEL(%d, %d)\n", sx, sy, x, y);
+  printf_line("-", 79);
+
+  if (!IN_LEV_FIELD(x, y))
+  {
+    printf("(not in level field)\n");
+    printf("\n");
+
+    return;
+  }
+
+  printf("  Feld:        %d\t['%s']\n", Feld[x][y],
+        element_info[Feld[x][y]].token_name);
+  printf("  Back:        %s\n", print_if_not_empty(Back[x][y]));
+  printf("  Store:       %s\n", print_if_not_empty(Store[x][y]));
+  printf("  Store2:      %s\n", print_if_not_empty(Store2[x][y]));
+  printf("  StorePlayer: %s\n", print_if_not_empty(StorePlayer[x][y]));
+  printf("  MovPos:      %d\n", MovPos[x][y]);
+  printf("  MovDir:      %d\n", MovDir[x][y]);
+  printf("  MovDelay:    %d\n", MovDelay[x][y]);
+  printf("  ChangeDelay: %d\n", ChangeDelay[x][y]);
+  printf("  GfxElement:  %d\n", GfxElement[x][y]);
+  printf("  GfxAction:   %d\n", GfxAction[x][y]);
+  printf("  GfxFrame:    %d\n", GfxFrame[x][y]);
+  printf("\n");
+}
+
 void SetDrawtoField(int mode)
 {
   if (mode == DRAW_BUFFERED && setup.soft_scrolling)
@@ -223,28 +274,33 @@ void BackToFront()
   {
     if (redraw_mask & REDRAW_DOOR_1)
       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)
-       BlitBitmap(backbuffer, window, VX,VY, VXSIZE,VYSIZE, VX,VY);
+#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);
+                    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);
+                    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);
+                    VX + VIDEO_CONTROL_XPOS, VY + VIDEO_CONTROL_YPOS,
+                    VIDEO_CONTROL_XSIZE, VIDEO_CONTROL_YSIZE,
+                    VX + VIDEO_CONTROL_XPOS, VY + VIDEO_CONTROL_YPOS);
       }
+#endif
     }
 
     if (redraw_mask & REDRAW_DOOR_3)
@@ -264,10 +320,10 @@ void BackToFront()
   if (redraw_mask & REDRAW_TILES)
   {
     for (x = 0; x < SCR_FIELDX; x++)
-      for (y =0 ; y < SCR_FIELDY; y++)
+      for (y = 0 ; y < SCR_FIELDY; y++)
        if (redraw[redraw_x1 + x][redraw_y1 + y])
          BlitBitmap(buffer, window,
-                    FX + x * TILEX, FX + y * TILEY, TILEX, TILEY,
+                    FX + x * TILEX, FY + y * TILEY, TILEX, TILEY,
                     SX + x * TILEX, SY + y * TILEY);
   }
 
@@ -633,6 +689,7 @@ void DrawPlayer(struct PlayerInfo *player)
            player->is_collecting ? ACTION_COLLECTING      :
            player->is_moving     ? ACTION_MOVING          :
            player->is_snapping   ? ACTION_SNAPPING        :
+           player->is_dropping   ? ACTION_DROPPING        :
            player->is_waiting    ? player->action_waiting : ACTION_DEFAULT);
 
   InitPlayerGfxAnimation(player, action, move_dir);
@@ -833,17 +890,41 @@ void DrawPlayer(struct PlayerInfo *player)
   /* draw elements the player is just walking/passing through/under          */
   /* ----------------------------------------------------------------------- */
 
-  /* handle the field the player is leaving ... */
-  if (player_is_moving && IS_ACCESSIBLE_INSIDE(last_element))
-    DrawLevelField(last_jx, last_jy);
-  else if (player_is_moving && IS_ACCESSIBLE_UNDER(last_element))
-    DrawLevelFieldThruMask(last_jx, last_jy);
+  if (player_is_moving)
+  {
+    /* handle the field the player is leaving ... */
+    if (IS_ACCESSIBLE_INSIDE(last_element))
+      DrawLevelField(last_jx, last_jy);
+    else if (IS_ACCESSIBLE_UNDER(last_element))
+      DrawLevelFieldThruMask(last_jx, last_jy);
+  }
 
-  /* ... and the field the player is entering */
-  if (IS_ACCESSIBLE_INSIDE(element))
-    DrawLevelField(jx, jy);
-  else if (IS_ACCESSIBLE_UNDER(element))
-    DrawLevelFieldThruMask(jx, jy);
+#if 1
+  /* do not redraw accessible elements if the player is just pushing them */
+  if (!player_is_moving || !player->is_pushing)
+  {
+    /* ... and the field the player is entering */
+    if (IS_ACCESSIBLE_INSIDE(element))
+      DrawLevelField(jx, jy);
+    else if (IS_ACCESSIBLE_UNDER(element))
+      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)
   {
@@ -857,7 +938,7 @@ void DrawPlayer(struct PlayerInfo *player)
     SetDrawtoField(DRAW_DIRECT);
   }
 
-  MarkTileDirty(sx,sy);
+  MarkTileDirty(sx, sy);
 }
 
 void getGraphicSource(int graphic, int frame, Bitmap **bitmap, int *x, int *y)
@@ -981,7 +1062,7 @@ void DrawMiniGraphicExt(DrawBuffer *d, int x, int y, int graphic)
   BlitBitmap(src_bitmap, d, src_x, src_y, MINI_TILEX, MINI_TILEY, x, y);
 }
 
-void DrawGraphicShifted(int x,int y, int dx,int dy, int graphic, int frame,
+void DrawGraphicShifted(int x, int y, int dx, int dy, int graphic, int frame,
                        int cut_mode, int mask_mode)
 {
   Bitmap *src_bitmap;
@@ -1101,13 +1182,13 @@ void DrawGraphicShifted(int x,int y, int dx,int dy, int graphic, int frame,
     BlitBitmap(src_bitmap, drawto_field, src_x, src_y, width, height,
               dest_x, dest_y);
 
-  MarkTileDirty(x,y);
+  MarkTileDirty(x, y);
 }
 
 void DrawGraphicShiftedThruMask(int x, int y, int dx, int dy, int graphic,
                                int frame, int cut_mode)
 {
-  DrawGraphicShifted(x,y, dx,dy, graphic, frame, cut_mode, USE_MASKING);
+  DrawGraphicShifted(x, y, dx, dy, graphic, frame, cut_mode, USE_MASKING);
 }
 
 void DrawScreenElementExt(int x, int y, int dx, int dy, int element,
@@ -1191,6 +1272,10 @@ 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;
@@ -1220,8 +1305,7 @@ static void DrawLevelFieldCrumbledSandExt(int x, int y, int graphic, int frame)
   if (!IN_LEV_FIELD(x, y))
     return;
 
-  element = (GfxElement[x][y] != EL_UNDEFINED && Feld[x][y] != EL_EXPLOSION ?
-            GfxElement[x][y] : Feld[x][y]);
+  element = TILE_GFX_ELEMENT(x, y);
 
   /* crumble field itself */
   if (GFX_CRUMBLED(element) && !IS_MOVING(x, y))
@@ -1236,7 +1320,12 @@ 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))
@@ -1283,11 +1372,23 @@ static void DrawLevelFieldCrumbledSandExt(int x, int y, int graphic, int frame)
       int sxx = sx + xy[i][0];
       int syy = sy + xy[i][1];
 
+#if 1
+      if (!IN_LEV_FIELD(xx, yy) ||
+         !IN_SCR_FIELD(sxx, syy) ||
+         IS_MOVING(xx, yy))
+       continue;
+
+      element = TILE_GFX_ELEMENT(xx, yy);
+
+      if (!GFX_CRUMBLED(element))
+       continue;
+#else
       if (!IN_LEV_FIELD(xx, yy) ||
          !IN_SCR_FIELD(sxx, syy) ||
          !GFX_CRUMBLED(Feld[xx][yy]) ||
          IS_MOVING(xx, yy))
        continue;
+#endif
 
 #if 1
       graphic = el_act2crm(Feld[xx][yy], ACTION_DEFAULT);
@@ -1464,7 +1565,13 @@ void DrawScreenField(int x, int y)
       DrawScreenElementShifted(x, y, 0, MovPos[lx][ly], content, cut_mode);
 
     if (content == EL_ACID)
-      DrawLevelElementThruMask(lx, ly + 1, EL_ACID);
+    {
+      int dir = MovDir[lx][ly];
+      int newlx = lx + (dir == MV_LEFT ? -1 : dir == MV_RIGHT ? +1 : 0);
+      int newly = ly + (dir == MV_UP   ? -1 : dir == MV_DOWN  ? +1 : 0);
+
+      DrawLevelElementThruMask(newlx, newly, EL_ACID);
+    }
   }
   else if (IS_BLOCKED(lx, ly))
   {
@@ -1595,11 +1702,18 @@ 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;
-  int anim_delay_value = (ffwd_delay ? FfwdFrameDelay : GameFrameDelay);
+  int frame_delay_value = (ffwd_delay ? FfwdFrameDelay : GameFrameDelay);
+  int anim_delay_value = (no_delay ? 0 : frame_delay_value);
   int font_nr = FONT_ENVELOPE_1 + envelope_nr;
   int font_width = getFontWidth(font_nr);
   int font_height = getFontHeight(font_nr);
@@ -1648,7 +1762,9 @@ void ShowEnvelope(int envelope_nr)
   int sound_opening = element_info[element].sound[ACTION_OPENING];
   int sound_closing = element_info[element].sound[ACTION_CLOSING];
   boolean ffwd_delay = (tape.playing && tape.fast_forward);
-  int wait_delay_value = (ffwd_delay ? 500 : 1000);
+  boolean no_delay = (tape.warp_forward);
+  int normal_delay_value = ONE_SECOND_DELAY / (ffwd_delay ? 2 : 1);
+  int wait_delay_value = (no_delay ? 0 : normal_delay_value);
   int anim_mode = graphic_info[graphic].anim_mode;
   int main_anim_mode = (anim_mode == ANIM_NONE ? ANIM_VERTICAL|ANIM_HORIZONTAL:
                        anim_mode == ANIM_DEFAULT ? ANIM_VERTICAL : anim_mode);
@@ -1986,11 +2102,17 @@ boolean Request(char *text, unsigned int req_state)
     }
   }
 
+#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(PLATFORM_UNIX)
+#if defined(NETWORK_AVALIABLE)
   /* pause network game while waiting for request to answer */
   if (options.network &&
       game_status == GAME_MODE_PLAYING &&
@@ -2231,8 +2353,8 @@ boolean Request(char *text, unsigned int req_state)
     if (!(req_state & REQ_STAY_CLOSED) && (old_door_state & DOOR_OPEN_1))
     {
       BlitBitmap(bitmap_db_door, bitmap_db_door,
-                DOOR_GFX_PAGEX2,DOOR_GFX_PAGEY1, DXSIZE,DYSIZE,
-                DOOR_GFX_PAGEX1,DOOR_GFX_PAGEY1);
+                DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE,
+                DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
       OpenDoor(DOOR_OPEN_1);
     }
   }
@@ -2241,7 +2363,7 @@ boolean Request(char *text, unsigned int req_state)
 
   SetDrawBackgroundMask(REDRAW_FIELD);
 
-#if defined(PLATFORM_UNIX)
+#if defined(NETWORK_AVALIABLE)
   /* continue network game after request */
   if (options.network &&
       game_status == GAME_MODE_PLAYING &&
@@ -2249,6 +2371,12 @@ 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;
 }
 
@@ -2331,8 +2459,10 @@ 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)
@@ -2350,7 +2480,7 @@ unsigned int MoveDoor(unsigned int door_state)
               door_1.anim_mode == ANIM_VERTICAL ? DYSIZE : DXSIZE);
     int x;
 
-    if (!(door_state & DOOR_NO_DELAY))
+    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))
@@ -2533,11 +2663,13 @@ unsigned int MoveDoor(unsigned int door_state)
     }
   }
 
+#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;
@@ -2770,7 +2902,7 @@ int get_next_element(int element)
 int el_act_dir2img(int element, int action, int direction)
 {
   element = GFX_ELEMENT(element);
-  direction = MV_DIR_BIT(direction);
+  direction = MV_DIR_BIT(direction);   /* default: MV_NO_MOVING => MV_DOWN */
 
   return element_info[element].direction_graphic[action][direction];
 }
@@ -2778,7 +2910,7 @@ int el_act_dir2img(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);
+  direction = MV_DIR_BIT(direction);   /* default: MV_NO_MOVING => MV_DOWN */
 
   return element_info[element].direction_crumbled[action][direction];
 }
@@ -2804,6 +2936,11 @@ int el_dir2img(int element, int direction)
   return el_act_dir2img(element, ACTION_DEFAULT, direction);
 }
 
+int el2baseimg(int element)
+{
+  return element_info[element].graphic[ACTION_DEFAULT];
+}
+
 int el2img(int element)
 {
   element = GFX_ELEMENT(element);
index f226a9cfd09a40ae8e2a1c83e1104d0a8728bb15..022473a95dba8be9b015f17b144c55867e8071ed 100644 (file)
@@ -58,6 +58,8 @@
 
 #define REQUEST_WAIT_FOR       (REQ_ASK | REQ_CONFIRM | REQ_PLAYER)
 
+void DumpTile(int, int);
+
 void SetDrawtoField(int);
 void RedrawPlayfield(boolean, int, int, int, int);
 void BackToFront();
@@ -139,6 +141,7 @@ int get_next_element(int);
 int el_act_dir2img(int, int, int);
 int el_act2img(int, int);
 int el_dir2img(int, int);
+int el2baseimg(int);
 int el2img(int);
 int el2edimg(int);
 int el2preimg(int);