rnd-19970921-src
authorHolger Schemel <info@artsoft.org>
Sun, 21 Sep 1997 21:59:59 +0000 (23:59 +0200)
committerHolger Schemel <info@artsoft.org>
Sat, 30 Aug 2014 08:30:17 +0000 (10:30 +0200)
28 files changed:
REGISTRATION [deleted symlink]
src/Makefile
src/cartoons.c [new file with mode: 0644]
src/cartoons.h [new file with mode: 0644]
src/editor.c
src/events.c
src/events.h
src/files.c
src/game.c
src/game.h
src/gfxloader.c [new file with mode: 0644]
src/gfxloader.h [new file with mode: 0644]
src/init.c
src/init.h
src/joystick.c [new file with mode: 0644]
src/joystick.h [new file with mode: 0644]
src/main.c
src/main.h
src/misc.c
src/misc.h
src/random.c [new file with mode: 0644]
src/random.h [new file with mode: 0644]
src/screens.c
src/sound.c
src/sound.h
src/tape.c
src/tools.c
src/tools.h

diff --git a/REGISTRATION b/REGISTRATION
deleted file mode 120000 (symlink)
index 5f4a260..0000000
+++ /dev/null
@@ -1 +0,0 @@
-THIS_IS_NOW_FREEWARE
\ No newline at end of file
index 273cecd..22682e1 100644 (file)
@@ -15,8 +15,12 @@ GAME_DIR = -DGAME_DIR=\".\"          # path of the game and its data
 # 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>"
+# The XPM-Library is no longer needed to build this program,
+# but is used to load graphics if XPM_INCLUDE_FILE is defined,
+# because the GIF loading routines are still a bit beta.
+# If you use the Xpm library, convert the GIF files to Xpm
+# files (and the mask files ('*Maske.gif') to xbm files).
+# XPM_INCLUDE_FILE = -DXPM_INCLUDE_FILE="<X11/xpm.h>"
 
 CONFIG = $(GAME_DIR) $(SOUNDS) $(JOYSTICK)     \
         $(SCORE_ENTRIES) $(XPM_INCLUDE_FILE)
@@ -27,10 +31,15 @@ DEBUG = -DDEBUG -g -Wall
 
 # 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 = -L/usr/lib/X11R5 -lXpm -lX11 -lm # for HP-UX and others
-LIBS = -L/usr/X11R6/lib -lXpm -lX11 -lm
+# INCL = -I/usr/local/X11/include      # for SunOS and others
+# LIBS = -L/usr/lib/X11R5 -lXpm -lX11 -lm
+#                                      # for HP-UX and others
+# LIBS = -L/usr/local/X11/lib -lXpm -lX11 -lm -lsocket -R/usr/local/X11/lib
+#                                      # for SunOS and others
+
+# LIBS = -L/usr/X11R6/lib -lXpm -lX11 -lm
+LIBS = -L/usr/X11R6/lib -lX11 -lm
 
 # CFLAGS = -O2 $(CONFIG) $(SYSTEM)
 CFLAGS = $(DEBUG) $(CONFIG) $(SYSTEM) $(INCL)
@@ -46,7 +55,11 @@ SRCS =       main.c          \
        buttons.c       \
        files.c         \
        tape.c          \
-       sound.c
+       sound.c         \
+       joystick.c      \
+       cartoons.c      \
+       gfxloader.c     \
+       random.c
 
 OBJS = main.o          \
        init.o          \
@@ -59,7 +72,11 @@ OBJS =       main.o          \
        buttons.o       \
        files.o         \
        tape.o          \
-       sound.o
+       sound.o         \
+       joystick.o      \
+       cartoons.o      \
+       gfxloader.o     \
+       random.o
 
 all:   $(OBJS)
        $(CC) $(CFLAGS) $(OBJS) $(LIBS) -o $(PROGNAME)
@@ -69,3 +86,14 @@ all: $(OBJS)
 
 clean:
        $(RM) $(OBJS)
+
+backup:
+       @echo "tar cvzf /usr/AEGLOS/BACKUP/rnd-`date +%Y%m%d | cut -b 3-8`.tgz *.c *.h Makefile"
+       @tar cvzf /usr/AEGLOS/BACKUP/rnd-`date +%Y%m%d | cut -b 3-8`.tgz *.c *.h Makefile
+
+depend:
+       for i in $(SRCS); do $(CPP) $(CFLAGS) -M $$i; done > .depend
+
+ifeq (.depend,$(wildcard .depend))
+include .depend
+endif
diff --git a/src/cartoons.c b/src/cartoons.c
new file mode 100644 (file)
index 0000000..a295844
--- /dev/null
@@ -0,0 +1,552 @@
+/***********************************************************
+*  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             *
+*----------------------------------------------------------*
+*  cartoons.c                                              *
+***********************************************************/
+
+#include "cartoons.h"
+#include "main.h"
+#include "misc.h"
+#include "tools.h"
+
+static void HandleAnimation(int);
+static BOOL AnimateToon(int, BOOL);
+static void DrawAnim(Pixmap, GC, int, int, int, int, int, int, int, int);
+
+struct AnimInfo
+{
+  int width, height;
+  int src_x, src_y;
+  int frames;
+  int frames_per_second;
+  int stepsize;
+  BOOL pingpong;
+  int direction;
+  int position;
+};
+
+/* values for cartoon figures */
+#define NUM_TOONS      18
+
+#define DWARF_XSIZE    40
+#define DWARF_YSIZE    48
+#define DWARF_X                2
+#define DWARF_Y                72
+#define DWARF2_Y       186
+#define DWARF_FRAMES   8
+#define DWARF_FPS      10
+#define DWARF_STEPSIZE 4
+#define JUMPER_XSIZE   48
+#define JUMPER_YSIZE   56
+#define JUMPER_X       2
+#define JUMPER_Y       125
+#define JUMPER_FRAMES  8
+#define JUMPER_FPS     10
+#define JUMPER_STEPSIZE        4
+#define CLOWN_XSIZE    80
+#define CLOWN_YSIZE    110
+#define CLOWN_X                327
+#define CLOWN_Y                10
+#define CLOWN_FRAMES   1
+#define CLOWN_FPS      10
+#define CLOWN_STEPSIZE 4
+#define BIRD_XSIZE     32
+#define BIRD_YSIZE     30
+#define BIRD1_X                2
+#define BIRD1_Y                2
+#define BIRD2_X                2
+#define BIRD2_Y                37
+#define BIRD_FRAMES    8
+#define BIRD_FPS       20
+#define BIRD_STEPSIZE  4
+
+#define GAMETOON_XSIZE         TILEX
+#define GAMETOON_YSIZE         TILEY
+#define GAMETOON_FRAMES_4      4
+#define GAMETOON_FRAMES_8      8
+#define GAMETOON_FPS           20
+#define GAMETOON_STEPSIZE      4
+
+#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
+
+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;
+  int draw_mode;
+
+  if (!toons_on)
+    return;
+
+  switch(mode)
+  {
+    case ANIM_START:
+      anim_restart = TRUE;
+      reset_delay = TRUE;
+
+      /* Fill empty backbuffer for animation functions */
+      if (direct_draw_on && game_status==PLAYING)
+      {
+       int xx,yy;
+
+       drawto_field = backbuffer;
+
+       for(xx=0;xx<SCR_FIELDX;xx++)
+         for(yy=0;yy<SCR_FIELDY;yy++)
+           DrawScreenField(xx,yy);
+       DrawPlayerField();
+
+       drawto_field = window;
+      }
+
+      return;
+      break;
+    case ANIM_CONTINUE:
+      break;
+    case ANIM_STOP:
+      redraw_mask |= REDRAW_FIELD;
+
+      /* Redraw background even when in direct drawing mode */
+      draw_mode = direct_draw_on;
+      direct_draw_on = FALSE;
+
+      BackToFront();
+
+      direct_draw_on = draw_mode;
+
+      return;
+      break;
+    default:
+      break;
+  }
+
+  if (reset_delay)
+  {
+    animstart_delay = Counter();
+    animstart_delay_value = SimpleRND(500);
+    reset_delay = FALSE;
+  }
+
+  if (anim_restart)
+  {
+    if (!DelayReached(&animstart_delay,animstart_delay_value))
+      return;
+
+    toon_nr = SimpleRND(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;
+  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;
+  static struct AnimInfo toon[NUM_TOONS] =
+  {
+    {
+      DWARF_XSIZE, DWARF_YSIZE,
+      DWARF_X, DWARF_Y,
+      DWARF_FRAMES,
+      DWARF_FPS,
+      DWARF_STEPSIZE,
+      ANIM_NORMAL,
+      ANIMDIR_RIGHT,
+      ANIMPOS_DOWN
+    },
+    {
+      DWARF_XSIZE, DWARF_YSIZE,
+      DWARF_X, DWARF2_Y,
+      DWARF_FRAMES,
+      DWARF_FPS,
+      DWARF_STEPSIZE,
+      ANIM_NORMAL,
+      ANIMDIR_LEFT,
+      ANIMPOS_DOWN
+    },
+    {
+      JUMPER_XSIZE, JUMPER_YSIZE,
+      JUMPER_X, JUMPER_Y,
+      JUMPER_FRAMES,
+      JUMPER_FPS,
+      JUMPER_STEPSIZE,
+      ANIM_NORMAL,
+      ANIMDIR_LEFT,
+      ANIMPOS_DOWN
+    },
+    {
+      CLOWN_XSIZE, CLOWN_YSIZE,
+      CLOWN_X, CLOWN_Y,
+      CLOWN_FRAMES,
+      CLOWN_FPS,
+      CLOWN_STEPSIZE,
+      ANIM_NORMAL,
+      ANIMDIR_UP,
+      ANIMPOS_ANY
+    },
+    {
+      BIRD_XSIZE, BIRD_YSIZE,
+      BIRD1_X, BIRD1_Y,
+      BIRD_FRAMES,
+      BIRD_FPS,
+      BIRD_STEPSIZE,
+      ANIM_OSCILLATE,
+      ANIMDIR_RIGHT,
+      ANIMPOS_UPPER
+    },
+    {
+      BIRD_XSIZE, BIRD_YSIZE,
+      BIRD2_X, BIRD2_Y,
+      BIRD_FRAMES,
+      BIRD_FPS,
+      BIRD_STEPSIZE,
+      ANIM_OSCILLATE,
+      ANIMDIR_LEFT,
+      ANIMPOS_UPPER
+    },
+    {
+      GAMETOON_XSIZE, GAMETOON_YSIZE,
+      ((GFX_SPIELER_LEFT - GFX_START_ROCKSHEROES) % HEROES_PER_LINE)*TILEX,
+      ((GFX_SPIELER_LEFT - GFX_START_ROCKSHEROES) / HEROES_PER_LINE)*TILEY,
+      GAMETOON_FRAMES_4,
+      GAMETOON_FPS,
+      GAMETOON_STEPSIZE,
+      ANIM_NORMAL,
+      ANIMDIR_LEFT,
+      ANIMPOS_DOWN
+    },
+    {
+      GAMETOON_XSIZE, GAMETOON_YSIZE,
+      ((GFX_SPIELER_RIGHT - GFX_START_ROCKSHEROES) % HEROES_PER_LINE)*TILEX,
+      ((GFX_SPIELER_RIGHT - GFX_START_ROCKSHEROES) / HEROES_PER_LINE)*TILEY,
+      GAMETOON_FRAMES_4,
+      GAMETOON_FPS,
+      GAMETOON_STEPSIZE,
+      ANIM_NORMAL,
+      ANIMDIR_RIGHT,
+      ANIMPOS_DOWN
+    },
+    {
+      GAMETOON_XSIZE, GAMETOON_YSIZE,
+      ((GFX_PINGUIN_LEFT - GFX_START_ROCKSHEROES) % HEROES_PER_LINE)*TILEX,
+      ((GFX_PINGUIN_LEFT - GFX_START_ROCKSHEROES) / HEROES_PER_LINE)*TILEY,
+      GAMETOON_FRAMES_4,
+      GAMETOON_FPS,
+      GAMETOON_STEPSIZE,
+      ANIM_NORMAL,
+      ANIMDIR_LEFT,
+      ANIMPOS_DOWN
+    },
+    {
+      GAMETOON_XSIZE, GAMETOON_YSIZE,
+      ((GFX_PINGUIN_RIGHT - GFX_START_ROCKSHEROES) % HEROES_PER_LINE)*TILEX,
+      ((GFX_PINGUIN_RIGHT - GFX_START_ROCKSHEROES) / HEROES_PER_LINE)*TILEY,
+      GAMETOON_FRAMES_4,
+      GAMETOON_FPS,
+      GAMETOON_STEPSIZE,
+      ANIM_NORMAL,
+      ANIMDIR_RIGHT,
+      ANIMPOS_DOWN
+    },
+    {
+      GAMETOON_XSIZE, GAMETOON_YSIZE,
+      ((GFX_MAULWURF_LEFT - GFX_START_ROCKSHEROES) % HEROES_PER_LINE)*TILEX,
+      ((GFX_MAULWURF_LEFT - GFX_START_ROCKSHEROES) / HEROES_PER_LINE)*TILEY,
+      GAMETOON_FRAMES_4,
+      GAMETOON_FPS,
+      GAMETOON_STEPSIZE,
+      ANIM_NORMAL,
+      ANIMDIR_LEFT,
+      ANIMPOS_DOWN
+    },
+    {
+      GAMETOON_XSIZE, GAMETOON_YSIZE,
+      ((GFX_MAULWURF_RIGHT - GFX_START_ROCKSHEROES) % HEROES_PER_LINE)*TILEX,
+      ((GFX_MAULWURF_RIGHT - GFX_START_ROCKSHEROES) / HEROES_PER_LINE)*TILEY,
+      GAMETOON_FRAMES_4,
+      GAMETOON_FPS,
+      GAMETOON_STEPSIZE,
+      ANIM_NORMAL,
+      ANIMDIR_RIGHT,
+      ANIMPOS_DOWN
+    },
+    {
+      GAMETOON_XSIZE, GAMETOON_YSIZE,
+      ((GFX_SCHWEIN_LEFT - GFX_START_ROCKSHEROES) % HEROES_PER_LINE)*TILEX,
+      ((GFX_SCHWEIN_LEFT - GFX_START_ROCKSHEROES) / HEROES_PER_LINE)*TILEY,
+      GAMETOON_FRAMES_4,
+      GAMETOON_FPS,
+      GAMETOON_STEPSIZE,
+      ANIM_NORMAL,
+      ANIMDIR_LEFT,
+      ANIMPOS_DOWN
+    },
+    {
+      GAMETOON_XSIZE, GAMETOON_YSIZE,
+      ((GFX_SCHWEIN_RIGHT - GFX_START_ROCKSHEROES) % HEROES_PER_LINE)*TILEX,
+      ((GFX_SCHWEIN_RIGHT - GFX_START_ROCKSHEROES) / HEROES_PER_LINE)*TILEY,
+      GAMETOON_FRAMES_4,
+      GAMETOON_FPS,
+      GAMETOON_STEPSIZE,
+      ANIM_NORMAL,
+      ANIMDIR_RIGHT,
+      ANIMPOS_DOWN
+    },
+    {
+      GAMETOON_XSIZE, GAMETOON_YSIZE,
+      ((GFX_DRACHE_LEFT - GFX_START_ROCKSHEROES) % HEROES_PER_LINE)*TILEX,
+      ((GFX_DRACHE_LEFT - GFX_START_ROCKSHEROES) / HEROES_PER_LINE)*TILEY,
+      GAMETOON_FRAMES_4,
+      GAMETOON_FPS,
+      GAMETOON_STEPSIZE,
+      ANIM_NORMAL,
+      ANIMDIR_LEFT,
+      ANIMPOS_DOWN
+    },
+    {
+      GAMETOON_XSIZE, GAMETOON_YSIZE,
+      ((GFX_DRACHE_RIGHT - GFX_START_ROCKSHEROES) % HEROES_PER_LINE)*TILEX,
+      ((GFX_DRACHE_RIGHT - GFX_START_ROCKSHEROES) / HEROES_PER_LINE)*TILEY,
+      GAMETOON_FRAMES_4,
+      GAMETOON_FPS,
+      GAMETOON_STEPSIZE,
+      ANIM_NORMAL,
+      ANIMDIR_RIGHT,
+      ANIMPOS_DOWN
+    },
+    {
+      GAMETOON_XSIZE, GAMETOON_YSIZE,
+      ((GFX_SONDE - GFX_START_ROCKSHEROES) % HEROES_PER_LINE)*TILEX,
+      ((GFX_SONDE - GFX_START_ROCKSHEROES) / HEROES_PER_LINE)*TILEY,
+      GAMETOON_FRAMES_8,
+      GAMETOON_FPS,
+      GAMETOON_STEPSIZE,
+      ANIM_NORMAL,
+      ANIMDIR_LEFT,
+      ANIMPOS_ANY
+    },
+    {
+      GAMETOON_XSIZE, GAMETOON_YSIZE,
+      ((GFX_SONDE - GFX_START_ROCKSHEROES) % HEROES_PER_LINE)*TILEX,
+      ((GFX_SONDE - GFX_START_ROCKSHEROES) / HEROES_PER_LINE)*TILEY,
+      GAMETOON_FRAMES_8,
+      GAMETOON_FPS,
+      GAMETOON_STEPSIZE,
+      ANIM_NORMAL,
+      ANIMDIR_RIGHT,
+      ANIMPOS_ANY
+    },
+  };
+  struct AnimInfo *anim = &toon[toon_nr];
+  Pixmap anim_pixmap = (toon_nr < 6 ? pix[PIX_TOONS] : pix[PIX_HEROES]);
+  GC anim_clip_gc = (toon_nr < 6 ? clip_gc[PIX_TOONS] : clip_gc[PIX_HEROES]);
+
+  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 = SimpleRND((FULL_SYSIZE-anim->height)/2);
+      else
+       pos_y = SimpleRND(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 = SimpleRND(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(anim_pixmap,anim_clip_gc,
+              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(anim_pixmap,anim_clip_gc,
+          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(Pixmap toon_pixmap, GC toon_clip_gc,
+             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;
+
+#if 1
+  /* special method to avoid flickering interference with BackToFront() */
+  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,toon_clip_gc,dest_x-src_x,dest_y-src_y);
+  XCopyArea(display,toon_pixmap,backbuffer,toon_clip_gc,
+           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);
+#else
+  /* normal method, causing flickering interference with BackToFront() */
+  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,toon_clip_gc,
+                buf_x-src_x+pad_x,buf_y-src_y+pad_y);
+  XCopyArea(display,toon_pixmap,pix[PIX_DB_DOOR],toon_clip_gc,
+           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);
+#endif
+
+  XFlush(display);
+}
diff --git a/src/cartoons.h b/src/cartoons.h
new file mode 100644 (file)
index 0000000..25b4d2c
--- /dev/null
@@ -0,0 +1,22 @@
+/***********************************************************
+*  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             *
+*----------------------------------------------------------*
+*  cartoons.h                                              *
+***********************************************************/
+
+#ifndef CARTOONS_H
+#define CARTOONS_H
+
+void InitAnimation(void);
+void StopAnimation(void);
+void DoAnimation(void);
+
+#endif
index 871eafa..b5567df 100644 (file)
@@ -112,7 +112,7 @@ int editor_element[] =
   EL_MAMPFER,
   EL_KAEFER_O,
   EL_FLIEGER_O,
-  EL_ZOMBIE,
+  EL_ROBOT,
 
   EL_KAEFER_L,
   EL_FLIEGER_L,
@@ -159,6 +159,11 @@ int editor_element[] =
   EL_CHAR_A + ('R' - 'A'),
   EL_CHAR_A + ('E' - 'A'),
 
+  EL_PFEIL_L,
+  EL_PFEIL_R,
+  EL_PFEIL_O,
+  EL_PFEIL_U,
+
   EL_AMOEBE_VOLL,
   EL_EDELSTEIN_GELB,
   EL_EDELSTEIN_ROT,
@@ -189,6 +194,16 @@ int editor_element[] =
   EL_DYNABOMB_XL,
   EL_BADEWANNE,
 
+  EL_MAULWURF,
+  EL_PINGUIN,
+  EL_SCHWEIN,
+  EL_DRACHE,
+
+  EL_SONDE,
+  EL_LEERRAUM,
+  EL_LEERRAUM,
+  EL_LEERRAUM,
+
   EL_CHAR_A + ('S' - 'A'),
   EL_CHAR_A + ('O' - 'A'),
   EL_CHAR_A + ('K' - 'A'),
@@ -221,6 +236,11 @@ int editor_element[] =
   EL_CHAR_A + ('R' - 'A'),
 */
 
+  EL_LEERRAUM,
+  EL_LEERRAUM,
+  EL_LEERRAUM,
+  EL_LEERRAUM,
+
   EL_CHAR_AUSRUF,
   EL_CHAR_ZOLL,
   EL_CHAR_DOLLAR,
@@ -1188,7 +1208,7 @@ void LevelNameTyping(KeySym key)
                ED_COUNT_TEXT_YPOS+16*ED_COUNT_TEXT_YSIZE,
                "<",FS_SMALL,FC_RED);
   }
-  else if (key==XK_Delete && len>0)
+  else if ((key==XK_Delete || key==XK_BackSpace) && len>0)
   {
     level.name[len-1] = 0;
     len--;
index cbf6e1d..63856e5 100644 (file)
@@ -19,6 +19,7 @@
 #include "editor.h"
 #include "misc.h"
 #include "tape.h"
+#include "joystick.h"
 
 void EventLoop(void)
 {
@@ -39,8 +40,6 @@ void EventLoop(void)
          SleepWhileUnmapped();
          break;
        case ButtonPress:
-         HandleButtonEvent((XButtonEvent *) &event);
-         break;
        case ButtonRelease:
          HandleButtonEvent((XButtonEvent *) &event);
          break;
@@ -48,16 +47,12 @@ void EventLoop(void)
          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);
+         HandleFocusEvent((XFocusChangeEvent *) &event);
          break;
        default:
          break;
@@ -99,10 +94,8 @@ void ClearEventQueue()
        key_joystick_mapping = 0;
        break;
       case FocusIn:
-       HandleFocusEvent(FOCUS_IN);
-       break;
       case FocusOut:
-       HandleFocusEvent(FOCUS_OUT);
+       HandleFocusEvent((XFocusChangeEvent *) &event);
        break;
       default:
        break;
@@ -150,21 +143,25 @@ 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;
 
+    drawto_field = backbuffer;
+
     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);
+    DrawPlayerField();
+
+    drawto_field = window;
   }
 
+  XCopyArea(display,drawto,window,gc, x,y, width,height, x,y);
+
   XFlush(display);
 }
 
@@ -196,17 +193,17 @@ void HandleKeyEvent(XKeyEvent *event)
   HandleKey(key, key_status);
 }
 
