rocks_n_diamonds-0.9 0.9
authorHolger Schemel <info@artsoft.org>
Sun, 22 Oct 1995 19:13:31 +0000 (20:13 +0100)
committerHolger Schemel <info@artsoft.org>
Sat, 30 Aug 2014 08:30:13 +0000 (10:30 +0200)
28 files changed:
CHANGES [new file with mode: 0644]
COPYRIGHT [new file with mode: 0644]
DISCLAIMER [new file with mode: 0644]
INSTALLATION [new file with mode: 0644]
README [new file with mode: 0644]
RECOMMENDATIONS [new file with mode: 0644]
REGISTRATION [new file with mode: 0644]
src/Makefile [new file with mode: 0644]
src/editor.c [new file with mode: 0644]
src/editor.h [new file with mode: 0644]
src/events.c [new file with mode: 0644]
src/events.h [new file with mode: 0644]
src/game.c [new file with mode: 0644]
src/game.h [new file with mode: 0644]
src/images.c [new file with mode: 0644]
src/images.h [new file with mode: 0644]
src/init.c [new file with mode: 0644]
src/init.h [new file with mode: 0644]
src/main.c [new file with mode: 0644]
src/main.h [new file with mode: 0644]
src/misc.c [new file with mode: 0644]
src/misc.h [new file with mode: 0644]
src/screens.c [new file with mode: 0644]
src/screens.h [new file with mode: 0644]
src/sound.c [new file with mode: 0644]
src/sound.h [new file with mode: 0644]
src/tools.c [new file with mode: 0644]
src/tools.h [new file with mode: 0644]

diff --git a/CHANGES b/CHANGES
new file mode 100644 (file)
index 0000000..0dafe5d
--- /dev/null
+++ b/CHANGES
@@ -0,0 +1,4 @@
+
+Prerelease Version 0.9 [23 OCT 95]
+----------------------------------
+       - first (pre)release version
diff --git a/COPYRIGHT b/COPYRIGHT
new file mode 100644 (file)
index 0000000..b2b7fc7
--- /dev/null
+++ b/COPYRIGHT
@@ -0,0 +1,25 @@
+This program is copyrighted (c) 1995 by Holger Schemel.
+
+It is freely distributable as long as no profit is made with it
+and as long as the package is left complete and unmodified.
+
+The fact that this program comes with full source does not mean
+that you can do what you want with it - it is only intended to
+give you the chance to build it on your own machine.
+
+If you want to distribute this program on CDROM, you have to ask for
+permission first -- just send me E-Mail and tell me what kind of
+CDROM it is. Normally I will give my permission if
+ - the CDROM itself contains only freely distributable software
+ - the author of this program (me!) gets a free copy of the CDROM
+ - the program is distributed in its original, unmodified package
+
+If the three conditions above are fulfilled, this permission will
+automatically given to the following CDROM distributions:
+ - InfoMagic "LINUX Developer's Resource"
+ - The Debian Linux Distribution CDROM
+ - any CDROM with a mirror of sunsite.unc.edu or a mirror of another
+   FTP server that contains this program
+
+If you are in doubt (e.g., want to distribute a pre-installed version),
+feel free to mail me about it (see the file 'README' in this archive).
diff --git a/DISCLAIMER b/DISCLAIMER
new file mode 100644 (file)
index 0000000..b6e06a6
--- /dev/null
@@ -0,0 +1,5 @@
+
+THIS GAME IS PROVIDED "AS IS" -- USE IT AT YOUR OWN RISK!
+IF THIS GAME BLOWS UP YOUR COMPUTER OR OPERATING SYSTEM
+OR ANYTHING ELSE, IT'S NOT MY FAULT! I'M NOT RESPONSIBLE
+FOR ANY DAMAGE THAT MIGHT BE CAUSED BY MY PROGRAM!
diff --git a/INSTALLATION b/INSTALLATION
new file mode 100644 (file)
index 0000000..298ff6d
--- /dev/null
@@ -0,0 +1,68 @@
+
+WHAT TO DO TO INSTALL "ROCKS_N_DIAMONDS-0.9" ON YOUR SYSTEM
+===========================================================
+
+If you have a Linux system (Intel based, a.out, kernel 1.2.x), you
+can use the precompiled binary.
+
+If you have another Unix system, or an ELF system or just want to
+compile the program by yourself, do the following:
+
+Edit the file "Makefile" and set the following options:
+
+XPM_INCLUDE_FILE       -       change this to the location where you
+                               have your XPM-Library include file.
+
+                               You must have the XPM-Library "libXpm"
+                               installed on your system to run this game.
+                               If you don't have it, look at your local
+                               FTP site with X11 archive to get it! :)
+
+GAME_DIR               -       You can leave these values untouched
+                               if you use the default location for
+                               the game directory.
+                               If you want to move it to other places in
+                               your directory tree, just change them
+                               accordingly. (You can use symlinks instead,
+                               of course.)
+                               You might want to set GAME_DIR to the full
+                               path of the game in your file system, so
+                               you don't have to go to the game directory
+                               when you want to play it.
+
+SOUNDS                 -       If you never want to hear any sounds,
+                               set this to "-DNO_SOUNDS", but be warned:
+                               It's much less fun playing without sound! :)
+                               (The program detects by itself if it can
+                               play sounds or not, anyway.)
+
+SCORE_ENTRIES          -       Set this to "-DONE_PER_NAME" if you want
+                               to allow only one entry per player in the
+                               score file for each level. This is useful
+                               if there are many players to prevent one
+                               single player to "flood" the Hall Of Fame
+                               of every level completely with his name...
+                               On single user systems, "-DMANY_PER_NAME"
+                               might be useful to have your name more
+                               than once in the list.
+
+SYSTEM                 -       If you have problems with the default
+                               settings, it might be useful to uncomment
+                               one of the defines for "SYSTEM" in the
+                               Makefile, which defines values like
+                               "-DSYSV" and something like that.
+
+CC, INCL, LIBS         -       Set these ones to the appropriate values
+                               you usually use on your system to compile.
+
+
+Now you can 'make clean' and 'make' and the game binary should be
+compiled right out of the box. I have tested it with "-Wall" on my
+system, so I hope that it compiles fine on other systems, too.
+
+The program should compile and run on Linux (of course),
+HP-UX, AIX, Net-BSD, SUN and IRIX.
+
+Have fun!
+
+Holger Schemel, 22. Oktober 1995
diff --git a/README b/README
new file mode 100644 (file)
index 0000000..e8933d0
--- /dev/null
+++ b/README
@@ -0,0 +1,263 @@
+Welcome to
+
+   R O C K S   ' N '   D I A M O N D S
+   -----------------------------------
+
+A game for Unix/X11 by Holger Schemel, (c) 1995 by Holger Schemel.
+
+Introduction
+============
+This is a nice little game with color graphics and sound for your
+Unix system with color X11. You need an 8-Bit color display or better.
+It is not recommended on black&white systems, and maybe not on gray
+scale systems.
+
+If you know the game "Boulderdash" (Commodore C64) or "Emerald Mine"
+(Amiga), you know what "ROCKS'N'DIAMONDS" is about.
+
+
+Getting started
+===============
+Just 'cd' to the 'rocks_n_diamonds' directory and type 'rocksndiamonds'!
+This works only on Linux boxes, because the included binary was
+compiled for Linux systems. If you have another Unix system like
+HPUX, NetBSD or SUN, you first have to type 'make' to compile it.
+This may be needed on Linux systems, too, if you have an older
+system (kernel, libraries, ...) or if you have only ELF libraries.
+
+(The included binary was compiled on the following system:
+Kernel 1.2.13, libc 4.5.26, GCC 2.5.8, 'a.out' format)
+
+The Menues
+==========
+You can see eight blue circles on the left side of the eight green menu
+texts; these are buttons to activate the menu commands by simply clicking
+on them with the left mouse button. The button will then change to red.
+(You can control the menues over the keyboard or joystick, too. Just use
+the arrow keys and the 'Return' or 'Enter' key or, if you use a joystick,
+the appropriate direction and the fire button.)
+
+The menu 'name'
+---------------
+When you start the game the first time, your login name will appear in
+the 'NAME:' field. If you want to use a different name for playing, for
+example a funny player name or a name for cheating, you can click on the
+button and enter a new name.
+
+If you choose a certain special name, you will be in a cheat mode where
+you can choose all levels without playing the lower levels before... :)
+
+The menue 'level'
+-----------------
+If you have played some levels of this game, you can choose the already
+played levels at any time, but you cannot choose the higher levels. This
+means, you can choose levels from level 0 to the highest level that you
+have ever won. This is known as your 'handicap'.
+
+If the level number is red, you have choosen a 'ready' level, if it is
+yellow, you have choosen a 'user' level, which is blank and can be
+edited by yourself with the built-in level editor (see below).
+
+To choose new level series, click on the button on the left and choose
+the new level serie.
+
+Hall of fame
+------------
+Click on this button to see a list of the best players of this level.
+Click again to go back to the main menu.
+
+Level creator
+-------------
+This brings you to the level editor, if you have switched to a 'yellow'
+level, which are empty and can be filled by yourself. See below.
+
+Info screen
+-----------
+This screen shows you all elements which appear in the game and presents
+you the background music loops which you can listen to while playing the
+levels (only available on Linux systems).
+
+Start game
+----------
+This will start the game.
+
+Setup
+-----
+To change some things in the game, use the setup menu.
+You can enable/disable "Sound" (enables/disables _all_ sounds in
+the game), "Sound loops" (only allowed on Linux systems with
+VoxWare[tm] sound driver; don't worry if you never heard of it --
+it's the name of the standard Linux sound driver), "Game music"
+(can always be enabled on very fast systems [exception: you don't
+like it], on slower systems it will take some percent of CPU time
+which will slow things down a bit) and "Toons", which will forbid/
+permit the little animated toons.
+
+"Buffered Gfx" can be set to "off" on slower systems, "Fading" gives
+a nice fading effect when displaying new screens, but unfortunately
+I haven't found a system which is fast enough to display it so far.
+(Maybe this works better on highly accelerated X servers.) Better set
+this to "off" if you have a normal system...
+
+Set "auto-record" to "on" if you want to automatically record each game
+to tape.
+
+If you have a Linux system with a joystick, you can choose the "1st" or
+the "2nd" joystick port and use "Cal. Joystick" to calibrate it. Use
+"Save and exit" after calibration to save it for later playing sessions.
+
+"Exit" quits the setup menu without saving the changes, "Save and exit"
+will save and then return to the main menu.
+
+Quit
+----
+Exit the game.
+
+
+How To Play The Game
+====================
+When the game has started, you can see the playfield on the left side
+and a control field on the right side. The control field contains the
+following elements:
+
+Level indicator                Tells you which level you are playing.
+
+Emeralds               Shows you how many emeralds you still need
+                       to win the current level.
+
+Dynamite               Shows you how many dynamite bombs you have.
+
+Keys                   Shows you which keys you have in your inventory.
+
+Score                  Shows the current score. In some levels there
+                       are some extra items giving extra score points.
+
+Time                   The seconds you have still left to play the level.
+
+Stop/Pause/Play                Game controls to stop the game, pause it and go on
+                       playing. If the tape recorder is recording your
+                       game, it is stopping/pausing/playing as well.
+
+Music buttons          The three music buttons can be used to control the
+                       background music loop, the 'looping' sounds and
+                       all other sounds. The little red light shows you
+                       if it is enabled or disabled. On slower systems
+                       (and a 486DX33 with Soundblaster _is_ a slower
+                       system) it increases the game speed to turn off
+                       background music. You can completely turn off all
+                       sound effects in the setup menu, although it is
+                       much more fun to have them enabled when it
+                       doesn't eats up to much speed.
+
+                       (A little note: The sound server currently needs
+                       about 10% CPU time on my 486DX/33/SBPro system
+                       when playing background music. I wonder if this
+                       would get better with a better soundcard, like
+                       Gravis Ultrasound, or if only pure CPU power
+                       helps in this case...)
+
+About the game itself: Of course you know Boulderdash, so you will know
+how to play the game. :)
+If not: You can move your playing figure (the smiley) with the arrow
+keys or with the joystick (if you have no joystick and even no arrow
+keys on your keyboard, you can use the keys 'i', 'j', 'k' and 'm' for
+the directions. To 'snap' a field near you without moving to it, you
+can use the left fire button on your joystick (hold it down, move the
+stick to 'snap' the field, release the button) or the keys 'e', 's',
+'d' and 'x'. To place a piece of dynamite, use the right fire button
+on your joystick or use the 'b' key (and, after placing the dynamite,
+better see to move away from this field...).
+
+Just try the levels from the 'tutorial' level serie to see what most
+of the elements do or have a look at the info screen!
+
+Note: It is *highly recommended* to use a joystick for playing this
+game! It is possible to play it with the keyboard, but it is *much
+more fun* to play with a joystick, and some levels are very difficult
+to solve with the keyboard. So, the best platform for this game is a
+Linux system (which gives you background music, too).
+
+The Level Editor
+================
+To build your own levels, just choose a 'yellow', empty level. If you
+cannot find any 'yellow' levels, choose a different level serie or
+choose the higher level numbers (if you have a small 'handicap' number,
+the higher levels will be skipped to reach the 'empty' levels.
+
+Another way is to create your own level series. Just add a line to the
+file 'levels/ROCKS.levelinfo' with the following entries:
+- the name of the level directory (create this directory under 'levels')
+- the name of the level serie (don't use any whitespaces within the name)
+- the 'ready' (red) levels (start with zero)
+- the 'empty' (yellow) levels (set this to some number of blank levels)
+
+To edit a level, you can use all three mouse buttons to draw in the
+level window. Click into the elements field with one of the three buttons
+to remap it to the new element. Use the arrow widgets to scroll around in
+the level. Use the 'flood fill' field to init exactly ony flood fill
+operation in the level field (you will be prompted). Click on 'control
+window' to switch to the control window.
+
+In the control window you can modify different parameters like the size
+of the level playfield, the name of the level, the scores for different
+elements and something like that. The four 3x3 field on the upper left
+can be edited like the level field and indicate the 'contents' of smashed
+crunchers (just try it out with some crunchers in one of your own levels).
+
+'Undo & Exit' leaves the level editor, throwing away all the changes you
+have done to the level.
+'Save & Exit' leveas the level editor and saves the new level (the old one
+will be deleted).
+
+
+The Tape Recorder
+=================
+You can use the tape recorder to record games and play tapes of previously
+played games. Just use them like a normal video recorder.
+
+Recording a game on tape:
+-------------------------
+Just press the 'record' button (the one with the red point on it) and
+either press 'Start Game' or press on 'record' or 'pause' to end the
+pause mode and start playing and recording.
+
+If you have set "auto record" in the setup menu to "on", you just have
+to press 'Start Game' as usual.
+
+Saving a game tape:
+-------------------
+To save a tape to the tape file corresponding to the level (that means
+that you can only save one tape file for each level), just press the
+'eject' button (the very left button). Then you will be prompted if
+you really want to replace the old tape (if an old tape exists).
+
+Playing a tape:
+---------------
+Just press 'play' and then either 'play' or 'pause'.
+
+While recording or playing, you can press 'pause' to stop the recording
+or the playing of the tape and continue by pressing 'pause' again.
+You can use either the tape recorder buttons or the game control buttons
+for this purpose.
+
+
+And Now Have Fun!
+=================
+Have fun playing the game, building new levels and breaking all high
+scores! ;)
+
+If you have any comments, problems, suggestions, donations, flames,
+send them to
+
+       aeglos@valinor.owl.de
+or     aeglos@uni-paderborn.de
+
+or Snail Mail
+
+       Holger Schemel
+       Sennehof 28
+       33659 Bielefeld
+       GERMANY
+
+Have fun,
+               Holger
diff --git a/RECOMMENDATIONS b/RECOMMENDATIONS
new file mode 100644 (file)
index 0000000..a08795b
--- /dev/null
@@ -0,0 +1,89 @@
+
+Some recommendations for more fun playing Rocks'n'Diamonds:
+===========================================================
+
+About sound
+-----------
+It is highly recommended to have a decent sound interface for playing
+this game (although it only comes with bad-quality 8000-Hz-samples to
+save memory and to be compatible with /dev/audio).
+
+The best sound platform is an actual Linux system with (at least) kernel
+1.2.x, because it offers some nice real-time sound features which are
+needed to have background music loops in the game.
+
+On all other systems you don't have music loops, but you still have all
+the other sounds.
+
+
+About game speed
+----------------
+You should have a relatively fast hardware.
+
+The game was developed on a i486/33 (which is three years old now),
+and you should probably better not try to run it on a slower system.
+
+You should have an accelerated graphic card; I have found out that it
+starts being playable on my 486/33 with an old ISA cirrus logic 5426
+graphic card, which has a blitter that is supported by XFree86[tm],
+but that it was nearly unplayable on a 486/66 with old, unaccelerated
+ET4000.
+
+If all works fine, you should have something around 30 frames per second.
+
+If you think that the game is to slow to play, you should try out the
+following things:
+
+- Set "Buffered Gfx" to "off" in the setup menu. Normally (on a fast
+  enough system) you should use buffered graphics, which means that
+  all graphics is drawn into an invisible Pixmap and is then copied
+  to the X11 window to avoid flickering. If you disable this double
+  buffering, the graphic is directly drawn into the window. This can
+  cause some slight flickering, but makes graphic operations roughly
+  twice as fast compared to double buffering.
+
+- Set "Game Music" to "off" in the setup menu (and maybe "sound loops"
+  too). Where disabling buffered graphics may be required with slow
+  graphics hardware, disabling sound is especially recommended on slow
+  CPU systems (486/33 and slower), because the sound server eats up a
+  significant amount of CPU time when playing long sounds.
+
+You might also notice that bigger levels tend to be slower on slow
+systems.
+
+About the option "Fading" in the setup menu: It gives a nice looking
+fading when switching to a new screen, but you should really only try
+this out if you think that you have a very fast graphics hardware.
+
+
+About music
+-----------
+The background music loops are ripped out from several nice music albums.
+Just have a look at the info screen to find out from which album each
+sound loop came from -- they are all very well done pieces of music, but
+unfortunately they don't sound better after converting them to 8 kHz
+samples (to conform to standard SUN /dev/audio). Maybe I change this to
+a better quality in the future, but at the moment, where the sounds
+directory has a size of nearly a megabyte, I'll stay with 8 kHz samples.
+
+So, if you have a non-Linux system (which cannot play sound loops) or
+don't like the "telephone quality" of the music loops, just get some of
+these CDs and play them while your playing the game! ;-)
+
+
+About game-play
+---------------
+It is *strongly recommended* to play this game with a high-quality joystick.
+That means, throw your $10 joystick out of the window and buy a decent
+Competition-Pro Digital PC joystick or a high-quality CH Products Analog
+joystick. Believe me, it doubles the fun of playing the game.
+
+If you only have a normal Unix system (and no fine Linux system), you
+are forced to play with the keyboard. It works, but is not only less fun,
+but also more difficult with some levels, because you cannot move in
+diagonal directions with keyboard control at the moment. Another bad thing
+is that you will have some problems when pressing many keys at the same
+time. This might change in the future, when I implement a better keyboard
+handling which not only solves these problems but allows diagonal directions,
+too.
+
diff --git a/REGISTRATION b/REGISTRATION
new file mode 100644 (file)
index 0000000..00233a6
--- /dev/null
@@ -0,0 +1,65 @@
+
+How to (and why) become a registered user of Rocks'n'Diamonds
+=============================================================
+
+It was much fun writing this game, and I hope that it is much fun playing
+it, too.
+
+Writing it was much work, too, and if you like this game, please think about
+becoming a registered user. Registered users will get a keyfile which allows
+them to use registered-users-only level series, starting with 50 new levels
+when version 1.0 come out (around December '95 or January '96). If you own
+the Amiga game "Emerald Mine", you can use its levels with the registered
+version of Rocks'n'Diamonds, too.
+
+There are some other plans for future versions of Rocks'n'Diamonds which
+will be only available for registered users, like support for more than
+one player on one machine, multi-player support for games over a network
+or Dyna-Blaster like levels (especially for multi player modes).
+
+If you want to become a registered user, send $20 or DM 20 to the
+following Snail-Mail address:
+
+       Holger Schemel
+       Sennehof 28
+       33659 Bielefeld
+       GERMANY
+
+... and send the filled-out registration form (at the end of this file)
+to the following E-Mail address:
+
+       aeglos@valinor.owl.de
+
+If you live outside Europe, you can use an international money order
+or just send a banknote, if you live in Europe, you can send an Euro-
+Cheque or remit the registration fee directly to my bank account in
+Germany (please write a short e-mail note and I'll send you the bank
+account information).
+
+You will then get a patch to change the program to a registered version
+(together with each main release version, if needed), a keyfile to use
+the registered-users-only level series and a little program to convert
+old "Emerald Mine" levels to Rocks'n'Diamonds levels.
+
+---------- 8< ---------- cut here ---------- 8< ----------
+
+Name:
+----------------------------------------------------------
+Street:
+----------------------------------------------------------
+City:
+----------------------------------------------------------
+Country:
+----------------------------------------------------------
+E-Mail:
+----------------------------------------------------------
+Username:
+----------------------------------------------------------
+
+(All informations will only be used to create a personalized
+keyfile. The game will work for the user in "Username", the
+fields "Name" to "Country" will appear in the info screen
+and your e-mail address will be used to inform you of new
+main release versions of Rocks'n'Diamonds.)
+
+---------- 8< ---------- cut here ---------- 8< ----------
diff --git a/src/Makefile b/src/Makefile
new file mode 100644 (file)
index 0000000..fffe019
--- /dev/null
@@ -0,0 +1,56 @@
+#
+# Makefile fuer "Rocks'n'Diamonds -- McDuffin Strikes Back"
+#
+
+PROGNAME = rocksndiamonds
+
+RM = rm -f
+CC = gcc
+# CC = cc                              # for HP-UX and others
+
+GAME_DIR = -DGAME_DIR=\".\"            # path of the game and its data
+# JOYSTICK = -DNO_JOYSTICK             # no joystick
+# SOUNDS = -DNO_SOUNDS                 # no sounds
+# SCORE_ENTRIES = -DONE_PER_NAME       # only one score entry per name
+SCORE_ENTRIES = -DMANY_PER_NAME                # many score entries per name
+
+# the XPM-Library is needed to build this program:
+XPM_INCLUDE_FILE = -DXPM_INCLUDE_FILE="<X11/xpm.h>"
+
+CONFIG = $(GAME_DIR) $(SOUNDS) $(JOYSTICK)     \
+        $(SCORE_ENTRIES) $(XPM_INCLUDE_FILE)
+
+# DEBUG = -DDEBUG -g -ansi -pedantic -Wall
+# DEBUG = -DDEBUG -g -Wall
+DEBUG = -O6
+
+# SYSTEM = -Aa -D_HPUX_SOURCE -Dhpux   # for HP-UX (obsolete)
+# SYSTEM = -DSYSV -Ae                  # for HP-UX
+# SYSTEM = -DSYSV                      # for systems without 'usleep()'
+# INCL = -I/usr/include/X11R5          # for HP-UX and others
+# LIBS = -lXpm -lX11 -lm
+# LIBS = -L/usr/lib/X11R5 -lXpm -lX11 -lm # for HP-UX and others
+LIBS = -lXpm -lXpm -lXpm -lX11 -lm     # triple -lXpm; else I got an error...
+
+# CFLAGS = -O2 $(CONFIG) $(SYSTEM)
+CFLAGS = $(DEBUG) $(CONFIG) $(SYSTEM) $(INCL)
+
+OBJS = main.o \
+       init.o \
+       images.o \
+       events.o \
+       tools.o \
+       screens.o \
+       misc.o \
+       game.o \
+       editor.o \
+       sound.o
+
+all:   $(OBJS)
+       $(CC) $(CFLAGS) $(OBJS) $(LIBS) -o $(PROGNAME)
+
+.c.o:
+       $(CC) $(CFLAGS) -c $*.c
+
+clean:
+       $(RM) $(OBJS)
diff --git a/src/editor.c b/src/editor.c
new file mode 100644 (file)
index 0000000..ee7fe4e
--- /dev/null
@@ -0,0 +1,1516 @@
+/***********************************************************
+*  Rocks'n'Diamonds -- McDuffin Strikes Back!              *
+*----------------------------------------------------------*
+*  ©1995 Artsoft Development                               *
+*        Holger Schemel                                    *
+*        33659 Bielefeld-Senne                             *
+*        Telefon: (0521) 493245                            *
+*        eMail: aeglos@valinor.owl.de                      *
+*               aeglos@uni-paderborn.de                    *
+*               q99492@pbhrzx.uni-paderborn.de             *
+*----------------------------------------------------------*
+*  editor.c                                                *
+*                                                          *
+*  Letzte Aenderung: 15.06.1995                            *
+***********************************************************/
+
+#include "editor.h"
+#include "screens.h"
+#include "game.h"
+#include "tools.h"
+#include "misc.h"
+
+static int level_xpos,level_ypos;
+static BOOL edit_mode;
+static BOOL name_typing;
+static int element_shift;
+static int new_element1 = EL_MAUERWERK;
+static int new_element2 = EL_LEERRAUM;
+static int new_element3 = EL_ERDREICH;
+static int editor_element[] =
+{
+  EL_SPIELFIGUR,
+  EL_LEERRAUM,
+  EL_ERDREICH,
+  EL_FELSBROCKEN,
+
+  EL_BETON,
+  EL_MAUERWERK,
+  EL_FELSBODEN,
+  EL_SIEB_LEER,
+
+  EL_EDELSTEIN,
+  EL_DIAMANT,
+  EL_KOKOSNUSS,
+  EL_BOMBE,
+
+  EL_MORAST_LEER,
+  EL_MORAST_VOLL,
+  EL_AUSGANG_ZU,
+  EL_AUSGANG_AUF,
+
+  EL_KAEFER,
+  EL_FLIEGER,
+  EL_MAMPFER,
+  EL_ZOMBIE,
+
+  EL_PACMAN,
+  EL_DYNAMIT_AUS,
+  EL_DYNAMIT,
+  EL_ABLENK_AUS,
+
+  EL_BADEWANNE1,
+  EL_SALZSAEURE,
+  EL_BADEWANNE2,
+  EL_BADEWANNE,
+
+  EL_BADEWANNE3,
+  EL_BADEWANNE4,
+  EL_BADEWANNE5,
+  EL_UNSICHTBAR,
+
+  EL_TROPFEN,
+  EL_AMOEBE1,
+  EL_AMOEBE2,
+  EL_AMOEBE3,
+
+  EL_LIFE,
+  EL_LIFE_ASYNC,
+
+  EL_ERZ_1,
+  EL_ERZ_2,
+
+/*
+  EL_BIRNE_AUS,
+  EL_BIRNE_EIN,
+*/
+
+  EL_SCHLUESSEL1,
+  EL_SCHLUESSEL2,
+  EL_SCHLUESSEL3,
+  EL_SCHLUESSEL4,
+
+  EL_PFORTE1,
+  EL_PFORTE2,
+  EL_PFORTE3,
+  EL_PFORTE4,
+
+  EL_PFORTE1X,
+  EL_PFORTE2X,
+  EL_PFORTE3X,
+  EL_PFORTE4X,
+
+  EL_KAEFER_R,
+  EL_KAEFER_O,
+  EL_KAEFER_L,
+  EL_KAEFER_U,
+
+  EL_FLIEGER_R,
+  EL_FLIEGER_O,
+  EL_FLIEGER_L,
+  EL_FLIEGER_U,
+
+  EL_PACMAN_R,
+  EL_PACMAN_O,
+  EL_PACMAN_L,
+  EL_PACMAN_U,
+
+  EL_CHAR_AUSRUF,
+  EL_CHAR_ZOLL,
+  EL_CHAR_DOLLAR,
+  EL_CHAR_PROZ,
+
+  EL_CHAR_APOSTR,
+  EL_CHAR_KLAMM1,
+  EL_CHAR_KLAMM2,
+  EL_CHAR_PLUS,
+
+  EL_CHAR_KOMMA,
+  EL_CHAR_MINUS,
+  EL_CHAR_PUNKT,
+  EL_CHAR_SLASH,
+
+  EL_CHAR_0 + 0,
+  EL_CHAR_0 + 1,
+  EL_CHAR_0 + 2,
+  EL_CHAR_0 + 3,
+
+  EL_CHAR_0 + 4,
+  EL_CHAR_0 + 5,
+  EL_CHAR_0 + 6,
+  EL_CHAR_0 + 7,
+
+  EL_CHAR_0 + 8,
+  EL_CHAR_0 + 9,
+  EL_CHAR_DOPPEL,
+  EL_CHAR_SEMIKL,
+
+  EL_CHAR_LT,
+  EL_CHAR_GLEICH,
+  EL_CHAR_GT,
+  EL_CHAR_FRAGE,
+
+  EL_CHAR_AT,
+  EL_CHAR_A + 0,
+  EL_CHAR_A + 1,
+  EL_CHAR_A + 2,
+
+  EL_CHAR_A + 3,
+  EL_CHAR_A + 4,
+  EL_CHAR_A + 5,
+  EL_CHAR_A + 6,
+
+  EL_CHAR_A + 7,
+  EL_CHAR_A + 8,
+  EL_CHAR_A + 9,
+  EL_CHAR_A + 10,
+
+  EL_CHAR_A + 11,
+  EL_CHAR_A + 12,
+  EL_CHAR_A + 13,
+  EL_CHAR_A + 14,
+
+  EL_CHAR_A + 15,
+  EL_CHAR_A + 16,
+  EL_CHAR_A + 17,
+  EL_CHAR_A + 18,
+
+  EL_CHAR_A + 19,
+  EL_CHAR_A + 20,
+  EL_CHAR_A + 21,
+  EL_CHAR_A + 22,
+
+  EL_CHAR_A + 23,
+  EL_CHAR_A + 24,
+  EL_CHAR_A + 25,
+  EL_CHAR_AE,
+
+  EL_CHAR_OE,
+  EL_CHAR_UE,
+  EL_CHAR_COPY
+};
+static int elements_in_list = sizeof(editor_element)/sizeof(int);
+
+void DrawLevelEd()
+{
+  int i, graphic;
+
+  level_xpos=-1;
+  level_ypos=-1;
+  edit_mode = TRUE;
+  name_typing = FALSE;
+  element_shift = 0;
+
+  CloseDoor(DOOR_CLOSE_2);
+
+  DrawMiniLevel(level_xpos,level_ypos);
+  FadeToFront();
+
+  XCopyArea(display,pix[PIX_DOOR],pix[PIX_DB_DOOR],gc,
+           DOOR_GFX_PAGEX6,DOOR_GFX_PAGEY1,
+           DXSIZE,DYSIZE,
+           DOOR_GFX_PAGEX1,DOOR_GFX_PAGEY1);
+  XCopyArea(display,pix[PIX_DOOR],pix[PIX_DB_DOOR],gc,
+           DOOR_GFX_PAGEX6+ED_BUTTON_ELEM_XPOS,
+           DOOR_GFX_PAGEY1+ED_BUTTON_ELEM_YPOS,
+           4*ED_BUTTON_ELEM_XSIZE,5*ED_BUTTON_ELEM_YSIZE,
+           DOOR_GFX_PAGEX1+ED_BUTTON_ELEM_XPOS,
+           DOOR_GFX_PAGEY1+ED_BUTTON_EUP_Y2POS);
+
+  for(i=0;i<MAX_ELEM_X*MAX_ELEM_Y;i++)
+  {
+    if (i < elements_in_list)
+      graphic = el2gfx(editor_element[i]);
+    else
+      graphic = GFX_LEERRAUM;
+
+    DrawMiniGraphicExtHiRes(pix[PIX_DB_DOOR],gc,
+                           DOOR_GFX_PAGEX1+ED_BUTTON_ELEM_XPOS+3 + 
+                           (i%MAX_ELEM_X)*ED_BUTTON_ELEM_XSIZE,
+                           DOOR_GFX_PAGEY1+ED_BUTTON_ELEM_YPOS+3 +
+                           (i/MAX_ELEM_X)*ED_BUTTON_ELEM_YSIZE,
+                           graphic);
+  }
+
+  DrawMiniGraphicExtHiRes(pix[PIX_DB_DOOR],gc,
+                         DOOR_GFX_PAGEX1+ED_WIN_MB_LEFT_XPOS,
+                         DOOR_GFX_PAGEY1+ED_WIN_MB_LEFT_YPOS,
+                         el2gfx(new_element1));
+  DrawMiniGraphicExtHiRes(pix[PIX_DB_DOOR],gc,
+                         DOOR_GFX_PAGEX1+ED_WIN_MB_MIDDLE_XPOS,
+                         DOOR_GFX_PAGEY1+ED_WIN_MB_MIDDLE_YPOS,
+                         el2gfx(new_element2));
+  DrawMiniGraphicExtHiRes(pix[PIX_DB_DOOR],gc,
+                         DOOR_GFX_PAGEX1+ED_WIN_MB_RIGHT_XPOS,
+                         DOOR_GFX_PAGEY1+ED_WIN_MB_RIGHT_YPOS,
+                         el2gfx(new_element3));
+  DrawTextExt(pix[PIX_DB_DOOR],gc,
+             DOOR_GFX_PAGEX2+ED_WIN_LEVELNR_XPOS,
+             DOOR_GFX_PAGEY1+ED_WIN_LEVELNR_YPOS,
+             int2str(level_nr,2),FS_SMALL,FC_SPECIAL1);
+  XCopyArea(display,pix[PIX_DB_DOOR],pix[PIX_DB_DOOR],gc,
+           DOOR_GFX_PAGEX2+ED_WIN_LEVELNR_XPOS+3,
+           DOOR_GFX_PAGEY1+ED_WIN_LEVELNR_YPOS,
+           7,FONT3_YSIZE,
+           DOOR_GFX_PAGEX1+ED_WIN_LEVELNR_XPOS,
+           DOOR_GFX_PAGEY1+ED_WIN_LEVELNR_YPOS);
+  XCopyArea(display,pix[PIX_DB_DOOR],pix[PIX_DB_DOOR],gc,
+           DOOR_GFX_PAGEX2+ED_WIN_LEVELNR_XPOS+14,
+           DOOR_GFX_PAGEY1+ED_WIN_LEVELNR_YPOS,
+           7,FONT3_YSIZE,
+           DOOR_GFX_PAGEX1+ED_WIN_LEVELNR_XPOS+9,
+           DOOR_GFX_PAGEY1+ED_WIN_LEVELNR_YPOS);
+
+  XCopyArea(display,pix[PIX_DOOR],pix[PIX_DB_DOOR],gc,
+           DOOR_GFX_PAGEX6,DOOR_GFX_PAGEY2,
+           VXSIZE,VYSIZE,
+           DOOR_GFX_PAGEX1,DOOR_GFX_PAGEY2);
+
+  OpenDoor(DOOR_OPEN_1 | DOOR_OPEN_2);
+}
+
+void DrawControlWindow()
+{
+  int i,x,y;
+
+  ClearWindow();
+
+  DrawText(ED_COUNT_GADGET_XPOS+1,SY+6,
+          "Contents of a smashed cruncher:",FS_SMALL,FC_YELLOW);
+  for(i=0;i<4;i++) for(y=0;y<4;y++) for(x=0;x<4;x++)
+  {
+    DrawMiniElement(1+5*i+x,2+y,EL_ERDREICH);
+    XFillRectangle(display,drawto,gc,
+                  SX+(2+5*i)*MINI_TILEX-MINI_TILEX/2-1,
+                  SY+(3)*MINI_TILEY-MINI_TILEY/2-1,
+                  3*MINI_TILEX+2,3*MINI_TILEY+2);
+  }
+  XCopyArea(display,drawto,drawto,gc,
+           SX+MINI_TILEX,SY+2*MINI_TILEY,
+           4*5*MINI_TILEX,5*MINI_TILEY,
+           SX+MINI_TILEX-MINI_TILEX/2,SY+2*MINI_TILEY-MINI_TILEY/2);
+  for(i=0;i<4;i++)
+  {
+    for(y=0;y<3;y++) for(x=0;x<3;x++)
+      DrawMiniElement(1+5*i+x,2+y,level.mampfer_inhalt[i][x][y]);
+
+    DrawText(SX+MINI_TILEX+(5*i+1)*MINI_TILEX+1,
+            SY+2*MINI_TILEY+(4)*MINI_TILEY-4,
+            int2str(i+1,1),FS_SMALL,FC_YELLOW);
+  }
+
+  for(i=0;i<11+3+2;i++)
+  {
+    XCopyArea(display,pix[PIX_DOOR],drawto,gc,
+             DOOR_GFX_PAGEX4+ED_BUTTON_MINUS_XPOS,
+             DOOR_GFX_PAGEY1+ED_BUTTON_MINUS_YPOS,
+             DXSIZE-4,ED_BUTTON_MINUS_YSIZE,
+             ED_COUNT_GADGET_XPOS,
+             ED_COUNT_GADGET_YPOS+i*ED_COUNT_GADGET_YSIZE);
+
+    if (i<11)
+      DrawText(ED_COUNT_VALUE_XPOS,
+              ED_COUNT_VALUE_YPOS+i*ED_COUNT_GADGET_YSIZE,
+              int2str(level.score[i],3),FS_SMALL,FC_YELLOW);
+    else if (i==11)
+      DrawText(ED_COUNT_VALUE_XPOS,
+              ED_COUNT_VALUE_YPOS+11*ED_COUNT_GADGET_YSIZE,
+              int2str(level.tempo_amoebe,3),FS_SMALL,FC_YELLOW);
+    else if (i==12)
+      DrawText(ED_COUNT_VALUE_XPOS,
+              ED_COUNT_VALUE_YPOS+12*ED_COUNT_GADGET_YSIZE,
+              int2str(level.dauer_sieb,3),FS_SMALL,FC_YELLOW);
+    else if (i==13)
+      DrawText(ED_COUNT_VALUE_XPOS,
+              ED_COUNT_VALUE_YPOS+13*ED_COUNT_GADGET_YSIZE,
+              int2str(level.dauer_ablenk,3),FS_SMALL,FC_YELLOW);
+    else if (i==14)
+      DrawText(ED_COUNT_VALUE_XPOS,
+              ED_COUNT_VALUE_YPOS+14*ED_COUNT_GADGET_YSIZE,
+              int2str(level.edelsteine,3),FS_SMALL,FC_YELLOW);
+    else if (i==15)
+      DrawText(ED_COUNT_VALUE_XPOS,
+              ED_COUNT_VALUE_YPOS+15*ED_COUNT_GADGET_YSIZE,
+              int2str(level.time,3),FS_SMALL,FC_YELLOW);
+  }
+
+  DrawText(ED_COUNT_TEXT_XPOS,ED_COUNT_TEXT_YPOS+0*ED_COUNT_TEXT_YSIZE,
+          "Score for Emerald",FS_SMALL,FC_YELLOW);
+  DrawText(ED_COUNT_TEXT_XPOS,ED_COUNT_TEXT_YPOS+1*ED_COUNT_TEXT_YSIZE,
+          "Score for Diamond",FS_SMALL,FC_YELLOW);
+  DrawText(ED_COUNT_TEXT_XPOS,ED_COUNT_TEXT_YPOS+2*ED_COUNT_TEXT_YSIZE,
+          "Score for smashing a Bug",FS_SMALL,FC_YELLOW);
+  DrawText(ED_COUNT_TEXT_XPOS,ED_COUNT_TEXT_YPOS+3*ED_COUNT_TEXT_YSIZE,
+          "Score for smashing a Spaceship",FS_SMALL,FC_YELLOW);
+  DrawText(ED_COUNT_TEXT_XPOS,ED_COUNT_TEXT_YPOS+4*ED_COUNT_TEXT_YSIZE,
+          "Score for smashing a Cruncher",FS_SMALL,FC_YELLOW);
+  DrawText(ED_COUNT_TEXT_XPOS,ED_COUNT_TEXT_YPOS+5*ED_COUNT_TEXT_YSIZE,
+          "Score for smashing an Alien",FS_SMALL,FC_YELLOW);
+  DrawText(ED_COUNT_TEXT_XPOS,ED_COUNT_TEXT_YPOS+6*ED_COUNT_TEXT_YSIZE,
+          "Score for smashing a Pacman",FS_SMALL,FC_YELLOW);
+  DrawText(ED_COUNT_TEXT_XPOS,ED_COUNT_TEXT_YPOS+7*ED_COUNT_TEXT_YSIZE,
+          "Score for cracking a nut",FS_SMALL,FC_YELLOW);
+  DrawText(ED_COUNT_TEXT_XPOS,ED_COUNT_TEXT_YPOS+8*ED_COUNT_TEXT_YSIZE,
+          "Score for dynamite",FS_SMALL,FC_YELLOW);
+  DrawText(ED_COUNT_TEXT_XPOS,ED_COUNT_TEXT_YPOS+9*ED_COUNT_TEXT_YSIZE,
+          "Score for key",FS_SMALL,FC_YELLOW);
+  DrawText(ED_COUNT_TEXT_XPOS,ED_COUNT_TEXT_YPOS+10*ED_COUNT_TEXT_YSIZE,
+          "Score for each 10 seconds left",FS_SMALL,FC_YELLOW);
+  DrawText(ED_COUNT_TEXT_XPOS,ED_COUNT_TEXT_YPOS+11*ED_COUNT_TEXT_YSIZE,
+          "Speed of the amoeba",FS_SMALL,FC_YELLOW);
+  DrawText(ED_COUNT_TEXT_XPOS,ED_COUNT_TEXT_YPOS+12*ED_COUNT_TEXT_YSIZE,
+          "Time for magic wall",FS_SMALL,FC_YELLOW);
+  DrawText(ED_COUNT_TEXT_XPOS,ED_COUNT_TEXT_YPOS+13*ED_COUNT_TEXT_YSIZE,
+          "Time for wheel",FS_SMALL,FC_YELLOW);
+  DrawText(ED_COUNT_TEXT_XPOS,ED_COUNT_TEXT_YPOS+14*ED_COUNT_TEXT_YSIZE,
+          "Emeralds needed in this level",FS_SMALL,FC_YELLOW);
+  DrawText(ED_COUNT_TEXT_XPOS,ED_COUNT_TEXT_YPOS+15*ED_COUNT_TEXT_YSIZE,
+          "Time available for this level",FS_SMALL,FC_YELLOW);
+
+  XCopyArea(display,pix[PIX_DOOR],drawto,gc,
+           DOOR_GFX_PAGEX4+ED_WIN_COUNT_XPOS,
+           DOOR_GFX_PAGEY1+ED_WIN_COUNT_YPOS,
+           ED_WIN_COUNT_XSIZE,ED_WIN_COUNT_YSIZE,
+           ED_COUNT_GADGET_XPOS,
+           ED_COUNT_GADGET_YPOS+16*ED_COUNT_GADGET_YSIZE);
+  for(i=1;i<31;i++)
+    XCopyArea(display,pix[PIX_DOOR],drawto,gc,
+             DOOR_GFX_PAGEX4+ED_WIN_COUNT_XPOS+3+2*FONT2_XSIZE,
+             DOOR_GFX_PAGEY1+ED_WIN_COUNT_YPOS,
+             ED_WIN_COUNT_XSIZE-3-2*FONT2_XSIZE,ED_WIN_COUNT_YSIZE,
+             ED_COUNT_GADGET_XPOS+3+i*FONT2_XSIZE,
+             ED_COUNT_GADGET_YPOS+16*ED_COUNT_GADGET_YSIZE);
+  DrawText(ED_COUNT_GADGET_XPOS+5,
+          ED_COUNT_TEXT_YPOS+16*ED_COUNT_TEXT_YSIZE,
+          level.name,FS_SMALL,FC_YELLOW);
+  DrawText(ED_COUNT_GADGET_XPOS+(30+3)*FONT2_XSIZE-5,
+          ED_COUNT_TEXT_YPOS+16*ED_COUNT_TEXT_YSIZE,
+          "Title",FS_SMALL,FC_YELLOW);
+
+  DrawText(ED_SIZE_GADGET_XPOS,ED_SIZE_GADGET_YPOS-18,
+          "Playfield size:",FS_SMALL,FC_YELLOW);
+  XCopyArea(display,pix[PIX_DOOR],drawto,gc,
+           DOOR_GFX_PAGEX4+ED_BUTTON_MINUS_XPOS,
+           DOOR_GFX_PAGEY1+ED_BUTTON_MINUS_YPOS,
+           DXSIZE-4,ED_BUTTON_MINUS_YSIZE,
+           ED_SIZE_GADGET_XPOS,
+           ED_SIZE_GADGET_YPOS+0*ED_COUNT_GADGET_YSIZE);
+  XCopyArea(display,pix[PIX_DOOR],drawto,gc,
+           DOOR_GFX_PAGEX4+ED_BUTTON_MINUS_XPOS,
+           DOOR_GFX_PAGEY1+ED_BUTTON_MINUS_YPOS,
+           DXSIZE-4,ED_BUTTON_MINUS_YSIZE,
+           ED_SIZE_GADGET_XPOS,
+           ED_SIZE_GADGET_YPOS+1*ED_COUNT_GADGET_YSIZE);
+  DrawText(ED_SIZE_TEXT_XPOS,ED_SIZE_TEXT_YPOS+0*ED_SIZE_TEXT_YSIZE,
+          "Width",FS_SMALL,FC_YELLOW);
+  DrawText(ED_SIZE_TEXT_XPOS,ED_SIZE_TEXT_YPOS+1*ED_SIZE_TEXT_YSIZE,
+          "Height",FS_SMALL,FC_YELLOW);
+  DrawText(ED_SIZE_VALUE_XPOS,ED_SIZE_VALUE_YPOS+0*ED_SIZE_GADGET_YSIZE,
+          int2str(level.fieldx,3),FS_SMALL,FC_YELLOW);
+  DrawText(ED_SIZE_VALUE_XPOS,ED_SIZE_VALUE_YPOS+1*ED_SIZE_GADGET_YSIZE,
+          int2str(level.fieldy,3),FS_SMALL,FC_YELLOW);
+}
+
+void ScrollMiniLevel(int from_x, int from_y, int scroll)
+{
+  int x,y;
+  int dx = (scroll==ED_SCROLL_LEFT ? -1 : scroll==ED_SCROLL_RIGHT ? 1 : 0);
+  int dy = (scroll==ED_SCROLL_UP   ? -1 : scroll==ED_SCROLL_DOWN  ? 1 : 0);
+
+  XCopyArea(display,drawto,drawto,gc,
+           SX+MINI_TILEX*(dx==-1),SY+MINI_TILEY*(dy==-1),
+           SXSIZE-MINI_TILEX*ABS(dx),SYSIZE-MINI_TILEY*ABS(dy),
+           SX+MINI_TILEX*(dx==+1),SY+MINI_TILEY*(dy==+1));
+  if (dx)
+  {
+    x = (dx==1 ? 0 : 2*SCR_FIELDX-1);
+    for(y=0;y<2*SCR_FIELDY;y++)
+      DrawMiniElementOrWall(x,y,from_x,from_y);
+  }
+  else if (dy)
+  {
+    y = (dy==1 ? 0 : 2*SCR_FIELDY-1);
+    for(x=0;x<2*SCR_FIELDX;x++)
+      DrawMiniElementOrWall(x,y,from_x,from_y);
+  }
+
+  redraw_mask |= REDRAW_FIELD;
+  BackToFront();
+}
+
+void AdjustLevelScrollPosition()
+{
+  if (level_xpos<-1)
+    level_xpos = -1;
+  if (level_xpos>lev_fieldx-2*SCR_FIELDX+1)
+    level_xpos = lev_fieldx-2*SCR_FIELDX+1;
+  if (lev_fieldx<2*SCR_FIELDX-2)
+    level_xpos = -1;
+
+  if (level_ypos<-1)
+    level_ypos = -1;
+  if (level_ypos>lev_fieldy-2*SCR_FIELDY+1)
+    level_ypos = lev_fieldy-2*SCR_FIELDY+1;
+  if (lev_fieldy<2*SCR_FIELDY-2)
+    level_ypos = -1;
+}
+
+void FloodFill(int from_x, int from_y, int fill_element)
+{
+  int i,x,y;
+  int old_element;
+  static int check[4][2] = { -1,0, 0,-1, 1,0, 0,1 };
+  static int safety = 0;
+
+  safety++;
+
+  if (safety>lev_fieldx*lev_fieldy)
+  {
+    fprintf(stderr,"Something went wrong in 'FloodFill()'. Please debug.\n");
+    exit(-1);
+  }
+
+  old_element = Feld[from_x][from_y];
+  Feld[from_x][from_y] = fill_element;
+
+  for(i=0;i<4;i++)
+  {
+    x = from_x+check[i][0];
+    y = from_y+check[i][1];
+
+    if (IN_LEV_FIELD(x,y) && Feld[x][y]==old_element)
+      FloodFill(x,y,fill_element);
+  }
+
+  safety--;
+}
+
+void LevelEd(int mx, int my, int button)
+{
+  static int last_button = 0;
+  static int in_field_pressed = FALSE;
+  static BOOL use_floodfill = FALSE;
+  int x = (mx-SX)/MINI_TILEX; 
+  int y = (my-SY)/MINI_TILEY; 
+
+  if (use_floodfill)           /********** FLOOD FILL **********/
+  {
+    if (button)
+    {
+      if (mx>=SX && mx<SX+SXSIZE && my>=SY && my<SY+SYSIZE)
+      {
+       int from_x, from_y;
+       int fill_element;
+
+       if (x>lev_fieldx || y>lev_fieldy ||
+           (x==0 && level_xpos<0) ||
+           (x==2*SCR_FIELDX-1 && level_xpos>lev_fieldx-2*SCR_FIELDX) ||
+           (y==0 && level_ypos<0) ||
+           (y==2*SCR_FIELDY-1 && level_ypos>lev_fieldy-2*SCR_FIELDY))
+         return;
+
+       from_x = x+level_xpos;
+       from_y = y+level_ypos;
+       fill_element = (button==1 ? new_element1 :
+                       button==2 ? new_element2 :
+                       button==3 ? new_element3 : 0);
+
+       FloodFill(from_x,from_y,fill_element);
+       DrawMiniLevel(level_xpos,level_ypos);
+      }
+
+      use_floodfill = FALSE;
+      CloseDoor(DOOR_CLOSE_1);
+      OpenDoor(DOOR_OPEN_1 | DOOR_COPY_BACK);
+    }
+    return;
+  }
+  else                         /********** EDIT/CTRL-FENSTER **********/
+  {
+    int choice = CheckElemButtons(mx,my,button);
+    int elem_pos = choice-ED_BUTTON_ELEM;
+
+    switch(choice)
+    {
+      case ED_BUTTON_EUP:
+      case ED_BUTTON_EDOWN:
+        if ((choice==ED_BUTTON_EUP && element_shift>0) ||
+           (choice==ED_BUTTON_EDOWN &&
+            element_shift<elements_in_list-MAX_ELEM_X*MAX_ELEM_Y))
+       {
+         int i, step;
+
+         step = (button==1 ? MAX_ELEM_X : button==2 ? 5*MAX_ELEM_X :
+                 elements_in_list);
+         element_shift += (choice==ED_BUTTON_EUP ? -step : step);
+         if (element_shift<0)
+           element_shift = 0;
+         if (element_shift>elements_in_list-MAX_ELEM_X*MAX_ELEM_Y)
+           element_shift = elements_in_list-MAX_ELEM_X*MAX_ELEM_Y;
+         if (element_shift % MAX_ELEM_X)
+           element_shift += MAX_ELEM_X-(element_shift % MAX_ELEM_X);
+
+         for(i=0;i<MAX_ELEM_X*MAX_ELEM_Y;i++)
+           DrawElemButton(i+2,ED_BUTTON_RELEASED);
+         BackToFront();
+         Delay(100000);
+       }
+       break;
+      default:
+       if (elem_pos>=0 && elem_pos<MAX_ELEM_X*MAX_ELEM_Y)
+       {
+         int new_element;
+
+         if (elem_pos+element_shift < elements_in_list)
+           new_element = editor_element[elem_pos+element_shift];
+         else
+           new_element = EL_LEERRAUM;
+
+         if (last_button==1)
+           new_element1 = new_element;
+         else if (last_button==2)
+           new_element2 = new_element;
+         else if (last_button==3)
+           new_element3 = new_element;
+
+         DrawMiniGraphicExtHiRes(drawto,gc,
+                                 DX+ED_WIN_MB_LEFT_XPOS,
+                                 DY+ED_WIN_MB_LEFT_YPOS,
+                                 el2gfx(new_element1));
+         DrawMiniGraphicExtHiRes(drawto,gc,
+                                 DX+ED_WIN_MB_MIDDLE_XPOS,
+                                 DY+ED_WIN_MB_MIDDLE_YPOS,
+                                 el2gfx(new_element2));
+         DrawMiniGraphicExtHiRes(drawto,gc,
+                                 DX+ED_WIN_MB_RIGHT_XPOS,
+                                 DY+ED_WIN_MB_RIGHT_YPOS,
+                                 el2gfx(new_element3));
+         redraw_mask |= REDRAW_DOOR_1;
+       }
+       break;
+    }
+
+    if (edit_mode)             /********** EDIT-FENSTER **********/
+    {
+      switch(CheckEditButtons(mx,my,button))
+      {
+       case ED_BUTTON_CTRL:
+         CloseDoor(DOOR_CLOSE_2);
+         DrawControlWindow();
+         XCopyArea(display,pix[PIX_DOOR],pix[PIX_DB_DOOR],gc,
+                   DOOR_GFX_PAGEX4,DOOR_GFX_PAGEY1+80,
+                   VXSIZE,VYSIZE,
+                   DOOR_GFX_PAGEX1,DOOR_GFX_PAGEY2);
+         OpenDoor(DOOR_OPEN_2);
+         edit_mode = FALSE;
+         break;
+       case ED_BUTTON_FILL:
+         AreYouSure("Caution ! Flood fill mode ! Choose area !",AYS_OPEN);
+         use_floodfill = TRUE;
+         return;
+         break;
+       case ED_BUTTON_LEFT:
+         if (level_xpos>=0)
+         {
+           if (lev_fieldx<2*SCR_FIELDX-2)
+             break;
+
+           level_xpos -= (button==1 ? 1 : button==2 ? 5 : lev_fieldx);
+           if (level_xpos<-1)
+             level_xpos = -1;
+           if (button==1)
+             ScrollMiniLevel(level_xpos,level_ypos,ED_SCROLL_RIGHT);
+           else
+             DrawMiniLevel(level_xpos,level_ypos);
+           BackToFront();
+           Delay(100000);
+         }
+         break;
+       case ED_BUTTON_RIGHT:
+         if (level_xpos<=lev_fieldx-2*SCR_FIELDX)
+         {
+           if (lev_fieldx<2*SCR_FIELDX-2)
+             break;
+
+           level_xpos += (button==1 ? 1 : button==2 ? 5 : lev_fieldx);
+           if (level_xpos>lev_fieldx-2*SCR_FIELDX+1)
+             level_xpos = lev_fieldx-2*SCR_FIELDX+1;
+           if (button==1)
+             ScrollMiniLevel(level_xpos,level_ypos,ED_SCROLL_LEFT);
+           else
+             DrawMiniLevel(level_xpos,level_ypos);
+           BackToFront();
+           Delay(100000);
+         }
+         break;
+       case ED_BUTTON_UP:
+         if (level_ypos>=0)
+         {
+           if (lev_fieldy<2*SCR_FIELDY-2)
+             break;
+
+           level_ypos -= (button==1 ? 1 : button==2 ? 5 : lev_fieldy);
+           if (level_ypos<-1)
+             level_ypos = -1;
+           if (button==1)
+             ScrollMiniLevel(level_xpos,level_ypos,ED_SCROLL_DOWN);
+           else
+             DrawMiniLevel(level_xpos,level_ypos);
+           BackToFront();
+           Delay(100000);
+         }
+         break;
+       case ED_BUTTON_DOWN:
+         if (level_ypos<=lev_fieldy-2*SCR_FIELDY)
+         {
+           if (lev_fieldy<2*SCR_FIELDY-2)
+             break;
+
+           level_ypos += (button==1 ? 1 : button==2 ? 5 : lev_fieldy);
+           if (level_ypos>lev_fieldy-2*SCR_FIELDY+1)
+             level_ypos = lev_fieldy-2*SCR_FIELDY+1;
+           if (button==1)
+             ScrollMiniLevel(level_xpos,level_ypos,ED_SCROLL_UP);
+           else
+             DrawMiniLevel(level_xpos,level_ypos);
+           BackToFront();
+           Delay(100000);
+         }
+         break;
+       default:
+         break;
+      }
+
+      if (mx>=SX && mx<SX+SXSIZE && my>=SY && my<SY+SYSIZE)
+      {
+       int new_element;
+
+       if (button && !motion_status)
+         in_field_pressed = TRUE;
+
+       if (!button || !in_field_pressed || button<1 || button>3 ||
+           (y==0 && level_ypos<0) ||
+           (y==2*SCR_FIELDY-1 && level_ypos>lev_fieldy-2*SCR_FIELDY) ||
+           (x==0 && level_xpos<0) ||
+           (x==2*SCR_FIELDX-1 && level_xpos>lev_fieldx-2*SCR_FIELDX) ||
+           x>lev_fieldx || y>lev_fieldy)
+         return;
+
+       new_element = (button==1 ? new_element1 :
+                      button==2 ? new_element2 :
+                      button==3 ? new_element3 : 0);
+
+       if (new_element != Feld[x+level_xpos][y+level_ypos])
+       {
+         if (new_element==EL_SPIELFIGUR) /* Jeder nur EINE Figur bitte... */
+         {
+           int x,y;
+
+           for(x=0;x<lev_fieldx;x++) for(y=0;y<lev_fieldy;y++)
+           {
+             if (Feld[x][y]==EL_SPIELFIGUR || Feld[x][y]==EL_SPIELER1)
+             {
+               Feld[x][y] = EL_LEERRAUM;
+               if (x-level_xpos>=0 && x-level_xpos<2*SCR_FIELDX &&
+                   y-level_ypos>=0 && y-level_ypos<2*SCR_FIELDY)
+                 DrawMiniElement(x-level_xpos,y-level_ypos,EL_LEERRAUM);
+             }
+           }
+         }
+
+         Feld[x+level_xpos][y+level_ypos] = new_element;
+         DrawMiniElement(x,y,new_element);
+       }
+      }
+      else if (!motion_status) /* Mauszeiger nicht im Level-Feld */
+       in_field_pressed = FALSE;
+    }
+    else                       /********** KONTROLL-FENSTER **********/
+    {
+      static long choice_delay = 0;
+      int choice = CheckCountButtons(mx,my,button);
+      int step = (button==1 ? 1 : button==2 ? 5 : button==3 ? 10 : 0);
+
+      if (choice>=0 && choice<36 && DelayReached(&choice_delay,10))
+      {
+       if (!(choice % 2))
+         step = -step;
+
+       choice /= 2;
+
+       if (choice<11)
+       {
+         level.score[choice] += step;
+         if (level.score[choice]<0)
+           level.score[choice] = 0;
+         else if (level.score[choice]>255)
+           level.score[choice] = 255;
+       }
+       else if (choice==11)
+       {
+         level.tempo_amoebe += step;
+         if (level.tempo_amoebe<0)
+           level.tempo_amoebe = 0;
+         else if (level.tempo_amoebe>255)
+           level.tempo_amoebe = 255;
+       }
+       else if (choice==12)
+       {
+         level.dauer_sieb += step;
+         if (level.dauer_sieb<0)
+           level.dauer_sieb = 0;
+         else if (level.dauer_sieb>255)
+           level.dauer_sieb = 255;
+       }
+       else if (choice==13)
+       {
+         level.dauer_ablenk += step;
+         if (level.dauer_ablenk<0)
+           level.dauer_ablenk = 0;
+         else if (level.dauer_ablenk>255)
+           level.dauer_ablenk = 255;
+       }
+       else if (choice==14)
+       {
+         level.edelsteine += step;
+         if (level.edelsteine<0)
+           level.edelsteine = 0;
+         else if (level.edelsteine>999)
+           level.edelsteine = 999;
+       }
+       else if (choice==15)
+       {
+         level.time += step;
+         if (level.time<0)
+           level.time = 0;
+         else if (level.time>999)
+           level.time = 999;
+       }
+       else if (choice==16)
+       {
+         lev_fieldx += step;
+         if (lev_fieldx<MIN_LEV_FIELDX)
+           lev_fieldx = MIN_LEV_FIELDX;
+         else if (lev_fieldx>MAX_LEV_FIELDX)
+           lev_fieldx = MAX_LEV_FIELDX;
+         level.fieldx = lev_fieldx;
+       }
+       else if (choice==17)
+       {
+         lev_fieldy += step;
+         if (lev_fieldy<MIN_LEV_FIELDY)
+           lev_fieldy = MIN_LEV_FIELDY;
+         else if (lev_fieldy>MAX_LEV_FIELDY)
+           lev_fieldy = MAX_LEV_FIELDY;
+         level.fieldy = lev_fieldy;
+       }
+
+       if (choice<11)
+         DrawText(ED_COUNT_VALUE_XPOS,
+                  ED_COUNT_VALUE_YPOS+choice*ED_COUNT_GADGET_YSIZE,
+                  int2str(level.score[choice],3),FS_SMALL,FC_YELLOW);
+       else if (choice==11)
+         DrawText(ED_COUNT_VALUE_XPOS,
+                  ED_COUNT_VALUE_YPOS+11*ED_COUNT_GADGET_YSIZE,
+                  int2str(level.tempo_amoebe,3),FS_SMALL,FC_YELLOW);
+       else if (choice==12)
+         DrawText(ED_COUNT_VALUE_XPOS,
+                  ED_COUNT_VALUE_YPOS+12*ED_COUNT_GADGET_YSIZE,
+                  int2str(level.dauer_sieb,3),FS_SMALL,FC_YELLOW);
+       else if (choice==13)
+         DrawText(ED_COUNT_VALUE_XPOS,
+                  ED_COUNT_VALUE_YPOS+13*ED_COUNT_GADGET_YSIZE,
+                  int2str(level.dauer_ablenk,3),FS_SMALL,FC_YELLOW);
+       else if (choice==14)
+         DrawText(ED_COUNT_VALUE_XPOS,
+                  ED_COUNT_VALUE_YPOS+14*ED_COUNT_GADGET_YSIZE,
+                  int2str(level.edelsteine,3),FS_SMALL,FC_YELLOW);
+       else if (choice==15)
+         DrawText(ED_COUNT_VALUE_XPOS,
+                  ED_COUNT_VALUE_YPOS+15*ED_COUNT_GADGET_YSIZE,
+                  int2str(level.time,3),FS_SMALL,FC_YELLOW);
+       else if (choice==16)
+         DrawText(ED_SIZE_VALUE_XPOS,
+                  ED_SIZE_VALUE_YPOS+0*ED_SIZE_GADGET_YSIZE,
+                  int2str(level.fieldx,3),FS_SMALL,FC_YELLOW);
+       else if (choice==17)
+         DrawText(ED_SIZE_VALUE_XPOS,
+                  ED_SIZE_VALUE_YPOS+1*ED_SIZE_GADGET_YSIZE,
+                  int2str(level.fieldy,3),FS_SMALL,FC_YELLOW);
+
+       redraw_mask &= ~REDRAW_FIELD;
+       if (choice<16)
+         XCopyArea(display,drawto,window,gc,
+                   ED_COUNT_VALUE_XPOS,
+                   ED_COUNT_VALUE_YPOS+choice*ED_COUNT_GADGET_YSIZE,
+                   3*FONT2_XSIZE,FONT2_YSIZE,
+                   ED_COUNT_VALUE_XPOS,
+                   ED_COUNT_VALUE_YPOS+choice*ED_COUNT_GADGET_YSIZE);
+       else
+         XCopyArea(display,drawto,window,gc,
+                   ED_SIZE_VALUE_XPOS,
+                   ED_SIZE_VALUE_YPOS+(choice-16)*ED_SIZE_GADGET_YSIZE,
+                   3*FONT2_XSIZE,FONT2_YSIZE,
+                   ED_SIZE_VALUE_XPOS,
+                   ED_SIZE_VALUE_YPOS+(choice-16)*ED_SIZE_GADGET_YSIZE);
+       XFlush(display);
+      }
+
+      switch(CheckCtrlButtons(mx,my,button))
+      {
+       case ED_BUTTON_EDIT:
+         CloseDoor(DOOR_CLOSE_2);
+         AdjustLevelScrollPosition();
+         DrawMiniLevel(level_xpos,level_ypos);
+         XCopyArea(display,pix[PIX_DOOR],pix[PIX_DB_DOOR],gc,
+                   DOOR_GFX_PAGEX6,DOOR_GFX_PAGEY2,
+                   VXSIZE,VYSIZE,
+                   DOOR_GFX_PAGEX1,DOOR_GFX_PAGEY2);
+         OpenDoor(DOOR_OPEN_2);
+         edit_mode = TRUE;
+         break;
+       case ED_BUTTON_CLEAR:
+         if (AreYouSure("Are you sure to clear this level ?",AYS_ASK))
+         {
+           for(x=0;x<MAX_LEV_FIELDX;x++) 
+             for(y=0;y<MAX_LEV_FIELDY;y++) 
+               Feld[x][y] = EL_ERDREICH;
+           DrawMiniLevel(level_xpos,level_ypos);
+         }
+         break;
+       case ED_BUTTON_UNDO:
+         if (AreYouSure("Exit without saving ?",AYS_ASK | AYS_STAY_OPEN))
+         {
+           CloseDoor(DOOR_CLOSE_BOTH);
+           game_status=MAINMENU;
+           DrawMainMenu();
+         }
+         else
+         {
+           CloseDoor(DOOR_CLOSE_1);
+           OpenDoor(DOOR_OPEN_1 | DOOR_COPY_BACK);
+         }
+         break;
+       case ED_BUTTON_EXIT:
+         {
+           int figur_vorhanden = FALSE;
+           for(y=0;y<lev_fieldy;y++) 
+             for(x=0;x<lev_fieldx;x++)
+               if (Feld[x][y]==EL_SPIELFIGUR || Feld[x][y]==EL_SPIELER1) 
+                 figur_vorhanden = TRUE;
+
+           if (!figur_vorhanden)
+             AreYouSure("No Level without Gregor Mc Duffin please !",
+                        AYS_CONFIRM);
+           else
+           {
+             if (AreYouSure("Save this level and kill the old ?",
+                            AYS_ASK | AYS_STAY_OPEN))
+             {
+               for(x=0;x<lev_fieldx;x++)
+                 for(y=0;y<lev_fieldy;y++) 
+                   Ur[x][y]=Feld[x][y];
+               SaveLevel(level_nr);
+             }
+             CloseDoor(DOOR_CLOSE_BOTH);
+             game_status=MAINMENU;
+             DrawMainMenu();
+           }
+         }
+         break;
+       default:
+         break;
+      }
+
+      if (mx>=ED_COUNT_GADGET_XPOS &&
+         mx<ED_COUNT_GADGET_XPOS+31*FONT2_XSIZE+10 &&
+         my>=ED_COUNT_GADGET_YPOS+16*ED_COUNT_GADGET_YSIZE &&
+         my<ED_COUNT_GADGET_YPOS+16*ED_COUNT_GADGET_YSIZE+ED_WIN_COUNT_YSIZE)
+      {
+       if (!name_typing)
+       {
+         name_typing = TRUE;
+         DrawText(ED_COUNT_GADGET_XPOS+5,
+                  ED_COUNT_TEXT_YPOS+16*ED_COUNT_TEXT_YSIZE,
+                  level.name,FS_SMALL,FC_GREEN);
+         DrawText(ED_COUNT_GADGET_XPOS+5+strlen(level.name)*FONT2_XSIZE,
+                  ED_COUNT_TEXT_YPOS+16*ED_COUNT_TEXT_YSIZE,
+                  "<",FS_SMALL,FC_RED);
+       }
+      }
+      else
+      {
+       if (name_typing)
+       {
+         name_typing = FALSE;
+         DrawText(ED_COUNT_GADGET_XPOS+5,
+                  ED_COUNT_TEXT_YPOS+16*ED_COUNT_TEXT_YSIZE,
+                  level.name,FS_SMALL,FC_YELLOW);
+         DrawText(ED_COUNT_GADGET_XPOS+5+strlen(level.name)*FONT2_XSIZE,
+                  ED_COUNT_TEXT_YPOS+16*ED_COUNT_TEXT_YSIZE,
+                  " ",FS_SMALL,FC_RED);
+       }
+      }
+
+      if (mx>=SX+1*MINI_TILEX && mx<SX+(1+4*5)*MINI_TILEX &&
+         my>=SY+2*MINI_TILEY && my<SY+(2+3)*MINI_TILEY)
+      {
+       int x = (mx-SX-1*MINI_TILEX)/MINI_TILEX;
+       int y = (my-SY-2*MINI_TILEY)/MINI_TILEY;
+       int i = x/5;
+       int new_element;
+
+       x = x-i*5;
+       if (i>=0 && i<43 && x>=0 && x<3 && y>=0 && y<3)
+       {
+         if (button && !motion_status)
+           in_field_pressed = TRUE;
+
+         if (!button || !in_field_pressed || button<1 || button>3)
+           return;
+
+         new_element = (button==1 ? new_element1 :
+                        button==2 ? new_element2 :
+                        button==3 ? new_element3 : 0);
+
+         if (new_element != level.mampfer_inhalt[i][x][y])
+         {
+           level.mampfer_inhalt[i][x][y] = new_element;
+           DrawMiniElement(1+5*i+x,2+y,level.mampfer_inhalt[i][x][y]);
+         }
+       }
+       else if (!motion_status)/* Mauszeiger nicht im Cruncher-Feld */
+         in_field_pressed = FALSE;
+      }
+      else if (!motion_status) /* Mauszeiger nicht im Cruncher-Feld */
+       in_field_pressed = FALSE;
+    }
+  }
+
+  last_button = button;
+
+  BackToFront();
+}
+
+void LevelNameTyping(KeySym key)
+{
+  unsigned char ascii = 0;
+  int len = strlen(level.name);
+
+  if (!name_typing)
+    return;
+
+  if (key>=XK_A && key<=XK_Z)
+    ascii = 'A'+(char)(key-XK_A);
+  else if (key>=XK_a && key<=XK_z)
+    ascii = 'a'+(char)(key-XK_a);
+  else if (key>=XK_0 && key<=XK_9)
+    ascii = '0'+(char)(key-XK_0);
+#ifdef XK_LATIN1
+  else if (key>=XK_space && key<=XK_at)
+    ascii = ' '+(char)(key-XK_space);
+  else if (key==XK_Adiaeresis)
+    ascii = 'Ä';
+  else if (key==XK_Odiaeresis)
+    ascii = 'Ö';
+  else if (key==XK_Udiaeresis)
+    ascii = 'Ü';
+  else if (key==XK_adiaeresis)
+    ascii = 'ä';
+  else if (key==XK_odiaeresis)
+    ascii = 'ö';
+  else if (key==XK_udiaeresis)
+    ascii = 'ü';
+  else if (key==XK_underscore)
+    ascii = '_';
+#endif
+
+  if (ascii && len<MAX_LEVNAMLEN-2)
+  {
+    level.name[len] = ascii;
+    level.name[len+1] = 0;
+    len++;
+
+    DrawTextExt(drawto,gc,
+               ED_COUNT_GADGET_XPOS+5,
+               ED_COUNT_TEXT_YPOS+16*ED_COUNT_TEXT_YSIZE,
+               level.name,FS_SMALL,FC_GREEN);
+    DrawTextExt(window,gc,
+               ED_COUNT_GADGET_XPOS+5,
+               ED_COUNT_TEXT_YPOS+16*ED_COUNT_TEXT_YSIZE,
+               level.name,FS_SMALL,FC_GREEN);
+    DrawTextExt(drawto,gc,
+               ED_COUNT_GADGET_XPOS+5+len*FONT2_XSIZE,
+               ED_COUNT_TEXT_YPOS+16*ED_COUNT_TEXT_YSIZE,
+               "<",FS_SMALL,FC_RED);
+    DrawTextExt(window,gc,
+               ED_COUNT_GADGET_XPOS+5+len*FONT2_XSIZE,
+               ED_COUNT_TEXT_YPOS+16*ED_COUNT_TEXT_YSIZE,
+               "<",FS_SMALL,FC_RED);
+  }
+  else if (key==XK_Delete && len>0)
+  {
+    level.name[len-1] = 0;
+    len--;
+
+    DrawTextExt(drawto,gc,
+               ED_COUNT_GADGET_XPOS+5+len*FONT2_XSIZE,
+               ED_COUNT_TEXT_YPOS+16*ED_COUNT_TEXT_YSIZE,
+               "< ",FS_SMALL,FC_GREEN);
+    DrawTextExt(window,gc,
+               ED_COUNT_GADGET_XPOS+5+len*FONT2_XSIZE,
+               ED_COUNT_TEXT_YPOS+16*ED_COUNT_TEXT_YSIZE,
+               "< ",FS_SMALL,FC_GREEN);
+  }
+  else if (key==XK_Return)
+  {
+    DrawTextExt(drawto,gc,
+               ED_COUNT_GADGET_XPOS+5,
+               ED_COUNT_TEXT_YPOS+16*ED_COUNT_TEXT_YSIZE,
+               level.name,FS_SMALL,FC_YELLOW);
+    DrawTextExt(window,gc,
+               ED_COUNT_GADGET_XPOS+5,
+               ED_COUNT_TEXT_YPOS+16*ED_COUNT_TEXT_YSIZE,
+               level.name,FS_SMALL,FC_YELLOW);
+    DrawTextExt(drawto,gc,
+               ED_COUNT_GADGET_XPOS+5+len*FONT2_XSIZE,
+               ED_COUNT_TEXT_YPOS+16*ED_COUNT_TEXT_YSIZE,
+               " ",FS_SMALL,FC_YELLOW);
+    DrawTextExt(window,gc,
+               ED_COUNT_GADGET_XPOS+5+len*FONT2_XSIZE,
+               ED_COUNT_TEXT_YPOS+16*ED_COUNT_TEXT_YSIZE,
+               " ",FS_SMALL,FC_YELLOW);
+
+    name_typing = FALSE;
+  }
+}
+
+void DrawEditButton(unsigned long state)
+{
+  int i;
+  int xpos = 0, ypos = 1, xsize = 2, ysize = 3;
+  int cx = DOOR_GFX_PAGEX6, cy = DOOR_GFX_PAGEY2;
+  static int edit_pos[6][4] =
+  {
+    ED_BUTTON_CTRL_XPOS,ED_BUTTON_CTRL_YPOS,
+    ED_BUTTON_CTRL_XSIZE,ED_BUTTON_CTRL_YSIZE,
+
+    ED_BUTTON_FILL_XPOS,ED_BUTTON_FILL_YPOS,
+    ED_BUTTON_FILL_XSIZE,ED_BUTTON_FILL_YSIZE,
+
+    ED_BUTTON_LEFT_XPOS,ED_BUTTON_LEFT_YPOS,
+    ED_BUTTON_LEFT_XSIZE,ED_BUTTON_LEFT_YSIZE,
+
+    ED_BUTTON_UP_XPOS,ED_BUTTON_UP_YPOS,
+    ED_BUTTON_UP_XSIZE,ED_BUTTON_UP_YSIZE,
+
+    ED_BUTTON_DOWN_XPOS,ED_BUTTON_DOWN_YPOS,
+    ED_BUTTON_DOWN_XSIZE,ED_BUTTON_DOWN_YSIZE,
+
+    ED_BUTTON_RIGHT_XPOS,ED_BUTTON_RIGHT_YPOS,
+    ED_BUTTON_RIGHT_XSIZE,ED_BUTTON_RIGHT_YSIZE
+  };
+
+  if (state & ED_BUTTON_PRESSED)
+    cx = DOOR_GFX_PAGEX5;
+
+  for(i=0;i<6;i++)
+  {
+    if (state & (1<<i))
+      XCopyArea(display,pix[PIX_DOOR],drawto,gc,
+               cx + edit_pos[i][xpos],
+               cy + edit_pos[i][ypos],
+               edit_pos[i][xsize],
+               edit_pos[i][ysize],
+               VX + edit_pos[i][xpos],
+               VY + edit_pos[i][ypos]);
+  }
+
+  redraw_mask |= REDRAW_DOOR_2;
+}
+
+void DrawCtrlButton(unsigned long state)
+{
+  int i;
+  int xpos = 0, ypos = 1, xsize = 2, ysize = 3;
+  int cx = DOOR_GFX_PAGEX4, cy = DOOR_GFX_PAGEY1+80;
+  static int edit_pos[4][4] =
+  {
+    ED_BUTTON_EDIT_XPOS,ED_BUTTON_EDIT_YPOS,
+    ED_BUTTON_EDIT_XSIZE,ED_BUTTON_EDIT_YSIZE,
+
+    ED_BUTTON_CLEAR_XPOS,ED_BUTTON_CLEAR_YPOS,
+    ED_BUTTON_CLEAR_XSIZE,ED_BUTTON_CLEAR_YSIZE,
+
+    ED_BUTTON_UNDO_XPOS,ED_BUTTON_UNDO_YPOS,
+    ED_BUTTON_UNDO_XSIZE,ED_BUTTON_UNDO_YSIZE,
+
+    ED_BUTTON_EXIT_XPOS,ED_BUTTON_EXIT_YPOS,
+    ED_BUTTON_EXIT_XSIZE,ED_BUTTON_EXIT_YSIZE
+  };
+
+  if (state & ED_BUTTON_PRESSED)
+    cx = DOOR_GFX_PAGEX3;
+
+  for(i=0;i<4;i++)
+  {
+    if (state & (1<<(i+6)))
+      XCopyArea(display,pix[PIX_DOOR],drawto,gc,
+               cx + edit_pos[i][xpos],
+               cy + edit_pos[i][ypos],
+               edit_pos[i][xsize],
+               edit_pos[i][ysize],
+               VX + edit_pos[i][xpos],
+               VY + edit_pos[i][ypos]);
+  }
+
+  redraw_mask |= REDRAW_DOOR_2;
+}
+
+void DrawElemButton(int button_nr, int button_state)
+{
+  int xpos = 0, ypos = 1, xsize = 2, ysize = 3;
+  int cx = DOOR_GFX_PAGEX6, cy = DOOR_GFX_PAGEY1;
+  int from_x, from_y, to_x,to_y, size_x, size_y;
+  static int edit_pos[3][4] =
+  {
+    ED_BUTTON_EUP_XPOS,ED_BUTTON_EUP_YPOS,
+    ED_BUTTON_EUP_XSIZE,ED_BUTTON_EUP_YSIZE,
+
+    ED_BUTTON_EDOWN_XPOS,ED_BUTTON_EDOWN_YPOS,
+    ED_BUTTON_EDOWN_XSIZE,ED_BUTTON_EDOWN_YSIZE,
+
+    ED_BUTTON_ELEM_XPOS,ED_BUTTON_ELEM_YPOS,
+    ED_BUTTON_ELEM_XSIZE,ED_BUTTON_ELEM_YSIZE
+  };
+
+  if (button_nr<ED_BUTTON_ELEM)
+  {
+    int pos = button_nr;
+
+    from_x = cx + edit_pos[pos][xpos];
+    from_y = cy + edit_pos[pos][ypos];
+    size_x = edit_pos[pos][xsize];
+    size_y = edit_pos[pos][ysize];
+    to_x   = DX + edit_pos[pos][xpos];
+    to_y   = DY + edit_pos[pos][ypos];
+
+    if (button_state & ED_BUTTON_PRESSED)
+    {
+      if (button_nr==ED_BUTTON_EUP)
+       from_y = cy + ED_BUTTON_EUP_Y2POS;
+      else
+       from_y = cy + ED_BUTTON_EDOWN_Y2POS;
+    }
+
+    XCopyArea(display,pix[PIX_DOOR],drawto,gc,
+             from_x,from_y, size_x,size_y, to_x,to_y);
+  }
+  else
+  {
+    int pos = ED_BUTTON_ELEM;
+    int elem_pos = button_nr-ED_BUTTON_ELEM;
+    int x = elem_pos % MAX_ELEM_X;
+    int y = elem_pos / MAX_ELEM_X;
+    int graphic;
+    int shift = 0;
+
+    if (elem_pos+element_shift < elements_in_list)
+      graphic = el2gfx(editor_element[elem_pos+element_shift]);
+    else
+      graphic = GFX_LEERRAUM;
+
+    from_x = cx + edit_pos[pos][xpos];
+    from_y = cy + edit_pos[pos][ypos];
+    size_x = edit_pos[pos][xsize];
+    size_y = edit_pos[pos][ysize];
+    to_x   = DX + edit_pos[pos][xpos] + x * ED_BUTTON_ELEM_XSIZE;
+    to_y   = DY + edit_pos[pos][ypos] + y * ED_BUTTON_ELEM_YSIZE;
+
+    if (button_state & ED_BUTTON_PRESSED)
+    {
+      from_y = ED_BUTTON_ELEM_Y2POS;
+      shift = 1;
+    }
+
+    XCopyArea(display,pix[PIX_DOOR],drawto,gc,
+             from_x,from_y, size_x,size_y, to_x,to_y);
+
+    DrawMiniGraphicExtHiRes(drawto,gc,
+                           DX+ED_BUTTON_ELEM_XPOS+3+shift + 
+                           (elem_pos % MAX_ELEM_X)*ED_BUTTON_ELEM_XSIZE,
+                           DY+ED_BUTTON_ELEM_YPOS+3-shift +
+                           (elem_pos / MAX_ELEM_X)*ED_BUTTON_ELEM_YSIZE,
+                           graphic);
+  }
+
+  redraw_mask |= REDRAW_DOOR_1;
+}
+
+void DrawCountButton(int button_nr, int button_state)
+{
+  int from_x, from_y, to_x,to_y, size_x, size_y;
+
+  from_x =
+    DOOR_GFX_PAGEX4+(button_nr%2 ? ED_BUTTON_PLUS_XPOS : ED_BUTTON_MINUS_XPOS);
+  from_y = DOOR_GFX_PAGEY1 + ED_BUTTON_MINUS_YPOS;
+  size_x = ED_BUTTON_MINUS_XSIZE;
+  size_y = ED_BUTTON_MINUS_YSIZE;
+  to_x = (button_nr<32 ? ED_COUNT_GADGET_XPOS : ED_SIZE_GADGET_XPOS);
+  if (button_nr % 2)
+    to_x += (ED_BUTTON_PLUS_XPOS - ED_BUTTON_MINUS_XPOS);
+  to_y = (button_nr<32 ? ED_COUNT_GADGET_YPOS : ED_SIZE_GADGET_YPOS) +
+    ((button_nr<32 ? button_nr : button_nr-32)/2)*ED_COUNT_GADGET_YSIZE;
+
+  if (button_state & ED_BUTTON_PRESSED)
+    from_x -= DXSIZE;
+
+  XCopyArea(display,pix[PIX_DOOR],drawto,gc,
+           from_x,from_y, size_x,size_y, to_x,to_y);
+  XCopyArea(display,pix[PIX_DOOR],window,gc,
+           from_x,from_y, size_x,size_y, to_x,to_y);
+}
+
+int CheckEditButtons(int mx, int my, int button)
+{
+  int return_code = 0;
+  static int choice = -1;
+  static BOOL pressed = FALSE;
+  static int edit_button[6] =
+  {
+    ED_BUTTON_CTRL,
+    ED_BUTTON_FILL,
+    ED_BUTTON_LEFT,
+    ED_BUTTON_UP,
+    ED_BUTTON_DOWN,
+    ED_BUTTON_RIGHT
+  };
+
+  if (button)
+  {
+    if (!motion_status)                /* Maustaste neu gedrückt */
+    {
+      if (ON_EDIT_BUTTON(mx,my))
+      {
+       choice = EDIT_BUTTON(mx,my);
+       pressed = TRUE;
+       DrawEditButton(edit_button[choice] | ED_BUTTON_PRESSED);
+       if (edit_button[choice]!=ED_BUTTON_CTRL &&
+           edit_button[choice]!=ED_BUTTON_FILL)
+         return_code = 1<<choice;
+      }
+    }
+    else                       /* Mausbewegung bei gedrückter Maustaste */
+    {
+      if ((!ON_EDIT_BUTTON(mx,my) || EDIT_BUTTON(mx,my)!=choice) &&
+         choice>=0 && pressed)
+      {
+       pressed = FALSE;
+       DrawEditButton(edit_button[choice] | ED_BUTTON_RELEASED);
+      }
+      else if (ON_EDIT_BUTTON(mx,my) && EDIT_BUTTON(mx,my)==choice)
+      {
+       if (!pressed)
+         DrawEditButton(edit_button[choice] | ED_BUTTON_PRESSED);
+       pressed = TRUE;
+       if (edit_button[choice]!=ED_BUTTON_CTRL &&
+           edit_button[choice]!=ED_BUTTON_FILL)
+         return_code = 1<<choice;
+      }
+    }
+  }
+  else                         /* Maustaste wieder losgelassen */
+  {
+    if (ON_EDIT_BUTTON(mx,my) && EDIT_BUTTON(mx,my)==choice && pressed)
+    {
+      DrawEditButton(edit_button[choice] | ED_BUTTON_RELEASED);
+      if (edit_button[choice]==ED_BUTTON_CTRL ||
+         edit_button[choice]==ED_BUTTON_FILL)
+       return_code = 1<<choice;
+      choice = -1;
+      pressed = FALSE;
+    }
+    else
+    {
+      choice = -1;
+      pressed = FALSE;
+    }
+  }
+
+  BackToFront();
+  return(return_code);
+}
+
+int CheckCtrlButtons(int mx, int my, int button)
+{
+  int return_code = 0;
+  static int choice = -1;
+  static BOOL pressed = FALSE;
+  static int ctrl_button[4] =
+  {
+    ED_BUTTON_EDIT,
+    ED_BUTTON_CLEAR,
+    ED_BUTTON_UNDO,
+    ED_BUTTON_EXIT
+  };
+
+  if (button)
+  {
+    if (!motion_status)                /* Maustaste neu gedrückt */
+    {
+      if (ON_CTRL_BUTTON(mx,my))
+      {
+       choice = CTRL_BUTTON(mx,my);
+       pressed = TRUE;
+       DrawCtrlButton(ctrl_button[choice] | ED_BUTTON_PRESSED);
+      }
+    }
+    else                       /* Mausbewegung bei gedrückter Maustaste */
+    {
+      if ((!ON_CTRL_BUTTON(mx,my) || CTRL_BUTTON(mx,my)!=choice) &&
+         choice>=0 && pressed)
+      {
+       pressed = FALSE;
+       DrawCtrlButton(ctrl_button[choice] | ED_BUTTON_RELEASED);
+      }
+      else if (ON_CTRL_BUTTON(mx,my) && CTRL_BUTTON(mx,my)==choice && !pressed)
+      {
+       pressed = TRUE;
+       DrawCtrlButton(ctrl_button[choice] | ED_BUTTON_PRESSED);
+      }
+    }
+  }
+  else                         /* Maustaste wieder losgelassen */
+  {
+    if (ON_CTRL_BUTTON(mx,my) && CTRL_BUTTON(mx,my)==choice && pressed)
+    {
+      DrawCtrlButton(ctrl_button[choice] | ED_BUTTON_RELEASED);
+      return_code = 1<<(choice+6);
+      choice = -1;
+      pressed = FALSE;
+    }
+    else
+    {
+      choice = -1;
+      pressed = FALSE;
+    }
+  }
+
+  BackToFront();
+  return(return_code);
+}
+
+int CheckElemButtons(int mx, int my, int button)
+{
+  int return_code = -1;
+  static int choice = -1;
+  static BOOL pressed = FALSE;
+
+  if (button)
+  {
+    if (!motion_status)                /* Maustaste neu gedrückt */
+    {
+      if (ON_ELEM_BUTTON(mx,my))
+      {
+       choice = ELEM_BUTTON(mx,my);
+       pressed = TRUE;
+       DrawElemButton(choice,ED_BUTTON_PRESSED);
+       if (choice==ED_BUTTON_EUP ||
+           choice==ED_BUTTON_EDOWN)
+         return_code = choice;
+      }
+    }
+    else                       /* Mausbewegung bei gedrückter Maustaste */
+    {
+      if ((!ON_ELEM_BUTTON(mx,my) || ELEM_BUTTON(mx,my)!=choice) &&
+         choice>=0 && pressed)
+      {
+       pressed = FALSE;
+       DrawElemButton(choice,ED_BUTTON_RELEASED);
+      }
+      else if (ON_ELEM_BUTTON(mx,my) && ELEM_BUTTON(mx,my)==choice)
+      {
+       if (!pressed)
+         DrawElemButton(choice,ED_BUTTON_PRESSED);
+       pressed = TRUE;
+       if (choice==ED_BUTTON_EUP ||
+           choice==ED_BUTTON_EDOWN)
+         return_code = choice;
+      }
+    }
+  }
+  else                         /* Maustaste wieder losgelassen */
+  {
+    if (ON_ELEM_BUTTON(mx,my) && ELEM_BUTTON(mx,my)==choice && pressed)
+    {
+      DrawElemButton(choice,ED_BUTTON_RELEASED);
+      if (choice!=ED_BUTTON_EUP &&
+         choice!=ED_BUTTON_EDOWN)
+       return_code = choice;
+      choice = -1;
+      pressed = FALSE;
+    }
+    else
+    {
+      choice = -1;
+      pressed = FALSE;
+    }
+  }
+
+  BackToFront();
+  return(return_code);
+}
+
+int CheckCountButtons(int mx, int my, int button)
+{
+  int return_code = -1;
+  static int choice = -1;
+  static BOOL pressed = FALSE;
+
+  if (button)
+  {
+    if (!motion_status)                /* Maustaste neu gedrückt */
+    {
+      if (ON_COUNT_BUTTON(mx,my))
+      {
+       choice = COUNT_BUTTON(mx,my);
+       pressed = TRUE;
+       DrawCountButton(choice,ED_BUTTON_PRESSED);
+       return_code = choice;
+      }
+    }
+    else                       /* Mausbewegung bei gedrückter Maustaste */
+    {
+      if ((!ON_COUNT_BUTTON(mx,my) || COUNT_BUTTON(mx,my)!=choice) &&
+         choice>=0 && pressed)
+      {
+       pressed = FALSE;
+       DrawCountButton(choice,ED_BUTTON_RELEASED);
+      }
+      else if (ON_COUNT_BUTTON(mx,my) && COUNT_BUTTON(mx,my)==choice)
+      {
+       if (!pressed)
+         DrawCountButton(choice,ED_BUTTON_PRESSED);
+       pressed = TRUE;
+       return_code = choice;
+      }
+    }
+  }
+  else                         /* Maustaste wieder losgelassen */
+  {
+    if (ON_COUNT_BUTTON(mx,my) && COUNT_BUTTON(mx,my)==choice && pressed)
+    {
+      DrawCountButton(choice,ED_BUTTON_RELEASED);
+      choice = -1;
+      pressed = FALSE;
+    }
+    else
+    {
+      choice = -1;
+      pressed = FALSE;
+    }
+  }
+
+  BackToFront();
+  return(return_code);
+}
diff --git a/src/editor.h b/src/editor.h
new file mode 100644 (file)
index 0000000..d01f813
--- /dev/null
@@ -0,0 +1,312 @@
+/***********************************************************
+*  Rocks'n'Diamonds -- McDuffin Strikes Back!              *
+*----------------------------------------------------------*
+*  ©1995 Artsoft Development                               *
+*        Holger Schemel                                    *
+*        33659 Bielefeld-Senne                             *
+*        Telefon: (0521) 493245                            *
+*        eMail: aeglos@valinor.owl.de                      *
+*               aeglos@uni-paderborn.de                    *
+*               q99492@pbhrzx.uni-paderborn.de             *
+*----------------------------------------------------------*
+*  editor.h                                                *
+*                                                          *
+*  Letzte Aenderung: 15.06.1995                            *
+***********************************************************/
+
+#ifndef EDITOR_H
+#define EDITOR_H
+
+#include "main.h"
+
+/* sizes in the level editor */
+/* edit window */
+#define ED_WIN_MB_LEFT_XPOS    7
+#define ED_WIN_MB_LEFT_YPOS    6
+#define ED_WIN_LEVELNR_XPOS    77
+#define ED_WIN_LEVELNR_YPOS    7
+#define ED_WIN_MB_MIDDLE_XPOS  7
+#define ED_WIN_MB_MIDDLE_YPOS  258
+#define ED_WIN_MB_RIGHT_XPOS   77
+#define ED_WIN_MB_RIGHT_YPOS   258
+
+#define ED_BUTTON_EUP_XPOS     35
+#define ED_BUTTON_EUP_YPOS     5
+#define ED_BUTTON_EUP_XSIZE    30
+#define ED_BUTTON_EUP_YSIZE    25
+#define ED_BUTTON_EDOWN_XPOS   35
+#define ED_BUTTON_EDOWN_YPOS   250
+#define ED_BUTTON_EDOWN_XSIZE  30
+#define ED_BUTTON_EDOWN_YSIZE  25
+#define ED_BUTTON_ELEM_XPOS    6
+#define ED_BUTTON_ELEM_YPOS    30
+#define ED_BUTTON_ELEM_XSIZE   22
+#define ED_BUTTON_ELEM_YSIZE   22
+
+#define MAX_ELEM_X             4
+#define MAX_ELEM_Y             10
+
+#define ED_BUTTON_EUP_Y2POS    140
+#define ED_BUTTON_EDOWN_Y2POS  165
+#define ED_BUTTON_ELEM_Y2POS   190
+
+#define ED_BUTTON_CTRL_XPOS    5
+#define ED_BUTTON_CTRL_YPOS    5
+#define ED_BUTTON_CTRL_XSIZE   90
+#define ED_BUTTON_CTRL_YSIZE   30
+#define ED_BUTTON_FILL_XPOS    5
+#define ED_BUTTON_FILL_YPOS    35
+#define ED_BUTTON_FILL_XSIZE   90
+#define ED_BUTTON_FILL_YSIZE   20
+#define ED_BUTTON_LEFT_XPOS    5
+#define ED_BUTTON_LEFT_YPOS    65
+#define ED_BUTTON_LEFT_XSIZE   30
+#define ED_BUTTON_LEFT_YSIZE   20
+#define ED_BUTTON_UP_XPOS      35
+#define ED_BUTTON_UP_YPOS      55
+#define ED_BUTTON_UP_XSIZE     30
+#define ED_BUTTON_UP_YSIZE     20
+#define ED_BUTTON_DOWN_XPOS    35
+#define ED_BUTTON_DOWN_YPOS    75
+#define ED_BUTTON_DOWN_XSIZE   30
+#define ED_BUTTON_DOWN_YSIZE   20
+#define ED_BUTTON_RIGHT_XPOS   65
+#define ED_BUTTON_RIGHT_YPOS   65
+#define ED_BUTTON_RIGHT_XSIZE  30
+#define ED_BUTTON_RIGHT_YSIZE  20
+
+#define ED_BUTTON_EDIT_XPOS    5
+#define ED_BUTTON_EDIT_YPOS    5
+#define ED_BUTTON_EDIT_XSIZE   90
+#define ED_BUTTON_EDIT_YSIZE   30
+#define ED_BUTTON_CLEAR_XPOS   5
+#define ED_BUTTON_CLEAR_YPOS   35
+#define ED_BUTTON_CLEAR_XSIZE  90
+#define ED_BUTTON_CLEAR_YSIZE  20
+#define ED_BUTTON_UNDO_XPOS    5
+#define ED_BUTTON_UNDO_YPOS    55
+#define ED_BUTTON_UNDO_XSIZE   90
+#define ED_BUTTON_UNDO_YSIZE   20
+#define ED_BUTTON_EXIT_XPOS    5
+#define ED_BUTTON_EXIT_YPOS    75
+#define ED_BUTTON_EXIT_XSIZE   90
+#define ED_BUTTON_EXIT_YSIZE   20
+
+#define ED_BUTTON_MINUS_XPOS   2
+#define ED_BUTTON_MINUS_YPOS   60
+#define ED_BUTTON_MINUS_XSIZE  20
+#define ED_BUTTON_MINUS_YSIZE  20
+#define ED_WIN_COUNT_XPOS      (ED_BUTTON_MINUS_XPOS+ED_BUTTON_MINUS_XSIZE+2)
+#define ED_WIN_COUNT_YPOS      ED_BUTTON_MINUS_YPOS
+#define ED_WIN_COUNT_XSIZE     52
+#define ED_WIN_COUNT_YSIZE     ED_BUTTON_MINUS_YSIZE
+#define ED_BUTTON_PLUS_XPOS    (ED_WIN_COUNT_XPOS+ED_WIN_COUNT_XSIZE+2)
+#define ED_BUTTON_PLUS_YPOS    ED_BUTTON_MINUS_YPOS
+#define ED_BUTTON_PLUS_XSIZE   ED_BUTTON_MINUS_XSIZE
+#define ED_BUTTON_PLUS_YSIZE   ED_BUTTON_MINUS_YSIZE
+
+#define ED_COUNT_GADGET_XPOS   16
+#define ED_COUNT_GADGET_YPOS   (16+3*MINI_TILEY+64)
+#define ED_COUNT_GADGET_YSIZE  (ED_BUTTON_MINUS_YSIZE+4)
+#define ED_COUNT_TEXT_XPOS     (ED_COUNT_GADGET_XPOS+DXSIZE+10)
+#define ED_COUNT_TEXT_YPOS     (ED_COUNT_GADGET_YPOS+3)
+#define ED_COUNT_TEXT_YSIZE    ED_COUNT_GADGET_YSIZE
+#define ED_COUNT_VALUE_XPOS    (ED_COUNT_GADGET_XPOS+ED_BUTTON_MINUS_XSIZE+7)
+#define ED_COUNT_VALUE_YPOS    ED_COUNT_TEXT_YPOS
+#define ED_SIZE_GADGET_XPOS    (SX+21*MINI_TILEX)
+#define ED_SIZE_GADGET_YPOS    (SY+4*MINI_TILEY)
+#define ED_SIZE_GADGET_YSIZE   (ED_BUTTON_MINUS_YSIZE+4)
+#define ED_SIZE_TEXT_XPOS      (ED_SIZE_GADGET_XPOS+DXSIZE+10)
+#define ED_SIZE_TEXT_YPOS      (ED_SIZE_GADGET_YPOS+3)
+#define ED_SIZE_TEXT_YSIZE     ED_COUNT_GADGET_YSIZE
+#define ED_SIZE_VALUE_XPOS     (ED_SIZE_GADGET_XPOS+ED_BUTTON_MINUS_XSIZE+7)
+#define ED_SIZE_VALUE_YPOS     ED_SIZE_TEXT_YPOS
+
+#define ON_EDIT_BUTTON(x,y)    (((x)>=(VX+ED_BUTTON_CTRL_XPOS) &&      \
+                                 (x)< (VX+ED_BUTTON_CTRL_XPOS +        \
+                                       ED_BUTTON_CTRL_XSIZE) &&        \
+                                 (y)>=(VY+ED_BUTTON_CTRL_YPOS) &&      \
+                                 (y)< (VY+ED_BUTTON_CTRL_YPOS +        \
+                                       ED_BUTTON_CTRL_YSIZE +          \
+                                       ED_BUTTON_FILL_YSIZE)) ||       \
+                                ((x)>=(VX+ED_BUTTON_LEFT_XPOS) &&      \
+                                 (x)< (VX+ED_BUTTON_LEFT_XPOS +        \
+                                       ED_BUTTON_LEFT_XSIZE +          \
+                                       ED_BUTTON_UP_XSIZE +            \
+                                       ED_BUTTON_RIGHT_XSIZE) &&       \
+                                 (y)>=(VY+ED_BUTTON_LEFT_YPOS) &&      \
+                                 (y)< (VY+ED_BUTTON_LEFT_YPOS +        \
+                                       ED_BUTTON_LEFT_YSIZE)) ||       \
+                                ((x)>=(VX+ED_BUTTON_UP_XPOS) &&        \
+                                 (x)< (VX+ED_BUTTON_UP_XPOS +          \
+                                       ED_BUTTON_UP_XSIZE) &&          \
+                                 (y)>=(VY+ED_BUTTON_UP_YPOS) &&        \
+                                 (y)< (VY+ED_BUTTON_UP_YPOS +          \
+                                       ED_BUTTON_UP_YSIZE +            \
+                                       ED_BUTTON_DOWN_YSIZE)))
+
+#define ON_CTRL_BUTTON(x,y)    ((x)>=(VX+ED_BUTTON_EDIT_XPOS) &&       \
+                                (x)< (VX+ED_BUTTON_EDIT_XPOS +         \
+                                      ED_BUTTON_EDIT_XSIZE) &&         \
+                                (y)>=(VY+ED_BUTTON_EDIT_YPOS) &&       \
+                                (y)< (VY+ED_BUTTON_EDIT_YPOS +         \
+                                      ED_BUTTON_EDIT_YSIZE +           \
+                                      ED_BUTTON_CLEAR_YSIZE +          \
+                                      ED_BUTTON_UNDO_YSIZE +           \
+                                      ED_BUTTON_EXIT_YSIZE))
+
+#define ON_ELEM_BUTTON(x,y)    (((x)>=(DX+ED_BUTTON_EUP_XPOS) &&       \
+                                 (x)< (DX+ED_BUTTON_EUP_XPOS +         \
+                                       ED_BUTTON_EUP_XSIZE) &&         \
+                                 (y)>=(DY+ED_BUTTON_EUP_YPOS) &&       \
+                                 (y)< (DY+ED_BUTTON_EUP_YPOS +         \
+                                       ED_BUTTON_EUP_YSIZE)) ||        \
+                                ((x)>=(DX+ED_BUTTON_EDOWN_XPOS) &&     \
+                                 (x)< (DX+ED_BUTTON_EDOWN_XPOS +       \
+                                       ED_BUTTON_EDOWN_XSIZE) &&       \
+                                 (y)>=(DY+ED_BUTTON_EDOWN_YPOS) &&     \
+                                 (y)< (DY+ED_BUTTON_EDOWN_YPOS +       \
+                                       ED_BUTTON_EDOWN_YSIZE)) ||      \
+                                ((x)>=(DX+ED_BUTTON_ELEM_XPOS) &&      \
+                                 (x)< (DX+ED_BUTTON_ELEM_XPOS +        \
+                                       MAX_ELEM_X*ED_BUTTON_ELEM_XSIZE) && \
+                                 (y)>=(DY+ED_BUTTON_ELEM_YPOS) &&      \
+                                 (y)< (DY+ED_BUTTON_ELEM_YPOS +        \
+                                       MAX_ELEM_Y*ED_BUTTON_ELEM_YSIZE)))
+
+#define ON_COUNT_BUTTON(x,y)   (((((x)>=ED_COUNT_GADGET_XPOS &&        \
+                                   (x)<(ED_COUNT_GADGET_XPOS +         \
+                                        ED_BUTTON_MINUS_XSIZE)) ||     \
+                                  ((x)>=(ED_COUNT_GADGET_XPOS +        \
+                                         (ED_BUTTON_PLUS_XPOS -        \
+                                          ED_BUTTON_MINUS_XPOS)) &&    \
+                                   (x)<(ED_COUNT_GADGET_XPOS +         \
+                                        (ED_BUTTON_PLUS_XPOS -         \
+                                         ED_BUTTON_MINUS_XPOS) +       \
+                                        ED_BUTTON_PLUS_XSIZE))) &&     \
+                                 ((y)>=ED_COUNT_GADGET_YPOS &&         \
+                                  (y)<(ED_COUNT_GADGET_YPOS +          \
+                                       16*ED_COUNT_GADGET_YSIZE)) &&   \
+                                 (((y)-ED_COUNT_GADGET_YPOS) %         \
+                                  ED_COUNT_GADGET_YSIZE) <             \
+                                 ED_BUTTON_MINUS_YSIZE) ||             \
+                                ((((x)>=ED_SIZE_GADGET_XPOS &&         \
+                                   (x)<(ED_SIZE_GADGET_XPOS +          \
+                                        ED_BUTTON_MINUS_XSIZE)) ||     \
+                                  ((x)>=(ED_SIZE_GADGET_XPOS +         \
+                                         (ED_BUTTON_PLUS_XPOS -        \
+                                          ED_BUTTON_MINUS_XPOS)) &&    \
+                                   (x)<(ED_SIZE_GADGET_XPOS +          \
+                                        (ED_BUTTON_PLUS_XPOS -         \
+                                         ED_BUTTON_MINUS_XPOS) +       \
+                                        ED_BUTTON_PLUS_XSIZE))) &&     \
+                                 ((y)>=ED_SIZE_GADGET_YPOS &&          \
+                                  (y)<(ED_SIZE_GADGET_YPOS +           \
+                                       2*ED_SIZE_GADGET_YSIZE)) &&     \
+                                 (((y)-ED_SIZE_GADGET_YPOS) %          \
+                                  ED_SIZE_GADGET_YSIZE) <              \
+                                 ED_BUTTON_MINUS_YSIZE))
+
+#define EDIT_BUTTON(x,y)       (((y) < (VY + ED_BUTTON_CTRL_YPOS +     \
+                                        ED_BUTTON_CTRL_YSIZE)) ? 0 :   \
+                                ((y) < (VY + ED_BUTTON_CTRL_YPOS +     \
+                                        ED_BUTTON_CTRL_YSIZE +         \
+                                        ED_BUTTON_FILL_YSIZE)) ? 1 :   \
+                                ((x) < (VX + ED_BUTTON_LEFT_XPOS +     \
+                                        ED_BUTTON_LEFT_XSIZE) ? 2 :    \
+                                 (x) > (VX + ED_BUTTON_LEFT_XPOS +     \
+                                        ED_BUTTON_LEFT_XSIZE +         \
+                                        ED_BUTTON_UP_XSIZE) ? 5 :      \
+                                 3+(((y)-(VY + ED_BUTTON_CTRL_YPOS +   \
+                                          ED_BUTTON_CTRL_YSIZE +       \
+                                          ED_BUTTON_FILL_YSIZE)) /     \
+                                    ED_BUTTON_UP_YSIZE)))
+
+#define CTRL_BUTTON(x,y)       (((y) < (VY + ED_BUTTON_EDIT_YPOS +     \
+                                        ED_BUTTON_EDIT_YSIZE)) ? 0 :   \
+                                1+(((y)-(VY + ED_BUTTON_EDIT_YPOS +    \
+                                        ED_BUTTON_EDIT_YSIZE)) /       \
+                                   ED_BUTTON_CLEAR_YSIZE))
+
+#define ELEM_BUTTON(x,y)       (((y) < (DY + ED_BUTTON_EUP_YPOS +      \
+                                        ED_BUTTON_EUP_YSIZE)) ? 0 :    \
+                                ((y) > (DY + ED_BUTTON_EDOWN_YPOS)) ? 1 : \
+                                2+(((y) - (DY + ED_BUTTON_ELEM_YPOS)) /   \
+                                ED_BUTTON_ELEM_YSIZE)*MAX_ELEM_X +     \
+                                ((x) - (DX + ED_BUTTON_ELEM_XPOS)) /   \
+                                ED_BUTTON_ELEM_XSIZE)
+
+#define COUNT_BUTTON(x,y)      ((x) < ED_SIZE_GADGET_XPOS ?            \
+                                ((((y) - ED_COUNT_GADGET_YPOS) /       \
+                                  ED_COUNT_GADGET_YSIZE)*2 +           \
+                                 ((x) < (ED_COUNT_GADGET_XPOS +        \
+                                         ED_BUTTON_MINUS_XSIZE) ? 0 : 1)) : \
+                                32+((((y) - ED_SIZE_GADGET_YPOS) /     \
+                                     ED_SIZE_GADGET_YSIZE)*2 +         \
+                                    ((x) < (ED_SIZE_GADGET_XPOS +      \
+                                            ED_BUTTON_MINUS_XSIZE) ? 0 : 1)))
+
+/* values for asking control */
+#define ED_BUTTON_CTRL         (1L<<0)
+#define ED_BUTTON_FILL         (1L<<1)
+#define ED_BUTTON_LEFT         (1L<<2)
+#define ED_BUTTON_UP           (1L<<3)
+#define ED_BUTTON_DOWN         (1L<<4)
+#define ED_BUTTON_RIGHT                (1L<<5)
+#define ED_BUTTON_EDIT         (1L<<6)
+#define ED_BUTTON_CLEAR                (1L<<7)
+#define ED_BUTTON_UNDO         (1L<<8)
+#define ED_BUTTON_EXIT         (1L<<9)
+
+#define ED_BUTTON_PRESSED      (1L<<10)
+#define ED_BUTTON_RELEASED     (1L<<11)
+
+#define ED_BUTTON_EUP          0
+#define ED_BUTTON_EDOWN                1
+#define ED_BUTTON_ELEM         2
+
+#if 0
+
+/* OBSOLETE *********************** */
+
+/* sizes in the level editor */
+#define ED_PFEIL_XSIZE  46
+#define ED_PFEIL_YSIZE  19
+#define ED_ZEIT_XSIZE   20
+#define ED_ZEIT_YSIZE   20
+#define ED_CLEX_XSIZE   46
+#define ED_CLEX_YSIZE   18
+#define ED_BUT_CLEX_Y   (DYSIZE-2-ED_CLEX_YSIZE)
+#define ED_BUT_ZEIT_Y   (ED_BUT_CLEX_Y-2-ED_ZEIT_YSIZE)
+#define ED_BUT_PFEIL_Y  (ED_BUT_ZEIT_Y-2-ED_PFEIL_YSIZE)
+#define ED_BUT_ZEIT2_X  (ED_ZEIT_XSIZE+10)
+#define ED_BUT_ZEIT2_Y  (ED_BUT_ZEIT_Y+4)
+#define ED_BUT_X        2
+#define ED_BUT_Y        ED_BUT_PFEIL_Y
+
+/* OBSOLETE *********************** */
+
+#endif
+
+
+/* other constants for the editor */
+#define ED_SCROLL_NO           0
+#define ED_SCROLL_LEFT         1
+#define ED_SCROLL_RIGHT                2
+#define ED_SCROLL_UP           4
+#define ED_SCROLL_DOWN         8
+
+void DrawLevelEd(void);
+void ScrollMiniLevel(int, int, int);
+void LevelEd(int, int, int);
+void LevelNameTyping(KeySym);
+void DrawEditButton(unsigned long state);
+void DrawCtrlButton(unsigned long state);
+void DrawElemButton(int, int);
+void DrawCountButton(int, int);
+int CheckEditButtons(int, int, int);
+int CheckCtrlButtons(int, int, int);
+int CheckElemButtons(int, int, int);
+int CheckCountButtons(int, int, int);
+
+#endif
diff --git a/src/events.c b/src/events.c
new file mode 100644 (file)
index 0000000..1e8fcd1
--- /dev/null
@@ -0,0 +1,701 @@
+/***********************************************************
+*  Rocks'n'Diamonds -- McDuffin Strikes Back!              *
+*----------------------------------------------------------*
+*  ©1995 Artsoft Development                               *
+*        Holger Schemel                                    *
+*        33659 Bielefeld-Senne                             *
+*        Telefon: (0521) 493245                            *
+*        eMail: aeglos@valinor.owl.de                      *
+*               aeglos@uni-paderborn.de                    *
+*               q99492@pbhrzx.uni-paderborn.de             *
+*----------------------------------------------------------*
+*  events.c                                                *
+*                                                          *
+*  Letzte Aenderung: 15.06.1995                            *
+***********************************************************/
+
+#include "events.h"
+#include "screens.h"
+#include "tools.h"
+#include "game.h"
+#include "editor.h"
+
+void EventLoop(void)
+{
+  while(1)
+  {
+    if (XPending(display))     /* got an event */
+    {
+      XEvent event;
+
+      XNextEvent(display, &event);
+
+      switch(event.type)
+      {
+       case Expose:
+         HandleExposeEvent((XExposeEvent *) &event);
+         break;
+       case UnmapNotify:
+         SleepWhileUnmapped();
+         break;
+       case ButtonPress:
+         HandleButtonEvent((XButtonEvent *) &event);
+         break;
+       case ButtonRelease:
+         HandleButtonEvent((XButtonEvent *) &event);
+         break;
+       case MotionNotify:
+         HandleMotionEvent((XMotionEvent *) &event);
+         break;
+       case KeyPress:
+         HandleKeyEvent((XKeyEvent *) &event);
+         break;
+       case KeyRelease:
+         HandleKeyEvent((XKeyEvent *) &event);
+         break;
+       case FocusIn:
+         HandleFocusEvent(FOCUS_IN);
+         break;
+       case FocusOut:
+         HandleFocusEvent(FOCUS_OUT);
+         break;
+       default:
+         break;
+      }
+    }
+    else                       /* got no event, but don't be lazy... */
+    {
+      HandleNoXEvent();
+
+      if (game_status!=PLAYING)
+       Delay(10000);           /* don't use all CPU time when idle */
+    }
+
+    if (game_status==EXITGAME)
+      return;
+  }
+}
+
+void ClearEventQueue()
+{
+  while(XPending(display))
+  {
+    XEvent event;
+
+    XNextEvent(display, &event);
+
+    switch(event.type)
+    {
+      case Expose:
+        HandleExposeEvent((XExposeEvent *) &event);
+       break;
+      case UnmapNotify:
+       SleepWhileUnmapped();
+       break;
+      case ButtonRelease:
+       button_status = MB_RELEASED;
+       break;
+      case KeyRelease:
+       key_status = KEY_RELEASED;
+       break;
+      case FocusIn:
+       HandleFocusEvent(FOCUS_IN);
+       break;
+      case FocusOut:
+       HandleFocusEvent(FOCUS_OUT);
+       break;
+      default:
+       break;
+    }
+  }
+}
+
+void SleepWhileUnmapped()
+{
+  BOOL window_unmapped = TRUE;
+
+  XAutoRepeatOn(display);
+
+  while(window_unmapped)
+  {
+    XEvent event;
+
+    XNextEvent(display, &event);
+
+    switch(event.type)
+    {
+      case Expose:
+        HandleExposeEvent((XExposeEvent *) &event);
+       break;
+      case ButtonRelease:
+       button_status = MB_RELEASED;
+       break;
+      case KeyRelease:
+       key_status = KEY_RELEASED;
+       break;
+      case MapNotify:
+       window_unmapped = FALSE;
+       break;
+      default:
+       break;
+    }
+  }
+
+  if (game_status==PLAYING)
+    XAutoRepeatOff(display);
+}
+
+void HandleExposeEvent(XExposeEvent *event)
+{
+  int x = event->x, y = event->y;
+  int width = event->width, height = event->height;
+
+  XCopyArea(display,drawto,window,gc, x,y, width,height, x,y);
+
+  if (direct_draw_on && game_status==PLAYING)
+  {
+    int xx,yy;
+    int x1 = (x-SX)/TILEX, y1 = (y-SY)/TILEY;
+    int x2 = (x-SX+width)/TILEX, y2 = (y-SY+height)/TILEY;
+
+    for(xx=0;xx<SCR_FIELDX;xx++)
+      for(yy=0;yy<SCR_FIELDY;yy++)
+       if (xx>=x1 && xx<=x2 && yy>=y1 && yy<=y2)
+         DrawScreenField(xx,yy);
+    DrawLevelElement(JX,JY,EL_SPIELFIGUR);
+  }
+
+  XFlush(display);
+}
+
+void HandleButtonEvent(XButtonEvent *event)
+{
+  motion_status = FALSE;
+
+  if (event->type==ButtonPress)
+    button_status = event->button;
+  else
+    button_status = MB_RELEASED;
+
+  HandleButton(event->x, event->y, button_status);
+}
+
+void HandleMotionEvent(XMotionEvent *event)
+{
+  motion_status = TRUE;
+
+  HandleButton(event->x, event->y, button_status);
+}
+
+void HandleKeyEvent(XKeyEvent *event)
+{
+  static KeySym old_keycode = 0;
+  int new_keycode = event->keycode;
+  KeySym new_key = XLookupKeysym(event,event->state);
+  int new_key_status = (event->type==KeyPress ? KEY_PRESSED : KEY_RELEASED);
+
+  if (game_status==PLAYING &&
+      (old_keycode!=new_keycode || key_status!=new_key_status))
+  {
+    DigField(0,0,DF_NO_PUSH);
+    SnapField(0,0);
+  }
+
+  if (event->type==KeyPress)
+  {
+    key_status = KEY_PRESSED;
+    HandleKey(new_key);
+    old_keycode = new_keycode;
+  }
+  else if (key_status==KEY_PRESSED && old_keycode==new_keycode)
+    key_status = KEY_RELEASED;
+}
+
+void HandleFocusEvent(int focus_status)
+{
+  if (focus_status==FOCUS_OUT)
+    XAutoRepeatOn(display);
+  else if (game_status==PLAYING)
+    XAutoRepeatOff(display);
+}
+
+void HandleButton(int mx, int my, int button)
+{
+  static int old_mx = 0, old_my = 0;
+
+  if (mx<0 || my<0)
+  {
+    mx = old_mx;
+    my = old_my;
+  }
+  else
+  {
+    old_mx = mx;
+    old_my = my;
+
+    HandleVideoButtons(mx,my,button);
+    HandleSoundButtons(mx,my,button);
+    HandleGameButtons(mx,my,button);
+  }
+
+  switch(game_status)
+  {
+    case MAINMENU:
+      HandleMainMenu(mx,my,0,0,button);
+      break;
+    case TYPENAME:
+      HandleTypeName(0,XK_Return);
+      break;
+    case CHOOSELEVEL:
+      HandleChooseLevel(mx,my,0,0,button);
+      break;
+    case HALLOFFAME:
+      HandleHallOfFame(button);
+      break;
+    case LEVELED:
+      LevelEd(mx,my,button);
+      break;
+    case HELPSCREEN:
+      HandleHelpScreen(button);
+      break;
+    case SETUP:
+      HandleSetupScreen(mx,my,0,0,button);
+      break;
+    case PLAYING:
+      if (!LevelSolved)
+      {
+       switch(GameActions(mx,my,button))
+       {
+         case ACT_GAME_OVER:
+           game_status = MAINMENU;
+           DrawMainMenu();
+           BackToFront();
+           break;
+         case ACT_NEW_GAME:
+           game_status = PLAYING;
+           InitGame();
+           break;
+         case ACT_GO_ON:
+           break;
+         default:
+           break;
+       }
+      }
+      BackToFront();
+      Delay(10000);
+      break;
+    default:
+      break;
+  }
+}
+
+void HandleKey(KeySym key)
+{
+  static KeySym old_key = 0;
+
+  if (!key)
+    key = old_key;
+  else
+    old_key = key;
+
+  if (key==XK_Escape && game_status!=MAINMENU) /* quick quit to MAINMENU */
+  {
+    CloseDoor(DOOR_CLOSE_1 | DOOR_NO_DELAY);
+    game_status = MAINMENU;
+    DrawMainMenu();
+    return;
+  }
+
+  if (game_status==PLAYING && (tape.playing || tape.pausing))
+    return;
+
+  switch(game_status)
+  {
+    case TYPENAME:
+      HandleTypeName(0,key);
+      break;
+    case MAINMENU:
+    case CHOOSELEVEL:
+    case SETUP:
+    {
+      int dx = 0, dy = 0;
+
+      switch(key)
+      {
+       case XK_Return:
+         if (game_status==MAINMENU)
+           HandleMainMenu(0,0,0,0,MB_MENU_CHOICE);
+          else if (game_status==CHOOSELEVEL)
+            HandleChooseLevel(0,0,0,0,MB_MENU_CHOICE);
+         else if (game_status==SETUP)
+           HandleSetupScreen(0,0,0,0,MB_MENU_CHOICE);
+         break;
+       case XK_Left:
+#ifdef XK_KP_Left
+       case XK_KP_Left:
+#endif
+       case XK_KP_4:
+       case XK_J:
+       case XK_j:
+         dx = -1;
+         break;
+       case XK_Right:
+#ifdef XK_KP_Right
+       case XK_KP_Right:
+#endif
+       case XK_KP_6:
+       case XK_K:
+       case XK_k:
+         dx = 1;
+         break;
+       case XK_Up:
+#ifdef XK_KP_Up
+       case XK_KP_Up:
+#endif
+       case XK_KP_8:
+       case XK_I:
+       case XK_i:
+         dy = -1;
+         break;
+       case XK_Down:
+#ifdef XK_KP_Down
+       case XK_KP_Down:
+#endif
+       case XK_KP_2:
+       case XK_M:
+       case XK_m:
+         dy = 1;
+         break;
+       default:
+         break;
+      }
+
+      if (dx || dy)
+      {
+       if (game_status==MAINMENU)
+         HandleMainMenu(0,0,dx,dy,MB_MENU_MARK);
+        else if (game_status==CHOOSELEVEL)
+          HandleChooseLevel(0,0,dx,dy,MB_MENU_MARK);
+       else if (game_status==SETUP)
+         HandleSetupScreen(0,0,dx,dy,MB_MENU_MARK);
+      }
+      break;
+    }
+    case HELPSCREEN:
+      HandleHelpScreen(MB_RELEASED);
+      break;
+    case HALLOFFAME:
+      switch(key)
+      {
+       case XK_Return:
+         game_status = MAINMENU;
+         DrawMainMenu();
+         BackToFront();
+         break;
+       default:
+         break;
+      }
+      break;
+    case LEVELED:
+      LevelNameTyping(key);
+      break;
+    case PLAYING:
+    {
+      int mvx = 0, mvy = 0;
+      int sbx = 0, sby = 0;
+      int joy = 0;
+      BOOL bomb = FALSE;
+      BOOL moved = FALSE, snapped = FALSE, bombed = FALSE;
+
+      switch(key)
+      {
+       case XK_Left:           /* normale Richtungen */
+#ifdef XK_KP_Left
+       case XK_KP_Left:
+#endif
+       case XK_KP_4:
+       case XK_J:
+       case XK_j:
+         mvx = -1;
+         joy = JOY_LEFT;
+         break;
+       case XK_Right:
+#ifdef XK_KP_Right
+       case XK_KP_Right:
+#endif
+       case XK_KP_6:
+       case XK_K:
+       case XK_k:
+         mvx = 1;
+         joy = JOY_RIGHT;
+         break;
+       case XK_Up:
+#ifdef XK_KP_Up
+       case XK_KP_Up:
+#endif
+       case XK_KP_8:
+       case XK_I:
+       case XK_i:
+         mvy = -1;
+         joy = JOY_UP;
+         break;
+       case XK_Down:
+#ifdef XK_KP_Down
+       case XK_KP_Down:
+#endif
+       case XK_KP_2:
+       case XK_M:
+       case XK_m:
+         mvy = 1;
+         joy = JOY_DOWN;
+         break;
+#ifdef XK_KP_Home
+       case XK_KP_Home:        /* Diagonalrichtungen */
+#endif
+       case XK_KP_7:
+         mvx = -1;
+         mvy = -1;
+         joy = JOY_UP | JOY_LEFT;
+         break;
+#ifdef XK_KP_Page_Up
+       case XK_KP_Page_Up:
+#endif
+       case XK_KP_9:
+         mvx = 1;
+         mvy = -1;
+         joy = JOY_UP | JOY_RIGHT;
+         break;
+#ifdef XK_KP_End
+       case XK_KP_End:
+#endif
+       case XK_KP_1:
+         mvx = -1;
+         mvy = 1;
+         joy = JOY_DOWN | JOY_LEFT;
+         break;
+#ifdef XK_KP_Page_Down
+       case XK_KP_Page_Down:
+#endif
+       case XK_KP_3:
+         mvx = 1;
+         mvy = 1;
+         joy = JOY_DOWN | JOY_RIGHT;
+         break;
+       case XK_S:              /* Feld entfernen */
+       case XK_s:
+         sbx = -1;
+         joy = JOY_BUTTON_1 | JOY_LEFT;
+         break;
+       case XK_D:
+       case XK_d:
+         sbx = 1;
+         joy = JOY_BUTTON_1 | JOY_RIGHT;
+         break;
+       case XK_E:
+       case XK_e:
+         sby = -1;
+         joy = JOY_BUTTON_1 | JOY_UP;
+         break;
+       case XK_X:
+       case XK_x:
+         sby = 1;
+         joy = JOY_BUTTON_1 | JOY_DOWN;
+         break;
+       case XK_B:              /* Bombe legen */
+       case XK_b:
+         bomb = TRUE;
+         joy = JOY_BUTTON_2;
+         break;
+       case XK_Q:
+         Dynamite = 1000;
+         break;
+       default:
+         break;
+      }
+
+      if (mvx || mvy)
+       moved = MoveFigure(mvx,mvy);
+      else if (sbx || sby)
+       snapped = SnapField(sbx,sby);
+      else if (bomb)
+       bombed = PlaceBomb();
+
+      if (tape.recording && (moved || snapped || bombed))
+       TapeRecordAction(joy);
+
+      break;
+    }
+    default:
+      break;
+  }
+}
+
+void HandleNoXEvent()
+{
+  if (button_status)
+  {
+    HandleButton(-1,-1,button_status);
+    return;
+  }
+
+  switch(game_status)
+  {
+    case MAINMENU:
+    case CHOOSELEVEL:
+    case HALLOFFAME:
+    case HELPSCREEN:
+    case SETUP:
+      HandleJoystick();
+      break;
+    case PLAYING:
+      HandleJoystick();
+      if (key_status)
+       HandleKey(0);
+      if (game_status!=PLAYING)
+       break;
+
+      if (!LevelSolved)
+      {
+       switch(GameActions(0,0,MB_NOT_PRESSED))
+       {
+         case ACT_GAME_OVER:
+           game_status = MAINMENU;
+           DrawMainMenu();
+           BackToFront();
+           break;
+         case ACT_NEW_GAME:
+           game_status = PLAYING;
+           InitGame();
+           break;
+         case ACT_GO_ON:
+           break;
+         default:
+           break;
+       }
+      }
+
+      Delay(10000);
+
+      break;
+    default:
+      break;
+  }
+}
+
+void HandleJoystick()
+{
+  int joy      = Joystick();
+  int left     = joy & JOY_LEFT;
+  int right    = joy & JOY_RIGHT;
+  int up       = joy & JOY_UP;
+  int down     = joy & JOY_DOWN;
+  int button   = joy & JOY_BUTTON;
+  int button1  = joy & JOY_BUTTON_1;
+  int button2  = joy & JOY_BUTTON_2;
+  int newbutton        = (JoystickButton()==JOY_BUTTON_NEW_PRESSED);
+
+  if (button_status || key_status)
+    return;
+
+  switch(game_status)
+  {
+    case MAINMENU:
+    case CHOOSELEVEL:
+    case SETUP:
+    {
+      int dx = 0, dy = 0;
+      static long joystickmove_delay = 0;
+
+      if (DelayReached(&joystickmove_delay,15) || button)
+      {
+       if (left)
+         dx = -1;
+       else if (right)
+         dx = 1;
+       if (up)
+         dy = -1;
+       else if (down)
+         dy = 1;
+      }
+
+      if (game_status==MAINMENU)
+       HandleMainMenu(0,0,dx,dy,newbutton ? MB_MENU_CHOICE : MB_MENU_MARK);
+      else if (game_status==CHOOSELEVEL)
+        HandleChooseLevel(0,0,dx,dy,newbutton ? MB_MENU_CHOICE : MB_MENU_MARK);
+      else if (game_status==SETUP)
+       HandleSetupScreen(0,0,dx,dy,newbutton ? MB_MENU_CHOICE : MB_MENU_MARK);
+      break;
+    }
+    case HALLOFFAME:
+      HandleHallOfFame(!newbutton);
+      break;
+    case HELPSCREEN:
+      HandleHelpScreen(!newbutton);
+      break;
+    case PLAYING:
+    {
+      int mvx = 0, mvy = 0;
+      BOOL moved = FALSE, snapped = FALSE, bombed = FALSE;
+
+      if (tape.playing)
+      {
+       joy     = TapePlayAction();
+
+       left    = joy & JOY_LEFT;
+       right   = joy & JOY_RIGHT;
+       up      = joy & JOY_UP;
+       down    = joy & JOY_DOWN;
+       button  = joy & JOY_BUTTON;
+       button1 = joy & JOY_BUTTON_1;
+       button2 = joy & JOY_BUTTON_2;
+      }
+      else if (tape.pausing)
+       joy = 0;
+
+      if (!joy)
+      {
+       DigField(0,0,DF_NO_PUSH);
+       break;
+      }
+
+      if ((GameOver || LevelSolved) && newbutton)
+      {
+       CloseDoor(DOOR_CLOSE_1);
+       game_status = MAINMENU;
+       DrawMainMenu();
+       return;
+      }
+
+      if (left)
+       mvx = -1;
+      else if (right)
+       mvx = 1;
+      if (up)
+       mvy = -1;
+      else if (down)
+       mvy = 1;
+
+      if (button1)
+       snapped = SnapField(mvx,mvy);
+      else
+      {
+       if (button2)
+         bombed = PlaceBomb();
+       moved = MoveFigure(mvx,mvy);
+      }
+
+      if (tape.recording && (moved || snapped || bombed))
+      {
+       if (bombed && !moved)
+         joy &= JOY_BUTTON;
+       TapeRecordAction(joy);
+      }
+      else if (tape.playing && snapped)
+       SnapField(0,0);
+
+      break;
+    }
+    default:
+      break;
+  }
+}
diff --git a/src/events.h b/src/events.h
new file mode 100644 (file)
index 0000000..539db84
--- /dev/null
@@ -0,0 +1,37 @@
+/***********************************************************
+*  Rocks'n'Diamonds -- McDuffin Strikes Back!              *
+*----------------------------------------------------------*
+*  ©1995 Artsoft Development                               *
+*        Holger Schemel                                    *
+*        33659 Bielefeld-Senne                             *
+*        Telefon: (0521) 493245                            *
+*        eMail: aeglos@valinor.owl.de                      *
+*               aeglos@uni-paderborn.de                    *
+*               q99492@pbhrzx.uni-paderborn.de             *
+*----------------------------------------------------------*
+*  events.h                                                *
+*                                                          *
+*  Letzte Aenderung: 15.06.1995                            *
+***********************************************************/
+
+#ifndef EVENTS_H
+#define EVENTS_H
+
+#include "main.h"
+
+void EventLoop(void);
+void ClearEventQueue(void);
+void SleepWhileUnmapped(void);
+
+void HandleExposeEvent(XExposeEvent *);
+void HandleButtonEvent(XButtonEvent *);
+void HandleMotionEvent(XMotionEvent *);
+void HandleKeyEvent(XKeyEvent *);
+void HandleFocusEvent(int);
+void HandleNoXEvent(void);
+
+void HandleButton(int, int, int);
+void HandleKey(KeySym);
+void HandleJoystick();
+
+#endif
diff --git a/src/game.c b/src/game.c
new file mode 100644 (file)
index 0000000..6d5ca5b
--- /dev/null
@@ -0,0 +1,3098 @@
+/***********************************************************
+*  Rocks'n'Diamonds -- McDuffin Strikes Back!              *
+*----------------------------------------------------------*
+*  ©1995 Artsoft Development                               *
+*        Holger Schemel                                    *
+*        33659 Bielefeld-Senne                             *
+*        Telefon: (0521) 493245                            *
+*        eMail: aeglos@valinor.owl.de                      *
+*               aeglos@uni-paderborn.de                    *
+*               q99492@pbhrzx.uni-paderborn.de             *
+*----------------------------------------------------------*
+*  game.c                                                  *
+*                                                          *
+*  Letzte Aenderung: 15.06.1995                            *
+***********************************************************/
+
+#include "game.h"
+#include "misc.h"
+#include "tools.h"
+#include "screens.h"
+#include "sound.h"
+#include "init.h"
+
+BOOL CreateNewScoreFile()
+{
+  int i,j,k;
+  char filename[MAX_FILENAME];
+  char empty_alias[MAX_NAMELEN];
+  FILE *file;
+
+  sprintf(filename,"%s/%s/%s",
+         SCORE_PATH,leveldir[leveldir_nr].filename,SCORE_FILENAME);
+
+  if (!(file=fopen(filename,"w")))
+    return(FALSE);
+
+  for(i=0;i<MAX_NAMELEN;i++)
+    empty_alias[i] = 0;
+  strncpy(empty_alias,EMPTY_ALIAS,MAX_NAMELEN-1);
+
+  fputs(SCORE_COOKIE,file);            /* Formatkennung */
+  for(i=0;i<LEVELDIR_SIZE(leveldir[leveldir_nr]);i++)
+  {
+    for(j=0;j<MAX_SCORE_ENTRIES;j++)
+    {
+      for(k=0;k<MAX_NAMELEN;k++)
+       fputc(empty_alias[k],file);
+      fputc(0,file);
+      fputc(0,file);
+    }
+  }
+  fclose(file);
+
+  chmod(filename, SCORE_PERMS);
+  return(TRUE);
+}
+
+BOOL CreateNewNamesFile(int mode)
+{
+  char filename[MAX_FILENAME];
+  FILE *file;
+
+  if (mode==PLAYER_LEVEL)
+    sprintf(filename,"%s/%s/%s",
+           NAMES_PATH,leveldir[leveldir_nr].filename,NAMES_FILENAME);
+  else
+    sprintf(filename,"%s/%s",CONFIG_PATH,NAMES_FILENAME);
+
+  if (!(file=fopen(filename,"w")))
+    return(FALSE);
+
+  fputs(NAMES_COOKIE,file);            /* Formatkennung */
+  fclose(file);
+
+  chmod(filename, NAMES_PERMS);
+  return(TRUE);
+}
+
+void LoadLevelInfo()
+{
+  int i;
+  char filename[MAX_FILENAME];
+  char cookie[MAX_FILENAME];
+  FILE *file;
+
+  sprintf(filename,"%s/%s",LEVEL_PATH,LEVDIR_FILENAME);
+
+  if (!(file=fopen(filename,"r")))
+  {
+    fprintf(stderr,"%s: cannot load level info '%s'!\n",progname,filename);
+    CloseAll();
+  }
+
+  fscanf(file,"%s\n",cookie);
+  if (strcmp(cookie,LEVELDIR_COOKIE))  /* ungültiges Format? */
+  {
+    fprintf(stderr,"%s: wrong format of level info file!\n",progname);
+    fclose(file);
+    CloseAll();
+  }
+
+  num_leveldirs = 0;
+  leveldir_nr = 0;
+  for(i=0;i<MAX_LEVDIR_ENTRIES;i++)
+  {
+    fscanf(file,"%s",leveldir[i].filename);
+    fscanf(file,"%s",leveldir[i].name);
+    fscanf(file,"%d",&leveldir[i].num_ready);
+    fscanf(file,"%d",&leveldir[i].num_free);
+    if (feof(file))
+      break;
+
+    num_leveldirs++;
+  }
+
+  if (!num_leveldirs)
+  {
+    fprintf(stderr,"%s: empty level info '%s'!\n",progname,filename);
+    CloseAll();
+  }
+}
+
+void LoadLevel(int level_nr)
+{
+  int i,x,y;
+  char filename[MAX_FILENAME];
+  char cookie[MAX_FILENAME];
+  FILE *file;
+
+  sprintf(filename,"%s/%s/%d",
+         LEVEL_PATH,leveldir[leveldir_nr].filename,level_nr);
+
+  if (!(file=fopen(filename,"r")))
+  {
+/*
+    fprintf(stderr,"%s: cannot load level '%s'!\n",progname,filename);
+*/
+  }
+  else
+  {
+    fgets(cookie,LEVEL_COOKIE_LEN,file);
+    fgetc(file);
+    if (strcmp(cookie,LEVEL_COOKIE))   /* ungültiges Format? */
+    {
+      fprintf(stderr,"%s: wrong format of level file '%s'!\n",
+             progname,filename);
+      fclose(file);
+      file = NULL;
+    }
+  }
+
+  if (file)
+  {
+    lev_fieldx = level.fieldx = fgetc(file);
+    lev_fieldy = level.fieldy = fgetc(file);
+
+    level.time         = (fgetc(file)<<8) | fgetc(file);
+    level.edelsteine   = (fgetc(file)<<8) | fgetc(file);
+    for(i=0;i<MAX_LEVNAMLEN;i++)
+      level.name[i]    = fgetc(file);
+    for(i=0;i<MAX_SC_ENTRIES;i++)
+      level.score[i]   = fgetc(file);
+    for(i=0;i<4;i++)
+      for(y=0;y<3;y++)
+       for(x=0;x<3;x++)
+         level.mampfer_inhalt[i][x][y] = fgetc(file);
+    level.tempo_amoebe = fgetc(file);
+    level.dauer_sieb   = fgetc(file);
+    level.dauer_ablenk = fgetc(file);
+
+    for(i=0;i<19;i++)  /* Rest reserviert / Headergröße 80 Bytes */
+      fgetc(file);
+
+    for(y=0;y<lev_fieldy;y++) 
+      for(x=0;x<lev_fieldx;x++) 
+       Feld[x][y] = Ur[x][y] = fgetc(file);
+
+    fclose(file);
+
+    if (level.time<=10)        /* Mindestspieldauer */
+      level.time = 10;
+  }
+  else
+  {
+    lev_fieldx = level.fieldx = STD_LEV_FIELDX;
+    lev_fieldy = level.fieldy = STD_LEV_FIELDY;
+
+    level.time         = 100;
+    level.edelsteine   = 0;
+    strncpy(level.name,"Nameless Level",MAX_LEVNAMLEN-1);
+    for(i=0;i<MAX_SC_ENTRIES;i++)
+      level.score[i]   = 10;
+    for(i=0;i<4;i++)
+      for(y=0;y<3;y++)
+       for(x=0;x<3;x++)
+         level.mampfer_inhalt[i][x][y] = EL_FELSBROCKEN;
+    level.tempo_amoebe = 10;
+    level.dauer_sieb   = 10;
+    level.dauer_ablenk = 10;
+
+    for(y=0;y<STD_LEV_FIELDY;y++) 
+      for(x=0;x<STD_LEV_FIELDX;x++) 
+       Feld[x][y] = Ur[x][y] = EL_ERDREICH;
+    Feld[0][0] = Ur[0][0] = EL_SPIELFIGUR;
+    Feld[STD_LEV_FIELDX-1][STD_LEV_FIELDY-1] =
+      Ur[STD_LEV_FIELDX-1][STD_LEV_FIELDY-1] = EL_AUSGANG_ZU;
+  }
+}
+
+void LoadLevelTape(int level_nr)
+{
+  int i;
+  char filename[MAX_FILENAME];
+  char cookie[MAX_FILENAME];
+  FILE *file;
+
+  sprintf(filename,"%s/%s/%d.tape",
+         LEVEL_PATH,leveldir[leveldir_nr].filename,level_nr);
+
+  if ((file=fopen(filename,"r")))
+  {
+    fgets(cookie,LEVELREC_COOKIE_LEN,file);
+    fgetc(file);
+    if (strcmp(cookie,LEVELREC_COOKIE))        /* ungültiges Format? */
+    {
+      fprintf(stderr,"%s: wrong format of level recording file '%s'!\n",
+             progname,filename);
+      fclose(file);
+      file = NULL;
+    }
+  }
+
+  if (!file)
+    return;
+
+  tape.random_seed =
+    (fgetc(file)<<24) | (fgetc(file)<<16) | (fgetc(file)<<8) | fgetc(file);
+  tape.date =
+    (fgetc(file)<<24) | (fgetc(file)<<16) | (fgetc(file)<<8) | fgetc(file);
+  tape.length =
+    (fgetc(file)<<24) | (fgetc(file)<<16) | (fgetc(file)<<8) | fgetc(file);
+
+  tape.level_nr = level_nr;
+  tape.counter = 0;
+  tape.recording = FALSE;
+  tape.playing = FALSE;
+  tape.pausing = FALSE;
+
+  for(i=0;i<tape.length;i++)
+  {
+    if (i>=MAX_TAPELEN)
+      break;
+    tape.pos[i].joystickdata = fgetc(file);
+    tape.pos[i].delay        = fgetc(file);
+    if (feof(file))
+      break;
+  }
+
+  if (i != tape.length)
+    fprintf(stderr,"%s: level recording file '%s' corrupted!\n",
+           progname,filename);
+
+  fclose(file);
+
+  master_tape = tape;
+}
+
+void LoadScore(int level_nr)
+{
+  int i,j;
+  char filename[MAX_FILENAME];
+  char cookie[MAX_FILENAME];
+  FILE *file;
+
+  sprintf(filename,"%s/%s/%s",
+         SCORE_PATH,leveldir[leveldir_nr].filename,SCORE_FILENAME);
+
+  if (!(file=fopen(filename,"r")))
+  {
+    if (!CreateNewScoreFile())
+    {
+      fprintf(stderr,"%s: cannot create score file '%s'!\n",
+             progname,filename);
+    }
+    else if (!(file=fopen(filename,"r"))) 
+    {
+      fprintf(stderr,"%s: cannot load score for level %d!\n",
+             progname,level_nr);
+    }
+  }
+
+  if (file)
+  {
+    fgets(cookie,SCORE_COOKIE_LEN,file);
+    if (strcmp(cookie,SCORE_COOKIE))   /* ungültiges Format? */
+    {
+      fprintf(stderr,"%s: wrong format of score file!\n",progname);
+      fclose(file);
+      file = NULL;
+    }
+  }
+
+  if (file)
+  {
+    fseek(file,
+         SCORE_COOKIE_LEN-1+level_nr*(MAX_SCORE_ENTRIES*(MAX_NAMELEN+2)),
+         SEEK_SET);
+    for(i=0;i<MAX_SCORE_ENTRIES;i++)
+    {
+      for(j=0;j<MAX_NAMELEN;j++)
+       highscore[i].Name[j] = fgetc(file);
+      highscore[i].Score = (fgetc(file)<<8) | fgetc(file);
+    }
+    fclose(file);
+  }
+  else
+  {
+    for(i=0;i<MAX_SCORE_ENTRIES;i++)
+    {
+      strcpy(highscore[i].Name,EMPTY_ALIAS);
+      highscore[i].Score = 0;
+    }
+  }
+}
+
+void LoadPlayerInfo(int mode)
+{
+  int i;
+  char filename[MAX_FILENAME];
+  char cookie[MAX_FILENAME];
+  FILE *file;
+  char *login_name = GetLoginName();
+  struct PlayerInfo default_player, new_player;
+
+  if (mode==PLAYER_LEVEL)
+    sprintf(filename,"%s/%s/%s",
+           NAMES_PATH,leveldir[leveldir_nr].filename,NAMES_FILENAME);
+  else
+    sprintf(filename,"%s/%s",CONFIG_PATH,NAMES_FILENAME);
+
+  for(i=0;i<MAX_NAMELEN;i++)
+    default_player.login_name[i] = default_player.alias_name[i] = 0;
+  strncpy(default_player.login_name,login_name,MAX_NAMELEN-1);
+  strncpy(default_player.alias_name,login_name,MAX_NAMELEN-1);
+  default_player.handicap = 0;
+  default_player.setup = DEFAULT_SETUP;
+  default_player.leveldir_nr = 0;
+
+  new_player = default_player;
+
+  if (!(file=fopen(filename,"r")))
+  {
+    if (!CreateNewNamesFile(mode))
+    {
+      fprintf(stderr,"%s: cannot create names file '%s'!\n",
+             progname,filename);
+    }
+    else if (!(file=fopen(filename,"r"))) 
+    {
+      fprintf(stderr,"%s: cannot load player information '%s'!\n",
+             progname,filename);
+    }
+  }
+
+  if (file)
+  {
+    fgets(cookie,NAMES_COOKIE_LEN,file);
+    if (strcmp(cookie,NAMES_COOKIE))   /* ungültiges Format? */
+    {
+      fprintf(stderr,"%s: wrong format of names file '%s'!\n",
+             progname,filename);
+      fclose(file);
+      file = NULL;
+    }
+  }
+
+  if (!file)
+  {
+    player = default_player;
+    level_nr = default_player.handicap;
+    return;
+  }
+
+  while(1)
+  {
+    for(i=0;i<MAX_NAMELEN;i++)
+      new_player.login_name[i] = fgetc(file);
+    for(i=0;i<MAX_NAMELEN;i++)
+      new_player.alias_name[i] = fgetc(file);
+    new_player.handicap = fgetc(file);
+    new_player.setup = (fgetc(file)<<8) | fgetc(file);
+    new_player.leveldir_nr = fgetc(file);
+
+    if (feof(file))            /* Spieler noch nicht in Liste enthalten */
+    {
+      new_player = default_player;
+
+      fclose(file);
+      if (!(file=fopen(filename,"a")))
+      {
+       fprintf(stderr,"%s: cannot append new player to names file '%s'!\n",
+               progname,filename);
+      }
+      else
+      {
+       for(i=0;i<MAX_NAMELEN;i++)
+         fputc(new_player.login_name[i],file);
+       for(i=0;i<MAX_NAMELEN;i++)
+         fputc(new_player.alias_name[i],file);
+       fputc(new_player.handicap,file);
+       fputc(new_player.setup / 256,file);
+       fputc(new_player.setup % 256,file);
+       fputc(new_player.leveldir_nr,file);
+      }
+      break;
+    }
+    else                       /* prüfen, ob Spieler in Liste enthalten */
+      if (!strncmp(new_player.login_name,login_name,MAX_NAMELEN-1))
+       break;
+  }
+
+  if (mode==PLAYER_SETUP)
+  {
+    player = new_player;
+    if (player.leveldir_nr < num_leveldirs)
+      leveldir_nr = player.leveldir_nr;
+    else
+      leveldir_nr = 0;
+  }
+  else
+    player.handicap = new_player.handicap;
+
+  level_nr = player.handicap;
+  fclose(file);
+}
+
+void SaveLevel(int level_nr)
+{
+  int i,x,y;
+  char filename[MAX_FILENAME];
+  FILE *file;
+
+  sprintf(filename,"%s/%s/%d",
+         LEVEL_PATH,leveldir[leveldir_nr].filename,level_nr);
+
+  if (!(file=fopen(filename,"w")))
+  {
+    fprintf(stderr,"%s: cannot save level file '%s'!\n",progname,filename);
+    return;
+  }
+
+  fputs(LEVEL_COOKIE,file);            /* Formatkennung */
+  fputc(0x0a,file);
+
+  fputc(level.fieldx,file);
+  fputc(level.fieldy,file);
+  fputc(level.time / 256,file);
+  fputc(level.time % 256,file);
+  fputc(level.edelsteine / 256,file);
+  fputc(level.edelsteine % 256,file);
+
+  for(i=0;i<MAX_LEVNAMLEN;i++)
+    fputc(level.name[i],file);
+  for(i=0;i<MAX_SC_ENTRIES;i++)
+    fputc(level.score[i],file);
+  for(i=0;i<4;i++)
+    for(y=0;y<3;y++)
+      for(x=0;x<3;x++)
+       fputc(level.mampfer_inhalt[i][x][y],file);
+  fputc(level.tempo_amoebe,file);
+  fputc(level.dauer_sieb,file);
+  fputc(level.dauer_ablenk,file);
+
+  for(i=0;i<19;i++)    /* Rest reserviert / Headergröße 80 Bytes */
+    fputc(0,file);
+
+  for(y=0;y<lev_fieldy;y++) 
+    for(x=0;x<lev_fieldx;x++) 
+      fputc(Ur[x][y],file);
+
+  fclose(file);
+
+  chmod(filename, LEVEL_PERMS);
+}
+
+void SaveLevelTape(int level_nr)
+{
+  int i;
+  char filename[MAX_FILENAME];
+  FILE *file;
+  BOOL new_tape = TRUE;
+
+  sprintf(filename,"%s/%s/%d.tape",
+         LEVEL_PATH,leveldir[leveldir_nr].filename,level_nr);
+
+  /* Testen, ob bereits eine Aufnahme existiert */
+  if ((file=fopen(filename,"r")))
+  {
+    new_tape = FALSE;
+    fclose(file);
+
+    if (!AreYouSure("Replace old tape ?",AYS_ASK))
+      return;
+  }
+
+  if (!(file=fopen(filename,"w")))
+  {
+    fprintf(stderr,"%s: cannot save level recording file '%s'!\n",
+           progname,filename);
+    return;
+  }
+
+  fputs(LEVELREC_COOKIE,file);         /* Formatkennung */
+  fputc(0x0a,file);
+
+  tape = master_tape;
+
+  fputc((tape.random_seed >> 24) & 0xff,file);
+  fputc((tape.random_seed >> 16) & 0xff,file);
+  fputc((tape.random_seed >>  8) & 0xff,file);
+  fputc((tape.random_seed >>  0) & 0xff,file);
+
+  fputc((tape.date >>  24) & 0xff,file);
+  fputc((tape.date >>  16) & 0xff,file);
+  fputc((tape.date >>   8) & 0xff,file);
+  fputc((tape.date >>   0) & 0xff,file);
+
+  fputc((tape.length >>  24) & 0xff,file);
+  fputc((tape.length >>  16) & 0xff,file);
+  fputc((tape.length >>   8) & 0xff,file);
+  fputc((tape.length >>   0) & 0xff,file);
+
+  for(i=0;i<tape.length;i++)
+  {
+    fputc(tape.pos[i].joystickdata,file);
+    fputc(tape.pos[i].delay,file);
+  }
+
+  fclose(file);
+
+  chmod(filename, LEVREC_PERMS);
+
+  if (new_tape)
+    AreYouSure("tape saved !",AYS_CONFIRM);
+}
+
+void SaveScore(int level_nr)
+{
+  int i,j;
+  char filename[MAX_FILENAME];
+  FILE *file;
+
+  sprintf(filename,"%s/%s/%s",
+         SCORE_PATH,leveldir[leveldir_nr].filename,SCORE_FILENAME);
+
+  if (!(file=fopen(filename,"r+")))
+  {
+    fprintf(stderr,"%s: cannot save score for level %d!\n",
+           progname,level_nr);
+    return;
+  }
+
+  fseek(file,
+       SCORE_COOKIE_LEN-1+level_nr*(MAX_SCORE_ENTRIES*(MAX_NAMELEN+2)),
+       SEEK_SET);
+  for(i=0;i<MAX_SCORE_ENTRIES;i++)
+  {
+    for(j=0;j<MAX_NAMELEN;j++)
+      fputc(highscore[i].Name[j],file);
+    fputc(highscore[i].Score / 256,file);
+    fputc(highscore[i].Score % 256,file);
+  }
+  fclose(file);
+}
+
+void SavePlayerInfo(int mode)
+{
+  int i;
+  char filename[MAX_FILENAME];
+  char cookie[MAX_FILENAME];
+  FILE *file;
+  struct PlayerInfo default_player;
+
+  if (mode==PLAYER_LEVEL)
+    sprintf(filename,"%s/%s/%s",
+           NAMES_PATH,leveldir[leveldir_nr].filename,NAMES_FILENAME);
+  else
+    sprintf(filename,"%s/%s",CONFIG_PATH,NAMES_FILENAME);
+
+  if (!(file=fopen(filename,"r+")))
+  {
+    fprintf(stderr,"%s: cannot save player information '%s'!\n",
+           progname,filename);
+    return;
+  }
+
+  fgets(cookie,NAMES_COOKIE_LEN,file);
+  if (strcmp(cookie,NAMES_COOKIE))     /* ungültiges Format? */
+  {
+    fprintf(stderr,"%s: wrong format of names file '%s'!\n",
+           progname,filename);
+    fclose(file);
+    return;
+  }
+
+  while(1)
+  {
+    for(i=0;i<MAX_NAMELEN;i++)
+      default_player.login_name[i] = fgetc(file);
+    for(i=0;i<MAX_NAMELEN;i++)
+      default_player.alias_name[i] = fgetc(file);
+    default_player.handicap = fgetc(file);
+    default_player.setup = (fgetc(file)<<8) | fgetc(file);
+    default_player.leveldir_nr = fgetc(file);
+
+    if (feof(file))            /* Spieler noch nicht in Liste enthalten */
+      break;
+    else                       /* prüfen, ob Spieler in Liste enthalten */
+      if (!strncmp(default_player.login_name,player.login_name,MAX_NAMELEN-1))
+      {
+       fseek(file,-(2*MAX_NAMELEN+1+2+1),SEEK_CUR);
+       break;
+      }
+  }
+
+  for(i=0;i<MAX_NAMELEN;i++)
+    fputc(player.login_name[i],file);
+  for(i=0;i<MAX_NAMELEN;i++)
+    fputc(player.alias_name[i],file);
+  fputc(player.handicap,file);
+  fputc(player.setup / 256,file);
+  fputc(player.setup % 256,file);
+  fputc(player.leveldir_nr,file);
+
+  fclose(file);
+}
+
+void GetPlayerConfig()
+{
+  int old_joystick_nr = joystick_nr;
+
+  if (sound_status==SOUND_OFF)
+    player.setup &= ~SETUP_SOUND;
+  if (!sound_loops_allowed)
+  {
+    player.setup &= ~SETUP_SOUND_LOOPS;
+    player.setup &= ~SETUP_SOUND_MUSIC;
+  }
+
+  sound_on = SETUP_SOUND_ON(player.setup);
+  sound_loops_on = SETUP_SOUND_LOOPS_ON(player.setup);
+  sound_music_on = SETUP_SOUND_MUSIC_ON(player.setup);
+  toons_on = SETUP_TOONS_ON(player.setup);
+  direct_draw_on = SETUP_DIRECT_DRAW_ON(player.setup);
+  fading_on = SETUP_FADING_ON(player.setup);
+  autorecord_on = SETUP_RECORD_EACH_GAME_ON(player.setup);
+  joystick_nr = SETUP_2ND_JOYSTICK_ON(player.setup);
+
+  if (joystick_nr != old_joystick_nr)
+  {
+    if (joystick_device)
+      close(joystick_device);
+    InitJoystick();
+  }
+}
+
+void InitGame()
+{
+  int x,y;
+
+  Dynamite = Score = 0;
+  Gems = level.edelsteine;
+  Key[0] = Key[1] = Key[2] = Key[3] = FALSE;
+  MampferNr = 0;
+  TimeLeft = level.time;
+  CheckMoving = TRUE;
+  CheckExploding = FALSE;
+  LevelSolved = GameOver = SiebAktiv = FALSE;
+  JX = JY = 0;
+  ZX = ZY = -1;
+
+  if (tape.recording)
+    TapeStartRecording();
+  else if (tape.playing)
+    TapeStartPlaying();
+
+  DigField(0,0,DF_NO_PUSH);
+  SnapField(0,0);
+
+  for(y=0;y<lev_fieldy;y++) for(x=0;x<lev_fieldx;x++)
+  {
+    Feld[x][y]=Ur[x][y];
+    MovPos[x][y]=MovDir[x][y]=MovDelay[x][y]=0;
+    Store[x][y]=Store2[x][y]=Frame[x][y]=0;
+
+    switch(Feld[x][y])
+    {
+      case EL_SPIELFIGUR:
+      case EL_SPIELER1:
+       Feld[x][y] = EL_LEERRAUM;
+       JX = x;
+       JY = y;
+       break;
+      case EL_SPIELER2:
+       Feld[x][y] = EL_LEERRAUM;
+       break;
+      case EL_BADEWANNE:
+       if (x<lev_fieldx-1 && Feld[x+1][y]==EL_SALZSAEURE)
+         Feld[x][y] = EL_BADEWANNE1;
+       else if (x>0 && Feld[x-1][y]==EL_SALZSAEURE)
+         Feld[x][y] = EL_BADEWANNE2;
+       else if (y>0 && Feld[x][y-1]==EL_BADEWANNE1)
+         Feld[x][y] = EL_BADEWANNE3;
+       else if (y>0 && Feld[x][y-1]==EL_SALZSAEURE)
+         Feld[x][y] = EL_BADEWANNE4;
+       else if (y>0 && Feld[x][y-1]==EL_BADEWANNE2)
+         Feld[x][y] = EL_BADEWANNE5;
+       break;
+      case EL_KAEFER_R:
+      case EL_KAEFER_O:
+      case EL_KAEFER_L:
+      case EL_KAEFER_U:
+      case EL_KAEFER:
+      case EL_FLIEGER_R:
+      case EL_FLIEGER_O:
+      case EL_FLIEGER_L:
+      case EL_FLIEGER_U:
+      case EL_FLIEGER:
+      case EL_PACMAN_R:
+      case EL_PACMAN_O:
+      case EL_PACMAN_L:
+      case EL_PACMAN_U:
+      case EL_MAMPFER:
+      case EL_ZOMBIE:
+      case EL_PACMAN:
+       InitMovDir(x,y);
+       break;
+      default:
+       break;
+    }
+  }
+
+  scroll_x = scroll_y = -1;
+  if (JX>=MIDPOSX-1)
+    scroll_x =
+      (JX<=lev_fieldx-MIDPOSX ? JX-MIDPOSX : lev_fieldx-SCR_FIELDX+1);
+  if (JY>=MIDPOSY-1)
+    scroll_y =
+      (JY<=lev_fieldy-MIDPOSY ? JY-MIDPOSY : lev_fieldy-SCR_FIELDY+1);
+
+  DrawLevel();
+  DrawLevelElement(JX,JY,EL_SPIELFIGUR);
+  FadeToFront();
+
+  XCopyArea(display,pix[PIX_DOOR],pix[PIX_DB_DOOR],gc,
+           DOOR_GFX_PAGEX5,DOOR_GFX_PAGEY1, DXSIZE,DYSIZE,
+           DOOR_GFX_PAGEX1,DOOR_GFX_PAGEY1);
+  DrawTextExt(pix[PIX_DB_DOOR],gc,
+             DOOR_GFX_PAGEX1+XX_LEVEL,DOOR_GFX_PAGEY1+YY_LEVEL,
+             int2str(level_nr,2),FS_SMALL,FC_YELLOW);
+  DrawTextExt(pix[PIX_DB_DOOR],gc,
+             DOOR_GFX_PAGEX1+XX_EMERALDS,DOOR_GFX_PAGEY1+YY_EMERALDS,
+             int2str(Gems,3),FS_SMALL,FC_YELLOW);
+  DrawTextExt(pix[PIX_DB_DOOR],gc,
+             DOOR_GFX_PAGEX1+XX_DYNAMITE,DOOR_GFX_PAGEY1+YY_DYNAMITE,
+             int2str(Dynamite,3),FS_SMALL,FC_YELLOW);
+  DrawTextExt(pix[PIX_DB_DOOR],gc,
+             DOOR_GFX_PAGEX1+XX_SCORE,DOOR_GFX_PAGEY1+YY_SCORE,
+             int2str(Score,5),FS_SMALL,FC_YELLOW);
+  DrawTextExt(pix[PIX_DB_DOOR],gc,
+             DOOR_GFX_PAGEX1+XX_TIME,DOOR_GFX_PAGEY1+YY_TIME,
+             int2str(TimeLeft,3),FS_SMALL,FC_YELLOW);
+
+  DrawGameButton(BUTTON_GAME_STOP);
+  DrawGameButton(BUTTON_GAME_PAUSE);
+  DrawGameButton(BUTTON_GAME_PLAY);
+  DrawSoundDisplay(BUTTON_SOUND_MUSIC | (BUTTON_ON * sound_music_on));
+  DrawSoundDisplay(BUTTON_SOUND_LOOPS | (BUTTON_ON * sound_loops_on));
+  DrawSoundDisplay(BUTTON_SOUND_SOUND | (BUTTON_ON * sound_on));
+  XCopyArea(display,drawto,pix[PIX_DB_DOOR],gc,
+           DX+GAME_CONTROL_XPOS,DY+GAME_CONTROL_YPOS,
+           GAME_CONTROL_XSIZE,2*GAME_CONTROL_YSIZE,
+           DOOR_GFX_PAGEX1+GAME_CONTROL_XPOS,
+           DOOR_GFX_PAGEY1+GAME_CONTROL_YPOS);
+
+  OpenDoor(DOOR_OPEN_1);
+
+  if (sound_music_on)
+    PlaySoundLoop(background_loop[level_nr % num_bg_loops]);
+
+  XAutoRepeatOff(display);
+}
+
+void InitMovDir(int x, int y)
+{
+  int i, element = Feld[x][y];
+  static int xy[4][2] =
+  {
+    0,+1,
+    +1,0,
+    0,-1,
+    -1,0
+  };
+  static int direction[2][4] =
+  {
+    MV_RIGHT, MV_UP,   MV_LEFT,  MV_DOWN,
+    MV_LEFT,  MV_DOWN, MV_RIGHT, MV_UP
+  };
+
+  switch(element)
+  {
+    case EL_KAEFER_R:
+    case EL_KAEFER_O:
+    case EL_KAEFER_L:
+    case EL_KAEFER_U:
+      Feld[x][y] = EL_KAEFER;
+      MovDir[x][y] = direction[0][element-EL_KAEFER_R];
+      break;
+    case EL_FLIEGER_R:
+    case EL_FLIEGER_O:
+    case EL_FLIEGER_L:
+    case EL_FLIEGER_U:
+      Feld[x][y] = EL_FLIEGER;
+      MovDir[x][y] = direction[0][element-EL_FLIEGER_R];
+      break;
+    case EL_PACMAN_R:
+    case EL_PACMAN_O:
+    case EL_PACMAN_L:
+    case EL_PACMAN_U:
+      Feld[x][y] = EL_PACMAN;
+      MovDir[x][y] = direction[0][element-EL_PACMAN_R];
+      break;
+    default:
+      MovDir[x][y] = 1<<RND(4);
+      if (element!=EL_KAEFER && element!=EL_FLIEGER)
+       break;
+
+      for(i=0;i<4;i++)
+      {
+       int x1,y1;
+
+       x1 = x+xy[i][0];
+       y1 = y+xy[i][1];
+
+       if (!IN_LEV_FIELD(x1,y1) || !IS_FREE(x1,y1))
+       {
+         if (element==EL_KAEFER)
+         {
+           MovDir[x][y] = direction[0][i];
+           break;
+         }
+         else if (element==EL_FLIEGER)
+         {
+           MovDir[x][y] = direction[1][i];
+           break;
+         }
+       }
+      }
+      break;
+  }
+}
+
+void GameWon()
+{
+  int hi_pos;
+  int bumplevel = FALSE;
+
+  if (sound_loops_on)
+    PlaySoundExt(SND_SIRR,PSND_MAX_VOLUME,PSND_MAX_RIGHT,PSND_LOOP);
+
+  if (TimeLeft>0) 
+  {
+    for(;TimeLeft>=0;TimeLeft--)
+    {
+      if (!sound_loops_on)
+       PlaySoundStereo(SND_SIRR,PSND_MAX_RIGHT);
+      if (TimeLeft && !(TimeLeft % 10))
+       RaiseScore(level.score[SC_ZEITBONUS]);
+      DrawText(DX_TIME,DY_TIME,int2str(TimeLeft,3),FS_SMALL,FC_YELLOW);
+      BackToFront();
+      Delay(10000);
+    }
+  }
+
+  if (sound_loops_on)
+    StopSound(SND_SIRR);
+  FadeSounds();
+
+  if (tape.playing)
+    return;
+
+  CloseDoor(DOOR_CLOSE_1);
+
+  if (level_nr==player.handicap &&
+      level_nr<leveldir[leveldir_nr].num_ready) 
+  { 
+    player.handicap++; 
+    bumplevel = TRUE;
+    SavePlayerInfo(PLAYER_LEVEL);
+  }
+
+  if ((hi_pos=NewHiScore())>=0) 
+  {
+    game_status = HALLOFFAME;
+    DrawHallOfFame(hi_pos);
+    if (bumplevel && TAPE_IS_EMPTY(tape))
+      level_nr++;
+  }
+  else
+  {
+    game_status = MAINMENU;
+    if (bumplevel && TAPE_IS_EMPTY(tape))
+      level_nr++;
+    DrawMainMenu();
+  }
+  BackToFront();
+}
+
+BOOL NewHiScore()
+{
+  int k,l;
+  int position = -1;
+
+  LoadScore(level_nr);
+
+  if (!strcmp(player.alias_name,EMPTY_ALIAS) ||
+      Score<highscore[MAX_SCORE_ENTRIES-1].Score) 
+    return(-1);
+
+  for(k=0;k<MAX_SCORE_ENTRIES;k++) 
+  {
+    if (Score>highscore[k].Score)      /* Spieler kommt in Highscore-Liste */
+    {
+      if (k<MAX_SCORE_ENTRIES-1)
+      {
+       int m = MAX_SCORE_ENTRIES-1;
+
+#ifdef ONE_PER_NAME
+       for(l=k;l<MAX_SCORE_ENTRIES;l++)
+         if (!strcmp(player.alias_name,highscore[l].Name))
+           m = l;
+       if (m==k)       /* Spieler überschreibt seine alte Position */
+         goto put_into_list;
+#endif
+
+       for(l=m;l>k;l--)
+       {
+         strcpy(highscore[l].Name,highscore[l-1].Name);
+         highscore[l].Score = highscore[l-1].Score;
+       }
+      }
+
+#ifdef ONE_PER_NAME
+      put_into_list:
+#endif
+      sprintf(highscore[k].Name,player.alias_name);
+      highscore[k].Score = Score; 
+      position = k;
+      break;
+    }
+  }
+
+#ifdef ONE_PER_NAME
+  else if (!strcmp(player.alias_name,highscore[k].Name))
+    break;     /* Spieler schon mit besserer Punktzahl in der Liste */
+#endif
+
+  if (position>=0) 
+    SaveScore(level_nr);
+
+  return(position);
+}
+
+void InitMovingField(int x, int y, int direction)
+{
+  int newx = x + (direction==MV_LEFT ? -1 : direction==MV_RIGHT ? +1 : 0);
+  int newy = y + (direction==MV_UP   ? -1 : direction==MV_DOWN  ? +1 : 0);
+
+  CheckMoving = TRUE;
+  MovDir[x][y] = direction;
+  MovDir[newx][newy] = direction;
+  if (Feld[newx][newy]==EL_LEERRAUM)
+    Feld[newx][newy] = EL_BLOCKED;
+}
+
+void Moving2Blocked(int x, int y, int *goes_to_x, int *goes_to_y)
+{
+  int direction = MovDir[x][y];
+  int newx = x + (direction==MV_LEFT ? -1 : direction==MV_RIGHT ? +1 : 0);
+  int newy = y + (direction==MV_UP   ? -1 : direction==MV_DOWN  ? +1 : 0);
+
+  *goes_to_x = newx;
+  *goes_to_y = newy;
+}
+
+void Blocked2Moving(int x, int y, int *comes_from_x, int *comes_from_y)
+{
+  int oldx = x, oldy = y;
+  int direction = MovDir[x][y];
+
+  if (direction==MV_LEFT)
+    oldx++;
+  else if (direction==MV_RIGHT)
+    oldx--;
+  else if (direction==MV_UP)
+    oldy++;
+  else if (direction==MV_DOWN)
+    oldy--;
+
+  *comes_from_x = oldx;
+  *comes_from_y = oldy;
+}
+
+int MovingOrBlocked2Element(int x, int y)
+{
+  int element = Feld[x][y];
+
+  if (element==EL_BLOCKED)
+  {
+    int oldx,oldy;
+
+    Blocked2Moving(x,y,&oldx,&oldy);
+    return(Feld[oldx][oldy]);
+  }
+  else
+    return(element);
+}
+
+void RemoveMovingField(int x, int y)
+{
+  int oldx=x,oldy=y, newx=x,newy=y;
+
+  if (Feld[x][y]!=EL_BLOCKED && !IS_MOVING(x,y))
+    return;
+
+  if (IS_MOVING(x,y))
+  {
+    Moving2Blocked(x,y,&newx,&newy);
+    if (Feld[newx][newy]!=EL_BLOCKED)
+      return;
+  }
+  else if (Feld[x][y]==EL_BLOCKED)
+  {
+    Blocked2Moving(x,y,&oldx,&oldy);
+    if (!IS_MOVING(oldx,oldy))
+      return;
+  }
+
+  Feld[oldx][oldy] = EL_LEERRAUM;
+  Feld[newx][newy] = EL_LEERRAUM;
+  MovPos[oldx][oldy] = MovDir[oldx][oldy] = MovDelay[oldx][oldy] = 0;
+  MovPos[newx][newy] = MovDir[newx][newy] = MovDelay[newx][newy] = 0;
+  DrawLevelField(oldx,oldy);
+  DrawLevelField(newx,newy);
+}
+
+void DrawDynamite(int x, int y)
+{
+  int phase = (48-MovDelay[x][y])/6;
+
+  if (!IN_SCR_FIELD(SCROLLX(x),SCROLLY(y)))
+    return;
+
+  if (phase>6)
+    phase = 6;
+
+  if (Store[x][y])
+  {
+    DrawGraphic(SCROLLX(x),SCROLLY(y),el2gfx(Store[x][y]));
+    if (PLAYER(x,y))
+      DrawGraphicThruMask(SCROLLX(JX),SCROLLY(JY),GFX_SPIELFIGUR);
+  }
+  else if (PLAYER(x,y))
+    DrawGraphic(SCROLLX(JX),SCROLLY(JY),GFX_SPIELFIGUR);
+
+  if (Store[x][y] || PLAYER(x,y))
+    DrawGraphicThruMask(SCROLLX(x),SCROLLY(y),GFX_DYNAMIT+phase);
+  else
+    DrawGraphic(SCROLLX(x),SCROLLY(y),GFX_DYNAMIT+phase);
+}
+
+void CheckDynamite(int x, int y)
+{
+  CheckExploding=TRUE;
+
+  if (MovDelay[x][y])          /* neues Dynamit / in Wartezustand */
+  {
+    MovDelay[x][y]--;
+    if (MovDelay[x][y])
+    {
+      if (!(MovDelay[x][y] % 6))
+      {
+       DrawDynamite(x,y);
+       PlaySoundLevel(x,y,SND_ZISCH);
+      }
+
+      return;
+    }
+  }
+
+  StopSound(SND_ZISCH);
+  Bang(x,y);
+}
+
+void Explode(int ex, int ey, int phase)
+{
+  int x,y;
+  int num_phase = 9, delay = 1;
+  int last_phase = num_phase*delay;
+  int half_phase = (num_phase/2)*delay;
+
+  if (phase==0)                        /* Feld 'Store' initialisieren */
+  {
+    int center_element = Feld[ex][ey];
+
+    if (center_element==EL_BLOCKED)
+      center_element = MovingOrBlocked2Element(ex,ey);
+
+    for(y=ey-1;y<ey+2;y++) for(x=ex-1;x<ex+2;x++)
+    {
+      int element = Feld[x][y];
+
+      if (!IN_LEV_FIELD(x,y) || IS_MASSIV(element))
+       continue;
+
+      if (element==EL_EXPLODING)
+       element = Store2[x][y];
+
+      if (PLAYER(ex,ey) || center_element==EL_KAEFER)
+       Store[x][y] = ((x==ex && y==ey) ? EL_DIAMANT : EL_EDELSTEIN);
+      else if (center_element==EL_MAMPFER)
+       Store[x][y] = level.mampfer_inhalt[MampferNr][x-ex+1][y-ey+1];
+      else if (Feld[x][y]==EL_ERZ_1)
+       Store[x][y] = EL_EDELSTEIN;
+      else if (Feld[x][y]==EL_ERZ_2)
+       Store[x][y] = EL_DIAMANT;
+      else if (!IS_PFORTE(Store[x][y]))
+       Store[x][y] = EL_LEERRAUM;
+
+      if (x!=ex || y!=ey)
+       Store2[x][y] = element;
+
+      RemoveMovingField(x,y);
+      Feld[x][y] = EL_EXPLODING;
+      MovDir[x][y] = MovPos[x][y] = 0;
+      Frame[x][y] = 1;
+      Stop[x][y] = TRUE;
+    }
+
+    if (center_element==EL_MAMPFER)
+      MampferNr = (MampferNr+1) % 4;
+
+    return;
+  }
+
+  if (Stop[ex][ey])
+    return;
+
+  x = ex;
+  y = ey;
+
+  Frame[x][y] = (phase<last_phase ? phase+1 : 0);
+
+  if (phase==half_phase)
+  {
+    int element = Store2[x][y];
+
+    if (PLAYER(x,y))
+      KillHero();
+    else if (element==EL_BOMBE ||
+            element==EL_DYNAMIT ||
+            element==EL_DYNAMIT_AUS ||
+            element==EL_KAEFER)
+    {
+      Feld[x][y] = Store2[x][y];
+      Store2[x][y] = 0;
+      Bang(x,y);
+    }
+  }
+
+  if (phase==last_phase)
+  {
+    int element;
+
+    element = Feld[x][y] = Store[x][y];
+    Store[x][y] = Store2[x][y] = 0;
+    MovDir[x][y] = MovPos[x][y] = MovDelay[x][y] = 0;
+    if (CAN_MOVE(element) || COULD_MOVE(element))
+      InitMovDir(x,y);
+    DrawLevelField(x,y);
+  }
+  else if (!(phase%delay) && IN_SCR_FIELD(SCROLLX(x),SCROLLY(y)))
+  {
+    if (phase==delay)
+      ErdreichAnbroeckeln(SCROLLX(x),SCROLLY(y));
+
+    DrawGraphic(SCROLLX(x),SCROLLY(y),GFX_EXPLOSION+(phase/delay-1));
+  }
+
+  CheckExploding=TRUE;
+}
+
+void Bang(int x, int y)
+{
+  int element = Feld[x][y];
+
+  CheckExploding=TRUE;
+  PlaySoundLevel(x,y,SND_ROAAAR);
+
+  switch(element)
+  {
+    case EL_KAEFER:
+      RaiseScore(level.score[SC_KAEFER]);
+      break;
+    case EL_FLIEGER:
+      RaiseScore(level.score[SC_FLIEGER]);
+      break;
+    case EL_MAMPFER:
+      RaiseScore(level.score[SC_MAMPFER]);
+      break;
+    case EL_ZOMBIE:
+      RaiseScore(level.score[SC_ZOMBIE]);
+      break;
+    case EL_PACMAN:
+      RaiseScore(level.score[SC_PACMAN]);
+      break;
+    default:
+      break;
+  }
+
+  Explode(x,y,0);
+}
+
+void Blurb(int x, int y)
+{
+  int element = Feld[x][y];
+
+  if (element!=EL_BLURB_LEFT && element!=EL_BLURB_RIGHT) /* Anfang */
+  {
+    PlaySoundLevel(x,y,SND_BLURB);
+    if (IN_LEV_FIELD(x-1,y) && IS_FREE(x-1,y) &&
+       (!IN_LEV_FIELD(x-1,y-1) ||
+        !CAN_FALL(MovingOrBlocked2Element(x-1,y-1))))
+    {
+      Feld[x-1][y] = EL_BLURB_LEFT;
+    }
+    if (IN_LEV_FIELD(x+1,y) && IS_FREE(x+1,y) &&
+       (!IN_LEV_FIELD(x+1,y-1) ||
+        !CAN_FALL(MovingOrBlocked2Element(x+1,y-1))))
+    {
+      Feld[x+1][y] = EL_BLURB_RIGHT;
+    }
+  }
+  else                                                  /* Blubbern */
+  {
+    int graphic = (element==EL_BLURB_LEFT ? GFX_BLURB_LEFT : GFX_BLURB_RIGHT);
+
+    CheckExploding=TRUE;
+
+    if (!MovDelay[x][y])       /* neue Phase / noch nicht gewartet */
+      MovDelay[x][y] = 5;
+
+    if (MovDelay[x][y])                /* neue Phase / in Wartezustand */
+    {
+      MovDelay[x][y]--;
+      if (MovDelay[x][y] && IN_SCR_FIELD(SCROLLX(x),SCROLLY(y)))
+       DrawGraphic(SCROLLX(x),SCROLLY(y),graphic+4-MovDelay[x][y]);
+
+      if (!MovDelay[x][y])
+      {
+       Feld[x][y] = EL_LEERRAUM;
+       DrawLevelField(x,y);
+      }
+    }
+  }
+}
+
+void Impact(int x, int y)
+{
+  BOOL lastline = (y==lev_fieldy-1);
+  BOOL object_hit = FALSE;
+  int element = Feld[x][y];
+
+  /* Element darunter berührt? */
+  if (!lastline)
+    object_hit = (!IS_FREE(x,y+1) && (!IS_MOVING(x,y+1) ||
+                                     MovDir[x][y+1]!=MV_DOWN ||
+                                     MovPos[x][y+1]<=TILEY/2));
+
+  /* Auftreffendes Element fällt in Salzsäure */
+  if (!lastline && Feld[x][y+1]==EL_SALZSAEURE)
+  {
+    Blurb(x,y);
+    return;
+  }
+
+  /* Auftreffendes Element ist Bombe */
+  if (element==EL_BOMBE && (lastline || object_hit))
+  {
+    Bang(x,y);
+    return;
+  }
+
+  /* Auftreffendes Element ist Säuretropfen */
+  if (element==EL_TROPFEN && (lastline || object_hit))
+  {
+    if (object_hit && PLAYER(x,y+1))
+      KillHero();
+    else
+      Feld[x][y] = EL_AMOEBING2;
+    return;
+  }
+
+  /* Welches Element kriegt was auf die Rübe? */
+  if (!lastline && object_hit)
+  {
+    int smashed = Feld[x][y+1];
+
+    if (PLAYER(x,y+1))
+    {
+      KillHero();
+      return;
+    }
+    else if (element==EL_FELSBROCKEN)
+    {
+      if (IS_ENEMY(MovingOrBlocked2Element(x,y+1)))
+      {
+       Bang(x,y+1);
+       return;
+      }
+      else if (!IS_MOVING(x,y+1))
+      {
+       if (smashed==EL_BOMBE)
+       {
+         Bang(x,y+1);
+         return;
+       }
+       else if (smashed==EL_KOKOSNUSS)
+       {
+         Feld[x][y+1] = EL_CRACKINGNUT;
+         PlaySoundLevel(x,y,SND_KNACK);
+         RaiseScore(level.score[SC_KOKOSNUSS]);
+         return;
+       }
+       else if (smashed==EL_DIAMANT)
+       {
+         Feld[x][y+1] = EL_LEERRAUM;
+         PlaySoundLevel(x,y,SND_QUIRK);
+         return;
+       }
+      }
+    }
+  }
+
+  /* Kein Geräusch beim Durchqueren des Siebes */
+  if (!lastline && Feld[x][y+1]==EL_SIEB_LEER)
+    return;
+
+  /* Geräusch beim Auftreffen */
+  if (lastline || object_hit)
+  {
+    int sound;
+
+    switch(element)
+    {
+      case EL_EDELSTEIN:
+      case EL_DIAMANT:
+        sound = SND_PLING;
+       break;
+      case EL_KOKOSNUSS:
+       sound = SND_KLUMPF;
+       break;
+      case EL_FELSBROCKEN:
+       sound = SND_KLOPF;
+       break;
+      case EL_SCHLUESSEL:
+      case EL_SCHLUESSEL1:
+      case EL_SCHLUESSEL2:
+      case EL_SCHLUESSEL3:
+      case EL_SCHLUESSEL4:
+       sound = SND_KINK;
+       break;
+      default:
+       sound = -1;
+        break;
+    }
+
+    if (sound>=0)
+      PlaySoundLevel(x,y,sound);
+  }
+}
+
+void TurnRound(int x, int y)
+{
+  int element = Feld[x][y];
+  int direction = MovDir[x][y];
+
+  if (element==EL_KAEFER)
+  {
+    TestIfBadThingHitsOtherBadThing(x,y);
+
+    if (MovDir[x][y]==MV_LEFT)
+    {
+      if (IN_LEV_FIELD(x,y-1) && IS_FREE(x,y-1))
+       MovDir[x][y]=MV_UP;
+      else if (!IN_LEV_FIELD(x-1,y) || !IS_FREE(x-1,y))
+       MovDir[x][y]=MV_DOWN;
+    }
+    else if (MovDir[x][y]==MV_RIGHT)
+    {
+      if (IN_LEV_FIELD(x,y+1) && IS_FREE(x,y+1))
+       MovDir[x][y]=MV_DOWN;
+      else if (!IN_LEV_FIELD(x+1,y) || !IS_FREE(x+1,y))
+       MovDir[x][y]=MV_UP;
+    }
+    else if (MovDir[x][y]==MV_UP)
+    {
+      if (IN_LEV_FIELD(x+1,y) && IS_FREE(x+1,y))
+       MovDir[x][y]=MV_RIGHT;
+      else if (!IN_LEV_FIELD(x,y-1) || !IS_FREE(x,y-1))
+       MovDir[x][y]=MV_LEFT;
+    }
+    else if (MovDir[x][y]==MV_DOWN)
+    {
+      if (IN_LEV_FIELD(x-1,y) && IS_FREE(x-1,y))
+       MovDir[x][y]=MV_LEFT;
+      else if (!IN_LEV_FIELD(x,y+1) || !IS_FREE(x,y+1))
+       MovDir[x][y]=MV_RIGHT;
+    }
+
+    if (direction!=MovDir[x][y])
+      MovDelay[x][y]=5;
+  }
+  else if (element==EL_FLIEGER)
+  {
+    TestIfBadThingHitsOtherBadThing(x,y);
+
+    if (MovDir[x][y]==MV_LEFT)
+    {
+      if (IN_LEV_FIELD(x,y+1) && IS_FREE(x,y+1))
+       MovDir[x][y]=MV_DOWN;
+      else if (!IN_LEV_FIELD(x-1,y) || !IS_FREE(x-1,y))
+       MovDir[x][y]=MV_UP;
+    }
+    else if (MovDir[x][y]==MV_RIGHT)
+    {
+      if (IN_LEV_FIELD(x,y-1) && IS_FREE(x,y-1))
+       MovDir[x][y]=MV_UP;
+      else if (!IN_LEV_FIELD(x+1,y) || !IS_FREE(x+1,y))
+       MovDir[x][y]=MV_DOWN;
+    }
+    else if (MovDir[x][y]==MV_UP)
+    {
+      if (IN_LEV_FIELD(x-1,y) && IS_FREE(x-1,y))
+       MovDir[x][y]=MV_LEFT;
+      else if (!IN_LEV_FIELD(x,y-1) || !IS_FREE(x,y-1))
+       MovDir[x][y]=MV_RIGHT;
+    }
+    else if (MovDir[x][y]==MV_DOWN)
+    {
+      if (IN_LEV_FIELD(x+1,y) && IS_FREE(x+1,y))
+       MovDir[x][y]=MV_RIGHT;
+      else if (!IN_LEV_FIELD(x,y+1) || !IS_FREE(x,y+1))
+       MovDir[x][y]=MV_LEFT;
+    }
+
+    if (direction!=MovDir[x][y])
+      MovDelay[x][y]=5;
+  }
+  else if (element==EL_MAMPFER)
+  {
+    if (MovDir[x][y]==MV_LEFT || MovDir[x][y]==MV_RIGHT)
+    {
+      MovDir[x][y]=(MovDir[x][y]==MV_LEFT ? MV_RIGHT : MV_LEFT);
+      if (IN_LEV_FIELD(x,y-1) &&
+         (IS_FREE(x,y-1) || Feld[x][y-1]==EL_DIAMANT) &&
+         RND(2))
+       MovDir[x][y]=MV_UP;
+      if (IN_LEV_FIELD(x,y+1) &&
+         (IS_FREE(x,y+1) || Feld[x][y+1]==EL_DIAMANT) &&
+         RND(2))
+       MovDir[x][y]=MV_DOWN;
+    }
+    else if (MovDir[x][y]==MV_UP || MovDir[x][y]==MV_DOWN)
+    {
+      MovDir[x][y]=(MovDir[x][y]==MV_UP ? MV_DOWN : MV_UP);
+      if (IN_LEV_FIELD(x-1,y) &&
+         (IS_FREE(x-1,y) || Feld[x-1][y]==EL_DIAMANT) &&
+         RND(2))
+       MovDir[x][y]=MV_LEFT;
+      if (IN_LEV_FIELD(x+1,y) &&
+         (IS_FREE(x+1,y) || Feld[x+1][y]==EL_DIAMANT) &&
+         RND(2))
+       MovDir[x][y]=MV_RIGHT;
+    }
+
+    MovDelay[x][y]=8+8*RND(3);
+  }
+  else if (element==EL_PACMAN)
+  {
+    if (MovDir[x][y]==MV_LEFT || MovDir[x][y]==MV_RIGHT)
+    {
+      MovDir[x][y]=(MovDir[x][y]==MV_LEFT ? MV_RIGHT : MV_LEFT);
+      if (IN_LEV_FIELD(x,y-1) &&
+         (IS_FREE(x,y-1) || IS_AMOEBOID(Feld[x][y-1])) &&
+         RND(2))
+       MovDir[x][y]=MV_UP;
+      if (IN_LEV_FIELD(x,y+1) &&
+         (IS_FREE(x,y+1) || IS_AMOEBOID(Feld[x][y+1])) &&
+         RND(2))
+       MovDir[x][y]=MV_DOWN;
+    }
+    else if (MovDir[x][y]==MV_UP || MovDir[x][y]==MV_DOWN)
+    {
+      MovDir[x][y]=(MovDir[x][y]==MV_UP ? MV_DOWN : MV_UP);
+      if (IN_LEV_FIELD(x-1,y) &&
+         (IS_FREE(x-1,y) || IS_AMOEBOID(Feld[x-1][y])) &&
+         RND(2))
+       MovDir[x][y]=MV_LEFT;
+      if (IN_LEV_FIELD(x+1,y) &&
+         (IS_FREE(x+1,y) || IS_AMOEBOID(Feld[x+1][y])) &&
+         RND(2))
+       MovDir[x][y]=MV_RIGHT;
+    }
+
+    MovDelay[x][y]=3+RND(20);
+  }
+  else if (element==EL_ZOMBIE)
+  {
+    int attr_x = JX, attr_y = JY;
+
+    if (ZX>=0 && ZY>=0)
+    {
+      attr_x = ZX;
+      attr_y = ZY;
+    }
+
+    MovDir[x][y]=MV_NO_MOVING;
+    if (attr_x<x)
+      MovDir[x][y]|=MV_LEFT;
+    else if (attr_x>x)
+      MovDir[x][y]|=MV_RIGHT;
+    if (attr_y<y)
+      MovDir[x][y]|=MV_UP;
+    else if (attr_y>y)
+      MovDir[x][y]|=MV_DOWN;
+    if ((MovDir[x][y]&(MV_LEFT|MV_RIGHT)) && (MovDir[x][y]&(MV_UP|MV_DOWN)))
+      MovDir[x][y] &= (RND(2) ? (MV_LEFT|MV_RIGHT) : (MV_UP|MV_DOWN));
+
+    MovDelay[x][y] = 8+8*RND(2);
+  }
+}
+
+void StartMoving(int x, int y)
+{
+  int element = Feld[x][y];
+
+  if (Stop[x][y])
+    return;
+
+  if (CAN_FALL(element) && y<lev_fieldy-1)
+  {
+    if (element==EL_MORAST_VOLL)
+    {
+      if (IS_FREE(x,y+1))
+      {
+       InitMovingField(x,y,MV_DOWN);
+       Feld[x][y] = EL_FELSBROCKEN;
+       Store[x][y] = EL_MORAST_LEER;
+      }
+      else if (Feld[x][y+1]==EL_MORAST_LEER)
+      {
+       CheckMoving=TRUE;
+
+       if (!MovDelay[x][y])
+         MovDelay[x][y] = 16;
+
+       if (MovDelay[x][y])
+       {
+         MovDelay[x][y]--;
+         if (MovDelay[x][y])
+           return;
+       }
+
+       Feld[x][y] = EL_MORAST_LEER;
+       Feld[x][y+1] = EL_MORAST_VOLL;
+      }
+    }
+    else if (element==EL_FELSBROCKEN && Feld[x][y+1]==EL_MORAST_LEER)
+    {
+      InitMovingField(x,y,MV_DOWN);
+      Store[x][y] = EL_MORAST_VOLL;
+    }
+    else if (element==EL_SIEB_VOLL)
+    {
+      if (IS_FREE(x,y+1))
+      {
+       InitMovingField(x,y,MV_DOWN);
+       Feld[x][y] = EL_CHANGED(Store2[x][y]);
+       Store[x][y] = EL_SIEB_LEER;
+      }
+    }
+    else if (CAN_CHANGE(element) && Feld[x][y+1]==EL_SIEB_LEER)
+    {
+      InitMovingField(x,y,MV_DOWN);
+      Store[x][y] = EL_SIEB_VOLL;
+      Store2[x][y+1] = element;
+      SiebAktiv = 330;
+    }
+    else if (CAN_SMASH(element) && Feld[x][y+1]==EL_SALZSAEURE)
+    {
+      Blurb(x,y);
+      InitMovingField(x,y,MV_DOWN);
+      Store[x][y] = EL_SALZSAEURE;
+    }
+    else if (CAN_SMASH(element) && Feld[x][y+1]==EL_BLOCKED)
+    {
+      Impact(x,y);
+    }
+    else if (IS_FREE(x,y+1))
+    {
+      InitMovingField(x,y,MV_DOWN);
+    }
+    else if (element==EL_TROPFEN)
+    {
+      Feld[x][y] = EL_AMOEBING2;
+    }
+    else if (SLIPPERY(Feld[x][y+1]) && !Store[x][y+1])
+    {
+      int left  = (x>0 && IS_FREE(x-1,y) &&
+                  (IS_FREE(x-1,y+1) || Feld[x-1][y+1]==EL_SALZSAEURE));
+      int right = (x<lev_fieldx-1 && IS_FREE(x+1,y) &&
+                  (IS_FREE(x+1,y+1) || Feld[x+1][y+1]==EL_SALZSAEURE));
+
+      if (left || right)
+      {
+       if (left && right)
+         left = !(right=RND(2));
+       InitMovingField(x,y,left ? MV_LEFT : MV_RIGHT);
+      }
+    }
+  }
+  else if (CAN_MOVE(element))
+  {
+    int newx,newy;
+
+    CheckMoving = TRUE;
+
+    if (!MovDelay[x][y])       /* neuer Schritt / noch nicht gewartet */
+    {
+      if (element==EL_ZOMBIE || element==EL_KAEFER || element==EL_FLIEGER)
+      {
+       TurnRound(x,y);
+       if (MovDelay[x][y] && (element==EL_KAEFER || element==EL_FLIEGER))
+         DrawLevelField(x,y);
+      }
+    }
+
+    if (MovDelay[x][y])                /* neuer Schritt / in Wartezustand */
+    {
+      MovDelay[x][y]--;
+
+      if (element==EL_ZOMBIE || element==EL_MAMPFER)
+      {
+       int phase = MovDelay[x][y] % 8;
+
+       if (phase>3)
+         phase = 7-phase;
+
+       if (IN_SCR_FIELD(SCROLLX(x),SCROLLY(y)))
+         DrawGraphic(SCROLLX(x),SCROLLY(y),
+                     el2gfx(element)+phase);
+
+       if (element==EL_MAMPFER && MovDelay[x][y]%4==3)
+         PlaySoundLevel(x,y,SND_NJAM);
+      }
+
+      if (MovDelay[x][y])
+       return;
+    }
+
+    if (element==EL_KAEFER)
+    {
+      PlaySoundLevel(x,y,SND_KLAPPER);
+    }
+    else if (element==EL_FLIEGER)
+    {
+      PlaySoundLevel(x,y,SND_ROEHR);
+    }
+
+    /* neuer Schritt / Wartezustand beendet */
+
+    Moving2Blocked(x,y,&newx,&newy);   /* wohin soll's gehen? */
+
+    if (PLAYER(newx,newy))             /* Spieler erwischt */
+    {
+      MovDir[x][y] = 0;
+      KillHero();
+      return;
+    }
+    else if (element==EL_MAMPFER && IN_LEV_FIELD(newx,newy) &&
+            Feld[newx][newy]==EL_DIAMANT)
+    {
+      Feld[newx][newy] = EL_LEERRAUM;
+      DrawLevelField(newx,newy);
+    }
+    else if (element==EL_PACMAN && IN_LEV_FIELD(newx,newy) &&
+            IS_AMOEBOID(Feld[newx][newy]))
+    {
+      Feld[newx][newy] = EL_LEERRAUM;
+      DrawLevelField(newx,newy);
+    }
+    else if (element==EL_ZOMBIE && IN_LEV_FIELD(newx,newy) &&
+            MovDir[x][y]==MV_DOWN && Feld[newx][newy]==EL_SALZSAEURE)
+    {
+      Blurb(x,y);
+      Store[x][y] = EL_SALZSAEURE;
+    }
+    else if (!IN_LEV_FIELD(newx,newy) || !IS_FREE(newx,newy))
+    {                                  /* gegen Wand gelaufen */
+      TurnRound(x,y);
+      DrawLevelField(x,y);
+      return;
+    }
+
+    InitMovingField(x,y,MovDir[x][y]);
+  }
+
+  if (MovDir[x][y])
+    ContinueMoving(x,y);
+}
+
+void ContinueMoving(int x, int y)
+{
+  int element = Feld[x][y];
+  int direction = MovDir[x][y];
+  int dx = (direction==MV_LEFT ? -1 : direction==MV_RIGHT ? +1 : 0);
+  int dy = (direction==MV_UP   ? -1 : direction==MV_DOWN  ? +1 : 0);
+  int horiz_move = (dx!=0);
+  int newx = x + dx, newy = y + dy;
+  int step = (horiz_move ? dx : dy)*TILEX/4;
+
+  if (CAN_FALL(element) && horiz_move)
+    step*=2;
+  else if (element==EL_TROPFEN)
+    step/=2;
+  else if (Store[x][y]==EL_MORAST_VOLL || Store[x][y]==EL_MORAST_LEER)
+    step/=4;
+
+  MovPos[x][y] += step;
+
+  if (ABS(MovPos[x][y])>=TILEX)                /* Zielfeld erreicht */
+  {
+    Feld[x][y]=EL_LEERRAUM;
+    Feld[newx][newy]=element;
+
+    if (Store[x][y]==EL_MORAST_VOLL)
+    {
+      Store[x][y] = 0;
+      Feld[newx][newy] = EL_MORAST_VOLL;
+      element = EL_MORAST_VOLL;
+    }
+    else if (Store[x][y]==EL_MORAST_LEER)
+    {
+      Store[x][y] = 0;
+      Feld[x][y] = EL_MORAST_LEER;
+    }
+    else if (Store[x][y]==EL_SIEB_VOLL)
+    {
+      Store[x][y] = 0;
+      Feld[newx][newy] = EL_SIEB_VOLL;
+      element = EL_SIEB_VOLL;
+    }
+    else if (Store[x][y]==EL_SIEB_LEER)
+    {
+      Store[x][y] = Store2[x][y] = 0;
+      Feld[x][y] = EL_SIEB_LEER;
+    }
+    else if (Store[x][y]==EL_SALZSAEURE)
+    {
+      Store[x][y] = 0;
+      Feld[newx][newy] = EL_SALZSAEURE;
+      element = EL_SALZSAEURE;
+    }
+    else if (Store[x][y]==EL_AMOEBE2)
+    {
+      Store[x][y] = 0;
+      Feld[x][y] = EL_AMOEBE2;
+    }
+
+    MovPos[x][y] = MovDir[x][y] = 0;
+
+    if (!CAN_MOVE(element))
+      MovDir[newx][newy] = 0;
+
+    DrawLevelField(x,y);
+    DrawLevelField(newx,newy);
+
+    Stop[newx][newy]=TRUE;
+    CheckMoving=TRUE;
+
+    if (DONT_TOUCH(element))   /* Käfer oder Flieger */
+    {
+      TestIfBadThingHitsHero();
+      TestIfBadThingHitsOtherBadThing(newx,newy);
+    }
+
+    if (CAN_SMASH(element) && direction==MV_DOWN &&
+       (newy==lev_fieldy-1 || !IS_FREE(x,newy+1)))
+      Impact(x,newy);
+  }
+  else                         /* noch in Bewegung */
+  {
+    DrawLevelField(x,y);
+    CheckMoving=TRUE;
+  }
+}
+
+void AmoebeWaechst(int x, int y)
+{
+  static long sound_delay = 0;
+  static int sound_delay_value = 0;
+
+  CheckExploding=TRUE;
+
+  if (!MovDelay[x][y])         /* neue Phase / noch nicht gewartet */
+  {
+    MovDelay[x][y] = 4;
+
+    if (DelayReached(&sound_delay,sound_delay_value))
+    {
+      PlaySoundLevel(x,y,SND_AMOEBE);
+      sound_delay_value = 30;
+    }
+  }
+
+  if (MovDelay[x][y])          /* neue Phase / in Wartezustand */
+  {
+    MovDelay[x][y]--;
+    if (MovDelay[x][y] && IN_SCR_FIELD(SCROLLX(x),SCROLLY(y)))
+      DrawGraphic(SCROLLX(x),SCROLLY(y),GFX_AMOEBING+3-MovDelay[x][y]);
+
+    if (!MovDelay[x][y])
+    {
+      Feld[x][y] = (Feld[x][y]==EL_AMOEBING2 ? EL_AMOEBE2 : EL_AMOEBE3);
+      DrawLevelField(x,y);
+    }
+  }
+}
+
+void AmoebeAbleger(int ax, int ay)
+{
+  int i,j,start;
+  int newax = ax, neway = ay;
+  BOOL waiting_for_player = FALSE;
+  static int xy[4][2] =
+  {
+    0,-1,
+    -1,0,
+    +1,0,
+    0,+1
+  };
+
+  CheckExploding=TRUE;
+
+  if (!level.tempo_amoebe)
+  {
+    Feld[ax][ay] = EL_AMOEBE1;
+    DrawLevelField(ax,ay);
+    return;
+  }
+
+  if (!MovDelay[ax][ay])       /* neue Amoebe / noch nicht gewartet */
+    MovDelay[ax][ay] = RND(33*20/(1+level.tempo_amoebe));
+
+  if (MovDelay[ax][ay])                /* neue Amoebe / in Wartezustand */
+  {
+    MovDelay[ax][ay]--;
+    if (MovDelay[ax][ay])
+      return;
+  }
+
+  if (Feld[ax][ay]==EL_AMOEBE3)
+  {
+    start = RND(4);
+    for(i=0;i<4;i++)
+    {
+      int x,y;
+
+      j = (start+i)%4;
+      x = ax+xy[j][0];
+      y = ay+xy[j][1];
+      if (!IN_LEV_FIELD(x,y))
+       continue;
+
+      if (IS_FREE(x,y) ||
+         Feld[x][y]==EL_ERDREICH || Feld[x][y]==EL_MORAST_LEER)
+      {
+       newax=x;
+       neway=y;
+       break;
+      }
+      else if (PLAYER(x,y))
+       waiting_for_player = TRUE;
+    }
+
+    if (newax==ax && neway==ay)
+    {
+      if (Feld[ax][ay]==EL_AMOEBE3 && i==4 && !waiting_for_player)
+      {
+       Feld[ax][ay] = EL_AMOEBE1;
+       DrawLevelField(ax,ay);
+      }
+      return;
+    }
+  }
+  else
+  {
+    int x,y;
+
+    start = RND(4);
+    x = ax+xy[start][0];
+    y = ay+xy[start][1];
+    if (!IN_LEV_FIELD(x,y))
+      return;
+
+    if (IS_FREE(x,y) ||
+         Feld[x][y]==EL_ERDREICH || Feld[x][y]==EL_MORAST_LEER)
+    {
+      newax=x;
+      neway=y;
+    }
+
+    if (newax==ax && neway==ay)
+      return;
+  }
+
+  if (Feld[ax][ay]==EL_AMOEBE3)
+    Feld[newax][neway] = EL_AMOEBING3;
+  else if (neway==lev_fieldy-1)
+    Feld[newax][neway] = EL_AMOEBING2;
+  else if (neway<=ay || !IS_FREE(newax,neway))
+    Feld[newax][neway] = EL_TROPFEN;
+  else
+  {
+    InitMovingField(ax,ay,MV_DOWN);
+    Feld[ax][ay]=EL_TROPFEN;
+    Store[ax][ay]=EL_AMOEBE2;
+    ContinueMoving(ax,ay);
+    return;
+  }
+
+  DrawLevelField(newax,neway);
+}
+
+void Life(int ax, int ay)
+{
+  int x1,y1,x2,y2;
+  static int life[4] = { 2,3,3,3 };    /* "Life"-Parameter */
+  int life_time = 20;
+  int element = Feld[ax][ay];
+
+  CheckExploding=TRUE;
+
+  if (Stop[ax][ay])
+    return;
+
+  if (!MovDelay[ax][ay])       /* neue Phase / noch nicht gewartet */
+    MovDelay[ax][ay] = life_time;
+
+  if (MovDelay[ax][ay])                /* neue Phase / in Wartezustand */
+  {
+    MovDelay[ax][ay]--;
+    if (MovDelay[ax][ay])
+      return;
+  }
+
+  for(y1=-1;y1<2;y1++) for(x1=-1;x1<2;x1++)
+  {
+    int xx = ax+x1, yy = ay+y1;
+    int nachbarn = 0;
+
+    if (!IN_LEV_FIELD(xx,yy))
+      continue;
+
+    for(y2=-1;y2<2;y2++) for(x2=-1;x2<2;x2++)
+    {
+      int x = xx+x2, y = yy+y2;
+
+      if (!IN_LEV_FIELD(x,y) || (x==xx && y==yy))
+       continue;
+
+      if ((Feld[x][y]==element && !Stop[x][y]) ||
+         (IS_FREE(x,y) && Stop[x][y]))
+       nachbarn++;
+    }
+
+    if (xx==ax && yy==ay)              /* mittleres Feld mit Amoebe */
+    {
+      if (nachbarn<life[0] || nachbarn>life[1])
+      {
+       Feld[xx][yy] = EL_LEERRAUM;
+       if (!Stop[xx][yy])
+         DrawLevelField(xx,yy);
+       Stop[xx][yy] = TRUE;
+      }
+    }
+    else if (IS_FREE(xx,yy) || Feld[xx][yy]==EL_ERDREICH)
+    {                                  /* Randfeld ohne Amoebe */
+      if (nachbarn>=life[2] && nachbarn<=life[3])
+      {
+       Feld[xx][yy] = element;
+       MovDelay[xx][yy] = (element==EL_LIFE ? 0 : life_time-1);
+       if (!Stop[xx][yy])
+         DrawLevelField(xx,yy);
+       Stop[xx][yy] = TRUE;
+      }
+    }
+  }
+}
+
+void Ablenk(int x, int y)
+{
+  CheckExploding=TRUE;
+
+  if (!MovDelay[x][y])         /* neue Phase / noch nicht gewartet */
+    MovDelay[x][y] = 33*(level.dauer_ablenk/10);
+  if (MovDelay[x][y])          /* neue Phase / in Wartezustand */
+  {
+    MovDelay[x][y]--;
+    if (MovDelay[x][y])
+    {
+      if (IN_SCR_FIELD(SCROLLX(x),SCROLLY(y)))
+       DrawGraphic(SCROLLX(x),SCROLLY(y),GFX_ABLENK+MovDelay[x][y]%4);
+      if (!(MovDelay[x][y]%4))
+       PlaySoundLevel(x,y,SND_MIEP);
+      return;
+    }
+  }
+
+  Feld[x][y]=EL_ABLENK_AUS;
+  DrawLevelField(x,y);
+  if (ZX==x && ZY==y)
+    ZX=ZY=-1;
+}
+
+void Birne(int x, int y)
+{
+  CheckExploding=TRUE;
+
+  if (!MovDelay[x][y])         /* neue Phase / noch nicht gewartet */
+    MovDelay[x][y] = 400;
+
+  if (MovDelay[x][y])          /* neue Phase / in Wartezustand */
+  {
+    MovDelay[x][y]--;
+    if (MovDelay[x][y])
+    {
+      if (!(MovDelay[x][y]%5))
+      {
+       if (!(MovDelay[x][y]%10))
+         Feld[x][y]=EL_ABLENK_EIN;
+       else
+         Feld[x][y]=EL_ABLENK_AUS;
+       DrawLevelField(x,y);
+       Feld[x][y]=EL_ABLENK_EIN;
+      }
+      return;
+    }
+  }
+
+  Feld[x][y]=EL_ABLENK_AUS;
+  DrawLevelField(x,y);
+  if (ZX==x && ZY==y)
+    ZX=ZY=-1;
+}
+
+void Blubber(int x, int y)
+{
+  CheckExploding=TRUE;
+
+  if (!MovDelay[x][y])         /* neue Phase / noch nicht gewartet */
+    MovDelay[x][y] = 20;
+
+  if (MovDelay[x][y])          /* neue Phase / in Wartezustand */
+  {
+    int blubber;
+
+    MovDelay[x][y]--;
+    blubber = MovDelay[x][y]/5;
+    if (!(MovDelay[x][y]%5) && IN_SCR_FIELD(SCROLLX(x),SCROLLY(y)))
+      DrawGraphic(SCROLLX(x),SCROLLY(y),GFX_GEBLUBBER+3-blubber);
+  }
+}
+
+void NussKnacken(int x, int y)
+{
+  CheckExploding=TRUE;
+
+  if (!MovDelay[x][y])         /* neue Phase / noch nicht gewartet */
+    MovDelay[x][y] = 4;
+
+  if (MovDelay[x][y])          /* neue Phase / in Wartezustand */
+  {
+    MovDelay[x][y]--;
+    if (MovDelay[x][y] && IN_SCR_FIELD(SCROLLX(x),SCROLLY(y)))
+      DrawGraphic(SCROLLX(x),SCROLLY(y),GFX_CRACKINGNUT+3-MovDelay[x][y]);
+
+    if (!MovDelay[x][y])
+    {
+      Feld[x][y] = EL_EDELSTEIN;
+      DrawLevelField(x,y);
+    }
+  }
+}
+
+void SiebAktivieren(int x, int y)
+{
+  CheckExploding=TRUE;
+
+  if (SiebAktiv>1)
+  {
+    if (SiebAktiv%2 && IN_SCR_FIELD(SCROLLX(x),SCROLLY(y)))
+      DrawGraphic(SCROLLX(x),SCROLLY(y),GFX_SIEB_VOLL+3-(SiebAktiv%8)/2);
+
+/*
+    if (!(SiebAktiv%4))
+      PlaySoundLevel(x,y,SND_MIEP);
+*/
+
+  }
+  else
+  {
+    Feld[x][y] = EL_SIEB_TOT;
+    DrawLevelField(x,y);
+  }
+}
+
+void AusgangstuerPruefen(int x, int y)
+{
+  CheckExploding=TRUE;
+
+  if (!Gems)
+    Feld[x][y] = EL_AUSGANG_ACT;
+}
+
+void AusgangstuerOeffnen(int x, int y)
+{
+  CheckExploding=TRUE;
+
+  if (!MovDelay[x][y])         /* neue Phase / noch nicht gewartet */
+    MovDelay[x][y] = 20;
+
+  if (MovDelay[x][y])          /* neue Phase / in Wartezustand */
+  {
+    int tuer;
+
+    MovDelay[x][y]--;
+    tuer = MovDelay[x][y]/5;
+    if (!(MovDelay[x][y]%5) && IN_SCR_FIELD(SCROLLX(x),SCROLLY(y)))
+      DrawGraphic(SCROLLX(x),SCROLLY(y),GFX_AUSGANG_ZU+3-tuer);
+
+    if (!MovDelay[x][y])
+    {
+      Feld[x][y] = EL_AUSGANG_AUF;
+      DrawLevelField(x,y);
+    }
+  }
+}
+
+int GameActions(int mx, int my, int button)
+{
+  static long time_delay=0, action_delay=0;
+  int Action;
+
+  if (TimeLeft>0 && DelayReached(&time_delay,100) && !tape.pausing)
+  {
+    TimeLeft--;
+
+    if (tape.recording || tape.playing)
+      DrawVideoDisplay(VIDEO_STATE_TIME_ON,level.time-TimeLeft);
+
+    if (TimeLeft<=10)
+      PlaySoundStereo(SND_GONG,PSND_MAX_RIGHT);
+
+    DrawText(DX_TIME,DY_TIME,int2str(TimeLeft,3),FS_SMALL,FC_YELLOW);
+    BackToFront();
+  }
+
+  if (!TimeLeft)
+    KillHero();
+
+  Action = (CheckMoving || CheckExploding || SiebAktiv);
+
+/*
+  if (Action && DelayReached(&action_delay,3))
+*/
+
+  if (DelayReached(&action_delay,3))
+  {
+    int x,y,element;
+
+    if (tape.pausing || (tape.playing && !TapePlayDelay()))
+      return(ACT_GO_ON);
+    else if (tape.recording)
+      TapeRecordDelay();
+
+    CheckMoving = CheckExploding = FALSE;
+    for(y=0;y<lev_fieldy;y++) for(x=0;x<lev_fieldx;x++)
+      Stop[x][y] = FALSE;
+
+    for(y=0;y<lev_fieldy;y++) for(x=0;x<lev_fieldx;x++)
+    {
+      element = Feld[x][y];
+
+      if (element==EL_LEERRAUM || element==EL_ERDREICH)
+       continue;
+
+      if (!IS_MOVING(x,y) && (CAN_FALL(element) || CAN_MOVE(element)))
+       StartMoving(x,y);
+      else if (IS_MOVING(x,y))
+       ContinueMoving(x,y);
+      else if (element==EL_DYNAMIT)
+       CheckDynamite(x,y);
+      else if (element==EL_EXPLODING)
+       Explode(x,y,Frame[x][y]);
+      else if (element==EL_AMOEBING2 || element==EL_AMOEBING3)
+       AmoebeWaechst(x,y);
+      else if (element==EL_AMOEBE2 || element==EL_AMOEBE3)
+       AmoebeAbleger(x,y);
+      else if (element==EL_LIFE || element==EL_LIFE_ASYNC)
+       Life(x,y);
+      else if (element==EL_ABLENK_EIN)
+       Ablenk(x,y);
+      else if (element==EL_SALZSAEURE)
+       Blubber(x,y);
+      else if (element==EL_BLURB_LEFT || element==EL_BLURB_RIGHT)
+       Blurb(x,y);
+      else if (element==EL_CRACKINGNUT)
+       NussKnacken(x,y);
+      else if (element==EL_AUSGANG_ZU)
+       AusgangstuerPruefen(x,y);
+      else if (element==EL_AUSGANG_ACT)
+       AusgangstuerOeffnen(x,y);
+
+      if (SiebAktiv && (element==EL_SIEB_LEER ||
+                       element==EL_SIEB_VOLL ||
+                       Store[x][y]==EL_SIEB_LEER))
+       SiebAktivieren(x,y);
+    }
+
+    if (SiebAktiv)
+      SiebAktiv--;
+
+    if (CheckMoving || CheckExploding)
+      BackToFront();
+  }
+
+  return(ACT_GO_ON);
+}
+
+void ScrollLevel(int dx, int dy)
+{
+  int x,y;
+
+  XCopyArea(display,drawto_field,drawto_field,gc,
+           SX+TILEX*(dx==-1),SY+TILEY*(dy==-1),
+           SXSIZE-TILEX*(dx!=0),SYSIZE-TILEY*(dy!=0),
+           SX+TILEX*(dx==1),SY+TILEY*(dy==1));
+
+  if (dx)
+  {
+    x = dx==1 ? 0 : SCR_FIELDX-1;
+    for(y=0;y<SCR_FIELDY;y++)
+      DrawScreenField(x,y);
+  }
+  if (dy)
+  {
+    y = dy==1 ? 0 : SCR_FIELDY-1;
+    for(x=0;x<SCR_FIELDY;x++)
+      DrawScreenField(x,y);
+  }
+
+  redraw_mask|=REDRAW_FIELD;
+}
+
+BOOL MoveFigureOneStep(int dx, int dy)
+{
+  int oldJX,oldJY, newJX=JX+dx,newJY=JY+dy;
+  int element;
+  int can_move;
+
+  if (!dx && !dy)
+    return(MF_NO_ACTION);
+  if (!IN_LEV_FIELD(newJX,newJY))
+    return(MF_NO_ACTION);
+
+  element = MovingOrBlocked2Element(newJX,newJY);
+
+  if (DONT_GO_TO(element))
+  {
+    if (element==EL_SALZSAEURE && dx==0 && dy==1)
+    {
+      Blurb(JX,JY);
+      Feld[JX][JY] = EL_SPIELFIGUR;
+      InitMovingField(JX,JY,MV_DOWN);
+      Store[JX][JY] = EL_SALZSAEURE;
+      ContinueMoving(JX,JY);
+
+      PlaySoundLevel(JX,JY,SND_AUTSCH);
+      PlaySoundLevel(JX,JY,SND_LACHEN);
+      GameOver=TRUE;
+      JX=JY=-1;
+    }
+    else
+      KillHero();
+
+    return(MF_MOVING);
+  }
+
+  can_move = DigField(newJX,newJY,DF_DIG);
+  if (can_move != MF_MOVING)
+    return(can_move);
+
+  oldJX = JX;
+  oldJY = JY;
+  JX = newJX;
+  JY = newJY;
+
+  if (Store[oldJX][oldJY])
+  {
+    DrawGraphic(SCROLLX(oldJX),SCROLLY(oldJY),el2gfx(Store[oldJX][oldJY]));
+    DrawGraphicThruMask(SCROLLX(oldJX),SCROLLY(oldJY),
+                       el2gfx(Feld[oldJX][oldJY]));
+  }
+  else if (Feld[oldJX][oldJY]==EL_DYNAMIT)
+    DrawDynamite(oldJX,oldJY);
+  else
+    DrawLevelField(oldJX,oldJY);
+
+  return(MF_MOVING);
+}
+
+BOOL MoveFigure(int dx, int dy)
+{
+  static long move_delay = 0;
+  int moved = MF_NO_ACTION;
+
+  if (GameOver || (!dx && !dy))
+    return(FALSE);
+
+  if (!DelayReached(&move_delay,10) && !tape.playing)
+    return(FALSE);
+
+  if (moved |= MoveFigureOneStep(dx,0))
+    moved |= MoveFigureOneStep(0,dy);
+  else
+  {
+    moved |= MoveFigureOneStep(0,dy);
+    moved |= MoveFigureOneStep(dx,0);
+  }
+
+  if (moved & MF_MOVING)
+  {
+    int old_scroll_x=scroll_x, old_scroll_y=scroll_y;
+
+    if (scroll_x!=JX-MIDPOSX && JX>=MIDPOSX-1 && JX<=lev_fieldx-MIDPOSX)
+      scroll_x = JX-MIDPOSX;
+    if (scroll_y!=JY-MIDPOSY && JY>=MIDPOSY-1 && JY<=lev_fieldy-MIDPOSY)
+      scroll_y = JY-MIDPOSY;
+
+    if (scroll_x!=old_scroll_x || scroll_y!=old_scroll_y)
+      ScrollLevel(old_scroll_x-scroll_x,old_scroll_y-scroll_y);
+
+    if (Feld[JX][JY]==EL_LEERRAUM)
+      DrawLevelElement(JX,JY,EL_SPIELFIGUR);
+    else
+      DrawGraphicThruMask(SCROLLX(JX),SCROLLY(JY),GFX_SPIELFIGUR);
+  }
+
+  TestIfHeroHitsBadThing();
+
+  BackToFront();
+
+  if (LevelSolved)
+    GameWon();
+
+  return(moved);
+}
+
+void TestIfHeroHitsBadThing()
+{
+  int i, killx = JX,killy = JY;
+  static int xy[4][2] =
+  {
+    0,-1,
+    -1,0,
+    +1,0,
+    0,+1
+  };
+  static int harmless[4] =
+  {
+    MV_UP,
+    MV_LEFT,
+    MV_RIGHT,
+    MV_DOWN
+  };
+
+  for(i=0;i<4;i++)
+  {
+    int x,y,element;
+
+    x = JX+xy[i][0];
+    y = JY+xy[i][1];
+    if (!IN_LEV_FIELD(x,y))
+      continue;
+
+    element = Feld[x][y];
+
+    if (DONT_TOUCH(element))
+    {
+      if (MovDir[x][y]==harmless[i])
+       continue;
+
+      killx = x;
+      killy = y;
+      break;
+    }
+  }
+
+  if (killx!=JX || killy!=JY)
+    KillHero();
+}
+
+void TestIfBadThingHitsHero()
+{
+  TestIfHeroHitsBadThing();
+}
+
+void TestIfBadThingHitsOtherBadThing(int badx, int bady)
+{
+  int i, killx=badx, killy=bady;
+  static int xy[4][2] =
+  {
+    0,-1,
+    -1,0,
+    +1,0,
+    0,+1
+  };
+
+  for(i=0;i<4;i++)
+  {
+    int x,y,element;
+
+    x=badx+xy[i][0];
+    y=bady+xy[i][1];
+    if (!IN_LEV_FIELD(x,y))
+      continue;
+
+    element=Feld[x][y];
+    if (IS_AMOEBOID(element) || element==EL_LIFE ||
+       element==EL_AMOEBING2 || element==EL_AMOEBING3 || element==EL_TROPFEN)
+    {
+      killx=x;
+      killy=y;
+      break;
+    }
+  }
+
+  if (killx!=badx || killy!=bady)
+    Bang(badx,bady);
+}
+
+void KillHero()
+{
+  if (PLAYER(-1,-1))
+    return;
+
+  if (IS_PFORTE(Feld[JX][JY]))
+    Feld[JX][JY] = EL_LEERRAUM;
+
+  PlaySoundLevel(JX,JY,SND_AUTSCH);
+  PlaySoundLevel(JX,JY,SND_LACHEN);
+  Bang(JX,JY);
+  GameOver = TRUE;
+  JX = JY = -1;
+}
+
+int DigField(int x, int y, int mode)
+{
+  int dx=x-JX, dy=y-JY;
+  int element;
+  static long push_delay = 0;
+  static int push_delay_value = 20;
+
+  if (mode==DF_NO_PUSH)
+  {
+    push_delay = 0;
+    return(MF_NO_ACTION);
+  }
+
+  if (IS_MOVING(x,y))
+    return(MF_NO_ACTION);
+
+  element = Feld[x][y];
+
+  switch(element)
+  {
+    case EL_LEERRAUM:
+      CheckMoving=TRUE;
+      break;
+    case EL_ERDREICH:
+      Feld[x][y]=EL_LEERRAUM;
+      CheckMoving=TRUE;
+      break;
+    case EL_EDELSTEIN:
+      Feld[x][y]=EL_LEERRAUM;
+      CheckMoving=TRUE;
+      if (Gems>0)
+       Gems--;
+      RaiseScore(level.score[SC_EDELSTEIN]);
+      DrawText(DX_EMERALDS,DY_EMERALDS,int2str(Gems,3),FS_SMALL,FC_YELLOW);
+      PlaySoundLevel(x,y,SND_PONG);
+      break;
+    case EL_DIAMANT:
+      Feld[x][y]=EL_LEERRAUM;
+      CheckMoving=TRUE;
+      Gems -= 3;
+      if (Gems<0)
+       Gems=0;
+      RaiseScore(level.score[SC_DIAMANT]);
+      DrawText(DX_EMERALDS,DY_EMERALDS,int2str(Gems,3),FS_SMALL,FC_YELLOW);
+      PlaySoundLevel(x,y,SND_PONG);
+      break;
+    case EL_DYNAMIT_AUS:
+      Feld[x][y]=EL_LEERRAUM;
+      CheckMoving=TRUE;
+      Dynamite++;
+      RaiseScore(level.score[SC_DYNAMIT]);
+      DrawText(DX_DYNAMITE,DY_DYNAMITE,int2str(Dynamite,3),FS_SMALL,FC_YELLOW);
+      PlaySoundLevel(x,y,SND_PONG);
+      break;
+    case EL_SCHLUESSEL1:
+    case EL_SCHLUESSEL2:
+    case EL_SCHLUESSEL3:
+    case EL_SCHLUESSEL4:
+    {
+      int key_nr = element-EL_SCHLUESSEL1;
+
+      Feld[x][y] = EL_LEERRAUM;
+      CheckMoving = TRUE;
+      Key[key_nr] = TRUE;
+      RaiseScore(level.score[SC_SCHLUESSEL]);
+      DrawMiniGraphicExtHiRes(drawto,gc,
+                             DX_KEYS+key_nr*MINI_TILEX,DY_KEYS,
+                             GFX_SCHLUESSEL1+key_nr);
+      DrawMiniGraphicExtHiRes(window,gc,
+                             DX_KEYS+key_nr*MINI_TILEX,DY_KEYS,
+                             GFX_SCHLUESSEL1+key_nr);
+      PlaySoundLevel(x,y,SND_PONG);
+      break;
+    }
+    case EL_ABLENK_AUS:
+      Feld[x][y]=EL_ABLENK_EIN;
+      CheckExploding=TRUE;
+      ZX=x;
+      ZY=y;
+      DrawLevelField(x,y);
+/*
+      PlaySoundLevel(x,y,SND_DENG);
+*/
+      return(MF_ACTION);
+      break;
+    case EL_FELSBROCKEN:
+    case EL_BOMBE:
+    case EL_KOKOSNUSS:
+      if (mode==DF_SNAP)
+       return(MF_NO_ACTION);
+      if (dy || !IN_LEV_FIELD(x+dx,y+dy) || Feld[x+dx][y+dy]!=EL_LEERRAUM)
+       return(MF_NO_ACTION);
+
+      if (Counter() > push_delay+4*push_delay_value)
+       push_delay = Counter();
+      if (!DelayReached(&push_delay,push_delay_value) && !tape.playing)
+       return(MF_NO_ACTION);
+
+      Feld[x][y] = EL_LEERRAUM;
+      Feld[x+dx][y+dy] = element;
+      push_delay_value = 10+RND(30);
+      CheckMoving = TRUE;
+      DrawLevelField(x+dx,y+dy);
+      if (element==EL_FELSBROCKEN)
+       PlaySoundLevel(x+dx,y+dy,SND_PUSCH);
+      else if (element==EL_KOKOSNUSS)
+       PlaySoundLevel(x+dx,y+dy,SND_KNURK);
+      else
+       PlaySoundLevel(x+dx,y+dy,SND_KLOPF);
+      break;
+    case EL_PFORTE1:
+    case EL_PFORTE2:
+    case EL_PFORTE3:
+    case EL_PFORTE4:
+      if (!Key[element-EL_PFORTE1])
+       return(MF_NO_ACTION);
+      break;
+    case EL_PFORTE1X:
+    case EL_PFORTE2X:
+    case EL_PFORTE3X:
+    case EL_PFORTE4X:
+      if (!Key[element-EL_PFORTE1X])
+       return(MF_NO_ACTION);
+      break;
+    case EL_AUSGANG_ZU:
+    case EL_AUSGANG_ACT:
+      /* Tür ist (noch) nicht offen! */
+      return(MF_NO_ACTION);
+      break;
+    case EL_AUSGANG_AUF:
+      if (mode==DF_SNAP || Gems>0)
+       return(MF_NO_ACTION);
+      LevelSolved = TRUE;
+      PlaySoundLevel(x,y,SND_BUING);
+      break;
+    default:
+      return(MF_NO_ACTION);
+      break;
+  }
+  push_delay=0;
+  return(MF_MOVING);
+}
+
+BOOL SnapField(int dx, int dy)
+{
+  int x = JX+dx, y = JY+dy;
+  static int snapped = FALSE;
+
+  if (GameOver || !IN_LEV_FIELD(x,y))
+    return(FALSE);
+  if (dx && dy)
+    return(FALSE);
+  if (!dx && !dy)
+  {
+    snapped = FALSE;
+    return(FALSE);
+  }
+  if (snapped)
+    return(FALSE);
+
+  if (!DigField(x,y,DF_SNAP))
+    return(FALSE);
+
+  snapped = TRUE;
+  DrawLevelField(x,y);
+  BackToFront();
+
+  return(TRUE);
+}
+
+BOOL PlaceBomb(void)
+{
+  if (Dynamite==0 || Feld[JX][JY]==EL_DYNAMIT)
+    return(FALSE);
+
+  if (Feld[JX][JY]!=EL_LEERRAUM)
+    Store[JX][JY] = Feld[JX][JY];
+  Feld[JX][JY] = EL_DYNAMIT;
+  MovDelay[JX][JY] = 48;
+  Dynamite--;
+  DrawText(DX_DYNAMITE,DY_DYNAMITE,int2str(Dynamite,3),FS_SMALL,FC_YELLOW);
+  DrawGraphicThruMask(SCROLLX(JX),SCROLLY(JY),GFX_DYNAMIT);
+  CheckExploding = TRUE;
+  return(TRUE);
+}
+
+void PlaySoundLevel(int x, int y, int sound_nr)
+{
+  int sx = SCROLLX(x), sy = SCROLLY(y);
+  int volume, stereo;
+
+  if (!sound_loops_on && IS_LOOP_SOUND(sound_nr))
+    return;
+
+  if (!IN_LEV_FIELD(x,y))
+    return;
+
+  volume = PSND_MAX_VOLUME;
+  stereo = (sx-SCR_FIELDX/2)*12;
+
+  if (!IN_SCR_FIELD(sx,sy))
+  {
+    if (sx<0 || sx>=SCR_FIELDX)
+      volume = PSND_MAX_VOLUME - 2*ABS(sx-SCR_FIELDX/2);
+    else
+      volume = PSND_MAX_VOLUME - 2*ABS(sy-SCR_FIELDY/2);
+  }
+
+  PlaySoundExt(sound_nr, volume, stereo, PSND_NO_LOOP);
+}
+
+void RaiseScore(int value)
+{
+  Score += value;
+  DrawText(DX_SCORE,DY_SCORE,int2str(Score,5),FS_SMALL,FC_YELLOW);
+  BackToFront();
+}
+
+void TapeInitRecording()
+{
+  time_t zeit1 = time(NULL);
+  struct tm *zeit2 = localtime(&zeit1);
+
+  if (tape.recording || tape.playing)
+    return;
+
+  tape.level_nr = level_nr;
+  tape.recording = TRUE;
+  tape.pausing = TRUE;
+  tape.date =
+    10000*(zeit2->tm_year%100) + 100*zeit2->tm_mon + zeit2->tm_mday;
+
+  DrawVideoDisplay(VIDEO_STATE_REC_ON | VIDEO_STATE_PAUSE_ON,0);
+  DrawVideoDisplay(VIDEO_STATE_DATE_ON,tape.date);
+  DrawVideoDisplay(VIDEO_STATE_TIME_ON,0);
+}
+
+void TapeStartRecording()
+{
+  tape.length = 0;
+  tape.counter = 0;
+  tape.pos[tape.counter].delay = 0;
+  tape.recording = TRUE;
+  tape.playing = FALSE;
+  tape.pausing = FALSE;
+  tape.random_seed = InitRND(NEW_RANDOMIZE);
+  DrawVideoDisplay(VIDEO_STATE_REC_ON | VIDEO_STATE_PAUSE_OFF,0);
+}
+
+void TapeStopRecording()
+{
+  if (!tape.recording)
+    return;
+
+  tape.length = tape.counter;
+  tape.recording = FALSE;
+  tape.pausing = FALSE;
+  DrawVideoDisplay(VIDEO_STATE_REC_OFF,0);
+
+  master_tape = tape;
+}
+
+void TapeRecordAction(int joy)
+{
+  if (!tape.recording || tape.pausing)
+    return;
+
+  if (tape.counter>=MAX_TAPELEN-1)
+  {
+    TapeStopRecording();
+    return;
+  }
+
+  if (joy)
+  {
+    tape.pos[tape.counter].joystickdata = joy;
+    tape.counter++;
+    tape.pos[tape.counter].delay = 0;
+  }
+}
+
+void TapeRecordDelay()
+{
+  if (!tape.recording || tape.pausing)
+    return;
+
+  if (tape.counter>=MAX_TAPELEN)
+  {
+    TapeStopRecording();
+    return;
+  }
+
+  tape.pos[tape.counter].delay++;
+
+  if (tape.pos[tape.counter].delay>=255)
+  {
+    tape.pos[tape.counter].joystickdata = 0;
+    tape.counter++;
+    tape.pos[tape.counter].delay = 0;
+  }
+}
+
+void TapeTogglePause()
+{
+  if (!tape.recording && !tape.playing)
+    return;
+
+  if (tape.pausing)
+  {
+    tape.pausing = FALSE;
+    DrawVideoDisplay(VIDEO_STATE_PAUSE_OFF,0);
+    if (game_status==MAINMENU)
+      HandleMainMenu(SX+16,SY+7*32+16,0,0,MB_MENU_CHOICE);
+  }
+  else
+  {
+    tape.pausing = TRUE;
+    DrawVideoDisplay(VIDEO_STATE_PAUSE_ON,0);
+  }
+}
+
+void TapeInitPlaying()
+{
+  if (tape.recording || tape.playing || TAPE_IS_EMPTY(tape))
+    return;
+
+  tape.playing = TRUE;
+  tape.pausing = TRUE;
+  DrawVideoDisplay(VIDEO_STATE_PLAY_ON | VIDEO_STATE_PAUSE_ON,0);
+  DrawVideoDisplay(VIDEO_STATE_DATE_ON,tape.date);
+  DrawVideoDisplay(VIDEO_STATE_TIME_ON,0);
+}
+
+void TapeStartPlaying()
+{
+  tape = master_tape;
+
+  tape.counter = 0;
+  tape.recording = FALSE;
+  tape.playing = TRUE;
+  tape.pausing = FALSE;
+  InitRND(tape.random_seed);
+  DrawVideoDisplay(VIDEO_STATE_PLAY_ON | VIDEO_STATE_PAUSE_OFF,0);
+}
+
+void TapeStopPlaying()
+{
+  if (!tape.playing)
+    return;
+
+  tape.playing = FALSE;
+  tape.pausing = FALSE;
+  DrawVideoDisplay(VIDEO_STATE_PLAY_OFF,0);
+}
+
+int TapePlayAction()
+{
+  if (!tape.playing || tape.pausing)
+    return(0);
+
+  if (tape.counter>=tape.length)
+  {
+    TapeStopPlaying();
+    return(0);
+  }
+
+  if (!tape.pos[tape.counter].delay)
+  {
+    tape.counter++;
+    return(tape.pos[tape.counter-1].joystickdata);
+  }
+  else
+    return(0);
+}
+
+BOOL TapePlayDelay()
+{
+  if (!tape.playing || tape.pausing)
+    return(0);
+
+  if (tape.counter>=tape.length)
+  {
+    TapeStopPlaying();
+    return(TRUE);
+  }
+
+  if (tape.pos[tape.counter].delay)
+  {
+    tape.pos[tape.counter].delay--;
+    return(TRUE);
+  }
+  else
+    return(FALSE);
+}
+
+void TapeStop()
+{
+  TapeStopRecording();
+  TapeStopPlaying();
+  DrawVideoDisplay(VIDEO_ALL_OFF,0);
+  if (tape.date && tape.length)
+  {
+    DrawVideoDisplay(VIDEO_STATE_DATE_ON,tape.date);
+    DrawVideoDisplay(VIDEO_STATE_TIME_ON,0);
+  }
+}
+
+void TapeErase()
+{
+  tape.length = 0;
+}
+
+void DrawVideoDisplay(unsigned long state, unsigned long value)
+{
+  int i;
+  int part1 = 0, part2 = 1;
+  int xpos = 0, ypos = 1, xsize = 2, ysize = 3;
+  static char *monatsname[12] =
+  {
+    "JAN", "FEB", "MAR", "APR", "MAY", "JUN",
+    "JUL", "AUG", "SEP", "OCT", "NOV", "DEC"
+  };
+  static int video_pos[10][2][4] =
+  {
+    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,
+
+    VIDEO_BUTTON_PLAY_XPOS, VIDEO_BUTTON_ANY_YPOS,
+    VIDEO_BUTTON_XSIZE,VIDEO_BUTTON_YSIZE,
+    0,0,
+    0,0,
+
+    VIDEO_BUTTON_REC_XPOS, VIDEO_BUTTON_ANY_YPOS,
+    VIDEO_BUTTON_XSIZE,VIDEO_BUTTON_YSIZE,
+    0,0,
+    0,0,
+
+    VIDEO_BUTTON_PAUSE_XPOS, VIDEO_BUTTON_ANY_YPOS,
+    VIDEO_BUTTON_XSIZE,VIDEO_BUTTON_YSIZE,
+    0,0,
+    0,0,
+
+    VIDEO_BUTTON_STOP_XPOS, VIDEO_BUTTON_ANY_YPOS,
+    VIDEO_BUTTON_XSIZE,VIDEO_BUTTON_YSIZE,
+    0,0,
+    0,0,
+
+    VIDEO_BUTTON_EJECT_XPOS, VIDEO_BUTTON_ANY_YPOS,
+    VIDEO_BUTTON_XSIZE,VIDEO_BUTTON_YSIZE,
+    0,0,
+    0,0
+  };
+
+  for(i=0;i<20;i++)
+  {
+    if (state & (1<<i))
+    {
+      int pos = i/2, cx, 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][part1][0])
+       XCopyArea(display,pix[PIX_DOOR],drawto,gc,
+                 cx + video_pos[pos][part1][xpos],
+                 cy + video_pos[pos][part1][ypos],
+                 video_pos[pos][part1][xsize],
+                 video_pos[pos][part1][ysize],
+                 VX + video_pos[pos][part1][xpos],
+                 VY + video_pos[pos][part1][ypos]);
+      if (video_pos[pos][part2][0])
+       XCopyArea(display,pix[PIX_DOOR],drawto,gc,
+                 cx + video_pos[pos][part2][xpos],
+                 cy + video_pos[pos][part2][ypos],
+                 video_pos[pos][part2][xsize],
+                 video_pos[pos][part2][ysize],
+                 VX + video_pos[pos][part2][xpos],
+                 VY + video_pos[pos][part2][ypos]);
+    }
+  }
+
+  if (state & VIDEO_STATE_DATE_ON)
+  {
+    int tag = value % 100;
+    int monat = (value/100) % 100;
+    int jahr = (value/10000);
+
+    DrawText(VX+VIDEO_DATE_XPOS,VY+VIDEO_DATE_YPOS,
+            int2str(tag,2),FS_SMALL,FC_SPECIAL1);
+    DrawText(VX+VIDEO_DATE_XPOS+27,VY+VIDEO_DATE_YPOS,
+            monatsname[monat],FS_SMALL,FC_SPECIAL1);
+    DrawText(VX+VIDEO_DATE_XPOS+64,VY+VIDEO_DATE_YPOS,
+            int2str(jahr,2),FS_SMALL,FC_SPECIAL1);
+  }
+
+  if (state & VIDEO_STATE_TIME_ON)
+  {
+    int min = value / 60;
+    int sec = value % 60;
+
+    DrawText(VX+VIDEO_TIME_XPOS,VY+VIDEO_TIME_YPOS,
+            int2str(min,2),FS_SMALL,FC_SPECIAL1);
+    DrawText(VX+VIDEO_TIME_XPOS+27,VY+VIDEO_TIME_YPOS,
+            int2str(sec,2),FS_SMALL,FC_SPECIAL1);
+  }
+
+  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;
+}
+
+void DrawSoundDisplay(unsigned long state)
+{
+  int pos, cx = DOOR_GFX_PAGEX4, cy = 0;
+
+  pos = (state & BUTTON_SOUND_MUSIC ? SOUND_BUTTON_MUSIC_XPOS :
+        state & BUTTON_SOUND_LOOPS ? SOUND_BUTTON_LOOPS_XPOS :
+        SOUND_BUTTON_SOUND_XPOS);
+
+  if (state & BUTTON_ON)
+    cy -= SOUND_BUTTON_YSIZE;
+
+  if (state & BUTTON_PRESSED)
+    cx = DOOR_GFX_PAGEX3;
+
+  XCopyArea(display,pix[PIX_DOOR],drawto,gc,
+           cx + pos,cy + SOUND_BUTTON_ANY_YPOS,
+           SOUND_BUTTON_XSIZE,SOUND_BUTTON_YSIZE,
+           DX + pos,DY + SOUND_BUTTON_ANY_YPOS);
+
+  redraw_mask |= REDRAW_DOOR_1;
+}
+
+void DrawGameButton(unsigned long state)
+{
+  int pos, cx = DOOR_GFX_PAGEX4, cy = -GAME_BUTTON_YSIZE;
+
+  pos = (state & BUTTON_GAME_STOP ? GAME_BUTTON_STOP_XPOS :
+        state & BUTTON_GAME_PAUSE ? GAME_BUTTON_PAUSE_XPOS :
+        GAME_BUTTON_PLAY_XPOS);
+
+  if (state & BUTTON_PRESSED)
+    cx = DOOR_GFX_PAGEX3;
+
+  XCopyArea(display,pix[PIX_DOOR],drawto,gc,
+           cx + pos,cy + GAME_BUTTON_ANY_YPOS,
+           GAME_BUTTON_XSIZE,GAME_BUTTON_YSIZE,
+           DX + pos,DY + GAME_BUTTON_ANY_YPOS);
+
+  redraw_mask |= REDRAW_DOOR_1;
+}
+
+void DrawChooseButton(unsigned long state)
+{
+  int pos, cx = DOOR_GFX_PAGEX4, cy = 0;
+
+  pos = (state & BUTTON_OK ? OK_BUTTON_XPOS : NO_BUTTON_XPOS);
+
+  if (state & BUTTON_PRESSED)
+    cx = DOOR_GFX_PAGEX3;
+
+  XCopyArea(display,pix[PIX_DOOR],drawto,gc,
+           cx + pos,cy + OK_BUTTON_GFX_YPOS,
+           OK_BUTTON_XSIZE,OK_BUTTON_YSIZE,
+           DX + pos,DY + OK_BUTTON_YPOS);
+
+  redraw_mask |= REDRAW_DOOR_1;
+}
+
+void DrawConfirmButton(unsigned long state)
+{
+  int cx = DOOR_GFX_PAGEX4, cy = 0;
+
+  if (state & BUTTON_PRESSED)
+    cx = DOOR_GFX_PAGEX3;
+
+  XCopyArea(display,pix[PIX_DOOR],drawto,gc,
+           cx + CONFIRM_BUTTON_XPOS,cy + CONFIRM_BUTTON_GFX_YPOS,
+           CONFIRM_BUTTON_XSIZE,CONFIRM_BUTTON_YSIZE,
+           DX + CONFIRM_BUTTON_XPOS,DY + CONFIRM_BUTTON_YPOS);
+
+  redraw_mask |= REDRAW_DOOR_1;
+}
diff --git a/src/game.h b/src/game.h
new file mode 100644 (file)
index 0000000..422343d
--- /dev/null
@@ -0,0 +1,103 @@
+/***********************************************************
+*  Rocks'n'Diamonds -- McDuffin Strikes Back!              *
+*----------------------------------------------------------*
+*  ©1995 Artsoft Development                               *
+*        Holger Schemel                                    *
+*        33659 Bielefeld-Senne                             *
+*        Telefon: (0521) 493245                            *
+*        eMail: aeglos@valinor.owl.de                      *
+*               aeglos@uni-paderborn.de                    *
+*               q99492@pbhrzx.uni-paderborn.de             *
+*----------------------------------------------------------*
+*  game.h                                                  *
+*                                                          *
+*  Letzte Aenderung: 15.06.1995                            *
+***********************************************************/
+
+#ifndef GAME_H
+#define GAME_H
+
+#include "main.h"
+
+#define PLAYER_LEVEL   0
+#define PLAYER_SETUP   1
+
+#define DF_DIG         0
+#define DF_SNAP                1
+#define DF_NO_PUSH     2
+
+#define MF_NO_ACTION   0
+#define MF_MOVING      1
+#define MF_ACTION      2
+
+BOOL CreateNewScoreFile(void);
+BOOL CreateNewNamesFile(int);
+void LoadLevelInfo(void);
+void LoadLevel(int);
+void LoadLevelTape(int);
+void LoadScore(int);
+void LoadPlayerInfo(int);
+void SaveLevel(int);
+void SaveLevelTape(int);
+void SaveScore(int);
+void SavePlayerInfo(int);
+void GetPlayerConfig(void);
+void InitGame(void);
+void InitMovDir(int, int);
+void GameWon(void);
+BOOL NewHiScore(void);
+void InitMovingField(int, int, int);
+void Moving2Blocked(int, int, int *, int *);
+void Blocked2Moving(int, int, int *, int *);
+int MovingOrBlocked2Element(int, int);
+void RemoveMovingField(int, int);
+void DrawDynamite(int, int);
+void CheckDynamite(int, int);
+void Explode(int, int, int);
+void Bang(int, int);
+void Blurb(int, int);
+void Impact(int, int);
+void TurnRound(int, int);
+void StartMoving(int, int);
+void ContinueMoving(int, int);
+void AmoebeWaechst(int, int);
+void AmoebeAbleger(int, int);
+void Life(int, int);
+void Ablenk(int, int);
+void Blubber(int, int);
+void NussKnacken(int, int);
+void SiebAktivieren(int x, int y);
+void AusgangstuerPruefen(int x, int y);
+void AusgangstuerOeffnen(int x, int y);
+int GameActions(int, int, int);
+void ScrollLevel(int, int);
+BOOL MoveFigure(int, int);
+void TestIfHeroHitsBadThing(void);
+void TestIfBadThingHitsHero(void);
+void TestIfBadThingHitsOtherBadThing(int, int);
+void KillHero(void);
+int DigField(int, int, int);
+BOOL SnapField(int, int);
+BOOL PlaceBomb(void);
+void PlaySoundLevel(int, int, int);
+void RaiseScore(int);
+void TapeInitRecording(void);
+void TapeStartRecording(void);
+void TapeStopRecording(void);
+void TapeRecordAction(int);
+void TapeRecordDelay(void);
+void TapeTogglePause(void);
+void TapeInitPlaying(void);
+void TapeStartPlaying(void);
+void TapeStopPlaying(void);
+int TapePlayAction(void);
+BOOL TapePlayDelay(void);
+void TapeStop(void);
+void TapeErase(void);
+void DrawVideoDisplay(unsigned long, unsigned long);
+void DrawSoundDisplay(unsigned long);
+void DrawGameButton(unsigned long);
+void DrawChooseButton(unsigned long);
+void DrawConfirmButton(unsigned long);
+
+#endif
diff --git a/src/images.c b/src/images.c
new file mode 100644 (file)
index 0000000..83c7ae9
--- /dev/null
@@ -0,0 +1,41 @@
+/***********************************************************
+*  Rocks'n'Diamonds -- McDuffin Strikes Back!              *
+*----------------------------------------------------------*
+*  ©1995 Artsoft Development                               *
+*        Holger Schemel                                    *
+*        33659 Bielefeld-Senne                             *
+*        Telefon: (0521) 493245                            *
+*        eMail: aeglos@valinor.owl.de                      *
+*               aeglos@uni-paderborn.de                    *
+*               q99492@pbhrzx.uni-paderborn.de             *
+*----------------------------------------------------------*
+*  images.c                                                *
+*                                                          *
+*  Letzte Aenderung: 15.06.1995                            *
+***********************************************************/
+
+#include "images.h"
+
+struct PictureFile icon_pic =
+{
+  "rocks_icon.xbm",
+  "rocks_iconmask.xbm"
+};
+
+struct PictureFile pic[NUM_PICTURES] =
+{
+  "RocksScreen.xpm",
+  "RocksScreenMaske.xbm",
+
+  "RocksDoor.xpm",
+  "RocksDoorMaske.xbm",
+
+  "RocksToons.xpm",
+  "RocksToonsMaske.xbm",
+
+  "RocksFont.xpm",
+  NULL,
+
+  "RocksFont2.xpm",
+  NULL
+}; 
diff --git a/src/images.h b/src/images.h
new file mode 100644 (file)
index 0000000..6a83841
--- /dev/null
@@ -0,0 +1,25 @@
+/***********************************************************
+*  Rocks'n'Diamonds -- McDuffin Strikes Back!              *
+*----------------------------------------------------------*
+*  ©1995 Artsoft Development                               *
+*        Holger Schemel                                    *
+*        33659 Bielefeld-Senne                             *
+*        Telefon: (0521) 493245                            *
+*        eMail: aeglos@valinor.owl.de                      *
+*               aeglos@uni-paderborn.de                    *
+*               q99492@pbhrzx.uni-paderborn.de             *
+*----------------------------------------------------------*
+*  images.h                                                *
+*                                                          *
+*  Letzte Aenderung: 15.06.1995                            *
+***********************************************************/
+
+#ifndef IMAGES_H
+#define IMAGES_H
+
+#include "main.h"
+
+extern struct PictureFile icon_pic;
+extern struct PictureFile pic[];
+
+#endif
diff --git a/src/init.c b/src/init.c
new file mode 100644 (file)
index 0000000..ec0a1c7
--- /dev/null
@@ -0,0 +1,456 @@
+/***********************************************************
+*  Rocks'n'Diamonds -- McDuffin Strikes Back!              *
+*----------------------------------------------------------*
+*  ©1995 Artsoft Development                               *
+*        Holger Schemel                                    *
+*        33659 Bielefeld-Senne                             *
+*        Telefon: (0521) 493245                            *
+*        eMail: aeglos@valinor.owl.de                      *
+*               aeglos@uni-paderborn.de                    *
+*               q99492@pbhrzx.uni-paderborn.de             *
+*----------------------------------------------------------*
+*  init.c                                                  *
+*                                                          *
+*  Letzte Aenderung: 15.06.1995                            *
+***********************************************************/
+
+#include "init.h"
+#include "images.h"
+#include "sound.h"
+#include "screens.h"
+#include "tools.h"
+#include "game.h"
+#include "misc.h"
+
+#include <signal.h>
+
+int sound_process_id=0;
+
+void OpenAll(int argc, char *argv[])
+{
+  LoadLevelInfo();
+  LoadPlayerInfo(PLAYER_SETUP);
+  LoadPlayerInfo(PLAYER_LEVEL);
+
+  InitCounter();
+  InitSound();
+  InitSoundProcess();
+  InitJoystick();
+  InitRND(NEW_RANDOMIZE);
+
+  signal(SIGINT, CloseAll);
+  signal(SIGTERM, CloseAll);
+
+  InitDisplay(argc, argv);
+  InitWindow(argc, argv);
+  InitGfx();
+
+  DrawMainMenu();
+
+  XMapWindow(display, window);
+  XFlush(display);
+}
+
+void InitSound()
+{
+  int i;
+
+  if (sound_status==SOUND_OFF)
+    return;
+
+  if (access(sound_device_name,W_OK)<0)
+  {
+    fprintf(stderr,"%s: cannot access sound device - no sounds\n",progname);
+    sound_status=SOUND_OFF;
+    return;
+  }
+
+  if ((sound_device=open(sound_device_name,O_WRONLY))<0)
+  {
+    fprintf(stderr,"%s: cannot open sound device - no sounds\n",progname);
+    sound_status=SOUND_OFF;
+    return;
+  }
+
+  close(sound_device);
+  sound_status=SOUND_AVAILABLE;
+
+#ifdef VOXWARE
+  sound_loops_allowed = TRUE;
+  sound_loops_on = TRUE;
+#endif
+
+  for(i=0;i<NUM_SOUNDS;i++)
+  {
+    Sound[i].name = sound_name[i];
+    if (!LoadSound(&Sound[i]))
+    {
+      sound_status=SOUND_OFF;
+      return;
+    }
+  }
+}
+
+void InitSoundProcess()
+{
+  if (sound_status==SOUND_OFF)
+    return;
+
+  if (pipe(sound_pipe)<0)
+  {
+    fprintf(stderr,"%s: cannot create pipe - no sounds\n",progname);
+    sound_status=SOUND_OFF;
+    return;
+  }
+
+  if ((sound_process_id=fork())<0)
+  {       
+    fprintf(stderr,"%s: cannot create child process - no sounds\n",progname);
+    sound_status=SOUND_OFF;
+    return;
+  }
+
+  if (!sound_process_id)       /* we are child */
+    SoundServer();
+  else                         /* we are parent */
+    close(sound_pipe[0]);      /* no reading from pipe needed */
+}
+
+void InitJoystick()
+{
+  if (global_joystick_status==JOYSTICK_OFF)
+    return;
+
+  if (access(joystick_device_name[joystick_nr],R_OK)<0)
+  {
+    fprintf(stderr,"%s: cannot access joystick device '%s'\n",
+           joystick_device_name[joystick_nr],progname);
+    joystick_status = JOYSTICK_OFF;
+    return;
+  }
+
+  if ((joystick_device=open(joystick_device_name[joystick_nr],O_RDONLY))<0)
+  {
+    fprintf(stderr,"%s: cannot open joystick device '%s'\n",
+           joystick_device_name[joystick_nr],progname);
+    joystick_status = JOYSTICK_OFF;
+    return;
+  }
+
+  joystick_status = JOYSTICK_AVAILABLE;
+  LoadJoystickData();
+}
+
+void InitDisplay(int argc, char *argv[])
+{
+  char *display_name = NULL;
+  int i;
+
+  /* get X server to connect to, if given as an argument */
+  for (i=1;i<argc-1;i++)
+  {
+    char *dispstr="-display";
+    int len=MAX(strlen(dispstr),strlen(argv[i]));
+
+    if (len<4)
+      continue;
+    else if (!strncmp(argv[i],dispstr,len))
+    {
+      display_name=argv[i+1];
+      break;
+    }
+  }
+
+  /* connect to X server */
+  if (!(display=XOpenDisplay(display_name)))
+  {
+    fprintf(stderr,"%s: cannot connect to X server %s\n", 
+           progname, XDisplayName(display_name));
+    exit(-1);
+  }
+  
+  screen = DefaultScreen(display);
+  cmap   = DefaultColormap(display, screen);
+  pen_fg = WhitePixel(display,screen);
+  pen_bg = BlackPixel(display,screen);
+}
+
+void InitWindow(int argc, char *argv[])
+{
+  unsigned int border_width = 4;
+  Pixmap icon_pixmap, iconmask_pixmap;
+  unsigned int icon_width,icon_height;
+  int icon_hot_x,icon_hot_y;
+  char icon_filename[256];
+  XSizeHints size_hints;
+  XWMHints wm_hints;
+  XClassHint class_hints;
+  XTextProperty windowName, iconName;
+  XGCValues gc_values;
+  unsigned long gc_valuemask;
+  char *window_name = "Rocks'n'Diamonds";
+  char *icon_name = "Rocks'n'Diamonds";
+  long window_event_mask;
+
+  width = WIN_XSIZE;
+  height = WIN_YSIZE;
+
+  window = XCreateSimpleWindow(display, RootWindow(display, screen),
+                           WIN_XPOS, WIN_YPOS, width, height, border_width,
+                           pen_fg, pen_bg);
+
+  sprintf(icon_filename,"%s/%s",GFX_PATH,icon_pic.picture_filename);
+  XReadBitmapFile(display,window,icon_filename,
+                 &icon_width,&icon_height,
+                 &icon_pixmap,&icon_hot_x,&icon_hot_y);
+  if (!icon_pixmap)
+  {
+    fprintf(stderr, "%s: cannot read icon bitmap file '%s'.\n",
+           progname,icon_filename);
+    exit(-1);
+  }
+
+  sprintf(icon_filename,"%s/%s",GFX_PATH,icon_pic.picturemask_filename);
+  XReadBitmapFile(display,window,icon_filename,
+                 &icon_width,&icon_height,
+                 &iconmask_pixmap,&icon_hot_x,&icon_hot_y);
+  if (!iconmask_pixmap)
+  {
+    fprintf(stderr, "%s: cannot read icon bitmap file '%s'.\n",
+           progname,icon_filename);
+    exit(-1);
+  }
+
+  size_hints.flags = PSize | PMinSize | PMaxSize;
+  size_hints.width  = size_hints.min_width  = size_hints.max_width  = width;
+  size_hints.height = size_hints.min_height = size_hints.max_height = height;
+
+  if (!XStringListToTextProperty(&window_name, 1, &windowName))
+  {
+    fprintf(stderr, "%s: structure allocation for windowName failed.\n",
+           progname);
+    exit(-1);
+  }
+
+  if (!XStringListToTextProperty(&icon_name, 1, &iconName))
+  {
+    fprintf(stderr, "%s: structure allocation for iconName failed.\n",
+           progname);
+    exit(-1);
+  }
+
+  wm_hints.initial_state = NormalState;
+  wm_hints.input = True;
+  wm_hints.icon_pixmap = icon_pixmap;
+  wm_hints.icon_mask = iconmask_pixmap;
+  wm_hints.flags = StateHint | IconPixmapHint | IconMaskHint | InputHint;
+
+  class_hints.res_name = progname;
+  class_hints.res_class = "Rocks'n'Diamonds";
+
+  XSetWMProperties(display, window, &windowName, &iconName, 
+                  argv, argc, &size_hints, &wm_hints, 
+                  &class_hints);
+
+  XFree(windowName.value);
+  XFree(iconName.value);
+
+  /* Select event types wanted */
+  window_event_mask = ExposureMask | StructureNotifyMask | FocusChangeMask |
+                      ButtonPressMask | ButtonReleaseMask | ButtonMotionMask |
+                      KeyPressMask | KeyReleaseMask;
+  XSelectInput(display, window, window_event_mask);
+
+  /* create GC for drawing with window depth */
+  gc_values.graphics_exposures = False;
+  gc_values.foreground = pen_bg;
+  gc_values.background = pen_bg;
+  gc_valuemask = GCGraphicsExposures | GCForeground | GCBackground;
+  gc = XCreateGC(display, window, gc_valuemask, &gc_values);
+}
+
+void InitGfx()
+{
+  int i,j,x,y;
+  int xpm_err, xbm_err;
+  unsigned int width,height;
+  int hot_x,hot_y;
+  XGCValues gc_values;
+  unsigned long gc_valuemask;
+  XGCValues clip_gc_values;
+  unsigned long clip_gc_valuemask;
+  char filename[256];
+  Pixmap shapemask;
+
+  for(i=0;i<NUM_PICTURES;i++)
+  {
+    if (pic[i].picture_filename)
+    {
+      sprintf(filename,"%s/%s",GFX_PATH,pic[i].picture_filename);
+
+      xpm_att[i].valuemask = XpmCloseness;
+      xpm_att[i].closeness = 20000;
+      xpm_err = XpmReadFileToPixmap(display,window,filename,
+                                   &pix[i],&shapemask,&xpm_att[i]);
+      switch(xpm_err)
+      {
+       case XpmOpenFailed:
+          fprintf(stderr,"Xpm file open failed on '%s' !\n",filename);
+         CloseAll();
+         exit(-1);
+       case XpmFileInvalid:
+         fprintf(stderr,"Invalid Xpm file '%s'!\n",filename);
+         CloseAll();
+         exit(-1);
+       case XpmNoMemory:
+         fprintf(stderr,"Not enough memory !\n");      
+         CloseAll();
+         exit(1);
+       case XpmColorFailed:
+         fprintf(stderr,"Can`t get any colors...\n");
+         CloseAll();
+         exit(-1);
+       default:
+         break;
+      }
+      if (!pix[i])
+      {
+       fprintf(stderr, "%s: cannot read Xpm file '%s'.\n",
+               progname,filename);
+       CloseAll();
+       exit(-1);
+      }
+    }
+
+    if (pic[i].picturemask_filename)
+    {
+      sprintf(filename,"%s/%s",GFX_PATH,pic[i].picturemask_filename);
+
+      xbm_err = XReadBitmapFile(display,window,filename,
+                               &width,&height,&clipmask[i],&hot_x,&hot_y);
+      switch(xbm_err)
+      {
+       case BitmapSuccess:
+          break;
+       case BitmapOpenFailed:
+         fprintf(stderr,"Bitmap file open failed on '%s' !\n",filename);
+         CloseAll();
+         exit(-1);
+         break;
+       case BitmapFileInvalid:
+         fprintf(stderr,"Bitmap file invalid: '%s' !\n",filename);
+         CloseAll();
+         exit(-1);
+         break;
+       case BitmapNoMemory:
+         fprintf(stderr,"No memory for file '%s' !\n",filename);
+         CloseAll();
+         exit(-1);
+         break;
+       default:
+         break;
+      }
+      if (!clipmask[i])
+      {
+       fprintf(stderr, "%s: cannot read X11 bitmap file '%s'.\n",
+               progname,filename);
+       CloseAll();
+       exit(-1);
+      }
+    }
+  }
+
+  pix[PIX_DB_BACK] = XCreatePixmap(display, window,
+                                  WIN_XSIZE,WIN_YSIZE,
+                                  XDefaultDepth(display,screen));
+  pix[PIX_DB_DOOR] = XCreatePixmap(display, window,
+                                  3*DXSIZE,DYSIZE+VYSIZE,
+                                  XDefaultDepth(display,screen));
+
+  clipmask[PIX_FADEMASK] = XCreatePixmap(display, window,
+                                        SXSIZE+TILEX,SYSIZE+TILEY,1);
+
+  if (!pix[PIX_DB_BACK] || !pix[PIX_DB_DOOR] || !clipmask[PIX_FADEMASK])
+  {
+    fprintf(stderr, "%s: cannot create additional Pixmaps!\n",progname);
+    CloseAll();
+    exit(-1);
+  }
+
+  /* create GC for drawing with bitplane depth */
+  gc_values.graphics_exposures = False;
+  gc_values.foreground = pen_bg;
+  gc_values.background = pen_bg;
+  gc_valuemask = GCGraphicsExposures | GCForeground | GCBackground;
+  plane_gc = XCreateGC(display, clipmask[PIX_BACK], gc_valuemask, &gc_values);
+
+  for(y=0;y<=SCR_FIELDY;y++) for(x=0;x<=SCR_FIELDX;x++)
+    XCopyArea(display,clipmask[PIX_BACK],clipmask[PIX_FADEMASK],plane_gc,
+             SX+2*TILEX,SY+10*TILEY,TILEX,TILEY,x*TILEX,y*TILEY);
+
+  for(i=0;i<NUM_PIXMAPS;i++)
+  {
+    if (clipmask[i])
+    {
+      clip_gc_values.graphics_exposures = False;
+      clip_gc_values.foreground = pen_fg;
+      clip_gc_values.background = pen_bg;
+      clip_gc_values.clip_mask = clipmask[i];
+      clip_gc_valuemask =
+       GCGraphicsExposures | GCForeground | GCBackground | GCClipMask;
+      clip_gc[i] = XCreateGC(display,window,clip_gc_valuemask,&clip_gc_values);
+    }
+  }
+
+  drawto = drawto_field = backbuffer = pix[PIX_DB_BACK];
+
+  XCopyArea(display,pix[PIX_BACK],backbuffer,gc,
+           0,0, WIN_XSIZE,WIN_YSIZE, 0,0);
+  XFillRectangle(display,backbuffer,gc,
+                REAL_SX,REAL_SY, FULL_SXSIZE,FULL_SYSIZE);
+
+  for(i=0;i<SCR_FIELDX;i++)
+    for(j=0;j<SCR_FIELDY;j++)
+      redraw[i][j]=0;
+  redraw_tiles=0;
+  redraw_mask=REDRAW_ALL;
+}
+
+void CloseAll()
+{
+  int i;
+
+  if (sound_process_id)
+  {
+    StopSounds();
+    kill(sound_process_id, SIGTERM);
+    FreeSounds(NUM_SOUNDS);
+  }
+
+  for(i=0;i<NUM_PIXMAPS;i++)
+  {
+    if (pix[i])
+    {
+      if (i<NUM_PICTURES)      /* XPM pictures */
+      {
+       XFreeColors(display,DefaultColormap(display,screen),
+                   xpm_att[i].pixels,xpm_att[i].npixels,0);
+       XpmFreeAttributes(&xpm_att[i]);
+      }
+      XFreePixmap(display,pix[i]);
+    }
+    if (clipmask[i])
+      XFreePixmap(display,clipmask[i]);
+    if (clip_gc[i])
+      XFreeGC(display, clip_gc[i]);
+  }
+
+  if (gc)
+    XFreeGC(display, gc);
+  if (plane_gc)
+    XFreeGC(display, plane_gc);
+
+  XCloseDisplay(display);
+
+  exit(0);
+}
diff --git a/src/init.h b/src/init.h
new file mode 100644 (file)
index 0000000..f292c53
--- /dev/null
@@ -0,0 +1,31 @@
+/***********************************************************
+*  Rocks'n'Diamonds -- McDuffin Strikes Back!              *
+*----------------------------------------------------------*
+*  ©1995 Artsoft Development                               *
+*        Holger Schemel                                    *
+*        33659 Bielefeld-Senne                             *
+*        Telefon: (0521) 493245                            *
+*        eMail: aeglos@valinor.owl.de                      *
+*               aeglos@uni-paderborn.de                    *
+*               q99492@pbhrzx.uni-paderborn.de             *
+*----------------------------------------------------------*
+*  init.h                                                  *
+*                                                          *
+*  Letzte Aenderung: 15.06.1995                            *
+***********************************************************/
+
+#ifndef INIT_H
+#define INIT_H
+
+#include "main.h"
+
+void OpenAll(int, char **);
+void InitDisplay(int, char **);
+void InitSound(void);
+void InitSoundProcess(void);
+void InitJoystick(void);
+void InitWindow(int, char **);
+void InitGfx(void);
+void CloseAll();
+
+#endif
diff --git a/src/main.c b/src/main.c
new file mode 100644 (file)
index 0000000..2c237ce
--- /dev/null
@@ -0,0 +1,163 @@
+/***********************************************************
+*  Rocks'n'Diamonds -- McDuffin Strikes Back!              *
+*----------------------------------------------------------*
+*  ©1995 Artsoft Development                               *
+*        Holger Schemel                                    *
+*        33659 Bielefeld-Senne                             *
+*        Telefon: (0521) 493245                            *
+*        eMail: aeglos@valinor.owl.de                      *
+*               aeglos@uni-paderborn.de                    *
+*               q99492@pbhrzx.uni-paderborn.de             *
+*----------------------------------------------------------*
+*  main.c                                                  *
+*                                                          *
+*  Letzte Aenderung: 15.06.1995                            *
+***********************************************************/
+
+#include "main.h"
+#include "init.h"
+#include "events.h"
+#include "sound.h"
+
+Display        *display;
+int            screen;
+Window         window;
+GC             gc, plane_gc;
+GC             clip_gc[NUM_PIXMAPS];
+Pixmap         pix[NUM_PIXMAPS];
+Pixmap         clipmask[NUM_PIXMAPS];
+XpmAttributes  xpm_att[NUM_PICTURES];
+Drawable        drawto, drawto_field, backbuffer;
+Colormap       cmap;
+
+int            sound_pipe[2];
+int            sound_device;
+char          *sound_device_name = SOUND_DEVICE;
+int            joystick_device = 0;
+char          *joystick_device_name[2] = { DEV_JOYSTICK_0, DEV_JOYSTICK_1 };
+int            width, height;
+unsigned long  pen_fg, pen_bg;
+
+int            game_status = MAINMENU;
+int            button_status = MB_NOT_PRESSED, motion_status = FALSE;
+int            key_status = KEY_NOT_PRESSED;
+int            global_joystick_status = JOYSTICK_STATUS;
+int            joystick_status = JOYSTICK_STATUS;
+int            sound_status = SOUND_STATUS, sound_on=TRUE;
+int            sound_loops_allowed = FALSE, sound_loops_on = FALSE;
+int            sound_music_on = FALSE;
+int            toons_on = TRUE;
+int            direct_draw_on = FALSE;
+int            fading_on = FALSE;
+int            autorecord_on = FALSE;
+int            joystick_nr = 0;
+
+BOOL           redraw[SCR_FIELDX][SCR_FIELDY];
+int            redraw_mask;
+int            redraw_tiles;
+
+int            Feld[MAX_LEV_FIELDX][MAX_LEV_FIELDY];
+int            Ur[MAX_LEV_FIELDX][MAX_LEV_FIELDY];
+int            MovPos[MAX_LEV_FIELDX][MAX_LEV_FIELDY];
+int            MovDir[MAX_LEV_FIELDX][MAX_LEV_FIELDY];
+int            MovDelay[MAX_LEV_FIELDX][MAX_LEV_FIELDY];
+int            Store[MAX_LEV_FIELDX][MAX_LEV_FIELDY];
+int            Store2[MAX_LEV_FIELDX][MAX_LEV_FIELDY];
+int            Frame[MAX_LEV_FIELDX][MAX_LEV_FIELDY];
+int            Stop[MAX_LEV_FIELDX][MAX_LEV_FIELDY];
+int            level_nr, leveldir_nr, num_leveldirs;
+int            lev_fieldx,lev_fieldy, scroll_x,scroll_y;
+
+int            LevelSolved,GameOver, JX,JY, ZX,ZY;
+int            Gems,Dynamite,Key[4],TimeLeft,Score,MampferNr;
+int            CheckMoving,CheckExploding, SiebAktiv;
+
+struct LevelDirInfo    leveldir[MAX_LEVDIR_ENTRIES];
+struct LevelInfo       level;
+struct PlayerInfo      player;
+struct HiScore         highscore[MAX_SCORE_ENTRIES];
+struct SoundInfo       Sound[NUM_SOUNDS];
+struct RecordingInfo   tape,master_tape;
+
+/* data needed for playing sounds */
+char *sound_name[NUM_SOUNDS] =
+{
+  "alchemy",
+  "amoebe",
+  "antigrav",
+  "autsch",
+  "blurb",
+  "bong",
+  "buing",
+  "chase",
+  "czardasz",
+  "deng",
+  "fuel",
+  "gong",
+  "halloffame",
+  "holz",
+  "hui",
+  "kabumm",
+  "kink",
+  "klapper",
+  "kling",
+  "klopf",
+  "klumpf",
+  "knack",
+  "knurk",
+  "krach",
+  "lachen",
+  "laser",
+  "miep",
+  "network",
+  "njam",
+  "oeffnen",
+  "pling",
+  "pong",
+  "pusch",
+  "quiek",
+  "quirk",
+  "rhythmloop",
+  "roaaar",
+  "roehr",
+  "rumms",
+  "schlopp",
+  "schlurf",
+  "schrff",
+  "schwirr",
+  "sirr",
+  "slurp",
+  "sproing",
+  "twilight",
+  "tyger",
+  "voyager",
+  "warnton",
+  "whoosh",
+  "zisch"
+};
+
+/* background music */
+int background_loop[] =
+{
+  SND_ALCHEMY,
+  SND_CHASE,
+  SND_NETWORK,
+  SND_CZARDASZ,
+  SND_TYGER,
+  SND_VOYAGER,
+  SND_TWILIGHT
+};
+int num_bg_loops = sizeof(background_loop)/sizeof(int);
+
+char           *progname;
+
+int main(int argc, char *argv[])
+{
+  progname = argv[0];
+
+  OpenAll(argc,argv);
+  EventLoop();
+  CloseAll();
+
+  exit(0);
+}
diff --git a/src/main.h b/src/main.h
new file mode 100644 (file)
index 0000000..761bc9f
--- /dev/null
@@ -0,0 +1,1093 @@
+/***********************************************************
+*  Rocks'n'Diamonds -- McDuffin Strikes Back!              *
+*----------------------------------------------------------*
+*  ©1995 Artsoft Development                               *
+*        Holger Schemel                                    *
+*        33659 Bielefeld-Senne                             *
+*        Telefon: (0521) 493245                            *
+*        eMail: aeglos@valinor.owl.de                      *
+*               aeglos@uni-paderborn.de                    *
+*               q99492@pbhrzx.uni-paderborn.de             *
+*----------------------------------------------------------*
+*  main.h                                                  *
+*                                                          *
+*  Letzte Aenderung: 15.06.1995                            *
+***********************************************************/
+
+#ifndef MAIN_H
+#define MAIN_H
+
+#define XK_MISCELLANY
+#define XK_LATIN1
+
+#include <X11/Xlib.h>
+#include <X11/Xutil.h>
+#include <X11/Xos.h>
+#include <X11/Intrinsic.h>
+#include <X11/keysymdef.h>
+
+#include XPM_INCLUDE_FILE
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+
+typedef int BOOL;
+
+#define TRUE           1
+#define FALSE          0
+
+#define WIN_XPOS       0
+#define WIN_YPOS       0
+#define WIN_XSIZE      672
+#define WIN_YSIZE      560
+#define SCR_FIELDX     17
+#define SCR_FIELDY     17
+
+/*
+
+#define LEV_FIELDX     64
+#define LEV_FIELDY     32
+
+*/
+
+#define MIN_LEV_FIELDX (SCR_FIELDX-2)
+#define MIN_LEV_FIELDY (SCR_FIELDY-2)
+#define STD_LEV_FIELDX 64
+#define STD_LEV_FIELDY 32
+#define MAX_LEV_FIELDX 128
+#define MAX_LEV_FIELDY 128
+
+#define MIN(a,b)       ((a)<(b) ? (a) : (b))
+#define MAX(a,b)       ((a)>(b) ? (a) : (b))
+#define ABS(a)         ((a)<0 ? -(a) : (a))
+#define SIGN(a)                ((a)<0 ? -1 : ((a)>0 ? 1 : 0))
+#define SCROLLX(a)     ((a)-scroll_x)
+#define SCROLLY(a)     ((a)-scroll_y)
+#define UNSCROLLX(a)   ((a)+scroll_x)
+#define UNSCROLLY(a)   ((a)+scroll_y)
+#define IN_SCR_FIELD(x,y) ((x)>=0 && (x)<SCR_FIELDX && (y)>=0 &&(y)<SCR_FIELDY)
+#define IN_LEV_FIELD(x,y) ((x)>=0 && (x)<lev_fieldx && (y)>=0 &&(y)<lev_fieldy)
+#define PLAYER(x,y)    (JX==(x) && JY==(y))
+#define IS_FREE(x,y)   (Feld[x][y]==EL_LEERRAUM && !PLAYER(x,y))
+#define IS_MOVING(x,y) (MovPos[x][y]!=0)
+#define IS_BLOCKED(x,y)        (Feld[x][y]==EL_BLOCKED)
+#define IS_AMOEBOID(e) ((e)==EL_AMOEBE1 || (e)==EL_AMOEBE2 || (e)==EL_AMOEBE3)
+#define IS_BADEWANNOID(e) ((e)>=EL_BADEWANNE1 && (e)<=EL_BADEWANNE5)
+#define IS_SCHLUESSEL(e) ((e)>=EL_SCHLUESSEL1 && (e)<=EL_SCHLUESSEL4)
+#define IS_PFORTE(e)   ((e)>=EL_PFORTE1 && (e)<=EL_PFORTE4X)
+#define IS_CHAR(e)     ((e)>=EL_CHAR_START && (e)<=EL_CHAR_END)
+
+#define IS_SOLID(e)    ((e)==EL_BETON || (e)==EL_MAUERWERK || (e)==EL_FELSBODEN || (e)==EL_AUSGANG_ZU || (e)==EL_AUSGANG_ACT || (e)==EL_AUSGANG_AUF || IS_AMOEBOID(e) || (e)==EL_MORAST_VOLL || (e)==EL_MORAST_LEER || (e)==EL_SIEB_VOLL || (e)==EL_SIEB_LEER || (e)==EL_LIFE || (e)==EL_LIFE_ASYNC || IS_BADEWANNOID(e))
+
+#define IS_MASSIV(e)   ((e)==EL_BETON || (e)==EL_SALZSAEURE || IS_BADEWANNOID(e) || IS_PFORTE(e))
+
+#define CAN_FALL(e)    ((e)==EL_FELSBROCKEN || (e)==EL_EDELSTEIN || (e)==EL_DIAMANT || (e)==EL_BOMBE || (e)==EL_KOKOSNUSS || (e)==EL_TROPFEN || (e)==EL_MORAST_VOLL || (e)==EL_SIEB_VOLL)
+
+#define CAN_SMASH(e)   ((e)==EL_FELSBROCKEN || (e)==EL_EDELSTEIN || (e)==EL_DIAMANT || IS_SCHLUESSEL(e) || (e)==EL_BOMBE || (e)==EL_KOKOSNUSS || (e)==EL_TROPFEN)
+
+#define CAN_CHANGE(e)  ((e)==EL_FELSBROCKEN || (e)==EL_EDELSTEIN || (e)==EL_DIAMANT)
+
+#define CAN_MOVE(e)    ((e)==EL_KAEFER || (e)==EL_FLIEGER || (e)==EL_MAMPFER || (e)==EL_ZOMBIE || (e)==EL_PACMAN)
+
+#define COULD_MOVE(e)  (((e)>=EL_KAEFER_R && (e)<=EL_KAEFER_U) || ((e)>=EL_FLIEGER_R && (e)<=EL_FLIEGER_U) || ((e)>=EL_PACMAN && (e)==EL_PACMAN_U))
+
+/*
+#define CAN_KILL(e)    ((e)==EL_KAEFER || (e)==EL_FLIEGER || (e)==EL_MAMPFER || (e)==EL_ZOMBIE || (e)==EL_PACMAN || (e)==EL_TROPFEN)
+*/
+
+#define IS_ENEMY(e)    ((e)==EL_KAEFER || (e)==EL_FLIEGER || (e)==EL_MAMPFER || (e)==EL_ZOMBIE || (e)==EL_PACMAN)
+#define DONT_TOUCH(e)  ((e)==EL_KAEFER || (e)==EL_FLIEGER)
+#define DONT_GO_TO(e)  (IS_ENEMY(e) || (e)==EL_TROPFEN || (e)==EL_SALZSAEURE)
+
+#define SLIPPERY(e)    ((e)==EL_FELSBODEN || (e)==EL_FELSBROCKEN || (e)==EL_EDELSTEIN || (e)==EL_DIAMANT || (e)==EL_BOMBE || (e)==EL_KOKOSNUSS || (e)==EL_ABLENK_EIN || (e)==EL_ABLENK_AUS || (e)==EL_BADEWANNE1 || (e)==EL_BADEWANNE2)
+
+#define EL_CHANGED(e)  ((e)==EL_FELSBROCKEN ? EL_EDELSTEIN : (e)==EL_EDELSTEIN ? EL_DIAMANT : EL_FELSBROCKEN)
+#define IS_DRAWABLE(e)         ((e)<EL_BLOCKED)
+#define IS_NOT_DRAWABLE(e)     ((e)>=EL_BLOCKED)
+#define TIMESIZE       (TimeLeft*100/level.time)
+
+#define LEVELDIR_SIZE(x)       ((x).num_ready + (x).num_free)
+#define TAPE_IS_EMPTY(x)       ((x).length == 0)
+
+/* Pixmaps with Xpm or X11 Bitmap files */
+#define PIX_BACK               0
+#define PIX_DOOR               1
+#define PIX_TOONS              2
+#define        PIX_BIGFONT             3
+#define PIX_SMALLFONT          4
+/* Pixmaps without them */
+#define PIX_DB_BACK            5
+#define PIX_DB_DOOR            6
+#define PIX_FADEMASK           7
+
+#define NUM_PICTURES           5
+#define NUM_PIXMAPS            8
+
+#define MAX_NAMELEN            (10+1)
+
+#define MAX_LEVNAMLEN          32
+#define MAX_SC_ENTRIES         16
+#define MAX_TAPELEN            10000
+
+#define MAX_LEVDIR_FILENAME    (64+1)
+#define MAX_LEVDIR_NAME                (16+1)
+#define MAX_LEVDIR_ENTRIES     15
+#define MAX_SCORE_ENTRIES      15
+
+#define MAX_FILENAME           256
+
+struct PictureFile
+{
+  char *picture_filename;
+  char *picturemask_filename;
+};
+
+struct HiScore
+{
+  char Name[MAX_NAMELEN];
+  int Score;
+};
+
+struct PlayerInfo
+{
+  char login_name[MAX_NAMELEN];
+  char alias_name[MAX_NAMELEN];
+  int handicap;
+  unsigned int setup;
+  int leveldir_nr;
+};
+
+struct LevelInfo
+{
+  int fieldx;
+  int fieldy;
+  int time;
+  int edelsteine;
+  char name[MAX_LEVNAMLEN];
+  int score[MAX_SC_ENTRIES];
+  int mampfer_inhalt[4][3][3];
+  int tempo_amoebe;
+  int dauer_sieb;
+  int dauer_ablenk;
+};
+
+struct LevelDirInfo
+{
+  char filename[MAX_LEVDIR_FILENAME];
+  char name[MAX_LEVDIR_NAME];
+  int num_ready;
+  int num_free;
+};
+
+struct RecordingInfo
+{
+  int level_nr;
+  unsigned int random_seed;
+  unsigned long date;
+  unsigned long counter;
+  unsigned long length;
+  BOOL recording, playing, pausing;
+  struct
+  {
+    unsigned char joystickdata;
+    unsigned char delay;
+  } pos[MAX_TAPELEN];
+};
+
+struct JoystickInfo
+{
+  int xleft, xright, xmiddle;
+  int yupper, ylower, ymiddle;
+};
+
+extern Display        *display;
+extern int             screen;
+extern Window                  window;
+extern GC                      gc, plane_gc;
+extern GC              clip_gc[];
+extern XImage         *image[];
+extern Pixmap          clipmask[];
+extern Pixmap          pix[];
+extern XpmAttributes   xpm_att[];
+extern Drawable        drawto, drawto_field, backbuffer;
+extern Colormap                cmap;
+
+extern int             sound_pipe[2];
+extern int             sound_device;
+extern char           *sound_device_name;
+extern int             joystick_device;
+extern char           *joystick_device_name[2];
+extern int                     width, height;
+extern unsigned long   pen_fg, pen_bg;
+
+extern int             game_status;
+extern int             button_status, motion_status;
+extern int             key_status;
+extern int             global_joystick_status, joystick_status;
+extern int             sound_status, sound_on;
+extern int             sound_loops_allowed, sound_loops_on;
+extern int             sound_music_on;
+extern int             toons_on;
+extern int             direct_draw_on;
+extern int             fading_on;
+extern int             autorecord_on;
+extern int             joystick_nr;
+
+extern BOOL            redraw[SCR_FIELDX][SCR_FIELDY];
+extern int             redraw_mask;
+extern int             redraw_tiles;
+
+extern int             Feld[MAX_LEV_FIELDX][MAX_LEV_FIELDY];
+extern int             Ur[MAX_LEV_FIELDX][MAX_LEV_FIELDY];
+extern int             MovPos[MAX_LEV_FIELDX][MAX_LEV_FIELDY];
+extern int             MovDir[MAX_LEV_FIELDX][MAX_LEV_FIELDY];
+extern int             MovDelay[MAX_LEV_FIELDX][MAX_LEV_FIELDY];
+extern int             Store[MAX_LEV_FIELDX][MAX_LEV_FIELDY];
+extern int             Store2[MAX_LEV_FIELDX][MAX_LEV_FIELDY];
+extern int             Frame[MAX_LEV_FIELDX][MAX_LEV_FIELDY];
+extern int             Stop[MAX_LEV_FIELDX][MAX_LEV_FIELDY];
+extern int             level_nr, leveldir_nr, num_leveldirs;
+extern int             lev_fieldx,lev_fieldy, scroll_x,scroll_y;
+
+extern int             LevelSolved,GameOver, JX,JY, ZX,ZY;
+extern int             Gems,Dynamite,Key[4],TimeLeft,Score,MampferNr;
+extern int             CheckMoving,CheckExploding, SiebAktiv;
+
+extern struct LevelDirInfo     leveldir[];
+extern struct LevelInfo                level;
+extern struct PlayerInfo       player;
+extern struct HiScore          highscore[];
+extern struct RecordingInfo    tape, master_tape;
+
+extern int             background_loop[];
+extern int             num_bg_loops;
+
+extern char           *progname;
+
+
+/* often used screen positions */
+#define SX             8
+#define SY             8
+#define REAL_SX                (SX-2)
+#define REAL_SY                (SY-2)
+#define DX             566
+#define DY             60
+#define VX             DX
+#define VY             400
+#define TILEX          32
+#define TILEY          32
+#define MINI_TILEX     (TILEX/2)
+#define MINI_TILEY     (TILEY/2)
+#define MICRO_TILEX    (TILEX/8)
+#define MICRO_TILEY    (TILEY/8)
+#define MIDPOSX                (SCR_FIELDX/2)
+#define MIDPOSY                (SCR_FIELDY/2)
+#define SXSIZE         (SCR_FIELDX*TILEX)
+#define SYSIZE         (SCR_FIELDY*TILEY)
+#define DXSIZE         100
+#define DYSIZE         280
+#define VXSIZE         DXSIZE
+#define VYSIZE         100
+#define FULL_SXSIZE    (2+SXSIZE+2)
+#define FULL_SYSIZE    (2+SYSIZE+2)
+#define MICROLEV_XPOS  (SX+4*32+16)
+#define MICROLEV_YPOS  (SX+12*32)
+#define MICROLEV_XSIZE (STD_LEV_FIELDX*MICRO_TILEX)
+#define MICROLEV_YSIZE (STD_LEV_FIELDY*MICRO_TILEY)
+#define MICROLABEL_YPOS        (MICROLEV_YPOS+MICROLEV_YSIZE+12)
+#define FONT1_XSIZE    32
+#define FONT1_YSIZE    32
+#define FONT2_XSIZE    14
+#define FONT2_YSIZE    14
+#define FONT3_XSIZE    11
+#define FONT3_YSIZE    14
+#define FONT4_XSIZE    16
+#define FONT4_YSIZE    16
+
+#define GFX_STARTX             SX
+#define GFX_STARTY             SY
+#define MINI_GFX_STARTX                SX
+#define MINI_GFX_STARTY                432
+#define MICRO_GFX_STARTX       SX
+#define MICRO_GFX_STARTY       528
+#define GFX_PER_LINE           16
+#define MINI_GFX_PER_LINE      32
+#define MICRO_GFX_PER_LINE     128
+#define FONT_CHARS_PER_LINE    16
+#define FONT_LINES_PER_FONT    4
+
+/* game elements:
+**     0 - 255: real elements, stored in level file
+**     256 - ?: flag elements, only used at runtime
+*/
+/* "real" level elements */
+#define EL_LEERRAUM    0
+#define        EL_ERDREICH     1
+#define        EL_MAUERWERK    2
+#define        EL_FELSBODEN    3
+#define        EL_FELSBROCKEN  4
+#define        EL_SCHLUESSEL   5
+#define        EL_EDELSTEIN    6
+#define        EL_AUSGANG_ZU   7
+#define        EL_SPIELFIGUR   8
+#define EL_KAEFER      9
+#define EL_FLIEGER     10
+#define EL_MAMPFER     11
+#define EL_ZOMBIE      12
+#define EL_BETON       13
+#define EL_DIAMANT     14
+#define EL_AMOEBE1     15
+#define EL_MORAST_LEER 16
+#define EL_MORAST_VOLL 17
+#define EL_TROPFEN     18
+#define EL_BOMBE       19
+#define EL_SIEB_LEER   20
+#define EL_SIEB_VOLL   21
+#define EL_SALZSAEURE  22
+#define EL_AMOEBE2     23
+#define EL_AMOEBE3     24
+#define EL_KOKOSNUSS   25
+#define EL_LIFE                26
+#define EL_LIFE_ASYNC  27
+#define EL_DYNAMIT     28
+#define EL_BADEWANNE   29
+#define EL_ABLENK_AUS  30
+#define EL_ABLENK_EIN  31
+#define EL_SCHLUESSEL1 32
+#define EL_SCHLUESSEL2 33
+#define EL_SCHLUESSEL3 34
+#define EL_SCHLUESSEL4 35
+#define EL_PFORTE1     36
+#define EL_PFORTE2     37
+#define EL_PFORTE3     38
+#define EL_PFORTE4     39
+#define EL_PFORTE1X    40
+#define EL_PFORTE2X    41
+#define EL_PFORTE3X    42
+#define EL_PFORTE4X    43
+#define EL_DYNAMIT_AUS 44
+#define EL_PACMAN      45
+#define EL_UNSICHTBAR  46
+#define EL_BIRNE_AUS   47
+#define EL_BIRNE_EIN   48
+#define EL_ERZ_1       49
+#define EL_ERZ_2       50
+
+#define EL_SPIELER1    80
+#define EL_SPIELER2    81
+#define EL_SPIELER3    82
+#define EL_SPIELER4    83
+#define EL_KAEFER_R    84
+#define EL_KAEFER_O    85
+#define EL_KAEFER_L    86
+#define EL_KAEFER_U    87
+#define EL_FLIEGER_R   88
+#define EL_FLIEGER_O   89
+#define EL_FLIEGER_L   90
+#define EL_FLIEGER_U   91
+#define EL_PACMAN_R    92
+#define EL_PACMAN_O    93
+#define EL_PACMAN_L    94
+#define EL_PACMAN_U    95
+
+#define EL_BADEWANNE1  100
+#define EL_BADEWANNE2  101
+#define EL_BADEWANNE3  102
+#define EL_BADEWANNE4  103
+#define EL_BADEWANNE5  104
+#define EL_SIEB_TOT    105
+#define EL_AUSGANG_ACT 106
+#define EL_AUSGANG_AUF 107
+
+#define EL_CHAR_START  120
+#define EL_CHAR_ASCII0 (EL_CHAR_START-32)
+#define EL_CHAR_AUSRUF (EL_CHAR_ASCII0+33)
+#define EL_CHAR_ZOLL   (EL_CHAR_ASCII0+34)
+#define EL_CHAR_DOLLAR (EL_CHAR_ASCII0+36)
+#define EL_CHAR_PROZ   (EL_CHAR_ASCII0+37)
+#define EL_CHAR_APOSTR (EL_CHAR_ASCII0+39)
+#define EL_CHAR_KLAMM1 (EL_CHAR_ASCII0+40)
+#define EL_CHAR_KLAMM2 (EL_CHAR_ASCII0+41)
+#define EL_CHAR_PLUS   (EL_CHAR_ASCII0+43)
+#define EL_CHAR_KOMMA  (EL_CHAR_ASCII0+44)
+#define EL_CHAR_MINUS  (EL_CHAR_ASCII0+45)
+#define EL_CHAR_PUNKT  (EL_CHAR_ASCII0+46)
+#define EL_CHAR_SLASH  (EL_CHAR_ASCII0+47)
+#define EL_CHAR_0      (EL_CHAR_ASCII0+48)
+#define EL_CHAR_9      (EL_CHAR_ASCII0+57)
+#define EL_CHAR_DOPPEL (EL_CHAR_ASCII0+58)
+#define EL_CHAR_SEMIKL (EL_CHAR_ASCII0+59)
+#define EL_CHAR_LT     (EL_CHAR_ASCII0+60)
+#define EL_CHAR_GLEICH (EL_CHAR_ASCII0+61)
+#define EL_CHAR_GT     (EL_CHAR_ASCII0+62)
+#define EL_CHAR_FRAGE  (EL_CHAR_ASCII0+63)
+#define EL_CHAR_AT     (EL_CHAR_ASCII0+64)
+#define EL_CHAR_A      (EL_CHAR_ASCII0+65)
+#define EL_CHAR_Z      (EL_CHAR_ASCII0+90)
+#define EL_CHAR_AE     (EL_CHAR_ASCII0+91)
+#define EL_CHAR_OE     (EL_CHAR_ASCII0+92)
+#define EL_CHAR_UE     (EL_CHAR_ASCII0+93)
+#define EL_CHAR_COPY   (EL_CHAR_ASCII0+94)
+#define EL_CHAR_END    (EL_CHAR_START+79)
+
+/* "unreal" runtime elements */
+#define EL_BLOCKED     300
+#define EL_EXPLODING   301
+#define EL_CRACKINGNUT 302
+#define EL_BLURB_LEFT  303
+#define EL_BLURB_RIGHT 304
+#define EL_AMOEBING2   305
+#define EL_AMOEBING3   306
+
+/* names for the graphic objects */
+/* Zeile 0 (0) */
+#define GFX_LEERRAUM   (-1)
+#define        GFX_ERDREICH    0
+#define GFX_ERDENRAND  1
+#define GFX_MORAST_LEER        2
+#define GFX_MORAST_VOLL        3
+#define GFX_BETON      4
+#define        GFX_MAUERWERK   5
+#define        GFX_FELSBODEN   6
+#define GFX_BOMBE_MM   7
+#define        GFX_EDELSTEIN   8
+#define GFX_DIAMANT    10
+#define        GFX_FELSBROCKEN 12
+/* Zeile 1 (16) */
+#define GFX_BADEWANNE1 16
+#define GFX_SALZSAEURE 17
+#define GFX_BADEWANNE2 18
+#define GFX_UNSICHTBAR 19
+#define GFX_SCHLUESSEL1        20
+#define GFX_SCHLUESSEL2        21
+#define GFX_SCHLUESSEL3        22
+#define GFX_SCHLUESSEL4        23
+#define GFX_LIFE       24
+#define GFX_LIFE_ASYNC 25
+#define GFX_BADEWANNE  26
+#define GFX_BOMBE      27
+#define GFX_KOKOSNUSS  28
+#define GFX_CRACKINGNUT        29
+/* Zeile 2 (32) */
+#define GFX_BADEWANNE3 32
+#define GFX_BADEWANNE4 33
+#define GFX_BADEWANNE5 34
+#define        GFX_SPIELFIGUR  35
+#define GFX_PFORTE1    36
+#define GFX_PFORTE2    37
+#define GFX_PFORTE3    38
+#define GFX_PFORTE4    39
+#define GFX_PFORTE1X   40
+#define GFX_PFORTE2X   41
+#define GFX_PFORTE3X   42
+#define GFX_PFORTE4X   43
+#define        GFX_AUSGANG_ZU  44
+#define        GFX_AUSGANG_ACT 44
+#define        GFX_AUSGANG_AUF 47
+/* Zeile 3 (48) */
+#define GFX_DYNAMIT_AUS        48
+#define GFX_DYNAMIT    49
+#define GFX_FLIEGER    56
+#define GFX_FLIEGER_R  56
+#define GFX_FLIEGER_O  57
+#define GFX_FLIEGER_L  58
+#define GFX_FLIEGER_U  59
+/* Zeile 4 (64) */
+#define GFX_EXPLOSION  64
+#define GFX_KAEFER     72
+#define GFX_KAEFER_R   72
+#define GFX_KAEFER_O   73
+#define GFX_KAEFER_L   74
+#define GFX_KAEFER_U   75
+/* Zeile 5 (80) */
+#define GFX_MAMPFER    80
+#define GFX_ZOMBIE     84
+#define GFX_PACMAN     88
+#define GFX_PACMAN_R   88
+#define GFX_PACMAN_O   89
+#define GFX_PACMAN_L   90
+#define GFX_PACMAN_U   91
+/* Zeile 6 (96) */
+#define GFX_ABLENK     96
+#define GFX_ABLENK_EIN GFX_ABLENK
+#define GFX_ABLENK_AUS GFX_ABLENK
+#define GFX_AMOEBE2    100
+#define GFX_TROPFEN    101
+#define GFX_AMOEBING   GFX_TROPFEN
+#define GFX_AMOEBE_LEBT        104
+#define GFX_AMOEBE3    GFX_AMOEBE_LEBT
+#define GFX_AMOEBE_TOT 108
+#define GFX_AMOEBE1    GFX_AMOEBE_TOT
+/* Zeile 7 (112) */
+#define GFX_GEBLUBBER  124
+/* Zeile 8 (128) */
+#define GFX_SIEB_LEER  128
+#define GFX_SIEB_VOLL  GFX_SIEB_LEER
+#define GFX_SIEB_TOT   GFX_SIEB_LEER
+#define GFX_ERZ_1      132
+#define GFX_ERZ_2      133
+#define GFX_BIRNE_AUS  134
+#define GFX_BIRNE_EIN  135
+#define GFX_KUGEL_ROT  140
+#define GFX_KUGEL_BLAU 141
+#define GFX_KUGEL_GELB 142
+/* Zeile 9 (144) */
+#define GFX_BLURB_LEFT 144
+#define GFX_BLURB_RIGHT        148
+
+#define        GFX_SCHLUESSEL  GFX_SCHLUESSEL1
+
+#define GFX_SPIELER1   116
+#define GFX_SPIELER2   117
+#define GFX_SPIELER3   118
+#define GFX_SPIELER4   119
+
+/* nicht in "RocksScreen" sondern woanders :) */
+#define GFX_CHAR_START 256
+#define GFX_CHAR_ASCII0        (GFX_CHAR_START-32)
+#define GFX_CHAR_AUSRUF        (GFX_CHAR_ASCII0+33)
+#define GFX_CHAR_ZOLL  (GFX_CHAR_ASCII0+34)
+#define GFX_CHAR_DOLLAR        (GFX_CHAR_ASCII0+36)
+#define GFX_CHAR_PROZ  (GFX_CHAR_ASCII0+37)
+#define GFX_CHAR_APOSTR        (GFX_CHAR_ASCII0+39)
+#define GFX_CHAR_KLAMM1        (GFX_CHAR_ASCII0+40)
+#define GFX_CHAR_KLAMM2        (GFX_CHAR_ASCII0+41)
+#define GFX_CHAR_PLUS  (GFX_CHAR_ASCII0+43)
+#define GFX_CHAR_KOMMA (GFX_CHAR_ASCII0+44)
+#define GFX_CHAR_MINUS (GFX_CHAR_ASCII0+45)
+#define GFX_CHAR_PUNKT (GFX_CHAR_ASCII0+46)
+#define GFX_CHAR_SLASH (GFX_CHAR_ASCII0+47)
+#define GFX_CHAR_0     (GFX_CHAR_ASCII0+48)
+#define GFX_CHAR_9     (GFX_CHAR_ASCII0+57)
+#define GFX_CHAR_DOPPEL        (GFX_CHAR_ASCII0+58)
+#define GFX_CHAR_SEMIKL        (GFX_CHAR_ASCII0+59)
+#define GFX_CHAR_LT    (GFX_CHAR_ASCII0+60)
+#define GFX_CHAR_GLEICH        (GFX_CHAR_ASCII0+61)
+#define GFX_CHAR_GT    (GFX_CHAR_ASCII0+62)
+#define GFX_CHAR_FRAGE (GFX_CHAR_ASCII0+63)
+#define GFX_CHAR_AT    (GFX_CHAR_ASCII0+64)
+#define GFX_CHAR_A     (GFX_CHAR_ASCII0+65)
+#define GFX_CHAR_Z     (GFX_CHAR_ASCII0+90)
+#define GFX_CHAR_AE    (GFX_CHAR_ASCII0+91)
+#define GFX_CHAR_OE    (GFX_CHAR_ASCII0+92)
+#define GFX_CHAR_UE    (GFX_CHAR_ASCII0+93)
+#define GFX_CHAR_COPY  (GFX_CHAR_ASCII0+94)
+#define GFX_CHAR_END   (GFX_CHAR_START+79)
+
+/* score for elements */
+#define SC_EDELSTEIN   0
+#define SC_DIAMANT     1
+#define SC_KAEFER      2
+#define SC_FLIEGER     3
+#define SC_MAMPFER     4
+#define SC_ZOMBIE      5
+#define SC_PACMAN      6
+#define SC_KOKOSNUSS   7
+#define SC_DYNAMIT     8
+#define SC_SCHLUESSEL  9
+#define SC_ZEITBONUS   10
+
+/* the names of the sounds */
+#define SND_ALCHEMY    0
+#define SND_AMOEBE     1
+#define SND_ANTIGRAV   2
+#define SND_AUTSCH     3
+#define SND_BLURB      4
+#define SND_BONG       5
+#define SND_BUING      6
+#define SND_CHASE      7
+#define SND_CZARDASZ   8
+#define SND_DENG       9
+#define SND_FUEL       10
+#define SND_GONG       11
+#define SND_HALLOFFAME 12
+#define SND_HOLZ       13
+#define SND_HUI                14
+#define SND_KABUMM     15
+#define SND_KINK       16
+#define SND_KLAPPER    17
+#define SND_KLING      18
+#define SND_KLOPF      19
+#define SND_KLUMPF     20
+#define SND_KNACK      21
+#define SND_KNURK      22
+#define SND_KRACH      23
+#define SND_LACHEN     24
+#define SND_LASER      25
+#define SND_MIEP       26
+#define SND_NETWORK    27
+#define SND_NJAM       28
+#define SND_OEFFNEN    29
+#define SND_PLING      30
+#define SND_PONG       31
+#define SND_PUSCH      32
+#define SND_QUIEK      33
+#define SND_QUIRK      34
+#define SND_RHYTHMLOOP 35
+#define SND_ROAAAR     36
+#define SND_ROEHR      37
+#define SND_RUMMS      38
+#define SND_SCHLOPP    39
+#define SND_SCHLURF    40
+#define SND_SCHRFF     41
+#define SND_SCHWIRR    42
+#define SND_SIRR       43
+#define SND_SLURP      44
+#define SND_SPROING    45
+#define SND_TWILIGHT   46
+#define SND_TYGER      47
+#define SND_VOYAGER    48
+#define SND_WARNTON    49
+#define SND_WHOOSH     50
+#define SND_ZISCH      51
+
+#define NUM_SOUNDS     52
+
+#define IS_LOOP_SOUND(s)       ((s)==SND_KLAPPER || (s)==SND_ROEHR ||  \
+                                (s)==SND_NJAM || (s)==SND_MIEP)
+#define IS_MUSIC_SOUND(s)      ((s)==SND_ALCHEMY || (s)==SND_CHASE || \
+                                (s)==SND_NETWORK || (s)==SND_CZARDASZ || \
+                                (s)==SND_TYGER || (s)==SND_VOYAGER || \
+                                (s)==SND_TWILIGHT)
+extern char *sound_name[NUM_SOUNDS];
+
+/* this structure contains the sound data for the sound server */
+extern struct SoundInfo Sound[NUM_SOUNDS];
+
+/* directions for moving */
+#define MV_NO_MOVING   0
+#define MV_LEFT                1
+#define MV_RIGHT       2
+#define MV_UP          4
+#define MV_DOWN                8
+
+/* font types */
+#define FS_SMALL       0
+#define FS_BIG         1
+/* font colors */
+#define FC_RED         0
+#define FC_BLUE                1
+#define FC_GREEN       2
+#define FC_YELLOW      3
+#define FC_SPECIAL1    4
+#define FC_SPECIAL2    5
+
+/* values for game_status */
+#define MAINMENU       0
+#define PLAYING                1
+#define LEVELED                2
+#define HELPSCREEN     3
+#define CHOOSELEVEL    4
+#define TYPENAME       5
+#define HALLOFFAME     6
+#define SETUP          7
+#define EXITGAME       8
+
+/* return values for GameActions */
+#define ACT_GO_ON      0
+#define ACT_GAME_OVER  1
+#define ACT_NEW_GAME   2
+
+/* values for the joystick */
+#define JOYSTICK_OFF           0
+#define        JOYSTICK_AVAILABLE      1
+#define DEV_JOYSTICK_0         "/dev/js0"
+#define DEV_JOYSTICK_1         "/dev/js1"
+
+/* get these values from the program 'js' from the joystick package, */
+/* set JOYSTICK_PERCENT to a threshold appropriate for your joystick */
+#define JOYSTICK_XLEFT         30
+#define JOYSTICK_XRIGHT                1250
+#define JOYSTICK_XMIDDLE       530
+#define JOYSTICK_YUPPER                40
+#define JOYSTICK_YLOWER                1440
+#define JOYSTICK_YMIDDLE       680
+#define JOYSTICK_PERCENT       25
+#define JOY_LEFT               MV_LEFT
+#define JOY_RIGHT              MV_RIGHT
+#define JOY_UP                 MV_UP
+#define JOY_DOWN               MV_DOWN
+#define JOY_BUTTON_1           16
+#define JOY_BUTTON_2           32
+#define JOY_BUTTON             (JOY_BUTTON_1 | JOY_BUTTON_2)
+#define JOY_BUTTON_NOT_PRESSED 0
+#define JOY_BUTTON_PRESSED     1
+#define JOY_BUTTON_NEW_PRESSED 2
+#define JOY_BUTTON_NEW_RELEASED        3
+
+#ifdef NO_JOYSTICK
+#define JOYSTICK_STATUS        JOYSTICK_OFF
+#else
+#define JOYSTICK_STATUS        JOYSTICK_AVAILABLE
+#endif
+
+#ifndef GAME_DIR
+#define GAME_DIR       "."
+#endif
+
+#ifndef GFX_PATH
+#define GFX_PATH       GAME_DIR "/graphics"
+#endif
+#ifndef SND_PATH
+#define SND_PATH       GAME_DIR "/sounds"
+#endif
+#ifndef LEVEL_PATH
+#define LEVEL_PATH     GAME_DIR "/levels"
+#endif
+#ifndef SCORE_PATH
+#define SCORE_PATH     LEVEL_PATH
+#endif
+#ifndef NAMES_PATH
+#define NAMES_PATH     LEVEL_PATH
+#endif
+#ifndef CONFIG_PATH
+#define CONFIG_PATH    GAME_DIR
+#endif
+#ifndef JOYDAT_PATH
+#define JOYDAT_PATH    GAME_DIR
+#endif
+
+#define SCORE_FILENAME "ROCKS.score"
+#define NAMES_FILENAME "ROCKS.names"
+#define LEVDIR_FILENAME        "ROCKS.levelinfo"
+#define JOYDAT_FILENAME        "ROCKS.joystick"
+
+#define JOYDAT_FILE    JOYDAT_PATH "/" JOYDAT_FILENAME
+
+#define LEVEL_PERMS    (S_IRUSR|S_IWUSR | S_IRGRP|S_IWGRP | S_IROTH|S_IWOTH)
+#define SCORE_PERMS    LEVEL_PERMS
+#define NAMES_PERMS    LEVEL_PERMS
+#define LEVDIR_PERMS   LEVEL_PERMS
+#define LEVREC_PERMS   LEVEL_PERMS
+#define JOYDAT_PERMS   LEVEL_PERMS
+
+#define LEVEL_COOKIE   "ROCKSNDIAMONDS_LEVEL_FILE_VERSION_1.0"
+#define SCORE_COOKIE   "ROCKSNDIAMONDS_SCORE_FILE_VERSION_1.0"
+#define NAMES_COOKIE   "ROCKSNDIAMONDS_NAMES_FILE_VERSION_1.0"
+#define LEVELDIR_COOKIE        "ROCKSNDIAMONDS_LEVELDIR_FILE_VERSION_1.0"
+#define LEVELREC_COOKIE        "ROCKSNDIAMONDS_LEVELREC_FILE_VERSION_1.0"
+#define JOYSTICK_COOKIE        "ROCKSNDIAMONDS_JOYSTICK_FILE_VERSION_1.0"
+#define LEVEL_COOKIE_LEN       (strlen(LEVEL_COOKIE)+1)
+#define SCORE_COOKIE_LEN       (strlen(SCORE_COOKIE)+1)
+#define NAMES_COOKIE_LEN       (strlen(NAMES_COOKIE)+1)
+#define LEVELDIR_COOKIE_LEN    (strlen(LEVELDIR_COOKIE)+1)
+#define LEVELREC_COOKIE_LEN    (strlen(LEVELREC_COOKIE)+1)
+#define JOYSTICK_COOKIE_LEN    (strlen(JOYSTICK_COOKIE)+1)
+
+/* Leerer Login- und Alias-Name */
+#define EMPTY_LOGIN    "NO_LOGIN"
+#define EMPTY_ALIAS    "NO_NAME"
+
+/* values for button_status */
+#define MB_NOT_PRESSED FALSE
+#define MB_RELEASED    FALSE
+#define MB_PRESSED     TRUE
+#define MB_MENU_CHOICE FALSE
+#define MB_MENU_MARK   TRUE
+#define MB_LEFT                1
+#define MB_MIDDLE      2
+#define MB_RIGHT       3
+
+/* values for key_status */
+#define KEY_NOT_PRESSED        FALSE
+#define KEY_RELEASED   FALSE
+#define KEY_PRESSED    TRUE
+
+/* values for focus_status */
+#define FOCUS_OUT      FALSE
+#define FOCUS_IN       TRUE
+
+/* values for redraw_mask */
+#define REDRAW_ALL     (1L<<0)
+#define REDRAW_FIELD   (1L<<1)
+#define REDRAW_TILES   (1L<<2)
+#define REDRAW_DOOR_1  (1L<<3)
+#define REDRAW_VIDEO_1 (1L<<4)
+#define REDRAW_VIDEO_2 (1L<<5)
+#define REDRAW_VIDEO_3 (1L<<6)
+#define REDRAW_MICROLEV        (1L<<7)
+#define REDRAW_DOOR_2  (REDRAW_VIDEO_1 | REDRAW_VIDEO_2 | REDRAW_VIDEO_3)
+#define REDRAW_DOORS   (REDRAW_DOOR_1 | REDRAW_DOOR_2)
+#define REDRAW_MAIN    (REDRAW_FIELD | REDRAW_TILES | REDRAW_MICROLEV)
+#define REDRAWTILES_TH SCR_FIELDX*SCR_FIELDY/2
+
+/* positions in the game control window */
+#define XX_LEVEL       37
+#define YY_LEVEL       20
+#define XX_EMERALDS    29
+#define YY_EMERALDS    54
+#define XX_DYNAMITE    29
+#define YY_DYNAMITE    89
+#define XX_KEYS                18
+#define YY_KEYS                123
+#define XX_SCORE       15
+#define YY_SCORE       159
+#define XX_TIME                29
+#define YY_TIME                194
+
+#define DX_LEVEL       (DX+XX_LEVEL)
+#define DY_LEVEL       (DY+YY_LEVEL)
+#define DX_EMERALDS    (DX+XX_EMERALDS)
+#define DY_EMERALDS    (DY+YY_EMERALDS)
+#define DX_DYNAMITE    (DX+XX_DYNAMITE)
+#define DY_DYNAMITE    (DY+YY_DYNAMITE)
+#define DX_KEYS                (DX+XX_KEYS)
+#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 DY_TIME                (DY+YY_TIME)
+
+/* Felder in PIX_DOOR */
+/* Bedeutung in PIX_DB_DOOR: (3 PAGEs)
+   PAGEX1: 1. Zwischenspeicher für DOOR_1
+   PAGEX2: 2. Zwischenspeicher für DOOR_1
+   PAGEX3: Pufferspeicher für Animationen
+*/
+
+#define DOOR_GFX_PAGESIZE      DXSIZE
+#define DOOR_GFX_PAGEX1                (0*DOOR_GFX_PAGESIZE)
+#define DOOR_GFX_PAGEX2                (1*DOOR_GFX_PAGESIZE)
+#define DOOR_GFX_PAGEX3                (2*DOOR_GFX_PAGESIZE)
+#define DOOR_GFX_PAGEX4                (3*DOOR_GFX_PAGESIZE)
+#define DOOR_GFX_PAGEX5                (4*DOOR_GFX_PAGESIZE)
+#define DOOR_GFX_PAGEX6                (5*DOOR_GFX_PAGESIZE)
+#define DOOR_GFX_PAGEY1                0
+#define DOOR_GFX_PAGEY2                DYSIZE
+
+/* some positions in the video tape control window */
+#define VIDEO_DISPLAY1_XPOS    5
+#define VIDEO_DISPLAY1_YPOS    5
+#define VIDEO_DISPLAY2_XPOS    5
+#define VIDEO_DISPLAY2_YPOS    41
+#define VIDEO_DISPLAY_XSIZE    90
+#define VIDEO_DISPLAY_YSIZE    31
+#define VIDEO_BUTTON_XSIZE     18
+#define VIDEO_BUTTON_YSIZE     18
+#define VIDEO_CONTROL_XPOS     5
+#define VIDEO_CONTROL_YPOS     77
+#define VIDEO_CONTROL_XSIZE    (VIDEO_DISPLAY_XSIZE)
+#define VIDEO_CONTROL_YSIZE    (VIDEO_BUTTON_YSIZE)
+#define VIDEO_BUTTON_EJECT_XPOS        (VIDEO_CONTROL_XPOS + 0 * VIDEO_BUTTON_XSIZE)
+#define VIDEO_BUTTON_STOP_XPOS (VIDEO_CONTROL_XPOS + 1 * VIDEO_BUTTON_XSIZE)
+#define VIDEO_BUTTON_PAUSE_XPOS        (VIDEO_CONTROL_XPOS + 2 * VIDEO_BUTTON_XSIZE)
+#define VIDEO_BUTTON_REC_XPOS  (VIDEO_CONTROL_XPOS + 3 * VIDEO_BUTTON_XSIZE)
+#define VIDEO_BUTTON_PLAY_XPOS (VIDEO_CONTROL_XPOS + 4 * VIDEO_BUTTON_XSIZE)
+#define VIDEO_BUTTON_ANY_YPOS  (VIDEO_CONTROL_YPOS)
+#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+1)
+#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+50)
+#define VIDEO_PLAY_SYMBOL_YPOS (VIDEO_DISPLAY2_YPOS)
+#define VIDEO_PLAY_SYMBOL_XSIZE        13
+#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 13
+#define VIDEO_PAUSE_SYMBOL_YSIZE 13
+#define VIDEO_TIME_XPOS                (VIDEO_DISPLAY2_XPOS+38)
+#define VIDEO_TIME_YPOS                (VIDEO_DISPLAY2_YPOS+14)
+#define VIDEO_TIME_XSIZE       50
+#define VIDEO_TIME_YSIZE       16
+
+#define ON_VIDEO_BUTTON(x,y)   ((x)>=(VX+VIDEO_CONTROL_XPOS) &&        \
+                                (x)< (VX+VIDEO_CONTROL_XPOS +          \
+                                      VIDEO_CONTROL_XSIZE) &&          \
+                                (y)>=(VY+VIDEO_CONTROL_YPOS) &&        \
+                                (y)< (VY+VIDEO_CONTROL_YPOS +          \
+                                      VIDEO_CONTROL_YSIZE))
+#define VIDEO_BUTTON(x)                (((x)-(VX+VIDEO_CONTROL_XPOS))/VIDEO_BUTTON_XSIZE)
+
+/* values for video tape control */
+#define VIDEO_STATE_PLAY_OFF   (1L<<0)
+#define VIDEO_STATE_PLAY_ON    (1L<<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                (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      (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       (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       (VIDEO_STATE_TIME_OFF   | VIDEO_STATE_TIME_ON)
+#define VIDEO_PRESS_PLAY_ON    (1L<<10)
+#define VIDEO_PRESS_PLAY_OFF   (1L<<11)
+#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                (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      (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       (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      (VIDEO_PRESS_EJECT_OFF  | VIDEO_PRESS_EJECT_ON)
+
+#define BUTTON_VIDEO_EJECT     1
+#define BUTTON_VIDEO_STOP      2
+#define BUTTON_VIDEO_PAUSE     3
+#define BUTTON_VIDEO_REC       4
+#define BUTTON_VIDEO_PLAY      5
+
+#define VIDEO_STATE_OFF                (VIDEO_STATE_PLAY_OFF   |       \
+                                VIDEO_STATE_REC_OFF    |       \
+                                VIDEO_STATE_PAUSE_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_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)
+
+/* some positions in the sound control window */
+#define SOUND_BUTTON_XSIZE     30
+#define SOUND_BUTTON_YSIZE     30
+#define SOUND_CONTROL_XPOS     5
+#define SOUND_CONTROL_YPOS     245
+#define SOUND_CONTROL_XSIZE    90
+#define SOUND_CONTROL_YSIZE    (SOUND_BUTTON_YSIZE)
+#define SOUND_BUTTON_MUSIC_XPOS        (SOUND_CONTROL_XPOS + 0 * SOUND_BUTTON_XSIZE)
+#define SOUND_BUTTON_LOOPS_XPOS        (SOUND_CONTROL_XPOS + 1 * SOUND_BUTTON_XSIZE)
+#define SOUND_BUTTON_SOUND_XPOS        (SOUND_CONTROL_XPOS + 2 * SOUND_BUTTON_XSIZE)
+#define SOUND_BUTTON_ANY_YPOS  (SOUND_CONTROL_YPOS)
+
+#define ON_SOUND_BUTTON(x,y)   ((x)>=(DX+SOUND_CONTROL_XPOS) &&        \
+                                (x)< (DX+SOUND_CONTROL_XPOS +          \
+                                      SOUND_CONTROL_XSIZE) &&          \
+                                (y)>=(DY+SOUND_CONTROL_YPOS) &&        \
+                                (y)< (DY+SOUND_CONTROL_YPOS +          \
+                                      SOUND_CONTROL_YSIZE))
+#define SOUND_BUTTON(x)                (((x)-(DX+SOUND_CONTROL_XPOS))/SOUND_BUTTON_XSIZE)
+
+/* values for sound control */
+#define BUTTON_SOUND_MUSIC     (1L<<0)
+#define BUTTON_SOUND_LOOPS     (1L<<1)
+#define BUTTON_SOUND_SOUND     (1L<<2)
+#define BUTTON_RELEASED                0
+#define BUTTON_PRESSED         (1L<<3)
+#define BUTTON_OFF             0
+#define BUTTON_ON              (1L<<4)
+#define BUTTON_SOUND_MUSIC_OFF (BUTTON_SOUND_MUSIC | BUTTON_OFF)
+#define BUTTON_SOUND_LOOPS_OFF (BUTTON_SOUND_LOOPS | BUTTON_OFF)
+#define BUTTON_SOUND_SOUND_OFF (BUTTON_SOUND_SOUND | BUTTON_OFF)
+#define BUTTON_SOUND_MUSIC_ON  (BUTTON_SOUND_MUSIC | BUTTON_ON)
+#define BUTTON_SOUND_LOOPS_ON  (BUTTON_SOUND_LOOPS | BUTTON_ON)
+#define BUTTON_SOUND_SOUND_ON  (BUTTON_SOUND_SOUND | BUTTON_ON)
+
+/* some positions in the game control window */
+#define GAME_BUTTON_XSIZE      30
+#define GAME_BUTTON_YSIZE      30
+#define GAME_CONTROL_XPOS      5
+#define GAME_CONTROL_YPOS      215
+#define GAME_CONTROL_XSIZE     90
+#define GAME_CONTROL_YSIZE     (GAME_BUTTON_YSIZE)
+#define GAME_BUTTON_STOP_XPOS  (GAME_CONTROL_XPOS + 0 * GAME_BUTTON_XSIZE)
+#define GAME_BUTTON_PAUSE_XPOS (GAME_CONTROL_XPOS + 1 * GAME_BUTTON_XSIZE)
+#define GAME_BUTTON_PLAY_XPOS  (GAME_CONTROL_XPOS + 2 * GAME_BUTTON_XSIZE)
+#define GAME_BUTTON_ANY_YPOS   (GAME_CONTROL_YPOS)
+
+#define ON_GAME_BUTTON(x,y)    ((x)>=(DX+GAME_CONTROL_XPOS) && \
+                                (x)< (DX+GAME_CONTROL_XPOS +           \
+                                      GAME_CONTROL_XSIZE) &&           \
+                                (y)>=(DY+GAME_CONTROL_YPOS) && \
+                                (y)< (DY+GAME_CONTROL_YPOS +           \
+                                      GAME_CONTROL_YSIZE))
+#define GAME_BUTTON(x)         (((x)-(DX+GAME_CONTROL_XPOS))/GAME_BUTTON_XSIZE)
+
+/* values for game control */
+#define BUTTON_GAME_STOP       (1L<<0)
+#define BUTTON_GAME_PAUSE      (1L<<1)
+#define BUTTON_GAME_PLAY       (1L<<2)
+
+/* some positions in the asking window */
+#define OK_BUTTON_XPOS         2
+#define OK_BUTTON_YPOS         250
+#define OK_BUTTON_GFX_YPOS     0
+#define OK_BUTTON_XSIZE                46
+#define OK_BUTTON_YSIZE                28
+#define NO_BUTTON_XPOS         52
+#define NO_BUTTON_YPOS         OK_BUTTON_YPOS
+#define NO_BUTTON_XSIZE                OK_BUTTON_XSIZE
+#define NO_BUTTON_YSIZE                OK_BUTTON_YSIZE
+#define CONFIRM_BUTTON_XPOS    2
+#define CONFIRM_BUTTON_GFX_YPOS        30
+#define CONFIRM_BUTTON_YPOS    OK_BUTTON_YPOS
+#define CONFIRM_BUTTON_XSIZE   96
+#define CONFIRM_BUTTON_YSIZE   OK_BUTTON_YSIZE
+
+#define ON_CHOOSE_BUTTON(x,y)  (((x)>=(DX+OK_BUTTON_XPOS) &&           \
+                                 (x)< (DX+OK_BUTTON_XPOS +             \
+                                       OK_BUTTON_XSIZE) &&             \
+                                 (y)>=(DY+OK_BUTTON_YPOS) &&           \
+                                 (y)< (DY+OK_BUTTON_YPOS +             \
+                                       OK_BUTTON_YSIZE)) ||            \
+                                ((x)>=(DX+NO_BUTTON_XPOS) &&           \
+                                 (x)< (DX+NO_BUTTON_XPOS +             \
+                                       NO_BUTTON_XSIZE) &&             \
+                                 (y)>=(DY+NO_BUTTON_YPOS) &&           \
+                                 (y)< (DY+NO_BUTTON_YPOS +             \
+                                       NO_BUTTON_YSIZE)))
+#define ON_CONFIRM_BUTTON(x,y) (((x)>=(DX+CONFIRM_BUTTON_XPOS) &&      \
+                                 (x)< (DX+CONFIRM_BUTTON_XPOS +        \
+                                       CONFIRM_BUTTON_XSIZE) &&        \
+                                 (y)>=(DY+CONFIRM_BUTTON_YPOS) &&      \
+                                 (y)< (DY+CONFIRM_BUTTON_YPOS +        \
+                                       CONFIRM_BUTTON_YSIZE)))
+#define CHOOSE_BUTTON(x)       (((x)-(DX+OK_BUTTON_XPOS))/OK_BUTTON_XSIZE)
+
+/* values for asking control */
+#define BUTTON_OK              (1L<<0)
+#define BUTTON_NO              (1L<<1)
+#define BUTTON_CONFIRM         (1L<<2)
+
+#endif
diff --git a/src/misc.c b/src/misc.c
new file mode 100644 (file)
index 0000000..a066cff
--- /dev/null
@@ -0,0 +1,376 @@
+/***********************************************************
+*  Rocks'n'Diamonds -- McDuffin Strikes Back!              *
+*----------------------------------------------------------*
+*  ©1995 Artsoft Development                               *
+*        Holger Schemel                                    *
+*        33659 Bielefeld-Senne                             *
+*        Telefon: (0521) 493245                            *
+*        eMail: aeglos@valinor.owl.de                      *
+*               aeglos@uni-paderborn.de                    *
+*               q99492@pbhrzx.uni-paderborn.de             *
+*----------------------------------------------------------*
+*  misc.c                                                  *
+*                                                          *
+*  Letzte Aenderung: 15.06.1995                            *
+***********************************************************/
+
+#include "misc.h"
+#include "tools.h"
+#include "sound.h"
+#include <pwd.h>
+#include <unistd.h>
+#include <time.h>
+#include <sys/time.h>
+#include <sys/param.h>
+#include <sys/types.h>
+
+void microsleep(unsigned long usec)
+{
+  struct timeval delay;
+
+  delay.tv_sec  = usec / 1000000;
+  delay.tv_usec = usec % 1000000;
+
+  if (select(0,NULL,NULL,NULL,&delay)!=0)
+    fprintf(stderr,"%s: in function microsleep: select failed!\n",
+           progname);
+}
+
+unsigned long be2long(unsigned long *be)       /* big-endian -> longword */
+{
+  unsigned char *ptr = (unsigned char *)be;
+
+  return(ptr[0]<<24 | ptr[1]<<16 | ptr[2]<<8 | ptr[3]);
+}
+
+char *int2str(int ct, int nr)
+{
+  static char str[20];
+
+  sprintf(str,"%09d",ct);
+  return(&str[strlen(str)-nr]);
+}
+
+unsigned int RND(unsigned int max)
+{
+  return(rand() % max);
+}
+
+unsigned int InitRND(long seed)
+{
+  struct timeval current_time;
+
+  if (seed==NEW_RANDOMIZE)
+  {
+    gettimeofday(&current_time,NULL);
+    srand((unsigned int) current_time.tv_usec);
+    return((unsigned int) current_time.tv_usec);
+  }
+  else
+  {
+    srand((unsigned int) seed);
+    return((unsigned int) seed);
+  }
+}
+
+char *GetLoginName()
+{
+  struct passwd *pwd;
+
+  if (!(pwd=getpwuid(getuid())))
+    return("ANONYMOUS");
+  else
+    return(pwd->pw_name);
+}
+
+static struct AnimInfo toon[NUM_TOONS] =
+{
+  DWARF_XSIZE, DWARF_YSIZE,
+  DWARF_X, DWARF_Y,
+  DWARF_FRAMES,
+  DWARF_FPS,
+  DWARF_STEPSIZE,
+  FALSE,
+  ANIMDIR_RIGHT,
+  ANIMPOS_DOWN,
+
+  DWARF_XSIZE, DWARF_YSIZE,
+  DWARF_X, DWARF2_Y,
+  DWARF_FRAMES,
+  DWARF_FPS,
+  DWARF_STEPSIZE,
+  FALSE,
+  ANIMDIR_LEFT,
+  ANIMPOS_DOWN,
+
+  JUMPER_XSIZE, JUMPER_YSIZE,
+  JUMPER_X, JUMPER_Y,
+  JUMPER_FRAMES,
+  JUMPER_FPS,
+  JUMPER_STEPSIZE,
+  FALSE,
+  ANIMDIR_LEFT,
+  ANIMPOS_DOWN,
+
+  CLOWN_XSIZE, CLOWN_YSIZE,
+  CLOWN_X, CLOWN_Y,
+  CLOWN_FRAMES,
+  CLOWN_FPS,
+  CLOWN_STEPSIZE,
+  FALSE,
+  ANIMDIR_UP,
+  ANIMPOS_ANY,
+
+  BIRD_XSIZE, BIRD_YSIZE,
+  BIRD1_X, BIRD1_Y,
+  BIRD_FRAMES,
+  BIRD_FPS,
+  BIRD_STEPSIZE,
+  TRUE,
+  ANIMDIR_RIGHT,
+  ANIMPOS_UPPER,
+
+  BIRD_XSIZE, BIRD_YSIZE,
+  BIRD2_X, BIRD2_Y,
+  BIRD_FRAMES,
+  BIRD_FPS,
+  BIRD_STEPSIZE,
+  TRUE,
+  ANIMDIR_LEFT,
+  ANIMPOS_UPPER
+};
+
+void InitAnimation()
+{
+  HandleAnimation(ANIM_START);
+}
+
+void StopAnimation()
+{
+  HandleAnimation(ANIM_STOP);
+}
+
+void DoAnimation()
+{
+  HandleAnimation(ANIM_CONTINUE);
+}
+
+void HandleAnimation(int mode)
+{
+  static long animstart_delay = -1;
+  static long animstart_delay_value = 0;
+  static BOOL anim_restart = TRUE;
+  static BOOL reset_delay = TRUE;
+  static int toon_nr = 0;
+
+  if (!toons_on || game_status==PLAYING)
+    return;
+
+  switch(mode)
+  {
+    case ANIM_START:
+      anim_restart = TRUE;
+      reset_delay = TRUE;
+      return;
+      break;
+    case ANIM_CONTINUE:
+      break;
+    case ANIM_STOP:
+      redraw_mask |= REDRAW_FIELD;
+      BackToFront();
+      return;
+      break;
+    default:
+      break;
+  }
+
+  if (reset_delay)
+  {
+    animstart_delay = Counter();
+    animstart_delay_value = RND(500);
+    reset_delay = FALSE;
+  }
+
+  if (anim_restart)
+  {
+    if (!DelayReached(&animstart_delay,animstart_delay_value))
+      return;
+
+    toon_nr = RND(NUM_TOONS);
+  }
+
+  anim_restart = reset_delay = AnimateToon(toon_nr,anim_restart);
+}
+
+BOOL AnimateToon(int toon_nr, BOOL restart)
+{
+  static pos_x = 0, pos_y = 0;
+  static delta_x = 0, delta_y = 0;
+  static int frame = 0, frame_step = 1;
+  static BOOL horiz_move, vert_move;
+  static long anim_delay = 0;
+  static int anim_delay_value = 0;
+  struct AnimInfo *anim = &toon[toon_nr];
+  static int width,height;
+  static int pad_x,pad_y;
+  static int cut_x,cut_y;
+  static int src_x, src_y;
+  static int dest_x, dest_y;
+
+  if (restart)
+  {
+    horiz_move = (anim->direction & (ANIMDIR_LEFT | ANIMDIR_RIGHT));
+    vert_move = (anim->direction & (ANIMDIR_UP | ANIMDIR_DOWN));
+    anim_delay_value = 100/anim->frames_per_second;
+    frame = 0;
+
+    if (horiz_move)
+    {
+      if (anim->position==ANIMPOS_UP)
+       pos_y = 0;
+      else if (anim->position==ANIMPOS_DOWN)
+       pos_y = FULL_SYSIZE-anim->height;
+      else if (anim->position==ANIMPOS_UPPER)
+       pos_y = RND((FULL_SYSIZE-anim->height)/2);
+      else
+       pos_y = RND(FULL_SYSIZE-anim->height);
+
+      if (anim->direction==ANIMDIR_RIGHT)
+      {
+       delta_x = anim->stepsize;
+       pos_x = -anim->width+delta_x;
+      }
+      else
+      {
+       delta_x = -anim->stepsize;
+       pos_x = FULL_SXSIZE+delta_x;
+      }
+      delta_y = 0;
+    }
+    else
+    {
+      if (anim->position==ANIMPOS_LEFT)
+       pos_x = 0;
+      else if (anim->position==ANIMPOS_RIGHT)
+       pos_x = FULL_SXSIZE-anim->width;
+      else
+       pos_x = RND(FULL_SXSIZE-anim->width);
+
+      if (anim->direction==ANIMDIR_DOWN)
+      {
+       delta_y = anim->stepsize;
+       pos_y = -anim->height+delta_y;
+      }
+      else
+      {
+       delta_y = -anim->stepsize;
+       pos_y = FULL_SYSIZE+delta_y;
+      }
+      delta_x = 0;
+    }
+  }
+
+  if (pos_x <= -anim->width  - anim->stepsize ||
+      pos_x >=  FULL_SXSIZE  + anim->stepsize ||
+      pos_y <= -anim->height - anim->stepsize ||
+      pos_y >=  FULL_SYSIZE  + anim->stepsize)
+    return(TRUE);
+
+  if (!DelayReached(&anim_delay,anim_delay_value))
+  {
+    if (game_status==HELPSCREEN && !restart)
+      DrawAnim(src_x+cut_x,src_y+cut_y, width,height,
+              REAL_SX+dest_x,REAL_SY+dest_y, pad_x,pad_y);
+
+    return(FALSE);
+  }
+
+  if (pos_x<-anim->width)
+    pos_x = -anim->width;
+  else if (pos_x>FULL_SXSIZE)
+    pos_x = FULL_SXSIZE;
+  if (pos_y<-anim->height)
+    pos_y = -anim->height;
+  else if (pos_y>FULL_SYSIZE)
+    pos_y = FULL_SYSIZE;
+
+  pad_x = (horiz_move ? anim->stepsize : 0);
+  pad_y = (vert_move  ? anim->stepsize : 0);
+  src_x = anim->src_x + frame * anim->width;
+  src_y = anim->src_y;
+  dest_x = pos_x;
+  dest_y = pos_y;
+  cut_x = cut_y = 0;
+  width  = anim->width;
+  height = anim->height;
+
+  if (pos_x<0)
+  {
+    dest_x = 0;
+    width += pos_x;
+    cut_x = -pos_x;
+  }
+  else if (pos_x>FULL_SXSIZE-anim->width)
+    width -= (pos_x - (FULL_SXSIZE-anim->width));
+
+  if (pos_y<0)
+  {
+    dest_y = 0;
+    height += pos_y;
+    cut_y = -pos_y;
+  }
+  else if (pos_y>FULL_SYSIZE-anim->height)
+    height -= (pos_y - (FULL_SYSIZE-anim->height));
+
+  DrawAnim(src_x+cut_x,src_y+cut_y, width,height,
+          REAL_SX+dest_x,REAL_SY+dest_y, pad_x,pad_y);
+
+  pos_x += delta_x;
+  pos_y += delta_y;
+  frame += frame_step;
+
+  if (frame<0 || frame>=anim->frames)
+  {
+    if (anim->pingpong)
+    {
+      frame_step *= -1;
+      frame = (frame<0 ? 1 : anim->frames-2);
+    }
+    else
+      frame = (frame<0 ? anim->frames-1 : 0);
+  }
+
+  return(FALSE);
+}
+
+void DrawAnim(int src_x, int src_y, int width, int height,
+             int dest_x, int dest_y, int pad_x, int pad_y)
+{
+  int buf_x = DOOR_GFX_PAGEX3, buf_y = DOOR_GFX_PAGEY1;
+
+  XCopyArea(display,backbuffer,pix[PIX_DB_DOOR],gc,dest_x-pad_x,dest_y-pad_y,
+           width+2*pad_x,height+2*pad_y, buf_x,buf_y);
+  XSetClipOrigin(display,clip_gc[PIX_TOONS],dest_x-src_x,dest_y-src_y);
+  XCopyArea(display,pix[PIX_TOONS],backbuffer,clip_gc[PIX_TOONS],
+           src_x,src_y, width,height, dest_x,dest_y);
+  XCopyArea(display,backbuffer,window,gc, dest_x-pad_x,dest_y-pad_y,
+           width+2*pad_x,height+2*pad_y, dest_x-pad_x,dest_y-pad_y);
+
+  BackToFront();
+
+  XCopyArea(display,pix[PIX_DB_DOOR],backbuffer,gc, buf_x,buf_y,
+           width+2*pad_x,height+2*pad_y, dest_x-pad_x,dest_y-pad_y);
+
+/*
+  XCopyArea(display,backbuffer,pix[PIX_DB_DOOR],gc,dest_x-pad_x,dest_y-pad_y,
+           width+2*pad_x,height+2*pad_y, buf_x,buf_y);
+  XSetClipOrigin(display,clip_gc[PIX_TOONS],
+                buf_x-src_x+pad_x,buf_y-src_y+pad_y);
+  XCopyArea(display,pix[PIX_TOONS],pix[PIX_DB_DOOR],clip_gc[PIX_TOONS],
+           src_x,src_y, width,height, buf_x+pad_x,buf_y+pad_y);
+  XCopyArea(display,pix[PIX_DB_DOOR],window,gc, buf_x,buf_y,
+           width+2*pad_x,height+2*pad_y, dest_x-pad_x,dest_y-pad_y);
+*/
+
+  XFlush(display);
+}
diff --git a/src/misc.h b/src/misc.h
new file mode 100644 (file)
index 0000000..c4cba8d
--- /dev/null
@@ -0,0 +1,101 @@
+/***********************************************************
+*  Rocks'n'Diamonds -- McDuffin Strikes Back!              *
+*----------------------------------------------------------*
+*  ©1995 Artsoft Development                               *
+*        Holger Schemel                                    *
+*        33659 Bielefeld-Senne                             *
+*        Telefon: (0521) 493245                            *
+*        eMail: aeglos@valinor.owl.de                      *
+*               aeglos@uni-paderborn.de                    *
+*               q99492@pbhrzx.uni-paderborn.de             *
+*----------------------------------------------------------*
+*  misc.h                                                  *
+*                                                          *
+*  Letzte Aenderung: 15.06.1995                            *
+***********************************************************/
+
+#ifndef MISC_H
+#define MISC_H
+
+#include "main.h"
+
+/* values for cartoon figures */
+#define NUM_TOONS      6
+
+#define DWARF_XSIZE    40
+#define DWARF_YSIZE    48
+#define DWARF_X                2
+#define DWARF_Y                72
+#define DWARF2_Y       186
+#define DWARF_FRAMES   8
+#define DWARF_FPS      10
+#define DWARF_STEPSIZE 4
+#define JUMPER_XSIZE   48
+#define JUMPER_YSIZE   56
+#define JUMPER_X       2
+#define JUMPER_Y       125
+#define JUMPER_FRAMES  8
+#define JUMPER_FPS     10
+#define JUMPER_STEPSIZE        4
+#define CLOWN_XSIZE    80
+#define CLOWN_YSIZE    110
+#define CLOWN_X                327
+#define CLOWN_Y                10
+#define CLOWN_FRAMES   1
+#define CLOWN_FPS      10
+#define CLOWN_STEPSIZE 4
+#define BIRD_XSIZE     32
+#define BIRD_YSIZE     30
+#define BIRD1_X                2
+#define BIRD1_Y                2
+#define BIRD2_X                2
+#define BIRD2_Y                37
+#define BIRD_FRAMES    8
+#define BIRD_FPS       20
+#define BIRD_STEPSIZE  4
+
+#define ANIMDIR_LEFT   1
+#define ANIMDIR_RIGHT  2
+#define ANIMDIR_UP     4
+#define ANIMDIR_DOWN   8
+
+#define ANIMPOS_ANY    0
+#define ANIMPOS_LEFT   1
+#define ANIMPOS_RIGHT  2
+#define ANIMPOS_UP     4
+#define ANIMPOS_DOWN   8
+#define ANIMPOS_UPPER  16
+
+#define ANIM_START     0
+#define ANIM_CONTINUE  1
+#define ANIM_STOP      2
+
+struct AnimInfo
+{
+  int width, height;
+  int src_x, src_y;
+  int frames;
+  int frames_per_second;
+  int stepsize;
+  BOOL pingpong;
+  int direction;
+  int position;
+};
+
+#define NEW_RANDOMIZE  -1
+
+void microsleep(unsigned long);
+unsigned long be2long(unsigned long *);
+char *int2str(int, int);
+unsigned int RND(unsigned int);
+unsigned int InitRND(long);
+char *GetLoginName(void);
+
+void InitAnimation(void);
+void StopAnimation(void);
+void DoAnimation(void);
+void HandleAnimation(int);
+BOOL AnimateToon(int, BOOL);
+void DrawAnim(int, int, int, int, int, int, int, int);
+
+#endif
diff --git a/src/screens.c b/src/screens.c
new file mode 100644 (file)
index 0000000..2d5d17c
--- /dev/null
@@ -0,0 +1,1385 @@
+/***********************************************************
+*  Rocks'n'Diamonds -- McDuffin Strikes Back!              *
+*----------------------------------------------------------*
+*  ©1995 Artsoft Development                               *
+*        Holger Schemel                                    *
+*        33659 Bielefeld-Senne                             *
+*        Telefon: (0521) 493245                            *
+*        eMail: aeglos@valinor.owl.de                      *
+*               aeglos@uni-paderborn.de                    *
+*               q99492@pbhrzx.uni-paderborn.de             *
+*----------------------------------------------------------*
+*  screens.c                                               *
+*                                                          *
+*  Letzte Aenderung: 15.06.1995                            *
+***********************************************************/
+
+#include "screens.h"
+#include "events.h"
+#include "sound.h"
+#include "game.h"
+#include "tools.h"
+#include "editor.h"
+#include "misc.h"
+
+void DrawMainMenu()
+{
+  int i;
+
+  FadeSounds();
+  GetPlayerConfig();
+  LoadLevel(level_nr);
+
+  ClearWindow();
+  DrawText(SX+16, SY+8,  "ROCKS'N'DIAMONDS",FS_BIG,FC_YELLOW);
+  DrawText(SX+25+16, SY+46, "Copyright ^1995 by Holger Schemel",
+          FS_SMALL,FC_RED);
+  DrawText(SX+32, SY+64, "Name:",FS_BIG,FC_GREEN);
+  DrawText(SX+192,SY+64, player.alias_name,FS_BIG,FC_RED);
+  DrawText(SX+32, SY+96, "Level:",FS_BIG,FC_GREEN);
+  DrawText(SX+352,SY+96, int2str(level_nr,3),FS_BIG,
+          (level_nr<leveldir[leveldir_nr].num_ready ? FC_RED : FC_YELLOW));
+  DrawText(SX+32, SY+128,"Hall Of Fame",FS_BIG,FC_GREEN);
+  DrawText(SX+32, SY+160,"Level Creator",FS_BIG,FC_GREEN);
+  DrawText(SY+32, SY+192,"Info Screen",FS_BIG,FC_GREEN);
+  DrawText(SX+32, SY+224,"Start Game",FS_BIG,FC_GREEN);
+  DrawText(SX+32, SY+256,"Setup",FS_BIG,FC_GREEN);
+  DrawText(SX+32, SY+288,"Quit",FS_BIG,FC_GREEN);
+
+  DrawMicroLevel(MICROLEV_XPOS,MICROLEV_YPOS);
+
+  for(i=2;i<10;i++)
+    DrawGraphic(0,i,GFX_KUGEL_BLAU);
+  DrawGraphic(10,3,GFX_KUGEL_BLAU);
+  DrawGraphic(14,3,GFX_KUGEL_BLAU);
+
+  DrawText(SX+54+16,SY+326,"A Game by Artsoft Development",FS_SMALL,FC_BLUE);
+  DrawText(SX+40+16,SY+344,"Graphics: Deluxe Paint IV Amiga",
+          FS_SMALL,FC_BLUE);
+  DrawText(SX+60+16,SY+362,"Sounds: AudioMaster IV Amiga",
+          FS_SMALL,FC_BLUE);
+
+  FadeToFront();
+  InitAnimation();
+  HandleMainMenu(0,0,0,0,MB_MENU_MARK);
+
+  TapeStop();
+  if (TAPE_IS_EMPTY(tape))
+    LoadLevelTape(level_nr);
+  DrawCompleteVideoDisplay();
+
+  OpenDoor(DOOR_CLOSE_1 | DOOR_OPEN_2);
+
+  XAutoRepeatOn(display);
+}
+
+void HandleMainMenu(int mx, int my, int dx, int dy, int button)
+{
+  static int choice = 3;
+  static int redraw = TRUE;
+  int x = (mx+32-SX)/32, y = (my+32-SY)/32;
+
+  if (redraw)
+  {
+    DrawGraphic(0,choice-1,GFX_KUGEL_ROT);
+    redraw = FALSE;
+  }
+
+  if (dx || dy)
+  {
+    if (dx && choice==4)
+    {
+      x = (dx<0 ? 11 : 15);
+      y = 4;
+    }
+    else if (dy)
+    {
+      x = 1;
+      y = choice+dy;
+    }
+    else
+      x = y = 0;
+
+    if (y<3)
+      y = 3;
+    else if (y>10)
+      y = 10;
+  }
+
+  if (!mx && !my && !dx && !dy)
+  {
+    x = 1;
+    y = choice;
+  }
+
+  if (y==4 && ((x==11 && level_nr>0) ||
+              (x==15 && level_nr<LEVELDIR_SIZE(leveldir[leveldir_nr]))) &&
+      button)
+  {
+    static long level_delay = 0;
+    int step = (button==1 ? 1 : button==2 ? 5 : 10);
+
+    if (!DelayReached(&level_delay,20))
+      goto out;
+
+    level_nr += (x==11 ? -step : +step);
+    if (level_nr<0)
+      level_nr = 0;
+    if (level_nr>LEVELDIR_SIZE(leveldir[leveldir_nr])-1)
+      level_nr = LEVELDIR_SIZE(leveldir[leveldir_nr])-1;
+
+    if (level_nr>player.handicap && level_nr<leveldir[leveldir_nr].num_ready)
+    {
+      if (x==11 || leveldir[leveldir_nr].num_free==0)
+       level_nr = player.handicap;
+      else
+       level_nr = leveldir[leveldir_nr].num_ready;
+    }
+
+    DrawTextExt(drawto,gc,SX+352,SY+96, int2str(level_nr,3),FS_BIG,
+               (level_nr<leveldir[leveldir_nr].num_ready ?FC_RED :FC_YELLOW));
+    DrawTextExt(window,gc,SX+352,SY+96,        int2str(level_nr,3),FS_BIG,
+               (level_nr<leveldir[leveldir_nr].num_ready ?FC_RED :FC_YELLOW));
+
+    LoadLevel(level_nr);
+    DrawMicroLevel(MICROLEV_XPOS,MICROLEV_YPOS);
+
+    TapeErase();
+    LoadLevelTape(level_nr);
+    DrawCompleteVideoDisplay();
+  }
+  else if (x==1 && y>=3 && y<=10)
+  {
+    if (button)
+    {
+      if (y!=choice)
+      {
+       DrawGraphic(0,y-1,GFX_KUGEL_ROT);
+       DrawGraphic(0,choice-1,GFX_KUGEL_BLAU);
+      }
+      choice = y;
+    }
+    else
+    {
+      if (y==3)
+      {
+       game_status = TYPENAME;
+       HandleTypeName(strlen(player.alias_name),0);
+      }
+      else if (y==4)
+      {
+       if (num_leveldirs)
+       {
+         game_status = CHOOSELEVEL;
+         DrawChooseLevel();
+         redraw = TRUE;
+       }
+      }
+      else if (y==5)
+      {
+       game_status = HALLOFFAME;
+       DrawHallOfFame(-1);
+       redraw = TRUE;
+      }
+      else if (y==6)
+      {
+       game_status = LEVELED;
+       DrawLevelEd();
+       redraw = TRUE;
+      }
+      else if (y==7)
+      {
+       game_status = HELPSCREEN;
+       DrawHelpScreen();
+       redraw = TRUE;
+      }
+      else if (y==8)
+      {
+       if (autorecord_on && !tape.playing)
+         TapeInitRecording();
+
+       game_status = PLAYING;
+       InitGame();
+       redraw = TRUE;
+      }
+      else if (y==9)
+      {
+       game_status = SETUP;
+       DrawSetupScreen();
+       redraw = TRUE;
+      }
+      else if (y==10)
+      {
+        if (AreYouSure("Do you really want to quit ?",AYS_ASK|AYS_STAY_CLOSED))
+         game_status = EXITGAME;
+      }
+    }
+  }
+  BackToFront();
+
+  out:
+
+  if (game_status==MAINMENU)
+    DoAnimation();
+}
+
+#define MAX_HELPSCREEN_ELS     10
+#define HA_NEXT                        -999
+#define HA_END                 -1000
+
+static long helpscreen_state;
+static int helpscreen_step[MAX_HELPSCREEN_ELS];
+static int helpscreen_frame[MAX_HELPSCREEN_ELS];
+static int helpscreen_delay[MAX_HELPSCREEN_ELS];
+static int helpscreen_action[] =
+{
+  GFX_ERDREICH,1,100,                                          HA_NEXT,
+  GFX_LEERRAUM,1,100,                                          HA_NEXT,
+  GFX_MORAST_LEER,1,100,                                       HA_NEXT,
+  GFX_BETON,1,100,                                             HA_NEXT,
+  GFX_MAUERWERK,1,100,                                         HA_NEXT,
+  GFX_FELSBODEN,1,100,                                         HA_NEXT,
+  GFX_EDELSTEIN,2,5,                                           HA_NEXT,
+  GFX_DIAMANT,2,5,                                             HA_NEXT,
+  GFX_FELSBROCKEN,4,5,                                         HA_NEXT,
+  GFX_BOMBE,1,50, GFX_EXPLOSION,8,1, GFX_LEERRAUM,1,10,                HA_NEXT,
+  GFX_KOKOSNUSS,1,50, GFX_CRACKINGNUT,3,1, GFX_EDELSTEIN,1,10, HA_NEXT,
+  GFX_ERZ_1,1,50, GFX_EXPLOSION,8,1, GFX_EDELSTEIN,1,10,       HA_NEXT,
+  GFX_ERZ_2,1,50, GFX_EXPLOSION,8,1, GFX_DIAMANT,1,10,         HA_NEXT,
+  GFX_GEBLUBBER,4,4,                                           HA_NEXT,
+  GFX_SCHLUESSEL1,4,33,                                                HA_NEXT,
+  GFX_PFORTE1,4,33,                                            HA_NEXT,
+  GFX_PFORTE1X,4,33,                                           HA_NEXT,
+  GFX_DYNAMIT_AUS,1,100,                                       HA_NEXT,
+  GFX_DYNAMIT,7,6, GFX_EXPLOSION,8,1, GFX_LEERRAUM,1,10,       HA_NEXT,
+  GFX_FLIEGER+4,1,3, GFX_FLIEGER+0,1,3, GFX_FLIEGER+4,1,3,
+  GFX_FLIEGER+5,1,3, GFX_FLIEGER+1,1,3, GFX_FLIEGER+5,1,3,
+  GFX_FLIEGER+6,1,3, GFX_FLIEGER+2,1,3, GFX_FLIEGER+6,1,3,
+  GFX_FLIEGER+7,1,3, GFX_FLIEGER+3,1,3, GFX_FLIEGER+7,1,3,     HA_NEXT,
+  GFX_KAEFER+4,1,1, GFX_KAEFER+0,1,1, GFX_KAEFER+4,1,1,
+  GFX_KAEFER+5,1,1, GFX_KAEFER+1,1,1, GFX_KAEFER+5,1,1,
+  GFX_KAEFER+6,1,1, GFX_KAEFER+2,1,1, GFX_KAEFER+6,1,1,
+  GFX_KAEFER+7,1,1, GFX_KAEFER+3,1,1, GFX_KAEFER+7,1,1,                HA_NEXT,
+  GFX_PACMAN+0,1,3, GFX_PACMAN+4,1,2, GFX_PACMAN+0,1,3,
+  GFX_PACMAN+1,1,3, GFX_PACMAN+5,1,2, GFX_PACMAN+1,1,3,
+  GFX_PACMAN+2,1,3, GFX_PACMAN+6,1,2, GFX_PACMAN+2,1,3,
+  GFX_PACMAN+3,1,3, GFX_PACMAN+7,1,2, GFX_PACMAN+3,1,3,                HA_NEXT,
+  GFX_MAMPFER+0,4,0, GFX_MAMPFER+3,1,0, GFX_MAMPFER+2,1,0,
+  GFX_MAMPFER+1,1,0,                                           HA_NEXT,
+  GFX_ZOMBIE+0,4,0, GFX_ZOMBIE+3,1,0, GFX_ZOMBIE+2,1,0,
+  GFX_ZOMBIE+1,1,0,                                            HA_NEXT,
+  GFX_ABLENK,4,1,                                              HA_NEXT,
+  GFX_AMOEBE_LEBT,4,40,                                                HA_NEXT,
+  GFX_AMOEBE_TOT+2,2,50, GFX_AMOEBE_TOT,2,50,                  HA_NEXT,
+  GFX_SIEB_LEER,4,2,                                           HA_NEXT,
+  HA_END
+};
+static char *helpscreen_eltext[][2] =
+{
+  "Normal sand:", "You can dig through it",
+  "Empty field:", "You can walk through it",
+  "Quicksand: You cannot pass it,", "but rocks can fall though it",
+  "Massive Wall:", "Nothing can go through it",
+  "Normal Wall: You can't go through", "it, but you can bomb it away",
+  "Old Wall: Like normal wall, but", "some things can fall down from it",
+  "Emerald: You must collect enough of", "them to finish a level",
+  "Diamond: Counts as 3 emeralds;", "Can be destroyed by rocks",
+  "Rock: Smashes several things;", "Can be moved by the player",
+  "Bomb: You can move it, but be", "careful when dropping it",
+  "Nut: Throw a rock on it to open it;", "Each nut contains an emerald",
+  "Wall with an Emerald inside:", "Bomb the wall away to get it",
+  "Wall with a Diamond inside:", "Bomb the wall away to get it",
+  "Acid: Destroys everything that", "falls or walks into it",
+  "Key: Opens the door that has the", "same color (red/yellow/green/blue)",
+  "Door: Can be opened by the key", "with the same color",
+  "Door: You have to find out the", "right color of the key for it",
+  "Dynamite: Collect it and use it to", "destroy walls or kill enemies",
+  "Dynamite: This one explodes after", "a few seconds",
+  "Spaceship: Moves at the left side", "of walls; don't touch it!",
+  "Bug: Moves at the right side of", "walls; don't touch it!",
+  "Pacman: Eats the amoeba and you,", "if you're not careful",
+  "Cruncher: Eats diamonds and you,", "if you're not careful",
+  "Robot: Tries to kill the player", "",
+  "Magic Wheel: Touch it to get rid of", "the robots for some seconds",
+  "Living Amoeba: Grows through empty", "fields, sand and quicksand",
+  "Dead Amoeba: Does not grow, but", "can still kill bugs and spaceships",
+  "Magic Wall: Changes rocks, emeralds", "and diamonds when they pass it",
+};
+static int num_helpscreen_els = sizeof(helpscreen_eltext)/(2*sizeof(char *));
+
+static char *helpscreen_music[][3] =
+{
+  "Alchemy",                   "Ian Boddy",            "Drive",
+  "The Chase",                 "Propaganda",           "A Secret Wish",
+  "Network 23",                        "Tangerine Dream",      "Exit",
+  "Czardasz",                  "Robert Pieculewicz",   "Czardasz",
+  "21st Century Common Man",   "Tangerine Dream",      "Tyger",
+  "Voyager",                   "The Alan Parsons Project","Pyramid",
+  "Twilight Painter",          "Tangerine Dream",      "Heartbreakers"
+};
+static int helpscreen_musicpos;
+
+void DrawHelpScreenElAction(int start)
+{
+  int i = 0, j = 0;
+  int frame, delay, graphic;
+  int xstart = SX+16, ystart = SY+64+2*32, ystep = TILEY+4;
+
+  while(helpscreen_action[j] != HA_END)
+  {
+    if (i>=start+MAX_HELPSCREEN_ELS || i>=num_helpscreen_els)
+      break;
+    else if (i<start || helpscreen_delay[i-start])
+    {
+      if (i>=start && helpscreen_delay[i-start])
+       helpscreen_delay[i-start]--;
+
+      while(helpscreen_action[j] != HA_NEXT)
+       j++;
+      j++;
+      i++;
+      continue;
+    }
+
+    j += 3*helpscreen_step[i-start];
+    graphic = helpscreen_action[j++];
+
+    if (helpscreen_frame[i-start])
+    {
+      frame = helpscreen_action[j++] - helpscreen_frame[i-start];
+      helpscreen_frame[i-start]--;
+    }
+    else
+    {
+      frame = 0;
+      helpscreen_frame[i-start] = helpscreen_action[j++]-1;
+    }
+
+    delay = helpscreen_action[j++];
+    helpscreen_delay[i-start] = delay;
+
+    if (helpscreen_action[j] == HA_NEXT)
+    {
+      if (!helpscreen_frame[i-start])
+       helpscreen_step[i-start] = 0;
+    }
+    else
+    {
+      if (!helpscreen_frame[i-start])
+       helpscreen_step[i-start]++;
+      while(helpscreen_action[j] != HA_NEXT)
+       j++;
+    }
+    j++;
+
+    DrawGraphicExtHiRes(drawto,gc,xstart,ystart+(i-start)*ystep,
+                       graphic+frame);
+    i++;
+  }
+
+  redraw_tiles += 28;
+  for(i=2;i<16;i++)
+    redraw[0][i] = redraw[1][i] = TRUE;
+  redraw_mask |= REDRAW_TILES;
+}
+
+void DrawHelpScreenElText(int start)
+{
+  int i;
+  int xstart = SX+56, ystart = SY+65+2*32, ystep = TILEY+4;
+  char text[FULL_SXSIZE/FONT2_XSIZE+10];
+
+  ClearWindow();
+  DrawText(SX+16, SY+8,  "ROCKS'N'DIAMONDS",FS_BIG,FC_YELLOW);
+  DrawText(SX+25+16, SY+46, "Copyright ^1995 by Holger Schemel",
+          FS_SMALL,FC_RED);
+
+  sprintf(text,"The game elements:");
+  DrawText(SX+(SXSIZE-strlen(text)*FONT2_XSIZE)/2,SY+100,
+          text,FS_SMALL,FC_GREEN);
+
+  for(i=start;i<start+MAX_HELPSCREEN_ELS && i<num_helpscreen_els;i++)
+  {
+    DrawText(xstart,ystart+(i-start)*ystep+(*helpscreen_eltext[i][1] ? 0 : 8),
+            helpscreen_eltext[i][0],FS_SMALL,FC_YELLOW);
+    DrawText(xstart,ystart+(i-start)*ystep+16,
+            helpscreen_eltext[i][1],FS_SMALL,FC_YELLOW);
+  }
+
+  sprintf(text,"Press any key or button for next page");
+  DrawText(SX+(SXSIZE-strlen(text)*FONT2_XSIZE)/2,SY+SYSIZE-20,
+          text,FS_SMALL,FC_BLUE);
+}
+
+void DrawHelpScreenMusicText(int num)
+{
+  int ystart = 150, ystep = 30;
+  char text[FULL_SXSIZE/FONT2_XSIZE+10];
+
+  FadeSounds();
+  ClearWindow();
+  DrawText(SX+16, SY+8,  "ROCKS'N'DIAMONDS",FS_BIG,FC_YELLOW);
+  DrawText(SX+25+16, SY+46, "Copyright ^1995 by Holger Schemel",
+          FS_SMALL,FC_RED);
+
+  sprintf(text,"The game background music loops:");
+  DrawText(SX+(SXSIZE-strlen(text)*FONT2_XSIZE)/2,SY+100,
+          text,FS_SMALL,FC_GREEN);
+
+  sprintf(text,"Excerpt from");
+  DrawText(SX+(SXSIZE-strlen(text)*FONT2_XSIZE)/2,SY+ystart+0*ystep,
+          text,FS_SMALL,FC_YELLOW);
+  sprintf(text,"%c%s%c",'\"',helpscreen_music[num][0],'\"');
+  DrawText(SX+(SXSIZE-strlen(text)*FONT2_XSIZE)/2,SY+ystart+1*ystep,
+          text,FS_SMALL,FC_RED);
+  sprintf(text,"by");
+  DrawText(SX+(SXSIZE-strlen(text)*FONT2_XSIZE)/2,SY+ystart+2*ystep,
+          text,FS_SMALL,FC_YELLOW);
+  sprintf(text,"%s",helpscreen_music[num][1]);
+  DrawText(SX+(SXSIZE-strlen(text)*FONT2_XSIZE)/2,SY+ystart+3*ystep,
+          text,FS_SMALL,FC_RED);
+  sprintf(text,"from the album");
+  DrawText(SX+(SXSIZE-strlen(text)*FONT2_XSIZE)/2,SY+ystart+4*ystep,
+          text,FS_SMALL,FC_YELLOW);
+  sprintf(text,"%c%s%c",'\"',helpscreen_music[num][2],'\"');
+  DrawText(SX+(SXSIZE-strlen(text)*FONT2_XSIZE)/2,SY+ystart+5*ystep,
+          text,FS_SMALL,FC_RED);
+
+  sprintf(text,"Press any key or button for next page");
+  DrawText(SX+(SXSIZE-strlen(text)*FONT2_XSIZE)/2,SY+SYSIZE-20,
+          text,FS_SMALL,FC_BLUE);
+
+  PlaySoundLoop(background_loop[num]);
+}
+
+void DrawHelpScreenRegistrationText()
+{
+  int ystart = 150, ystep = 30;
+  char text[FULL_SXSIZE/FONT2_XSIZE+10];
+
+  FadeSounds();
+  ClearWindow();
+  DrawText(SX+16, SY+8,  "ROCKS'N'DIAMONDS",FS_BIG,FC_YELLOW);
+  DrawText(SX+25+16, SY+46, "Copyright ^1995 by Holger Schemel",
+          FS_SMALL,FC_RED);
+
+  sprintf(text,"Registration information:");
+  DrawText(SX+(SXSIZE-strlen(text)*FONT2_XSIZE)/2,SY+100,
+          text,FS_SMALL,FC_GREEN);
+
+  sprintf(text,"Unregistered version");
+  DrawText(SX+(SXSIZE-strlen(text)*FONT2_XSIZE)/2,SY+ystart+4*ystep,
+          text,FS_SMALL,FC_YELLOW);
+
+  sprintf(text,"Press any key or button for main menu");
+  DrawText(SX+(SXSIZE-strlen(text)*FONT2_XSIZE)/2,SY+SYSIZE-20,
+          text,FS_SMALL,FC_BLUE);
+}
+
+void DrawHelpScreen()
+{
+  int i;
+
+  CloseDoor(DOOR_CLOSE_2);
+
+  for(i=0;i<MAX_HELPSCREEN_ELS;i++)
+    helpscreen_step[i] = helpscreen_frame[i] = helpscreen_delay[i] = 0;
+  helpscreen_musicpos = 0;
+  helpscreen_state = 0;
+  DrawHelpScreenElText(0);
+  DrawHelpScreenElAction(0);
+
+  FadeToFront();
+  InitAnimation();
+  PlaySoundLoop(SND_RHYTHMLOOP);
+}
+
+void HandleHelpScreen(int button)
+{
+  static long hs_delay = 0;
+  int num_helpscreen_els_pages =
+    (num_helpscreen_els + MAX_HELPSCREEN_ELS-1) / MAX_HELPSCREEN_ELS;
+  int button_released = !button;
+  int i;
+
+  if (button_released)
+  {
+    if (helpscreen_state<num_helpscreen_els_pages-1)
+    {
+      for(i=0;i<MAX_HELPSCREEN_ELS;i++)
+       helpscreen_step[i] = helpscreen_frame[i] = helpscreen_delay[i] = 0;
+      helpscreen_state++;
+      DrawHelpScreenElText(helpscreen_state*MAX_HELPSCREEN_ELS);
+      DrawHelpScreenElAction(helpscreen_state*MAX_HELPSCREEN_ELS);
+    }
+    else if (helpscreen_state<num_helpscreen_els_pages+num_bg_loops-1)
+    {
+      helpscreen_state++;
+      DrawHelpScreenMusicText(helpscreen_state-num_helpscreen_els_pages);
+    }
+    else if (helpscreen_state==num_helpscreen_els_pages+num_bg_loops-1)
+    {
+      helpscreen_state++;
+      DrawHelpScreenRegistrationText();
+    }
+    else
+    {
+      FadeSounds();
+      DrawMainMenu();
+      game_status = MAINMENU;
+    }
+  }
+  else
+  {
+    if (DelayReached(&hs_delay,3))
+    {
+      if (helpscreen_state<num_helpscreen_els_pages)
+       DrawHelpScreenElAction(helpscreen_state*MAX_HELPSCREEN_ELS);
+    }
+    DoAnimation();
+  }
+
+  BackToFront();
+}
+
+void CheckCheat()
+{
+  int old_handicap = player.handicap;
+
+  if (!strcmp(player.alias_name,"Artsoft"))
+    player.handicap = MAX(0,leveldir[leveldir_nr].num_ready-1);
+
+  if (player.handicap != old_handicap)
+  {
+    SavePlayerInfo(PLAYER_LEVEL);
+    level_nr = player.handicap;
+  }
+}
+
+void HandleTypeName(int newxpos, KeySym key)
+{
+  static int xpos = 0, ypos = 2;
+  unsigned char ascii;
+
+  if (newxpos)
+  {
+    xpos = newxpos;
+    DrawText(SX+6*32,SY+ypos*32,player.alias_name,FS_BIG,FC_YELLOW);
+    DrawGraphic(xpos+6,ypos,GFX_KUGEL_ROT);
+    return;
+  }
+
+  if ((key>=XK_A && key<=XK_Z) || (key>=XK_a && key<=XK_z && 
+      xpos<MAX_NAMELEN-1))
+  {
+    if (key>=XK_A && key<=XK_Z)
+      ascii = 'A'+(char)(key-XK_A);
+    if (key>=XK_a && key<=XK_z)
+      ascii = 'a'+(char)(key-XK_a);
+    player.alias_name[xpos] = ascii;
+    player.alias_name[xpos+1] = 0;
+    xpos++;
+    DrawTextExt(drawto,gc,SX+6*32,SY+ypos*32,
+               player.alias_name,FS_BIG,FC_YELLOW);
+    DrawTextExt(window,gc,SX+6*32,SY+ypos*32,
+               player.alias_name,FS_BIG,FC_YELLOW);
+    DrawGraphic(xpos+6,ypos,GFX_KUGEL_ROT);
+  }
+  else if (key==XK_Delete && xpos>0)
+  {
+    player.alias_name[xpos] = 0;
+    xpos--;
+    DrawGraphic(xpos+6,ypos,GFX_KUGEL_ROT);
+    DrawGraphic(xpos+7,ypos,GFX_LEERRAUM);
+  }
+  else if (key==XK_Return && xpos>0)
+  {
+    DrawText(SX+6*32,SY+ypos*32,player.alias_name,FS_BIG,FC_RED);
+    DrawGraphic(xpos+6,ypos,GFX_LEERRAUM);
+    SavePlayerInfo(PLAYER_SETUP);
+    CheckCheat();
+
+    game_status = MAINMENU;
+    DrawMainMenu();
+  }
+  BackToFront();
+}
+
+void DrawChooseLevel()
+{
+  int i;
+
+  ClearWindow();
+  DrawText(SX,SY,"Level Directories",FS_BIG,FC_GREEN);
+  for(i=0;i<num_leveldirs;i++)
+  {
+    DrawText(SX+32,SY+(i+2)*32,leveldir[i].name,FS_BIG,FC_YELLOW);
+    DrawGraphic(0,i+2,GFX_KUGEL_BLAU);
+  }
+
+  FadeToFront();
+  InitAnimation();
+  HandleChooseLevel(0,0,0,0,MB_MENU_MARK);
+}
+
+void HandleChooseLevel(int mx, int my, int dx, int dy, int button)
+{
+  static int choice = 3;
+  static int redraw = TRUE;
+  int x = (mx+32-SX)/32, y = (my+32-SY)/32;
+
+  if (redraw)
+  {
+    DrawGraphic(0,choice-1,GFX_KUGEL_ROT);
+    redraw = FALSE;
+  }
+
+  if (dx || dy)
+  {
+    if (dy)
+    {
+      x = 1;
+      y = choice+dy;
+    }
+    else
+      x = y = 0;
+
+    if (y<3)
+      y = 3;
+    else if (y>num_leveldirs+2)
+      y = num_leveldirs+2;
+  }
+
+  if (!mx && !my && !dx && !dy)
+  {
+    x = 1;
+    y = choice;
+  }
+
+  if (x==1 && y>=3 && y<=num_leveldirs+2)
+  {
+    if (button)
+    {
+      if (y!=choice)
+      {
+        DrawGraphic(0,y-1,GFX_KUGEL_ROT);
+        DrawGraphic(0,choice-1,GFX_KUGEL_BLAU);
+      }
+      choice = y;
+    }
+    else
+    {
+      player.leveldir_nr = leveldir_nr = y-3;
+      LoadPlayerInfo(PLAYER_LEVEL);
+      SavePlayerInfo(PLAYER_SETUP);
+      CheckCheat();
+
+      game_status = MAINMENU;
+      DrawMainMenu();
+      redraw = TRUE;
+    }
+  }
+  BackToFront();
+
+  if (game_status==CHOOSELEVEL)
+    DoAnimation();
+}
+
+void DrawHallOfFame(int pos)
+{
+  int y;
+  char txt[40];
+
+  CloseDoor(DOOR_CLOSE_2);
+
+  if (pos<0) 
+    LoadScore(level_nr);
+  ClearWindow();
+  DrawText(SX+64,SY+10,"Hall Of Fame",FS_BIG,FC_YELLOW);
+  sprintf(txt,"HighScores of Level %d",level_nr);
+  DrawText(SX+256-strlen(txt)*7,SY+48,txt,FS_SMALL,FC_RED);
+  for(y=0;y<MAX_SCORE_ENTRIES;y++)
+  {
+    DrawText(SX,SY+64+y*32,".................",FS_BIG,
+            (y==pos ? FC_RED : FC_GREEN));
+    DrawText(SX,SY+64+y*32,highscore[y].Name,FS_BIG,
+            (y==pos ? FC_RED : FC_GREEN));
+    DrawText(SX+12*32,SY+64+y*32,
+            int2str(highscore[y].Score,5),FS_BIG,
+            (y==pos ? FC_RED : FC_GREEN));
+  }
+
+  FadeToFront();
+  InitAnimation();
+  PlaySound(SND_HALLOFFAME);
+}
+
+void HandleHallOfFame(int button)
+{
+  int button_released = !button;
+
+  if (button_released)
+  {
+    FadeSound(SND_HALLOFFAME);
+    game_status = MAINMENU;
+    DrawMainMenu();
+    BackToFront();
+  }
+  else
+    DoAnimation();
+}
+
+void DrawSetupScreen()
+{
+  int i;
+
+  CloseDoor(DOOR_CLOSE_2);
+
+  ClearWindow();
+  DrawText(SX+16, SY+16,  "SETUP",FS_BIG,FC_YELLOW);
+  DrawText(SX+32, SY+2*32,"Sound:",FS_BIG,FC_GREEN);
+  DrawText(SX+32, SY+3*32,"Sound loops:",FS_BIG,FC_GREEN);
+  DrawText(SX+32, SY+4*32,"Game music:",FS_BIG,FC_GREEN);
+  DrawText(SX+32, SY+5*32,"Toons:",FS_BIG,FC_GREEN);
+  DrawText(SX+32, SY+6*32,"Buffered gfx:",FS_BIG,FC_GREEN);
+  DrawText(SX+32, SY+7*32,"Fading:",FS_BIG,FC_GREEN);
+  DrawText(SX+32, SY+8*32,"Auto-Record:",FS_BIG,FC_GREEN);
+  DrawText(SX+32, SY+9*32,"Joystick:",FS_BIG,FC_GREEN);
+  DrawText(SX+32, SY+10*32,"Cal. Joystick",FS_BIG,FC_GREEN);
+  DrawText(SX+32, SY+12*32,"Exit",FS_BIG,FC_GREEN);
+  DrawText(SX+32, SY+13*32,"Save and exit",FS_BIG,FC_GREEN);
+
+  if (SETUP_SOUND_ON(player.setup))
+    DrawText(SX+14*32, SY+2*32,"on",FS_BIG,FC_YELLOW);
+  else
+    DrawText(SX+14*32, SY+2*32,"off",FS_BIG,FC_BLUE);
+
+  if (SETUP_SOUND_LOOPS_ON(player.setup))
+    DrawText(SX+14*32, SY+3*32,"on",FS_BIG,FC_YELLOW);
+  else
+    DrawText(SX+14*32, SY+3*32,"off",FS_BIG,FC_BLUE);
+
+  if (SETUP_SOUND_MUSIC_ON(player.setup))
+    DrawText(SX+14*32, SY+4*32,"on",FS_BIG,FC_YELLOW);
+  else
+    DrawText(SX+14*32, SY+4*32,"off",FS_BIG,FC_BLUE);
+
+  if (SETUP_TOONS_ON(player.setup))
+    DrawText(SX+14*32, SY+5*32,"on",FS_BIG,FC_YELLOW);
+  else
+    DrawText(SX+14*32, SY+5*32,"off",FS_BIG,FC_BLUE);
+
+  if (!SETUP_DIRECT_DRAW_ON(player.setup))
+    DrawText(SX+14*32, SY+6*32,"on",FS_BIG,FC_YELLOW);
+  else
+    DrawText(SX+14*32, SY+6*32,"off",FS_BIG,FC_BLUE);
+
+  if (SETUP_FADING_ON(player.setup))
+    DrawText(SX+14*32, SY+7*32,"on",FS_BIG,FC_YELLOW);
+  else
+    DrawText(SX+14*32, SY+7*32,"off",FS_BIG,FC_BLUE);
+
+  if (SETUP_RECORD_EACH_GAME_ON(player.setup))
+    DrawText(SX+14*32, SY+8*32,"on",FS_BIG,FC_YELLOW);
+  else
+    DrawText(SX+14*32, SY+8*32,"off",FS_BIG,FC_BLUE);
+
+  if (SETUP_2ND_JOYSTICK_ON(player.setup))
+    DrawText(SX+14*32, SY+9*32,"2nd",FS_BIG,FC_YELLOW);
+  else
+    DrawText(SX+14*32, SY+9*32,"1st",FS_BIG,FC_YELLOW);
+
+  for(i=2;i<14;i++)
+    if (i!=11)
+      DrawGraphic(0,i,GFX_KUGEL_BLAU);
+
+  FadeToFront();
+  InitAnimation();
+  HandleSetupScreen(0,0,0,0,MB_MENU_MARK);
+}
+
+void HandleSetupScreen(int mx, int my, int dx, int dy, int button)
+{
+  static int choice = 3;
+  static int redraw = TRUE;
+  int x = (mx+32-SX)/32, y = (my+32-SY)/32;
+
+  if (redraw)
+  {
+    DrawGraphic(0,choice-1,GFX_KUGEL_ROT);
+    redraw = FALSE;
+  }
+
+  if (dx || dy)
+  {
+    if (dy)
+    {
+      x = 1;
+      y = choice+dy;
+    }
+    else
+      x = y = 0;
+
+    if (y==12)
+      y = (dy>0 ? 13 : 11);
+
+    if (y<3)
+      y = 3;
+    else if (y>14)
+      y = 14;
+  }
+
+  if (!mx && !my && !dx && !dy)
+  {
+    x = 1;
+    y = choice;
+  }
+
+  if (x==1 && y>=3 && y<=14 && y!=12)
+  {
+    if (button)
+    {
+      if (y!=choice)
+      {
+       DrawGraphic(0,y-1,GFX_KUGEL_ROT);
+       DrawGraphic(0,choice-1,GFX_KUGEL_BLAU);
+      }
+      choice = y;
+    }
+    else
+    {
+      int yy = y-1;
+
+      if (y==3 && sound_status==SOUND_AVAILABLE)
+      {
+       if (SETUP_SOUND_ON(player.setup))
+         DrawText(SX+14*32, SY+yy*32,"off",FS_BIG,FC_BLUE);
+       else
+         DrawText(SX+14*32, SY+yy*32,"on ",FS_BIG,FC_YELLOW);
+       player.setup ^= SETUP_SOUND;
+      }
+      else if (y==4 && sound_loops_allowed)
+      {
+       if (SETUP_SOUND_LOOPS_ON(player.setup))
+         DrawText(SX+14*32, SY+yy*32,"off",FS_BIG,FC_BLUE);
+       else
+         DrawText(SX+14*32, SY+yy*32,"on ",FS_BIG,FC_YELLOW);
+       player.setup ^= SETUP_SOUND_LOOPS;
+      }
+      else if (y==5 && sound_loops_allowed)
+      {
+       if (SETUP_SOUND_MUSIC_ON(player.setup))
+         DrawText(SX+14*32, SY+yy*32,"off",FS_BIG,FC_BLUE);
+       else
+         DrawText(SX+14*32, SY+yy*32,"on ",FS_BIG,FC_YELLOW);
+       player.setup ^= SETUP_SOUND_MUSIC;
+      }
+      else if (y==6)
+      {
+       if (SETUP_TOONS_ON(player.setup))
+         DrawText(SX+14*32, SY+yy*32,"off",FS_BIG,FC_BLUE);
+       else
+         DrawText(SX+14*32, SY+yy*32,"on ",FS_BIG,FC_YELLOW);
+       player.setup ^= SETUP_TOONS;
+      }
+      else if (y==7)
+      {
+       if (!SETUP_DIRECT_DRAW_ON(player.setup))
+         DrawText(SX+14*32, SY+yy*32,"off",FS_BIG,FC_BLUE);
+       else
+         DrawText(SX+14*32, SY+yy*32,"on ",FS_BIG,FC_YELLOW);
+       player.setup ^= SETUP_DIRECT_DRAW;
+      }
+      else if (y==8)
+      {
+       if (SETUP_FADING_ON(player.setup))
+         DrawText(SX+14*32, SY+yy*32,"off",FS_BIG,FC_BLUE);
+       else
+         DrawText(SX+14*32, SY+yy*32,"on ",FS_BIG,FC_YELLOW);
+       player.setup ^= SETUP_FADING;
+      }
+      else if (y==9)
+      {
+       if (SETUP_RECORD_EACH_GAME_ON(player.setup))
+         DrawText(SX+14*32, SY+yy*32,"off",FS_BIG,FC_BLUE);
+       else
+         DrawText(SX+14*32, SY+yy*32,"on ",FS_BIG,FC_YELLOW);
+       player.setup ^= SETUP_RECORD_EACH_GAME;
+      }
+      else if (y==10)
+      {
+       if (SETUP_2ND_JOYSTICK_ON(player.setup))
+         DrawText(SX+14*32, SY+yy*32,"1st",FS_BIG,FC_YELLOW);
+       else
+         DrawText(SX+14*32, SY+yy*32,"2nd",FS_BIG,FC_YELLOW);
+       player.setup ^= SETUP_2ND_JOYSTICK;
+      }
+      else if (y==11)
+      {
+       CalibrateJoystick();
+       redraw = TRUE;
+      }
+      else if (y==13 || y==14)
+      {
+        if (y==14)
+       {
+         SavePlayerInfo(PLAYER_SETUP);
+         SaveJoystickData();
+       }
+
+       game_status = MAINMENU;
+       DrawMainMenu();
+       redraw = TRUE;
+      }
+    }
+  }
+  BackToFront();
+
+  if (game_status==SETUP)
+    DoAnimation();
+}
+
+void HandleVideoButtons(int mx, int my, int button)
+{
+  if (game_status!=MAINMENU && game_status!=PLAYING)
+    return;
+
+  switch(CheckVideoButtons(mx,my,button))
+  {
+    case BUTTON_VIDEO_EJECT:
+      TapeStop();
+      if (!TAPE_IS_EMPTY(tape))
+       SaveLevelTape(tape.level_nr);
+      else
+       AreYouSure("Tape is empty !",AYS_CONFIRM);
+      DrawCompleteVideoDisplay();
+      break;
+    case BUTTON_VIDEO_STOP:
+      TapeStop();
+      break;
+    case BUTTON_VIDEO_PAUSE:
+      TapeTogglePause();
+      break;
+    case BUTTON_VIDEO_REC:
+      if (tape.pausing)
+       TapeTogglePause();
+      else if (game_status==MAINMENU)
+       TapeInitRecording();
+      break;
+    case BUTTON_VIDEO_PLAY:
+      if (tape.pausing)
+       TapeTogglePause();
+      else if (game_status==MAINMENU)
+       TapeInitPlaying();
+      break;
+    default:
+      break;
+  }
+}
+
+void HandleSoundButtons(int mx, int my, int button)
+{
+  if (game_status!=PLAYING)
+    return;
+
+  switch(CheckSoundButtons(mx,my,button))
+  {
+    case BUTTON_SOUND_MUSIC:
+      if (sound_music_on)
+      { 
+       sound_music_on = FALSE;
+       player.setup &= ~SETUP_SOUND_MUSIC;
+       FadeSound(background_loop[level_nr % num_bg_loops]);
+       DrawSoundDisplay(BUTTON_SOUND_MUSIC_OFF);
+      }
+      else if (sound_loops_allowed)
+      { 
+       sound_music_on = TRUE;
+       player.setup |= SETUP_SOUND_MUSIC;
+       PlaySoundLoop(background_loop[level_nr % num_bg_loops]);
+       DrawSoundDisplay(BUTTON_SOUND_MUSIC_ON);
+      }
+      else
+       DrawSoundDisplay(BUTTON_SOUND_MUSIC_OFF);
+      break;
+    case BUTTON_SOUND_LOOPS:
+      if (sound_loops_on)
+      { 
+       sound_loops_on = FALSE;
+       player.setup &= ~SETUP_SOUND_LOOPS;
+       DrawSoundDisplay(BUTTON_SOUND_LOOPS_OFF);
+      }
+      else if (sound_loops_allowed)
+      { 
+       sound_loops_on = TRUE;
+       player.setup |= SETUP_SOUND_LOOPS;
+       DrawSoundDisplay(BUTTON_SOUND_LOOPS_ON);
+      }
+      else
+       DrawSoundDisplay(BUTTON_SOUND_LOOPS_OFF);
+      break;
+    case BUTTON_SOUND_SOUND:
+      if (sound_on)
+      { 
+       sound_on = FALSE;
+       player.setup &= ~SETUP_SOUND;
+       DrawSoundDisplay(BUTTON_SOUND_SOUND_OFF);
+      }
+      else if (sound_status==SOUND_AVAILABLE)
+      { 
+       sound_on = TRUE;
+       player.setup |= SETUP_SOUND;
+       DrawSoundDisplay(BUTTON_SOUND_SOUND_ON);
+      }
+      else
+       DrawSoundDisplay(BUTTON_SOUND_SOUND_OFF);
+      break;
+    default:
+      break;
+  }
+}
+
+void HandleGameButtons(int mx, int my, int button)
+{
+  if (game_status!=PLAYING)
+    return;
+
+  switch(CheckGameButtons(mx,my,button))
+  {
+    case BUTTON_GAME_STOP:
+      if (AreYouSure("Do you really want to quit the game ?",
+                     AYS_ASK | AYS_STAY_CLOSED))
+      { 
+       game_status = MAINMENU;
+       DrawMainMenu();
+      }
+      else
+       OpenDoor(DOOR_OPEN_1 | DOOR_COPY_BACK);
+      break;
+    case BUTTON_GAME_PAUSE:
+      if (tape.pausing)
+      {
+       tape.pausing = FALSE;
+       DrawVideoDisplay(VIDEO_STATE_PAUSE_OFF,0);
+      }
+      else
+      {
+       tape.pausing = TRUE;
+       DrawVideoDisplay(VIDEO_STATE_PAUSE_ON,0);
+      }
+      break;
+    case BUTTON_GAME_PLAY:
+      if (tape.pausing)
+      {
+       tape.pausing = FALSE;
+       DrawVideoDisplay(VIDEO_STATE_PAUSE_OFF,0);
+      }
+      break;
+    default:
+      break;
+  }
+}
+
+int CheckVideoButtons(int mx, int my, int button)
+{
+  int return_code = 0;
+  static int choice = -1;
+  static BOOL pressed = FALSE;
+  static int video_button[5] =
+  {
+    VIDEO_PRESS_EJECT_ON,
+    VIDEO_PRESS_STOP_ON,
+    VIDEO_PRESS_PAUSE_ON,
+    VIDEO_PRESS_REC_ON,
+    VIDEO_PRESS_PLAY_ON
+  };
+
+  if (button)
+  {
+    if (!motion_status)                /* Maustaste neu gedrückt */
+    {
+      if (ON_VIDEO_BUTTON(mx,my))
+      {
+       choice = VIDEO_BUTTON(mx);
+       pressed = TRUE;
+       DrawVideoDisplay(video_button[choice],0);
+      }
+    }
+    else                       /* Mausbewegung bei gedrückter Maustaste */
+    {
+      if ((!ON_VIDEO_BUTTON(mx,my) || VIDEO_BUTTON(mx)!=choice) &&
+         choice>=0 && pressed)
+      {
+       pressed = FALSE;
+       DrawVideoDisplay(video_button[choice]<<1,0);
+      }
+      else if (ON_VIDEO_BUTTON(mx,my) && VIDEO_BUTTON(mx)==choice && !pressed)
+      {
+       pressed = TRUE;
+       DrawVideoDisplay(video_button[choice],0);
+      }
+    }
+  }
+  else                         /* Maustaste wieder losgelassen */
+  {
+    if (ON_VIDEO_BUTTON(mx,my) && VIDEO_BUTTON(mx)==choice && pressed)
+    {
+      DrawVideoDisplay(video_button[choice]<<1,0);
+      return_code = choice+1;
+      choice = -1;
+      pressed = FALSE;
+    }
+    else
+    {
+      choice = -1;
+      pressed = FALSE;
+    }
+  }
+
+  BackToFront();
+  return(return_code);
+}
+
+int CheckSoundButtons(int mx, int my, int button)
+{
+  int return_code = 0;
+  static int choice = -1;
+  static BOOL pressed = FALSE;
+  int sound_state[3];
+
+  sound_state[0] = BUTTON_SOUND_MUSIC | (BUTTON_ON * sound_music_on);
+  sound_state[1] = BUTTON_SOUND_LOOPS | (BUTTON_ON * sound_loops_on);
+  sound_state[2] = BUTTON_SOUND_SOUND | (BUTTON_ON * sound_on);
+
+  if (button)
+  {
+    if (!motion_status)                /* Maustaste neu gedrückt */
+    {
+      if (ON_SOUND_BUTTON(mx,my))
+      {
+       choice = SOUND_BUTTON(mx);
+       pressed = TRUE;
+       DrawSoundDisplay(sound_state[choice] | BUTTON_PRESSED);
+      }
+    }
+    else                       /* Mausbewegung bei gedrückter Maustaste */
+    {
+      if ((!ON_SOUND_BUTTON(mx,my) || SOUND_BUTTON(mx)!=choice) &&
+         choice>=0 && pressed)
+      {
+       pressed = FALSE;
+       DrawSoundDisplay(sound_state[choice] | BUTTON_RELEASED);
+      }
+      else if (ON_SOUND_BUTTON(mx,my) && SOUND_BUTTON(mx)==choice && !pressed)
+      {
+       pressed = TRUE;
+       DrawSoundDisplay(sound_state[choice] | BUTTON_PRESSED);
+      }
+    }
+  }
+  else                         /* Maustaste wieder losgelassen */
+  {
+    if (ON_SOUND_BUTTON(mx,my) && SOUND_BUTTON(mx)==choice && pressed)
+    {
+      DrawSoundDisplay(sound_state[choice] | BUTTON_RELEASED);
+      return_code = 1<<choice;
+      choice = -1;
+      pressed = FALSE;
+    }
+    else
+    {
+      choice = -1;
+      pressed = FALSE;
+    }
+  }
+
+  BackToFront();
+  return(return_code);
+}
+
+int CheckGameButtons(int mx, int my, int button)
+{
+  int return_code = 0;
+  static int choice = -1;
+  static BOOL pressed = FALSE;
+  int game_state[3] =
+  {
+    BUTTON_GAME_STOP,
+    BUTTON_GAME_PAUSE,
+    BUTTON_GAME_PLAY
+  };
+
+  if (button)
+  {
+    if (!motion_status)                /* Maustaste neu gedrückt */
+    {
+      if (ON_GAME_BUTTON(mx,my))
+      {
+       choice = GAME_BUTTON(mx);
+       pressed = TRUE;
+       DrawGameButton(game_state[choice] | BUTTON_PRESSED);
+      }
+    }
+    else                       /* Mausbewegung bei gedrückter Maustaste */
+    {
+      if ((!ON_GAME_BUTTON(mx,my) || GAME_BUTTON(mx)!=choice) &&
+         choice>=0 && pressed)
+      {
+       pressed = FALSE;
+       DrawGameButton(game_state[choice] | BUTTON_RELEASED);
+      }
+      else if (ON_GAME_BUTTON(mx,my) && GAME_BUTTON(mx)==choice && !pressed)
+      {
+       pressed = TRUE;
+       DrawGameButton(game_state[choice] | BUTTON_PRESSED);
+      }
+    }
+  }
+  else                         /* Maustaste wieder losgelassen */
+  {
+    if (ON_GAME_BUTTON(mx,my) && GAME_BUTTON(mx)==choice && pressed)
+    {
+      DrawGameButton(game_state[choice] | BUTTON_RELEASED);
+      return_code = 1<<choice;
+      choice = -1;
+      pressed = FALSE;
+    }
+    else
+    {
+      choice = -1;
+      pressed = FALSE;
+    }
+  }
+
+  BackToFront();
+  return(return_code);
+}
+
+int CheckChooseButtons(int mx, int my, int button)
+{
+  int return_code = 0;
+  static int choice = -1;
+  static BOOL pressed = FALSE;
+  static int choose_button[5] =
+  {
+    BUTTON_OK,
+    BUTTON_NO
+  };
+
+  if (button)
+  {
+    if (!motion_status)                /* Maustaste neu gedrückt */
+    {
+      if (ON_CHOOSE_BUTTON(mx,my))
+      {
+       choice = CHOOSE_BUTTON(mx);
+       pressed = TRUE;
+       DrawChooseButton(choose_button[choice] | BUTTON_PRESSED);
+      }
+    }
+    else                       /* Mausbewegung bei gedrückter Maustaste */
+    {
+      if ((!ON_CHOOSE_BUTTON(mx,my) || CHOOSE_BUTTON(mx)!=choice) &&
+         choice>=0 && pressed)
+      {
+       pressed = FALSE;
+       DrawChooseButton(choose_button[choice] | BUTTON_RELEASED);
+      }
+      else if (ON_CHOOSE_BUTTON(mx,my) &&CHOOSE_BUTTON(mx)==choice && !pressed)
+      {
+       pressed = TRUE;
+       DrawChooseButton(choose_button[choice] | BUTTON_PRESSED);
+      }
+    }
+  }
+  else                         /* Maustaste wieder losgelassen */
+  {
+    if (ON_CHOOSE_BUTTON(mx,my) && CHOOSE_BUTTON(mx)==choice && pressed)
+    {
+      DrawChooseButton(choose_button[choice] | BUTTON_RELEASED);
+      return_code = choice+1;
+      choice = -1;
+      pressed = FALSE;
+    }
+    else
+    {
+      choice = -1;
+      pressed = FALSE;
+    }
+  }
+
+  BackToFront();
+  return(return_code);
+}
+
+int CheckConfirmButton(int mx, int my, int button)
+{
+  int return_code = 0;
+  static int choice = -1;
+  static BOOL pressed = FALSE;
+
+  if (button)
+  {
+    if (!motion_status)                /* Maustaste neu gedrückt */
+    {
+      if (ON_CONFIRM_BUTTON(mx,my))
+      {
+       choice = 0;
+       pressed = TRUE;
+       DrawConfirmButton(BUTTON_PRESSED);
+      }
+    }
+    else                       /* Mausbewegung bei gedrückter Maustaste */
+    {
+      if (!ON_CONFIRM_BUTTON(mx,my) && choice>=0 && pressed)
+      {
+       pressed = FALSE;
+       DrawConfirmButton(BUTTON_RELEASED);
+      }
+      else if (ON_CONFIRM_BUTTON(mx,my) && !pressed)
+      {
+       pressed = TRUE;
+       DrawConfirmButton(BUTTON_PRESSED);
+      }
+    }
+  }
+  else                         /* Maustaste wieder losgelassen */
+  {
+    if (ON_CONFIRM_BUTTON(mx,my) && pressed)
+    {
+      DrawConfirmButton(BUTTON_RELEASED);
+      return_code = BUTTON_CONFIRM;
+      choice = -1;
+      pressed = FALSE;
+    }
+    else
+    {
+      choice = -1;
+      pressed = FALSE;
+    }
+  }
+
+  BackToFront();
+  return(return_code);
+}
+
+void DrawCompleteVideoDisplay()
+{
+  XCopyArea(display,pix[PIX_DOOR],drawto,gc,
+           DOOR_GFX_PAGEX3,DOOR_GFX_PAGEY2, VXSIZE,VYSIZE, VX,VY);
+  XCopyArea(display,pix[PIX_DOOR],drawto,gc,
+           DOOR_GFX_PAGEX4+VIDEO_CONTROL_XPOS,
+           DOOR_GFX_PAGEY2+VIDEO_CONTROL_YPOS,
+           VIDEO_CONTROL_XSIZE,VIDEO_CONTROL_YSIZE,
+           VX+VIDEO_CONTROL_XPOS,VY+VIDEO_CONTROL_YPOS);
+
+  DrawVideoDisplay(VIDEO_ALL_OFF,0);
+  if (tape.date && tape.length)
+  {
+    DrawVideoDisplay(VIDEO_STATE_DATE_ON,tape.date);
+    DrawVideoDisplay(VIDEO_STATE_TIME_ON,0);
+  }
+
+  XCopyArea(display,drawto,pix[PIX_DB_DOOR],gc,
+           VX,VY, VXSIZE,VYSIZE, DOOR_GFX_PAGEX1,DOOR_GFX_PAGEY2);
+}
diff --git a/src/screens.h b/src/screens.h
new file mode 100644 (file)
index 0000000..c76ade7
--- /dev/null
@@ -0,0 +1,72 @@
+/***********************************************************
+*  Rocks'n'Diamonds -- McDuffin Strikes Back!              *
+*----------------------------------------------------------*
+*  ©1995 Artsoft Development                               *
+*        Holger Schemel                                    *
+*        33659 Bielefeld-Senne                             *
+*        Telefon: (0521) 493245                            *
+*        eMail: aeglos@valinor.owl.de                      *
+*               aeglos@uni-paderborn.de                    *
+*               q99492@pbhrzx.uni-paderborn.de             *
+*----------------------------------------------------------*
+*  screens.h                                               *
+*                                                          *
+*  Letzte Aenderung: 15.06.1995                            *
+***********************************************************/
+
+#ifndef SCREENS_H
+#define SCREENS_H
+
+#include "main.h"
+
+/* Setup-Bits */
+#define SETUP_TOONS                    (1<<0)
+#define SETUP_SOUND                    (1<<1)
+#define SETUP_SOUND_LOOPS              (1<<2)
+#define SETUP_SOUND_MUSIC              (1<<3)
+#define SETUP_DIRECT_DRAW              (1<<4)
+#define SETUP_FADING                   (1<<5)
+#define SETUP_RECORD_EACH_GAME         (1<<6)
+#define SETUP_2ND_JOYSTICK             (1<<7)
+
+#define DEFAULT_SETUP                  (SETUP_TOONS |          \
+                                        SETUP_SOUND |          \
+                                        SETUP_SOUND_LOOPS |    \
+                                        SETUP_SOUND_MUSIC)
+
+/* Setup-Voreinstellungen */
+#define SETUP_TOONS_ON(x)              (((x) & SETUP_TOONS) != 0)
+#define SETUP_SOUND_ON(x)              (((x) & SETUP_SOUND) != 0)
+#define SETUP_SOUND_LOOPS_ON(x)                (((x) & SETUP_SOUND_LOOPS) != 0)
+#define SETUP_SOUND_MUSIC_ON(x)                (((x) & SETUP_SOUND_MUSIC) != 0)
+#define SETUP_DIRECT_DRAW_ON(x)                (((x) & SETUP_DIRECT_DRAW) != 0)
+#define SETUP_FADING_ON(x)             (((x) & SETUP_FADING) != 0)
+#define SETUP_RECORD_EACH_GAME_ON(x)   (((x) & SETUP_RECORD_EACH_GAME) != 0)
+#define SETUP_2ND_JOYSTICK_ON(x)       (((x) & SETUP_2ND_JOYSTICK) != 0)
+
+void DrawMainMenu();
+void HandleMainMenu(int, int, int, int, int);
+void DrawHelpScreenElAction(int);
+void DrawHelpScreenElText(int);
+void DrawHelpScreenMusicText(int);
+void DrawHelpScreenRegistrationText(void);
+void DrawHelpScreen();
+void HandleHelpScreen(int);
+void HandleTypeName(int, KeySym);
+void DrawChooseLevel(void);
+void HandleChooseLevel(int, int, int, int, int);
+void DrawHallOfFame(int);
+void HandleHallOfFame(int);
+void DrawSetupScreen();
+void HandleSetupScreen(int, int, int, int, int);
+void HandleVideoButtons(int, int, int);
+void HandleSoundButtons(int, int, int);
+void HandleGameButtons(int, int, int);
+int CheckVideoButtons(int, int, int);
+int CheckSoundButtons(int, int, int);
+int CheckGameButtons(int, int, int);
+int CheckChooseButtons(int, int, int);
+int CheckConfirmButton(int, int, int);
+void DrawCompleteVideoDisplay(void);
+
+#endif
diff --git a/src/sound.c b/src/sound.c
new file mode 100644 (file)
index 0000000..b234a89
--- /dev/null
@@ -0,0 +1,758 @@
+/***********************************************************
+*  Rocks'n'Diamonds -- McDuffin Strikes Back!              *
+*----------------------------------------------------------*
+*  ©1995 Artsoft Development                               *
+*        Holger Schemel                                    *
+*        33659 Bielefeld-Senne                             *
+*        Telefon: (0521) 493245                            *
+*        eMail: aeglos@valinor.owl.de                      *
+*               aeglos@uni-paderborn.de                    *
+*               q99492@pbhrzx.uni-paderborn.de             *
+*----------------------------------------------------------*
+*  sound.c                                                 *
+*                                                          *
+*  Letzte Aenderung: 15.06.1995                            *
+***********************************************************/
+
+#include "sound.h"
+
+/*** THE STUFF BELOW IS ONLY USED BY THE SOUND SERVER CHILD PROCESS ***/
+
+static struct SoundControl playlist[MAX_SOUNDS_PLAYING];
+static struct SoundControl emptySoundControl =
+{
+  -1,0,0, FALSE,FALSE,FALSE,FALSE,FALSE, 0,0L,0L,NULL
+};
+static int stereo_volume[PSND_MAX_LEFT2RIGHT+1];
+static char premix_first_buffer[SND_BLOCKSIZE];
+static char premix_left_buffer[SND_BLOCKSIZE];
+static char premix_right_buffer[SND_BLOCKSIZE];
+static int premix_last_buffer[SND_BLOCKSIZE];
+static unsigned char playing_buffer[SND_BLOCKSIZE];
+static int playing_sounds = 0;
+
+void SoundServer()
+{
+  struct SoundControl snd_ctrl;
+  fd_set sound_fdset;
+  int i;
+
+  close(sound_pipe[1]);                /* no writing into pipe needed */
+
+  for(i=0;i<MAX_SOUNDS_PLAYING;i++)
+    playlist[i] = emptySoundControl;
+
+  stereo_volume[PSND_MAX_LEFT2RIGHT] = 0;
+  for(i=0;i<PSND_MAX_LEFT2RIGHT;i++)
+    stereo_volume[i] =
+      (int)sqrt((float)(PSND_MAX_LEFT2RIGHT*PSND_MAX_LEFT2RIGHT-i*i));
+
+#ifdef HPUX_AUDIO
+  HPUX_Audio_Control();
+#endif
+
+  FD_ZERO(&sound_fdset); 
+  FD_SET(sound_pipe[0], &sound_fdset);
+
+  for(;;)      /* wait for calls from PlaySound(), StopSound(), ... */
+  {
+    FD_SET(sound_pipe[0], &sound_fdset);
+    select(sound_pipe[0]+1, &sound_fdset, NULL, NULL, NULL);
+    if (!FD_ISSET(sound_pipe[0], &sound_fdset))
+      continue;
+    if (read(sound_pipe[0], &snd_ctrl, sizeof(snd_ctrl)) != sizeof(snd_ctrl))
+    {
+      fprintf(stderr,"%s: broken pipe - no sounds\n",progname);
+      exit(0);
+    }
+
+#ifdef VOXWARE
+
+    if (snd_ctrl.fade_sound)
+    {
+      if (!playing_sounds)
+       continue;
+
+      for(i=0;i<MAX_SOUNDS_PLAYING;i++)
+       if (snd_ctrl.stop_all_sounds || playlist[i].nr == snd_ctrl.nr)
+         playlist[i].fade_sound = TRUE;
+    }
+    else if (snd_ctrl.stop_all_sounds)
+    {
+      if (!playing_sounds)
+       continue;
+
+      for(i=0;i<MAX_SOUNDS_PLAYING;i++)
+       playlist[i]=emptySoundControl;
+      playing_sounds=0;
+
+      close(sound_device);
+    }
+    else if (snd_ctrl.stop_sound)
+    {
+      if (!playing_sounds)
+       continue;
+
+      for(i=0;i<MAX_SOUNDS_PLAYING;i++)
+       if (playlist[i].nr == snd_ctrl.nr)
+       {
+         playlist[i]=emptySoundControl;
+         playing_sounds--;
+       }
+
+      if (!playing_sounds)
+       close(sound_device);
+    }
+
+    if (playing_sounds || snd_ctrl.active)
+    {
+      struct timeval delay = { 0, 0 };
+      char *sample_ptr;
+      long sample_size, max_sample_size;
+      long fragment_size;
+      BOOL stereo;
+
+      if (playing_sounds || (sound_device=open(sound_device_name,O_WRONLY))>=0)
+      {
+       if (!playing_sounds)    /* we just opened the audio device */
+       {
+         /* 2 buffers / 512 bytes, giving 1/16 second resolution */
+         /* (with stereo the effective buffer size will shrink to 256) */
+         fragment_size = 0x00020009;
+         ioctl(sound_device, SNDCTL_DSP_SETFRAGMENT, &fragment_size);
+         /* try if we can use stereo sound */
+         stereo = TRUE;
+         ioctl(sound_device, SNDCTL_DSP_STEREO, &stereo);
+         /* get the real fragmentation size; this should return 512 */
+         ioctl(sound_device, SNDCTL_DSP_GETBLKSIZE, &fragment_size);
+         max_sample_size = fragment_size / (stereo ? 2 : 1);
+       }
+
+       if (snd_ctrl.active)    /* new sound has arrived */
+         SoundServer_InsertNewSound(snd_ctrl);
+
+       while(playing_sounds &&
+             select(sound_pipe[0]+1,&sound_fdset,NULL,NULL,&delay)<1)
+       {       
+         FD_SET(sound_pipe[0], &sound_fdset);
+
+         /* first clear the last premixing buffer */
+         memset(premix_last_buffer,0,fragment_size*sizeof(int));
+
+         for(i=0;i<MAX_SOUNDS_PLAYING;i++)
+         {
+           int j;
+
+           if (!playlist[i].active)
+             continue;
+
+           /* get pointer and size of the actual sound sample */
+           sample_ptr = playlist[i].data_ptr+playlist[i].playingpos;
+           sample_size =
+             MIN(max_sample_size,playlist[i].data_len-playlist[i].playingpos);
+           playlist[i].playingpos += sample_size;
+
+           /* fill the first mixing buffer with original sample */
+           memcpy(premix_first_buffer,sample_ptr,sample_size);
+
+           /* are we about to restart a looping sound? */
+           if (playlist[i].loop && sample_size<max_sample_size)
+           {
+             playlist[i].playingpos = max_sample_size-sample_size;
+             memcpy(premix_first_buffer+sample_size,
+                    playlist[i].data_ptr,max_sample_size-sample_size);
+             sample_size = max_sample_size;
+           }
+
+           /* decrease volume if sound is fading out */
+           if (playlist[i].fade_sound &&
+               playlist[i].volume>=PSND_MAX_VOLUME/10)
+             playlist[i].volume-=PSND_MAX_VOLUME/20;
+
+           /* adjust volume of actual sound sample */
+           if (playlist[i].volume != PSND_MAX_VOLUME)
+             for(j=0;j<sample_size;j++)
+               premix_first_buffer[j] =
+                 (playlist[i].volume * (int)premix_first_buffer[j])
+                   >> PSND_MAX_VOLUME_BITS;
+
+           /* fill the last mixing buffer with stereo or mono sound */
+           if (stereo)
+           {
+             int middle_pos = PSND_MAX_LEFT2RIGHT/2;
+             int left_volume = stereo_volume[middle_pos+playlist[i].stereo];
+             int right_volume = stereo_volume[middle_pos-playlist[i].stereo];
+
+             for(j=0;j<sample_size;j++)
+             {
+               premix_left_buffer[j] =
+                 (left_volume * (int)premix_first_buffer[j])
+                   >> PSND_MAX_LEFT2RIGHT_BITS;
+               premix_right_buffer[j] =
+                 (right_volume * (int)premix_first_buffer[j])
+                   >> PSND_MAX_LEFT2RIGHT_BITS;
+               premix_last_buffer[2*j+0] += premix_left_buffer[j];
+               premix_last_buffer[2*j+1] += premix_right_buffer[j];
+             }
+           }
+           else
+           {
+             for(j=0;j<sample_size;j++)
+               premix_last_buffer[j] += (int)premix_first_buffer[j];
+           }
+
+           /* delete completed sound entries from the playlist */
+           if (playlist[i].playingpos >= playlist[i].data_len)
+           {
+             if (playlist[i].loop)
+               playlist[i].playingpos = 0;
+             else
+             {
+               playlist[i] = emptySoundControl;
+               playing_sounds--;
+             }
+           }
+           else if (playlist[i].volume <= PSND_MAX_VOLUME/10)
+           {
+             playlist[i] = emptySoundControl;
+             playing_sounds--;
+           }
+         }
+
+         /* put last mixing buffer to final playing buffer */
+         for(i=0;i<fragment_size;i++)
+         {
+           if (premix_last_buffer[i]<-255)
+             playing_buffer[i] = 0;
+           else if (premix_last_buffer[i]>255)
+             playing_buffer[i] = 255;
+           else
+             playing_buffer[i] = (premix_last_buffer[i]>>1)^0x80;
+         }
+
+         /* finally play the sound fragment */
+         write(sound_device,playing_buffer,fragment_size);
+       }
+
+       /* if no sounds playing, free device for other sound programs */
+       if (!playing_sounds)
+         close(sound_device);
+      }
+    }
+
+#else  /* von '#ifdef VOXWARE' */
+
+    if (snd_ctrl.active && !snd_ctrl.loop)
+    {
+      struct timeval delay = { 0, 0 };
+      char *sample_ptr;
+      long sample_size, max_sample_size = SND_BLOCKSIZE;
+      long sample_rate = 8000; /* standard "/dev/audio" sampling rate */
+      int wait_percent = 90;   /* wait 90% of the real playing time */
+      int i;
+
+      if ((sound_device=open(sound_device_name,O_WRONLY))>=0)
+      {
+       playing_sounds = 1;
+
+       while(playing_sounds &&
+             select(sound_pipe[0]+1,&sound_fdset,NULL,NULL,&delay)<1)
+       {       
+         FD_SET(sound_pipe[0], &sound_fdset);
+
+         /* get pointer and size of the actual sound sample */
+         sample_ptr = snd_ctrl.data_ptr+snd_ctrl.playingpos;
+         sample_size =
+           MIN(max_sample_size,snd_ctrl.data_len-snd_ctrl.playingpos);
+         snd_ctrl.playingpos += sample_size;
+
+         /* fill the first mixing buffer with original sample */
+         memcpy(premix_first_buffer,sample_ptr,sample_size);
+
+
+         /* adjust volume of actual sound sample */
+         if (snd_ctrl.volume != PSND_MAX_VOLUME)
+           for(i=0;i<sample_size;i++)
+             premix_first_buffer[i] =
+               (snd_ctrl.volume * (int)premix_first_buffer[i])
+                 >> PSND_MAX_VOLUME_BITS;
+
+         for(i=0;i<sample_size;i++)
+           playing_buffer[i] =
+             linear_to_ulaw(((int)premix_first_buffer[i]) << 8);
+
+         if (snd_ctrl.playingpos >= snd_ctrl.data_len)
+           playing_sounds = 0;
+
+         /* finally play the sound fragment */
+         write(sound_device,playing_buffer,sample_size);
+
+         delay.tv_sec = 0;
+         delay.tv_usec = ((sample_size*10*wait_percent)/(sample_rate))*1000;
+       }
+       close(sound_device);
+      }
+    }
+
+#endif /* von '#ifdef VOXWARE' */
+
+  }
+}
+
+void SoundServer_InsertNewSound(struct SoundControl snd_ctrl)
+{
+  int i,k;
+
+  /* wenn voll, ältesten Sound 'rauswerfen */
+  if (playing_sounds==MAX_SOUNDS_PLAYING)
+  {
+    int longest=0, longest_nr=0;
+
+    for(i=0;i<MAX_SOUNDS_PLAYING;i++)
+    {
+      int actual =
+       100 * playlist[i].playingpos / playlist[i].data_len;
+
+      if (!playlist[i].loop && actual>longest)
+      {
+       longest=actual;
+       longest_nr=i;
+      }
+    }
+    playlist[longest_nr] = emptySoundControl;
+    playing_sounds--;
+  }
+
+  /* nachsehen, ob (und ggf. wie oft) Sound bereits gespielt wird */
+  for(k=0,i=0;i<MAX_SOUNDS_PLAYING;i++)
+  {
+    if (playlist[i].nr == snd_ctrl.nr)
+      k++;
+  }
+
+  /* falls Sound-Loop: nur neu beginnen, wenn Sound gerade ausklingt */
+  if (k>=1 && snd_ctrl.loop)
+  {
+    for(i=0;i<MAX_SOUNDS_PLAYING;i++)
+    {
+      if (playlist[i].nr == snd_ctrl.nr && playlist[i].fade_sound)
+      {
+       playlist[i].fade_sound = FALSE;
+       playlist[i].volume = PSND_MAX_VOLUME;
+      }
+    }
+    return;
+  }
+
+  /* keinen Sound mehr als n mal gleichzeitig spielen (momentan n==2) */
+  if (k>=2)
+  {
+    int longest=0, longest_nr=0;
+
+    /* den bereits am längsten gespielten (gleichen) Sound suchen */
+    for(i=0;i<MAX_SOUNDS_PLAYING;i++)
+    {
+      int actual;
+
+      if (!playlist[i].active || playlist[i].nr != snd_ctrl.nr)
+       continue;
+
+      actual = 100 * playlist[i].playingpos / playlist[i].data_len;
+      if (actual>=longest)
+      {
+       longest=actual;
+       longest_nr=i;
+      }
+    }
+    playlist[longest_nr] = emptySoundControl;
+    playing_sounds--;
+  }
+
+  /* neuen Sound in Liste packen */
+  for(i=0;i<MAX_SOUNDS_PLAYING;i++)
+  {
+    if (!playlist[i].active)
+    {
+      playlist[i] = snd_ctrl;
+      playing_sounds++;
+      break;
+    }
+  }
+}
+
+/*
+void SoundServer_FadeSound(int nr)
+{
+  int i;
+
+  if (!playing_sounds)
+    return;
+
+  for(i=0;i<MAX_SOUNDS_PLAYING;i++)
+    if (snd_ctrl.stop_all_sounds || playlist[i].nr == snd_ctrl.nr)
+      playlist[i].fade_sound = TRUE;
+}
+*/
+
+void SoundServer_StopSound(int nr)
+{
+  int i;
+
+  if (!playing_sounds)
+    return;
+
+  for(i=0;i<MAX_SOUNDS_PLAYING;i++)
+    if (playlist[i].nr == nr)
+    {
+      playlist[i] = emptySoundControl;
+      playing_sounds--;
+    }
+
+  if (!playing_sounds)
+    close(sound_device);
+}
+
+void SoundServer_StopAllSounds()
+{
+  int i;
+
+  for(i=0;i<MAX_SOUNDS_PLAYING;i++)
+    playlist[i]=emptySoundControl;
+  playing_sounds=0;
+
+  close(sound_device);
+}
+
+#ifdef HPUX_AUDIO
+void HPUX_Audio_Control()
+{
+  struct audio_describe ainfo;
+  int audio_ctl;
+
+  audio_ctl = open("/dev/audioCtl", O_WRONLY | O_NDELAY);
+  if (audio_ctl == -1)
+  {
+    fprintf(stderr,"%s: cannot open /dev/audioCtl - no sounds\n",progname);
+    exit(0);
+  }
+
+  if (ioctl(audio_ctl, AUDIO_DESCRIBE, &ainfo) == -1)
+  {
+    fprintf(stderr,"%s: no audio info - no sounds\n",progname);
+    exit(0);
+  }
+
+  if (ioctl(audio_ctl, AUDIO_SET_DATA_FORMAT, AUDIO_FORMAT_ULAW) == -1)
+  {
+    fprintf(stderr,"%s: ulaw audio not available - no sounds\n",progname);
+    exit(0);
+  }
+
+  ioctl(audio_ctl, AUDIO_SET_CHANNELS, 1);
+  ioctl(audio_ctl, AUDIO_SET_SAMPLE_RATE, 8000);
+
+  close(audio_ctl);
+}
+#endif /* HPUX_AUDIO */
+
+/* these two are stolen from "sox"... :) */
+
+/*
+** This routine converts from linear to ulaw.
+**
+** Craig Reese: IDA/Supercomputing Research Center
+** Joe Campbell: Department of Defense
+** 29 September 1989
+**
+** References:
+** 1) CCITT Recommendation G.711  (very difficult to follow)
+** 2) "A New Digital Technique for Implementation of Any
+**     Continuous PCM Companding Law," Villeret, Michel,
+**     et al. 1973 IEEE Int. Conf. on Communications, Vol 1,
+**     1973, pg. 11.12-11.17
+** 3) MIL-STD-188-113,"Interoperability and Performance Standards
+**     for Analog-to_Digital Conversion Techniques,"
+**     17 February 1987
+**
+** Input: Signed 16 bit linear sample
+** Output: 8 bit ulaw sample
+*/
+
+#define ZEROTRAP    /* turn on the trap as per the MIL-STD */
+#define BIAS 0x84   /* define the add-in bias for 16 bit samples */
+#define CLIP 32635
+
+unsigned char linear_to_ulaw(int sample)
+{
+  static int exp_lut[256] =
+  {
+    0,0,1,1,2,2,2,2,3,3,3,3,3,3,3,3,
+    4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,
+    5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,
+    5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,
+    6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,
+    6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,
+    6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,
+    6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,
+    7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
+    7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
+    7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
+    7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
+    7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
+    7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
+    7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
+    7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7
+  };
+
+  int sign, exponent, mantissa;
+  unsigned char ulawbyte;
+
+  /* Get the sample into sign-magnitude. */
+  sign = (sample >> 8) & 0x80;         /* set aside the sign */
+  if (sign != 0)
+    sample = -sample;                  /* get magnitude */
+  if (sample > CLIP)
+    sample = CLIP;                     /* clip the magnitude */
+
+  /* Convert from 16 bit linear to ulaw. */
+  sample = sample + BIAS;
+  exponent = exp_lut[( sample >> 7 ) & 0xFF];
+  mantissa = ( sample >> ( exponent + 3 ) ) & 0x0F;
+  ulawbyte = ~ ( sign | ( exponent << 4 ) | mantissa );
+#ifdef ZEROTRAP
+  if (ulawbyte == 0)
+    ulawbyte = 0x02;                   /* optional CCITT trap */
+#endif
+
+  return(ulawbyte);
+}
+
+/*
+** This routine converts from ulaw to 16 bit linear.
+**
+** Craig Reese: IDA/Supercomputing Research Center
+** 29 September 1989
+**
+** References:
+** 1) CCITT Recommendation G.711  (very difficult to follow)
+** 2) MIL-STD-188-113,"Interoperability and Performance Standards
+**     for Analog-to_Digital Conversion Techniques,"
+**     17 February 1987
+**
+** Input: 8 bit ulaw sample
+** Output: signed 16 bit linear sample
+*/
+
+int ulaw_to_linear(unsigned char ulawbyte)
+{
+  static int exp_lut[8] = { 0, 132, 396, 924, 1980, 4092, 8316, 16764 };
+  int sign, exponent, mantissa, sample;
+
+  ulawbyte = ~ ulawbyte;
+  sign = ( ulawbyte & 0x80 );
+  exponent = ( ulawbyte >> 4 ) & 0x07;
+  mantissa = ulawbyte & 0x0F;
+  sample = exp_lut[exponent] + ( mantissa << ( exponent + 3 ) );
+  if (sign != 0)
+    sample = -sample;
+
+  return(sample);
+}
+
+/*** THE STUFF ABOVE IS ONLY USED BY THE SOUND SERVER CHILD PROCESS ***/
+
+/*===========================================================================*/
+
+/*** THE STUFF BELOW IS ONLY USED BY THE MAIN PROCESS ***/
+
+BOOL LoadSound(struct SoundInfo *snd_info)
+{
+  FILE *file;
+  char filename[256];
+  char *sound_ext = "8svx";
+  struct SoundHeader_8SVX *snd_hdr;
+  unsigned char *ptr;
+
+  sprintf(filename,"%s/%s.%s",SND_PATH,snd_info->name,sound_ext);
+
+  if (!(file=fopen(filename,"r")))
+  {
+    fprintf(stderr,"%s: cannot open sound file '%s' - no sounds\n",
+           progname,filename);
+    return(FALSE);
+  }
+
+  if (fseek(file,0,SEEK_END)<0)
+  {
+    fprintf(stderr,"%s: cannot read sound file '%s' - no sounds\n",
+           progname,filename);
+    fclose(file);
+    return(FALSE);
+  }
+
+  snd_info->file_len = ftell(file);
+  rewind(file);
+
+  if (!(snd_info->file_ptr=malloc(snd_info->file_len)))
+  {
+    fprintf(stderr,"%s: out of memory (this shouldn't happen :) - no sounds\n",
+           progname);
+    fclose(file);
+    return(FALSE);
+  }
+
+  if (fread(snd_info->file_ptr,1,snd_info->file_len,file)!=snd_info->file_len)
+  {
+    fprintf(stderr,"%s: cannot read sound file '%s' - no sounds\n",
+           progname,filename);
+    fclose(file);
+    return(FALSE);
+  }
+
+  fclose(file);
+
+  snd_hdr = (struct SoundHeader_8SVX *)snd_info->file_ptr;
+
+  if (strncmp(snd_hdr->magic_FORM,"FORM",4) ||
+      snd_info->file_len!=be2long(&snd_hdr->chunk_size)+8 ||
+      strncmp(snd_hdr->magic_8SVX,"8SVX",4))
+  {
+    fprintf(stderr,"%s: '%s' is not an IFF/8SVX file or broken- no sounds\n",
+           progname,filename);
+    return(FALSE);
+  }
+
+  ptr = (unsigned char *)snd_info->file_ptr;
+
+  while(ptr<(unsigned char *)snd_info->file_ptr+snd_info->file_len)
+  {
+    if (!strncmp(ptr,"VHDR",4))
+    {
+      ptr+=be2long((unsigned long *)(ptr+4));
+    }
+    if (!strncmp(ptr,"ANNO",4))
+    {
+      ptr+=be2long((unsigned long *)(ptr+4));
+    }
+    if (!strncmp(ptr,"CHAN",4))
+    {
+      ptr+=be2long((unsigned long *)(ptr+4));
+    }
+    if (!strncmp(ptr,"BODY",4))
+    {
+      snd_info->data_ptr = ptr+8;
+      snd_info->data_len = be2long((unsigned long *)(ptr+4));
+      return(TRUE);
+    }
+    ptr++;
+  }
+
+  return(FALSE);
+}
+
+void PlaySound(int nr)
+{
+  PlaySoundExt(nr, PSND_MAX_VOLUME, PSND_MIDDLE, PSND_NO_LOOP);
+}
+
+void PlaySoundStereo(int nr, int stereo)
+{
+  PlaySoundExt(nr, PSND_MAX_VOLUME, stereo, PSND_NO_LOOP);
+}
+
+void PlaySoundLoop(int nr)
+{
+  PlaySoundExt(nr, PSND_MAX_VOLUME, PSND_MIDDLE, PSND_LOOP);
+}
+
+void PlaySoundExt(int nr, int volume, int stereo, BOOL loop)
+{
+  struct SoundControl snd_ctrl = emptySoundControl;
+
+  if (sound_status==SOUND_OFF || !sound_on)
+    return;
+
+  if (volume<PSND_MIN_VOLUME)
+    volume = PSND_MIN_VOLUME;
+  else if (volume>PSND_MAX_VOLUME)
+    volume = PSND_MAX_VOLUME;
+
+  if (stereo<PSND_MAX_LEFT)
+    stereo = PSND_MAX_LEFT;
+  else if (stereo>PSND_MAX_RIGHT)
+    stereo = PSND_MAX_RIGHT;
+
+  snd_ctrl.nr          = nr;
+  snd_ctrl.volume      = volume;
+  snd_ctrl.stereo      = stereo;
+  snd_ctrl.loop                = loop;
+  snd_ctrl.active      = TRUE;
+  snd_ctrl.data_ptr    = Sound[nr].data_ptr;
+  snd_ctrl.data_len    = Sound[nr].data_len;
+
+  if (write(sound_pipe[1], &snd_ctrl, sizeof(snd_ctrl))<0)
+  {
+    fprintf(stderr,"%s: cannot pipe to child process - no sounds\n",progname);
+    sound_status=SOUND_OFF;
+    return;
+  }
+}
+
+void FadeSound(int nr)
+{
+  StopSoundExt(nr, SSND_FADE_SOUND);
+}
+
+void FadeSounds()
+{
+  StopSoundExt(-1, SSND_FADE_ALL_SOUNDS);
+}
+
+void StopSound(int nr)
+{
+  StopSoundExt(nr, SSND_STOP_SOUND);
+}
+
+void StopSounds()
+{
+  StopSoundExt(-1, SSND_STOP_ALL_SOUNDS);
+}
+
+void StopSoundExt(int nr, int method)
+{
+  struct SoundControl snd_ctrl = emptySoundControl;
+
+  if (sound_status==SOUND_OFF)
+    return;
+
+  if (SSND_FADING(method))
+    snd_ctrl.fade_sound = TRUE;
+
+  if (SSND_ALL(method))
+    snd_ctrl.stop_all_sounds = TRUE;
+  else
+  {
+    snd_ctrl.nr = nr;
+    snd_ctrl.stop_sound = TRUE;
+  }
+
+  if (write(sound_pipe[1], &snd_ctrl, sizeof(snd_ctrl))<0)
+  {
+    fprintf(stderr,"%s: cannot pipe to child process - no sounds\n",progname);
+    sound_status=SOUND_OFF;
+    return;
+  }
+}
+
+void FreeSounds(int max)
+{
+  int i;
+
+  if (sound_status==SOUND_OFF)
+    return;
+
+  for(i=0;i<max;i++)
+    free(Sound[i].file_ptr);
+}
+
+/*** THE STUFF ABOVE IS ONLY USED BY THE MAIN PROCESS ***/
diff --git a/src/sound.h b/src/sound.h
new file mode 100644 (file)
index 0000000..be853f8
--- /dev/null
@@ -0,0 +1,157 @@
+/***********************************************************
+*  Rocks'n'Diamonds -- McDuffin Strikes Back!              *
+*----------------------------------------------------------*
+*  ©1995 Artsoft Development                               *
+*        Holger Schemel                                    *
+*        33659 Bielefeld-Senne                             *
+*        Telefon: (0521) 493245                            *
+*        eMail: aeglos@valinor.owl.de                      *
+*               aeglos@uni-paderborn.de                    *
+*               q99492@pbhrzx.uni-paderborn.de             *
+*----------------------------------------------------------*
+*  sound.c                                                 *
+*                                                          *
+*  Letzte Aenderung: 15.06.1995                            *
+***********************************************************/
+
+#ifndef SOUND_H
+#define SOUND_H
+
+#include "main.h"
+#include <math.h>
+
+#ifdef linux
+#include <linux/soundcard.h>
+#ifndef VOXWARE
+#define VOXWARE
+#endif
+/* where is the right declaration for 'ioctl'? */
+extern void ioctl(long, long, void *);
+#endif
+
+#define SND_BLOCKSIZE 4096
+
+#ifdef _HPUX_SOURCE
+#include <sys/audio.h>
+#undef  SND_BLOCKSIZE
+#define SND_BLOCKSIZE 32768
+#define HPUX_AUDIO
+#endif /* _HPUX_SOURCE */
+
+#define MAX_SOUNDS_PLAYING     16
+
+/* some values for PlaySound(), StopSound() and friends */
+#define PSND_SILENCE           0
+#define PSND_MAX_VOLUME_BITS   7
+#define PSND_MIN_VOLUME                0
+#define PSND_MAX_VOLUME                (1 << PSND_MAX_VOLUME_BITS)
+#define PSND_NO_LOOP           0
+#define PSND_LOOP              1
+#define PSND_MIDDLE            0
+#define PSND_MAX_STEREO_BITS   7
+#define PSND_MAX_STEREO                (1 << PSND_MAX_STEREO_BITS)
+#define PSND_MAX_LEFT          (-PSND_MAX_STEREO)
+#define PSND_MAX_RIGHT         (+PSND_MAX_STEREO)
+#define PSND_MAX_LEFT2RIGHT_BITS (PSND_MAX_STEREO_BITS+1)
+#define PSND_MAX_LEFT2RIGHT    (1 << PSND_MAX_LEFT2RIGHT_BITS)
+
+#define SSND_FADE_SOUND                (1<<0)
+#define SSND_FADE_ALL_SOUNDS   (1<<1)
+#define SSND_FADING(x)         (x & (SSND_FADE_SOUND | SSND_FADE_ALL_SOUNDS))
+#define SSND_STOP_SOUND                (1<<2)
+#define SSND_STOP_ALL_SOUNDS   (1<<3)
+#define SSND_STOPPING(x)       (x & (SSND_STOP_SOUND | SSND_STOP_ALL_SOUNDS))
+#define SSND_ALL(x)            (x&(SSND_FADE_ALL_SOUNDS|SSND_STOP_ALL_SOUNDS))
+
+#define        TRUE    1
+#define FALSE  0
+
+/* settings for sound path, sound device, etc. */
+#ifndef SND_PATH
+#define SND_PATH       "./sounds"
+#endif
+
+#define DEV_AUDIO      "/dev/audio"
+#define DEV_DSP                "/dev/dsp"
+
+#ifdef VOXWARE
+#define SOUND_DEVICE           DEV_DSP
+#else
+#define SOUND_DEVICE   DEV_AUDIO
+#endif
+
+#define SOUND_OFF      0
+#define        SOUND_AVAILABLE 1
+
+#ifdef NO_SOUNDS
+#define SOUND_STATUS   SOUND_OFF
+#else
+#define SOUND_STATUS   SOUND_AVAILABLE
+#endif
+
+struct SoundHeader_SUN
+{
+  unsigned long magic;
+  unsigned long hdr_size;
+  unsigned long data_size;
+  unsigned long encoding;
+  unsigned long sample_rate;
+  unsigned long channels;
+};
+
+struct SoundHeader_8SVX
+{
+  char magic_FORM[4];
+  unsigned long chunk_size;
+  char magic_8SVX[4];
+};
+
+struct SoundInfo
+{ 
+  char *name;
+  char *file_ptr, *data_ptr;
+  long file_len, data_len;
+};
+
+struct SoundControl
+{
+  int nr;
+  int volume;
+  int stereo;
+  BOOL active;
+  BOOL loop;
+  BOOL fade_sound;
+  BOOL stop_sound;
+  BOOL stop_all_sounds;
+  int playingtime;
+  long playingpos;
+  long data_len;
+  char *data_ptr;
+};
+
+/* function from "misc.c" */
+unsigned long be2long(unsigned long *);
+
+/* sound server functions */
+void SoundServer(void);
+void SoundServer_InsertNewSound(struct SoundControl);
+void SoundServer_StopSound(int);
+void SoundServer_StopAllSounds(void);
+void HPUX_Audio_Control(void);
+unsigned char linear_to_ulaw(int);
+int ulaw_to_linear(unsigned char);
+
+/* application functions */
+BOOL LoadSound(struct SoundInfo *);
+void PlaySound(int);
+void PlaySoundStereo(int, int);
+void PlaySoundLoop(int);
+void PlaySoundExt(int, int, int, BOOL);
+void FadeSound(int);
+void FadeSounds(void);
+void StopSound(int);
+void StopSounds(void);
+void StopSoundExt(int, int);
+void FreeSounds(int);
+
+#endif
diff --git a/src/tools.c b/src/tools.c
new file mode 100644 (file)
index 0000000..f1d2e25
--- /dev/null
@@ -0,0 +1,1554 @@
+/***********************************************************
+*  Rocks'n'Diamonds -- McDuffin Strikes Back!              *
+*----------------------------------------------------------*
+*  ©1995 Artsoft Development                               *
+*        Holger Schemel                                    *
+*        33659 Bielefeld-Senne                             *
+*        Telefon: (0521) 493245                            *
+*        eMail: aeglos@valinor.owl.de                      *
+*               aeglos@uni-paderborn.de                    *
+*               q99492@pbhrzx.uni-paderborn.de             *
+*----------------------------------------------------------*
+*  tools.c                                                 *
+*                                                          *
+*  Letzte Aenderung: 15.06.1995                            *
+***********************************************************/
+
+#include "tools.h"
+#include "game.h"
+#include "events.h"
+#include "sound.h"
+#include "screens.h"
+#include "misc.h"
+
+void BackToFront()
+{
+  int x,y;
+
+  if (direct_draw_on && game_status==PLAYING)
+    redraw_mask &= ~REDRAW_MAIN;
+
+  if (!redraw_mask)
+    return;
+
+  if (redraw_mask & REDRAW_ALL ||
+      (redraw_mask & REDRAW_FIELD && redraw_mask & REDRAW_DOORS))
+  {
+    XCopyArea(display,backbuffer,window,gc,
+             0,0, WIN_XSIZE,WIN_YSIZE,
+             0,0);
+    redraw_mask = 0;
+  }
+  else if (redraw_mask & REDRAW_FIELD)
+  {
+    XCopyArea(display,backbuffer,window,gc,
+             REAL_SX,REAL_SY, FULL_SXSIZE,FULL_SYSIZE,
+             REAL_SX,REAL_SY);
+    redraw_mask &= ~REDRAW_MAIN;
+  }
+  else if (redraw_mask & REDRAW_DOORS)
+  {
+    if (redraw_mask & REDRAW_DOOR_1)
+      XCopyArea(display,backbuffer,window,gc,
+               DX,DY, DXSIZE,DYSIZE, DX,DY);
+    if (redraw_mask & REDRAW_DOOR_2)
+    {
+      if ((redraw_mask & REDRAW_DOOR_2) == REDRAW_DOOR_2)
+       XCopyArea(display,backbuffer,window,gc,
+                 VX,VY, VXSIZE,VYSIZE, VX,VY);
+      else
+      {
+       if (redraw_mask & REDRAW_VIDEO_1)
+         XCopyArea(display,backbuffer,window,gc,
+                   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)
+         XCopyArea(display,backbuffer,window,gc,
+                   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)
+         XCopyArea(display,backbuffer,window,gc,
+                   VX+VIDEO_CONTROL_XPOS,VY+VIDEO_CONTROL_YPOS,
+                   VIDEO_CONTROL_XSIZE,VIDEO_CONTROL_YSIZE,
+                   VX+VIDEO_CONTROL_XPOS,VY+VIDEO_CONTROL_YPOS);
+      }
+    }
+    redraw_mask &= ~REDRAW_DOORS;
+  }
+
+  if (redraw_mask & REDRAW_MICROLEV)
+  {
+    XCopyArea(display,backbuffer,window,gc,
+             MICROLEV_XPOS,MICROLEV_YPOS, MICROLEV_XSIZE,MICROLEV_YSIZE,
+             MICROLEV_XPOS,MICROLEV_YPOS);
+    XCopyArea(display,backbuffer,window,gc,
+             SX,MICROLABEL_YPOS, SXSIZE,FONT4_YSIZE,
+             SX,MICROLABEL_YPOS);
+    redraw_mask &= ~REDRAW_MICROLEV;
+  }
+
+  if (redraw_mask & REDRAW_TILES)
+  {
+    if (redraw_tiles>REDRAWTILES_TH)
+      XCopyArea(display,backbuffer,window,gc,SX,SY,SXSIZE,SYSIZE,SX,SY);
+    else
+      for(x=0;x<SCR_FIELDX;x++)
+       for(y=0;y<SCR_FIELDY;y++)
+         if (redraw[x][y])
+           XCopyArea(display,backbuffer,window,gc,
+                     SX+x*TILEX,SY+y*TILEY,TILEX,TILEY,SX+x*TILEX,SY+y*TILEY);
+  }
+
+  XFlush(display);
+
+  for(x=0;x<SCR_FIELDX;x++)
+    for(y=0;y<SCR_FIELDY;y++)
+      redraw[x][y]=0;
+  redraw_tiles=0;
+  redraw_mask=0;
+}
+
+void FadeToFront()
+{
+  long fading_delay = 300000;
+
+  if (fading_on && (redraw_mask & REDRAW_FIELD))
+  {
+    XSetClipOrigin(display,clip_gc[PIX_FADEMASK],0,0);
+    XCopyArea(display,backbuffer,window,clip_gc[PIX_FADEMASK],
+             REAL_SX,REAL_SY, FULL_SXSIZE,FULL_SYSIZE, REAL_SX,REAL_SY);
+    XFlush(display);
+    Delay(fading_delay);
+
+    XSetClipOrigin(display,clip_gc[PIX_FADEMASK],-1,-1);
+    XCopyArea(display,backbuffer,window,clip_gc[PIX_FADEMASK],
+             REAL_SX,REAL_SY, FULL_SXSIZE,FULL_SYSIZE, REAL_SX,REAL_SY);
+    XFlush(display);
+    Delay(fading_delay);
+
+    XSetClipOrigin(display,clip_gc[PIX_FADEMASK],0,-1);
+    XCopyArea(display,backbuffer,window,clip_gc[PIX_FADEMASK],
+             REAL_SX,REAL_SY, FULL_SXSIZE,FULL_SYSIZE, REAL_SX,REAL_SY);
+    XFlush(display);
+    Delay(fading_delay);
+
+    XSetClipOrigin(display,clip_gc[PIX_FADEMASK],-1,0);
+    XCopyArea(display,backbuffer,window,clip_gc[PIX_FADEMASK],
+             REAL_SX,REAL_SY, FULL_SXSIZE,FULL_SYSIZE, REAL_SX,REAL_SY);
+    XFlush(display);
+    Delay(fading_delay);
+
+    redraw_mask &= ~REDRAW_MAIN;
+  }
+
+  BackToFront();
+}
+
+void ClearWindow()
+{
+  drawto_field = backbuffer;
+  XFillRectangle(display,drawto_field,gc,
+                REAL_SX,REAL_SY,FULL_SXSIZE,FULL_SYSIZE);
+  redraw_mask|=REDRAW_FIELD;
+
+  if (game_status==PLAYING && direct_draw_on)
+  {
+    drawto_field = window;
+    XFillRectangle(display,drawto_field,gc,
+                  REAL_SX,REAL_SY,FULL_SXSIZE,FULL_SYSIZE);
+  }
+}
+
+void DrawText(int x, int y, char *text, int font, int col)
+{
+  DrawTextExt(drawto, gc, x, y, text, font, col);
+  if (x<DX)
+    redraw_mask|=REDRAW_FIELD;
+  else if (y<VY)
+    redraw_mask|=REDRAW_DOOR_1;
+}
+
+void DrawTextExt(Drawable d, GC gc, int x, int y,
+                char *text, int font, int font_color)
+{
+  int font_width, font_height, font_start;
+  int font_pixmap;
+
+  if (font!=FS_SMALL && font!=FS_BIG)
+    font = FS_SMALL;
+  if (font_color<FC_RED || font_color>FC_SPECIAL2)
+    font_color = FC_RED;
+
+  font_width =
+    (font==FS_BIG ? FONT1_XSIZE :
+     font_color<FC_SPECIAL1 ? FONT2_XSIZE :
+     font_color<FC_SPECIAL2 ? FONT3_XSIZE : FONT4_XSIZE);
+  font_height =
+    (font==FS_BIG ? FONT1_XSIZE :
+     font_color<FC_SPECIAL2 ? FONT2_XSIZE: FONT4_XSIZE);
+  font_pixmap = (font==FS_BIG ? PIX_BIGFONT : PIX_SMALLFONT);
+  font_start =
+    font_color*(font==FS_BIG ? FONT1_YSIZE : FONT2_YSIZE)*FONT_LINES_PER_FONT;
+
+  while(*text)
+  {
+    char c = *text++;
+
+    if (c>='a' && c<='z')
+      c = 'A' + (c - 'a');
+    else if (c=='ä' || c=='Ä')
+      c = 91;
+    else if (c=='ö' || c=='Ö')
+      c = 92;
+    else if (c=='ü' || c=='Ü')
+      c = 93;
+
+    if (c>=32 && c<=95)
+      XCopyArea(display,pix[font_pixmap],d,gc,
+               ((c-32) % FONT_CHARS_PER_LINE)*font_width,
+               ((c-32) / FONT_CHARS_PER_LINE)*font_height + font_start,
+               font_width,font_height, x,y);
+
+    x += font_width;
+  }
+}
+
+void DrawGraphic(int x, int y, int graphic)
+{
+  DrawGraphicExt(drawto_field, gc, x, y, graphic);
+  redraw_tiles++;
+  redraw[x][y] = TRUE;
+  redraw_mask |= REDRAW_TILES;
+}
+
+void DrawGraphicExt(Drawable d, GC gc, int x, int y, int graphic)
+{
+  DrawGraphicExtHiRes(d, gc, SX+x*TILEX, SY+y*TILEY, graphic);
+}
+
+void DrawGraphicExtHiRes(Drawable d, GC gc, int x, int y, int graphic)
+{
+  if (graphic<0)
+    XFillRectangle(display,d,gc, x,y, TILEX,TILEY);
+  else if (graphic<256)
+    XCopyArea(display,pix[PIX_BACK],d,gc,
+             SX+(graphic % GFX_PER_LINE)*TILEX,
+             SY+(graphic / GFX_PER_LINE)*TILEY,
+             TILEX,TILEY, x,y);
+  else
+  {
+    graphic -= 256;
+    XCopyArea(display,pix[PIX_BIGFONT],d,gc,
+             (graphic % FONT_CHARS_PER_LINE)*TILEX,
+             (graphic / FONT_CHARS_PER_LINE)*TILEY +
+             FC_SPECIAL1*TILEY*FONT_LINES_PER_FONT,
+             TILEX,TILEY, x,y);
+  }
+}
+
+void DrawGraphicThruMask(int x, int y, int graphic)
+{
+  int src_x,src_y, dest_x,dest_y;
+
+  if (graphic<0 || graphic>255)
+  {
+    DrawGraphic(x,y,graphic);
+    return;
+  }
+
+  src_x  = SX+(graphic % GFX_PER_LINE)*TILEX;
+  src_y  = SY+(graphic / GFX_PER_LINE)*TILEY;
+  dest_x = SX+x*TILEX;
+  dest_y = SY+y*TILEY;
+
+  XSetClipOrigin(display,clip_gc[PIX_BACK],dest_x-src_x,dest_y-src_y);
+  XCopyArea(display,pix[PIX_BACK],drawto_field,clip_gc[PIX_BACK], src_x,src_y,
+           TILEX,TILEY, dest_x,dest_y);
+
+  redraw_tiles++;
+  redraw[x][y]=TRUE;
+  redraw_mask|=REDRAW_TILES;
+}
+
+void DrawElementThruMask(int x, int y, int element)
+{
+  DrawGraphicThruMask(x,y,el2gfx(element));
+}
+
+void DrawMiniGraphic(int x, int y, int graphic)
+{
+  DrawMiniGraphicExt(drawto, gc, x, y, graphic);
+  redraw_tiles++;
+  redraw[x/2][y/2]=TRUE;
+  redraw_mask|=REDRAW_TILES;
+}
+
+void DrawMiniGraphicExt(Drawable d, GC gc, int x, int y, int graphic)
+{
+  DrawMiniGraphicExtHiRes(d,gc, SX+x*MINI_TILEX,SY+y*MINI_TILEY, graphic);
+}
+
+void DrawMiniGraphicExtHiRes(Drawable d, GC gc, int x, int y, int graphic)
+{
+  if (graphic<0)
+    XFillRectangle(display,d,gc, x,y, MINI_TILEX,MINI_TILEY);
+  else if (graphic<256)
+    XCopyArea(display,pix[PIX_BACK],d,gc,
+             MINI_GFX_STARTX+(graphic % MINI_GFX_PER_LINE)*MINI_TILEX,
+             MINI_GFX_STARTY+(graphic / MINI_GFX_PER_LINE)*MINI_TILEY,
+             MINI_TILEX,MINI_TILEY, x,y);
+  else
+  {
+    graphic -= 256;
+    XCopyArea(display,pix[PIX_SMALLFONT],d,gc,
+             (graphic % FONT_CHARS_PER_LINE)*FONT4_XSIZE,
+             (graphic / FONT_CHARS_PER_LINE)*FONT4_YSIZE +
+             FC_SPECIAL2*FONT2_YSIZE*FONT_LINES_PER_FONT,
+             MINI_TILEX,MINI_TILEY, x,y);
+  }
+}
+
+int el2gfx(int element)
+{
+  switch(element)
+  {
+    case EL_LEERRAUM:          return(-1);
+    case EL_ERDREICH:          return(GFX_ERDREICH);
+    case EL_MAUERWERK:         return(GFX_MAUERWERK);
+    case EL_FELSBODEN:         return(GFX_FELSBODEN);
+    case EL_FELSBROCKEN:       return(GFX_FELSBROCKEN);
+    case EL_SCHLUESSEL:                return(GFX_SCHLUESSEL);
+    case EL_EDELSTEIN:         return(GFX_EDELSTEIN);
+    case EL_AUSGANG_ZU:                return(GFX_AUSGANG_ZU);
+    case EL_AUSGANG_ACT:       return(GFX_AUSGANG_ACT);
+    case EL_AUSGANG_AUF:       return(GFX_AUSGANG_AUF);
+    case EL_SPIELFIGUR:                return(GFX_SPIELFIGUR);
+    case EL_SPIELER1:          return(GFX_SPIELER1);
+    case EL_SPIELER2:          return(GFX_SPIELER2);
+    case EL_SPIELER3:          return(GFX_SPIELER3);
+    case EL_SPIELER4:          return(GFX_SPIELER4);
+    case EL_KAEFER:            return(GFX_KAEFER);
+    case EL_KAEFER_R:          return(GFX_KAEFER_R);
+    case EL_KAEFER_O:          return(GFX_KAEFER_O);
+    case EL_KAEFER_L:          return(GFX_KAEFER_L);
+    case EL_KAEFER_U:          return(GFX_KAEFER_U);
+    case EL_FLIEGER:           return(GFX_FLIEGER);
+    case EL_FLIEGER_R:         return(GFX_FLIEGER_R);
+    case EL_FLIEGER_O:         return(GFX_FLIEGER_O);
+    case EL_FLIEGER_L:         return(GFX_FLIEGER_L);
+    case EL_FLIEGER_U:         return(GFX_FLIEGER_U);
+    case EL_MAMPFER:           return(GFX_MAMPFER);
+    case EL_ZOMBIE:            return(GFX_ZOMBIE);
+    case EL_BETON:             return(GFX_BETON);
+    case EL_DIAMANT:           return(GFX_DIAMANT);
+    case EL_MORAST_LEER:       return(GFX_MORAST_LEER);
+    case EL_MORAST_VOLL:       return(GFX_MORAST_VOLL);
+    case EL_TROPFEN:           return(GFX_TROPFEN);
+    case EL_BOMBE:             return(GFX_BOMBE);
+    case EL_SIEB_LEER:         return(GFX_SIEB_LEER);
+    case EL_SIEB_VOLL:         return(GFX_SIEB_VOLL);
+    case EL_SIEB_TOT:          return(GFX_SIEB_TOT);
+    case EL_SALZSAEURE:                return(GFX_SALZSAEURE);
+    case EL_AMOEBE1:           return(GFX_AMOEBE1);
+    case EL_AMOEBE2:           return(GFX_AMOEBE2);
+    case EL_AMOEBE3:           return(GFX_AMOEBE3);
+    case EL_KOKOSNUSS:         return(GFX_KOKOSNUSS);
+    case EL_LIFE:              return(GFX_LIFE);
+    case EL_LIFE_ASYNC:                return(GFX_LIFE_ASYNC);
+    case EL_DYNAMIT:           return(GFX_DYNAMIT);
+    case EL_BADEWANNE:         return(GFX_BADEWANNE);
+    case EL_BADEWANNE1:                return(GFX_BADEWANNE1);
+    case EL_BADEWANNE2:                return(GFX_BADEWANNE2);
+    case EL_BADEWANNE3:                return(GFX_BADEWANNE3);
+    case EL_BADEWANNE4:                return(GFX_BADEWANNE4);
+    case EL_BADEWANNE5:                return(GFX_BADEWANNE5);
+    case EL_ABLENK_AUS:                return(GFX_ABLENK_AUS);
+    case EL_ABLENK_EIN:                return(GFX_ABLENK_EIN);
+    case EL_SCHLUESSEL1:       return(GFX_SCHLUESSEL1);
+    case EL_SCHLUESSEL2:       return(GFX_SCHLUESSEL2);
+    case EL_SCHLUESSEL3:       return(GFX_SCHLUESSEL3);
+    case EL_SCHLUESSEL4:       return(GFX_SCHLUESSEL4);
+    case EL_PFORTE1:           return(GFX_PFORTE1);
+    case EL_PFORTE2:           return(GFX_PFORTE2);
+    case EL_PFORTE3:           return(GFX_PFORTE3);
+    case EL_PFORTE4:           return(GFX_PFORTE4);
+    case EL_PFORTE1X:          return(GFX_PFORTE1X);
+    case EL_PFORTE2X:          return(GFX_PFORTE2X);
+    case EL_PFORTE3X:          return(GFX_PFORTE3X);
+    case EL_PFORTE4X:          return(GFX_PFORTE4X);
+    case EL_DYNAMIT_AUS:       return(GFX_DYNAMIT_AUS);
+    case EL_PACMAN:            return(GFX_PACMAN);
+    case EL_PACMAN_R:          return(GFX_PACMAN_R);
+    case EL_PACMAN_O:          return(GFX_PACMAN_O);
+    case EL_PACMAN_L:          return(GFX_PACMAN_L);
+    case EL_PACMAN_U:          return(GFX_PACMAN_U);
+    case EL_UNSICHTBAR:                return(GFX_UNSICHTBAR);
+    case EL_ERZ_1:             return(GFX_ERZ_1);
+    case EL_ERZ_2:             return(GFX_ERZ_2);
+    case EL_BIRNE_AUS:         return(GFX_BIRNE_AUS);
+    case EL_BIRNE_EIN:         return(GFX_BIRNE_EIN);
+    default:
+    {
+      if (IS_CHAR(element))
+       return(GFX_CHAR_START + (element-EL_CHAR_START));
+      else
+       return(-1);
+    }
+  }
+}
+
+void DrawGraphicShifted(int x,int y, int dx,int dy, int graphic, int cut_mode)
+{
+  int width = TILEX, height = TILEY;
+  int cx = 0, cy = 0;
+
+  if (graphic<0)
+  {
+    DrawGraphic(x,y,graphic);
+    return;
+  }
+
+  if (dx || dy)                        /* Verschiebung der Grafik? */
+  {
+    if (x<0)                   /* Element kommt von links ins Bild */
+    {
+      x=0;
+      width=dx;
+      cx=TILEX-dx;
+      dx=0;
+    }
+    else if (x==SCR_FIELDX)    /* Element kommt von rechts ins Bild */
+    {
+      x=SCR_FIELDX-1;
+      width=-dx;
+      dx=TILEX+dx;
+    }
+    else if (x==0 && dx<0)     /* Element verläßt links das Bild */
+    {
+      width+=dx;
+      cx=-dx;
+      dx=0;
+    }
+    else if (x==SCR_FIELDX-1 && dx>0)  /* El. verläßt rechts das Bild */
+      width-=dx;
+    else if (dx)               /* allg. Bewegung in x-Richtung */
+      redraw[x+SIGN(dx)][y]=TRUE;
+
+    if (y<0)                   /* Element kommt von oben ins Bild */
+    {
+      if (cut_mode==CUT_BELOW) /* Element oberhalb des Bildes */
+       return;
+
+      y=0;
+      height=dy;
+      cy=TILEY-dy;
+      dy=0;
+    }
+    else if (y==SCR_FIELDY)    /* Element kommt von unten ins Bild */
+    {
+      y=SCR_FIELDY-1;
+      height=-dy;
+      dy=TILEY+dy;
+    }
+    else if (y==0 && dy<0)     /* Element verläßt oben das Bild */
+    {
+      height+=dy;
+      cy=-dy;
+      dy=0;
+    }
+    else if (dy>0 && cut_mode==CUT_ABOVE)
+    {
+      if (y==SCR_FIELDY-1)     /* Element unterhalb des Bildes */
+       return;
+
+      height=dy;
+      cy=TILEY-dy;
+      dy=TILEY;
+      redraw[x][y+1]=TRUE;
+    }                          /* Element verläßt unten das Bild */
+    else if (dy>0 && (y==SCR_FIELDY-1 || cut_mode==CUT_BELOW))
+      height-=dy;
+    else if (dy)               /* allg. Bewegung in y-Richtung */
+      redraw[x][y+SIGN(dy)]=TRUE;
+  }
+
+  XCopyArea(display,pix[PIX_BACK],drawto_field,gc,
+           SX+(graphic % GFX_PER_LINE)*TILEX+cx,
+           SY+(graphic / GFX_PER_LINE)*TILEY+cy,
+           width,height, SX+x*TILEX+dx,SY+y*TILEY+dy);
+
+  redraw_tiles++;
+  redraw[x][y]=TRUE;
+  redraw_mask|=REDRAW_TILES;
+}
+
+void DrawElementShifted(int x, int y, int dx, int dy, int element,int cut_mode)
+{
+  int ux = UNSCROLLX(x), uy = UNSCROLLY(y);
+  int graphic = el2gfx(element);
+  int phase = ABS(MovPos[ux][uy])/(TILEX/2);
+  int dir = MovDir[ux][uy];
+  int horiz_move = (dir==MV_LEFT || dir==MV_RIGHT);
+
+  if (element==EL_PACMAN ||
+      element==EL_KAEFER ||
+      element==EL_FLIEGER)
+  {
+    if (element==EL_PACMAN)
+      graphic = GFX_PACMAN + 4*!phase;
+    else
+      graphic += 4*!phase;
+
+    if (dir==MV_UP)
+      graphic += 1;
+    else if (dir==MV_LEFT)
+      graphic += 2;
+    else if (dir==MV_DOWN)
+      graphic += 3;
+  }
+  else if ((element==EL_FELSBROCKEN ||
+           element==EL_EDELSTEIN ||
+           element==EL_DIAMANT) && horiz_move && phase)
+  {
+    if (element==EL_FELSBROCKEN)
+      graphic += 2;
+    else
+      graphic += 1;
+  }
+  else if ((element==EL_SIEB_LEER ||
+           element==EL_SIEB_VOLL) && SiebAktiv)
+  {
+    graphic += 3-(SiebAktiv%8)/2;
+  }
+  else if (IS_AMOEBOID(element))
+  {
+    graphic = (element==EL_AMOEBE1 ? GFX_AMOEBE_TOT : GFX_AMOEBE_LEBT);
+    graphic += (x+2*y) % 4;
+  }
+
+  if (dx || dy)
+    DrawGraphicShifted(x,y, dx,dy, graphic, cut_mode);
+  else
+    DrawGraphic(x,y, graphic);
+}
+
+void ErdreichAnbroeckeln(int x, int y)
+{
+  int i, width, height, cx,cy;
+  int ux = UNSCROLLX(x), uy = UNSCROLLY(y);
+  int element, graphic;
+  int snip = 4;
+  static int xy[4][2] =
+  {
+    0,-1,
+    -1,0,
+    +1,0,
+    0,+1
+  };
+
+  if (!IN_LEV_FIELD(ux,uy))
+    return;
+
+  element = Feld[ux][uy];
+
+  if (element==EL_ERDREICH)
+  {
+    if (!IN_SCR_FIELD(x,y))
+      return;
+
+    graphic = GFX_ERDENRAND;
+
+    for(i=0;i<4;i++)
+    {
+      int uxx,uyy;
+
+      uxx = ux+xy[i][0];
+      uyy = uy+xy[i][1];
+      if (!IN_LEV_FIELD(uxx,uyy))
+       element = EL_BETON;
+      else
+       element = Feld[uxx][uyy];
+
+/*
+      if (element==EL_ERDREICH || IS_SOLID(element))
+       continue;
+*/
+      if (element==EL_ERDREICH)
+       continue;
+
+      if (i==1 || i==2)
+      {
+       width = snip;
+       height = TILEY;
+       cx = (i==2 ? TILEX-snip : 0);
+       cy = 0;
+      }
+      else
+      {
+       width = TILEX;
+       height = snip;
+       cx = 0;
+       cy = (i==3 ? TILEY-snip : 0);
+      }
+
+      XCopyArea(display,pix[PIX_BACK],drawto_field,gc,
+               SX+(graphic % GFX_PER_LINE)*TILEX+cx,
+               SY+(graphic / GFX_PER_LINE)*TILEY+cy,
+               width,height, SX+x*TILEX+cx,SY+y*TILEY+cy);
+    }
+
+    redraw_tiles++;
+    redraw[x][y]=TRUE;
+  }
+  else
+  {
+    graphic = GFX_ERDENRAND;
+
+    for(i=0;i<4;i++)
+    {
+      int xx,yy,uxx,uyy;
+
+      xx = x+xy[i][0];
+      yy = y+xy[i][1];
+      uxx = ux+xy[i][0];
+      uyy = uy+xy[i][1];
+/*
+      if (!IN_LEV_FIELD(uxx,uyy) || Feld[uxx][uyy]!=EL_ERDREICH ||
+         !IN_SCR_FIELD(xx,yy) || IS_SOLID(element))
+       continue;
+*/
+
+      if (!IN_LEV_FIELD(uxx,uyy) || Feld[uxx][uyy]!=EL_ERDREICH ||
+         !IN_SCR_FIELD(xx,yy))
+       continue;
+
+      if (i==1 || i==2)
+      {
+       width = snip;
+       height = TILEY;
+       cx = (i==1 ? TILEX-snip : 0);
+       cy = 0;
+      }
+      else
+      {
+       width = TILEX;
+       height = snip;
+       cx = 0;
+       cy = (i==0 ? TILEY-snip : 0);
+      }
+
+      XCopyArea(display,pix[PIX_BACK],drawto_field,gc,
+               SX+(graphic % GFX_PER_LINE)*TILEX+cx,
+               SY+(graphic / GFX_PER_LINE)*TILEY+cy,
+               width,height, SX+xx*TILEX+cx,SY+yy*TILEY+cy);
+
+      redraw_tiles++;
+      redraw[xx][yy]=TRUE;
+    }
+  }
+}
+
+void DrawScreenElement(int x, int y, int element)
+{
+  DrawElementShifted(x,y,0,0,element,CUT_NO_CUTTING);
+  ErdreichAnbroeckeln(x,y);
+}
+
+void DrawLevelElement(int x, int y, int element)
+{
+  if (IN_LEV_FIELD(x,y) && IN_SCR_FIELD(SCROLLX(x),SCROLLY(y)))
+    DrawScreenElement(SCROLLX(x),SCROLLY(y),element);
+}
+
+void DrawScreenField(int x, int y)
+{
+  int ux = UNSCROLLX(x), uy = UNSCROLLY(y);
+  int element;
+
+  if (!IN_LEV_FIELD(ux,uy))
+  {
+    DrawScreenElement(x,y,EL_BETON);
+    return;
+  }
+
+  element = Feld[ux][uy];
+
+  if (IS_MOVING(ux,uy))
+  {
+    int horiz_move = (MovDir[ux][uy]==MV_LEFT || MovDir[ux][uy]==MV_RIGHT);
+    BOOL cut_mode = CUT_NO_CUTTING;
+
+    if (Store[ux][uy]==EL_MORAST_LEER ||
+       Store[ux][uy]==EL_SIEB_LEER ||
+       Store[ux][uy]==EL_AMOEBE2)
+      cut_mode = CUT_ABOVE;
+    else if (Store[ux][uy]==EL_MORAST_VOLL ||
+       Store[ux][uy]==EL_SIEB_VOLL ||
+       Store[ux][uy]==EL_SALZSAEURE)
+      cut_mode = CUT_BELOW;
+
+    if (cut_mode==CUT_ABOVE)
+      DrawElementShifted(x,y,0,0,Store[ux][uy],CUT_NO_CUTTING);
+    else
+      DrawScreenElement(x,y,EL_LEERRAUM);
+
+    if (horiz_move)
+      DrawElementShifted(x,y,MovPos[ux][uy],0,element,CUT_NO_CUTTING);
+    else
+      DrawElementShifted(x,y,0,MovPos[ux][uy],element,cut_mode);
+  }
+  else if (IS_BLOCKED(ux,uy))
+  {
+    int oldx,oldy;
+    int sx, sy;
+    int horiz_move;
+    BOOL cut_mode = CUT_NO_CUTTING;
+
+    Blocked2Moving(ux,uy,&oldx,&oldy);
+    sx = SCROLLX(oldx);
+    sy = SCROLLY(oldy);
+    horiz_move = (MovDir[oldx][oldy]==MV_LEFT || MovDir[oldx][oldy]==MV_RIGHT);
+
+    if (Store[oldx][oldy]==EL_MORAST_LEER ||
+       Store[oldx][oldy]==EL_SIEB_LEER ||
+       Store[oldx][oldy]==EL_AMOEBE2)
+      cut_mode = CUT_ABOVE;
+
+    DrawScreenElement(x,y,EL_LEERRAUM);
+    element = Feld[oldx][oldy];
+
+    if (horiz_move)
+      DrawElementShifted(sx,sy,MovPos[oldx][oldy],0,element,CUT_NO_CUTTING);
+    else
+      DrawElementShifted(sx,sy,0,MovPos[oldx][oldy],element,cut_mode);
+  }
+  else if (IS_DRAWABLE(element))
+    DrawScreenElement(x,y,element);
+  else
+    DrawScreenElement(x,y,EL_LEERRAUM);
+}
+
+void DrawLevelField(int x, int y)
+{
+  if (IN_SCR_FIELD(SCROLLX(x),SCROLLY(y)))
+    DrawScreenField(SCROLLX(x),SCROLLY(y));
+  else if (IS_MOVING(x,y))
+  {
+    int newx,newy;
+
+    Moving2Blocked(x,y,&newx,&newy);
+    if (IN_SCR_FIELD(SCROLLX(newx),SCROLLY(newy)))
+      DrawScreenField(SCROLLX(newx),SCROLLY(newy));
+  }
+  else if (IS_BLOCKED(x,y))
+  {
+    int oldx,oldy;
+
+    Blocked2Moving(x,y,&oldx,&oldy);
+    if (IN_SCR_FIELD(SCROLLX(oldx),SCROLLY(oldy)))
+      DrawScreenField(SCROLLX(oldx),SCROLLY(oldy));
+  }
+}
+
+void DrawMiniElement(int x, int y, int element)
+{
+  int graphic;
+
+  if (!element)
+  {
+    DrawMiniGraphic(x,y,-1);
+    return;
+  }
+
+  graphic = el2gfx(element);
+  DrawMiniGraphic(x,y,graphic);
+
+  redraw_tiles++;
+  redraw[x/2][y/2]=TRUE;
+  redraw_mask|=REDRAW_TILES;
+}
+
+void DrawMiniElementOrWall(int x, int y, int scroll_x, int scroll_y)
+{
+  if (x+scroll_x<-1 || x+scroll_x>lev_fieldx ||
+      y+scroll_y<-1 || y+scroll_y>lev_fieldy)
+    DrawMiniElement(x,y,EL_LEERRAUM);
+  else if (x+scroll_x==-1 || x+scroll_x==lev_fieldx ||
+          y+scroll_y==-1 || y+scroll_y==lev_fieldy)
+    DrawMiniElement(x,y,EL_BETON);
+  else
+    DrawMiniElement(x,y,Feld[x+scroll_x][y+scroll_y]);
+}
+
+void DrawMicroElement(int xpos, int ypos, int element)
+{
+  int graphic;
+
+  if (element==EL_LEERRAUM)
+    return;
+
+  graphic = el2gfx(element);
+
+  XCopyArea(display,pix[PIX_BACK],drawto,gc,
+           MICRO_GFX_STARTX+(graphic % MICRO_GFX_PER_LINE)*MICRO_TILEX,
+           MICRO_GFX_STARTY+(graphic / MICRO_GFX_PER_LINE)*MICRO_TILEY,
+           MICRO_TILEX,MICRO_TILEY, xpos,ypos);
+}
+
+void DrawLevel()
+{
+  int x,y;
+
+  ClearWindow();
+
+  for(x=0;x<SCR_FIELDX;x++)
+    for(y=0;y<SCR_FIELDY;y++)
+      DrawScreenField(x,y);
+
+  redraw_mask |= REDRAW_FIELD;
+}
+
+void DrawMiniLevel(int scroll_x, int scroll_y)
+{
+  int x,y;
+
+  ClearWindow();
+
+  for(x=0;x<2*SCR_FIELDX;x++)
+    for(y=0;y<2*SCR_FIELDY;y++)
+      DrawMiniElementOrWall(x,y,scroll_x,scroll_y);
+
+  redraw_mask |= REDRAW_FIELD;
+}
+
+void DrawMicroLevel(int xpos, int ypos)
+{
+  int x,y;
+
+  XFillRectangle(display,drawto,gc,
+                xpos-MICRO_TILEX,ypos-MICRO_TILEY,
+                MICRO_TILEX*(STD_LEV_FIELDX+2),
+                MICRO_TILEY*(STD_LEV_FIELDY+2));
+
+  for(x=-1;x<=STD_LEV_FIELDX;x++)
+    for(y=-1;y<=STD_LEV_FIELDY;y++)
+      if (x>=0 && x<lev_fieldx && y>=0 && y<lev_fieldy)
+       DrawMicroElement(xpos+MICRO_TILEX*x,ypos+MICRO_TILEY*y,
+                        Feld[x][y]=Ur[x][y]);
+      else if (x>=-1 && x<lev_fieldx+1 && y>=-1 && y<lev_fieldy+1)
+       DrawMicroElement(xpos+MICRO_TILEX*x,ypos+MICRO_TILEY*y,
+                        EL_BETON);
+
+  XFillRectangle(display,drawto,gc, SX,MICROLABEL_YPOS, SXSIZE,FONT4_YSIZE);
+
+  if (level.name)
+  {
+    int len = strlen(level.name);
+    int lxpos = SX+(SXSIZE-len*FONT4_XSIZE)/2;
+    int lypos = MICROLABEL_YPOS;
+
+    DrawText(lxpos,lypos,level.name,FS_SMALL,FC_SPECIAL2);
+  }
+
+  redraw_mask |= REDRAW_MICROLEV;
+}
+
+int AYS_in_range(int x, int y)
+{
+  if (y>DY+249 && y<DY+278)
+  {
+    if (x>DX+1 && x<DX+48)
+      return(1);
+    else if (x>DX+51 && x<DX+98) 
+      return(2);
+  }
+  return(0);
+}
+
+BOOL AreYouSure(char *text, unsigned int ays_state)
+{
+  int mx,my, ty, result = -1;
+
+  CloseDoor(DOOR_CLOSE_1);
+
+  /* Alten Türinhalt sichern */
+  XCopyArea(display,pix[PIX_DB_DOOR],pix[PIX_DB_DOOR],gc,
+           DOOR_GFX_PAGEX1,DOOR_GFX_PAGEY1, DXSIZE,DYSIZE,
+           DOOR_GFX_PAGEX2,DOOR_GFX_PAGEY1);
+
+  /* Fragetext schreiben */
+  XFillRectangle(display,pix[PIX_DB_DOOR],gc,
+                DOOR_GFX_PAGEX1,DOOR_GFX_PAGEY1,DXSIZE,DYSIZE);
+
+  for(ty=0;ty<13;ty++)
+  {
+    int tx,tl,tc;
+    char txt[256];
+
+    if (!(*text))
+      break;
+    for(tl=0,tx=0;tx<7;tl++,tx++)
+    {
+      tc=*(text+tx);
+      if (!tc || tc==32)
+       break;
+    }
+    if (!tl)
+    { 
+      text++; 
+      ty--; 
+      continue; 
+    }
+    sprintf(txt,text); 
+    txt[tl]=0;
+    DrawTextExt(pix[PIX_DB_DOOR],gc,
+               DOOR_GFX_PAGEX1+51-(tl*14)/2,SY+ty*16,txt,FS_SMALL,FC_YELLOW);
+    text+=(tl+(tc==32));
+  }
+
+  if (ays_state & AYS_ASK)
+    XCopyArea(display,pix[PIX_DOOR],pix[PIX_DB_DOOR],gc,
+             DOOR_GFX_PAGEX4,OK_BUTTON_GFX_YPOS,
+             DXSIZE,OK_BUTTON_YSIZE,
+             DOOR_GFX_PAGEX1,OK_BUTTON_YPOS);
+  else if (ays_state & AYS_CONFIRM)
+    XCopyArea(display,pix[PIX_DOOR],pix[PIX_DB_DOOR],gc,
+             DOOR_GFX_PAGEX4,CONFIRM_BUTTON_GFX_YPOS,
+             DXSIZE,CONFIRM_BUTTON_YSIZE,
+             DOOR_GFX_PAGEX1,CONFIRM_BUTTON_YPOS);
+
+  OpenDoor(DOOR_OPEN_1);
+
+  if (!(ays_state & AYS_ASK) && !(ays_state & AYS_CONFIRM))
+    return(FALSE);
+
+  if (game_status!=MAINMENU)
+    InitAnimation();
+
+  button_status = MB_RELEASED;
+
+  while(result<0)
+  {
+    DoAnimation();
+    Delay(10000);
+
+    if (XPending(display))
+    {
+      XEvent event;
+
+      XNextEvent(display, &event);
+      switch(event.type)
+      {
+       case Expose:
+         HandleExposeEvent((XExposeEvent *) &event);
+         break;
+       case UnmapNotify:
+         SleepWhileUnmapped();
+         break;
+       case ButtonPress:
+       case ButtonRelease:
+       case MotionNotify:
+       {
+         int choice;
+
+         if (event.type==MotionNotify)
+         {
+           motion_status = TRUE;
+           mx = ((XMotionEvent *) &event)->x;
+           my = ((XMotionEvent *) &event)->y;
+         }
+         else
+         {
+           motion_status = FALSE;
+           mx = ((XButtonEvent *) &event)->x;
+           my = ((XButtonEvent *) &event)->y;
+           if (event.type==ButtonPress)
+             button_status = ((XButtonEvent *) &event)->button;
+           else
+             button_status = MB_RELEASED;
+         }
+
+         if (ays_state & AYS_ASK)
+           choice = CheckChooseButtons(mx,my,button_status);
+         else
+           choice = CheckConfirmButton(mx,my,button_status);
+
+         switch(choice)
+         {
+           case BUTTON_OK:
+             result = TRUE;
+             break;
+           case BUTTON_NO:
+             result = FALSE;
+             break;
+           case BUTTON_CONFIRM:
+             result = TRUE|FALSE;
+             break;
+           default:
+             break;
+         }
+         break;
+       }
+       case KeyPress:
+         key_status = KEY_PRESSED;
+         switch(XLookupKeysym((XKeyEvent *)&event,
+                              ((XKeyEvent *)&event)->state))
+         {
+           case XK_Return:
+             result = 1;
+             break;
+           case XK_Escape:
+             result = 0;
+             break;
+         }
+         break;
+       case FocusIn:
+         HandleFocusEvent(FOCUS_IN);
+         break;
+       case FocusOut:
+         HandleFocusEvent(FOCUS_OUT);
+         break;
+       default:
+         break;
+      }
+    }
+    else if (JoystickButton()==JOY_BUTTON_NEW_PRESSED)
+    {
+      int joy=Joystick();
+
+      if (joy & JOY_BUTTON_1)
+       result = 1;
+      else if (joy & JOY_BUTTON_2)
+       result = 0;
+    }
+  }
+
+  if (game_status!=MAINMENU)
+    StopAnimation();
+
+  if (!(ays_state & AYS_STAY_OPEN))
+  {
+    CloseDoor(DOOR_CLOSE_1);
+
+    if (!(ays_state & AYS_STAY_CLOSED) &&
+       (game_status==PLAYING || game_status==LEVELED))
+    {
+      XCopyArea(display,pix[PIX_DB_DOOR],pix[PIX_DB_DOOR],gc,
+               DOOR_GFX_PAGEX2,DOOR_GFX_PAGEY1, DXSIZE,DYSIZE,
+               DOOR_GFX_PAGEX1,DOOR_GFX_PAGEY1);
+      OpenDoor(DOOR_OPEN_1);
+    }
+  }
+
+  return(result);
+}
+
+void OpenDoor(unsigned int door_state)
+{
+  if (door_state & DOOR_COPY_BACK)
+  {
+    XCopyArea(display,pix[PIX_DB_DOOR],pix[PIX_DB_DOOR],gc,
+             DOOR_GFX_PAGEX2,DOOR_GFX_PAGEY1, DXSIZE,DYSIZE+VYSIZE,
+             DOOR_GFX_PAGEX1,DOOR_GFX_PAGEY1);
+    door_state &= ~DOOR_COPY_BACK;
+  }
+
+  MoveDoor(door_state);
+  ClearEventQueue();
+}
+
+void CloseDoor(unsigned int door_state)
+{
+  XCopyArea(display,backbuffer,pix[PIX_DB_DOOR],gc,
+           DX,DY, DXSIZE,DYSIZE, DOOR_GFX_PAGEX1,DOOR_GFX_PAGEY1);
+  XCopyArea(display,backbuffer,pix[PIX_DB_DOOR],gc,
+           VX,VY, VXSIZE,VYSIZE, DOOR_GFX_PAGEX1,DOOR_GFX_PAGEY2);
+
+  MoveDoor(door_state);
+  ClearEventQueue();
+}
+
+void MoveDoor(unsigned int door_state)
+{
+  static int door1 = DOOR_CLOSE_1;
+  static int door2 = DOOR_OPEN_2;
+  int x, start, stepsize = 4;
+
+  if (door1==DOOR_OPEN_1 && door_state & DOOR_OPEN_1)
+    door_state &= ~DOOR_OPEN_1;
+  else if (door1==DOOR_CLOSE_1 && door_state & DOOR_CLOSE_1)
+    door_state &= ~DOOR_CLOSE_1;
+  if (door2==DOOR_OPEN_2 && door_state & DOOR_OPEN_2)
+    door_state &= ~DOOR_OPEN_2;
+  else if (door2==DOOR_CLOSE_2 && door_state & DOOR_CLOSE_2)
+    door_state &= ~DOOR_CLOSE_2;
+
+  if (door_state & DOOR_ACTION)
+  {
+    if (door_state & DOOR_OPEN_1)
+    {
+      XCopyArea(display,pix[PIX_DOOR],pix[PIX_DOOR],gc,
+               104,136, 8,8, 146,136);
+      if (!(door_state & DOOR_NO_DELAY))
+      {
+       int i;
+
+       XCopyArea(display,pix[PIX_DOOR],window,gc,
+                 104,136, 8,8, DX+46,DY+136);
+       XFlush(display);
+       for(i=0;i<30;i++)
+       {
+         if (game_status==MAINMENU)
+           DoAnimation();
+         Delay(10000);
+       }
+      }
+    }
+    else if (door_state & DOOR_CLOSE_1)
+      XCopyArea(display,pix[PIX_DOOR],pix[PIX_DOOR],gc,
+               88,136, 8,8, 146,136);
+
+    if (!(door_state & DOOR_NO_DELAY))
+      PlaySoundStereo(SND_OEFFNEN,PSND_MAX_RIGHT);
+
+    start = ((door_state & DOOR_NO_DELAY) ? DXSIZE : 0);
+
+    for(x=start;x<=DXSIZE;x+=stepsize)
+    {
+      if (door_state & DOOR_ACTION_1)
+      {
+       int i = (door_state & DOOR_OPEN_1 ? DXSIZE-x : x);
+
+       XCopyArea(display,pix[PIX_DB_DOOR],drawto,gc,
+                 DOOR_GFX_PAGEX1,DOOR_GFX_PAGEY1+i/2,
+                 DXSIZE,DYSIZE-i/2, DX,DY);
+
+       XFillRectangle(display,drawto,gc,DX,DY+DYSIZE-i/2,DXSIZE,i/2);
+
+       XSetClipOrigin(display,clip_gc[PIX_DOOR],DX-DXSIZE+i,DY);
+       XCopyArea(display,pix[PIX_DOOR],drawto,clip_gc[PIX_DOOR],
+                 DXSIZE-i,0, i,30, DX,DY);
+       XCopyArea(display,pix[PIX_DOOR],drawto,clip_gc[PIX_DOOR],
+                 DXSIZE-i,DYSIZE-30, i,30, DX,DY+DYSIZE-30);
+       XSetClipOrigin(display,clip_gc[PIX_DOOR],DX-i,DY);
+       XCopyArea(display,pix[PIX_DOOR],drawto,clip_gc[PIX_DOOR],
+                 DXSIZE,0, i,30, DX+DXSIZE-i,DY);
+       XCopyArea(display,pix[PIX_DOOR],drawto,clip_gc[PIX_DOOR],
+                 DXSIZE,DYSIZE-30, i,30, DX+DXSIZE-i,DY+DYSIZE-30);
+       if (i>14)
+       {
+         XSetClipOrigin(display,clip_gc[PIX_DOOR],DX-i,DY);
+         XCopyArea(display,pix[PIX_DOOR],drawto,clip_gc[PIX_DOOR],
+                   DXSIZE+14,30,i-14,DYSIZE-60,DX+DXSIZE+14-i,DY+30);
+         XSetClipOrigin(display,clip_gc[PIX_DOOR],DX-DXSIZE+i,DY);
+         XCopyArea(display,pix[PIX_DOOR],drawto,clip_gc[PIX_DOOR],
+                   DXSIZE-i,30,i-14,DYSIZE-60,DX,DY+30);
+       }
+       redraw_mask |= REDRAW_DOOR_1;
+      }
+
+      if (door_state & DOOR_ACTION_2)
+      {
+       int i = (door_state & DOOR_OPEN_2 ? VXSIZE-x : x);
+
+       XCopyArea(display,pix[PIX_DB_DOOR],drawto,gc,
+                 DOOR_GFX_PAGEX1,DOOR_GFX_PAGEY2+i/2,
+                 VXSIZE,VYSIZE-i/2, VX,VY);
+
+       XFillRectangle(display,drawto,gc,VX,VY+VYSIZE-i/2,VXSIZE,i/2);
+
+       XSetClipOrigin(display,clip_gc[PIX_DOOR],
+                      VX-VXSIZE+i,VY-DOOR_GFX_PAGEY2);
+       XCopyArea(display,pix[PIX_DOOR],drawto,clip_gc[PIX_DOOR],
+                 VXSIZE-i,DOOR_GFX_PAGEY2, i,VYSIZE, VX,VY);
+       XSetClipOrigin(display,clip_gc[PIX_DOOR],
+                      VX-i,VY-DOOR_GFX_PAGEY2);
+       XCopyArea(display,pix[PIX_DOOR],drawto,clip_gc[PIX_DOOR],
+                 VXSIZE,DOOR_GFX_PAGEY2, i,VYSIZE, VX+VXSIZE-i,VY);
+
+       redraw_mask |= REDRAW_DOOR_2;
+      }
+
+      BackToFront();
+      Delay(stepsize*5000);
+
+      if (game_status==MAINMENU)
+       DoAnimation();
+    }
+  }
+
+  if (door_state & DOOR_ACTION_1)
+    door1 = door_state & DOOR_ACTION_1;
+  if (door_state & DOOR_ACTION_2)
+    door2 = door_state & DOOR_ACTION_2;
+}
+
+long mainCounter(int mode)
+{
+  static struct timeval base_time = { 0, 0 };
+  struct timeval current_time;
+  long counter_ms;
+
+  gettimeofday(&current_time,NULL);
+  if (mode==0 || current_time.tv_sec<base_time.tv_sec)
+    base_time = current_time;
+
+  counter_ms = (current_time.tv_sec - base_time.tv_sec)*1000
+             + (current_time.tv_usec - base_time.tv_usec)/1000;
+
+  if (mode==1)
+    return(counter_ms/10);     /* return 1/100 secs since last init */
+  else
+    return(counter_ms);                /* return 1/1000 secs since last init */
+}
+
+void InitCounter() /* set counter back to zero */
+{
+  mainCounter(0);
+}
+
+long Counter() /* returns 1/100 secs since last call of InitCounter() */
+{
+  return(mainCounter(1));
+}
+
+long Counter2()        /* returns 1/1000 secs since last call of InitCounter() */
+{
+  return(mainCounter(2));
+}
+
+void WaitCounter(long value)   /* wait for counter to reach value */
+{
+  long wait;
+
+  while((wait=value-Counter())>0)
+    microsleep(wait*10000);
+}
+
+void WaitCounter2(long value)  /* wait for counter to reach value */
+{
+  long wait;
+
+  while((wait=value-Counter2())>0)
+    microsleep(wait*1000);
+}
+
+void Delay(long value)
+{
+  microsleep(value);
+}
+
+BOOL DelayReached(long *counter_var, int delay)
+{
+  long actual_counter = Counter();
+
+  if (actual_counter>*counter_var+delay || actual_counter<*counter_var)
+  {
+    *counter_var = actual_counter;
+    return(TRUE);
+  }
+  else
+    return(FALSE);
+}
+
+int ReadPixel(Drawable d, int x, int y)
+{
+  static XImage *pixelimage;
+
+  pixelimage = XGetImage(display, d, x,y, 1,1, AllPlanes, ZPixmap);
+  return(XGetPixel(pixelimage,0,0));
+}
+
+static struct JoystickInfo joystick[2] =
+{
+  JOYSTICK_XLEFT, JOYSTICK_XRIGHT, JOYSTICK_XMIDDLE,
+  JOYSTICK_YUPPER, JOYSTICK_YLOWER, JOYSTICK_YMIDDLE,
+
+  JOYSTICK_XLEFT, JOYSTICK_XRIGHT, JOYSTICK_XMIDDLE,
+  JOYSTICK_YUPPER, JOYSTICK_YLOWER, JOYSTICK_YMIDDLE
+};
+
+void LoadJoystickData()
+{
+  int i;
+  char cookie[256];
+  FILE *file;
+
+  if (joystick_status==JOYSTICK_OFF)
+    return;
+
+  if (!(file=fopen(JOYDAT_FILE,"r")))
+    return;
+
+  fscanf(file,"%s",cookie);
+  if (strcmp(cookie,JOYSTICK_COOKIE))  /* ungültiges Format? */
+  {
+    fprintf(stderr,"%s: wrong format of joystick file!\n",progname);
+    fclose(file);
+    return;
+  }
+
+  for(i=0;i<2;i++)
+  {
+    fscanf(file,"%s",cookie);
+    fscanf(file, "%d %d %d \n",
+          &joystick[i].xleft, &joystick[i].xmiddle, &joystick[i].xright);
+    fscanf(file, "%d %d %d \n",
+          &joystick[i].yupper, &joystick[i].ymiddle, &joystick[i].ylower);
+  }
+  fclose(file);
+
+  CheckJoystickData();
+}
+
+void SaveJoystickData()
+{
+  int i;
+  FILE *file;
+
+  if (joystick_status==JOYSTICK_OFF)
+    return;
+
+  CheckJoystickData();
+
+  if (!(file=fopen(JOYDAT_FILE,"w")))
+  {
+    fprintf(stderr,"%s: cannot save joystick calibration data!\n",progname);
+    return;
+  }
+
+  fprintf(file,"%s\n",JOYSTICK_COOKIE);        /* Formatkennung */
+  for(i=0;i<2;i++)
+  {
+    fprintf(file,"JOYSTICK_%d_DATA\n",i);
+    fprintf(file, "%d %d %d \n",
+           joystick[i].xleft, joystick[i].xmiddle, joystick[i].xright);
+    fprintf(file, "%d %d %d \n",
+           joystick[i].yupper, joystick[i].ymiddle, joystick[i].ylower);
+  }
+  fclose(file);
+
+  chmod(JOYDAT_FILE, JOYDAT_PERMS);
+}
+
+void CheckJoystickData()
+{
+  int i;
+  int distance = 100;
+
+  for(i=0;i<2;i++)
+  {
+    if (joystick[i].xmiddle <= distance)
+      joystick[i].xmiddle = distance;
+    if (joystick[i].ymiddle <= distance)
+      joystick[i].ymiddle = distance;
+
+    if (joystick[i].xleft >= joystick[i].xmiddle)
+      joystick[i].xleft = joystick[i].xmiddle-distance;
+    if (joystick[i].xright <= joystick[i].xmiddle)
+      joystick[i].xright = joystick[i].xmiddle+distance;
+
+    if (joystick[i].yupper >= joystick[i].ymiddle)
+      joystick[i].yupper = joystick[i].ymiddle-distance;
+    if (joystick[i].ylower <= joystick[i].ymiddle)
+      joystick[i].ylower = joystick[i].ymiddle+distance;
+  }
+}
+
+int JoystickPosition(int middle, int margin, int actual)
+{
+  long range, pos;
+  int percentage;
+
+  if (margin<middle && actual>middle)
+    return(0);
+  if (margin>middle && actual<middle)
+    return(0);
+
+  range=ABS(margin-middle);
+  pos=ABS(actual-middle);
+  percentage=(int)(pos*100/range);
+  if (percentage>100)
+    percentage=100;
+
+  return(percentage);
+}
+
+int Joystick()
+{
+  struct joystick_control
+  {
+    int buttons;
+    int x;
+    int y;
+  } joy_ctrl;
+
+  int js_x,js_y, js_b1,js_b2;
+  int left, right, up, down;
+  int result=0;
+
+  if (joystick_status==JOYSTICK_OFF)
+    return(0);
+
+  if (read(joystick_device, &joy_ctrl, sizeof(joy_ctrl)) != sizeof(joy_ctrl))
+  {
+    fprintf(stderr,"%s: cannot read joystick settings - no joystick support\n",progname);
+    joystick_status = JOYSTICK_OFF;
+    return(0);
+  }
+
+  js_x  = joy_ctrl.x;
+  js_y  = joy_ctrl.y;
+  js_b1 = joy_ctrl.buttons & 1;
+  js_b2 = joy_ctrl.buttons & 2;
+
+  left = JoystickPosition(joystick[joystick_nr].xmiddle,
+                         joystick[joystick_nr].xleft,  js_x);
+  right = JoystickPosition(joystick[joystick_nr].xmiddle,
+                          joystick[joystick_nr].xright, js_x);
+  up =    JoystickPosition(joystick[joystick_nr].ymiddle,
+                          joystick[joystick_nr].yupper, js_y);
+  down =  JoystickPosition(joystick[joystick_nr].ymiddle,
+                          joystick[joystick_nr].ylower, js_y);
+
+  if (left>JOYSTICK_PERCENT)
+    result |= JOY_LEFT;
+  else if (right>JOYSTICK_PERCENT)
+    result |= JOY_RIGHT;
+  if (up>JOYSTICK_PERCENT)
+    result |= JOY_UP;
+  else if (down>JOYSTICK_PERCENT)
+    result |= JOY_DOWN;
+  if (js_b1)
+    result |= JOY_BUTTON_1;
+  if (js_b2)
+    result |= JOY_BUTTON_2;
+
+  return(result);
+}
+
+int JoystickButton()
+{
+  static int last_joy_button=0;
+  int joy_button=(Joystick() & JOY_BUTTON);
+  int result;
+
+  if (joy_button)
+  {
+    if (last_joy_button)
+      result=JOY_BUTTON_PRESSED;
+    else
+      result=JOY_BUTTON_NEW_PRESSED;
+  }
+  else
+  {
+    if (last_joy_button)
+      result=JOY_BUTTON_NEW_RELEASED;
+    else
+      result=JOY_BUTTON_NOT_PRESSED;
+  }
+
+  last_joy_button = joy_button;
+  return(result);
+}
+
+void CalibrateJoystick()
+{
+  struct joystick_control
+  {
+    int buttons;
+    int x;
+    int y;
+  } joy_ctrl;
+
+  int new_joystick_xleft, new_joystick_xright, new_joystick_xmiddle;
+  int new_joystick_yupper, new_joystick_ylower, new_joystick_ymiddle;
+
+  if (joystick_status==JOYSTICK_OFF)
+    goto error_out;
+
+  ClearWindow();
+  DrawText(SX+16, SY+7*32, "MOVE JOYSTICK TO",FS_BIG,FC_YELLOW);
+  DrawText(SX+16, SY+8*32, " THE UPPER LEFT ",FS_BIG,FC_YELLOW);
+  DrawText(SX+16, SY+9*32, "AND PRESS BUTTON",FS_BIG,FC_YELLOW);
+  BackToFront();
+
+  joy_ctrl.buttons = 0;
+  while(Joystick() & JOY_BUTTON);
+  while(!joy_ctrl.buttons)
+  {
+    if (read(joystick_device, &joy_ctrl, sizeof(joy_ctrl)) != sizeof(joy_ctrl))
+    {
+      joystick_status=JOYSTICK_OFF;
+      goto error_out;
+    }
+    Delay(10000);
+  }
+
+  new_joystick_xleft = joy_ctrl.x;
+  new_joystick_yupper = joy_ctrl.y;
+
+  ClearWindow();
+  DrawText(SX+16, SY+7*32, "MOVE JOYSTICK TO",FS_BIG,FC_YELLOW);
+  DrawText(SX+32, SY+8*32, "THE LOWER RIGHT",FS_BIG,FC_YELLOW);
+  DrawText(SX+16, SY+9*32, "AND PRESS BUTTON",FS_BIG,FC_YELLOW);
+  BackToFront();
+
+  joy_ctrl.buttons = 0;
+  while(Joystick() & JOY_BUTTON);
+  while(!joy_ctrl.buttons)
+  {
+    if (read(joystick_device, &joy_ctrl, sizeof(joy_ctrl)) != sizeof(joy_ctrl))
+    {
+      joystick_status=JOYSTICK_OFF;
+      goto error_out;
+    }
+    Delay(10000);
+  }
+
+  new_joystick_xright = joy_ctrl.x;
+  new_joystick_ylower = joy_ctrl.y;
+
+  ClearWindow();
+  DrawText(SX+32, SY+16+7*32, "CENTER JOYSTICK",FS_BIG,FC_YELLOW);
+  DrawText(SX+16, SY+16+8*32, "AND PRESS BUTTON",FS_BIG,FC_YELLOW);
+  BackToFront();
+
+  joy_ctrl.buttons = 0;
+  while(Joystick() & JOY_BUTTON);
+  while(!joy_ctrl.buttons)
+  {
+    if (read(joystick_device, &joy_ctrl, sizeof(joy_ctrl)) != sizeof(joy_ctrl))
+    {
+      joystick_status=JOYSTICK_OFF;
+      goto error_out;
+    }
+    Delay(10000);
+  }
+
+  new_joystick_xmiddle = joy_ctrl.x;
+  new_joystick_ymiddle = joy_ctrl.y;
+
+  joystick[joystick_nr].xleft = new_joystick_xleft;
+  joystick[joystick_nr].yupper = new_joystick_yupper;
+  joystick[joystick_nr].xright = new_joystick_xright;
+  joystick[joystick_nr].ylower = new_joystick_ylower;
+  joystick[joystick_nr].xmiddle = new_joystick_xmiddle;
+  joystick[joystick_nr].ymiddle = new_joystick_ymiddle;
+
+  CheckJoystickData();
+
+  DrawSetupScreen();
+  while(Joystick() & JOY_BUTTON);
+  return;
+
+  error_out:
+
+  ClearWindow();
+  DrawText(SX+16, SY+16, "NO JOYSTICK",FS_BIG,FC_YELLOW);
+  DrawText(SX+16, SY+48, " AVAILABLE ",FS_BIG,FC_YELLOW);
+  Delay(3000000);
+  DrawSetupScreen();
+}
diff --git a/src/tools.h b/src/tools.h
new file mode 100644 (file)
index 0000000..b3fa84e
--- /dev/null
@@ -0,0 +1,101 @@
+/***********************************************************
+*  Rocks'n'Diamonds -- McDuffin Strikes Back!              *
+*----------------------------------------------------------*
+*  ©1995 Artsoft Development                               *
+*        Holger Schemel                                    *
+*        33659 Bielefeld-Senne                             *
+*        Telefon: (0521) 493245                            *
+*        eMail: aeglos@valinor.owl.de                      *
+*               aeglos@uni-paderborn.de                    *
+*               q99492@pbhrzx.uni-paderborn.de             *
+*----------------------------------------------------------*
+*  tools.h                                                 *
+*                                                          *
+*  Letzte Aenderung: 15.06.1995                            *
+***********************************************************/
+
+#ifndef TOOLS_H
+#define TOOLS_H
+
+#include "main.h"
+
+#include <sys/time.h>
+
+/* für DrawElementShifted */
+#define CUT_NO_CUTTING 0
+#define CUT_ABOVE      1
+#define CUT_BELOW      2
+#define CUT_LEFT       4
+#define CUT_RIGHT      8
+
+/* für MoveDoor */
+#define DOOR_OPEN_1    1
+#define DOOR_OPEN_2    2
+#define DOOR_CLOSE_1   4
+#define DOOR_CLOSE_2   8
+#define DOOR_OPEN_BOTH (DOOR_OPEN_1 | DOOR_OPEN_2)
+#define DOOR_CLOSE_BOTH        (DOOR_CLOSE_1 | DOOR_CLOSE_2)
+#define DOOR_ACTION_1  (DOOR_OPEN_1 | DOOR_CLOSE_1)
+#define DOOR_ACTION_2  (DOOR_OPEN_2 | DOOR_CLOSE_2)
+#define DOOR_ACTION    (DOOR_ACTION_1 | DOOR_ACTION_2)
+#define DOOR_COPY_BACK 16
+#define DOOR_NO_DELAY  32
+
+/* für AreYouSure */
+#define AYS_ASK                1
+#define AYS_OPEN       2
+#define AYS_CLOSE      4
+#define AYS_CONFIRM    8
+#define AYS_STAY_CLOSED        16
+#define AYS_STAY_OPEN  32
+
+void BackToFront();
+void FadeToFront();
+void ClearWindow();
+void DrawText(int, int, char *, int, int);
+void DrawTextExt(Drawable, GC, int, int, char *, int, int);
+void DrawGraphic(int, int, int);
+void DrawGraphicExt(Drawable, GC, int, int, int);
+void DrawGraphicExtHiRes(Drawable, GC, int, int, int);
+void DrawGraphicThruMask(int, int, int);
+void DrawElementThruMask(int, int, int);
+void DrawMiniGraphic(int, int, int);
+void DrawMiniGraphicExt(Drawable, GC, int, int, int);
+void DrawMiniGraphicExtHiRes(Drawable, GC, int, int, int);
+int el2gfx(int);
+void DrawGraphicShifted(int, int, int, int, int, int);
+void DrawElementShifted(int, int, int, int, int, int);
+void ErdreichAnbroeckeln(int, int);
+void DrawScreenElement(int, int, int);
+void DrawLevelElement(int, int, int);
+void DrawScreenField(int, int);
+void DrawLevelField(int, int);
+void DrawMiniElement(int, int, int);
+void DrawMiniElementOrWall(int, int, int, int);
+void DrawMicroElement(int, int, int);
+void DrawLevel(void);
+void DrawMiniLevel(int, int);
+void DrawMicroLevel(int, int);
+BOOL AreYouSure(char *, unsigned int);
+void OpenDoor(unsigned int);
+void CloseDoor(unsigned int);
+void MoveDoor(unsigned int);
+long mainCounter(int);
+void InitCounter(void);
+long Counter(void);
+long Counter2(void);
+void WaitCounter(long);
+void WaitCounter2(long);
+void Delay(long);
+BOOL DelayReached(long *, int);
+int ReadPixel(Drawable, int, int);
+int el2gfx(int);
+void LoadJoystickData(void);
+void SaveJoystickData(void);
+void CheckJoystickData(void);
+int JoystickPosition(int, int, int);
+int Joystick(void);
+int JoystickButton(void);
+void CalibrateJoystick(void);
+
+#endif