-void HandleFocusEvent(int focus_status)
+void HandleFocusEvent(XFocusChangeEvent *event)
 {
   static int old_joystick_status = -1;
 
-  if (focus_status==FOCUS_OUT)
+  if (event->type == FocusOut)
   {
     XAutoRepeatOn(display);
     old_joystick_status = joystick_status;
     joystick_status = JOYSTICK_OFF;
   }
-  else
+  else if (event->type == FocusIn)
   {
     if (game_status == PLAYING)
       XAutoRepeatOff(display);
@@ -381,6 +378,14 @@ void HandleKey(KeySym key, int key_status)
   if (key_status == KEY_RELEASED)
     return;
 
+  if (key==XK_Return && game_status==PLAYING && GameOver)
+  {
+    CloseDoor(DOOR_CLOSE_1);
+    game_status = MAINMENU;
+    DrawMainMenu();
+    return;
+  }
+
   if (key==XK_Escape && game_status!=MAINMENU) /* quick quit to MAINMENU */
   {
     CloseDoor(DOOR_CLOSE_1 | DOOR_NO_DELAY);
@@ -568,6 +573,9 @@ void HandleJoystick()
   int dx       = (left ? -1    : right ? 1     : 0);
   int dy       = (up   ? -1    : down  ? 1     : 0);
 
+  if (game_status==PLAYING && (tape.playing || keyboard))
+    newbutton = ((joy & JOY_BUTTON) != 0);
+
   switch(game_status)
   {
     case MAINMENU:
@@ -577,7 +585,7 @@ void HandleJoystick()
       static long joystickmove_delay = 0;
 
       if (joystick && !button && !DelayReached(&joystickmove_delay,15))
-       break;
+       newbutton = dx = dy = 0;
 
       if (game_status==MAINMENU)
        HandleMainMenu(0,0,dx,dy,newbutton ? MB_MENU_CHOICE : MB_MENU_MARK);
@@ -597,16 +605,6 @@ void HandleJoystick()
     {
       BOOL moved = FALSE, snapped = FALSE, bombed = FALSE;
 
-      if (tape.pausing)
-       joy = 0;
-
-      if (!joy)
-      {
-       DigField(0,0,0,0,DF_NO_PUSH);
-       SnapField(0,0);
-       break;
-      }
-
       if (GameOver && newbutton)
       {
        CloseDoor(DOOR_CLOSE_1);
@@ -615,23 +613,61 @@ void HandleJoystick()
        return;
       }
 
-      if (button1)
-       snapped = SnapField(dx,dy);
+      if (tape.pausing || PlayerGone)
+       joy = 0;
+
+      if (joy)
+      {
+       if (button1)
+         snapped = SnapField(dx,dy);
+       else
+       {
+         if (button2)
+           bombed = PlaceBomb();
+         moved = MoveFigure(dx,dy);
+       }
+
+       if (tape.recording && (moved || snapped || bombed))
+       {
+         if (bombed && !moved)
+           joy &= JOY_BUTTON;
+         TapeRecordAction(joy);
+       }
+       else if (tape.playing && snapped)
+         SnapField(0,0);                       /* stop snapping */
+      }
       else
       {
-       if (button2)
-         bombed = PlaceBomb();
-       moved = MoveFigure(dx,dy);
+       DigField(0,0,0,0,DF_NO_PUSH);
+       SnapField(0,0);
+       PlayerFrame = 0;
       }
 
-      if (tape.recording && (moved || snapped || bombed))
+      if (tape.playing && !tape.pausing && !joy && tape.counter<tape.length)
       {
-       if (bombed && !moved)
-         joy &= JOY_BUTTON;
-       TapeRecordAction(joy);
+       int next_joy =
+         tape.pos[tape.counter].joystickdata & (JOY_LEFT|JOY_RIGHT);
+
+       if (next_joy == JOY_LEFT || next_joy == JOY_RIGHT)
+       {
+         int dx = (next_joy == JOY_LEFT ? -1 : +1);
+
+         if (IN_LEV_FIELD(JX+dx,JY) && IS_PUSHABLE(Feld[JX+dx][JY]))
+         {
+           int el = Feld[JX+dx][JY];
+           int push_delay = (IS_SB_ELEMENT(el) || el==EL_SONDE ? 2 : 10);
+
+           if (tape.delay_played + push_delay >= tape.pos[tape.counter].delay)
+           {
+             PlayerMovDir = next_joy;
+             PlayerFrame = FrameCounter % 4;
+             PlayerPushing = TRUE;
+           }
+         }
+       }
       }
-      else if (tape.playing && snapped)
-       SnapField(0,0);                 /* stop snapping */
+
+      DrawPlayerField();
 
       break;
     }
index 31948c1..700f8ae 100644 (file)
@@ -25,7 +25,7 @@ void HandleExposeEvent(XExposeEvent *);
 void HandleButtonEvent(XButtonEvent *);
 void HandleMotionEvent(XMotionEvent *);
 void HandleKeyEvent(XKeyEvent *);
-void HandleFocusEvent(int);
+void HandleFocusEvent(XFocusChangeEvent *);
 void HandleNoXEvent(void);
 
 void HandleButton(int, int, int);
index 1441cd0..bbd282a 100644 (file)
@@ -16,6 +16,7 @@
 #include "tools.h"
 #include "misc.h"
 #include "tape.h"
+#include "joystick.h"
 
 BOOL CreateNewScoreFile()
 {
index cda9257..e170331 100644 (file)
@@ -21,6 +21,7 @@
 #include "buttons.h"
 #include "files.h"
 #include "tape.h"
+#include "joystick.h"
 
 extern int Gamespeed;
 extern int Movemethod;
@@ -65,7 +66,7 @@ void InitGame()
 
   Dynamite = Score = 0;
   Gems = level.edelsteine;
-  SokobanFields = Lights = 0;
+  SokobanFields = Lights = Friends = 0;
   DynaBombCount = DynaBombSize = DynaBombsLeft = 0;
   DynaBombXL = FALSE;
   Key[0] = Key[1] = Key[2] = Key[3] = FALSE;
@@ -73,7 +74,10 @@ void InitGame()
   FrameCounter = 0;
   TimeFrames = 0;
   TimeLeft = level.time;
-  LevelSolved = GameOver = SiebAktiv = FALSE;
+  PlayerMovDir = MV_NO_MOVING;
+  PlayerFrame = 0;
+  PlayerPushing = FALSE;
+  PlayerGone = LevelSolved = GameOver = SiebAktiv = FALSE;
   JX = JY = 0;
   ZX = ZY = -1;
 
@@ -144,7 +148,7 @@ void InitGame()
       case EL_PACMAN_U:
       case EL_MAMPFER:
       case EL_MAMPFER2:
-      case EL_ZOMBIE:
+      case EL_ROBOT:
       case EL_PACMAN:
        InitMovDir(x,y);
        break;
@@ -168,6 +172,14 @@ void InitGame()
       case EL_SOKOBAN_FELD_LEER:
        SokobanFields++;
        break;
+      case EL_MAULWURF:
+      case EL_PINGUIN:
+       Friends++;
+       break;
+      case EL_SCHWEIN:
+      case EL_DRACHE:
+       MovDir[x][y] = 1<<RND(4);
+       break;
       default:
        break;
     }
@@ -371,8 +383,7 @@ void GameWon()
   FadeSounds();
 
   /* Hero disappears */
-  DrawLevelElement(JX,JY,Feld[JX][JY]);
-  JX = JY = -1;
+  DrawLevelElement(ExitX,ExitY,Feld[ExitX][ExitY]);
   BackToFront();
 
   if (tape.playing)
@@ -524,15 +535,15 @@ int MovingOrBlocked2Element(int x, int y)
 
 void RemoveMovingField(int x, int y)
 {
-  int oldx=x,oldy=y, newx=x,newy=y;
+  int oldx = x,oldy = y, newx = x,newy = y;
 
-  if (Feld[x][y]!=EL_BLOCKED && !IS_MOVING(x,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)
+    if (Feld[newx][newy] != EL_BLOCKED)
       return;
   }
   else if (Feld[x][y]==EL_BLOCKED)
@@ -542,52 +553,53 @@ void RemoveMovingField(int x, int y)
       return;
   }
 
-  Feld[oldx][oldy] = EL_LEERRAUM;
+  if (Feld[x][y]==EL_BLOCKED &&
+      (Store[oldx][oldy]==EL_MORAST_LEER ||
+       Store[oldx][oldy]==EL_SIEB_LEER ||
+       Store[oldx][oldy]==EL_SIEB2_LEER ||
+       Store[oldx][oldy]==EL_AMOEBE_NASS))
+  {
+    Feld[oldx][oldy] = Store[oldx][oldy];
+    Store[oldx][oldy] = Store2[oldx][oldy] = 0;
+  }
+  else
+    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)
 {
-  if (!IN_SCR_FIELD(SCROLLX(x),SCROLLY(y)))
+  int sx = SCROLLX(x), sy = SCROLLY(y);
+  int graphic = el2gfx(Feld[x][y]);
+  int phase;
+
+  if (!IN_SCR_FIELD(sx,sy) || IS_PLAYER(x,y))
     return;
 
   if (Store[x][y])
-  {
-    DrawGraphic(SCROLLX(x),SCROLLY(y),el2gfx(Store[x][y]));
-    if (IS_PLAYER(x,y))
-      DrawGraphicThruMask(SCROLLX(JX),SCROLLY(JY),GFX_SPIELFIGUR);
-  }
-  else if (IS_PLAYER(x,y))
-    DrawGraphic(SCROLLX(JX),SCROLLY(JY),GFX_SPIELFIGUR);
+    DrawGraphic(sx,sy, el2gfx(Store[x][y]));
 
   if (Feld[x][y]==EL_DYNAMIT)
   {
-    int phase = (48-MovDelay[x][y])/6;
-
-    if (phase>6)
+    if ((phase = (48-MovDelay[x][y])/6) > 6)
       phase = 6;
-
-    if (Store[x][y] || IS_PLAYER(x,y))
-      DrawGraphicThruMask(SCROLLX(x),SCROLLY(y),GFX_DYNAMIT+phase);
-    else
-      DrawGraphic(SCROLLX(x),SCROLLY(y),GFX_DYNAMIT+phase);
   }
   else
   {
-    int phase = ((48-MovDelay[x][y])/3) % 8;
-
-    if (phase>3)
+    if ((phase = ((48-MovDelay[x][y])/3) % 8) > 3)
       phase = 7-phase;
-
-    if (Store[x][y] || IS_PLAYER(x,y))
-      DrawGraphicThruMask(SCROLLX(x),SCROLLY(y),GFX_DYNABOMB+phase);
-    else
-      DrawGraphic(SCROLLX(x),SCROLLY(y),GFX_DYNABOMB+phase);
   }
+
+  if (Store[x][y])
+    DrawGraphicThruMask(sx,sy, graphic + phase);
+  else
+    DrawGraphic(sx,sy, graphic + phase);
 }
 
 void CheckDynamite(int x, int y)
@@ -624,14 +636,23 @@ void Explode(int ex, int ey, int phase, int mode)
   {
     int center_element = Feld[ex][ey];
 
-    if (center_element==EL_BLOCKED)
+    if (IS_MOVING(ex,ey) || IS_BLOCKED(ex,ey))
+    {
       center_element = MovingOrBlocked2Element(ex,ey);
+      RemoveMovingField(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))
+      if (IS_MOVING(x,y) || IS_BLOCKED(x,y))
+      {
+       element = MovingOrBlocked2Element(x,y);
+       RemoveMovingField(x,y);
+      }
+
+      if (!IN_LEV_FIELD(x,y) || IS_MASSIV(element) || element==EL_BURNING)
        continue;
 
       if ((mode!=EX_NORMAL || center_element==EL_AMOEBA2DIAM) &&
@@ -643,6 +664,10 @@ void Explode(int ex, int ey, int phase, int mode)
 
       if (IS_PLAYER(ex,ey))
        Store[x][y] = EL_EDELSTEIN_GELB;
+      else if (center_element==EL_MAULWURF)
+       Store[x][y] = EL_EDELSTEIN_ROT;
+      else if (center_element==EL_PINGUIN)
+       Store[x][y] = EL_EDELSTEIN_LILA;
       else if (center_element==EL_KAEFER)
        Store[x][y] = ((x==ex && y==ey) ? EL_DIAMANT : EL_EDELSTEIN);
       else if (center_element==EL_BUTTERFLY)
@@ -678,7 +703,6 @@ void Explode(int ex, int ey, int phase, int mode)
        AmoebaCnt2[AmoebaNr[x][y]]--;
       }
 
-      RemoveMovingField(x,y);
       Feld[x][y] = EL_EXPLODING;
       MovDir[x][y] = MovPos[x][y] = 0;
       AmoebaNr[x][y] = 0;
@@ -706,14 +730,7 @@ void Explode(int ex, int ey, int phase, int mode)
 
     if (IS_PLAYER(x,y))
       KillHero();
-    else if (element==EL_BOMBE ||
-            element==EL_DYNAMIT ||
-            element==EL_DYNAMIT_AUS ||
-            element==EL_DYNABOMB ||
-            element==EL_DYNABOMB_NR ||
-            element==EL_DYNABOMB_SZ ||
-            element==EL_DYNABOMB_XL ||
-            element==EL_KAEFER)
+    else if (IS_EXPLOSIVE(element))
     {
       Feld[x][y] = Store2[x][y];
       Store2[x][y] = 0;
@@ -795,7 +812,7 @@ void Bang(int x, int y)
     case EL_FIREFLY:
     case EL_MAMPFER:
     case EL_MAMPFER2:
-    case EL_ZOMBIE:
+    case EL_ROBOT:
     case EL_PACMAN:
       RaiseScoreElement(element);
       Explode(x,y,0,EX_NORMAL);
@@ -863,15 +880,20 @@ void Impact(int x, int y)
   BOOL lastline = (y==lev_fieldy-1);
   BOOL object_hit = FALSE;
   int element = Feld[x][y];
+  int smashed = 0;
 
   /* 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));
+    if (object_hit)
+      smashed = MovingOrBlocked2Element(x,y+1);
+  }
 
   /* Auftreffendes Element fällt in Salzsäure */
-  if (!lastline && Feld[x][y+1]==EL_SALZSAEURE)
+  if (!lastline && smashed==EL_SALZSAEURE)
   {
     Blurb(x,y);
     return;
@@ -889,6 +911,8 @@ void Impact(int x, int y)
   {
     if (object_hit && IS_PLAYER(x,y+1))
       KillHero();
+    else if (object_hit && (smashed==EL_MAULWURF || smashed==EL_PINGUIN))
+      Bang(x,y+1);
     else
     {
       Feld[x][y] = EL_AMOEBING;
@@ -900,8 +924,6 @@ void Impact(int x, int y)
   /* Welches Element kriegt was auf die Rübe? */
   if (!lastline && object_hit)
   {
-    int smashed = MovingOrBlocked2Element(x,y+1);
-
     if (CAN_CHANGE(element) && 
        (smashed==EL_SIEB_LEER || smashed==EL_SIEB2_LEER) && !SiebAktiv)
       SiebAktiv = level.dauer_sieb * FRAMES_PER_SECOND;
@@ -911,6 +933,11 @@ void Impact(int x, int y)
       KillHero();
       return;
     }
+    else if (smashed==EL_MAULWURF || smashed==EL_PINGUIN)
+    {
+      Bang(x,y+1);
+      return;
+    }
     else if (element==EL_EDELSTEIN_BD)
     {
       if (IS_ENEMY(smashed) && IS_BD_ELEMENT(smashed))
@@ -921,15 +948,15 @@ void Impact(int x, int y)
     }
     else if (element==EL_FELSBROCKEN)
     {
-      if (IS_ENEMY(smashed))
+      if (IS_ENEMY(smashed) || smashed==EL_BOMBE || smashed==EL_SONDE ||
+         smashed==EL_SCHWEIN || smashed==EL_DRACHE)
       {
        Bang(x,y+1);
        return;
       }
       else if (!IS_MOVING(x,y+1))
       {
-       if (smashed==EL_BOMBE ||
-           smashed==EL_BIRNE_AUS || smashed==EL_BIRNE_EIN)
+       if (smashed==EL_BIRNE_AUS || smashed==EL_BIRNE_EIN)
        {
          Bang(x,y+1);
          return;
@@ -1038,6 +1065,7 @@ void TurnRound(int x, int y)
   int left_dx = move_xy[left_dir].x, left_dy = move_xy[left_dir].y;
   int right_dx = move_xy[right_dir].x, right_dy = move_xy[right_dir].y;
   int move_dx = move_xy[old_move_dir].x, move_dy = move_xy[old_move_dir].y;
+  int back_dx = move_xy[back_dir].x, back_dy = move_xy[back_dir].y;
 
   int left_x = x+left_dx, left_y = y+left_dy;
   int right_x = x+right_dx, right_y = y+right_dy;
@@ -1147,17 +1175,150 @@ void TurnRound(int x, int y)
 
     MovDelay[x][y] = 3+RND(20);
   }
-  else if (element==EL_ZOMBIE)
+  else if (element==EL_SCHWEIN)
+  {
+    BOOL can_turn_left = FALSE, can_turn_right = FALSE, can_move_on = FALSE;
+    BOOL should_turn_left = FALSE, should_turn_right = FALSE;
+    BOOL should_move_on = FALSE;
+    int rnd_value = 24;
+    int rnd = RND(rnd_value);
+
+    if (IN_LEV_FIELD(left_x,left_y) &&
+       (IS_FREE(left_x,left_y) || IS_GEM(Feld[left_x][left_y])))
+      can_turn_left = TRUE;
+    if (IN_LEV_FIELD(right_x,right_y) &&
+       (IS_FREE(right_x,right_y) || IS_GEM(Feld[right_x][right_y])))
+      can_turn_right = TRUE;
+    if (IN_LEV_FIELD(move_x,move_y) &&
+       (IS_FREE(move_x,move_y) || IS_GEM(Feld[move_x][move_y])))
+      can_move_on = TRUE;
+
+    if (can_turn_left &&
+       (!can_move_on ||
+        (IN_LEV_FIELD(x+back_dx+left_dx,y+back_dy+left_dy) &&
+         !IS_FREE(x+back_dx+left_dx,y+back_dy+left_dy))))
+      should_turn_left = TRUE;
+    if (can_turn_right &&
+       (!can_move_on ||
+        (IN_LEV_FIELD(x+back_dx+right_dx,y+back_dy+right_dy) &&
+         !IS_FREE(x+back_dx+right_dx,y+back_dy+right_dy))))
+      should_turn_right = TRUE;
+    if (can_move_on &&
+       (!can_turn_left || !can_turn_right ||
+        (IN_LEV_FIELD(x+move_dx+left_dx,y+move_dy+left_dy) &&
+         !IS_FREE(x+move_dx+left_dx,y+move_dy+left_dy)) ||
+        (IN_LEV_FIELD(x+move_dx+right_dx,y+move_dy+right_dy) &&
+         !IS_FREE(x+move_dx+right_dx,y+move_dy+right_dy))))
+      should_move_on = TRUE;
+
+    if (should_turn_left || should_turn_right || should_move_on)
+    {
+      if (should_turn_left && should_turn_right && should_move_on)
+       MovDir[x][y] = (rnd < rnd_value/3 ? left_dir :
+                       rnd < 2*rnd_value/3 ? right_dir :
+                       old_move_dir);
+      else if (should_turn_left && should_turn_right)
+       MovDir[x][y] = (rnd < rnd_value/2 ? left_dir : right_dir);
+      else if (should_turn_left && should_move_on)
+       MovDir[x][y] = (rnd < rnd_value/2 ? left_dir : old_move_dir);
+      else if (should_turn_right && should_move_on)
+       MovDir[x][y] = (rnd < rnd_value/2 ? right_dir : old_move_dir);
+      else if (should_turn_left)
+       MovDir[x][y] = left_dir;
+      else if (should_turn_right)
+       MovDir[x][y] = right_dir;
+      else if (should_move_on)
+       MovDir[x][y] = old_move_dir;
+    }
+    else if (can_move_on && rnd > rnd_value/8)
+      MovDir[x][y] = old_move_dir;
+    else if (can_turn_left && can_turn_right)
+      MovDir[x][y] = (rnd < rnd_value/2 ? left_dir : right_dir);
+    else if (can_turn_left && rnd > rnd_value/8)
+      MovDir[x][y] = left_dir;
+    else if (can_turn_right && rnd > rnd_value/8)
+      MovDir[x][y] = right_dir;
+    else
+      MovDir[x][y] = back_dir;
+
+    if (!IS_FREE(x+move_xy[MovDir[x][y]].x,y+move_xy[MovDir[x][y]].y) &&
+       !IS_GEM(Feld[x+move_xy[MovDir[x][y]].x][y+move_xy[MovDir[x][y]].y]))
+      MovDir[x][y] = old_move_dir;
+
+    MovDelay[x][y] = 0;
+  }
+  else if (element==EL_DRACHE)
+  {
+    BOOL can_turn_left = FALSE, can_turn_right = FALSE, can_move_on = FALSE;
+    int rnd_value = 24;
+    int rnd = RND(rnd_value);
+
+    if (IN_LEV_FIELD(left_x,left_y) && IS_FREE(left_x,left_y))
+      can_turn_left = TRUE;
+    if (IN_LEV_FIELD(right_x,right_y) && IS_FREE(right_x,right_y))
+      can_turn_right = TRUE;
+    if (IN_LEV_FIELD(move_x,move_y) && IS_FREE(move_x,move_y))
+      can_move_on = TRUE;
+
+    if (can_move_on && rnd > rnd_value/8)
+      MovDir[x][y] = old_move_dir;
+    else if (can_turn_left && can_turn_right)
+      MovDir[x][y] = (rnd < rnd_value/2 ? left_dir : right_dir);
+    else if (can_turn_left && rnd > rnd_value/8)
+      MovDir[x][y] = left_dir;
+    else if (can_turn_right && rnd > rnd_value/8)
+      MovDir[x][y] = right_dir;
+    else
+      MovDir[x][y] = back_dir;
+
+    if (!IS_FREE(x+move_xy[MovDir[x][y]].x,y+move_xy[MovDir[x][y]].y))
+      MovDir[x][y] = old_move_dir;
+
+    MovDelay[x][y] = 0;
+  }
+  else if (element==EL_ROBOT || element==EL_SONDE ||
+          element==EL_MAULWURF || element==EL_PINGUIN)
   {
     int attr_x = JX, attr_y = JY;
     int newx, newy;
 
-    if (ZX>=0 && ZY>=0)
+    if (PlayerGone)
+    {
+      attr_x = ExitX;
+      attr_y = ExitY;
+    }
+
+    if (element==EL_ROBOT && ZX>=0 && ZY>=0)
     {
       attr_x = ZX;
       attr_y = ZY;
     }
 
+    if (element==EL_MAULWURF || element==EL_PINGUIN)
+    {
+      int i;
+      static int xy[4][2] =
+      {
+       { 0,-1 },
+       { -1,0 },
+       { +1,0 },
+       { 0,+1 }
+      };
+
+      for(i=0;i<4;i++)
+      {
+       int ex = x+xy[i%4][0];
+       int ey = y+xy[i%4][1];
+
+       if (IN_LEV_FIELD(ex,ey) && Feld[ex][ey] == EL_AUSGANG_AUF)
+       {
+         attr_x = ex;
+         attr_y = ey;
+         break;
+       }
+      }
+    }
+
     MovDir[x][y] = MV_NO_MOVING;
     if (attr_x<x)
       MovDir[x][y] |= (GameOver ? MV_RIGHT : MV_LEFT);
@@ -1167,14 +1328,55 @@ void TurnRound(int x, int y)
       MovDir[x][y] |= (GameOver ? MV_DOWN : MV_UP);
     else if (attr_y>y)
       MovDir[x][y] |= (GameOver ? MV_UP : 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));
 
-    Moving2Blocked(x,y,&newx,&newy);
-    if (IN_LEV_FIELD(newx,newy) && IS_FREE_OR_PLAYER(newx,newy))
-      MovDelay[x][y] = 4+4*!RND(3);
+    if (element==EL_ROBOT)
+    {
+      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));
+      Moving2Blocked(x,y,&newx,&newy);
+
+      if (IN_LEV_FIELD(newx,newy) && IS_FREE_OR_PLAYER(newx,newy))
+       MovDelay[x][y] = 4+4*!RND(3);
+      else
+       MovDelay[x][y] = 8;
+    }
     else
-      MovDelay[x][y] = 8;
+    {
+      MovDelay[x][y] = 1;
+
+      if ((MovDir[x][y]&(MV_LEFT|MV_RIGHT)) && (MovDir[x][y]&(MV_UP|MV_DOWN)))
+      {
+       BOOL first_horiz = RND(2);
+       int new_move_dir = MovDir[x][y];
+
+       MovDir[x][y] =
+         new_move_dir & (first_horiz ? (MV_LEFT|MV_RIGHT) : (MV_UP|MV_DOWN));
+       Moving2Blocked(x,y,&newx,&newy);
+
+       if (IN_LEV_FIELD(newx,newy) &&
+           (IS_FREE(newx,newy) ||
+            Feld[newx][newy] == EL_SALZSAEURE ||
+            ((element == EL_MAULWURF || element==EL_PINGUIN) &&
+             (Feld[newx][newy] == EL_AUSGANG_AUF ||
+              IS_MAMPF3(Feld[newx][newy])))))
+         return;
+
+       MovDir[x][y] =
+         new_move_dir & (!first_horiz ? (MV_LEFT|MV_RIGHT) : (MV_UP|MV_DOWN));
+       Moving2Blocked(x,y,&newx,&newy);
+
+       if (IN_LEV_FIELD(newx,newy) &&
+           (IS_FREE(newx,newy) ||
+            Feld[newx][newy] == EL_SALZSAEURE ||
+            ((element == EL_MAULWURF || element==EL_PINGUIN) &&
+             (Feld[newx][newy] == EL_AUSGANG_AUF ||
+              IS_MAMPF3(Feld[newx][newy])))))
+         return;
+
+       MovDir[x][y] = old_move_dir;
+       return;
+      }
+    }
   }
 }
 
@@ -1224,6 +1426,23 @@ void StartMoving(int x, int y)
        Feld[x][y] = EL_CHANGED(Store2[x][y]);
        Store[x][y] = EL_SIEB_LEER;
       }
+      else if (Feld[x][y+1]==EL_SIEB_LEER)
+      {
+       if (!MovDelay[x][y])
+         MovDelay[x][y] = 2;
+
+       if (MovDelay[x][y])
+       {
+         MovDelay[x][y]--;
+         if (MovDelay[x][y])
+           return;
+       }
+
+       Feld[x][y] = EL_SIEB_LEER;
+       Feld[x][y+1] = EL_SIEB_VOLL;
+       Store2[x][y+1] = EL_CHANGED(Store2[x][y]);
+       Store2[x][y] = 0;
+      }
     }
     else if (element==EL_SIEB2_VOLL)
     {
@@ -1233,6 +1452,23 @@ void StartMoving(int x, int y)
        Feld[x][y] = EL_CHANGED2(Store2[x][y]);
        Store[x][y] = EL_SIEB2_LEER;
       }
+      else if (Feld[x][y+1]==EL_SIEB2_LEER)
+      {
+       if (!MovDelay[x][y])
+         MovDelay[x][y] = 2;
+
+       if (MovDelay[x][y])
+       {
+         MovDelay[x][y]--;
+         if (MovDelay[x][y])
+           return;
+       }
+
+       Feld[x][y] = EL_SIEB2_LEER;
+       Feld[x][y+1] = EL_SIEB2_VOLL;
+       Store2[x][y+1] = EL_CHANGED2(Store2[x][y]);
+       Store2[x][y] = 0;
+      }
     }
     else if (SiebAktiv && CAN_CHANGE(element) &&
             (Feld[x][y+1]==EL_SIEB_LEER || Feld[x][y+1]==EL_SIEB2_LEER))
@@ -1283,8 +1519,11 @@ void StartMoving(int x, int y)
 
     if (!MovDelay[x][y])       /* neuer Schritt / noch nicht gewartet */
     {
-      if (element==EL_ZOMBIE || element==EL_KAEFER || element==EL_FLIEGER ||
-         element==EL_BUTTERFLY || element==EL_FIREFLY)
+      /* Alle Figuren, die nach jeden Schritt die Richtung wechseln können.
+       * (MAMPFER, MAMPFER2 und PACMAN laufen bis zur nächsten Wand.)
+       */
+
+      if (element!=EL_MAMPFER && element!=EL_MAMPFER2 && element!=EL_PACMAN)
       {
        TurnRound(x,y);
        if (MovDelay[x][y] && (element == EL_KAEFER || element == EL_FLIEGER))
@@ -1296,7 +1535,7 @@ void StartMoving(int x, int y)
     {
       MovDelay[x][y]--;
 
-      if (element==EL_ZOMBIE || element==EL_MAMPFER || element==EL_MAMPFER2)
+      if (element==EL_ROBOT || element==EL_MAMPFER || element==EL_MAMPFER2)
       {
        int phase = MovDelay[x][y] % 8;
 
@@ -1310,12 +1549,47 @@ void StartMoving(int x, int y)
            && MovDelay[x][y]%4==3)
          PlaySoundLevel(x,y,SND_NJAM);
       }
-      else if (element==EL_BUTTERFLY || element==EL_FIREFLY)
+      else if (element==EL_DRACHE)
       {
-       int phase = (FrameCounter % 4) / 2;
+       int i;
+       int dir = MovDir[x][y];
+       int dx = (dir == MV_LEFT ? -1 : dir == MV_RIGHT ? +1 : 0);
+       int dy = (dir == MV_UP   ? -1 : dir == MV_DOWN  ? +1 : 0);
+       int graphic = (dir == MV_LEFT   ? GFX_FLAMMEN_LEFT :
+                      dir == MV_RIGHT  ? GFX_FLAMMEN_RIGHT :
+                      dir == MV_UP     ? GFX_FLAMMEN_UP :
+                      dir == MV_DOWN   ? GFX_FLAMMEN_DOWN : GFX_LEERRAUM);
+       int phase = FrameCounter % 2;
+
+       for(i=1;i<=3;i++)
+       {
+         int xx = x + i*dx, yy = y + i*dy;
+         int sx = SCROLLX(xx), sy = SCROLLY(yy);
 
-       if (IN_SCR_FIELD(SCROLLX(x),SCROLLY(y)))
-         DrawGraphic(SCROLLX(x),SCROLLY(y), el2gfx(element)+phase);
+         if (!IN_LEV_FIELD(xx,yy) ||
+             IS_SOLID(Feld[xx][yy]) || Feld[xx][yy]==EL_EXPLODING)
+           break;
+
+         if (MovDelay[x][y])
+         {
+           int flamed = MovingOrBlocked2Element(xx,yy);
+
+           if (IS_ENEMY(flamed) || IS_EXPLOSIVE(flamed))
+             Bang(xx,yy);
+           else
+             RemoveMovingField(xx,yy);
+
+           Feld[xx][yy] = EL_BURNING;
+           if (IN_SCR_FIELD(sx,sy))
+             DrawGraphic(sx,sy, graphic + phase*3 + i-1);
+         }
+         else
+         {
+           if (Feld[xx][yy] == EL_BURNING)
+             Feld[xx][yy] = EL_LEERRAUM;
+           DrawLevelField(xx,yy);
+         }
+       }
       }
 
       if (MovDelay[x][y])
@@ -1335,12 +1609,116 @@ void StartMoving(int x, int y)
 
     Moving2Blocked(x,y,&newx,&newy);   /* wohin soll's gehen? */
 
-    if (IS_PLAYER(newx,newy))          /* Spieler erwischt */
+    if (IS_ENEMY(element) && IS_PLAYER(newx,newy))
     {
+      /* Spieler erwischt */
       MovDir[x][y] = 0;
       KillHero();
       return;
     }
+    else if ((element == EL_MAULWURF || element == EL_PINGUIN ||
+             element==EL_ROBOT || element==EL_SONDE) &&
+            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 ((element == EL_MAULWURF || element == EL_PINGUIN) &&
+            IN_LEV_FIELD(newx,newy))
+    {
+      if (Feld[newx][newy] == EL_AUSGANG_AUF)
+      {
+       Feld[x][y] = EL_LEERRAUM;
+       DrawLevelField(x,y);
+
+       PlaySoundLevel(newx,newy,SND_BUING);
+       if (IN_SCR_FIELD(SCROLLX(newx),SCROLLY(newy)))
+         DrawGraphicThruMask(SCROLLX(newx),SCROLLY(newy),el2gfx(element));
+
+       Friends--;
+       if (!Friends && PlayerGone && !GameOver)
+         LevelSolved = GameOver = TRUE;
+
+       return;
+      }
+      else if (IS_MAMPF3(Feld[newx][newy]))
+      {
+       if (DigField(newx,newy, 0,0, DF_DIG) == MF_MOVING)
+         DrawLevelField(newx,newy);
+       else
+         MovDir[x][y] = MV_NO_MOVING;
+      }
+      else if (!IS_FREE(newx,newy))
+      {
+       if (IS_PLAYER(x,y))
+         DrawPlayerField();
+       else
+         DrawLevelField(x,y);
+       return;
+      }
+    }
+    else if (element == EL_SCHWEIN && IN_LEV_FIELD(newx,newy))
+    {
+      if (IS_GEM(Feld[newx][newy]))
+      {
+       if (IS_MOVING(newx,newy))
+         RemoveMovingField(newx,newy);
+       else
+       {
+         Feld[newx][newy] = EL_LEERRAUM;
+         DrawLevelField(newx,newy);
+       }
+      }
+      else if (!IS_FREE(newx,newy))
+      {
+       if (IS_PLAYER(x,y))
+         DrawPlayerField();
+       else
+         DrawLevelField(x,y);
+       return;
+      }
+    }
+    else if (element==EL_DRACHE && IN_LEV_FIELD(newx,newy))
+    {
+      if (!IS_FREE(newx,newy))
+      {
+       if (IS_PLAYER(x,y))
+         DrawPlayerField();
+       else
+         DrawLevelField(x,y);
+       return;
+      }
+      else
+      {
+       BOOL wanna_flame = !RND(10);
+       int dx = newx - x, dy = newy - y;
+       int newx1 = newx+1*dx, newy1 = newy+1*dy;
+       int newx2 = newx+2*dx, newy2 = newy+2*dy;
+       int element1 = (IN_LEV_FIELD(newx1,newy1) ?
+                       MovingOrBlocked2Element(newx1,newy1) : EL_BETON);
+       int element2 = (IN_LEV_FIELD(newx2,newy2) ?
+                       MovingOrBlocked2Element(newx2,newy2) : EL_BETON);
+
+       if ((wanna_flame || IS_ENEMY(element1) || IS_ENEMY(element2)) &&
+           element1 != EL_DRACHE && element2 != EL_DRACHE &&
+           element1 != EL_BURNING && element2 != EL_BURNING)
+       {
+         if (IS_PLAYER(x,y))
+           DrawPlayerField();
+         else
+           DrawLevelField(x,y);
+
+         MovDelay[x][y] = 25;
+         Feld[newx][newy] = EL_BURNING;
+         if (IN_LEV_FIELD(newx1,newy1) && Feld[newx1][newy1] == EL_LEERRAUM)
+           Feld[newx1][newy1] = EL_BURNING;
+         if (IN_LEV_FIELD(newx2,newy2) && Feld[newx2][newy2] == EL_LEERRAUM)
+           Feld[newx2][newy2] = EL_BURNING;
+         return;
+       }
+      }
+    }
     else if (element==EL_MAMPFER && IN_LEV_FIELD(newx,newy) &&
             Feld[newx][newy]==EL_DIAMANT)
     {
@@ -1383,21 +1761,21 @@ void StartMoving(int x, int y)
       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);
-      if (MovDelay[x][y] && (element == EL_KAEFER || element == EL_FLIEGER))
+
+      if (element == EL_KAEFER || element == EL_FLIEGER)
        DrawLevelField(x,y);
+      else if (element == EL_BUTTERFLY || element == EL_FIREFLY)
+       DrawGraphicAnimation(x,y, el2gfx(element), 2, 2, ANIM_NORMAL);
+      else if (element==EL_SONDE)
+       DrawGraphicAnimation(x,y, GFX_SONDE_START, 8, 1, ANIM_NORMAL);
+
       return;
     }
 
-    if (element==EL_ZOMBIE)
+    if (element==EL_ROBOT && IN_SCR_FIELD(x,y))
       PlaySoundLevel(x,y,SND_SCHLURF);
 
     InitMovingField(x,y,MovDir[x][y]);
@@ -1489,8 +1867,11 @@ void ContinueMoving(int x, int y)
     if (DONT_TOUCH(element))   /* Käfer oder Flieger */
     {
       TestIfBadThingHitsHero();
+      TestIfBadThingHitsFriend(newx,newy);
       TestIfBadThingHitsOtherBadThing(newx,newy);
     }
+    else if (element == EL_PINGUIN)
+      TestIfFriendHitsBadThing(newx,newy);
 
     if (CAN_SMASH(element) && direction==MV_DOWN &&
        (newy==lev_fieldy-1 || !IS_FREE(x,newy+1)))
@@ -1938,17 +2319,9 @@ void NussKnacken(int x, int y)
 
 void SiebAktivieren(int x, int y, int typ)
 {
-  if (SiebAktiv>1)
-  {
-    if (SiebAktiv%2 && IN_SCR_FIELD(SCROLLX(x),SCROLLY(y)))
-      DrawGraphic(SCROLLX(x),SCROLLY(y),
-                 (typ==1 ? GFX_SIEB_VOLL : GFX_SIEB2_VOLL)+3-(SiebAktiv%8)/2);
-  }
-  else
-  {
-    Feld[x][y] = (typ==1 ? EL_SIEB_TOT : EL_SIEB2_TOT);
-    DrawLevelField(x,y);
-  }
+  if (SiebAktiv%2 && IN_SCR_FIELD(SCROLLX(x),SCROLLY(y)))
+    DrawGraphic(SCROLLX(x),SCROLLY(y),
+               (typ==1 ? GFX_SIEB_VOLL : GFX_SIEB2_VOLL)+3-(SiebAktiv%8)/2);
 }
 
 void AusgangstuerPruefen(int x, int y)
@@ -2126,6 +2499,55 @@ void MauerAbleger(int ax, int ay)
     Feld[ax][ay] = EL_MAUERWERK;
 }
 
+void CheckForDragon(int x, int y)
+{
+  int i,j;
+  BOOL dragon_found = FALSE;
+  static int xy[4][2] =
+  {
+    { 0,-1 },
+    { -1,0 },
+    { +1,0 },
+    { 0,+1 }
+  };
+
+  for(i=0;i<4;i++)
+  {
+    for(j=0;j<4;j++)
+    {
+      int xx = x + j*xy[i][0], yy = y + j*xy[i][1];
+
+      if (IN_LEV_FIELD(xx,yy) &&
+         (Feld[xx][yy] == EL_BURNING || Feld[xx][yy] == EL_DRACHE))
+      {
+       if (Feld[xx][yy] == EL_DRACHE)
+         dragon_found = TRUE;
+      }
+      else
+       break;
+    }
+  }
+
+  if (!dragon_found)
+  {
+    for(i=0;i<4;i++)
+    {
+      for(j=0;j<3;j++)
+      {
+       int xx = x + j*xy[i][0], yy = y + j*xy[i][1];
+  
+       if (IN_LEV_FIELD(xx,yy) && Feld[xx][yy] == EL_BURNING)
+       {
+         Feld[xx][yy] = EL_LEERRAUM;
+         DrawLevelField(xx,yy);
+       }
+       else
+         break;
+      }
+    }
+  }
+}
+
 void GameActions()
 {
   static long action_delay=0;
@@ -2147,19 +2569,36 @@ void GameActions()
     int x,y,element;
     int sieb_x = 0, sieb_y = 0;
 
-    FrameCounter++;
-    TimeFrames++;
-
     if (tape.pausing || (tape.playing && !TapePlayDelay()))
       return;
     else if (tape.recording)
       TapeRecordDelay();
 
+    FrameCounter++;
+    TimeFrames++;
+
     for(y=0;y<lev_fieldy;y++) for(x=0;x<lev_fieldx;x++)
     {
       Stop[x][y] = FALSE;
       if (JustHit[x][y]>0)
        JustHit[x][y]--;
+
+#if DEBUG
+      if (IS_BLOCKED(x,y))
+      {
+       int oldx,oldy;
+
+       Blocked2Moving(x,y,&oldx,&oldy);
+       if (!IS_MOVING(oldx,oldy))
+       {
+         printf("GameActions(): (BLOCKED=>MOVING) context corrupted!\n");
+         printf("GameActions(): BLOCKED: x = %d, y = %d\n",x,y);
+         printf("GameActions(): !MOVING: oldx = %d, oldy = %d\n",oldx,oldy);
+         printf("GameActions(): This should never happen!\n");
+       }
+      }
+#endif
+
     }
 
     for(y=0;y<lev_fieldy;y++) for(x=0;x<lev_fieldx;x++)
@@ -2169,11 +2608,6 @@ void GameActions()
       if (IS_INACTIVE(element))
        continue;
 
-/*
-      if (element==EL_LEERRAUM || element==EL_ERDREICH)
-       continue;
-*/
-
       if (!IS_MOVING(x,y) && (CAN_FALL(element) || CAN_MOVE(element)))
       {
        StartMoving(x,y);
@@ -2211,6 +2645,8 @@ void GameActions()
        MauerWaechst(x,y);
       else if (element==EL_MAUER_LEBT)
        MauerAbleger(x,y);
+      else if (element==EL_BURNING)
+       CheckForDragon(x,y);
 
       if (SiebAktiv)
       {
@@ -2242,6 +2678,23 @@ void GameActions()
       if (!(SiebAktiv%4))
        PlaySoundLevel(sieb_x,sieb_y,SND_MIEP);
       SiebAktiv--;
+      if (!SiebAktiv)
+      {
+       for(y=0;y<lev_fieldy;y++) for(x=0;x<lev_fieldx;x++)
+       {
+         element = Feld[x][y];
+         if (element==EL_SIEB_LEER || element==EL_SIEB_VOLL)
+         {
+           Feld[x][y] = EL_SIEB_TOT;
+           DrawLevelField(x,y);
+         }
+         else if (element==EL_SIEB2_LEER || element==EL_SIEB2_VOLL)
+         {
+           Feld[x][y] = EL_SIEB2_TOT;
+           DrawLevelField(x,y);
+         }
+       }
+      }
     }
   }
 
@@ -2276,14 +2729,14 @@ void ScrollLevel(int dx, int dy)
 
   if (dx)
   {
-    x = dx==1 ? 0 : SCR_FIELDX-1;
+    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++)
+    y = (dy==1 ? 0 : SCR_FIELDY-1);
+    for(x=0;x<SCR_FIELDX;x++)
       DrawScreenField(x,y);
   }
 
@@ -2296,8 +2749,24 @@ BOOL MoveFigureOneStep(int dx, int dy, int real_dx, int real_dy)
   int element;
   int can_move;
 
-  if (GameOver || (!dx && !dy))
+/*
+  int old_move_dir = PlayerMovDir;
+*/
+
+  if (PlayerGone || (!dx && !dy))
     return(MF_NO_ACTION);
+
+  PlayerMovDir = (dx < 0 ? MV_LEFT :
+                 dx > 0 ? MV_RIGHT :
+                 dy < 0 ? MV_UP :
+                 dy > 0 ? MV_DOWN :    MV_NO_MOVING);
+/*
+  if (old_move_dir != PlayerMovDir)
+    PlayerFrame = 0;
+  else
+    PlayerFrame = (PlayerFrame + 1) % 4;
+*/
+
   if (!IN_LEV_FIELD(newJX,newJY))
     return(MF_NO_ACTION);
 
@@ -2312,11 +2781,7 @@ BOOL MoveFigureOneStep(int dx, int dy, int real_dx, int real_dy)
       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;
+      BuryHero();
     }
     else
       KillHero();
@@ -2351,8 +2816,9 @@ BOOL MoveFigure(int dx, int dy)
 {
   static long move_delay = 0;
   int moved = MF_NO_ACTION;
+  int oldJX = JX, oldJY = JY;
 
-  if (GameOver || (!dx && !dy))
+  if (PlayerGone || (!dx && !dy))
     return(FALSE);
 
 /*
@@ -2394,18 +2860,6 @@ BOOL MoveFigure(int dx, int dy)
     int old_scroll_x=scroll_x, old_scroll_y=scroll_y;
     int offset = (scroll_delay_on ? 3 : 0);
 
-/*
-    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;
-*/
-
-/*
-    printf("(scroll_x, scroll_y, JX, JY) == (%d, %d, %d, %d)\n",
-          scroll_x, scroll_y, JX, JY);
-*/
-
     if ((scroll_x < JX-MIDPOSX-offset || scroll_x > JX-MIDPOSX+offset) &&
        JX>=MIDPOSX-1-offset && JX<=lev_fieldx-(MIDPOSX-offset))
       scroll_x = JX-MIDPOSX + (scroll_x < JX-MIDPOSX ? -offset : offset);
@@ -2415,28 +2869,36 @@ BOOL MoveFigure(int dx, int dy)
 
     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);
+  if (!(moved & MF_MOVING) && !PlayerPushing)
+    PlayerFrame = 0;
+  else
+    PlayerFrame = (PlayerFrame + 1) % 4;
+
+  if (moved & MF_MOVING)
+  {
+    if (oldJX != JX && oldJY == JY)
+      PlayerMovDir = (oldJX < JX ? MV_RIGHT : MV_LEFT);
+    else if (oldJX == JX && oldJY != JY)
+      PlayerMovDir = (oldJY < JY ? MV_DOWN : MV_UP);
+
+    DrawLevelField(JX,JY);     /* für "ErdreichAnbroeckeln()" */
   }
 
   TestIfHeroHitsBadThing();
 
   BackToFront();
 
-/*
-  if (LevelSolved)
-    GameWon();
-*/
+  if (PlayerGone)
+    RemoveHero();
 
   return(moved);
 }
 
-void TestIfHeroHitsBadThing()
+void TestIfGoodThingHitsBadThing(int goodx, int goody)
 {
-  int i, killx = JX,killy = JY;
+  int i, killx = goodx, killy = goody;
   static int xy[4][2] =
   {
     { 0,-1 },
@@ -2456,8 +2918,8 @@ void TestIfHeroHitsBadThing()
   {
     int x,y,element;
 
-    x = JX+xy[i][0];
-    y = JY+xy[i][1];
+    x = goodx+xy[i][0];
+    y = goody+xy[i][1];
     if (!IN_LEV_FIELD(x,y))
       continue;
 
@@ -2474,13 +2936,78 @@ void TestIfHeroHitsBadThing()
     }
   }
 
-  if (killx!=JX || killy!=JY)
-    KillHero();
+  if (killx!=goodx || killy!=goody)
+  {
+    if (IS_PLAYER(goodx,goody))
+      KillHero();
+    else
+      Bang(goodx,goody);
+  }
+}
+
+void TestIfBadThingHitsGoodThing(int badx, int bady)
+{
+  int i, killx = badx, killy = bady;
+  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 = badx+xy[i][0];
+    y = bady+xy[i][1];
+    if (!IN_LEV_FIELD(x,y))
+      continue;
+
+    element = Feld[x][y];
+
+    if (element==EL_PINGUIN)
+    {
+      if (MovDir[x][y]==harmless[i] && IS_MOVING(x,y))
+       continue;
+
+      killx = x;
+      killy = y;
+      break;
+    }
+  }
+
+  if (killx!=badx || killy!=bady)
+    Bang(killx,killy);
+}
+
+void TestIfHeroHitsBadThing()
+{
+  TestIfGoodThingHitsBadThing(JX,JY);
 }
 
 void TestIfBadThingHitsHero()
 {
-  TestIfHeroHitsBadThing();
+  TestIfGoodThingHitsBadThing(JX,JY);
+  /* (no typo!) */
+}
+
+void TestIfFriendHitsBadThing(int x, int y)
+{
+  TestIfGoodThingHitsBadThing(x,y);
+}
+
+void TestIfBadThingHitsFriend(int x, int y)
+{
+  TestIfBadThingHitsGoodThing(x,y);
 }
 
 void TestIfBadThingHitsOtherBadThing(int badx, int bady)
@@ -2519,18 +3046,34 @@ void TestIfBadThingHitsOtherBadThing(int badx, int bady)
 
 void KillHero()
 {
-  if (IS_PLAYER(-1,-1))
+  if (PlayerGone)
     return;
 
   if (IS_PFORTE(Feld[JX][JY]))
     Feld[JX][JY] = EL_LEERRAUM;
 
+  Bang(JX,JY);
+  BuryHero();
+}
+
+void BuryHero()
+{
+  if (PlayerGone)
+    return;
+
   PlaySoundLevel(JX,JY,SND_AUTSCH);
   PlaySoundLevel(JX,JY,SND_LACHEN);
-  Bang(JX,JY);
+
   GameOver = TRUE;
-  ZX = JX;
-  ZY = JY;
+  RemoveHero();
+}
+
+void RemoveHero()
+{
+  PlayerGone = TRUE;
+
+  ExitX = ZX = JX;
+  ExitY = ZY = JY;
   JX = JY = -1;
 }
 
@@ -2541,6 +3084,8 @@ int DigField(int x, int y, int real_dx, int real_dy, int mode)
   static long push_delay = 0;
   static int push_delay_value = 5;
 
+  PlayerPushing = FALSE;
+
   if (mode == DF_NO_PUSH)
   {
     push_delay = 0;
@@ -2556,9 +3101,11 @@ int DigField(int x, int y, int real_dx, int real_dy, int mode)
   {
     case EL_LEERRAUM:
       break;
+
     case EL_ERDREICH:
       Feld[x][y] = EL_LEERRAUM;
       break;
+
     case EL_EDELSTEIN:
     case EL_EDELSTEIN_BD:
     case EL_EDELSTEIN_GELB:
@@ -2572,6 +3119,7 @@ int DigField(int x, int y, int real_dx, int real_dy, int mode)
       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;
       Gems -= 3;
@@ -2581,6 +3129,7 @@ int DigField(int x, int y, int real_dx, int real_dy, int mode)
       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;
       Dynamite++;
@@ -2588,6 +3137,7 @@ int DigField(int x, int y, int real_dx, int real_dy, int mode)
       DrawText(DX_DYNAMITE,DY_DYNAMITE,int2str(Dynamite,3),FS_SMALL,FC_YELLOW);
       PlaySoundLevel(x,y,SND_PONG);
       break;
+
     case EL_DYNABOMB_NR:
       Feld[x][y] = EL_LEERRAUM;
       DynaBombCount++;
@@ -2596,17 +3146,20 @@ int DigField(int x, int y, int real_dx, int real_dy, int mode)
       PlaySoundLevel(x,y,SND_PONG);
       break;
     case EL_DYNABOMB_SZ:
+
       Feld[x][y] = EL_LEERRAUM;
       DynaBombSize++;
       RaiseScoreElement(EL_DYNAMIT);
       PlaySoundLevel(x,y,SND_PONG);
       break;
+
     case EL_DYNABOMB_XL:
       Feld[x][y] = EL_LEERRAUM;
       DynaBombXL = TRUE;
       RaiseScoreElement(EL_DYNAMIT);
       PlaySoundLevel(x,y,SND_PONG);
       break;
+
     case EL_SCHLUESSEL1:
     case EL_SCHLUESSEL2:
     case EL_SCHLUESSEL3:
@@ -2626,20 +3179,25 @@ int DigField(int x, int y, int real_dx, int real_dy, int mode)
       PlaySoundLevel(x,y,SND_PONG);
       break;
     }
+
     case EL_ABLENK_AUS:
       Feld[x][y] = EL_ABLENK_EIN;
-      ZX=x;
-      ZY=y;
+      ZX = x;
+      ZY = y;
       DrawLevelField(x,y);
       return(MF_ACTION);
       break;
+
     case EL_FELSBROCKEN:
     case EL_BOMBE:
     case EL_KOKOSNUSS:
     case EL_ZEIT_LEER:
-      if (mode==DF_SNAP)
+      if (dy || mode==DF_SNAP)
        return(MF_NO_ACTION);
-      if (dy || !IN_LEV_FIELD(x+dx,y+dy) || Feld[x+dx][y+dy] != EL_LEERRAUM)
+
+      PlayerPushing = TRUE;
+
+      if (!IN_LEV_FIELD(x+dx,y+dy) || Feld[x+dx][y+dy] != EL_LEERRAUM)
        return(MF_NO_ACTION);
 
       if (real_dy)
@@ -2666,6 +3224,7 @@ int DigField(int x, int y, int real_dx, int real_dy, int mode)
       else
        PlaySoundLevel(x+dx,y+dy,SND_KLOPF);
       break;
+
     case EL_PFORTE1:
     case EL_PFORTE2:
     case EL_PFORTE3:
@@ -2673,6 +3232,7 @@ int DigField(int x, int y, int real_dx, int real_dy, int mode)
       if (!Key[element-EL_PFORTE1])
        return(MF_NO_ACTION);
       break;
+
     case EL_PFORTE1X:
     case EL_PFORTE2X:
     case EL_PFORTE3X:
@@ -2680,17 +3240,25 @@ int DigField(int x, int y, int real_dx, int real_dy, int mode)
       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)
        return(MF_NO_ACTION);
-      LevelSolved = GameOver = TRUE;
+
+      PlayerGone = TRUE;
       PlaySoundLevel(x,y,SND_BUING);
+
+      if (!Friends)
+       LevelSolved = GameOver = TRUE;
+
       break;
+
     case EL_BIRNE_AUS:
       Feld[x][y] = EL_BIRNE_EIN;
       Lights--;
@@ -2698,6 +3266,7 @@ int DigField(int x, int y, int real_dx, int real_dy, int mode)
       PlaySoundLevel(x,y,SND_DENG);
       return(MF_ACTION);
       break;
+
     case EL_ZEIT_VOLL:
       Feld[x][y] = EL_ZEIT_LEER;
       TimeLeft += 10;
@@ -2706,15 +3275,22 @@ int DigField(int x, int y, int real_dx, int real_dy, int mode)
       PlaySoundStereo(SND_GONG,PSND_MAX_RIGHT);
       return(MF_ACTION);
       break;
+
     case EL_SOKOBAN_FELD_LEER:
       break;
+
     case EL_SOKOBAN_FELD_VOLL:
     case EL_SOKOBAN_OBJEKT:
+    case EL_SONDE:
       if (mode==DF_SNAP)
        return(MF_NO_ACTION);
+
+      PlayerPushing = TRUE;
+
       if (!IN_LEV_FIELD(x+dx,y+dy)
          || (Feld[x+dx][y+dy] != EL_LEERRAUM
-             && Feld[x+dx][y+dy] != EL_SOKOBAN_FELD_LEER))
+             && (Feld[x+dx][y+dy] != EL_SOKOBAN_FELD_LEER
+                 || !IS_SB_ELEMENT(element))))
        return(MF_NO_ACTION);
 
       if (dx && real_dy)
@@ -2733,23 +3309,31 @@ int DigField(int x, int y, int real_dx, int real_dy, int mode)
       if (!FrameReached(&push_delay,push_delay_value) && !tape.playing)
        return(MF_NO_ACTION);
 
-      if (element == EL_SOKOBAN_FELD_VOLL)
+      if (IS_SB_ELEMENT(element))
       {
-       Feld[x][y] = EL_SOKOBAN_FELD_LEER;
-       SokobanFields++;
+       if (element == EL_SOKOBAN_FELD_VOLL)
+       {
+         Feld[x][y] = EL_SOKOBAN_FELD_LEER;
+         SokobanFields++;
+       }
+       else
+         Feld[x][y] = EL_LEERRAUM;
+
+       if (Feld[x+dx][y+dy] == EL_SOKOBAN_FELD_LEER)
+       {
+         Feld[x+dx][y+dy] = EL_SOKOBAN_FELD_VOLL;
+         SokobanFields--;
+         if (element == EL_SOKOBAN_OBJEKT)
+           PlaySoundLevel(x,y,SND_DENG);
+       }
+       else
+         Feld[x+dx][y+dy] = EL_SOKOBAN_OBJEKT;
       }
       else
-       Feld[x][y] = EL_LEERRAUM;
-
-      if (Feld[x+dx][y+dy] == EL_SOKOBAN_FELD_LEER)
       {
-       Feld[x+dx][y+dy] = EL_SOKOBAN_FELD_VOLL;
-       SokobanFields--;
-       if (element == EL_SOKOBAN_OBJEKT)
-         PlaySoundLevel(x,y,SND_DENG);
+       Feld[x][y] = EL_LEERRAUM;
+       Feld[x+dx][y+dy] = element;
       }
-      else
-       Feld[x+dx][y+dy] = EL_SOKOBAN_OBJEKT;
 
       push_delay_value = 2;
 
@@ -2757,13 +3341,21 @@ int DigField(int x, int y, int real_dx, int real_dy, int mode)
       DrawLevelField(x+dx,y+dy);
       PlaySoundLevel(x+dx,y+dy,SND_PUSCH);
 
-      if (SokobanFields == 0 && game_emulation == EMU_SOKOBAN)
+      if (IS_SB_ELEMENT(element) &&
+         SokobanFields == 0 && game_emulation == EMU_SOKOBAN)
       {
        LevelSolved = GameOver = TRUE;
        PlaySoundLevel(x,y,SND_BUING);
       }
 
       break;
+
+    case EL_MAULWURF:
+    case EL_PINGUIN:
+    case EL_SCHWEIN:
+    case EL_DRACHE:
+      break;
+
     default:
       return(MF_NO_ACTION);
       break;
@@ -2779,7 +3371,7 @@ BOOL SnapField(int dx, int dy)
   int x = JX+dx, y = JY+dy;
   static int snapped = FALSE;
 
-  if (GameOver || !IN_LEV_FIELD(x,y))
+  if (PlayerGone || !IN_LEV_FIELD(x,y))
     return(FALSE);
   if (dx && dy)
     return(FALSE);
@@ -2791,6 +3383,11 @@ BOOL SnapField(int dx, int dy)
   if (snapped)
     return(FALSE);
 
+  PlayerMovDir = (dx < 0 ? MV_LEFT :
+                 dx > 0 ? MV_RIGHT :
+                 dy < 0 ? MV_UP :
+                 dy > 0 ? MV_DOWN :    MV_NO_MOVING);
+
   if (!DigField(x,y, 0,0, DF_SNAP))
     return(FALSE);
 
@@ -2805,7 +3402,7 @@ BOOL PlaceBomb(void)
 {
   int element;
 
-  if (GameOver)
+  if (PlayerGone)
     return(FALSE);
 
   element = Feld[JX][JY];
@@ -2814,7 +3411,7 @@ BOOL PlaceBomb(void)
       element==EL_DYNAMIT || element==EL_DYNABOMB || element==EL_EXPLODING)
     return(FALSE);
 
-  if (element!=EL_LEERRAUM)
+  if (element != EL_LEERRAUM)
     Store[JX][JY] = element;
 
   if (Dynamite)
@@ -2840,12 +3437,15 @@ void PlaySoundLevel(int x, int y, int sound_nr)
 {
   int sx = SCROLLX(x), sy = SCROLLY(y);
   int volume, stereo;
+  int silence_distance = 8;
 
   if ((!sound_simple_on && !IS_LOOP_SOUND(sound_nr)) ||
       (!sound_loops_on && IS_LOOP_SOUND(sound_nr)))
     return;
 
-  if (!IN_LEV_FIELD(x,y))
+  if (!IN_LEV_FIELD(x,y) ||
+      sx < -silence_distance || sx >= SCR_FIELDX+silence_distance ||
+      sy < -silence_distance || sy >= SCR_FIELDY+silence_distance)
     return;
 
   volume = PSND_MAX_VOLUME;
@@ -2853,10 +3453,10 @@ void PlaySoundLevel(int x, int y, int sound_nr)
 
   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);
+    int dx = ABS(sx-SCR_FIELDX/2)-SCR_FIELDX/2;
+    int dy = ABS(sy-SCR_FIELDY/2)-SCR_FIELDY/2;
+
+    volume -= volume*(dx > dy ? dx : dy)/silence_distance;
   }
 
   PlaySoundExt(sound_nr, volume, stereo, PSND_NO_LOOP);
@@ -2891,8 +3491,8 @@ void RaiseScoreElement(int element)
     case EL_MAMPFER2:
       RaiseScore(level.score[SC_MAMPFER]);
       break;
-    case EL_ZOMBIE:
-      RaiseScore(level.score[SC_ZOMBIE]);
+    case EL_ROBOT:
+      RaiseScore(level.score[SC_ROBOT]);
       break;
     case EL_PACMAN:
       RaiseScore(level.score[SC_PACMAN]);
index a0a2107..8b76cb7 100644 (file)
@@ -76,10 +76,16 @@ void GameActions(void);
 void ScrollLevel(int, int);
 BOOL MoveFigureOneStep(int, int, int, int);
 BOOL MoveFigure(int, int);
+void TestIfGoodThingHitsBadThing(int, int);
+void TestIfBadThingHitsGoodThing(int, int);
 void TestIfHeroHitsBadThing(void);
 void TestIfBadThingHitsHero(void);
+void TestIfFriendHitsBadThing(int, int);
+void TestIfBadThingHitsFriend(int, int);
 void TestIfBadThingHitsOtherBadThing(int, int);
 void KillHero(void);
+void BuryHero(void);
+void RemoveHero(void);
 int DigField(int, int, int, int, int);
 BOOL SnapField(int, int);
 BOOL PlaceBomb(void);
diff --git a/src/gfxloader.c b/src/gfxloader.c
new file mode 100644 (file)
index 0000000..d0bd1cb
--- /dev/null
@@ -0,0 +1,1068 @@
+/***********************************************************
+*  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             *
+*----------------------------------------------------------*
+*  gfxloader.c                                             *
+***********************************************************/
+
+#include "gfxloader.h"
+
+#ifdef DEBUG
+/*
+#define DEBUG_GIF
+#define DEBUG_ILBM
+*/
+#endif
+
+struct IFF_ILBM_FORM_big_endian
+{
+  char magic_FORM[4];
+  unsigned char chunk_size[4];
+  char magic_ILBM[4];
+};
+
+struct IFF_ILBM_BMHD_big_endian
+{
+  char Width[2], Height[2];
+  char LeftEdge[2], TopEdge[2];
+  char Depth;
+  char Mask;
+  char Compression;
+  char pad1;
+  char transparentColor[2];
+  char xAspect, yAspect;
+  char pageWidth[2], pageHeight[2];
+};
+
+struct IFF_ILBM_BMHD
+{
+  unsigned int Width, Height;
+  int LeftEdge, TopEdge;
+  unsigned int Depth;
+  unsigned int Mask;
+  unsigned int Compression;
+  unsigned char pad1;
+  unsigned int transparentColor;
+  unsigned int xAspect, yAspect;
+  int pageWidth, pageHeight;
+};
+
+static int ConvertXImageDepth(Display *, XImage **);
+static int Read_GIF_to_Pixmap_or_Bitmap(Display *, char *, Pixmap *, int);
+
+#define READ_GIF_TO_BITMAP     0
+#define READ_GIF_TO_PIXMAP     1
+
+
+int Read_GIF_to_Bitmap(Display *display, char *filename, Pixmap *pixmap)
+{
+  return(Read_GIF_to_Pixmap_or_Bitmap(display, filename,
+                                     pixmap, READ_GIF_TO_BITMAP));
+}
+
+int Read_GIF_to_Pixmap(Display *display, char *filename, Pixmap *pixmap)
+{
+  return(Read_GIF_to_Pixmap_or_Bitmap(display, filename,
+                                     pixmap, READ_GIF_TO_PIXMAP));
+}
+
+int Read_GIF_to_Pixmap_or_Bitmap(Display *display, char *filename,
+                                Pixmap *pixmap, int mode)
+{
+  XImage *image = NULL;
+  Pixmap new_pixmap = 0;
+  int return_code;
+
+  *pixmap = 0;
+  return_code = Read_GIF_to_XImage(display, filename, &image);
+  if (return_code != GIF_Success)
+    return(return_code);
+
+  if (image)
+  {
+    int screen = DefaultScreen(display);
+    Drawable root = RootWindow(display,screen);
+    int depth = DefaultDepth(display, screen);
+    int width = image->width;
+    int height = image->height;
+
+    if (mode == READ_GIF_TO_BITMAP)
+    {
+      int i,x,y;
+      unsigned long black_pixel = BlackPixel(display,screen);
+      int bytes_per_line = (width+7) / 8;
+      int size = bytes_per_line * height;
+      char *data, *ptr;
+
+      data = (char *)malloc(size);
+      if (!data)
+       return(GIF_NoMemory);
+
+      ptr = data;
+      for(i=0;i<size;i++)
+       *ptr++ = 0;
+
+      for(y=0;y<height;y++)
+      {
+       for(x=0;x<width;x++)
+       {
+         if (XGetPixel(image,x,y) == black_pixel)
+           data[y * bytes_per_line + x/8] |= (1 << (x%8));
+       }
+      }
+
+      new_pixmap = XCreateBitmapFromData(display,root,data,width,height);
+      free(data);
+
+      if (!new_pixmap)
+       return(GIF_NoMemory);
+    }
+    else
+    {
+      GC gc;
+      XGCValues gcv;
+
+      if (ConvertXImageDepth(display, &image) != GIF_Success)
+       return(GIF_ColorFailed);
+
+      new_pixmap = XCreatePixmap(display,root,width,height,depth);
+
+      if (!new_pixmap)
+       return(GIF_NoMemory);
+
+      gcv.foreground = BlackPixel(display,screen);
+      gcv.background = WhitePixel(display,screen);
+      gc = XCreateGC(display, root, GCForeground | GCBackground, &gcv);
+      XPutImage(display,new_pixmap,gc,image,0,0,0,0,width,height);
+      XFreeGC(display, gc);
+    }
+
+    XDestroyImage(image);
+  }
+
+  *pixmap = new_pixmap;
+  return(return_code);
+}
+
+
+/*
+ * Read_GIF_to_XImage()  -  based strongly on...
+ *
+ * xgifload.c  -  based strongly on...
+ *
+ * gif2ras.c - Converts from a Compuserve GIF (tm) image to a Sun Raster image.
+ *
+ * Copyright (c) 1988, 1989 by Patrick J. Naughton
+ *
+ * Author: Patrick J. Naughton
+ * naughton@wind.sun.com
+ *
+ * Permission to use, copy, modify, and distribute this software and its
+ * documentation for any purpose and without fee is hereby granted,
+ * provided that the above copyright notice appear in all copies and that
+ * both that copyright notice and this permission notice appear in
+ * supporting documentation.
+ *
+ * This file is provided AS IS with no warranties of any kind.  The author
+ * shall have no liability with respect to the infringement of copyrights,
+ * trade secrets or any patents by this file or any part thereof.  In no
+ * event will the author be liable for any lost revenue or profits or
+ * other special, indirect and consequential damages.
+ *
+ */
+
+typedef int boolean;
+typedef unsigned char byte;
+
+static int ReadCode(void);
+static void AddToPixel(byte);
+static int ColorDicking(Display *);
+
+#define NEXTBYTE       (*ptr++)
+#define IMAGESEP       0x2c
+#define INTERLACEMASK  0x40
+#define COLORMAPMASK   0x80
+
+static
+int BitOffset,                 /* Bit Offset of next code */
+    XC, YC,                    /* Output X and Y coords of current pixel */
+    Pass,                      /* Used by output routine if interlaced pic */
+    OutCount,                  /* Decompressor output 'stack count' */
+    RWidth, RHeight,           /* screen dimensions */
+    Width, Height,             /* image dimensions */
+    LeftOfs, TopOfs,           /* image offset */
+    BitsPerPixel,              /* Bits per pixel, read from GIF header */
+    BytesPerScanline,          /* bytes per scanline in output raster */
+    ColorMapSize,              /* number of colors */
+    Background,                        /* background color */
+    CodeSize,                  /* Code size, read from GIF header */
+    InitCodeSize,              /* Starting code size, used during Clear */
+    Code,                      /* Value returned by ReadCode */
+    MaxCode,                   /* limiting value for current code size */
+    ClearCode,                 /* GIF clear code */
+    EOFCode,                   /* GIF end-of-information code */
+    CurCode, OldCode, InCode,  /* Decompressor variables */
+    FirstFree,                 /* First free code, generated per GIF spec */
+    FreeCode,                  /* Decompressor, next free slot in hash table*/
+    FinChar,                   /* Decompressor variable */
+    BitMask,                   /* AND mask for data size */
+    ReadMask;                  /* Code AND mask for current code size */
+
+static boolean Interlace, HasColormap;
+
+static byte *ImageData;                /* The result array */
+static byte *RawGIF;           /* The heap array to hold it, raw */
+static byte *Raster;           /* The raster data stream, unblocked */
+
+/* The color map, read from the GIF header */
+static byte Red[256], Green[256], Blue[256], used[256];
+static int  numused;
+
+extern char *progname;
+
+static int numcols;
+static unsigned long cols[256];
+static XColor defs[256];
+
+int Read_GIF_to_XImage(Display *display, char *filename, XImage **image)
+{
+  int filesize;
+  register byte ch, ch1;
+  register byte *ptr, *ptr1;
+  register int i;
+  int screen = DefaultScreen(display);
+  Visual *visual = DefaultVisual(display,screen);
+  XImage *new_image = NULL;
+  char *id = "GIF87a";
+  FILE *file;
+  int Prefix[4096];    /* The hash table used by the decompressor */
+  int Suffix[4096];
+  int OutCode[1025];   /* An output array used by the decompressor */
+
+  BitOffset = XC = YC = Pass = OutCount = 0;
+  *image = NULL;
+
+  if (strcmp(filename,"-")==0)
+  {
+    file = stdin;
+    filename = "<stdin>";
+  }
+  else
+    file = fopen(filename,"r");
+
+  if (!file)
+    return(GIF_OpenFailed);
+
+  /* find the size of the file */
+  fseek(file, 0L, 2);
+  filesize = ftell(file);
+  fseek(file, 0L, 0);
+
+  if (!(ptr = RawGIF = (byte *) malloc(filesize)))
+    return(GIF_NoMemory);
+
+  if (!(Raster = (byte *) malloc(filesize)))
+    return(GIF_NoMemory);
+
+  if (fread(ptr, filesize, 1, file) != 1)
+    return(GIF_ReadFailed);
+
+  if (strncmp(ptr, id, 6))
+    return(GIF_FileInvalid);
+
+  ptr += 6;
+
+  /* Get variables from the GIF screen descriptor */
+
+  ch = NEXTBYTE;
+  RWidth = ch + 0x100 * NEXTBYTE;    /* screen dimensions... not used. */
+  ch = NEXTBYTE;
+  RHeight = ch + 0x100 * NEXTBYTE;
+
+  ch = NEXTBYTE;
+  HasColormap = ((ch & COLORMAPMASK) ? True : False);
+
+  BitsPerPixel = (ch & 7) + 1;
+  numcols = ColorMapSize = 1 << BitsPerPixel;
+  BitMask = ColorMapSize - 1;
+
+  Background = NEXTBYTE;             /* background color... not used. */
+
+  if (NEXTBYTE)              /* supposed to be NULL */
+    return(GIF_FileInvalid);
+
+  /* Read in global colormap. */
+
+  if (HasColormap)
+  {
+    for (i = 0; i < ColorMapSize; i++)
+    {
+      Red[i] = NEXTBYTE;
+      Green[i] = NEXTBYTE;
+      Blue[i] = NEXTBYTE;
+      used[i] = 0;
+    }
+    numused = 0;
+  }
+  else
+  {
+    /* no colormap in GIF file */
+    fprintf(stderr,"%s:  warning!  no colortable in this file.  Winging it.\n",
+           progname);
+    if (!numcols)
+      numcols=256;
+    for (i=0; i<numcols; i++)
+      cols[i] = (unsigned long) i;
+  }
+
+  /* Check for image seperator */
+
+  if (NEXTBYTE != IMAGESEP)
+    return(GIF_FileInvalid);
+
+  /* Now read in values from the image descriptor */
+
+  ch = NEXTBYTE;
+  LeftOfs = ch + 0x100 * NEXTBYTE;
+  ch = NEXTBYTE;
+  TopOfs = ch + 0x100 * NEXTBYTE;
+  ch = NEXTBYTE;
+  Width = ch + 0x100 * NEXTBYTE;
+  ch = NEXTBYTE;
+  Height = ch + 0x100 * NEXTBYTE;
+  Interlace = ((NEXTBYTE & INTERLACEMASK) ? True : False);
+
+#ifdef DEBUG_GIF
+  fprintf(stderr, "%s:\n", filename);
+  fprintf(stderr, "   %dx%d, %d bpp / %d colors, %sinterlaced\n",
+         Width,Height, BitsPerPixel,ColorMapSize,(Interlace ? "" : "non-"));
+  fprintf(stderr, "   Reading file... ");
+#endif
+
+  /* Note that I ignore the possible existence of a local color map.
+   * I'm told there aren't many files around that use them, and the spec
+   * says it's defined for future use.  This could lead to an error
+   * reading some files. 
+   */
+
+  /* Start reading the raster data. First we get the intial code size
+   * and compute decompressor constant values, based on this code size.
+   */
+
+  CodeSize = NEXTBYTE;
+  ClearCode = (1 << CodeSize);
+  EOFCode = ClearCode + 1;
+    FreeCode = FirstFree = ClearCode + 2;
+
+  /* The GIF spec has it that the code size is the code size used to
+   * compute the above values is the code size given in the file, but the
+   * code size used in compression/decompression is the code size given in
+   * the file plus one. (thus the ++).
+   */
+
+  CodeSize++;
+  InitCodeSize = CodeSize;
+  MaxCode = (1 << CodeSize);
+  ReadMask = MaxCode - 1;
+
+  /* Read the raster data.  Here we just transpose it from the GIF array
+   * to the Raster array, turning it from a series of blocks into one long
+   * data stream, which makes life much easier for ReadCode().
+   */
+
+  ptr1 = Raster;
+  do
+  {
+    ch = ch1 = NEXTBYTE;
+    while (ch--) *ptr1++ = NEXTBYTE;
+    if ((Raster - ptr1) > filesize)
+      return(GIF_FileInvalid);
+  }
+  while(ch1);
+
+  free(RawGIF);              /* We're done with the raw data now... */
+
+#ifdef DEBUG_GIF
+  fprintf(stderr, "done\n");
+  fprintf(stderr, "   Decompressing... ");
+#endif
+
+  /* Allocate the X Image */
+  ImageData = (byte *) malloc(Width*Height);
+  if (!ImageData)
+    return(GIF_NoMemory);
+
+  new_image = XCreateImage(display,visual,8,ZPixmap,0,ImageData,
+                          Width,Height,8,Width);
+  if (!new_image)
+    return(GIF_NoMemory);
+
+  BytesPerScanline = Width;
+
+
+  /* Decompress the file, continuing until you see the GIF EOF code.
+   * One obvious enhancement is to add checking for corrupt files here.
+   */
+
+  Code = ReadCode();
+  while (Code != EOFCode)
+  {
+    /* Clear code sets everything back to its initial value, then reads the
+     * immediately subsequent code as uncompressed data.
+     */
+
+    if (Code == ClearCode)
+    {
+      CodeSize = InitCodeSize;
+      MaxCode = (1 << CodeSize);
+      ReadMask = MaxCode - 1;
+      FreeCode = FirstFree;
+      CurCode = OldCode = Code = ReadCode();
+      FinChar = CurCode & BitMask;
+      AddToPixel(FinChar);
+    }
+    else
+    {
+      /* If not a clear code, then must be data:
+       * save same as CurCode and InCode
+       */
+
+      CurCode = InCode = Code;
+
+      /* If greater or equal to FreeCode, not in the hash table yet;
+       * repeat the last character decoded
+       */
+
+      if (CurCode >= FreeCode)
+      {
+       CurCode = OldCode;
+       OutCode[OutCount++] = FinChar;
+      }
+
+      /* Unless this code is raw data, pursue the chain pointed to by CurCode
+       * through the hash table to its end; each code in the chain puts its
+       * associated output code on the output queue.
+       */
+
+      while (CurCode > BitMask)
+      {
+       if (OutCount > 1024)
+         return(GIF_FileInvalid);
+
+       OutCode[OutCount++] = Suffix[CurCode];
+       CurCode = Prefix[CurCode];
+      }
+
+      /* The last code in the chain is treated as raw data. */
+
+      FinChar = CurCode & BitMask;
+      OutCode[OutCount++] = FinChar;
+
+      /* Now we put the data out to the Output routine.
+       * It's been stacked LIFO, so deal with it that way...
+       */
+
+      for (i = OutCount - 1; i >= 0; i--)
+       AddToPixel(OutCode[i]);
+      OutCount = 0;
+
+      /* Build the hash table on-the-fly. No table is stored in the file. */
+
+      Prefix[FreeCode] = OldCode;
+      Suffix[FreeCode] = FinChar;
+      OldCode = InCode;
+
+      /* Point to the next slot in the table.  If we exceed the current
+       * MaxCode value, increment the code size unless it's already 12.  If it
+       * is, do nothing: the next code decompressed better be CLEAR
+       */
+
+      FreeCode++;
+      if (FreeCode >= MaxCode)
+      {
+       if (CodeSize < 12)
+       {
+         CodeSize++;
+         MaxCode *= 2;
+         ReadMask = (1 << CodeSize) - 1;
+       }
+      }
+    }
+    Code = ReadCode();
+  }
+
+  free(Raster);
+
+#ifdef DEBUG_GIF
+  fprintf(stderr, "done\n");
+  fprintf(stderr,"   %d colors used\n",numused);
+#endif
+
+  if (file != stdin)
+    fclose(file);
+
+  if (ColorDicking(display) != GIF_Success)
+    return(GIF_ColorFailed);
+
+  *image = new_image;
+  return(GIF_Success);
+}
+
+
+/* Fetch the next code from the raster data stream.  The codes can be
+ * any length from 3 to 12 bits, packed into 8-bit bytes, so we have to
+ * maintain our location in the Raster array as a BIT Offset.  We compute
+ * the byte Offset into the raster array by dividing this by 8, pick up
+ * three bytes, compute the bit Offset into our 24-bit chunk, shift to
+ * bring the desired code to the bottom, then mask it off and return it. 
+ */
+
+static int ReadCode()
+{
+  int RawCode, ByteOffset;
+
+  ByteOffset = BitOffset / 8;
+  RawCode = Raster[ByteOffset] + (0x100 * Raster[ByteOffset + 1]);
+  if (CodeSize >= 8)
+    RawCode += (0x10000 * Raster[ByteOffset + 2]);
+  RawCode >>= (BitOffset % 8);
+  BitOffset += CodeSize;
+  return(RawCode & ReadMask);
+}
+
+
+static void AddToPixel(byte Index)
+{
+  if (YC<Height)
+    *(ImageData + YC * BytesPerScanline + XC) = Index;
+
+  if (!used[Index])
+  {
+    used[Index]=1;
+    numused++;
+  }
+
+  /* Update the X-coordinate, and if it overflows, update the Y-coordinate */
+
+  if (++XC == Width)
+  {
+    /* If a non-interlaced picture, just increment YC to the next scan line. 
+     * If it's interlaced, deal with the interlace as described in the GIF
+     * spec.  Put the decoded scan line out to the screen if we haven't gone
+     * past the bottom of it
+     */
+
+    XC = 0;
+    if (!Interlace)
+      YC++;
+    else
+    {
+      switch (Pass)
+      {
+       case 0:
+         YC += 8;
+         if (YC >= Height)
+         {
+           Pass++;
+           YC = 4;
+         }
+         break;
+
+       case 1:
+         YC += 8;
+         if (YC >= Height)
+         {
+           Pass++;
+           YC = 2;
+         }
+         break;
+
+       case 2:
+         YC += 4;
+         if (YC >= Height)
+         {
+           Pass++;
+           YC = 1;
+         }
+         break;
+
+       case 3:
+         YC += 2;
+         break;
+
+       default:
+         break;
+       }
+    }
+  }
+}
+
+
+static int ColorDicking(Display *display)
+{
+  /* we've got the picture loaded, we know what colors are needed. get 'em */
+
+  register int i,j;
+  static byte lmasks[8] = {0xff, 0xfe, 0xfc, 0xf8, 0xf0, 0xe0, 0xc0, 0x80};
+  byte lmask, *ptr;
+  int screen = DefaultScreen(display);
+  Colormap cmap = DefaultColormap(display,screen);
+  int dispcells = DisplayCells(display,screen);
+
+  int strip = 0;
+  int nostrip = 0; 
+
+  if (!HasColormap)
+    return(GIF_Success);
+  /* no need to allocate any colors if no colormap in GIF file */
+
+  /* Allocate the X colors for this picture */
+
+  if (nostrip)
+  {
+    /* nostrip was set.  try REAL hard to do it */
+    for (i=j=0; i<numcols; i++)
+    {
+      if (used[i])
+      {
+       defs[i].red   = Red[i]<<8;
+       defs[i].green = Green[i]<<8;
+       defs[i].blue  = Blue[i]<<8;
+       defs[i].flags = DoRed | DoGreen | DoBlue;
+       if (!XAllocColor(display,cmap,&defs[i]))
+       { 
+         j++;
+         defs[i].pixel = 0xffff;
+       }
+       cols[i] = defs[i].pixel;
+      }
+    }
+
+    if (j)
+    {
+      /* failed to pull it off */
+
+      XColor ctab[256];
+      int dc;
+
+      dc = (dispcells<256) ? dispcells : 256;
+
+      fprintf(stderr,
+             "failed to allocate %d out of %d colors.  Trying extra hard.\n",
+             j,numused);
+
+      /* read in the color table */
+      for (i=0; i<dc; i++)
+       ctab[i].pixel = i;
+      XQueryColors(display,cmap,ctab,dc);
+                
+      /* run through the used colors.  any used color that has a pixel
+        value of 0xffff wasn't allocated.  for such colors, run through
+        the entire X colormap and pick the closest color */
+
+      for (i=0; i<numcols; i++)
+       if (used[i] && cols[i]==0xffff)
+       {
+         /* an unallocated pixel */
+
+         int d, mdist, close;
+         unsigned long r,g,b;
+
+         mdist = 100000;   close = -1;
+         r =  Red[i];
+         g =  Green[i];
+         b =  Blue[i];
+         for (j=0; j<dc; j++)
+         {
+           d = abs(r - (ctab[j].red>>8)) +
+             abs(g - (ctab[j].green>>8)) +
+               abs(b - (ctab[j].blue>>8));
+           if (d<mdist)
+           {
+             mdist=d;
+             close=j;
+           }
+         }
+
+         if (close<0)
+           return(GIF_ColorFailed);
+
+         bcopy(&defs[close],&defs[i],sizeof(XColor));
+         cols[i] = ctab[close].pixel;
+       }
+    }  /* end 'failed to pull it off' */
+  }
+  else
+  {
+    /* strip wasn't set, do the best auto-strip */
+
+    j = 0;
+    while (strip<8)
+    {
+      lmask = lmasks[strip];
+      for (i=0; i<numcols; i++)
+      {
+       if (used[i])
+       {
+         defs[i].red   = (Red[i]  &lmask)<<8;
+         defs[i].green = (Green[i]&lmask)<<8;
+         defs[i].blue  = (Blue[i] &lmask)<<8;
+         defs[i].flags = DoRed | DoGreen | DoBlue;
+         if (!XAllocColor(display,cmap,&defs[i]))
+           break;
+         cols[i] = defs[i].pixel;
+       }
+      }
+
+      if (i<numcols)
+      {
+       /* failed */
+       strip++;
+       j++;
+       for (i--; i>=0; i--)
+         if (used[i])
+           XFreeColors(display,cmap,cols+i,1,0L);
+      }
+      else
+       break;
+    }
+
+#ifdef DEBUG_GIF
+    if (j && strip<8)
+      fprintf(stderr,"%s: stripped %d bits\n",progname,strip);
+#endif
+
+    if (strip==8)
+    {
+      fprintf(stderr,"UTTERLY failed to allocate the desired colors.\n");
+      for (i=0; i<numcols; i++) cols[i]=i;
+    }
+  }
+
+  ptr = ImageData;
+  for (i=0; i<Height; i++)
+    for (j=0; j<Width; j++,ptr++) 
+      *ptr = (byte) cols[*ptr];
+
+  return(GIF_Success);
+}
+
+
+/******************************************************************************
+ *  This makes sure the display's depth is the same as the
+ * depth of the default 8 bit image.  If not, we build a new image
+ * that has the correct depth.  This works on the fact that
+ * the color mapper has already changed every pixel value in the
+ * image into the proper number of bits (to fit into the pallet)
+ * so we can just chop down the number of bits.
+ *   This changes the global variable 'expImage' if necessary.
+ */
+
+static int ConvertXImageDepth(Display *display, XImage **image)
+{
+  int screen = DefaultScreen(display);
+  int depth = DefaultDepth(display, screen);
+
+  if ((*image)->depth != depth)
+  {
+    XImage *old_image, *new_image;
+    Visual *visual = DefaultVisual(display,screen);
+    int width = (*image)->width;
+    int height = (*image)->height;
+    register int dwx, dwy;
+    byte *data;
+
+    data = (byte *)malloc(width * height);
+    old_image = *image;
+    new_image = XCreateImage(display,visual,depth,
+                            ZPixmap,0,data,width,height,8,0);
+    if (!new_image)
+      return(GIF_NoMemory);
+
+    if (old_image->depth == 8 && new_image->depth == 4)
+    {
+      /* speedup for the most common format change */
+
+      register byte *sptr = (byte *)old_image->data;
+      register byte *dptr = (byte *)new_image->data;
+
+      for (dwy=1; dwy<=height; dwy++)
+      {
+       for (dwx=1; dwx<width; dwx+=2)
+       {
+         *dptr = (*sptr) | (*(sptr+1)<<4);
+         dptr++;
+         sptr+=2;
+       }
+       if (width & 1)
+       {
+         /* if extra pixal at end of line, just move it */
+         *dptr = *sptr;
+         sptr++; dptr++;
+       }
+      }
+    }
+    else       /* other format change than 8 bit -> 4 bit */
+    {
+      register unsigned long pixel_value;
+
+      for (dwx=0; dwx<width; dwx++)
+      {
+       for (dwy=0; dwy<height; dwy++)
+       {
+         pixel_value = XGetPixel(old_image, dwx, dwy);
+         XPutPixel(new_image, dwx, dwy, pixel_value);
+       }
+      }
+    }
+
+    free(old_image->data);
+    old_image->data = NULL;
+    XDestroyImage(old_image);
+
+    *image = new_image;
+  }
+
+  return(GIF_Success);
+}
+
+
+static unsigned long be2long(unsigned char *be) /* big-endian -> long int */
+{
+  return((be[0]<<24) | (be[1]<<16) | (be[2]<<8) | be[3]);
+}
+
+static unsigned short be2short(unsigned char *be) /* big-endian -> short int */
+{
+  return((be[0]<<8) | be[1]);
+}
+
+static struct IFF_ILBM_BMHD *ConvertBMHD(unsigned char *header_data)
+{
+  struct IFF_ILBM_BMHD_big_endian *bmhd_be;
+  struct IFF_ILBM_BMHD *bmhd;
+
+  bmhd_be = (struct IFF_ILBM_BMHD_big_endian *)header_data;
+  bmhd = (struct IFF_ILBM_BMHD *)malloc(sizeof(struct IFF_ILBM_BMHD));
+  if (!bmhd)
+    return(NULL);
+
+  bmhd->Width = be2short(bmhd_be->Width);
+  bmhd->Height = be2short(bmhd_be->Height);
+  bmhd->LeftEdge = be2short(bmhd_be->LeftEdge);
+  bmhd->TopEdge = be2short(bmhd_be->TopEdge);
+  bmhd->Depth = (int)bmhd_be->Depth;
+  bmhd->Mask = (int)bmhd_be->Mask;
+  bmhd->Compression = (int)bmhd_be->Compression;
+  bmhd->pad1 = bmhd_be->pad1;
+  bmhd->transparentColor = be2short(bmhd_be->transparentColor);
+  bmhd->xAspect = (int)bmhd_be->xAspect;
+  bmhd->yAspect = (int)bmhd_be->yAspect;
+  bmhd->pageWidth = be2short(bmhd_be->pageWidth);
+  bmhd->pageHeight = be2short(bmhd_be->pageHeight);
+
+  return(bmhd);
+}
+
+static unsigned char MSBitFirst2LSBitFirst(unsigned char msb_byte)
+{
+  unsigned char lsb_byte = 0;
+  int i;
+
+  for(i=7;i>=0;i--)
+  {
+    lsb_byte |= (msb_byte & 1) << i;
+    msb_byte >>= 1;
+  }
+
+  return(lsb_byte);
+}
+
+int Read_ILBM_to_Bitmap(Display *display, char *filename, Pixmap *pixmap)
+{
+  Pixmap new_pixmap = 0;
+  int screen = DefaultScreen(display);
+  Drawable root = RootWindow(display,screen);
+  struct IFF_ILBM_FORM_big_endian *form_header;
+  struct IFF_ILBM_BMHD *bitmap_header;
+  unsigned long file_len, body_len;
+  unsigned char *file_data, *bitmap_data;
+  unsigned char *file_ptr, *bitmap_ptr, *body_ptr;
+  unsigned char byte_count, byte_value;
+  int i,x,y,z;
+  int width, height, depth;
+  int bytes_per_line, bitmap_size;
+  FILE *file;
+
+  if (!(file = fopen(filename,"r")))
+    return(ILBM_OpenFailed);
+
+  if (fseek(file,0,SEEK_END) < 0)
+  {
+    fclose(file);
+    return(ILBM_ReadFailed);
+  }
+
+  file_len = ftell(file);
+  rewind(file);
+
+  if (!(file_data = (unsigned char *)malloc(file_len)))
+  {
+    fclose(file);
+    return(ILBM_NoMemory);
+  }
+
+  if (fread(file_data,1,file_len,file) != file_len)
+  {
+    free(file_data);
+    fclose(file);
+    return(ILBM_ReadFailed);
+  }
+
+  fclose(file);
+
+  form_header = (struct IFF_ILBM_FORM_big_endian *)file_data;
+
+  if (strncmp(form_header->magic_FORM,"FORM",4) ||
+      file_len != be2long(form_header->chunk_size)+8 ||
+      strncmp(form_header->magic_ILBM,"ILBM",4))
+  {
+#ifdef DEBUG_ILBM
+      printf("%s: IFF chunk 'FORM' and/or 'ILBM' not found.\n",filename);
+#endif
+    free(file_data);
+    return(ILBM_FileInvalid);
+  }
+
+  bitmap_header = NULL;
+  body_ptr = NULL;
+  file_ptr = file_data + 12;
+
+  while(file_ptr < (unsigned char *)(file_data + file_len))
+  {
+    if (!strncmp(file_ptr,"BMHD",4))
+    {
+#ifdef DEBUG_ILBM
+      printf("%s: IFF chunk 'BMHD' found.\n",filename);
+#endif
+      bitmap_header = ConvertBMHD(file_ptr + 8);
+      file_ptr += be2long(file_ptr + 4) + 8;
+      continue;
+    }
+    else if (!strncmp(file_ptr,"BODY",4))
+    {
+#ifdef DEBUG_ILBM
+      printf("%s: IFF chunk 'BODY' found.\n",filename);
+#endif
+      body_ptr = file_ptr + 8;
+      body_len = be2long(file_ptr + 4);
+      file_ptr += be2long(file_ptr + 4) + 8;
+      continue;
+    }
+    else
+    {
+#ifdef DEBUG_ILBM
+      printf("%s: IFF chunk '%c%c%c%c' found (but not used).\n",filename,
+            file_ptr[0],file_ptr[1],file_ptr[2],file_ptr[3]);
+#endif
+      /* other chunk not recognized here */
+      file_ptr += be2long(file_ptr + 4) + 8;
+      continue;
+    }
+  }
+
+  if (!bitmap_header || !body_ptr)
+  {
+#ifdef DEBUG_ILBM
+      printf("%s: IFF chunk 'BMHD' and/or 'BODY' not found.\n",filename);
+#endif
+    free(file_data);
+    return(ILBM_FileInvalid);
+  }
+
+  width = bitmap_header->Width;
+  height = bitmap_header->Height;
+  depth = bitmap_header->Depth;
+
+#ifdef DEBUG_ILBM
+  if (depth > 1)
+    printf("%s: %d bitplanes found; using only the first plane.\n",
+          filename,depth);
+#endif
+
+  bytes_per_line = ((width + 15) / 16) * 2;
+  bitmap_size = bytes_per_line * height;
+
+  bitmap_data = (char *)malloc(bitmap_size);
+  if (!bitmap_data)
+  {
+    free(file_data);
+    free(bitmap_header);
+    return(ILBM_NoMemory);
+  }
+
+  bitmap_ptr = bitmap_data;
+  for(i=0;i<bitmap_size;i++)
+    *bitmap_ptr++ = 0;
+
+  for(y=0;y<height;y++)
+  {
+    /* we only read the first bitplane here to create a black/white bitmap */
+
+    for(z=0;z<depth;z++)
+    {
+      bitmap_ptr = bitmap_data + y * bytes_per_line;
+      x = 0;
+
+      if (!bitmap_header->Compression)
+      {
+       while(x++ < bytes_per_line)
+         *bitmap_ptr++ |= MSBitFirst2LSBitFirst(*body_ptr++);
+      }
+      else
+      {
+       while(x < bytes_per_line)
+       {
+         byte_count = *body_ptr++;
+
+         if (byte_count <= 128)
+         {
+           for(i=0;i<byte_count+1;i++)
+             *bitmap_ptr++ |= MSBitFirst2LSBitFirst(*body_ptr++);
+           x += byte_count + 1;
+         }
+         else
+         {
+           byte_value = *body_ptr++;
+           for(i=0;i<257-byte_count;i++)
+             *bitmap_ptr++ |= MSBitFirst2LSBitFirst(byte_value);
+           x += 257 - byte_count;
+         }
+       }
+      }
+    }
+  }
+
+  bitmap_ptr = bitmap_data;
+  for(i=0;i<bitmap_size;i++)
+    *bitmap_ptr++ ^= 0xff;
+
+  new_pixmap = XCreateBitmapFromData(display,root,bitmap_data,width,height);
+
+  free(file_data);
+  free(bitmap_data);
+  free(bitmap_header);
+
+  if (!new_pixmap)
+    return(ILBM_NoMemory);
+
+  *pixmap = new_pixmap;
+  return(ILBM_Success);
+}
diff --git a/src/gfxloader.h b/src/gfxloader.h
new file mode 100644 (file)
index 0000000..d5b2257
--- /dev/null
@@ -0,0 +1,43 @@
+/***********************************************************
+*  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             *
+*----------------------------------------------------------*
+*  gfxloader.h                                             *
+***********************************************************/
+
+#ifndef GFXLOADER_H
+#define GFXLOADER_H
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <X11/Xlib.h>
+#include <X11/Xutil.h>
+
+#define GIF_Success             0
+#define GIF_OpenFailed         -1
+#define GIF_ReadFailed         -2
+#define        GIF_FileInvalid         -3
+#define GIF_NoMemory           -4
+#define GIF_ColorFailed                -5
+
+#define ILBM_Success            0
+#define ILBM_OpenFailed                -1
+#define ILBM_ReadFailed                -2
+#define        ILBM_FileInvalid        -3
+#define ILBM_NoMemory          -4
+#define ILBM_ColorFailed       -5
+
+int Read_ILBM_to_Bitmap(Display *, char *, Pixmap *);
+int Read_GIF_to_Bitmap(Display *, char *, Pixmap *);
+int Read_GIF_to_Pixmap(Display *, char *, Pixmap *);
+int Read_GIF_to_XImage(Display *, char *, XImage **);
+
+#endif
index 2d9b304..c9fc72c 100644 (file)
 #include "screens.h"
 #include "tools.h"
 #include "files.h"
+#include "joystick.h"
+#include "gfxloader.h"
+
 #include <signal.h>
 
+#ifdef DEBUG
+/*
+#define DEBUG_TIMING
+*/
+#endif
+
+struct PictureFileInfo
+{
+  char *picture_filename;
+  BOOL picture_with_mask;
+};
+
+struct IconFileInfo
+{
+  char *picture_filename;
+  char *picturemask_filename;
+};
+
 static int sound_process_id = 0;
 
+static void InitLevelAndPlayerInfo(void);
+static void InitDisplay(int, char **);
+static void InitSound(void);
+static void InitSoundProcess(void);
+static void InitWindow(int, char **);
+static void InitGfx(void);
+static void LoadGfx(int, struct PictureFileInfo *);
+static void InitElementProperties(void);
+
 void OpenAll(int argc, char *argv[])
 {
   InitLevelAndPlayerInfo();
@@ -196,7 +226,7 @@ void InitWindow(int argc, char *argv[])
   char *window_name = WINDOWTITLE_STRING;
   char *icon_name = WINDOWTITLE_STRING;
   long window_event_mask;
-  static struct PictureFile icon_pic =
+  static struct IconFileInfo icon_pic =
   {
     "rocks_icon.xbm",
     "rocks_iconmask.xbm"
@@ -295,15 +325,21 @@ void InitGfx()
   int i,j;
   XGCValues clip_gc_values;
   unsigned long clip_gc_valuemask;
-  static struct PictureFile pic[NUM_PICTURES] =
+  static struct PictureFileInfo pic[NUM_PICTURES] =
   {
-    { "RocksScreen.xpm",       "RocksScreenMaske.xbm" },
-    { "RocksDoor.xpm",         "RocksDoorMaske.xbm" },
-    { "RocksToons.xpm",                "RocksToonsMaske.xbm" },
-    { "RocksFont.xpm",         NULL },
-    { "RocksFont2.xpm",                NULL }
+    { "RocksScreen",   TRUE },
+    { "RocksDoor",     TRUE },
+    { "RocksHeroes",   TRUE },
+    { "RocksToons",    TRUE },
+    { "RocksFont",     FALSE },
+    { "RocksFont2",    FALSE }
   }; 
 
+#ifdef DEBUG_TIMING
+  long count1, count2;
+  count1 = Counter();
+#endif
+
   LoadGfx(PIX_SMALLFONT,&pic[PIX_SMALLFONT]);
   DrawInitText(WINDOWTITLE_STRING,20,FC_YELLOW);
   DrawInitText(COPYRIGHT_STRING,50,FC_RED);
@@ -313,6 +349,12 @@ void InitGfx()
     if (i!=PIX_SMALLFONT)
       LoadGfx(i,&pic[i]);
 
+#ifdef DEBUG_TIMING
+  count2 = Counter();
+  printf("SUMMARY: %.2f SECONDS LOADING TIME\n",(float)(count2-count1)/100.0);
+#endif
+
+
   pix[PIX_DB_BACK] = XCreatePixmap(display, window,
                                   WIN_XSIZE,WIN_YSIZE,
                                   XDefaultDepth(display,screen));
@@ -357,19 +399,40 @@ void InitGfx()
   redraw_mask=REDRAW_ALL;
 }
 
-void LoadGfx(int pos, struct PictureFile *pic)
+void LoadGfx(int pos, struct PictureFileInfo *pic)
 {
+  char basefilename[256];
+  char filename[256];
+
+#ifdef XPM_INCLUDE_FILE
   int xpm_err, xbm_err;
   unsigned int width,height;
   int hot_x,hot_y;
-  char filename[256];
   Pixmap shapemask;
+  char *picture_ext = ".xpm";
+  char *picturemask_ext = "Mask.xbm";
+#else
+  int gif_err, ilbm_err;
+  char *picture_ext = ".gif";
+  char *picturemask_ext = "Mask.ilbm";
+#endif
+
+#ifdef DEBUG_TIMING
+  long count1, count2;
+#endif
 
   /* Grafik laden */
   if (pic->picture_filename)
   {
-    DrawInitText(pic->picture_filename,150,FC_YELLOW);
-    sprintf(filename,"%s/%s",GFX_PATH,pic->picture_filename);
+    sprintf(basefilename,"%s%s",pic->picture_filename,picture_ext);
+    DrawInitText(basefilename,150,FC_YELLOW);
+    sprintf(filename,"%s/%s",GFX_PATH,basefilename);
+
+#ifdef DEBUG_TIMING
+    count1 = Counter();
+#endif
+
+#ifdef XPM_INCLUDE_FILE
 
     xpm_att[pos].valuemask = XpmCloseness;
     xpm_att[pos].closeness = 20000;
@@ -378,7 +441,7 @@ void LoadGfx(int pos, struct PictureFile *pic)
     switch(xpm_err)
     {
       case XpmOpenFailed:
-        fprintf(stderr,"Xpm file open failed on '%s' !\n",filename);
+        fprintf(stderr,"Cannot open Xpm file '%s' !\n",filename);
        CloseAll();
        exit(-1);
       case XpmFileInvalid:
@@ -386,20 +449,60 @@ void LoadGfx(int pos, struct PictureFile *pic)
        CloseAll();
        exit(-1);
       case XpmNoMemory:
-       fprintf(stderr,"Not enough memory !\n");        
+       fprintf(stderr,"Not enough memory for Xpm file '%s'!\n",filename);
        CloseAll();
        exit(1);
       case XpmColorFailed:
-       fprintf(stderr,"Can`t get any colors...\n");
+       fprintf(stderr,"Can't get colors for Xpm file '%s'!\n",filename);
        CloseAll();
        exit(-1);
       default:
        break;
     }
 
+#else 
+
+    gif_err = Read_GIF_to_Pixmap(display,filename,&pix[pos]);
+
+    switch(gif_err)
+    {
+      case GIF_Success:
+        break;
+      case GIF_OpenFailed:
+        fprintf(stderr,"Cannot open GIF file '%s' !\n",filename);
+       CloseAll();
+       exit(-1);
+      case GIF_ReadFailed:
+        fprintf(stderr,"Cannot read GIF file '%s' !\n",filename);
+       CloseAll();
+       exit(-1);
+      case GIF_FileInvalid:
+       fprintf(stderr,"Invalid GIF file '%s'!\n",filename);
+       CloseAll();
+       exit(-1);
+      case GIF_NoMemory:
+       fprintf(stderr,"Not enough memory for GIF file '%s'!\n",filename);
+       CloseAll();
+       exit(1);
+      case GIF_ColorFailed:
+       fprintf(stderr,"Can't get colors for GIF file '%s'!\n",filename);
+       CloseAll();
+       exit(-1);
+      default:
+       break;
+    }
+
+#endif
+
+#ifdef DEBUG_TIMING
+    count2 = Counter();
+    printf("LOADING %s IN %.2f SECONDS\n",
+          filename,(float)(count2-count1)/100.0);
+#endif
+
     if (!pix[pos])
     {
-      fprintf(stderr, "%s: cannot read Xpm file '%s'.\n",
+      fprintf(stderr, "%s: cannot read graphics file '%s'.\n",
              progname,filename);
       CloseAll();
       exit(-1);
@@ -407,10 +510,17 @@ void LoadGfx(int pos, struct PictureFile *pic)
   }
 
   /* zugehörige Maske laden (wenn vorhanden) */
-  if (pic->picturemask_filename)
+  if (pic->picture_with_mask)
   {
-    DrawInitText(pic->picturemask_filename,150,FC_YELLOW);
-    sprintf(filename,"%s/%s",GFX_PATH,pic->picturemask_filename);
+    sprintf(basefilename,"%s%s",pic->picture_filename,picturemask_ext);
+    DrawInitText(basefilename,150,FC_YELLOW);
+    sprintf(filename,"%s/%s",GFX_PATH,basefilename);
+
+#ifdef DEBUG_TIMING
+    count1 = Counter();
+#endif
+
+#ifdef XPM_INCLUDE_FILE
 
     xbm_err = XReadBitmapFile(display,window,filename,
                              &width,&height,&clipmask[pos],&hot_x,&hot_y);
@@ -437,9 +547,45 @@ void LoadGfx(int pos, struct PictureFile *pic)
        break;
     }
 
+#else
+
+    ilbm_err = Read_ILBM_to_Bitmap(display,filename,&clipmask[pos]);
+
+    switch(ilbm_err)
+    {
+      case ILBM_Success:
+        break;
+      case ILBM_OpenFailed:
+        fprintf(stderr,"Cannot open ILBM file '%s' !\n",filename);
+       CloseAll();
+       exit(-1);
+      case ILBM_ReadFailed:
+        fprintf(stderr,"Cannot read ILBM file '%s' !\n",filename);
+       CloseAll();
+       exit(-1);
+      case ILBM_FileInvalid:
+       fprintf(stderr,"Invalid ILBM file '%s'!\n",filename);
+       CloseAll();
+       exit(-1);
+      case ILBM_NoMemory:
+       fprintf(stderr,"Not enough memory for ILBM file '%s'!\n",filename);
+       CloseAll();
+       exit(1);
+      default:
+       break;
+    }
+
+#endif
+
+#ifdef DEBUG_TIMING
+    count2 = Counter();
+    printf("LOADING %s IN %.2f SECONDS\n",
+          filename,(float)(count2-count1)/100.0);
+#endif
+
     if (!clipmask[pos])
     {
-      fprintf(stderr, "%s: cannot read X11 bitmap file '%s'.\n",
+      fprintf(stderr, "%s: cannot read graphics file '%s'.\n",
              progname,filename);
       CloseAll();
       exit(-1);
@@ -470,16 +616,6 @@ void InitElementProperties()
   };
   static int ep_amoeboid_num = sizeof(ep_amoeboid)/sizeof(int);
 
-  static int ep_badewannoid[] =
-  {
-    EL_BADEWANNE1,
-    EL_BADEWANNE2,
-    EL_BADEWANNE3,
-    EL_BADEWANNE4,
-    EL_BADEWANNE5
-  };
-  static int ep_badewannoid_num = sizeof(ep_badewannoid)/sizeof(int);
-
   static int ep_schluessel[] =
   {
     EL_SCHLUESSEL1,
@@ -573,7 +709,8 @@ void InitElementProperties()
     EL_BIRNE_EIN,
     EL_BIRNE_AUS,
     EL_BADEWANNE1,
-    EL_BADEWANNE2
+    EL_BADEWANNE2,
+    EL_SONDE
   };
   static int ep_slippery_num = sizeof(ep_slippery)/sizeof(int);
 
@@ -585,7 +722,7 @@ void InitElementProperties()
     EL_FIREFLY,
     EL_MAMPFER,
     EL_MAMPFER2,
-    EL_ZOMBIE,
+    EL_ROBOT,
     EL_PACMAN
   };
   static int ep_enemy_num = sizeof(ep_enemy)/sizeof(int);
@@ -672,8 +809,13 @@ void InitElementProperties()
     EL_FIREFLY,
     EL_MAMPFER,
     EL_MAMPFER2,
-    EL_ZOMBIE,
-    EL_PACMAN
+    EL_ROBOT,
+    EL_PACMAN,
+    EL_MAULWURF,
+    EL_PINGUIN,
+    EL_SCHWEIN,
+    EL_DRACHE,
+    EL_SONDE
   };
   static int ep_can_move_num = sizeof(ep_can_move)/sizeof(int);
 
@@ -719,7 +861,7 @@ void InitElementProperties()
     EL_FIREFLY,
     EL_MAMPFER,
     EL_MAMPFER2,
-    EL_ZOMBIE,
+    EL_ROBOT,
     EL_PACMAN,
     EL_TROPFEN,
     EL_SALZSAEURE
@@ -734,7 +876,7 @@ void InitElementProperties()
     EL_BUTTERFLY,
     EL_FIREFLY,
     EL_MAMPFER,
-    EL_ZOMBIE,
+    EL_ROBOT,
     EL_PACMAN,
     EL_TROPFEN,
     EL_AMOEBE_TOT,
@@ -852,11 +994,51 @@ void InitElementProperties()
   };
   static int ep_inactive_num = sizeof(ep_inactive)/sizeof(int);
 
+  static int ep_explosive[] =
+  {
+    EL_BOMBE,
+    EL_DYNAMIT,
+    EL_DYNAMIT_AUS,
+    EL_DYNABOMB,
+    EL_DYNABOMB_NR,
+    EL_DYNABOMB_SZ,
+    EL_DYNABOMB_XL,
+    EL_KAEFER,
+    EL_MAULWURF,
+    EL_PINGUIN,
+    EL_SCHWEIN,
+    EL_DRACHE,
+    EL_SONDE
+  };
+  static int ep_explosive_num = sizeof(ep_explosive)/sizeof(int);
+
+  static int ep_mampf3[] =
+  {
+    EL_EDELSTEIN,
+    EL_EDELSTEIN_BD,
+    EL_EDELSTEIN_GELB,
+    EL_EDELSTEIN_ROT,
+    EL_EDELSTEIN_LILA,
+    EL_DIAMANT
+  };
+  static int ep_mampf3_num = sizeof(ep_mampf3)/sizeof(int);
+
+  static int ep_pushable[] =
+  {
+    EL_FELSBROCKEN,
+    EL_BOMBE,
+    EL_KOKOSNUSS,
+    EL_ZEIT_LEER,
+    EL_SOKOBAN_FELD_VOLL,
+    EL_SOKOBAN_OBJEKT,
+    EL_SONDE
+  };
+  static int ep_pushable_num = sizeof(ep_pushable)/sizeof(int);
+
   static long ep_bit[] =
   {
     EP_BIT_AMOEBALIVE,
     EP_BIT_AMOEBOID,
-    EP_BIT_BADEWANNOID,
     EP_BIT_SCHLUESSEL,
     EP_BIT_PFORTE,
     EP_BIT_SOLID,
@@ -875,13 +1057,15 @@ void InitElementProperties()
     EP_BIT_BD_ELEMENT,
     EP_BIT_SB_ELEMENT,
     EP_BIT_GEM,
-    EP_BIT_INACTIVE
+    EP_BIT_INACTIVE,
+    EP_BIT_EXPLOSIVE,
+    EP_BIT_MAMPF3,
+    EP_BIT_PUSHABLE
   };
   static int *ep_array[] =
   {
     ep_amoebalive,
     ep_amoeboid,
-    ep_badewannoid,
     ep_schluessel,
     ep_pforte,
     ep_solid,
@@ -900,13 +1084,15 @@ void InitElementProperties()
     ep_bd_element,
     ep_sb_element,
     ep_gem,
-    ep_inactive
+    ep_inactive,
+    ep_explosive,
+    ep_mampf3,
+    ep_pushable
   };
   static int *ep_num[] =
   {
     &ep_amoebalive_num,
     &ep_amoeboid_num,
-    &ep_badewannoid_num,
     &ep_schluessel_num,
     &ep_pforte_num,
     &ep_solid_num,
@@ -925,7 +1111,10 @@ void InitElementProperties()
     &ep_bd_element_num,
     &ep_sb_element_num,
     &ep_gem_num,
-    &ep_inactive_num
+    &ep_inactive_num,
+    &ep_explosive_num,
+    &ep_mampf3_num,
+    &ep_pushable_num
   };
   static int num_properties = sizeof(ep_num)/sizeof(int *);
 
@@ -954,12 +1143,14 @@ void CloseAll()
   {
     if (pix[i])
     {
+#ifdef XPM_INCLUDE_FILE
       if (i<NUM_PICTURES)      /* XPM pictures */
       {
        XFreeColors(display,DefaultColormap(display,screen),
                    xpm_att[i].pixels,xpm_att[i].npixels,0);
        XpmFreeAttributes(&xpm_att[i]);
       }
+#endif
       XFreePixmap(display,pix[i]);
     }
     if (clipmask[i])
index 43970fd..a402531 100644 (file)
 #include "main.h"
 
 void OpenAll(int, char **);
-void InitLevelAndPlayerInfo(void);
-void InitDisplay(int, char **);
-void InitSound(void);
-void InitSoundProcess(void);
-void InitJoystick(void);
-void InitWindow(int, char **);
-void InitGfx(void);
-void LoadGfx(int, struct PictureFile *);
-void InitElementProperties(void);
 void CloseAll();
+void InitJoystick(void);
 
 #endif
diff --git a/src/joystick.c b/src/joystick.c
new file mode 100644 (file)
index 0000000..3855400
--- /dev/null
@@ -0,0 +1,159 @@
+/***********************************************************
+*  Rocks'n'Diamonds -- McDuffin Strikes Back!              *
+*----------------------------------------------------------*
+*  ©1995 Artsoft Development                               *
+*        Holger Schemel                                    *
+*        33604 Bielefeld                                   *
+*        Telefon: (0521) 290471                            *
+*        eMail: aeglos@valinor.owl.de                      *
+*               aeglos@uni-paderborn.de                    *
+*----------------------------------------------------------*
+*  joystick.c                                              *
+***********************************************************/
+
+#ifdef __FreeBSD__
+#include <machine/joystick.h>
+#endif
+
+#include "joystick.h"
+
+/*
+#include "tools.h"
+#include "game.h"
+#include "events.h"
+#include "sound.h"
+#include "misc.h"
+#include "buttons.h"
+#include <math.h>
+*/
+
+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()
+{
+#ifdef __FreeBSD__
+  struct joystick joy_ctrl;
+#else
+  struct joystick_control
+  {
+    int buttons;
+    int x;
+    int y;
+  } joy_ctrl;
+#endif
+
+  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;
+#ifdef __FreeBSD__
+  js_b1 = joy_ctrl.b1;
+  js_b2 = joy_ctrl.b2;
+#else
+  js_b1 = joy_ctrl.buttons & 1;
+  js_b2 = joy_ctrl.buttons & 2;
+#endif
+
+  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);
+}
diff --git a/src/joystick.h b/src/joystick.h
new file mode 100644 (file)
index 0000000..64a8166
--- /dev/null
@@ -0,0 +1,64 @@
+/***********************************************************
+*  Rocks'n'Diamonds -- McDuffin Strikes Back!              *
+*----------------------------------------------------------*
+*  ©1997 Artsoft Development                               *
+*        Holger Schemel                                    *
+*        33604 Bielefeld                                   *
+*        Telefon: (0521) 290471                            *
+*        eMail: aeglos@valinor.owl.de                      *
+*               aeglos@uni-paderborn.de                    *
+*----------------------------------------------------------*
+*  joystick.h                                              *
+***********************************************************/
+
+#ifndef JOYSTICK_H
+#define JOYSTICK_H
+
+#include "main.h"
+
+/* values for the joystick */
+#define JOYSTICK_OFF           0
+#define        JOYSTICK_AVAILABLE      1
+#ifdef __FreeBSD__
+#include <machine/joystick.h>
+#define DEV_JOYSTICK_0         "/dev/joy0"
+#define DEV_JOYSTICK_1         "/dev/joy1"
+#else
+#define DEV_JOYSTICK_0         "/dev/js0"
+#define DEV_JOYSTICK_1         "/dev/js1"
+#endif
+
+/* 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
+
+
+void CheckJoystickData(void);
+int JoystickPosition(int, int, int);
+int Joystick(void);
+int JoystickButton(void);
+
+#endif
index 0c9d1f1..2db25f2 100644 (file)
@@ -16,6 +16,7 @@
 #include "init.h"
 #include "events.h"
 #include "sound.h"
+#include "joystick.h"
 
 Display        *display;
 int            screen;
@@ -23,7 +24,11 @@ Window       window;
 GC             gc, clip_gc[NUM_PIXMAPS];
 Pixmap         pix[NUM_PIXMAPS];
 Pixmap         clipmask[NUM_PIXMAPS];
+
+#ifdef XPM_INCLUDE_FILE
 XpmAttributes  xpm_att[NUM_PICTURES];
+#endif
+
 Drawable        drawto, drawto_field, backbuffer;
 Colormap       cmap;
 
@@ -75,9 +80,12 @@ long         Elementeigenschaften[MAX_ELEMENTS];
 int            level_nr, leveldir_nr, num_leveldirs;
 int            lev_fieldx,lev_fieldy, scroll_x,scroll_y;
 
-int            LevelSolved,GameOver, JX,JY, ZX,ZY;
+int            JX,JY, ZX,ZY, ExitX,ExitY;
+int            PlayerMovDir, PlayerFrame, PlayerPushing;
+int            PlayerGone,LevelSolved,GameOver;
 int            FrameCounter,TimeFrames,TimeLeft,Score;
-int            Gems,SokobanFields,Lights,Dynamite,Key[4],MampferNr;
+int            Gems,SokobanFields,Lights,Friends;
+int            Dynamite,Key[4],MampferNr;
 int            DynaBombCount, DynaBombSize, DynaBombsLeft, DynaBombXL;
 int            SiebAktiv;
 
index 6cf2bb2..36c0978 100644 (file)
@@ -26,8 +26,6 @@
 
 #ifdef   XPM_INCLUDE_FILE
 #include XPM_INCLUDE_FILE
-#else
-#include "YOU HAVE TO SET 'XPM_INCLUDE_FILE' IN THE 'Makefile'!!!"
 #endif
 
 #include <sys/types.h>
@@ -75,31 +73,32 @@ typedef int BOOL;
 
 #define EP_BIT_AMOEBALIVE      (1<<0)
 #define EP_BIT_AMOEBOID                (1<<1)
-#define EP_BIT_BADEWANNOID     (1<<2)
-#define EP_BIT_SCHLUESSEL      (1<<3)
-#define EP_BIT_PFORTE          (1<<4)
-#define EP_BIT_SOLID           (1<<5)
-#define EP_BIT_MASSIV          (1<<6)
-#define EP_BIT_SLIPPERY                (1<<7)
-#define EP_BIT_ENEMY           (1<<8)
-#define EP_BIT_MAUER           (1<<9)
-#define EP_BIT_CAN_FALL                (1<<10)
-#define EP_BIT_CAN_SMASH       (1<<11)
-#define EP_BIT_CAN_CHANGE      (1<<12)
-#define EP_BIT_CAN_MOVE                (1<<13)
-#define EP_BIT_COULD_MOVE      (1<<14)
-#define EP_BIT_DONT_TOUCH      (1<<15)
-#define EP_BIT_DONT_GO_TO      (1<<16)
-#define EP_BIT_MAMPF2          (1<<17)
-#define EP_BIT_CHAR            (1<<18)
-#define EP_BIT_BD_ELEMENT      (1<<19)
-#define EP_BIT_SB_ELEMENT      (1<<20)
-#define EP_BIT_GEM             (1<<21)
-#define EP_BIT_INACTIVE                (1<<22)
+#define EP_BIT_SCHLUESSEL      (1<<2)
+#define EP_BIT_PFORTE          (1<<3)
+#define EP_BIT_SOLID           (1<<4)
+#define EP_BIT_MASSIV          (1<<5)
+#define EP_BIT_SLIPPERY                (1<<6)
+#define EP_BIT_ENEMY           (1<<7)
+#define EP_BIT_MAUER           (1<<8)
+#define EP_BIT_CAN_FALL                (1<<9)
+#define EP_BIT_CAN_SMASH       (1<<10)
+#define EP_BIT_CAN_CHANGE      (1<<11)
+#define EP_BIT_CAN_MOVE                (1<<12)
+#define EP_BIT_COULD_MOVE      (1<<13)
+#define EP_BIT_DONT_TOUCH      (1<<14)
+#define EP_BIT_DONT_GO_TO      (1<<15)
+#define EP_BIT_MAMPF2          (1<<16)
+#define EP_BIT_CHAR            (1<<17)
+#define EP_BIT_BD_ELEMENT      (1<<18)
+#define EP_BIT_SB_ELEMENT      (1<<19)
+#define EP_BIT_GEM             (1<<20)
+#define EP_BIT_INACTIVE                (1<<21)
+#define EP_BIT_EXPLOSIVE       (1<<22)
+#define EP_BIT_MAMPF3          (1<<23)
+#define EP_BIT_PUSHABLE                (1<<24)
 
 #define IS_AMOEBALIVE(e)       (Elementeigenschaften[e] & EP_BIT_AMOEBALIVE)
 #define IS_AMOEBOID(e)         (Elementeigenschaften[e] & EP_BIT_AMOEBOID)
-#define IS_BADEWANNOID(e)      (Elementeigenschaften[e] & EP_BIT_BADEWANNOID)
 #define IS_SCHLUESSEL(e)       (Elementeigenschaften[e] & EP_BIT_SCHLUESSEL)
 #define IS_PFORTE(e)           (Elementeigenschaften[e] & EP_BIT_PFORTE)
 #define IS_SOLID(e)            (Elementeigenschaften[e] & EP_BIT_SOLID)
@@ -120,6 +119,9 @@ typedef int BOOL;
 #define IS_SB_ELEMENT(e)       (Elementeigenschaften[e] & EP_BIT_SB_ELEMENT)
 #define IS_GEM(e)              (Elementeigenschaften[e] & EP_BIT_GEM)
 #define IS_INACTIVE(e)         (Elementeigenschaften[e] & EP_BIT_INACTIVE)
+#define IS_EXPLOSIVE(e)                (Elementeigenschaften[e] & EP_BIT_EXPLOSIVE)
+#define IS_MAMPF3(e)           (Elementeigenschaften[e] & EP_BIT_MAMPF3)
+#define IS_PUSHABLE(e)         (Elementeigenschaften[e] & EP_BIT_PUSHABLE)
 
 #define EL_CHANGED(e)          ((e)==EL_FELSBROCKEN    ? EL_EDELSTEIN :  \
                                 (e)==EL_EDELSTEIN      ? EL_DIAMANT :    \
@@ -138,15 +140,16 @@ typedef int BOOL;
 /* 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
+#define PIX_HEROES             2
+#define PIX_TOONS              3
+#define        PIX_BIGFONT             4
+#define PIX_SMALLFONT          5
 /* Pixmaps without them */
-#define PIX_DB_BACK            5
-#define PIX_DB_DOOR            6
+#define PIX_DB_BACK            6
+#define PIX_DB_DOOR            7
 
-#define NUM_PICTURES           5
-#define NUM_PIXMAPS            7
+#define NUM_PICTURES           6
+#define NUM_PIXMAPS            8
 
 /* boundaries of arrays etc. */
 #define MAX_NAMELEN            (10+1)
@@ -165,12 +168,6 @@ typedef int BOOL;
 #define MAX_NUM_AMOEBA         100
 #define MAX_ELEMENTS           512
 
-struct PictureFile
-{
-  char *picture_filename;
-  char *picturemask_filename;
-};
-
 struct HiScore
 {
   char Name[MAX_NAMELEN];
@@ -220,9 +217,9 @@ struct RecordingInfo
   unsigned long length_seconds;
   unsigned int delay_played;
   BOOL pause_before_death;
-  BOOL changed;
   BOOL recording, playing, pausing;
   BOOL fast_forward;
+  BOOL changed;
   struct
   {
     unsigned char joystickdata;
@@ -243,7 +240,11 @@ extern GC          gc, clip_gc[];
 extern XImage         *image[];
 extern Pixmap          clipmask[];
 extern Pixmap          pix[];
+
+#ifdef XPM_INCLUDE_FILE
 extern XpmAttributes   xpm_att[];
+#endif
+
 extern Drawable        drawto, drawto_field, backbuffer;
 extern Colormap                cmap;
 
@@ -294,9 +295,12 @@ extern long                Elementeigenschaften[MAX_ELEMENTS];
 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             JX,JY, ZX,ZY, ExitX,ExitY;
+extern int             PlayerMovDir, PlayerFrame, PlayerPushing;
+extern int             PlayerGone,LevelSolved,GameOver;
 extern int             FrameCounter,TimeFrames,TimeLeft,Score;
-extern int             Gems,SokobanFields,Lights,Dynamite,Key[4],MampferNr;
+extern int             Gems,SokobanFields,Lights,Friends;
+extern int             Dynamite,Key[4],MampferNr;
 extern int             DynaBombCount, DynaBombSize, DynaBombsLeft, DynaBombXL;
 extern int             SiebAktiv;
 
@@ -305,8 +309,10 @@ extern struct LevelInfo            level;
 extern struct PlayerInfo       player;
 extern struct HiScore          highscore[];
 extern struct RecordingInfo    tape;
+extern struct SoundInfo                Sound[];
 extern struct JoystickInfo     joystick[];
 
+extern char            *sound_name[];
 extern int             background_loop[];
 extern int             num_bg_loops;
 
@@ -361,6 +367,7 @@ extern char         *progname;
 #define GFX_PER_LINE           16
 #define MINI_GFX_PER_LINE      32
 #define MICRO_GFX_PER_LINE     128
+#define HEROES_PER_LINE                16
 #define FONT_CHARS_PER_LINE    16
 #define FONT_LINES_PER_FONT    4
 
@@ -381,7 +388,7 @@ extern char         *progname;
 #define EL_KAEFER              9
 #define EL_FLIEGER             10
 #define EL_MAMPFER             11
-#define EL_ZOMBIE              12
+#define EL_ROBOT               12
 #define EL_BETON               13
 #define EL_DIAMANT             14
 #define EL_AMOEBE_TOT          15
@@ -487,6 +494,17 @@ extern char                *progname;
 #define EL_AUSGANG_AUF         107
 #define EL_SIEB2_TOT           108
 #define EL_AMOEBA2DIAM         109
+#define EL_MAULWURF            110
+#define EL_PINGUIN             111
+#define EL_SONDE               112
+#define EL_PFEIL_L             113
+#define EL_PFEIL_R             114
+#define EL_PFEIL_O             115
+#define EL_PFEIL_U             116
+#define EL_SCHWEIN             117
+#define EL_DRACHE              118
+
+#define EL_UNUSED_119          119
 
 #define EL_CHAR_START          120
 #define EL_CHAR_ASCII0         (EL_CHAR_START-32)
@@ -519,6 +537,10 @@ extern char                *progname;
 #define EL_CHAR_COPY           (EL_CHAR_ASCII0+94)
 #define EL_CHAR_END            (EL_CHAR_START+79)
 
+#define EL_UNUSED_200          200
+/* ... */
+#define EL_UNUSED_255          255
+
 /* "unreal" runtime elements */
 #define EL_BLOCKED             300
 #define EL_EXPLODING           301
@@ -527,8 +549,22 @@ extern char                *progname;
 #define EL_BLURB_RIGHT         304
 #define EL_AMOEBING            305
 #define EL_MAUERND             306
+#define EL_BURNING             307
+
+/* game graphics:
+**       0 - 255: graphics from "RocksScreen"
+**     256 - 511: graphics from "RocksFont"
+**     512 - 767: graphics from "RocksHeroes"
+*/
 
-/* names for the graphic objects */
+#define GFX_START_ROCKSSCREEN  0
+#define GFX_END_ROCKSSCREEN    255
+#define GFX_START_ROCKSFONT    256
+#define GFX_END_ROCKSFONT      511
+#define GFX_START_ROCKSHEROES  512
+#define GFX_END_ROCKSHEROES    767
+
+/* graphics from "RocksScreen" */
 /* Zeile 0 (0) */
 #define GFX_LEERRAUM           (-1)
 #define        GFX_ERDREICH            0
@@ -560,7 +596,7 @@ extern char         *progname;
 #define GFX_BADEWANNE3         32
 #define GFX_BADEWANNE4         33
 #define GFX_BADEWANNE5         34
-#define        GFX_SPIELFIGUR          35
+#define        GFX_SMILEY              35
 #define GFX_PFORTE1            36
 #define GFX_PFORTE2            37
 #define GFX_PFORTE3            38
@@ -586,7 +622,7 @@ extern char         *progname;
 #define GFX_KAEFER_U           75
 /* Zeile 5 (80) */
 #define GFX_MAMPFER            80
-#define GFX_ZOMBIE             84
+#define GFX_ROBOT              84
 #define GFX_PACMAN             88
 #define GFX_PACMAN_R           88
 #define GFX_PACMAN_O           89
@@ -608,6 +644,10 @@ extern char                *progname;
 #define GFX_BIRNE_EIN          113
 #define GFX_ZEIT_VOLL          114
 #define GFX_ZEIT_LEER          115
+#define GFX_SPIELER1           116
+#define GFX_SPIELER2           117
+#define GFX_SPIELER3           118
+#define GFX_SPIELER4           119
 #define GFX_AMOEBE_VOLL                120
 #define GFX_AMOEBE_BD          GFX_AMOEBE_VOLL
 #define GFX_SOKOBAN_OBJEKT     121
@@ -630,11 +670,14 @@ extern char               *progname;
 #define GFX_KUGEL_GELB         142
 #define GFX_KUGEL_GRAU         143
 /* Zeile 9 (144) */
-#define GFX_BLURB_LEFT         144
-#define GFX_BLURB_RIGHT                148
+#define GFX_PINGUIN            144
+#define GFX_MAULWURF           145
+#define GFX_SCHWEIN            146
+#define GFX_DRACHE             147
 #define GFX_EDELSTEIN_ROT      152
 #define GFX_EDELSTEIN_LILA     154
 #define GFX_DYNABOMB_XL                156
+#define GFX_SONDE              159
 /* Zeile 10 (160) */
 #define GFX_EDELSTEIN_BD       163
 #define GFX_MAUER_R1           165
@@ -669,15 +712,44 @@ extern char               *progname;
 #define GFX_FIREFLY_L          206
 #define GFX_FIREFLY_U          207
 
-#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_SCHLUESSEL         GFX_SCHLUESSEL1
+#define GFX_SPIELFIGUR         GFX_SPIELER1
+
+
+/* graphics from "RocksHeroes" */
+
+#define GFX_SPIELER_DOWN       (GFX_START_ROCKSHEROES + 0*HEROES_PER_LINE + 0)
+#define GFX_SPIELER_UP         (GFX_START_ROCKSHEROES + 0*HEROES_PER_LINE + 4)
+#define GFX_SPIELER_LEFT       (GFX_START_ROCKSHEROES + 1*HEROES_PER_LINE + 0)
+#define GFX_SPIELER_RIGHT      (GFX_START_ROCKSHEROES + 1*HEROES_PER_LINE + 4)
+#define GFX_SPIELER_PUSH_RIGHT (GFX_START_ROCKSHEROES + 2*HEROES_PER_LINE + 0)
+#define GFX_SPIELER_PUSH_LEFT  (GFX_START_ROCKSHEROES + 2*HEROES_PER_LINE + 4)
+#define GFX_SONDE_START                (GFX_START_ROCKSHEROES + 7*HEROES_PER_LINE + 0)
+#define GFX_SCHWEIN_DOWN       (GFX_START_ROCKSHEROES + 0*HEROES_PER_LINE + 8)
+#define GFX_SCHWEIN_UP         (GFX_START_ROCKSHEROES + 0*HEROES_PER_LINE +12)
+#define GFX_SCHWEIN_LEFT       (GFX_START_ROCKSHEROES + 1*HEROES_PER_LINE + 8)
+#define GFX_SCHWEIN_RIGHT      (GFX_START_ROCKSHEROES + 1*HEROES_PER_LINE +12)
+#define GFX_DRACHE_DOWN                (GFX_START_ROCKSHEROES + 2*HEROES_PER_LINE + 8)
+#define GFX_DRACHE_UP          (GFX_START_ROCKSHEROES + 2*HEROES_PER_LINE +12)
+#define GFX_DRACHE_LEFT                (GFX_START_ROCKSHEROES + 3*HEROES_PER_LINE + 8)
+#define GFX_DRACHE_RIGHT       (GFX_START_ROCKSHEROES + 3*HEROES_PER_LINE +12)
+#define GFX_MAULWURF_DOWN      (GFX_START_ROCKSHEROES + 4*HEROES_PER_LINE + 8)
+#define GFX_MAULWURF_UP                (GFX_START_ROCKSHEROES + 4*HEROES_PER_LINE +12)
+#define GFX_MAULWURF_LEFT      (GFX_START_ROCKSHEROES + 5*HEROES_PER_LINE + 8)
+#define GFX_MAULWURF_RIGHT     (GFX_START_ROCKSHEROES + 5*HEROES_PER_LINE +12)
+#define GFX_PINGUIN_DOWN       (GFX_START_ROCKSHEROES + 7*HEROES_PER_LINE + 8)
+#define GFX_PINGUIN_UP         (GFX_START_ROCKSHEROES + 7*HEROES_PER_LINE +12)
+#define GFX_PINGUIN_LEFT       (GFX_START_ROCKSHEROES + 8*HEROES_PER_LINE + 8)
+#define GFX_PINGUIN_RIGHT      (GFX_START_ROCKSHEROES + 8*HEROES_PER_LINE +12)
+#define GFX_BLURB_LEFT         (GFX_START_ROCKSHEROES + 9*HEROES_PER_LINE + 8)
+#define GFX_BLURB_RIGHT                (GFX_START_ROCKSHEROES + 9*HEROES_PER_LINE +12)
+#define GFX_FLAMMEN_LEFT       (GFX_START_ROCKSHEROES + 8*HEROES_PER_LINE + 0)
+#define GFX_FLAMMEN_RIGHT      (GFX_START_ROCKSHEROES + 9*HEROES_PER_LINE + 0)
+#define GFX_FLAMMEN_UP         (GFX_START_ROCKSHEROES +10*HEROES_PER_LINE + 0)
+#define GFX_FLAMMEN_DOWN       (GFX_START_ROCKSHEROES +11*HEROES_PER_LINE + 0)
+
+/* graphics from "RocksFont" */
+#define GFX_CHAR_START         (GFX_START_ROCKSFONT)
 #define GFX_CHAR_ASCII0                (GFX_CHAR_START-32)
 #define GFX_CHAR_AUSRUF                (GFX_CHAR_ASCII0+33)
 #define GFX_CHAR_ZOLL          (GFX_CHAR_ASCII0+34)
@@ -714,7 +786,7 @@ extern char         *progname;
 #define SC_KAEFER              2
 #define SC_FLIEGER             3
 #define SC_MAMPFER             4
-#define SC_ZOMBIE              5
+#define SC_ROBOT               5
 #define SC_PACMAN              6
 #define SC_KOKOSNUSS           7
 #define SC_DYNAMIT             8
@@ -783,10 +855,7 @@ extern char                *progname;
                                 (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
@@ -822,44 +891,6 @@ extern struct SoundInfo Sound[NUM_SOUNDS];
 #define EMU_BOULDERDASH                1
 #define EMU_SOKOBAN            2
 
-/* values for the joystick */
-#define JOYSTICK_OFF           0
-#define        JOYSTICK_AVAILABLE      1
-#ifdef __FreeBSD__
-#include <machine/joystick.h>
-#define DEV_JOYSTICK_0         "/dev/joy0"
-#define DEV_JOYSTICK_1         "/dev/joy1"
-#else
-#define DEV_JOYSTICK_0         "/dev/js0"
-#define DEV_JOYSTICK_1         "/dev/js1"
-#endif
-
-/* 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               "."
@@ -932,6 +963,7 @@ extern struct SoundInfo Sound[NUM_SOUNDS];
 #define MB_PRESSED             TRUE
 #define MB_MENU_CHOICE         FALSE
 #define MB_MENU_MARK           TRUE
+#define MB_MENU_INITIALIZE     (-1)
 #define MB_LEFT                        1
 #define MB_MIDDLE              2
 #define MB_RIGHT               3
@@ -941,10 +973,6 @@ extern struct SoundInfo Sound[NUM_SOUNDS];
 #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)
@@ -1003,4 +1031,8 @@ extern struct SoundInfo Sound[NUM_SOUNDS];
 #define DOOR_GFX_PAGEY1                0
 #define DOOR_GFX_PAGEY2                DYSIZE
 
+/* für DrawGraphicAnimation (tools.c) und AnimateToon (cartoons.c) */
+#define ANIM_NORMAL    0
+#define ANIM_OSCILLATE 1
+
 #endif
index 61683e6..b912732 100644 (file)
@@ -15,6 +15,8 @@
 #include "misc.h"
 #include "tools.h"
 #include "sound.h"
+#include "random.h"
+
 #include <pwd.h>
 #include <unistd.h>
 #include <time.h>
@@ -116,13 +118,6 @@ BOOL FrameReached(long *frame_counter_var, int frame_delay)
     return(FALSE);
 }
 
-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];
@@ -143,7 +138,7 @@ unsigned int SimpleRND(unsigned int max)
 
 unsigned int RND(unsigned int max)
 {
-  return(rand() % max);
+  return(random_linux_libc() % max);
 }
 
 unsigned int InitRND(long seed)
@@ -153,12 +148,12 @@ unsigned int InitRND(long seed)
   if (seed==NEW_RANDOMIZE)
   {
     gettimeofday(&current_time,NULL);
-    srand((unsigned int) current_time.tv_usec);
+    srandom_linux_libc((unsigned int) current_time.tv_usec);
     return((unsigned int) current_time.tv_usec);
   }
   else
   {
-    srand((unsigned int) seed);
+    srandom_linux_libc((unsigned int) seed);
     return((unsigned int) seed);
   }
 }
@@ -172,329 +167,3 @@ char *GetLoginName()
   else
     return(pwd->pw_name);
 }
-
-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;
-  int draw_mode;
-
-/*
-  if (!toons_on || game_status==PLAYING)
-    return;
-*/
-
-/*
-  if (!toons_on || tape.playing || tape.recording)
-    return;
-*/
-
-  if (!toons_on)
-    return;
-
-  switch(mode)
-  {
-    case ANIM_START:
-      anim_restart = TRUE;
-      reset_delay = TRUE;
-
-      /* Fill empty backbuffer for animation functions */
-      if (direct_draw_on && game_status==PLAYING)
-      {
-       int xx,yy;
-
-       drawto_field = backbuffer;
-
-       for(xx=0;xx<SCR_FIELDX;xx++)
-         for(yy=0;yy<SCR_FIELDY;yy++)
-           DrawScreenField(xx,yy);
-       DrawLevelElement(JX,JY,EL_SPIELFIGUR);
-
-       drawto_field = window;
-      }
-
-      return;
-      break;
-    case ANIM_CONTINUE:
-      break;
-    case ANIM_STOP:
-      redraw_mask |= REDRAW_FIELD;
-
-      /* Redraw background even when in direct drawing mode */
-      draw_mode = direct_draw_on;
-      direct_draw_on = FALSE;
-
-      BackToFront();
-
-      direct_draw_on = draw_mode;
-
-      return;
-      break;
-    default:
-      break;
-  }
-
-  if (reset_delay)
-  {
-    animstart_delay = Counter();
-    animstart_delay_value = SimpleRND(500);
-    reset_delay = FALSE;
-  }
-
-  if (anim_restart)
-  {
-    if (!DelayReached(&animstart_delay,animstart_delay_value))
-      return;
-
-    toon_nr = SimpleRND(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;
-  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;
-  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}
-  };
-  struct AnimInfo *anim = &toon[toon_nr];
-
-  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 = SimpleRND((FULL_SYSIZE-anim->height)/2);
-      else
-       pos_y = SimpleRND(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 = SimpleRND(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;
-
-#if 1
-  /* special method to avoid flickering interference with BackToFront() */
-  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);
-#else
-  /* normal method, causing flickering interference with BackToFront() */
-  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);
-#endif
-
-  XFlush(display);
-}
index 685c2b8..1a2f29f 100644 (file)
 
 #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 INIT_COUNTER           0
 #define READ_COUNTER_100       1
 #define READ_COUNTER_1000      2
@@ -96,18 +33,10 @@ void WaitCounter2(long);
 void Delay(long);
 BOOL DelayReached(long *, int);
 BOOL FrameReached(long *, int);
-unsigned long be2long(unsigned long *);
 char *int2str(int, int);
 unsigned int SimpleRND(unsigned 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/random.c b/src/random.c
new file mode 100644 (file)
index 0000000..bbac6e5
--- /dev/null
@@ -0,0 +1,227 @@
+/*
+ * Copyright (c) 1983 Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that the above copyright notice and this paragraph are
+ * duplicated in all such forms and that any documentation,
+ * advertising materials, and other materials related to such
+ * distribution and use acknowledge that the software was developed
+ * by the University of California, Berkeley.  The name of the
+ * University may not be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+/*
+ * This is derived from the Berkeley source:
+ *     @(#)random.c    5.5 (Berkeley) 7/6/88
+ * It was reworked for the GNU C Library by Roland McGrath.
+ */
+
+#include <ansidecl.h>
+#include <errno.h>
+#include <limits.h>
+#include <stddef.h>
+#include <stdlib.h>
+
+#include "random.h"
+
+
+/* An improved random number generation package.  In addition to the standard
+   rand()/srand() like interface, this package also has a special state info
+   interface.  The initstate() routine is called with a seed, an array of
+   bytes, and a count of how many bytes are being passed in; this array is
+   then initialized to contain information for random number generation with
+   that much state information.  Good sizes for the amount of state
+   information are 32, 64, 128, and 256 bytes.  The state can be switched by
+   calling the setstate() function with the same array as was initiallized
+   with initstate().  By default, the package runs with 128 bytes of state
+   information and generates far better random numbers than a linear
+   congruential generator.  If the amount of state information is less than
+   32 bytes, a simple linear congruential R.N.G. is used.  Internally, the
+   state information is treated as an array of longs; the zeroeth element of
+   the array is the type of R.N.G. being used (small integer); the remainder
+   of the array is the state information for the R.N.G.  Thus, 32 bytes of
+   state information will give 7 longs worth of state information, which will
+   allow a degree seven polynomial.  (Note: The zeroeth word of state
+   information also has some other information stored in it; see setstate
+   for details).  The random number generation technique is a linear feedback
+   shift register approach, employing trinomials (since there are fewer terms
+   to sum up that way).  In this approach, the least significant bit of all
+   the numbers in the state table will act as a linear feedback shift register,
+   and will have period 2^deg - 1 (where deg is the degree of the polynomial
+   being used, assuming that the polynomial is irreducible and primitive).
+   The higher order bits will have longer periods, since their values are
+   also influenced by pseudo-random carries out of the lower bits.  The
+   total period of the generator is approximately deg*(2**deg - 1); thus
+   doubling the amount of state information has a vast influence on the
+   period of the generator.  Note: The deg*(2**deg - 1) is an approximation
+   only good for large deg, when the period of the shift register is the
+   dominant factor.  With deg equal to seven, the period is actually much
+   longer than the 7*(2**7 - 1) predicted by this formula.  */
+
+
+
+/* For each of the currently supported random number generators, we have a
+   break value on the amount of state information (you need at least thi
+   bytes of state info to support this random number generator), a degree for
+   the polynomial (actually a trinomial) that the R.N.G. is based on, and
+   separation between the two lower order coefficients of the trinomial.  */
+
+/* Linear congruential.  */
+#define        TYPE_0          0
+#define        BREAK_0         8
+#define        DEG_0           0
+#define        SEP_0           0
+
+/* x**7 + x**3 + 1.  */
+#define        TYPE_1          1
+#define        BREAK_1         32
+#define        DEG_1           7
+#define        SEP_1           3
+
+/* x**15 + x + 1.  */
+#define        TYPE_2          2
+#define        BREAK_2         64
+#define        DEG_2           15
+#define        SEP_2           1
+
+/* x**31 + x**3 + 1.  */
+#define        TYPE_3          3
+#define        BREAK_3         128
+#define        DEG_3           31
+#define        SEP_3           3
+
+/* x**63 + x + 1.  */
+#define        TYPE_4          4
+#define        BREAK_4         256
+#define        DEG_4           63
+#define        SEP_4           1
+
+
+/* Array versions of the above information to make code run faster.
+   Relies on fact that TYPE_i == i.  */
+
+#define        MAX_TYPES       5       /* Max number of types above.  */
+
+
+
+/* Initially, everything is set up as if from:
+       initstate(1, randtbl, 128);
+   Note that this initialization takes advantage of the fact that srandom
+   advances the front and rear pointers 10*rand_deg times, and hence the
+   rear pointer which starts at 0 will also end up at zero; thus the zeroeth
+   element of the state information, which contains info about the current
+   position of the rear pointer is just
+       (MAX_TYPES * (rptr - state)) + TYPE_3 == TYPE_3.  */
+
+static long int randtbl[DEG_3 + 1] =
+{
+  TYPE_3,
+  -851904987, -43806228, -2029755270, 1390239686, -1912102820,
+  -485608943, 1969813258, -1590463333, -1944053249, 455935928, 508023712,
+  -1714531963, 1800685987, -2015299881, 654595283, -1149023258,
+  -1470005550, -1143256056, -1325577603, -1568001885, 1275120390,
+  -607508183, -205999574, -1696891592, 1492211999, -1528267240,
+  -952028296, -189082757, 362343714, 1424981831, 2039449641,
+};
+
+/* FPTR and RPTR are two pointers into the state info, a front and a rear
+   pointer.  These two pointers are always rand_sep places aparts, as they
+   cycle through the state information.  (Yes, this does mean we could get
+   away with just one pointer, but the code for random is more efficient
+   this way).  The pointers are left positioned as they would be from the call:
+       initstate(1, randtbl, 128);
+   (The position of the rear pointer, rptr, is really 0 (as explained above
+   in the initialization of randtbl) because the state table pointer is set
+   to point to randtbl[1] (as explained below).)  */
+
+static long int *fptr = &randtbl[SEP_3 + 1];
+static long int *rptr = &randtbl[1];
+
+
+
+/* The following things are the pointer to the state information table,
+   the type of the current generator, the degree of the current polynomial
+   being used, and the separation between the two pointers.
+   Note that for efficiency of random, we remember the first location of
+   the state information, not the zeroeth.  Hence it is valid to access
+   state[-1], which is used to store the type of the R.N.G.
+   Also, we remember the last location, since this is more efficient than
+   indexing every time to find the address of the last element to see if
+   the front and rear pointers have wrapped.  */
+
+static long int *state = &randtbl[1];
+
+static int rand_type = TYPE_3;
+static int rand_deg = DEG_3;
+static int rand_sep = SEP_3;
+
+static long int *end_ptr = &randtbl[sizeof(randtbl) / sizeof(randtbl[0])];
+
+/* Initialize the random number generator based on the given seed.  If the
+   type is the trivial no-state-information type, just remember the seed.
+   Otherwise, initializes state[] based on the given "seed" via a linear
+   congruential generator.  Then, the pointers are set to known locations
+   that are exactly rand_sep places apart.  Lastly, it cycles the state
+   information a given number of times to get rid of any initial dependencies
+   introduced by the L.C.R.N.G.  Note that the initialization of randtbl[]
+   for default usage relies on values produced by this routine.  */
+
+void srandom_linux_libc(unsigned int x)
+{
+  state[0] = x;
+  if (rand_type != TYPE_0)
+  {
+    register long int i;
+    for (i = 1; i < rand_deg; ++i)
+      state[i] = (1103515145 * state[i - 1]) + 12345;
+    fptr = &state[rand_sep];
+    rptr = &state[0];
+    for (i = 0; i < 10 * rand_deg; ++i)
+      (void) random_linux_libc();
+  }
+}
+
+/* If we are using the trivial TYPE_0 R.N.G., just do the old linear
+   congruential bit.  Otherwise, we do our fancy trinomial stuff, which is the
+   same in all ther other cases due to all the global variables that have been
+   set up.  The basic operation is to add the number at the rear pointer into
+   the one at the front pointer.  Then both pointers are advanced to the next
+   location cyclically in the table.  The value returned is the sum generated,
+   reduced to 31 bits by throwing away the "least random" low bit.
+   Note: The code takes advantage of the fact that both the front and
+   rear pointers can't wrap on the same call by not testing the rear
+   pointer if the front one has wrapped.  Returns a 31-bit random number.  */
+
+long int random_linux_libc()
+{
+  if (rand_type == TYPE_0)
+  {
+    state[0] = ((state[0] * 1103515245) + 12345) & LONG_MAX;
+    return state[0];
+  }
+  else
+  {
+    long int i;
+    *fptr += *rptr;
+    /* Chucking least random bit.  */
+    i = (*fptr >> 1) & LONG_MAX;
+    ++fptr;
+    if (fptr >= end_ptr)
+    {
+      fptr = state;
+      ++rptr;
+    }
+    else
+    {
+      ++rptr;
+      if (rptr >= end_ptr)
+       rptr = state;
+    }
+    return i;
+  }
+}
diff --git a/src/random.h b/src/random.h
new file mode 100644 (file)
index 0000000..0f99fff
--- /dev/null
@@ -0,0 +1,21 @@
+/***********************************************************
+*  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             *
+*----------------------------------------------------------*
+*  random.h                                                *
+***********************************************************/
+
+#ifndef RANDOM_H
+#define RANDOM_H
+
+void srandom_linux_libc(unsigned int);
+long int random_linux_libc(void);
+
+#endif
index 3a8f0bb..bfb4f11 100644 (file)
@@ -22,6 +22,8 @@
 #include "files.h"
 #include "buttons.h"
 #include "tape.h"
+#include "joystick.h"
+#include "cartoons.h"
 
 void DrawHeadline()
 {
@@ -71,7 +73,7 @@ void DrawMainMenu()
 
   FadeToFront();
   InitAnimation();
-  HandleMainMenu(0,0,0,0,MB_MENU_MARK);
+  HandleMainMenu(0,0,0,0,MB_MENU_INITIALIZE);
 
   TapeStop();
   if (TAPE_IS_EMPTY(tape))
@@ -80,6 +82,7 @@ void DrawMainMenu()
 
   OpenDoor(DOOR_CLOSE_1 | DOOR_OPEN_2);
 
+  ClearEventQueue();
   XAutoRepeatOn(display);
 }
 
@@ -89,12 +92,15 @@ void HandleMainMenu(int mx, int my, int dx, int dy, int button)
   static int redraw = TRUE;
   int x = (mx+32-SX)/32, y = (my+32-SY)/32;
 
-  if (redraw || (!mx && !my && !dx && !dy))
+  if (redraw || button == MB_MENU_INITIALIZE)
   {
     DrawGraphic(0,choice-1,GFX_KUGEL_ROT);
     redraw = FALSE;
   }
 
+  if (button == MB_MENU_INITIALIZE)
+    return;
+
   if (dx || dy)
   {
     if (dx && choice==4)
@@ -223,7 +229,8 @@ void HandleMainMenu(int mx, int my, int dx, int dy, int button)
          game_status = EXITGAME;
       }
 
-      redraw = TRUE;
+      if (!button)
+       redraw = TRUE;
     }
   }
   BackToFront();
@@ -244,7 +251,12 @@ static int helpscreen_frame[MAX_HELPSCREEN_ELS];
 static int helpscreen_delay[MAX_HELPSCREEN_ELS];
 static int helpscreen_action[] =
 {
-  GFX_SPIELFIGUR,1,100,                                                HA_NEXT,
+  GFX_SPIELER_DOWN,4,2,
+  GFX_SPIELER_UP,4,2,
+  GFX_SPIELER_LEFT,4,2,
+  GFX_SPIELER_RIGHT,4,2,
+  GFX_SPIELER_PUSH_LEFT,4,2,
+  GFX_SPIELER_PUSH_RIGHT,4,2,                                  HA_NEXT,
   GFX_ERDREICH,1,100,                                          HA_NEXT,
   GFX_LEERRAUM,1,100,                                          HA_NEXT,
   GFX_MORAST_LEER,1,100,                                       HA_NEXT,
@@ -254,7 +266,7 @@ static int helpscreen_action[] =
   GFX_MAUER_L1,3,4, GFX_MAUERWERK,1,20, GFX_LEERRAUM,1,10,     HA_NEXT,
   GFX_UNSICHTBAR,1,100,                                                HA_NEXT,
   GFX_FELSBODEN,1,100,                                         HA_NEXT,
-  GFX_CHAR_A,30,3, GFX_CHAR_AUSRUF,32,3,                       HA_NEXT,
+  GFX_CHAR_A,30,4, GFX_CHAR_AUSRUF,32,4,                       HA_NEXT,
   GFX_EDELSTEIN,2,5,                                           HA_NEXT,
   GFX_DIAMANT,2,5,                                             HA_NEXT,
   GFX_EDELSTEIN_BD,2,5,                                                HA_NEXT,
@@ -272,9 +284,9 @@ static int helpscreen_action[] =
   GFX_ERZ_EDEL_LILA,1,50, GFX_EXPLOSION,8,1,
   GFX_EDELSTEIN_LILA,1,10,                                     HA_NEXT,
   GFX_GEBLUBBER,4,4,                                           HA_NEXT,
-  GFX_SCHLUESSEL1,4,33,                                                HA_NEXT,
-  GFX_PFORTE1,4,33,                                            HA_NEXT,
-  GFX_PFORTE1X,4,33,                                           HA_NEXT,
+  GFX_SCHLUESSEL1,4,25,                                                HA_NEXT,
+  GFX_PFORTE1,4,25,                                            HA_NEXT,
+  GFX_PFORTE1X,4,25,                                           HA_NEXT,
   GFX_DYNAMIT_AUS,1,100,                                       HA_NEXT,
   GFX_DYNAMIT,7,6, GFX_EXPLOSION,8,1, GFX_LEERRAUM,1,10,       HA_NEXT,
   GFX_DYNABOMB+0,4,3, GFX_DYNABOMB+3,1,3, GFX_DYNABOMB+2,1,3,
@@ -290,36 +302,53 @@ static int helpscreen_action[] =
   GFX_KAEFER+5,1,1, GFX_KAEFER+1,1,1, GFX_KAEFER+5,1,1,
   GFX_KAEFER+6,1,1, GFX_KAEFER+2,1,1, GFX_KAEFER+6,1,1,
   GFX_KAEFER+7,1,1, GFX_KAEFER+3,1,1, GFX_KAEFER+7,1,1,                HA_NEXT,
-  GFX_BUTTERFLY,1,1, GFX_BUTTERFLY+1,1,1,                      HA_NEXT,
-  GFX_FIREFLY,1,1, GFX_FIREFLY+1,1,1,                          HA_NEXT,
+  GFX_BUTTERFLY,2,2,                                           HA_NEXT,
+  GFX_FIREFLY,2,2,                                             HA_NEXT,
   GFX_PACMAN+0,1,3, GFX_PACMAN+4,1,2, GFX_PACMAN+0,1,3,
   GFX_PACMAN+1,1,3, GFX_PACMAN+5,1,2, GFX_PACMAN+1,1,3,
   GFX_PACMAN+2,1,3, GFX_PACMAN+6,1,2, GFX_PACMAN+2,1,3,
   GFX_PACMAN+3,1,3, GFX_PACMAN+7,1,2, GFX_PACMAN+3,1,3,                HA_NEXT,
-  GFX_MAMPFER+0,4,0, GFX_MAMPFER+3,1,0, GFX_MAMPFER+2,1,0,
-  GFX_MAMPFER+1,1,0, GFX_MAMPFER+0,1,0,                                HA_NEXT,
-  GFX_MAMPFER2+0,4,0, GFX_MAMPFER2+3,1,0, GFX_MAMPFER2+2,1,0,
-  GFX_MAMPFER2+1,1,0, GFX_MAMPFER2+0,1,0,                      HA_NEXT,
-  GFX_ZOMBIE+0,4,0, GFX_ZOMBIE+3,1,0, GFX_ZOMBIE+2,1,0,
-  GFX_ZOMBIE+1,1,0, GFX_ZOMBIE+0,1,0,                          HA_NEXT,
+  GFX_MAMPFER+0,4,1, GFX_MAMPFER+3,1,1, GFX_MAMPFER+2,1,1,
+  GFX_MAMPFER+1,1,1, GFX_MAMPFER+0,1,1,                                HA_NEXT,
+  GFX_MAMPFER2+0,4,1, GFX_MAMPFER2+3,1,1, GFX_MAMPFER2+2,1,1,
+  GFX_MAMPFER2+1,1,1, GFX_MAMPFER2+0,1,1,                      HA_NEXT,
+  GFX_ROBOT+0,4,1, GFX_ROBOT+3,1,1, GFX_ROBOT+2,1,1,
+  GFX_ROBOT+1,1,1, GFX_ROBOT+0,1,1,                            HA_NEXT,
+  GFX_MAULWURF_DOWN,4,2,
+  GFX_MAULWURF_UP,4,2,
+  GFX_MAULWURF_LEFT,4,2,
+  GFX_MAULWURF_RIGHT,4,2,                                      HA_NEXT,
+  GFX_PINGUIN_DOWN,4,2,
+  GFX_PINGUIN_UP,4,2,
+  GFX_PINGUIN_LEFT,4,2,
+  GFX_PINGUIN_RIGHT,4,2,                                       HA_NEXT,
+  GFX_SCHWEIN_DOWN,4,2,
+  GFX_SCHWEIN_UP,4,2,
+  GFX_SCHWEIN_LEFT,4,2,
+  GFX_SCHWEIN_RIGHT,4,2,                                       HA_NEXT,
+  GFX_DRACHE_DOWN,4,2,
+  GFX_DRACHE_UP,4,2,
+  GFX_DRACHE_LEFT,4,2,
+  GFX_DRACHE_RIGHT,4,2,                                                HA_NEXT,
+  GFX_SONDE_START,8,1,                                         HA_NEXT,
   GFX_ABLENK,4,1,                                              HA_NEXT,
-  GFX_BIRNE_AUS,1,33, GFX_BIRNE_EIN,1,33,                      HA_NEXT,
-  GFX_ZEIT_VOLL,1,33, GFX_ZEIT_LEER,1,33,                      HA_NEXT,
-  GFX_TROPFEN,1,33, GFX_AMOEBING,4,1, GFX_AMOEBE_LEBT,1,10,    HA_NEXT,
+  GFX_BIRNE_AUS,1,25, GFX_BIRNE_EIN,1,25,                      HA_NEXT,
+  GFX_ZEIT_VOLL,1,25, GFX_ZEIT_LEER,1,25,                      HA_NEXT,
+  GFX_TROPFEN,1,25, GFX_AMOEBING,4,1, GFX_AMOEBE_LEBT,1,10,    HA_NEXT,
   GFX_AMOEBE_TOT+2,2,50, GFX_AMOEBE_TOT,2,50,                  HA_NEXT,
   GFX_AMOEBE_LEBT,4,40,                                                HA_NEXT,
   GFX_AMOEBE_LEBT,1,10,        GFX_AMOEBING,4,2,                       HA_NEXT,
-  GFX_AMOEBE_LEBT,1,33, GFX_AMOEBE_TOT,1,33, GFX_EXPLOSION,8,1,
+  GFX_AMOEBE_LEBT,1,25, GFX_AMOEBE_TOT,1,25, GFX_EXPLOSION,8,1,
   GFX_DIAMANT,1,10,                                            HA_NEXT,
   GFX_LIFE,1,100,                                              HA_NEXT,
   GFX_LIFE_ASYNC,1,100,                                                HA_NEXT,
   GFX_SIEB_LEER,4,2,                                           HA_NEXT,
   GFX_SIEB2_LEER,4,2,                                          HA_NEXT,
   GFX_AUSGANG_ZU,1,100, GFX_AUSGANG_ACT,4,2,
-  GFX_AUSGANG_AUF+0,4,1, GFX_AUSGANG_AUF+3,1,1,
-  GFX_AUSGANG_AUF+2,1,1, GFX_AUSGANG_AUF+1,1,1,                        HA_NEXT,
-  GFX_AUSGANG_AUF+0,4,1, GFX_AUSGANG_AUF+3,1,1,
-  GFX_AUSGANG_AUF+2,1,1, GFX_AUSGANG_AUF+1,1,1,                        HA_NEXT,
+  GFX_AUSGANG_AUF+0,4,2, GFX_AUSGANG_AUF+3,1,2,
+  GFX_AUSGANG_AUF+2,1,2, GFX_AUSGANG_AUF+1,1,2,                        HA_NEXT,
+  GFX_AUSGANG_AUF+0,4,2, GFX_AUSGANG_AUF+3,1,2,
+  GFX_AUSGANG_AUF+2,1,2, GFX_AUSGANG_AUF+1,1,2,                        HA_NEXT,
   HA_END
 };
 static char *helpscreen_eltext[][2] =
@@ -362,6 +391,11 @@ static char *helpscreen_eltext[][2] =
  {"Cruncher: Eats diamonds and you,",  "if you're not careful"},
  {"Cruncher (BD style):",              "Eats almost everything"},
  {"Robot: Tries to kill the player",   ""},
+ {"The mole: You must guide him savely","to the exit; he will follow you"},
+ {"The penguin: Guide him to the exit,","but keep him away from monsters!"},
+ {"The Pig: Harmless, but eats all",   "gems it can get"},
+ {"The Dragon: Breathes fire,",                "especially to some monsters"},
+ {"Sonde: Follows you everywhere;",    "harmless, but may block your way"},
  {"Magic Wheel: Touch it to get rid of","the robots for some seconds"},
  {"Light Bulb: All of them must be",   "switched on to finish a level"},
  {"Extra Time Orb: Adds some seconds", "to the time available for the level"},
@@ -394,7 +428,7 @@ static int helpscreen_musicpos;
 void DrawHelpScreenElAction(int start)
 {
   int i = 0, j = 0;
-  int frame, delay, graphic;
+  int frame, graphic;
   int xstart = SX+16, ystart = SY+64+2*32, ystep = TILEY+4;
 
   while(helpscreen_action[j] != HA_END)
@@ -427,8 +461,7 @@ void DrawHelpScreenElAction(int start)
       helpscreen_frame[i-start] = helpscreen_action[j++]-1;
     }
 
-    delay = helpscreen_action[j++];
-    helpscreen_delay[i-start] = delay;
+    helpscreen_delay[i-start] = helpscreen_action[j++] - 1;
 
     if (helpscreen_action[j] == HA_NEXT)
     {
@@ -628,7 +661,7 @@ void HandleHelpScreen(int button)
   }
   else
   {
-    if (DelayReached(&hs_delay,3))
+    if (DelayReached(&hs_delay,GAME_FRAME_DELAY))
     {
       if (helpscreen_state<num_helpscreen_els_pages)
        DrawHelpScreenElAction(helpscreen_state*MAX_HELPSCREEN_ELS);
@@ -682,7 +715,7 @@ void HandleTypeName(int newxpos, KeySym key)
                player.alias_name,FS_BIG,FC_YELLOW);
     DrawGraphic(xpos+6,ypos,GFX_KUGEL_ROT);
   }
-  else if (key==XK_Delete && xpos>0)
+  else if ((key==XK_Delete || key==XK_BackSpace) && xpos>0)
   {
     xpos--;
     player.alias_name[xpos] = 0;
@@ -721,7 +754,7 @@ void DrawChooseLevel()
 
   FadeToFront();
   InitAnimation();
-  HandleChooseLevel(0,0,0,0,MB_MENU_MARK);
+  HandleChooseLevel(0,0,0,0,MB_MENU_INITIALIZE);
 }
 
 void HandleChooseLevel(int mx, int my, int dx, int dy, int button)
@@ -730,12 +763,21 @@ void HandleChooseLevel(int mx, int my, int dx, int dy, int button)
   static int redraw = TRUE;
   int x = (mx+32-SX)/32, y = (my+32-SY)/32;
 
+  if (button == MB_MENU_INITIALIZE)
+  {
+    redraw = TRUE;
+    choice = leveldir_nr + 3;
+  }
+
   if (redraw)
   {
     DrawGraphic(0,choice-1,GFX_KUGEL_ROT);
     redraw = FALSE;
   }
 
+  if (button == MB_MENU_INITIALIZE)
+    return;
+
   if (dx || dy)
   {
     if (dy)
@@ -885,7 +927,7 @@ void DrawSetupScreen()
 
   FadeToFront();
   InitAnimation();
-  HandleSetupScreen(0,0,0,0,MB_MENU_MARK);
+  HandleSetupScreen(0,0,0,0,MB_MENU_INITIALIZE);
 }
 
 void HandleSetupScreen(int mx, int my, int dx, int dy, int button)
@@ -897,12 +939,18 @@ void HandleSetupScreen(int mx, int my, int dx, int dy, int button)
   int pos_empty = SETUP_SCREEN_POS_EMPTY + 1;
   int pos_end   = SETUP_SCREEN_POS_END   + 1;
 
+  if (button == MB_MENU_INITIALIZE)
+    redraw = TRUE;
+
   if (redraw)
   {
     DrawGraphic(0,choice-1,GFX_KUGEL_ROT);
     redraw = FALSE;
   }
 
+  if (button == MB_MENU_INITIALIZE)
+    return;
+
   if (dx || dy)
   {
     if (dy)
@@ -1197,7 +1245,7 @@ void HandleGameActions()
   if (LevelSolved)
     GameWon();
 
-  if (GameOver && !TAPE_IS_STOPPED(tape))
+  if (PlayerGone && !TAPE_IS_STOPPED(tape))
     TapeStop();
 
   GameActions();
@@ -1246,6 +1294,7 @@ void HandleVideoButtons(int mx, int my, int button)
          tape.pos[tape.counter].delay = tape.delay_played;
          tape.playing = FALSE;
          tape.recording = TRUE;
+         tape.changed = TRUE;
 
          DrawVideoDisplay(VIDEO_STATE_PLAY_OFF | VIDEO_STATE_REC_ON,0);
        }
index dc14ad5..3ee23f3 100644 (file)
@@ -563,12 +563,19 @@ int ulaw_to_linear(unsigned char ulawbyte)
 
 /*** THE STUFF BELOW IS ONLY USED BY THE MAIN PROCESS ***/
 
+static 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]);
+}
+
 BOOL LoadSound(struct SoundInfo *snd_info)
 {
   FILE *file;
   char filename[256];
   char *sound_ext = "8svx";
-  struct SoundHeader_8SVX *snd_hdr;
+  struct SoundHeader_8SVX *sound_header;
   unsigned char *ptr;
 
   sprintf(filename,"%s/%s.%s",SND_PATH,snd_info->name,sound_ext);
@@ -609,40 +616,48 @@ BOOL LoadSound(struct SoundInfo *snd_info)
 
   fclose(file);
 
-  snd_hdr = (struct SoundHeader_8SVX *)snd_info->file_ptr;
+  sound_header = (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))
+  if (strncmp(sound_header->magic_FORM,"FORM",4) ||
+      snd_info->file_len != be2long(&sound_header->chunk_size)+8 ||
+      strncmp(sound_header->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;
+  ptr = snd_info->file_ptr + 12;
 
-  while(ptr<(unsigned char *)snd_info->file_ptr+snd_info->file_len)
+  while(ptr < (unsigned char *)(snd_info->file_ptr + snd_info->file_len))
   {
     if (!strncmp(ptr,"VHDR",4))
     {
-      ptr+=be2long((unsigned long *)(ptr+4));
+      ptr += be2long((unsigned long *)(ptr + 4)) + 8;
+      continue;
     }
-    if (!strncmp(ptr,"ANNO",4))
+    else if (!strncmp(ptr,"ANNO",4))
     {
-      ptr+=be2long((unsigned long *)(ptr+4));
+      ptr += be2long((unsigned long *)(ptr + 4)) + 8;
+      continue;
     }
-    if (!strncmp(ptr,"CHAN",4))
+    else if (!strncmp(ptr,"CHAN",4))
     {
-      ptr+=be2long((unsigned long *)(ptr+4));
+      ptr += be2long((unsigned long *)(ptr + 4)) + 8;
+      continue;
     }
-    if (!strncmp(ptr,"BODY",4))
+    else if (!strncmp(ptr,"BODY",4))
     {
-      snd_info->data_ptr = ptr+8;
-      snd_info->data_len = be2long((unsigned long *)(ptr+4));
+      snd_info->data_ptr = ptr + 8;
+      snd_info->data_len = be2long((unsigned long *)(ptr + 4));
       return(TRUE);
     }
-    ptr++;
+    else
+    {
+      /* other chunk not recognized here */
+      ptr += be2long((unsigned long *)(ptr + 4)) + 8;
+      continue;
+    }
   }
 
   return(FALSE);
index 384f77c..089c44f 100644 (file)
@@ -110,8 +110,9 @@ struct SoundHeader_8SVX
 
 struct SoundInfo
 { 
-  char *name;
-  char *file_ptr, *data_ptr;
+  unsigned char *name;
+  unsigned char *file_ptr;
+  char *data_ptr;
   long file_len, data_len;
 };
 
@@ -131,9 +132,6 @@ struct SoundControl
   char *data_ptr;
 };
 
-/* function from "misc.c" */
-unsigned long be2long(unsigned long *);
-
 /* sound server functions */
 void SoundServer(void);
 void SoundServer_InsertNewSound(struct SoundControl);
index 35929e8..3371306 100644 (file)
@@ -28,10 +28,10 @@ void TapeStartRecording()
   tape.length = 0;
   tape.counter = 0;
   tape.pos[tape.counter].delay = 0;
-  tape.changed = TRUE;
   tape.recording = TRUE;
   tape.playing = FALSE;
   tape.pausing = FALSE;
+  tape.changed = TRUE;
   tape.date = 10000*(zeit2->tm_year%100) + 100*zeit2->tm_mon + zeit2->tm_mday;
   tape.random_seed = InitRND(NEW_RANDOMIZE);
 
@@ -146,7 +146,7 @@ int TapePlayAction()
 
   if (tape.counter>=tape.length)
   {
-    TapeStopPlaying();
+    TapeStop();
     return(0);
   }
 
@@ -184,7 +184,7 @@ BOOL TapePlayDelay()
 
   if (tape.counter>=tape.length)
   {
-    TapeStopPlaying();
+    TapeStop();
     return(TRUE);
   }
 
index 63c027f..7ffa3c1 100644 (file)
@@ -22,6 +22,9 @@
 #include "sound.h"
 #include "misc.h"
 #include "buttons.h"
+#include "joystick.h"
+#include "cartoons.h"
+
 #include <math.h>
 
 void BackToFront()
@@ -251,9 +254,116 @@ void DrawTextExt(Drawable d, GC gc, int x, int y,
   }
 }
 
+void DrawPlayerField()
+{
+  int x = JX, y = JY;
+  int sx = SCROLLX(x), sy = SCROLLY(y);
+  int element = Feld[x][y];
+  int graphic, phase;
+  BOOL draw_thru_mask = FALSE;
+
+  if (PlayerGone)
+    return;
+
+#if DEBUG
+  if (!IN_LEV_FIELD(x,y) || !IN_SCR_FIELD(sx,sy))
+  {
+    printf("DrawPlayerField(): x = %d, y = %d\n",x,y);
+    printf("DrawPlayerField(): This should never happen!\n");
+    return;
+  }
+#endif
+
+  if (element == EL_EXPLODING)
+    return;
+
+  if (direct_draw_on)
+    drawto_field = backbuffer;
+
+  /* draw things behind the player (EL_PFORTE* || mole/penguin/pig/dragon) */
+
+  if (Store[x][y])
+  {
+    DrawGraphic(sx,sy, el2gfx(Store[x][y]));
+    draw_thru_mask = TRUE;
+  }
+  else if (element!=EL_LEERRAUM && element!=EL_DYNAMIT && element!=EL_DYNABOMB)
+  {
+    DrawLevelField(x,y);
+    draw_thru_mask = TRUE;
+  }
+
+  /* draw player himself */
+
+  if (PlayerMovDir==MV_LEFT)
+    graphic = (PlayerPushing ? GFX_SPIELER_PUSH_LEFT : GFX_SPIELER_LEFT);
+  else if (PlayerMovDir==MV_RIGHT)
+    graphic = (PlayerPushing ? GFX_SPIELER_PUSH_RIGHT : GFX_SPIELER_RIGHT);
+  else if (PlayerMovDir==MV_UP)
+    graphic = GFX_SPIELER_UP;
+  else /* MV_DOWN || MV_NO_MOVING */
+    graphic = GFX_SPIELER_DOWN;
+
+  graphic += PlayerFrame;
+
+  if (draw_thru_mask)
+    DrawGraphicThruMask(sx,sy, graphic);
+  else
+    DrawGraphic(sx,sy, graphic);
+
+  /* draw things in front of player (EL_DYNAMIT || EL_DYNABOMB) */
+
+  if (element == EL_DYNAMIT || element == EL_DYNABOMB)
+  {
+    graphic = el2gfx(element);
+
+    if (element == EL_DYNAMIT)
+    {
+      if ((phase = (48-MovDelay[x][y])/6) > 6)
+       phase = 6;
+    }
+    else
+    {
+      if ((phase = ((48-MovDelay[x][y])/3) % 8) > 3)
+       phase = 7-phase;
+    }
+
+    DrawGraphicThruMask(sx,sy, graphic + phase);
+  }
+
+  if (direct_draw_on)
+  {
+    int dest_x = SX+SCROLLX(x)*TILEX;
+    int dest_y = SY+SCROLLY(y)*TILEY;
+
+    XCopyArea(display,backbuffer,window,gc,
+             dest_x,dest_y, TILEX,TILEY, dest_x,dest_y);
+    drawto_field = window;
+  }
+}
+
+static int getGraphicAnimationPhase(int frames, int delay, int mode)
+{
+  int phase;
+
+  if (mode == ANIM_OSCILLATE)
+  {
+    int max_anim_frames = frames*2 - 2;
+    phase = (FrameCounter % (delay * max_anim_frames)) / delay;
+    phase = (phase < frames ? phase : max_anim_frames - phase);
+  }
+  else
+    phase = (FrameCounter % (delay * frames)) / delay;
+
+  return(phase);
+}
+
 void DrawGraphicAnimation(int x, int y, int graphic,
                          int frames, int delay, int mode)
 {
+  int phase = getGraphicAnimationPhase(frames, delay, mode);
+
+/*
   int phase;
 
   if (mode == ANIM_OSCILLATE)
@@ -264,6 +374,7 @@ void DrawGraphicAnimation(int x, int y, int graphic,
   }
   else
     phase = (FrameCounter % (delay * frames)) / delay;
+*/
 
   if (!(FrameCounter % delay) && IN_SCR_FIELD(SCROLLX(x),SCROLLY(y)))
     DrawGraphic(SCROLLX(x),SCROLLY(y), graphic + phase);
@@ -271,6 +382,16 @@ void DrawGraphicAnimation(int x, int y, int graphic,
 
 void DrawGraphic(int x, int y, int graphic)
 {
+
+#if DEBUG
+  if (!IN_SCR_FIELD(x,y))
+  {
+    printf("DrawGraphic(): x = %d, y = %d, graphic = %d\n",x,y,graphic);
+    printf("DrawGraphic(): This should never happen!\n");
+    return;
+  }
+#endif
+
   DrawGraphicExt(drawto_field, gc, x, y, graphic);
   redraw_tiles++;
   redraw[x][y] = TRUE;
@@ -284,42 +405,77 @@ void DrawGraphicExt(Drawable d, GC gc, int x, int y, int 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)
+  if (graphic >= GFX_START_ROCKSSCREEN && graphic <= GFX_END_ROCKSSCREEN)
+  {
+    graphic -= GFX_START_ROCKSSCREEN;
     XCopyArea(display,pix[PIX_BACK],d,gc,
              SX+(graphic % GFX_PER_LINE)*TILEX,
              SY+(graphic / GFX_PER_LINE)*TILEY,
              TILEX,TILEY, x,y);
-  else
+  }
+  else if (graphic >= GFX_START_ROCKSHEROES && graphic <= GFX_END_ROCKSHEROES)
   {
-    graphic -= 256;
+    graphic -= GFX_START_ROCKSHEROES;
+    XCopyArea(display,pix[PIX_HEROES],d,gc,
+             (graphic % HEROES_PER_LINE)*TILEX,
+             (graphic / HEROES_PER_LINE)*TILEY,
+             TILEX,TILEY, x,y);
+  }
+  else if (graphic >= GFX_START_ROCKSFONT && graphic <= GFX_END_ROCKSFONT)
+  {
+    graphic -= GFX_START_ROCKSFONT;
     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);
   }
+  else
+    XFillRectangle(display,d,gc, x,y, TILEX,TILEY);
 }
 
 void DrawGraphicThruMask(int x, int y, int graphic)
 {
   int src_x,src_y, dest_x,dest_y;
 
-  if (graphic<0 || graphic>255)
+#if DEBUG
+  if (!IN_SCR_FIELD(x,y))
   {
-    DrawGraphic(x,y,graphic);
+    printf("DrawGraphicThruMask(): x = %d, y = %d\n",x,y);
+    printf("DrawGraphicThruMask(): This should never happen!\n");
     return;
   }
+#endif
 
-  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);
+  if (graphic >= GFX_START_ROCKSSCREEN && graphic <= GFX_END_ROCKSSCREEN)
+  {
+    graphic -= GFX_START_ROCKSSCREEN;
+    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);
+  }
+  else if (graphic >= GFX_START_ROCKSHEROES && graphic <= GFX_END_ROCKSHEROES)
+  {
+    graphic -= GFX_START_ROCKSHEROES;
+    src_x  = (graphic % HEROES_PER_LINE)*TILEX;
+    src_y  = (graphic / HEROES_PER_LINE)*TILEY;
+    dest_x = SX+x*TILEX;
+    dest_y = SY+y*TILEY;
+
+    XSetClipOrigin(display,clip_gc[PIX_HEROES],dest_x-src_x,dest_y-src_y);
+    XCopyArea(display,pix[PIX_HEROES],drawto_field,clip_gc[PIX_HEROES],
+             src_x,src_y, TILEX,TILEY, dest_x,dest_y);
+  }
+  else
+  {
+    DrawGraphic(x,y,graphic);
+    return;
+  }
 
   redraw_tiles++;
   redraw[x][y]=TRUE;
@@ -346,22 +502,25 @@ void DrawMiniGraphicExt(Drawable d, GC gc, int x, int y, int 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)
+  if (graphic >= GFX_START_ROCKSSCREEN && graphic <= GFX_END_ROCKSSCREEN)
+  {
+    graphic -= GFX_START_ROCKSSCREEN;
     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
+  }
+  else if (graphic >= GFX_START_ROCKSFONT && graphic <= GFX_END_ROCKSFONT)
   {
-    graphic -= 256;
+    graphic -= GFX_START_ROCKSFONT;
     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);
   }
+  else
+    XFillRectangle(display,d,gc, x,y, MINI_TILEX,MINI_TILEY);
 }
 
 void DrawGraphicShifted(int x,int y, int dx,int dy, int graphic, int cut_mode)
@@ -439,10 +598,31 @@ void DrawGraphicShifted(int x,int y, int dx,int dy, int graphic, int cut_mode)
       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);
+  if (graphic >= GFX_START_ROCKSSCREEN && graphic <= GFX_END_ROCKSSCREEN)
+  {
+    graphic -= GFX_START_ROCKSSCREEN;
+    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);
+  }
+  else if (graphic >= GFX_START_ROCKSHEROES && graphic <= GFX_END_ROCKSHEROES)
+  {
+    graphic -= GFX_START_ROCKSHEROES;
+    XCopyArea(display,pix[PIX_HEROES],drawto_field,gc,
+             (graphic % HEROES_PER_LINE)*TILEX+cx,
+             (graphic / HEROES_PER_LINE)*TILEY+cy,
+             width,height, SX+x*TILEX+dx,SY+y*TILEY+dy);
+  }
+
+#if DEBUG
+  if (!IN_SCR_FIELD(x,y))
+  {
+    printf("DrawGraphicShifted(): x = %d, y = %d, graphic = %d\n",x,y,graphic);
+    printf("DrawGraphicShifted(): This should never happen!\n");
+    return;
+  }
+#endif
 
   redraw_tiles++;
   redraw[x][y]=TRUE;
@@ -453,32 +633,50 @@ 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 phase4 = ABS(MovPos[ux][uy])/(TILEX/4);
+  int phase  = phase4 / 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 ||
-      element==EL_BUTTERFLY ||
-      element==EL_FIREFLY)
+  if (element==EL_PACMAN || element==EL_KAEFER || element==EL_FLIEGER)
   {
-    if (element==EL_BUTTERFLY || element==EL_FIREFLY)
-      graphic += !phase;
+    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_MAULWURF || element==EL_PINGUIN ||
+          element==EL_SCHWEIN || element==EL_DRACHE)
+  {
+    if (dir==MV_LEFT)
+      graphic = (element==EL_MAULWURF ? GFX_MAULWURF_LEFT :
+                element==EL_PINGUIN ? GFX_PINGUIN_LEFT :
+                element==EL_SCHWEIN ? GFX_SCHWEIN_LEFT : GFX_DRACHE_LEFT);
+    else if (dir==MV_RIGHT)
+      graphic = (element==EL_MAULWURF ? GFX_MAULWURF_RIGHT :
+                element==EL_PINGUIN ? GFX_PINGUIN_RIGHT :
+                element==EL_SCHWEIN ? GFX_SCHWEIN_RIGHT : GFX_DRACHE_RIGHT);
+    else if (dir==MV_UP)
+      graphic = (element==EL_MAULWURF ? GFX_MAULWURF_UP :
+                element==EL_PINGUIN ? GFX_PINGUIN_UP :
+                element==EL_SCHWEIN ? GFX_SCHWEIN_UP : GFX_DRACHE_UP);
     else
-    {
-      graphic += 4*!phase;
-
-      if (dir==MV_UP)
-       graphic += 1;
-      else if (dir==MV_LEFT)
-       graphic += 2;
-      else if (dir==MV_DOWN)
-       graphic += 3;
-    }
+      graphic = (element==EL_MAULWURF ? GFX_MAULWURF_DOWN :
+                element==EL_PINGUIN ? GFX_PINGUIN_DOWN :
+                element==EL_SCHWEIN ? GFX_SCHWEIN_DOWN : GFX_DRACHE_DOWN);
+
+    graphic += phase4;
+  }
+  else if (element==EL_SONDE)
+  {
+    graphic = GFX_SONDE_START + getGraphicAnimationPhase(8, 2, ANIM_NORMAL);
+  }
+  else if (element==EL_BUTTERFLY || element==EL_FIREFLY)
+  {
+    graphic += !phase;
   }
   else if ((element==EL_FELSBROCKEN || IS_GEM(element)) && !cut_mode)
   {
@@ -998,10 +1196,8 @@ BOOL AreYouSure(char *text, unsigned int ays_state)
          }
          break;
        case FocusIn:
-         HandleFocusEvent(FOCUS_IN);
-         break;
        case FocusOut:
-         HandleFocusEvent(FOCUS_OUT);
+         HandleFocusEvent((XFocusChangeEvent *) &event);
          break;
        default:
          break;
@@ -1213,137 +1409,6 @@ int ReadPixel(Drawable d, int x, int y)
   return(XGetPixel(pixelimage,0,0));
 }
 
-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()
-{
-#ifdef __FreeBSD__
-  struct joystick joy_ctrl;
-#else
-  struct joystick_control
-  {
-    int buttons;
-    int x;
-    int y;
-  } joy_ctrl;
-#endif
-
-  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;
-#ifdef __FreeBSD__
-  js_b1 = joy_ctrl.b1;
-  js_b2 = joy_ctrl.b2;
-#else
-  js_b1 = joy_ctrl.buttons & 1;
-  js_b2 = joy_ctrl.buttons & 2;
-#endif
-
-  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);
-}
-
 int el2gfx(int element)
 {
   switch(element)
@@ -1384,7 +1449,7 @@ int el2gfx(int element)
     case EL_FIREFLY_L:         return(GFX_FIREFLY_L);
     case EL_FIREFLY_U:         return(GFX_FIREFLY_U);
     case EL_MAMPFER:           return(GFX_MAMPFER);
-    case EL_ZOMBIE:            return(GFX_ZOMBIE);
+    case EL_ROBOT:             return(GFX_ROBOT);
     case EL_BETON:             return(GFX_BETON);
     case EL_DIAMANT:           return(GFX_DIAMANT);
     case EL_MORAST_LEER:       return(GFX_MORAST_LEER);
@@ -1458,6 +1523,15 @@ int el2gfx(int element)
     case EL_SOKOBAN_OBJEKT:    return(GFX_SOKOBAN_OBJEKT);
     case EL_SOKOBAN_FELD_LEER: return(GFX_SOKOBAN_FELD_LEER);
     case EL_SOKOBAN_FELD_VOLL: return(GFX_SOKOBAN_FELD_VOLL);
+    case EL_MAULWURF:          return(GFX_MAULWURF);
+    case EL_PINGUIN:           return(GFX_PINGUIN);
+    case EL_SCHWEIN:           return(GFX_SCHWEIN);
+    case EL_DRACHE:            return(GFX_DRACHE);
+    case EL_SONDE:             return(GFX_SONDE);
+    case EL_PFEIL_L:           return(GFX_PFEIL_L);
+    case EL_PFEIL_R:           return(GFX_PFEIL_R);
+    case EL_PFEIL_O:           return(GFX_PFEIL_O);
+    case EL_PFEIL_U:           return(GFX_PFEIL_U);
     default:
     {
       if (IS_CHAR(element))
index ce4ab0f..43dcf1e 100644 (file)
 
 #include <sys/time.h>
 
-/* für DrawGraphicAnimation */
-#define ANIM_NORMAL    0
-#define ANIM_OSCILLATE 1
-
 /* für DrawElementShifted */
 #define CUT_NO_CUTTING 0
 #define CUT_ABOVE      1
@@ -57,6 +53,7 @@ void FadeToFront();
 void ClearWindow();
 void DrawText(int, int, char *, int, int);
 void DrawTextExt(Drawable, GC, int, int, char *, int, int);
+void DrawPlayerField(void);
 void DrawGraphicAnimation(int, int, int, int, int, int);
 void DrawGraphic(int, int, int);
 void DrawGraphicExt(Drawable, GC, int, int, int);
@@ -85,10 +82,6 @@ unsigned int CloseDoor(unsigned int);
 unsigned int GetDoorState(void);
 unsigned int MoveDoor(unsigned int);
 int ReadPixel(Drawable, int, int);
-void CheckJoystickData(void);
-int JoystickPosition(int, int, int);
-int Joystick(void);
-int JoystickButton(void);
 int el2gfx(int);
 
 #endif