rnd-20090623-1-src
authorHolger Schemel <info@artsoft.org>
Tue, 23 Jun 2009 00:13:06 +0000 (02:13 +0200)
committerHolger Schemel <info@artsoft.org>
Sat, 30 Aug 2014 08:57:18 +0000 (10:57 +0200)
* started with integration of native Supaplex engine, using source code
  of Megaplex from Frank Schindler, based on original Supaplex engine
* version number set to 3.2.6.2

99 files changed:
ChangeLog
src/Makefile
src/conftime.h
src/engines.h
src/files.c
src/game.c
src/game.h
src/game_em/Makefile
src/game_em/export.h
src/game_em/main_em.h
src/game_sp/ASM.c [new file with mode: 0644]
src/game_sp/ASM.h [new file with mode: 0644]
src/game_sp/BitMapObject.c [new file with mode: 0644]
src/game_sp/BitMapObject.h [new file with mode: 0644]
src/game_sp/BugsTerminals.c [new file with mode: 0644]
src/game_sp/BugsTerminals.h [new file with mode: 0644]
src/game_sp/Capture.c [new file with mode: 0644]
src/game_sp/Capture.h [new file with mode: 0644]
src/game_sp/DDScrollBuffer.c [new file with mode: 0644]
src/game_sp/DDScrollBuffer.h [new file with mode: 0644]
src/game_sp/DDSpriteBuffer.c [new file with mode: 0644]
src/game_sp/DDSpriteBuffer.h [new file with mode: 0644]
src/game_sp/Demo.c [new file with mode: 0644]
src/game_sp/Demo.h [new file with mode: 0644]
src/game_sp/DemoBufferObject.c [new file with mode: 0644]
src/game_sp/DemoBufferObject.h [new file with mode: 0644]
src/game_sp/DirectDrawGlobals.c [new file with mode: 0644]
src/game_sp/DirectDrawGlobals.h [new file with mode: 0644]
src/game_sp/DirectXGlobals.c [new file with mode: 0644]
src/game_sp/DirectXGlobals.h [new file with mode: 0644]
src/game_sp/Display.c [new file with mode: 0644]
src/game_sp/Display.h [new file with mode: 0644]
src/game_sp/DoGameStuff.c [new file with mode: 0644]
src/game_sp/DoGameStuff.h [new file with mode: 0644]
src/game_sp/Electrons.c [new file with mode: 0644]
src/game_sp/Electrons.h [new file with mode: 0644]
src/game_sp/ErrorReporting.c [new file with mode: 0644]
src/game_sp/ErrorReporting.h [new file with mode: 0644]
src/game_sp/Explosions.c [new file with mode: 0644]
src/game_sp/Explosions.h [new file with mode: 0644]
src/game_sp/FakeDeclares.c [new file with mode: 0644]
src/game_sp/FakeDeclares.h [new file with mode: 0644]
src/game_sp/FancyRestore.c [new file with mode: 0644]
src/game_sp/FancyRestore.h [new file with mode: 0644]
src/game_sp/GeneralTricks.c [new file with mode: 0644]
src/game_sp/GeneralTricks.h [new file with mode: 0644]
src/game_sp/Globals.c [new file with mode: 0644]
src/game_sp/Globals.h [new file with mode: 0644]
src/game_sp/Infotrons.c [new file with mode: 0644]
src/game_sp/Infotrons.h [new file with mode: 0644]
src/game_sp/InitGameConditions.c [new file with mode: 0644]
src/game_sp/InitGameConditions.h [new file with mode: 0644]
src/game_sp/Input.c [new file with mode: 0644]
src/game_sp/Input.h [new file with mode: 0644]
src/game_sp/LevelSetPreviewForm.c [new file with mode: 0644]
src/game_sp/LevelSetPreviewForm.h [new file with mode: 0644]
src/game_sp/MainForm.c [new file with mode: 0644]
src/game_sp/MainForm.h [new file with mode: 0644]
src/game_sp/MainGameLoop.c [new file with mode: 0644]
src/game_sp/MainGameLoop.h [new file with mode: 0644]
src/game_sp/Makefile [new file with mode: 0644]
src/game_sp/Marker.c [new file with mode: 0644]
src/game_sp/Marker.h [new file with mode: 0644]
src/game_sp/Murphy.c [new file with mode: 0644]
src/game_sp/Murphy.h [new file with mode: 0644]
src/game_sp/OrangeDisk.c [new file with mode: 0644]
src/game_sp/OrangeDisk.h [new file with mode: 0644]
src/game_sp/PathTools.c [new file with mode: 0644]
src/game_sp/PathTools.h [new file with mode: 0644]
src/game_sp/SettingsObject.c [new file with mode: 0644]
src/game_sp/SettingsObject.h [new file with mode: 0644]
src/game_sp/SnikSnaks.c [new file with mode: 0644]
src/game_sp/SnikSnaks.h [new file with mode: 0644]
src/game_sp/Sound.c [new file with mode: 0644]
src/game_sp/Sound.h [new file with mode: 0644]
src/game_sp/TickCountObject.c [new file with mode: 0644]
src/game_sp/TickCountObject.h [new file with mode: 0644]
src/game_sp/TopMost.c [new file with mode: 0644]
src/game_sp/TopMost.h [new file with mode: 0644]
src/game_sp/Zonk.c [new file with mode: 0644]
src/game_sp/Zonk.h [new file with mode: 0644]
src/game_sp/export.h [new file with mode: 0644]
src/game_sp/game_sp.h [new file with mode: 0644]
src/game_sp/global.h [new file with mode: 0644]
src/game_sp/main.c [new file with mode: 0644]
src/game_sp/main_sp.h [new file with mode: 0644]
src/game_sp/modAnimations.c [new file with mode: 0644]
src/game_sp/modAnimations.h [new file with mode: 0644]
src/game_sp/modGeneralTricks.c [new file with mode: 0644]
src/game_sp/modGeneralTricks.h [new file with mode: 0644]
src/game_sp/modMPX.c [new file with mode: 0644]
src/game_sp/modMPX.h [new file with mode: 0644]
src/game_sp/vb_defs.h [new file with mode: 0644]
src/game_sp/vb_lib.c [new file with mode: 0644]
src/game_sp/vb_lib.h [new file with mode: 0644]
src/game_sp/vb_types.h [new file with mode: 0644]
src/game_sp/vb_vars.c [new file with mode: 0644]
src/game_sp/vb_vars.h [new file with mode: 0644]
src/main.h

index 41f88faf0dd22234d59f47d5786559301f09af8d..094e442b25579be9cf22a38f6336fa2e32e0f84f 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,10 @@
+2009-06-20
+       * started with integration of native Supaplex engine, using source code
+         of Megaplex from Frank Schindler, based on original Supaplex engine
+
+2009-06-16
+       * version number set to 3.2.6.2
+
 2009-06-15
        * version 3.2.6.1 released
 
index bd5538eae7cb19bdd3894e5c8fdf911a1d3f589e..20b8f36790085e47ac016cb2d2759f61ffd2f01e 100644 (file)
@@ -144,7 +144,7 @@ CONFIG_GAME_DIR = $(CONFIG_RO_GAME_DIR) $(CONFIG_RW_GAME_DIR)
 CONFIG_GAME = $(CONFIG_GAME_DIR) $(CONFIG_SCORE_ENTRIES) $(CONFIG_SPECIAL)
 
 CONFIG = $(CONFIG_GAME) $(JOYSTICK)
-DEBUG = -DDEBUG -g
+DEBUG = -DDEBUG -g
 # PROFILING = $(PROFILING_FLAGS)
 
 # OPTIONS = $(DEBUG) -Wall                     # only for debugging purposes
@@ -228,7 +228,10 @@ LIBGAME = $(LIBGAME_DIR)/libgame.a
 GAME_EM_DIR = game_em
 GAME_EM = $(GAME_EM_DIR)/game_em.a
 
-RNDLIBS = $(LIBGAME) $(GAME_EM)
+GAME_SP_DIR = game_sp
+GAME_SP = $(GAME_SP_DIR)/game_sp.a
+
+RNDLIBS = $(LIBGAME) $(GAME_EM) $(GAME_SP)
 
 ICONBASE = windows_icon
 ifeq ($(PLATFORM),cross-win32)
@@ -246,7 +249,7 @@ endif
 # build targets
 # -----------------------------------------------------------------------------
 
-all: libgame_dir game_em_dir $(PROGNAME)
+all: libgame_dir game_em_dir game_sp_dir $(PROGNAME)
 
 $(PROGNAME): $(RNDLIBS) $(TIMESTAMP_FILE) $(OBJS) $(ICON)
        $(CC) $(PROFILING) $(OBJS) $(ICON) $(RNDLIBS) $(LDFLAGS) -o $(PROGNAME)
@@ -261,6 +264,11 @@ game_em_dir:
 $(GAME_EM):
        @$(MAKE) -C $(GAME_EM_DIR)
 
+game_sp_dir:
+       @$(MAKE) -C $(GAME_SP_DIR)
+$(GAME_SP):
+       @$(MAKE) -C $(GAME_SP_DIR)
+
 auto-conf:
        @for i in $(CNFS); do                   \
                echo "$(CNFS_CMD) $$i > $$i";   \
@@ -276,7 +284,7 @@ conf_snd.h: conf_snd.c
 conf_mus.h: conf_mus.c
        @$(MAKE) auto-conf
 
-$(TIMESTAMP_FILE): $(SRCS) $(LIBGAME) $(GAME_EM)
+$(TIMESTAMP_FILE): $(SRCS) $(LIBGAME) $(GAME_EM) $(GAME_SP)
        @date '+"%Y-%m-%d %H:%M"' \
        | sed -e 's/^/#define COMPILE_DATE_STRING /' \
        > $(TIMESTAMP_FILE)
@@ -291,9 +299,11 @@ $(ICON):
 clean-obj:
        $(MAKE) -C $(LIBGAME_DIR) clean
        $(MAKE) -C $(GAME_EM_DIR) clean
+       $(MAKE) -C $(GAME_SP_DIR) clean
        $(RM) $(OBJS)
        $(RM) $(LIBGAME)
        $(RM) $(GAME_EM)
+       $(RM) $(GAME_SP)
 
 clean-ico:
        $(RM) $(ICONBASE).ico
@@ -327,11 +337,12 @@ valgrind: all
 dist-clean: clean-obj
 
 tags:
-       $(ETAGS) *.[ch] $(LIBGAME_DIR)/*.[ch] $(GAME_EM_DIR)/*.[ch]
+       $(ETAGS) *.[ch] $(LIBGAME_DIR)/*.[ch] $(GAME_EM_DIR)/*.[ch] $(GAME_SP_DIR)/*.[ch]
 
 depend:
        $(MAKE) -C $(LIBGAME_DIR) depend
        $(MAKE) -C $(GAME_EM_DIR) depend
+       $(MAKE) -C $(GAME_SP_DIR) depend
        for i in $(SRCS); do $(CPP) $(CFLAGS) -M $$i; done > .depend
 
 ifeq (.depend,$(wildcard .depend))
index e3b6bfc91f60b860a302f5b0a28817ac1e4121da..7d13d780b794b9e88956ec73a5fc9a7fb22f5287 100644 (file)
@@ -1 +1 @@
-#define COMPILE_DATE_STRING "2009-06-15 22:46"
+#define COMPILE_DATE_STRING "2009-06-23 02:12"
index 156a639882e4b9dbe7e38cd65ae548d33f05c654..715edef3902d09b03fe2080ec2b589900407e5fb 100644 (file)
@@ -16,6 +16,7 @@
 
 #include "libgame/libgame.h"
 #include "game_em/export.h"
+#include "game_sp/export.h"
 
 
 /* ========================================================================= */
index bfa498816b667306e86dcf59f9ce43a6b07f0b18..239b85ec89a51863584162e5c2a7a9f840016854 100644 (file)
@@ -6160,6 +6160,9 @@ void LoadLevelFromFileInfo(struct LevelInfo *level,
 
     case LEVEL_FILE_TYPE_SP:
       LoadLevelFromFileInfo_SP(level, level_file_info);
+#if 1
+      level->game_engine_type = GAME_ENGINE_TYPE_SP;
+#endif
       break;
 
     case LEVEL_FILE_TYPE_DC:
index d4e4cf3f28c69bc7331151108bc03d011410b082..daf96fe52f7da0c1e22d0cfc4b6fa5539d17bd27 100644 (file)
@@ -4468,6 +4468,13 @@ void InitGame()
     /* blit playfield from scroll buffer to normal back buffer for fading in */
     BlitScreenToBitmap_EM(backbuffer);
   }
+  else if (level.game_engine_type == GAME_ENGINE_TYPE_SP)
+  {
+    InitGameEngine_SP();
+
+    /* blit playfield from scroll buffer to normal back buffer for fading in */
+    BlitScreenToBitmap_SP(backbuffer);
+  }
   else
   {
     DrawLevel();
@@ -12341,6 +12348,10 @@ void GameActions()
   {
     GameActions_EM_Main();
   }
+  else if (level.game_engine_type == GAME_ENGINE_TYPE_SP)
+  {
+    GameActions_SP_Main();
+  }
   else
   {
     GameActions_RND();
@@ -12363,6 +12374,22 @@ void GameActions_EM_Main()
   AdvanceFrameAndPlayerCounters(-1);   /* advance counters for all players */
 }
 
+void GameActions_SP_Main()
+{
+  byte effective_action[MAX_PLAYERS];
+  boolean warp_mode = (tape.playing && tape.warp_forward && !tape.pausing);
+  int i;
+
+  for (i = 0; i < MAX_PLAYERS; i++)
+    effective_action[i] = stored_player[i].effective_action;
+
+  GameActions_SP(effective_action, warp_mode);
+
+  CheckLevelTime();
+
+  AdvanceFrameAndPlayerCounters(-1);   /* advance counters for all players */
+}
+
 void GameActions_RND()
 {
   int magic_wall_x = 0, magic_wall_y = 0;
index 7a9bf984963fd9b76a8cc276605e23c203f0ac41..c957974cb49a98e532a41fc5d70b367ff0c7e0f9 100644 (file)
@@ -331,6 +331,7 @@ void StartGameActions(boolean, boolean, long);
 
 void GameActions(void);
 void GameActions_EM_Main();
+void GameActions_SP_Main();
 void GameActions_RND();
 
 void ScrollLevel(int, int);
index aec69d091a181b622e9c068441192bc77a5534d9..4fc21cd0f12f70d64b654b99203430597c36e5e0 100644 (file)
@@ -1,7 +1,7 @@
 # =============================================================================
 # Rocks'n'Diamonds Makefile (game_em)
 # -----------------------------------------------------------------------------
-# (c) 1995-2005 Holger Schemel <info@artsoft.org>
+# (c) 1995-2006 Holger Schemel <info@artsoft.org>
 # -----------------------------------------------------------------------------
 # Emerald Mine for X11 © 2000,2001 David Tritscher
 # =============================================================================
index 05e7ae65c5d8ce7c5ccec27055d7d3c32d00a0e1..f165712375a4f9138386b8abd1f509058695c9c9 100644 (file)
@@ -1,5 +1,5 @@
-#ifndef EXPORT_H
-#define EXPORT_H
+#ifndef GAME_SP_EXPORT_H
+#define GAME_SP_EXPORT_H
 
 /* ========================================================================= */
 /* functions and definitions exported from game_em to main program           */
@@ -743,4 +743,4 @@ extern void DrawGameDoorValues_EM();
 extern void LoadEngineSnapshotValues_EM();
 extern void SaveEngineSnapshotValues_EM();
 
-#endif /* EXPORT_H */
+#endif /* GAME_SP_EXPORT_H */
index 87e9d9527fb147a470eddbf8684cb25adc0ae20d..add5ae09e61e2076203ead5fe106f775a099043e 100644 (file)
@@ -77,7 +77,6 @@
 /* often used screen positions */
 #define ORIG_MENU_SX           ((ORIG_SCR_MENUX - SCR_MENUX) * TILEX / 2)
 #define ORIG_MENU_SY           0
-#define SY                     8
 #define SX                     8
 #define SY                     8
 #define SXSIZE                 (SCR_FIELDX * TILEX)
diff --git a/src/game_sp/ASM.c b/src/game_sp/ASM.c
new file mode 100644 (file)
index 0000000..6ef27ee
--- /dev/null
@@ -0,0 +1,205 @@
+// ----------------------------------------------------------------------------
+// ASM.c
+// ----------------------------------------------------------------------------
+
+#include "ASM.h"
+
+static char *VB_Name = "modASM";
+// --- Option Explicit
+
+// PseudoRegisters:
+// Public ax%, bx%
+// --- const int ByteMask = 0xFF;
+int cmpFlag;
+
+void Neg(int *Val)
+{
+  *Val = -*Val;
+}
+
+void Mov(int *Var, int Val)
+{
+  *Var = Val;
+}
+
+void MovLowByte(int *Var, int Val)
+{
+  *Var = (*Var & 0xFF00) | (Val & 0xFF);
+}
+
+void MovHighByte(int *Var, int Val)
+{
+  int Tmp;
+
+  Tmp = Val & 0x7F;
+  Tmp = 0x100 * Tmp;
+  if ((Val & 0x80) != 0)
+    Tmp = Tmp | 0x8000;
+
+  *Var = (*Var & 0xFF) | Tmp;
+}
+
+int LowByte(int Var)
+{
+  int LowByte;
+
+  // Dim Tmp As Byte
+  LowByte = (Var & 0xFF);
+  // LowByte = ByteToInt(Tmp)
+
+  return LowByte;
+}
+
+int HighByte(int Var)
+{
+  int HighByte;
+
+  if (Var & 0x8000)
+  {
+    HighByte = ((Var & 0x7FFF) / 0x100) | 0x80;
+  }
+  else
+  {
+    HighByte = Var / 0x100;
+  }
+
+  return HighByte;
+}
+
+int SgnHighByte(int Var) // extends the signum to 16 bit
+{
+  int SgnHighByte;
+
+  if (Var & 0x8000)
+  {
+    SgnHighByte = ((Var & 0x7FFF) / 0x100) | 0xFF80;
+  }
+  else
+  {
+    SgnHighByte = Var / 0x100;
+  }
+
+  return SgnHighByte;
+}
+
+boolean Less()
+{
+  boolean Less;
+
+  Less = (cmpFlag < 0);
+
+  return Less;
+}
+
+boolean GreaterOrEqual()
+{
+  boolean GreaterOrEqual;
+
+  GreaterOrEqual = (0 <= cmpFlag);
+
+  return GreaterOrEqual;
+}
+
+boolean Equal()
+{
+  boolean Equal;
+
+  Equal = (0 == cmpFlag);
+
+  return Equal;
+}
+
+void CMP(int A, int B)
+{
+  cmpFlag = A - B;
+}
+
+void Add(int *A, int B)
+{
+  *A = *A + B;
+}
+
+void MySub(int *A, int B)
+{
+  *A = *A - B;
+}
+
+int SHR(int Var, int Count)
+{
+  int SHR;
+
+  int i;
+
+  if (Var & 0x8000)
+  {
+    Var = ((Var & 0x7FFF) / 2) | 0x4000;
+  }
+  else
+  {
+    Var = Var / 2;
+  }
+
+  for (i = 2; i <= Count; i++)
+  {
+    Var = Var / 2;
+  }
+
+  return SHR;
+}
+
+int SHL(int Var, int Count)
+{
+  int SHL;
+
+  int i;
+
+  for (i = 1; i <= Count; i++)
+  {
+    Var = Var & 0x7FFF;
+    if ((Var & 0x4000) != 0)
+    {
+      Var = (2 * (Var & 0x3FFF)) | 0x8000;
+    }
+    else
+    {
+      Var = 2 * Var;
+    }
+  }
+
+  return SHL;
+}
+
+int ByteToInt(byte B)
+{
+  int ByteToInt;
+
+  if ((B & 0x80) == 0x80)
+  {
+    ByteToInt = -(0xFF - B + 1);
+  }
+  else
+  {
+    ByteToInt = B;
+  }
+
+  return ByteToInt;
+}
+
+byte IntToByte(int i)
+{
+  byte IntToByte;
+
+  // IntToByte = CByte(i & 0xFF);
+  IntToByte = (byte)(i & 0xFF);
+
+  return IntToByte;
+}
+
+void XCHG(int A, int B)
+{
+  int Tmp;
+
+  Tmp = B;
+  B = A;
+  A = Tmp;
+}
diff --git a/src/game_sp/ASM.h b/src/game_sp/ASM.h
new file mode 100644 (file)
index 0000000..3b27732
--- /dev/null
@@ -0,0 +1,38 @@
+// ----------------------------------------------------------------------------
+// ASM.h
+// ----------------------------------------------------------------------------
+
+#ifndef ASM_H
+#define ASM_H
+
+#include "vb_types.h"
+#include "vb_defs.h"
+#include "vb_vars.h"
+#include "vb_lib.h"
+
+#include "global.h"
+
+#define ByteMask                       (0xFF)
+
+extern void Add(int *A, int B);
+extern int ByteToInt(byte B);
+extern void CMP(int A, int B);
+extern boolean Equal();
+extern boolean GreaterOrEqual();
+extern int HighByte(int Var);
+extern byte IntToByte(int i);
+extern boolean Less();
+extern int LowByte(int Var);
+extern void Mov(int *Var, int Val);
+extern void MovHighByte(int *Var, int Val);
+extern void MovLowByte(int *Var, int Val);
+extern void MySub(int *A, int B);
+extern void Neg(int *Val);
+extern int SHL(int Var, int Count);
+extern int SHR(int Var, int Count);
+extern int SgnHighByte(int Var);
+extern void XCHG(int A, int B);
+
+extern int cmpFlag;
+
+#endif /* ASM_H */
diff --git a/src/game_sp/BitMapObject.c b/src/game_sp/BitMapObject.c
new file mode 100644 (file)
index 0000000..dafb965
--- /dev/null
@@ -0,0 +1,588 @@
+// ----------------------------------------------------------------------------
+// BitMapObject.c
+// ----------------------------------------------------------------------------
+
+#include "BitMapObject.h"
+
+static void ConvertToVBPalette();
+static long Get_ByteWidth();
+static long Get_LineLength();
+static void ReDimArrays();
+
+// --- VERSION 1.0 CLASS
+// --- BEGIN
+// ---   MultiUse = -1  'True  // True
+// ---   Persistable = 0  'NotPersistable  // NotPersistable
+// ---   DataBindingBehavior = 0  'vbNone  // vbNone
+// ---   DataSourceBehavior  = 0  'vbNone  // vbNone
+// ---   MTSTransactionMode  = 0  'NotAnMTSObject  // NotAnMTSObject
+// --- END
+
+static char *VB_Name = "BitMapObject";
+static boolean VB_GlobalNameSpace = False;
+static boolean VB_Creatable = True;
+static boolean VB_PredeclaredId = False;
+static boolean VB_Exposed = False;
+// --- Option Explicit
+
+// info von http://web.usxchange.net/elmo/bmp.htm
+
+// A BMP file consists of the four following parts:
+//
+//   1.BITMAPFILEHEADER
+//   2.BITMAPINFOHEADER
+//   3.A color table of RGBQUAD structures (1, 4 & 8 bit only)
+//   4.An array of bytes for the actual image data
+
+// 1.BITMAPFILEHEADER
+//        1.bfType
+//               Declared an unsigned integer. But, this is just to reserve space for 2 bytes.
+//               The 2 bytes must be the 2 characters BM to indicate a BitMap file.
+//        2.bfSize
+//               Total size of file in bytes.
+//        3.bfReserved1
+//               Always zero (ignore).
+//        4.bfReserved2
+//               Always zero (ignore).
+//        5.bfOffBits
+//               Specifies the byte offset from the BITMAPFILEHEADER structure to the actual bitmap data in the file.
+// ::: #ifndef HAS_BitmapFileHeaderType
+// ::: typedef struct // {    /* bmfh */
+// ::: {
+// :::   byte bfTypeB;
+// :::   byte bfTypeM;
+// :::   long bfSize;
+// :::   int bfReserved1;
+// :::   int bfReserved2;
+// :::   long bfOffBits;
+// ::: } BitmapFileHeaderType;
+// ::: #define HAS_BitmapFileHeaderType
+// ::: #endif
+
+//   2.BITMAPINFOHEADER
+//        1.biSize
+//               Size of BITMAPINFOHEADER structure (should always be 40).
+//        2.biWidth
+//               Width of image in pixels.
+//        3.biHeight
+//               Height of image in pixels.
+//        4.biPlanes
+//               Always one (ignore).
+//        5.biBitCount
+//               Specifies the number of bits per pixel. This value must be 1, 4, 8, or 24.
+//        6.biCompression
+//               Specifies the type of compression.
+//                  1.BI_RGB No compression.
+//                  2.BI_RLE8 8 bit RLE
+//                  3.BI_RLE4 4 bit RLE
+//        7.biSizeImage
+//               Specifies the size, in bytes, of the image data. May be zero if the bitmap is in the BI_RGB format.
+//        8.biXPelsPerMeter
+//               Ignore.
+//        9.biYPelsPerMeter
+//               Ignore.
+//       10.biClrUsed
+//               Specifies the number of color indices in the color table. Zero indicaes the bitmap uses the maximum number of colors corresponding to the value of the
+//               biBitCount member e.g. 8 bit -> 256 colors.
+//
+//               The maximum number of colors = 2N. Where N = biBitCount. 2N is the same as 1 << N. The same as you can get powers of 10 by shifting the decimal point
+//               in a decimal number, only it is binary.
+//       11.biClrImportant
+//               Ignore.
+// ::: #ifndef HAS_BitmapInfoHeaderType
+// ::: typedef struct // {    /* bmih */
+// ::: {
+// :::   long biSize;
+// :::   long biWidth;
+// :::   long biHeight;
+// :::   int biPlanes;
+// :::   int biBitCount;
+// :::   long biCompression;
+// :::   long biSizeImage;
+// :::   long biXPelsPerMeter;
+// :::   long biYPelsPerMeter;
+// :::   long biClrUsed;
+// :::   long biClrImportant;
+// ::: } BitmapInfoHeaderType;
+// ::: #define HAS_BitmapInfoHeaderType
+// ::: #endif
+
+//   3.A color table of RGBQUAD structures (1, 4 & 8 bit only)
+//          RGBQUAD structure is self explanatory.
+// ::: #ifndef HAS_RGBQUADType
+// ::: typedef struct // {     /* rgbq */
+// ::: {
+// :::   byte rgbBlue;
+// :::   byte rgbGreen;
+// :::   byte rgbRed;
+// :::   byte rgbReserved;
+// ::: } RGBQUADType;
+// ::: #define HAS_RGBQUADType
+// ::: #endif
+
+RGBQUADType *ColorTable;
+long *VBPalette;
+
+//   4.An array of bytes for the actual image data
+//          Bits per pixel & compression determined by biBitCount & biCompression.
+
+byte *ImageDataBytes;
+
+// ######################################################################################################
+
+BitmapFileHeaderType BMFH;
+BitmapInfoHeaderType BMIH;
+
+static long Get_LineLength()
+{
+  static long LineLength;
+
+  LineLength = 4 * (((Get_ByteWidth() - 1) / 4) + 1);
+
+  return LineLength;
+}
+
+static long Get_ByteWidth()
+{
+  static long ByteWidth;
+
+  ByteWidth = BMIH.biWidth * BMIH.biBitCount / 8;
+
+  return ByteWidth;
+}
+
+void BitMapObject_CreateAtSize(long XPixels, long YPixels, long BitsPerPixel)
+{
+  {
+    BMIH.biWidth = XPixels;
+    BMIH.biHeight = YPixels;
+    BMIH.biSize = 40;
+    BMIH.biBitCount = BitsPerPixel;
+    BMIH.biClrUsed = (1 << BMIH.biBitCount);
+    BMIH.biPlanes = 1;
+    BMIH.biClrImportant = BMIH.biClrUsed;
+    BMIH.biCompression = 0;
+  }
+  {
+    BMFH.bfTypeB = 0x42; // B'
+    BMFH.bfTypeM = 0x4D; // M'
+  }
+  ReDimArrays();
+}
+
+void BitMapObject_CreateFromFile(char *Path)
+{
+  long FNum;
+
+  FNum = FreeFile();
+  if (! FileExists(Path))
+    return;
+
+  if (FileLen(Path) < (Len(BMFH) + Len(BMIH)))
+    return;
+
+  FNum = fopen(Path, "rb");
+  FILE_GET(FNum, -1, &BMFH, sizeof(BMFH));
+  FILE_GET(FNum, -1, &BMIH, sizeof(BMIH));
+  ReDimArrays();
+  {
+    if (BMIH.biCompression != 0)
+    {
+      Err.Raise(600, "BitMapObject", "Cannot read compressed BMP files");
+      fclose(FNum);
+      return;
+    }
+
+    if (BMIH.biBitCount < 9)
+    {
+      FILE_GET(FNum, -1, &ColorTable, sizeof(ColorTable));
+    }
+
+  }
+  FILE_GET(FNum, 1 + BMFH.bfOffBits, &ImageDataBytes, sizeof(ImageDataBytes));
+  fclose(FNum);
+  if (BMIH.biBitCount < 9)
+    ConvertToVBPalette();
+}
+
+void BitMapObject_SaveToFile(char *Path)
+{
+  long FNum;
+
+  BMFH.bfOffBits = Len(BMFH) + Len(BMIH);
+  if (BMIH.biBitCount < 9)
+    BMFH.bfOffBits = BMFH.bfOffBits + ((1 << BMIH.biBitCount)) * Len(ColorTable[0]);
+
+  BMIH.biSizeImage = Get_LineLength() * BMIH.biHeight;
+  BMFH.bfSize = BMFH.bfOffBits + BMIH.biSizeImage;
+  FNum = FreeFile();
+  FNum = fopen(Path, "wb");
+  FILE_PUT(FNum, -1, &BMFH, sizeof(BMFH));
+  FILE_PUT(FNum, -1, &BMIH, sizeof(BMIH));
+  if (BMIH.biBitCount < 9)
+  {
+    FILE_PUT(FNum, -1, &ColorTable, sizeof(ColorTable));
+  }
+
+  FILE_PUT(FNum, -1, &ImageDataBytes, sizeof(ImageDataBytes));
+  fclose(FNum);
+}
+
+static void ConvertToVBPalette()
+{
+  long ColMax, i;
+
+  ColMax = UBound(ColorTable);
+  for (i = 0; i <= ColMax; i++)
+  {
+    {
+      VBPalette[i] = RGB(ColorTable[i].rgbRed, ColorTable[i].rgbGreen, ColorTable[i].rgbBlue);
+    }
+  }
+}
+
+static void ReDimArrays()
+{
+  {
+    if (BMIH.biBitCount < 9)
+    {
+      BMIH.biClrUsed = (1 << BMIH.biBitCount);
+      ColorTable = REDIM_1D(sizeof(RGBQUADType), 0, BMIH.biClrUsed - 1);
+      VBPalette = REDIM_1D(sizeof(long), 0, BMIH.biClrUsed - 1);
+    }
+
+    if (0 < Get_LineLength() && 0 < BMIH.biHeight)
+    {
+      ImageDataBytes = REDIM_2D(sizeof(byte), 0, Get_LineLength() - 1, 0, BMIH.biHeight - 1);
+    }
+
+  }
+}
+
+long BitMapObject_Get_Palette(long Index)
+{
+  long Palette;
+
+  Palette = VBPalette[Index];
+
+  return Palette;
+}
+
+void BitMapObject_Let_Palette(long Index, long NewVal)
+{
+  VBPalette[Index] = NewVal & 0xFFFFFF;
+  {
+    ColorTable[Index].rgbRed = (NewVal & 0xFF) / 0x1;
+    ColorTable[Index].rgbGreen = (NewVal & 0xFF00) / 0x100;
+    ColorTable[Index].rgbBlue = (NewVal & 0xFF0000) / 0x10000;
+  }
+}
+
+long BitMapObject_Get_ColorsUsed()
+{
+  long ColorsUsed;
+
+  if (BMIH.biBitCount < 9)
+  {
+    ColorsUsed = (1 << BMIH.biBitCount);
+  }
+  else
+  {
+    ColorsUsed = 0;
+  }
+
+  return ColorsUsed;
+}
+
+long BitMapObject_Get_ColorIndex(long X, long Y)
+{
+  long ColorIndex;
+
+  long ColIndex, NewX, BitPos, nY;
+
+  if (8 < BMIH.biBitCount)
+  {
+    Err.Raise(600, "BitmapObject", "I have ! Palette in this ColorDepthMode");
+    ColorIndex = -1;
+    return ColorIndex;
+  }
+
+  nY = BMIH.biHeight - 1 - Y;
+  switch (BMIH.biBitCount)
+  {
+    case 1:
+      ColIndex = ImageDataBytes[X / 8, nY];
+      BitPos = 7 - (X % 8);
+      NewX = (1 << BitPos);
+      if ((NewX && ColIndex) == 0)
+      {
+        ColorIndex = 0;
+      }
+      else
+      {
+        ColorIndex = 1;
+      }
+
+      break;
+
+    case 4:
+      ColIndex = ImageDataBytes[X / 2, nY];
+      if ((X % 2) == 0)
+      {
+        ColorIndex = (ColIndex & 0xF0) / 0x10;
+      }
+      else
+      {
+        ColorIndex = (ColIndex & 0xF);
+      }
+
+      break;
+
+    case 8:
+      ColorIndex = ImageDataBytes[X, nY];
+      break;
+
+    default:
+      Err.Raise(600, "BitmapObject", "Invalid bpx value");
+      break;
+  }
+
+  return ColorIndex;
+}
+
+void BitMapObject_Let_ColorIndex(long X, long Y, long ColorIndex)
+{
+  long ColIndex, ByteVal, NewX, BitPos, nY;
+
+  if (8 < BMIH.biBitCount)
+  {
+    Err.Raise(600, "BitmapObject", "I have ! Palette in this ColorDepthMode");
+    return;
+  }
+
+  nY = BMIH.biHeight - 1 - Y;
+  switch (BMIH.biBitCount)
+  {
+    case 1:
+      ByteVal = ImageDataBytes[X / 8, nY];
+      BitPos = 7 - (X % 8);
+      NewX = (1 << BitPos);
+      ColIndex = ColorIndex * NewX;
+      if (ColIndex == 0)
+      {
+        ByteVal = (ByteVal & (! NewX));
+      }
+      else
+      {
+        ByteVal = (ByteVal | NewX);
+      }
+
+      ImageDataBytes[X / 8, nY] = ByteVal;
+      break;
+
+    case 4:
+      ByteVal = ImageDataBytes[X / 2, nY];
+      if ((X % 2) == 0)
+      {
+        ByteVal = (ByteVal & 0xF) + ColorIndex * 0x10;
+      }
+      else
+      {
+        ByteVal = (ByteVal & 0xF0) + ColorIndex;
+      }
+
+      ImageDataBytes[X / 2, nY] = ByteVal;
+      break;
+
+    case 8:
+      ImageDataBytes[X, nY] = ColorIndex;
+      break;
+
+    case 24:
+      Err.Raise(600, "BitmapObject", "Invalid bpx value");
+      break;
+  }
+}
+
+long BitMapObject_Get_Point(long X, long Y)
+{
+  long Point;
+
+  long ColIndex, NewX, BitPos, nY;
+
+  nY = BMIH.biHeight - 1 - Y;
+  switch (BMIH.biBitCount)
+  {
+    case 1:
+      ColIndex = ImageDataBytes[X / 8, nY];
+      BitPos = 7 - (X % 8);
+      NewX = (1 << BitPos);
+      if ((NewX && ColIndex) == 0)
+      {
+        ColIndex = 0;
+      }
+      else
+      {
+        ColIndex = 1;
+      }
+
+      Point = VBPalette[ColIndex];
+      break;
+
+    case 4:
+      ColIndex = ImageDataBytes[X / 2, nY];
+      if ((X % 2) == 0)
+      {
+        ColIndex = (ColIndex & 0xF0) / 0x10;
+      }
+      else
+      {
+        ColIndex = (ColIndex & 0xF);
+      }
+
+      Point = VBPalette[ColIndex];
+      break;
+
+    case 8:
+      ColIndex = ImageDataBytes[X, nY];
+      Point = VBPalette[ColIndex];
+      break;
+
+    case 24:
+      NewX = 3 * X;
+      Point = ImageDataBytes[NewX, nY] * 0x10000;
+      Point = Point + ImageDataBytes[NewX + 1, nY] * 0x100;
+      Point = Point + ImageDataBytes[NewX + 2, nY];
+      break;
+
+    default:
+      Err.Raise(600, "BitmapObject", "Invalid bpx value");
+      break;
+  }
+
+  return Point;
+}
+
+void BitMapObject_Let_Point(long X, long Y, long NewColor)
+{
+  long ColIndex, ByteVal, NewX, BitPos, nY;
+
+  nY = BMIH.biHeight - 1 - Y;
+  switch (BMIH.biBitCount)
+  {
+    case 1:
+      ColIndex = GetPaletteIndex(NewColor);
+      ByteVal = ImageDataBytes[X / 8, nY];
+      BitPos = 7 - (X % 8);
+      NewX = (1 << BitPos);
+      ColIndex = ColIndex * NewX;
+      if (ColIndex == 0)
+      {
+        ByteVal = (ByteVal & (! NewX));
+      }
+      else
+      {
+        ByteVal = (ByteVal | NewX);
+      }
+
+      ImageDataBytes[X / 8, nY] = ByteVal;
+      break;
+
+    case 4:
+      ColIndex = GetPaletteIndex(NewColor);
+      ByteVal = ImageDataBytes[X / 2, nY];
+      if ((X % 2) == 0)
+      {
+        ByteVal = (ByteVal & 0xF) + ColIndex * 0x10;
+      }
+      else
+      {
+        ByteVal = (ByteVal & 0xF0) + ColIndex;
+      }
+
+      ImageDataBytes[X / 2, nY] = ByteVal;
+      break;
+
+    case 8:
+      ImageDataBytes[X, nY] = GetPaletteIndex(NewColor);
+      break;
+
+    case 24:
+      NewX = 3 * X;
+      ImageDataBytes[NewX, nY] = (NewColor & 0xFF0000) / 0x10000;  // B
+      ImageDataBytes[NewX + 1, nY] = (NewColor & 0xFF00) / 0x100;  // G
+      ImageDataBytes[NewX + 2, nY] = (NewColor & 0xFF);  // R
+      break;
+
+    default:
+      Err.Raise(600, "BitmapObject", "Invalid bpx value");
+      break;
+  }
+}
+
+int BitMapObject_GetPaletteIndex(long Color)
+{
+  int GetPaletteIndex;
+
+  long i, ColMax;
+
+  ColMax = UBound(VBPalette);
+  for (i = 0; i <= ColMax; i++)
+  {
+    if (VBPalette[i] == Color)
+      break;
+  }
+
+  if (ColMax < i) // Error - Color not in Palette!
+    i = -1;
+
+  GetPaletteIndex = i;
+
+  return GetPaletteIndex;
+}
+
+long BitMapObject_Get_Width()
+{
+  long Width;
+
+  Width = BMIH.biWidth;
+
+  return Width;
+}
+
+long BitMapObject_Get_Height()
+{
+  long Height;
+
+  Height = BMIH.biHeight;
+
+  return Height;
+}
+
+BitMapObject BitMapObject_GetStretchCopy(float StretchVal)
+{
+  BitMapObject GetStretchCopy;
+
+  long nWidth, nHeight, iX, iY;
+
+  // GetStretchCopy = New BitMapObject; // (handle this later, if needed)
+  nWidth = StretchVal * BMIH.biWidth;
+  nHeight = StretchVal * BMIH.biHeight;
+  GetStretchCopy.CreateAtSize(nWidth, nHeight, CLng(BMIH.biBitCount));
+  nWidth = nWidth - 1;
+  nHeight = nHeight - 1;
+  for (iX = 0; iX <= BMIH.biClrUsed - 1; iX++)
+  {
+    GetStretchCopy.Let_Palette(iX, Palette(iX));
+  }
+
+  for (iY = 0; iY <= nHeight; iY++)
+  {
+    for (iX = 0; iX <= nWidth; iX++)
+    {
+      GetStretchCopy.Let_ColorIndex(iX, iY, ColorIndex(Int(iX / StretchVal), Int(iY / StretchVal)));
+    }
+  }
+
+  return GetStretchCopy;
+}
diff --git a/src/game_sp/BitMapObject.h b/src/game_sp/BitMapObject.h
new file mode 100644 (file)
index 0000000..64c10d9
--- /dev/null
@@ -0,0 +1,72 @@
+// ----------------------------------------------------------------------------
+// BitMapObject.h
+// ----------------------------------------------------------------------------
+
+#ifndef BITMAPOBJECT_H
+#define BITMAPOBJECT_H
+
+#include "vb_types.h"
+#include "vb_defs.h"
+#include "vb_vars.h"
+#include "vb_lib.h"
+
+#include "global.h"
+
+#ifndef HAS_BitmapFileHeaderType
+typedef struct // {    /* bmfh */
+{
+  byte bfTypeB;
+  byte bfTypeM;
+  long bfSize;
+  int bfReserved1;
+  int bfReserved2;
+  long bfOffBits;
+} BitmapFileHeaderType;
+#define HAS_BitmapFileHeaderType
+#endif
+
+#ifndef HAS_BitmapInfoHeaderType
+typedef struct // {    /* bmih */
+{
+  long biSize;
+  long biWidth;
+  long biHeight;
+  int biPlanes;
+  int biBitCount;
+  long biCompression;
+  long biSizeImage;
+  long biXPelsPerMeter;
+  long biYPelsPerMeter;
+  long biClrUsed;
+  long biClrImportant;
+} BitmapInfoHeaderType;
+#define HAS_BitmapInfoHeaderType
+#endif
+
+#ifndef HAS_RGBQUADType
+typedef struct // {     /* rgbq */
+{
+  byte rgbBlue;
+  byte rgbGreen;
+  byte rgbRed;
+  byte rgbReserved;
+} RGBQUADType;
+#define HAS_RGBQUADType
+#endif
+
+extern void BitMapObject_CreateAtSize(long XPixels, long YPixels, long BitsPerPixel);
+extern void BitMapObject_CreateFromFile(char *Path);
+extern int BitMapObject_GetPaletteIndex(long Color);
+extern BitMapObject BitMapObject_GetStretchCopy(float StretchVal);
+extern long BitMapObject_Get_ColorIndex(long X, long Y);
+extern long BitMapObject_Get_ColorsUsed();
+extern long BitMapObject_Get_Height();
+extern long BitMapObject_Get_Palette(long Index);
+extern long BitMapObject_Get_Point(long X, long Y);
+extern long BitMapObject_Get_Width();
+extern void BitMapObject_Let_ColorIndex(long X, long Y, long ColorIndex);
+extern void BitMapObject_Let_Palette(long Index, long NewVal);
+extern void BitMapObject_Let_Point(long X, long Y, long NewColor);
+extern void BitMapObject_SaveToFile(char *Path);
+
+#endif /* BITMAPOBJECT_H */
diff --git a/src/game_sp/BugsTerminals.c b/src/game_sp/BugsTerminals.c
new file mode 100644 (file)
index 0000000..f560395
--- /dev/null
@@ -0,0 +1,183 @@
+// ----------------------------------------------------------------------------
+// BugsTerminals.c
+// ----------------------------------------------------------------------------
+
+#include "BugsTerminals.h"
+
+static char *VB_Name = "modBugTerminal";
+// --- Option Explicit
+
+long GetTickCount();
+
+byte *TerminalState;
+int TerminalMaxCycles;
+#define aniTerminal                    (0x80)
+
+// ==========================================================================
+//                              SUBROUTINE
+// Animate bugs
+// ==========================================================================
+
+int subAnimateBugs(int si)
+{
+  int subAnimateBugs;
+
+  int ax, bx, cx, dx, di;
+  int ah, bh, ch, dh, al, bl, cl, dl;
+
+  if (fiBug != LowByte(PlayField16[si]))
+    return subAnimateBugs;
+
+  if (0 != (TimerVar & 3))
+    return subAnimateBugs;
+
+  bl = SgnHighByte(PlayField16[si]); // get and increment sequence#
+  bl = bl + 1;
+  if (bl >= 0xE)
+  {
+    bl = subGetRandomNumber(); // generate new random number
+    bl = -((bl & 0x3F) + 0x20);
+  }
+
+  MovHighByte(&PlayField16[si], bl); // save sequence#
+  if (bl < 0) // bug sleeps / is inactive
+    return subAnimateBugs;
+
+  // now the bug is active! Beware Murphy!
+  if ((ByteMask && PlayField16[si - FieldWidth - 1]) == fiMurphy)
+    goto markPlaySound;
+
+  if ((ByteMask && PlayField16[si - FieldWidth]) == fiMurphy)
+    goto markPlaySound;
+
+  if ((ByteMask && PlayField16[si - FieldWidth + 1]) == fiMurphy)
+    goto markPlaySound;
+
+  if ((ByteMask && PlayField16[si - 1]) == fiMurphy)
+    goto markPlaySound;
+
+  if ((ByteMask && PlayField16[si + 1]) == fiMurphy)
+    goto markPlaySound;
+
+  if ((ByteMask && PlayField16[si + FieldWidth - 1]) == fiMurphy)
+    goto markPlaySound;
+
+  if ((ByteMask && PlayField16[si + FieldWidth]) == fiMurphy)
+    goto markPlaySound;
+
+  if ((ByteMask && PlayField16[si + FieldWidth + 1]) == fiMurphy)
+    goto markPlaySound;
+
+  goto markDisplay;
+
+markPlaySound:
+  subSoundFXBug(); // play dangerous sound
+
+markDisplay:
+  // ++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+  cx = aniBug[bl];
+  StretchedSprites.BltEx(GetStretchX(si), GetStretchY(si), cx);
+  // ++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+
+  return subAnimateBugs;
+} // subAnimateBugs
+
+// ==========================================================================
+//                              SUBROUTINE
+// Animate terminals
+// ==========================================================================
+int subAnimateTerminals(int si)
+{
+  int subAnimateTerminals;
+
+  int bl, ax, al, X, Y;
+
+  if (LowByte(PlayField16[si]) != fiTerminal)
+    return subAnimateTerminals;
+
+  bl = HighByte(PlayField16[si]);
+  if ((bl & 0x80) == 0x80)
+    bl = (bl | 0xFF00);
+
+  bl = bl + 1;
+  if (bl <= 0)
+  {
+    MovHighByte(&PlayField16[si], bl);
+    return subAnimateTerminals;
+  }
+
+  bl = -(subGetRandomNumber() & TerminalMaxCycles); // generate new random number
+  MovHighByte(&PlayField16[si], bl); // save new sequence#
+  bl = TerminalState[si] + 1;
+  if (bl == 8)
+  {
+    bl = 0;
+  }
+  else if (15 < bl)
+  {
+    bl = 8;
+  }
+
+  TerminalState[si] = bl;
+  // ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+  al = aniTerminal + bl;
+  X = GetStretchX(si);
+  Y = GetStretchY(si);
+  StretchedSprites.BltEx(X, Y, al);
+  // ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+
+  return subAnimateTerminals;
+} // subAnimateElectrons
+
+// ==========================================================================
+//                              SUBROUTINE
+// Randomize random number generator
+// ==========================================================================
+
+int subRandomize()
+{
+  int subRandomize;
+
+  long Tick, Tmp;
+
+  Tick = GetTickCount();
+  Tmp = ((Tick ^ (long)(Tick / (1 << 16))) & 0xFFFF);
+  RandomSeed = 0x7FFF & Tmp;
+  if ((Tmp & 0x8000) != 0)
+    RandomSeed = RandomSeed | 0x8000;
+
+  return subRandomize;
+} // subRandomize
+
+
+// ==========================================================================
+//                              SUBROUTINE
+// Generate new random number, first method (see also sub_g_8580)
+// ==========================================================================
+
+int subGetRandomNumber()
+{
+  int subGetRandomNumber;
+
+  long Tmp, RSeed;
+
+  RSeed = (long)(0x7FFF & RandomSeed);
+  if (0x8000 == (RandomSeed & 0x8000))
+    RSeed = RSeed | 0x8000;
+
+  Tmp = 0xFFFF & (((0x5E5 * RandomSeed) & 0xFFFF) + 0x31);
+  RandomSeed = 0x7FFF & Tmp;
+  if ((Tmp & 0x8000) != 0)
+    RandomSeed = RandomSeed | 0x8000;
+
+  subGetRandomNumber = Tmp / 2;
+  //  Mov ax, randomseed
+  //  Mov bx, &H5E5
+  //  mul bx                          ' dx:ax = reg * ax
+  //  Add ax, &H31
+  //  Mov randomseed, ax
+  //  shr ax,1
+
+  return subGetRandomNumber;
+} // subGetRandomNumber
+
diff --git a/src/game_sp/BugsTerminals.h b/src/game_sp/BugsTerminals.h
new file mode 100644 (file)
index 0000000..4ec01cd
--- /dev/null
@@ -0,0 +1,23 @@
+// ----------------------------------------------------------------------------
+// BugsTerminals.h
+// ----------------------------------------------------------------------------
+
+#ifndef BUGSTERMINALS_H
+#define BUGSTERMINALS_H
+
+#include "vb_types.h"
+#include "vb_defs.h"
+#include "vb_vars.h"
+#include "vb_lib.h"
+
+#include "global.h"
+
+extern int subAnimateBugs(int si);
+extern int subAnimateTerminals(int si);
+extern int subGetRandomNumber();
+extern int subRandomize();
+
+extern byte *TerminalState;
+extern int TerminalMaxCycles;
+
+#endif /* BUGSTERMINALS_H */
diff --git a/src/game_sp/Capture.c b/src/game_sp/Capture.c
new file mode 100644 (file)
index 0000000..96997f6
--- /dev/null
@@ -0,0 +1,529 @@
+// ----------------------------------------------------------------------------
+// Capture.c
+// ----------------------------------------------------------------------------
+
+#include "Capture.h"
+
+static char *VB_Name = "CaptureModule";
+// --------------------------------------------------------------------
+// ''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
+//
+// Visual Basic 4.0 16/32 Capture Routines
+//
+// This module contains several routines for capturing windows into a
+// picture.  All the routines work on both 16 and 32 bit Windows
+// platforms.
+// The routines also have palette support.
+//
+// CreateBitmapPicture - Creates a picture object from a bitmap and
+// palette.
+// CaptureWindow - Captures any window given a window handle.
+// CaptureActiveWindow - Captures the active window on the desktop.
+// CaptureForm - Captures the entire form.
+// CaptureClient - Captures the client area of a form.
+// CaptureScreen - Captures the entire screen.
+// PrintPictureToFitPage - prints any picture as big as possible on
+// the page.
+//
+// NOTES
+//    - No error trapping is included in these routines.
+// ''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
+//
+// --- Option Explicit
+// --- Option Base 0
+
+// ::: #ifndef HAS_PALETTEENTRY
+// ::: typedef struct
+// ::: {
+// :::   byte peRed;
+// :::   byte peGreen;
+// :::   byte peBlue;
+// :::   byte peFlags;
+// ::: } PALETTEENTRY;
+// ::: #define HAS_PALETTEENTRY
+// ::: #endif
+
+// ::: #ifndef HAS_LOGPALETTE
+// ::: typedef struct
+// ::: {
+// :::   int palVersion;
+// :::   int palNumEntries;
+// :::   PALETTEENTRY palPalEntry[255];  // Enough for 256 colors.
+// ::: } LOGPALETTE;
+// ::: #define HAS_LOGPALETTE
+// ::: #endif
+
+// ::: #ifndef HAS_GUID
+// ::: typedef struct
+// ::: {
+// :::   long Data1;
+// :::   int Data2;
+// :::   int Data3;
+// :::   byte Data4[7];
+// ::: } GUID;
+// ::: #define HAS_GUID
+// ::: #endif
+
+#if Win32
+
+#define RASTERCAPS                     (38)
+#define RC_PALETTE                     (0x100)
+#define SIZEPALETTE                    (104)
+
+// ::: #ifndef HAS_RECT
+// ::: typedef struct
+// ::: {
+// :::   long left;
+// :::   long top;
+// :::   long right;
+// :::   long bottom;
+// ::: } RECT;
+// ::: #define HAS_RECT
+// ::: #endif
+
+long CreateCompatibleDC(long hDC);
+long CreateCompatibleBitmap(long hDC, long nWidth, long nHeight);
+long GetDeviceCaps(long hDC, long iCapabilitiy);
+long GetSystemPaletteEntries(long hDC, long wStartIndex, long wNumEntries, PALETTEENTRY lpPaletteEntries);
+long CreatePalette(LOGPALETTE lpLogPalette);
+long SelectObject(long hDC, long hObject);
+long BitBlt(long hDCDest, long XDest, long YDest, long nWidth, long nHeight, long hDCSrc, long XSrc, long YSrc, long dwRop);
+long DeleteDC(long hDC);
+long GetForegroundWindow();
+long SelectPalette(long hDC, long hPalette, long bForceBackground);
+long RealizePalette(long hDC);
+long GetWindowDC(long hWnd);
+long GetDC(long hWnd);
+long GetWindowRect(long hWnd, RECT lpRect);
+long ReleaseDC(long hWnd, long hDC);
+long GetDesktopWindow();
+
+// ::: #ifndef HAS_PicBmp
+// ::: typedef struct
+// ::: {
+// :::   long Size;
+// :::   long Type;
+// :::   long hBmp;
+// :::   long hPal;
+// :::   long Reserved;
+// ::: } PicBmp;
+// ::: #define HAS_PicBmp
+// ::: #endif
+
+long OleCreatePictureIndirect(PicBmp PicDesc, GUID RefIID, long fPictureOwnsHandle, IPicture IPic);
+
+#elif Win16
+
+#define RASTERCAPS                     (38)
+#define RC_PALETTE                     (0x100)
+#define SIZEPALETTE                    (104)
+
+// ::: #ifndef HAS_RECT
+// ::: typedef struct
+// ::: {
+// :::   int left;
+// :::   int top;
+// :::   int right;
+// :::   int bottom;
+// ::: } RECT;
+// ::: #define HAS_RECT
+// ::: #endif
+
+int CreateCompatibleDC(int hDC);
+int CreateCompatibleBitmap(int hDC, int nWidth, int nHeight);
+int GetDeviceCaps(int hDC, int iCapabilitiy);
+int GetSystemPaletteEntries(int hDC, int wStartIndex, int wNumEntries, PALETTEENTRY lpPaletteEntries);
+int CreatePalette(LOGPALETTE lpLogPalette);
+int SelectObject(int hDC, int hObject);
+int BitBlt(int hDCDest, int XDest, int YDest, int nWidth, int nHeight, int hDCSrc, int XSrc, int YSrc, long dwRop);
+int DeleteDC(int hDC);
+int GetForegroundWindow();
+int SelectPalette(int hDC, int hPalette, int bForceBackground);
+int RealizePalette(int hDC);
+int GetWindowDC(int hWnd);
+int GetDC(int hWnd);
+int GetWindowRect(int hWnd, RECT lpRect);
+int ReleaseDC(int hWnd, int hDC);
+int GetDesktopWindow();
+
+// ::: #ifndef HAS_PicBmp
+// ::: typedef struct
+// ::: {
+// :::   int Size;
+// :::   int Type;
+// :::   int hBmp;
+// :::   int hPal;
+// :::   int Reserved;
+// ::: } PicBmp;
+// ::: #define HAS_PicBmp
+// ::: #endif
+
+int OleCreatePictureIndirect(PicBmp PictDesc, GUID RefIID, int fPictureOwnsHandle, IPicture IPic);
+
+#endif
+
+// ''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
+//
+// CreateBitmapPicture
+//    - Creates a bitmap type Picture object from a bitmap and
+//      palette.
+//
+// hBmp
+//    - Handle to a bitmap.
+//
+// hPal
+//    - Handle to a Palette.
+//    - Can be null if the bitmap doesn't use a palette.
+//
+// Returns
+//    - Returns a Picture object containing the bitmap.
+// ''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
+//
+#if Win32
+Picture CreateBitmapPicture(long hBmp, long hPal)
+{
+  Picture CreateBitmapPicture;
+
+  long r;
+
+#elif Win16
+Picture CreateBitmapPicture(int hBmp, int hPal)
+{
+  Picture CreateBitmapPicture;
+
+  int r;
+
+#endif
+  PicBmp pic;
+
+  // IPicture requires a reference to "Standard OLE Types."
+  IPicture IPic;
+  GUID IID_IDispatch;
+
+  // Fill in with IDispatch Interface ID.
+  {
+    IID_IDispatch.Data1 = 0x20400;
+    IID_IDispatch.Data4[0] = 0xC0;
+    IID_IDispatch.Data4[7] = 0x46;
+  }
+
+  // Fill Pic with necessary parts.
+  {
+    pic.Size = Len(pic);          // Length of structure.
+    pic.Type = vbPicTypeBitmap;   // Type of Picture (bitmap).
+    pic.hBmp = hBmp;              // Handle to bitmap.
+    pic.hPal = hPal;              // Handle to palette (may be null).
+  }
+
+  // Create Picture object.
+  r = OleCreatePictureIndirect(pic, IID_IDispatch, 1, IPic);
+
+  // Return the new Picture object.
+  CreateBitmapPicture = IPic;
+
+  return CreateBitmapPicture;
+}
+
+// ''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
+//
+// CaptureWindow
+//    - Captures any portion of a window.
+//
+// hWndSrc
+//    - Handle to the window to be captured.
+//
+// Client
+//    - If True CaptureWindow captures from the client area of the
+//      window.
+//    - If False CaptureWindow captures from the entire window.
+//
+// LeftSrc, TopSrc, WidthSrc, HeightSrc
+//    - Specify the portion of the window to capture.
+//    - Dimensions need to be specified in pixels.
+//
+// Returns
+//    - Returns a Picture object containing a bitmap of the specified
+//      portion of the window that was captured.
+// ''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
+// '''''
+//
+#if Win32
+Picture CaptureWindow(long hWndSrc, boolean Client, long LeftSrc, long TopSrc, long WidthSrc, long HeightSrc)
+{
+  Picture CaptureWindow;
+
+  long hDCMemory;
+  long hBmp;
+  long hBmpPrev;
+  long r;
+  long hDCSrc;
+  long hPal;
+  long hPalPrev;
+  long RasterCapsScrn;
+  long HasPaletteScrn;
+  long PaletteSizeScrn;
+
+#elif Win16
+Picture CaptureWindow(int hWndSrc, boolean Client, int LeftSrc, int TopSrc, long WidthSrc, long HeightSrc)
+{
+  Picture CaptureWindow;
+
+  int hDCMemory;
+  int hBmp;
+  int hBmpPrev;
+  int r;
+  int hDCSrc;
+  int hPal;
+  int hPalPrev;
+  int RasterCapsScrn;
+  int HasPaletteScrn;
+  int PaletteSizeScrn;
+
+#endif
+  LOGPALETTE LogPal;
+
+  // Depending on the value of Client get the proper device context.
+  if (Client)
+  {
+    hDCSrc = GetDC(hWndSrc); // Get device context for client area.
+  }
+  else
+  {
+    hDCSrc = GetWindowDC(hWndSrc); // Get device context for entire
+    // window.
+  }
+
+  // Create a memory device context for the copy process.
+  hDCMemory = CreateCompatibleDC(hDCSrc);
+  // Create a bitmap and place it in the memory DC.
+  hBmp = CreateCompatibleBitmap(hDCSrc, WidthSrc, HeightSrc);
+  hBmpPrev = SelectObject(hDCMemory, hBmp);
+
+  // Get screen properties.
+  RasterCapsScrn = GetDeviceCaps(hDCSrc, RASTERCAPS); // Raster
+  // capabilities.
+  HasPaletteScrn = RasterCapsScrn & RC_PALETTE;       // Palette
+  // support.
+  PaletteSizeScrn = GetDeviceCaps(hDCSrc, SIZEPALETTE); // Size of
+  // palette.
+
+  // If the screen has a palette make a copy and realize it.
+  if (HasPaletteScrn && (PaletteSizeScrn == 256))
+  {
+    // Create a copy of the system palette.
+    LogPal.palVersion = 0x300;
+    LogPal.palNumEntries = 256;
+    r = GetSystemPaletteEntries(hDCSrc, 0, 256, LogPal.palPalEntry[0]);
+    hPal = CreatePalette(LogPal);
+    // Select the new palette into the memory DC and realize it.
+    hPalPrev = SelectPalette(hDCMemory, hPal, 0);
+    r = RealizePalette(hDCMemory);
+  }
+
+  // Copy the on-screen image into the memory DC.
+  r = BitBlt(hDCMemory, 0, 0, WidthSrc, HeightSrc, hDCSrc, LeftSrc, TopSrc, vbSrcCopy);
+
+  // Remove the new copy of the  on-screen image.
+  hBmp = SelectObject(hDCMemory, hBmpPrev);
+
+  // If the screen has a palette get back the palette that was
+  // selected in previously.
+  if (HasPaletteScrn && (PaletteSizeScrn == 256))
+  {
+    hPal = SelectPalette(hDCMemory, hPalPrev, 0);
+  }
+
+  // Release the device context resources back to the system.
+  r = DeleteDC(hDCMemory);
+  r = ReleaseDC(hWndSrc, hDCSrc);
+
+  // Call CreateBitmapPicture to create a picture object from the
+  // bitmap and palette handles. Then return the resulting picture
+  // object.
+
+  CaptureWindow = CreateBitmapPicture(hBmp, hPal);
+
+  return CaptureWindow;
+}
+
+// ''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
+//
+// CaptureScreen
+//    - Captures the entire screen.
+//
+// Returns
+//    - Returns a Picture object containing a bitmap of the screen.
+// ''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
+//
+Picture CaptureScreen()
+{
+  Picture CaptureScreen;
+
+#if Win32
+  long hWndScreen;
+
+#elif Win16
+  int hWndScreen;
+
+#endif
+
+  // Get a handle to the desktop window.
+  hWndScreen = GetDesktopWindow();
+
+  // Call CaptureWindow to capture the entire desktop give the handle
+  // and return the resulting Picture object.
+
+  CaptureScreen = CaptureWindow(hWndScreen, False, 0, 0, Screen.Width / Screen.TwipsPerPixelX, Screen.Height / Screen.TwipsPerPixelY);
+
+  return CaptureScreen;
+}
+
+// ''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
+//
+// CaptureForm
+//    - Captures an entire form including title bar and border.
+//
+// frmSrc
+//    - The Form object to capture.
+//
+// Returns
+//    - Returns a Picture object containing a bitmap of the entire
+//      form.
+// ''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
+//
+Picture CaptureForm(Form frmSrc)
+{
+  Picture CaptureForm;
+
+  // Call CaptureWindow to capture the entire form given its window
+  // handle and then return the resulting Picture object.
+  CaptureForm = CaptureWindow(frmSrc.hWnd, False, 0, 0, frmSrc.ScaleX(frmSrc.Width, vbTwips, vbPixels), frmSrc.ScaleY(frmSrc.Height, vbTwips, vbPixels));
+
+  return CaptureForm;
+}
+
+// ''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
+//
+// CaptureClient
+//    - Captures the client area of a form.
+//
+// frmSrc
+//    - The Form object to capture.
+//
+// Returns
+//    - Returns a Picture object containing a bitmap of the form's
+//      client area.
+// ''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
+//
+Picture CaptureClient(Form frmSrc)
+{
+  Picture CaptureClient;
+
+  // Call CaptureWindow to capture the client area of the form given
+  // its window handle and return the resulting Picture object.
+  CaptureClient = CaptureWindow(frmSrc.hWnd, True, 0, 0, frmSrc.ScaleX(frmSrc.ScaleWidth, frmSrc.ScaleMode, vbPixels), frmSrc.ScaleY(frmSrc.ScaleHeight, frmSrc.ScaleMode, vbPixels));
+
+  return CaptureClient;
+}
+
+// ''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
+//
+// CaptureActiveWindow
+//    - Captures the currently active window on the screen.
+//
+// Returns
+//    - Returns a Picture object containing a bitmap of the active
+//      window.
+// ''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
+//
+Picture CaptureActiveWindow()
+{
+  Picture CaptureActiveWindow;
+
+#if Win32
+  long hWndActive;
+  long r;
+
+#elif Win16
+  int hWndActive;
+  int r;
+
+#endif
+  RECT RectActive;
+
+  // Get a handle to the active/foreground window.
+  hWndActive = GetForegroundWindow();
+
+  // Get the dimensions of the window.
+  r = GetWindowRect(hWndActive, RectActive);
+
+  // Call CaptureWindow to capture the active window given its
+  // handle and return the Resulting Picture object.
+  CaptureActiveWindow = CaptureWindow(hWndActive, False, 0, 0, RectActive.right - RectActive.left, RectActive.bottom - RectActive.top);
+
+  return CaptureActiveWindow;
+}
+
+// ''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
+
+//
+// PrintPictureToFitPage
+//    - Prints a Picture object as big as possible.
+//
+// Prn
+//    - Destination Printer object.
+//
+// Pic
+//    - Source Picture object.
+// ''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
+//
+void PrintPictureToFitPage(Printer Prn, Picture pic)
+{
+  #define vbHiMetric                   (8)
+  double PicRatio;
+  double PrnWidth;
+  double PrnHeight;
+  double PrnRatio;
+  double PrnPicWidth;
+  double PrnPicHeight;
+
+  // Determine if picture should be printed in landscape or portrait
+  // and set the orientation.
+  if (pic.Height >= pic.Width)
+  {
+    Prn.Orientation = vbPRORPortrait;   // Taller than wide.
+  }
+  else
+  {
+    Prn.Orientation = vbPRORLandscape;  // Wider than tall.
+  }
+
+  // Calculate device independent Width-to-Height ratio for picture.
+  PicRatio = pic.Width / pic.Height;
+
+  // Calculate the dimentions of the printable area in HiMetric.
+  PrnWidth = Prn.ScaleX(Prn.ScaleWidth, Prn.ScaleMode, vbHiMetric);
+  PrnHeight = Prn.ScaleY(Prn.ScaleHeight, Prn.ScaleMode, vbHiMetric);
+  // Calculate device independent Width to Height ratio for printer.
+  PrnRatio = PrnWidth / PrnHeight;
+
+  // Scale the output to the printable area.
+  if (PicRatio >= PrnRatio)
+  {
+    // Scale picture to fit full width of printable area.
+    PrnPicWidth = Prn.ScaleX(PrnWidth, vbHiMetric, Prn.ScaleMode);
+    PrnPicHeight = Prn.ScaleY(PrnWidth / PicRatio, vbHiMetric, Prn.ScaleMode);
+  }
+  else
+  {
+    // Scale picture to fit full height of printable area.
+    PrnPicHeight = Prn.ScaleY(PrnHeight, vbHiMetric, Prn.ScaleMode);
+    PrnPicWidth = Prn.ScaleX(PrnHeight * PicRatio, vbHiMetric, Prn.ScaleMode);
+  }
+
+  // Print the picture using the PaintPicture method.
+  Prn_PaintPicture(pic, 0, 0, PrnPicWidth, PrnPicHeight);
+}
+
+// --------------------------------------------------------------------
+
diff --git a/src/game_sp/Capture.h b/src/game_sp/Capture.h
new file mode 100644 (file)
index 0000000..f2b8e1b
--- /dev/null
@@ -0,0 +1,147 @@
+// ----------------------------------------------------------------------------
+// Capture.h
+// ----------------------------------------------------------------------------
+
+#ifndef CAPTURE_H
+#define CAPTURE_H
+
+#include "vb_types.h"
+#include "vb_defs.h"
+#include "vb_vars.h"
+#include "vb_lib.h"
+
+#include "global.h"
+
+#ifndef HAS_PALETTEENTRY
+typedef struct
+{
+  byte peRed;
+  byte peGreen;
+  byte peBlue;
+  byte peFlags;
+} PALETTEENTRY;
+#define HAS_PALETTEENTRY
+#endif
+
+#ifndef HAS_LOGPALETTE
+typedef struct
+{
+  int palVersion;
+  int palNumEntries;
+  PALETTEENTRY palPalEntry[255];  // Enough for 256 colors.
+} LOGPALETTE;
+#define HAS_LOGPALETTE
+#endif
+
+#ifndef HAS_GUID
+typedef struct
+{
+  long Data1;
+  int Data2;
+  int Data3;
+  byte Data4[7];
+} GUID;
+#define HAS_GUID
+#endif
+
+#if Win32
+
+#ifndef HAS_RECT
+typedef struct
+{
+  long left;
+  long top;
+  long right;
+  long bottom;
+} RECT;
+#define HAS_RECT
+#endif
+
+#ifndef HAS_PicBmp
+typedef struct
+{
+  long Size;
+  long Type;
+  long hBmp;
+  long hPal;
+  long Reserved;
+} PicBmp;
+#define HAS_PicBmp
+#endif
+
+#elif Win16
+
+#ifndef HAS_RECT
+typedef struct
+{
+  int left;
+  int top;
+  int right;
+  int bottom;
+} RECT;
+#define HAS_RECT
+#endif
+
+#ifndef HAS_PicBmp
+typedef struct
+{
+  int Size;
+  int Type;
+  int hBmp;
+  int hPal;
+  int Reserved;
+} PicBmp;
+#define HAS_PicBmp
+#endif
+
+#endif
+
+#if Win32
+
+
+
+#elif Win16
+
+
+
+#endif
+
+#if Win32
+
+
+
+#elif Win16
+
+
+
+#endif
+
+#if Win32
+
+
+
+#elif Win16
+
+
+
+#endif
+
+#if Win32
+
+
+
+#elif Win16
+
+
+
+#endif
+
+extern Picture CaptureActiveWindow();
+extern Picture CaptureClient(Form frmSrc);
+extern Picture CaptureForm(Form frmSrc);
+extern Picture CaptureScreen();
+extern Picture CaptureWindow(int hWndSrc, boolean Client, int LeftSrc, int TopSrc, long WidthSrc, long HeightSrc);
+extern Picture CreateBitmapPicture(int hBmp, int hPal);
+extern void PrintPictureToFitPage(Printer Prn, Picture pic);
+
+#endif /* CAPTURE_H */
diff --git a/src/game_sp/DDScrollBuffer.c b/src/game_sp/DDScrollBuffer.c
new file mode 100644 (file)
index 0000000..1734aa8
--- /dev/null
@@ -0,0 +1,382 @@
+// ----------------------------------------------------------------------------
+// DDScrollBuffer.c
+// ----------------------------------------------------------------------------
+
+#include "DDScrollBuffer.h"
+
+#include <math.h>
+
+
+// --- VERSION 1.0 CLASS
+// --- BEGIN
+// ---   MultiUse = -1  'True  // True
+// ---   Persistable = 0  'NotPersistable  // NotPersistable
+// ---   DataBindingBehavior = 0  'vbNone  // vbNone
+// ---   DataSourceBehavior  = 0  'vbNone  // vbNone
+// ---   MTSTransactionMode  = 0  'NotAnMTSObject  // NotAnMTSObject
+// --- END
+
+static char *VB_Name = "DDScrollBuffer";
+static boolean VB_GlobalNameSpace = False;
+static boolean VB_Creatable = True;
+static boolean VB_PredeclaredId = False;
+static boolean VB_Exposed = False;
+// --- Option Explicit
+
+// needs reference to: DirectX7 for Visual Basic Type Library
+
+DirectDrawSurface7 Buffer;
+DirectDrawSurface7 mPrimary;
+long mWidth, mHeight;
+long mhWnd;
+long mScrollX, mScrollY;
+long mDestXOff, mDestYOff;
+
+void DDScrollBuffer_Let_DestXOff(long NewVal)
+{
+  mDestXOff = NewVal;
+}
+
+long DDScrollBuffer_Get_DestXOff()
+{
+  long DestXOff;
+
+  DestXOff = mDestXOff;
+
+  return DestXOff;
+}
+
+void DDScrollBuffer_Let_DestYOff(long NewVal)
+{
+  mDestYOff = NewVal;
+}
+
+long DDScrollBuffer_Get_DestYOff()
+{
+  long DestYOff;
+
+  DestYOff = mDestYOff;
+
+  return DestYOff;
+}
+
+DirectDrawSurface7 DDScrollBuffer_Get_Surface()
+{
+  DirectDrawSurface7 Surface;
+
+  Surface = Buffer;
+
+  return Surface;
+}
+
+long DDScrollBuffer_Get_Width()
+{
+  long Width;
+
+  Width = mWidth;
+
+  return Width;
+}
+
+int DDScrollBuffer_Get_Height()
+{
+  int Height;
+
+  Height = mHeight;
+
+  return Height;
+}
+
+long DDScrollBuffer_CreateAtSize(long Width, long Height, long hWndViewPort)
+{
+  long CreateAtSize;
+
+  DDSURFACEDESC2 SD;
+
+  CreateAtSize = 0;
+  mhWnd = hWndViewPort;
+  // Create ScrollBuffer:
+  {
+    SD.lFlags = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT;
+    SD.ddsCaps.lCaps = DDSCAPS_VIDEOMEMORY;
+    // SD.ddsCaps.lCaps = DDSCAPS_OFFSCREENPLAIN
+    SD.LWidth = Width;
+    SD.LHeight = Height;
+  }
+
+  // --- On Error Resume Next
+  Buffer = DDraw.CreateSurface(SD);
+  if (Err.Number != 0)
+    return CreateAtSize;
+
+  // --- On Error GoTo 0
+
+  mWidth = Width;
+  mHeight = Height;
+  mScrollX = 0;
+  mScrollY = 0;
+  CreateAtSize = -1;
+
+  return CreateAtSize;
+}
+
+void DDScrollBuffer_Cls(int BackColor)
+{
+  RECT EmptyRect;
+
+  if (NoDisplayFlag)
+    return;
+
+  Buffer.BltColorFill(EmptyRect, BackColor);
+}
+
+void DDScrollBuffer_Blt()
+{
+  RECT DR, SR;
+  long tX, tY, L;
+  // RECT ERect;
+  // long Restore;
+
+  if (NoDisplayFlag)
+    return;
+
+
+  // --- On Error GoTo BltEH
+  DirectX.GetWindowRect(mhWnd, DR);
+  // --- On Error GoTo 0
+
+  {
+    tX = (DR.right - DR.left) / Stretch;
+    tY = (DR.bottom - DR.top) / Stretch;
+  }
+  {
+    SR.left = mScrollX + mDestXOff;
+    SR.top = mScrollY + mDestYOff;
+    SR.right = SR.left + tX;
+    SR.bottom = SR.top + tY;
+    //    If mWidth < SR.right Then
+    //      SR.right = mWidth
+    //      DR.right = DR.left + Stretch * (SR.right - SR.left)
+    //    End If
+    //    If mHeight < SR.bottom Then
+    //      SR.bottom = mHeight
+    //      DR.bottom = DR.top + Stretch * (SR.bottom - SR.top)
+    //    End If
+    //    If (mScrollX + mDestXOff) < 0 Then
+    //      SR.left = 0
+    //      DR.left = DR.left - Stretch * (mScrollX + mDestXOff)
+    //    End If
+    //    If (mScrollY + mDestYOff) < 0 Then
+    //      SR.top = 0
+    //      DR.top = DR.top - Stretch * (mScrollY + mDestYOff)
+    //    End If
+  }
+  // DDraw.WaitForVerticalBlank DDWAITVB_BLOCKBEGIN, 0
+  if (IS_NOTHING(&Buffer, sizeof(Buffer)))
+    return;
+
+  if (IS_NOTHING(&PrimarySurface, sizeof(PrimarySurface)))
+    return;
+
+  L = PrimarySurface_Blt(DR, Buffer, SR, DDBLT_WAIT);
+  if (L != DD_OK)
+  {
+    switch (L)
+    {
+      case DDERR_GENERIC:
+        Debug.Assert(False);
+        break;
+
+      case DDERR_INVALIDCLIPLIST:
+        Debug.Assert(False);
+        break;
+
+      case DDERR_INVALIDOBJECT:
+        Debug.Assert(False);
+        break;
+
+      case DDERR_INVALIDPARAMS:
+        Debug.Assert(False);
+        break;
+
+      case DDERR_INVALIDRECT:
+        Debug.Assert(False);
+        break;
+
+      case DDERR_NOALPHAHW:
+        Debug.Assert(False);
+        break;
+
+      case DDERR_NOBLTHW:
+        Debug.Assert(False);
+        break;
+
+      case DDERR_NOCLIPLIST:
+        Debug.Assert(False);
+        break;
+
+      case DDERR_NODDROPSHW:
+        Debug.Assert(False);
+        break;
+
+      case DDERR_NOMIRRORHW:
+        Debug.Assert(False);
+        break;
+
+      case DDERR_NORASTEROPHW:
+        Debug.Assert(False);
+        break;
+
+      case DDERR_NOROTATIONHW:
+        Debug.Assert(False);
+        break;
+
+      case DDERR_NOSTRETCHHW:
+        Debug.Assert(False);
+        break;
+
+      case DDERR_NOZBUFFERHW:
+        Debug.Assert(False);
+        break;
+
+      case DDERR_SURFACEBUSY:
+        Debug.Assert(False);
+        break;
+
+      case DDERR_SURFACELOST:
+        DDraw.RestoreAllSurfaces();
+        if (! PrimarySurface.isLost())
+        {
+          subDisplayLevel();
+          // Blt();
+        }
+
+        // RestorePrimarySurface
+        // ClipToWindow 0
+        break;
+
+      case DDERR_UNSUPPORTED:
+        Debug.Assert(False);
+        break;
+
+      case DDERR_WASSTILLDRAWING:
+        Debug.Assert(False);
+        break;
+
+      default:
+        Debug.Assert(False);
+        break;
+    }
+  }
+
+#if 0
+  //  Buffer.UpdateOverlay SR, PrimarySurface, DR, DDOVER_SHOW
+  if (EditFlag)
+    FMark.RefreshMarker();
+#endif
+
+  // BltEH:
+}
+
+void DDScrollBuffer_ScrollTo(int X, int Y)
+{
+  if (NoDisplayFlag)
+    return;
+
+  X = X / Stretch;
+  Y = Y / Stretch;
+  mScrollX = X;
+  mScrollY = Y;
+  ScrollX = mScrollX;
+  ScrollY = mScrollY;
+}
+
+void DDScrollBuffer_ScrollTowards(int X, int Y, double Step)
+{
+  double dx, dY, r;
+
+  if (NoDisplayFlag)
+    return;
+
+  X = X / Stretch;
+  Y = Y / Stretch;
+  dx = X - mScrollX;
+  dY = Y - mScrollY;
+  r = Sqr(dx * dx + dY * dY);
+  if (r == 0) // we are there already
+    return;
+
+  if (Step < r)
+    r = Step / r;
+  else
+    r = 1;
+
+  mScrollX = mScrollX + dx * r;
+  mScrollY = mScrollY + dY * r;
+  ScrollX = mScrollX;
+  ScrollY = mScrollY;
+}
+
+void DDScrollBuffer_SoftScrollTo(int X, int Y, long TimeMS, int FPS)
+{
+  double dx, dY;
+  TickCountObject Tick;
+  long dT, StepCount;
+  double T, tStep;
+  long oldX, oldY, maxD;
+  boolean AlreadyRunning;
+
+  if (NoDisplayFlag)
+    return;
+
+  if (AlreadyRunning)
+  {
+    return;
+  }
+
+  AlreadyRunning = True;
+  X = X / Stretch;
+  Y = Y / Stretch;
+  dx = X - mScrollX;
+  dY = Y - mScrollY;
+  maxD = (Abs(dx) < Abs(dY) ?  Abs(dY) :  Abs(dY));
+  StepCount = FPS * (TimeMS / (double)1000);
+  if (StepCount > maxD)
+    StepCount = maxD;
+
+  if (StepCount == 0)
+    StepCount = 1;
+
+  dT = 1000 / FPS;
+  tStep = (double)1 / StepCount;
+  oldX = mScrollX;
+  oldY = mScrollY;
+  // R = Sqr(dX * dX + dY * dY)
+  // If R = 0 Then Exit Sub 'we are there already
+  for (T = (double)tStep; T <= (double)1; T += tStep)
+  {
+    if (UserDragFlag)
+      goto SoftScrollEH;
+
+    // If Claim Then Exit For
+    Tick.DelayMS(dT, False);
+    mScrollX = oldX + T * dx;
+    mScrollY = oldY + T * dY;
+    ScrollX = mScrollX;
+    ScrollY = mScrollY;
+    // Blt();
+  }
+
+  if (UserDragFlag)
+    goto SoftScrollEH;
+
+  Tick.DelayMS(dT, False);
+  mScrollX = X;
+  mScrollY = Y;
+  ScrollX = mScrollX;
+  ScrollY = mScrollY;
+  // Blt();
+
+SoftScrollEH:
+  AlreadyRunning = False;
+}
diff --git a/src/game_sp/DDScrollBuffer.h b/src/game_sp/DDScrollBuffer.h
new file mode 100644 (file)
index 0000000..cc77cf8
--- /dev/null
@@ -0,0 +1,29 @@
+// ----------------------------------------------------------------------------
+// DDScrollBuffer.h
+// ----------------------------------------------------------------------------
+
+#ifndef DDSCROLLBUFFER_H
+#define DDSCROLLBUFFER_H
+
+#include "vb_types.h"
+#include "vb_defs.h"
+#include "vb_vars.h"
+#include "vb_lib.h"
+
+#include "global.h"
+
+extern void DDScrollBuffer_Blt();
+extern void DDScrollBuffer_Cls(int BackColor);
+extern long DDScrollBuffer_CreateAtSize(long Width, long Height, long hWndViewPort);
+extern long DDScrollBuffer_Get_DestXOff();
+extern long DDScrollBuffer_Get_DestYOff();
+extern int DDScrollBuffer_Get_Height();
+extern DirectDrawSurface7 DDScrollBuffer_Get_Surface();
+extern long DDScrollBuffer_Get_Width();
+extern void DDScrollBuffer_Let_DestXOff(long NewVal);
+extern void DDScrollBuffer_Let_DestYOff(long NewVal);
+extern void DDScrollBuffer_ScrollTo(int X, int Y);
+extern void DDScrollBuffer_ScrollTowards(int X, int Y, double Step);
+extern void DDScrollBuffer_SoftScrollTo(int X, int Y, long TimeMS, int FPS);
+
+#endif /* DDSCROLLBUFFER_H */
diff --git a/src/game_sp/DDSpriteBuffer.c b/src/game_sp/DDSpriteBuffer.c
new file mode 100644 (file)
index 0000000..1384a38
--- /dev/null
@@ -0,0 +1,232 @@
+// ----------------------------------------------------------------------------
+// DDSpriteBuffer.c
+// ----------------------------------------------------------------------------
+
+#include "DDSpriteBuffer.h"
+
+static void Blt(int pX, int pY, int SpriteX, int SpriteY);
+
+// --- VERSION 1.0 CLASS
+// --- BEGIN
+// ---   MultiUse = -1  'True  // True
+// ---   Persistable = 0  'NotPersistable  // NotPersistable
+// ---   DataBindingBehavior = 0  'vbNone  // vbNone
+// ---   DataSourceBehavior  = 0  'vbNone  // vbNone
+// ---   MTSTransactionMode  = 0  'NotAnMTSObject  // NotAnMTSObject
+// --- END
+
+static char *VB_Name = "DDSpriteBuffer";
+static boolean VB_GlobalNameSpace = False;
+static boolean VB_Creatable = True;
+static boolean VB_PredeclaredId = False;
+static boolean VB_Exposed = False;
+// --- Option Explicit
+
+// needs reference to: DirectX7 for Visual Basic Type Library
+
+DirectDrawSurface7 Buffer;
+DirectDrawSurface7 mDest;
+long mXSpriteCount, mYSpriteCount;
+long mSpriteWidth, mSpriteHeight;
+long mDestXOff, mDestYOff;
+
+void DDSpriteBuffer_Let_DestXOff(long NewVal)
+{
+  mDestXOff = NewVal;
+}
+
+long DDSpriteBuffer_Get_DestXOff()
+{
+  long DestXOff;
+
+  DestXOff = mDestXOff;
+
+  return DestXOff;
+}
+
+void DDSpriteBuffer_Let_DestYOff(long NewVal)
+{
+  mDestYOff = NewVal;
+}
+
+long DDSpriteBuffer_Get_DestYOff()
+{
+  long DestYOff;
+
+  DestYOff = mDestYOff;
+
+  return DestYOff;
+}
+
+int DDSpriteBuffer_Set_DestinationSurface(DirectDrawSurface7 DSurface)
+{
+  int DestinationSurface;
+
+  mDest = DSurface;
+
+  return DestinationSurface;
+}
+
+DirectDrawSurface7 DDSpriteBuffer_Get_Surface()
+{
+  DirectDrawSurface7 Surface;
+
+  Surface = Buffer;
+
+  return Surface;
+}
+
+long DDSpriteBuffer_Get_Width()
+{
+  long Width;
+
+  Width = mSpriteWidth * mXSpriteCount;
+
+  return Width;
+}
+
+int DDSpriteBuffer_Get_Height()
+{
+  int Height;
+
+  Height = mSpriteHeight * mYSpriteCount;
+
+  return Height;
+}
+
+boolean DDSpriteBuffer_CreateFromFile(char *Path, long xSprites, long ySprites)
+{
+  boolean CreateFromFile;
+
+  DDSURFACEDESC2 SD;
+
+  {
+    SD.lFlags = DDSD_CAPS; // Or DDSD_WIDTH Or DDSD_HEIGHT
+    SD.ddsCaps.lCaps = DDSCAPS_VIDEOMEMORY; // DDSCAPS_SYSTEMMEMORY 'DDSCAPS_OFFSCREENPLAIN
+  }
+
+  // --- On Error GoTo CreateFromFileEH
+  Buffer = DDraw.CreateSurfaceFromFile(Path, SD);
+  // --- On Error GoTo 0
+
+  Buffer.GetSurfaceDesc(SD);
+  mSpriteWidth = SD.LWidth / xSprites;
+  mSpriteHeight = SD.LHeight / ySprites;
+  mXSpriteCount = xSprites;
+  mYSpriteCount = ySprites;
+  CreateFromFile = True;
+  return CreateFromFile;
+
+CreateFromFileEH:
+  CreateFromFile = False;
+
+  return CreateFromFile;
+}
+
+boolean DDSpriteBuffer_CreateAtSize(long Width, long Height, long xSprites, long ySprites)
+{
+  boolean CreateAtSize;
+
+  DDSURFACEDESC2 SD;
+
+  {
+    SD.lFlags = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT;
+    SD.ddsCaps.lCaps = DDSCAPS_VIDEOMEMORY;
+    // SD.ddsCaps.lCaps = DDSCAPS_OFFSCREENPLAIN
+    SD.LWidth = Width;
+    SD.LHeight = Height;
+  }
+
+  // --- On Error GoTo CreateAtSizeEH
+  Buffer = DDraw.CreateSurface(SD);
+  // --- On Error GoTo 0
+
+  mSpriteWidth = Width / xSprites;
+  mSpriteHeight = Height / ySprites;
+  mXSpriteCount = xSprites;
+  mYSpriteCount = ySprites;
+  CreateAtSize = True;
+  return CreateAtSize;
+
+CreateAtSizeEH:
+  CreateAtSize = False;
+
+  return CreateAtSize;
+}
+
+void DDSpriteBuffer_Cls(int BackColor)
+{
+  RECT EmptyRect;
+
+  Buffer.BltColorFill(EmptyRect, BackColor);
+}
+
+static void Blt(int pX, int pY, int SpriteX, int SpriteY)
+{
+  RECT DR, SR;
+  long Tmp;
+
+  if (NoDisplayFlag)
+    return;
+
+  {
+    DR.left = pX + mDestXOff;
+    DR.top = pY + mDestYOff;
+    DR.right = pX + mSpriteWidth + mDestXOff;
+    DR.bottom = pY + mSpriteHeight + mDestYOff;
+  }
+  {
+    SR.left = mSpriteWidth * (SpriteX - 1);
+    SR.top = mSpriteHeight * (SpriteY - 1);
+    SR.right = SR.left + mSpriteWidth;
+    SR.bottom = SR.top + mSpriteHeight;
+  }
+  Tmp = mDest_Blt(DR, Buffer, SR, DDBLT_WAIT);
+}
+
+void DDSpriteBuffer_BltEx(int pX, int pY, int SpritePos)
+{
+  int XPos, YPos;
+
+  if (NoDisplayFlag)
+    return;
+
+  XPos = (SpritePos % mXSpriteCount) + 1;
+  YPos = (SpritePos / mXSpriteCount) + 1;
+  Blt(pX, pY, XPos, YPos);
+}
+
+// Public Function GetStretchCopy(Stretch!) As DDSpriteBuffer
+// Dim SR As RECT, DR As RECT, Y%, X%, pX%, pY%, Tmp&
+// //  Set GetStretchCopy = New DDSpriteBuffer // (handle this later, if needed)
+//  If Not GetStretchCopy.CreateAtSize(Stretch * Width, Stretch * Height, mXSpriteCount, mYSpriteCount) Then
+//    Set GetStretchCopy = Nothing
+//  Else
+//    For Y = 0 To mYSpriteCount - 1
+//      pY = Y * Stretch * mSpriteHeight
+//      For X = 0 To mXSpriteCount - 1
+//        pX = X * Stretch * mSpriteWidth
+//        With DR
+//          .left = pX
+//          .top = pY
+//          .right = pX + mSpriteWidth * Stretch
+//          .bottom = pY + mSpriteHeight * Stretch
+//        End With
+//        With SR
+//          .left = mSpriteWidth * X
+//          .top = mSpriteHeight * Y
+//          .right = .left + mSpriteWidth
+//          .bottom = .top + mSpriteHeight
+//        End With
+//        Tmp = GetStretchCopy.Surface.Blt(DR, Buffer, SR, DDBLT_WAIT)
+//      Next X
+//    Next Y
+//    'GetStretchCopy.Surface.Blt DR, Buffer, DR, DDBLT_WAIT
+//  End If
+// End Function
+
+static void Class_Initialize()
+{
+  mDestXOff = 0;
+  mDestYOff = 0;
+}
diff --git a/src/game_sp/DDSpriteBuffer.h b/src/game_sp/DDSpriteBuffer.h
new file mode 100644 (file)
index 0000000..64a8daa
--- /dev/null
@@ -0,0 +1,28 @@
+// ----------------------------------------------------------------------------
+// DDSpriteBuffer.h
+// ----------------------------------------------------------------------------
+
+#ifndef DDSPRITEBUFFER_H
+#define DDSPRITEBUFFER_H
+
+#include "vb_types.h"
+#include "vb_defs.h"
+#include "vb_vars.h"
+#include "vb_lib.h"
+
+#include "global.h"
+
+extern void DDSpriteBuffer_BltEx(int pX, int pY, int SpritePos);
+extern void DDSpriteBuffer_Cls(int BackColor);
+extern boolean DDSpriteBuffer_CreateAtSize(long Width, long Height, long xSprites, long ySprites);
+extern boolean DDSpriteBuffer_CreateFromFile(char *Path, long xSprites, long ySprites);
+extern long DDSpriteBuffer_Get_DestXOff();
+extern long DDSpriteBuffer_Get_DestYOff();
+extern int DDSpriteBuffer_Get_Height();
+extern DirectDrawSurface7 DDSpriteBuffer_Get_Surface();
+extern long DDSpriteBuffer_Get_Width();
+extern void DDSpriteBuffer_Let_DestXOff(long NewVal);
+extern void DDSpriteBuffer_Let_DestYOff(long NewVal);
+extern int DDSpriteBuffer_Set_DestinationSurface(DirectDrawSurface7 DSurface);
+
+#endif /* DDSPRITEBUFFER_H */
diff --git a/src/game_sp/Demo.c b/src/game_sp/Demo.c
new file mode 100644 (file)
index 0000000..7bbf90f
--- /dev/null
@@ -0,0 +1,83 @@
+// ----------------------------------------------------------------------------
+// Demo.c
+// ----------------------------------------------------------------------------
+
+#include "Demo.h"
+
+static char *VB_Name = "modDemo";
+// --- Option Explicit
+//
+// Public Function subCloseDemoRecordingFile()
+//
+// End Function
+int RecDemoRandomSeed;
+byte FirstDemoByte;
+char *MySignature;
+
+void subGetNextDemoKey()
+{
+  int ax;
+
+  if (0 < DemoKeyRepeatCounter)
+  {
+    DemoKeyRepeatCounter = DemoKeyRepeatCounter - 1;
+  }
+  else
+  {
+    DemoOffset = DemoOffset + 1;
+    if (DemoOffset <= FileMax)
+    {
+      ax = PlayField8[DemoOffset];
+      if (ax == 0xFF)
+      {
+        demo_stopped = 1;
+        ExitToMenuFlag = 1;
+      }
+      else
+      {
+        DemoKeyCode = ax & 0xF;
+        DemoKeyRepeatCounter = (ax & 0xF0) / 0x10;
+      }
+
+    }
+    else
+    {
+      ExitToMenuFlag = 1;
+    }
+  }
+}
+
+currency GetTotalFramesOfDemo()
+{
+  currency GetTotalFramesOfDemo;
+
+  long i;
+  currency nFrames;
+  byte db;
+
+  GetTotalFramesOfDemo = 0;
+  if (! DemoAvailable)
+    return GetTotalFramesOfDemo;
+
+  nFrames = 1;
+  i = DemoPointer + 1;
+
+  // --- On Error GoTo GetTotalFramesOfDemoEH
+  db = PlayField8[i];
+  while (db != 0xFF)
+  {
+    nFrames = nFrames + (db & 0xF0) / 0x10 + 1;
+    i = i + 1;
+    db = PlayField8[i];
+  }
+
+  GetTotalFramesOfDemo = nFrames;
+  return GetTotalFramesOfDemo;
+
+GetTotalFramesOfDemoEH:
+  // ReportError "GetTotalFramesOfDemo()", "invalid data detected in file " & OrigPath
+  GetTotalFramesOfDemo = 0;
+  DemoAvailable = False;
+
+  return GetTotalFramesOfDemo;
+}
diff --git a/src/game_sp/Demo.h b/src/game_sp/Demo.h
new file mode 100644 (file)
index 0000000..a9daa14
--- /dev/null
@@ -0,0 +1,22 @@
+// ----------------------------------------------------------------------------
+// Demo.h
+// ----------------------------------------------------------------------------
+
+#ifndef DEMO_H
+#define DEMO_H
+
+#include "vb_types.h"
+#include "vb_defs.h"
+#include "vb_vars.h"
+#include "vb_lib.h"
+
+#include "global.h"
+
+extern currency GetTotalFramesOfDemo();
+extern void subGetNextDemoKey();
+
+extern byte FirstDemoByte;
+extern char *MySignature;
+extern int RecDemoRandomSeed;
+
+#endif /* DEMO_H */
diff --git a/src/game_sp/DemoBufferObject.c b/src/game_sp/DemoBufferObject.c
new file mode 100644 (file)
index 0000000..37e758e
--- /dev/null
@@ -0,0 +1,240 @@
+// ----------------------------------------------------------------------------
+// DemoBufferObject.c
+// ----------------------------------------------------------------------------
+
+#include "DemoBufferObject.h"
+
+static void Class_Terminate();
+static int RemoveLastDemoKey();
+
+// --- VERSION 1.0 CLASS
+// --- BEGIN
+// ---   MultiUse = -1  'True  // True
+// ---   Persistable = 0  'NotPersistable  // NotPersistable
+// ---   DataBindingBehavior = 0  'vbNone  // vbNone
+// ---   DataSourceBehavior  = 0  'vbNone  // vbNone
+// ---   MTSTransactionMode  = 0  'NotAnMTSObject  // NotAnMTSObject
+// --- END
+
+static char *VB_Name = "DemoBufferObject";
+static boolean VB_GlobalNameSpace = False;
+static boolean VB_Creatable = True;
+static boolean VB_PredeclaredId = False;
+static boolean VB_Exposed = False;
+// --- Option Explicit
+
+#define MaxPos                         ((long)1024)
+
+// Private Const MaxPos& = 20& 'debug only
+byte DemoByte[MaxPos + 1];
+DemoBufferObject SubBuffer;
+
+byte nFirstByte;
+
+char *mSignature;
+boolean bSignatureAvailable;
+
+long WritePos;
+int LastKey;
+int CheckSum;
+long nSize;
+
+static void Class_Initialize()
+{
+  int lSize;
+
+  Trace("DemoBufferObject", "Construction");
+  DemoBufferObject_Reset();
+  if (! IS_NOTHING(&DemoBuffer, sizeof(DemoBuffer)))
+  {
+    lSize = DemoBuffer_Size();
+    Trace("DemoBufferObject", "Size == ...");
+    Trace("DemoBufferObject", "BufferCount == ...");
+    Trace("DemoBufferObject", "TimerVar == ...");
+  }
+}
+
+static void Class_Terminate()
+{
+  SET_TO_NOTHING(&SubBuffer, sizeof(SubBuffer));
+}
+
+void DemoBufferObject_Reset()
+{
+  nSize = 0;
+  nFirstByte = 0x81;
+  WritePos = 0;
+  LastKey = -1;
+  CheckSum = 0;
+  bSignatureAvailable = False;
+  mSignature = "";
+  SET_TO_NOTHING(&SubBuffer, sizeof(SubBuffer));
+}
+
+long DemoBufferObject_Get_Size()
+{
+  long Size;
+
+  Size = (nSize < 1 ?  0 :  0);
+  if (! IS_NOTHING(&SubBuffer, sizeof(SubBuffer)))
+    Size = Size + SubBuffer_Size();
+
+  return Size;
+}
+
+byte DemoBufferObject_Get_CheckSumByte()
+{
+  byte CheckSumByte;
+
+  CheckSumByte = CheckSum & 0xFF;
+
+  return CheckSumByte;
+}
+
+byte DemoBufferObject_Get_FirstByte()
+{
+  byte FirstByte;
+
+  FirstByte = nFirstByte;
+
+  return FirstByte;
+}
+
+void DemoBufferObject_Let_FirstByte(byte NewVal)
+{
+  nFirstByte = NewVal;
+}
+
+//
+// Public Property Get DemoAvailable() As Boolean
+//  DemoAvailable = (0 < nSize)
+// End Property
+//
+// Public Property Get Signature() As String
+//  If SubBuffer Is Nothing Then
+//    Signature = mSignature
+//  Else
+//    Signature = SubBuffer.Signature
+//  End If
+// End Property
+
+// Public Property Let Signature(NewSig$)
+//  If SubBuffer Is Nothing Then
+//    Signature = NewSig
+//  Else
+//    SubBuffer.Signature = NewSig
+//  End If
+// End Property
+//
+// Public Property Get SignatureAvailable() As Boolean
+//  If SubBuffer Is Nothing Then
+//    SignatureAvailable = (mSignature <> "")
+//  Else
+//    SignatureAvailable = SubBuffer
+//  End If
+// End Property
+
+boolean DemoBufferObject_Serialize(int FNum)
+{
+  boolean Serialize;
+
+  int i; // , LKey%
+
+  Serialize = True;
+  if (! IS_NOTHING(&SubBuffer, sizeof(SubBuffer)))
+    Serialize = SubBuffer_Serialize(FNum);
+
+  if (nSize == 0)
+    return Serialize;
+
+  // LKey = RemoveLastDemoKey()
+  if (! nSize < MaxPos) // this buffer is full
+  {
+
+    // --- On Error GoTo SerializeEH
+    FILE_PUT(FNum, -1, &DemoByte, sizeof(DemoByte));
+    // --- On Error GoTo 0
+
+  }
+  else // this is the last buffer in the recursive chain
+  {
+
+    // --- On Error GoTo SerializeEH
+    for (i = 1; i <= WritePos; i++)
+    {
+      FILE_PUT(FNum, -1, &DemoByte[i], sizeof(DemoByte[i]));
+    }
+
+    // --- On Error GoTo 0
+
+  }
+
+  // AddDemoKey LKey
+  return Serialize;
+
+SerializeEH:
+  Serialize = False;
+
+  return Serialize;
+}
+
+void DemoBufferObject_AddDemoKey(int KeyCode)
+{
+  CheckSum = (CheckSum + 1) & 0xFF; // increment checksum
+  //  If Not SubBuffer Is Nothing Then 'delegate
+  //    Debug.Assert False
+  //    'SubBuffer.AddDemoKey KeyCode
+  //    Exit Sub
+  //  End If
+  if (LastKey == KeyCode)
+  {
+    DemoByte[WritePos] = DemoByte[WritePos] + 0x10;
+    if (0xEF < DemoByte[WritePos])
+      LastKey = -1;
+
+  }
+  else // LastKey <> KeyCode
+  {
+    WritePos = WritePos + 1;
+
+    if (MaxPos < WritePos) // if overflow then create new buffer, hang myself in list
+    {
+      DemoBufferObject Tmp;
+
+      // Tmp = New DemoBufferObject; // (handle this later, if needed)
+      Tmp.SetSubBuffer(&VB_OBJECT_SELF);
+      Tmp.AddDemoKey(KeyCode); // and delegate
+      DemoBuffer = Tmp;
+    }
+    else
+    {
+      nSize = nSize + 1; // increment size
+      DemoByte[WritePos] = KeyCode;
+      LastKey = KeyCode;
+    }
+  }
+}
+
+void DemoBufferObject_SetSubBuffer(DemoBufferObject SBuf)
+{
+  SubBuffer = SBuf;
+}
+
+static int RemoveLastDemoKey()
+{
+  static int RemoveLastDemoKey;
+
+  RemoveLastDemoKey = (DemoByte[WritePos] & 0xF);
+  if (DemoByte[WritePos] < 0x10)
+  {
+    WritePos = WritePos - 1;
+    nSize = nSize - 1;
+    LastKey = -1;
+  }
+  else
+  {
+    DemoByte[WritePos] = DemoByte[WritePos] - 0x10;
+  }
+
+  return RemoveLastDemoKey;
+}
diff --git a/src/game_sp/DemoBufferObject.h b/src/game_sp/DemoBufferObject.h
new file mode 100644 (file)
index 0000000..464db73
--- /dev/null
@@ -0,0 +1,24 @@
+// ----------------------------------------------------------------------------
+// DemoBufferObject.h
+// ----------------------------------------------------------------------------
+
+#ifndef DEMOBUFFEROBJECT_H
+#define DEMOBUFFEROBJECT_H
+
+#include "vb_types.h"
+#include "vb_defs.h"
+#include "vb_vars.h"
+#include "vb_lib.h"
+
+#include "global.h"
+
+extern void DemoBufferObject_AddDemoKey(int KeyCode);
+extern byte DemoBufferObject_Get_CheckSumByte();
+extern byte DemoBufferObject_Get_FirstByte();
+extern long DemoBufferObject_Get_Size();
+extern void DemoBufferObject_Let_FirstByte(byte NewVal);
+extern void DemoBufferObject_Reset();
+extern boolean DemoBufferObject_Serialize(int FNum);
+extern void DemoBufferObject_SetSubBuffer(DemoBufferObject SBuf);
+
+#endif /* DEMOBUFFEROBJECT_H */
diff --git a/src/game_sp/DirectDrawGlobals.c b/src/game_sp/DirectDrawGlobals.c
new file mode 100644 (file)
index 0000000..4b96d9e
--- /dev/null
@@ -0,0 +1,47 @@
+// ----------------------------------------------------------------------------
+// DirectDrawGlobals.c
+// ----------------------------------------------------------------------------
+
+#include "DirectDrawGlobals.h"
+
+static char *VB_Name = "DirectDrawGlobals";
+// --- Option Explicit
+
+DirectX7 DirectX;
+DirectDraw7 DirectDraw;
+DirectDrawSurface7 PrimarySurface;
+
+void InitDirectDraw(long hWndClip)
+{
+  DDSURFACEDESC2 SD;
+
+  // DirectX = New DirectX7; // (handle this later, if needed)
+  DirectDraw = DirectX.DirectDrawCreate("");
+  DirectDraw.SetCooperativeLevel(0, DDSCL_NORMAL);
+  // Create PrimarySurface:
+  {
+    SD.lFlags = DDSD_CAPS;
+    SD.ddsCaps.lCaps = DDSCAPS_PRIMARYSURFACE;
+  }
+  PrimarySurface = DirectDraw.CreateSurface(SD);
+  if (hWndClip != 0)
+    ClipToWindow(hWndClip);
+}
+
+void ReleaseDirectDraw()
+{
+  SET_TO_NOTHING(&PrimarySurface, sizeof(PrimarySurface));
+  SET_TO_NOTHING(&DirectDraw, sizeof(DirectDraw));
+  SET_TO_NOTHING(&DirectX, sizeof(DirectX));
+}
+
+void ClipToWindow(long hWnd)
+{
+  DirectDrawClipper Clipper;
+
+  // create clipper
+  Clipper = DirectDraw.CreateClipper(0);
+  Clipper.SetHWnd(hWnd);
+  PrimarySurface.SetClipper(Clipper);
+  SET_TO_NOTHING(&Clipper, sizeof(Clipper));
+}
diff --git a/src/game_sp/DirectDrawGlobals.h b/src/game_sp/DirectDrawGlobals.h
new file mode 100644 (file)
index 0000000..71cc763
--- /dev/null
@@ -0,0 +1,23 @@
+// ----------------------------------------------------------------------------
+// DirectDrawGlobals.h
+// ----------------------------------------------------------------------------
+
+#ifndef DIRECTDRAWGLOBALS_H
+#define DIRECTDRAWGLOBALS_H
+
+#include "vb_types.h"
+#include "vb_defs.h"
+#include "vb_vars.h"
+#include "vb_lib.h"
+
+#include "global.h"
+
+extern void ClipToWindow(long hWnd);
+extern void InitDirectDraw(long hWndClip);
+extern void ReleaseDirectDraw();
+
+extern DirectDraw7 DirectDraw;
+extern DirectDrawSurface7 PrimarySurface;
+extern DirectX7 DirectX;
+
+#endif /* DIRECTDRAWGLOBALS_H */
diff --git a/src/game_sp/DirectXGlobals.c b/src/game_sp/DirectXGlobals.c
new file mode 100644 (file)
index 0000000..3e2b0f7
--- /dev/null
@@ -0,0 +1,94 @@
+// ----------------------------------------------------------------------------
+// DirectXGlobals.c
+// ----------------------------------------------------------------------------
+
+#include "DirectXGlobals.h"
+
+static char *VB_Name = "DirectXGlobals";
+// --- Option Explicit
+
+DirectX7 DirectX;
+DirectX7 DirectXS;
+DirectDraw7 DDraw;
+DirectSound DSound;
+
+// Public DInput As DirectInput
+// Public DKeyboard As DirectInputDevice
+DirectDrawSurface7 PrimarySurface;
+
+void InitDirectX(long hWndForm, long hWndClip)
+{
+  // DirectX = New DirectX7; // (handle this later, if needed)
+  // DirectXS = New DirectX7; // (handle this later, if needed)
+
+  // DirectSound:
+
+  // --- On Error Resume Next
+  DSound = DirectXS.DirectSoundCreate("");
+  if (Err.Number != 0)
+  {
+    ReportError("InitDirectX()", "Unable to start DirectSound.");
+  }
+  else
+  {
+    DSound.SetCooperativeLevel(hWndForm, DSSCL_PRIORITY);
+    LoadSoundFX();
+  }
+
+  // DirectDraw:
+  DDraw = DirectX.DirectDrawCreate("");
+  DDraw.SetCooperativeLevel(0, DDSCL_NORMAL);
+  RestorePrimarySurface();
+  if (hWndClip != 0)
+    ClipToWindow(hWndClip);
+
+  // 'DirectInput:
+  //  Set DInput = DirectX.DirectInputCreate()
+  //  Set DKeyboard = DInput.CreateDevice("GUID_SysKeyboard")
+  //  Call DKeyboard.SetCommonDataFormat(DIFORMAT_KEYBOARD)
+  //  Call DKeyboard.SetCooperativeLevel(hWndForm, DISCL_NONEXCLUSIVE Or DISCL_BACKGROUND)
+  //  Call DKeyboard.Acquire
+}
+
+void RestorePrimarySurface()
+{
+  DDSURFACEDESC2 SD;
+
+  // Create PrimarySurface:
+  {
+    SD.lFlags = DDSD_CAPS;
+    SD.ddsCaps.lCaps = DDSCAPS_PRIMARYSURFACE;
+  }
+
+  // --- On Error Resume Next
+  SET_TO_NOTHING(&PrimarySurface, sizeof(PrimarySurface));
+  PrimarySurface = DDraw.CreateSurface(SD);
+}
+
+void ReleaseDirectDraw()
+{
+  SET_TO_NOTHING(&PrimarySurface, sizeof(PrimarySurface));
+  SET_TO_NOTHING(&DDraw, sizeof(DDraw));
+  SET_TO_NOTHING(&DirectX, sizeof(DirectX));
+}
+
+void ClipToWindow(long hWnd)
+{
+  DirectDrawClipper Clipper;
+  long shWnd;
+
+  if (hWnd != 0)
+    shWnd = hWnd;
+
+  // create clipper
+  Clipper = DDraw.CreateClipper(0);
+  Clipper.SetHWnd(shWnd);
+  PrimarySurface.SetClipper(Clipper);
+  SET_TO_NOTHING(&Clipper, sizeof(Clipper));
+}
+
+// Public Sub DimPrimary(Brightness&)
+// Dim Pal As DirectDrawPalette
+//  Set Pal = PrimarySurface.GetPalette()
+// End Sub
+
diff --git a/src/game_sp/DirectXGlobals.h b/src/game_sp/DirectXGlobals.h
new file mode 100644 (file)
index 0000000..4615d91
--- /dev/null
@@ -0,0 +1,26 @@
+// ----------------------------------------------------------------------------
+// DirectXGlobals.h
+// ----------------------------------------------------------------------------
+
+#ifndef DIRECTXGLOBALS_H
+#define DIRECTXGLOBALS_H
+
+#include "vb_types.h"
+#include "vb_defs.h"
+#include "vb_vars.h"
+#include "vb_lib.h"
+
+#include "global.h"
+
+extern void ClipToWindow(long hWnd);
+extern void InitDirectX(long hWndForm, long hWndClip);
+extern void ReleaseDirectDraw();
+extern void RestorePrimarySurface();
+
+extern DirectDraw7 DDraw;
+extern DirectDrawSurface7 PrimarySurface;
+extern DirectSound DSound;
+extern DirectX7 DirectX;
+extern DirectX7 DirectXS;
+
+#endif /* DIRECTXGLOBALS_H */
diff --git a/src/game_sp/Display.c b/src/game_sp/Display.c
new file mode 100644 (file)
index 0000000..b34ffa5
--- /dev/null
@@ -0,0 +1,160 @@
+// ----------------------------------------------------------------------------
+// Display.c
+// ----------------------------------------------------------------------------
+
+#include "Display.h"
+
+static char *VB_Name = "modDisplay";
+// --- Option Explicit
+
+int ScreenScrollXPos, ScreenScrollYPos;
+int ScreenPosition, data_h_Xtmp, data_h_Ytmp;
+
+int ShowRedDiskCounter, ShowPanel;
+int ExplosionShake;
+boolean NoDisplayFlag;
+
+long DisplayMinX, DisplayMaxX, DisplayWidth;
+long DisplayMinY, DisplayMaxY, DisplayHeight;
+
+
+int subDisplayInfotronsNeeded()
+{
+  int subDisplayInfotronsNeeded;
+
+  if (NoDisplayFlag)
+    return subDisplayInfotronsNeeded;
+
+  {
+#if 0
+    MainForm.lblInfoCount.Caption = InfotronsNeeded;
+    MainForm.lblInfoCount.Refresh;
+#endif
+  }
+
+  return subDisplayInfotronsNeeded;
+}
+
+int subDisplayPlayingTime()
+{
+  int subDisplayPlayingTime;
+
+
+  return subDisplayPlayingTime;
+}
+
+int subDisplayLevel()
+{
+  int subDisplayLevel;
+
+  if (NoDisplayFlag || ! LevelLoaded)
+    return subDisplayLevel;
+
+#if 0
+  MainForm.DisplayLevel();
+#endif
+
+  return subDisplayLevel;
+}
+
+void subDisplayPanel()
+{
+}
+
+int subCheckRestoreRedDiskCountDisplay()
+{
+  int subCheckRestoreRedDiskCountDisplay;
+
+  if (NoDisplayFlag)
+    return subCheckRestoreRedDiskCountDisplay;
+
+  if (ShowRedDiskCounter == 0)
+    return subCheckRestoreRedDiskCountDisplay;
+
+  ShowRedDiskCounter = ShowRedDiskCounter - 1;
+  if (ShowRedDiskCounter == 0)
+  {
+    {
+#if 0
+      MainForm.lblRedDiskCount.Caption = 0;
+      MainForm.lblRedDiskCount.Refresh;
+#endif
+    }
+  }
+
+  return subCheckRestoreRedDiskCountDisplay;
+}
+
+void subDisplayRedDiskCount()
+{
+  if (NoDisplayFlag)
+    return;
+
+  {
+#if 0
+    MainForm.lblRedDiskCount.Caption = RedDiskCount;
+    MainForm.lblRedDiskCount.Refresh;
+#endif
+  }
+  ShowRedDiskCounter = 0x46;
+}
+
+void ScrollTo(int X, int Y)
+{
+  long oldX, oldY;
+
+  if (NoDisplayFlag)
+    return;
+
+  oldX = ScrollX;
+  oldY = ScrollY;
+  X = ScrollDelta * (X / ScrollDelta);
+  X = Max(X, ScrollMinX);
+  X = Min(X, ScrollMaxX);
+  Y = ScrollDelta * (Y / ScrollDelta);
+  Y = Max(Y, ScrollMinY);
+  Y = Min(Y, ScrollMaxY);
+  //  ScrollX = X
+  //  ScrollY = Y
+  Stage.ScrollTo(X, Y);
+}
+
+void ScrollTowards(int X, int Y)
+{
+  long oldX, oldY;
+
+  if (NoDisplayFlag)
+    return;
+
+  oldX = ScrollX;
+  oldY = ScrollY;
+  X = ScrollDelta * (X / ScrollDelta);
+  X = Max(X, ScrollMinX);
+  X = Min(X, ScrollMaxX);
+  Y = ScrollDelta * (Y / ScrollDelta);
+  Y = Max(Y, ScrollMinY);
+  Y = Min(Y, ScrollMaxY);
+  //  ScrollX = X
+  //  ScrollY = Y
+  Stage.ScrollTowards(X, Y, 2 * Stretch);
+}
+
+void SoftScrollTo(int X, int Y, long TimeMS, int FPS)
+{
+  long oldX, oldY;
+
+  if (NoDisplayFlag)
+    return;
+
+  oldX = ScrollX;
+  oldY = ScrollY;
+  X = ScrollDelta * (X / ScrollDelta);
+  X = Max(X, ScrollMinX);
+  X = Min(X, ScrollMaxX);
+  Y = ScrollDelta * (Y / ScrollDelta);
+  Y = Max(Y, ScrollMinY);
+  Y = Min(Y, ScrollMaxY);
+  //  ScrollX = X
+  //  ScrollY = Y
+  Stage.SoftScrollTo(X, Y, TimeMS, FPS);
+}
diff --git a/src/game_sp/Display.h b/src/game_sp/Display.h
new file mode 100644 (file)
index 0000000..e1dec9e
--- /dev/null
@@ -0,0 +1,33 @@
+// ----------------------------------------------------------------------------
+// Display.h
+// ----------------------------------------------------------------------------
+
+#ifndef DISPLAY_H
+#define DISPLAY_H
+
+#include "vb_types.h"
+#include "vb_defs.h"
+#include "vb_vars.h"
+#include "vb_lib.h"
+
+#include "global.h"
+
+extern void ScrollTo(int X, int Y);
+extern void ScrollTowards(int X, int Y);
+extern void SoftScrollTo(int X, int Y, long TimeMS, int FPS);
+extern int subCheckRestoreRedDiskCountDisplay();
+extern int subDisplayInfotronsNeeded();
+extern int subDisplayLevel();
+extern void subDisplayPanel();
+extern int subDisplayPlayingTime();
+extern void subDisplayRedDiskCount();
+
+extern boolean NoDisplayFlag;
+extern int ExplosionShake;
+extern int ScreenPosition, data_h_Xtmp, data_h_Ytmp;
+extern int ScreenScrollXPos, ScreenScrollYPos;
+extern int ShowRedDiskCounter, ShowPanel;
+extern long DisplayMinX, DisplayMaxX, DisplayWidth;
+extern long DisplayMinY, DisplayMaxY, DisplayHeight;
+
+#endif /* DISPLAY_H */
diff --git a/src/game_sp/DoGameStuff.c b/src/game_sp/DoGameStuff.c
new file mode 100644 (file)
index 0000000..baa1102
--- /dev/null
@@ -0,0 +1,150 @@
+// ----------------------------------------------------------------------------
+// DoGameStuff.c
+// ----------------------------------------------------------------------------
+
+#include "DoGameStuff.h"
+
+static void CallAnimation(int si, byte bl);
+static boolean IsToBeAnimated(int bl);
+
+static char *VB_Name = "modDoGameStuff";
+// --- Option Explicit
+
+int *AnimationPosTable;
+byte *AnimationSubTable;
+
+// ==========================================================================
+//                              SUBROUTINE
+// Do game stuff
+// ==========================================================================
+
+int subDoGameStuff()
+{
+  int subDoGameStuff;
+
+  int si, cx, dx, bl;
+
+  subAnimateMurphy(MurphyPosIndex);       // move Murphy in any direction
+
+  // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+  // Build a database of locations and subs-to-call of animatable fields only:
+  // Make a snapshot from the field before the animation cycle starts.
+  // first and last line are not animated.
+  si = FieldWidth + 1;
+  cx = LevelMax - 2 * FieldWidth - 1;
+  dx = 0;
+  do // locloop_g_2282:
+  {
+    bl = LowByte(PlayField16[si]);
+    if (((bl & 0xD) != 0) && (bl < 0x20)) // all animatables have 1's in &H0D' above &H1F? (&H1F=explosion!)
+    {
+      if (IsToBeAnimated(bl))
+      {
+        AnimationPosTable[dx] = si;
+        AnimationSubTable[dx] = bl;
+        dx = dx + 1; // count database entries
+      }
+    }
+
+    si = si + 1; // next field
+    cx = cx - 1;
+  }
+  while (0 < cx); // locloop_g_2282' until all lines scanned(not top- and bottom edge)
+
+  // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+  // Now use the database to animate all animatables the fastest way.
+  // All the other fields are not checked anymore: those have no database entry.
+  // The field from before animation is frozen in the database in order not to
+  // do follow-up animations in the same loop.
+  if (dx != 0) // any database entries?
+  {
+    dx = dx - 1;
+    for (cx = 0; cx <= dx; cx++)
+    {
+      CallAnimation(AnimationPosTable[cx], AnimationSubTable[cx]);
+    } // loop    locloop_g_22B8          ' until all animatables done
+  }
+
+  // All animations are done now
+  // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+  if (KillMurphyFlag == 1 || MurphyMoveCounter == 0)
+  {
+    if (LeadOutCounter == 0)
+    {
+      KillMurphyFlag = 0;             // no more "kill Murphy"
+      ExplodeFieldSP(MurphyExplodePos);                 // Explode
+      LeadOutCounter = 0x40;           // quit: start lead-out
+    }
+  } //  loc_g_22FB:
+
+
+  return subDoGameStuff;
+} // subDoGameStuff
+
+static boolean IsToBeAnimated(int bl)
+{
+  static boolean IsToBeAnimated;
+
+  switch (bl)
+  {
+    case fiZonk:
+    case fiInfotron:
+    case fiOrangeDisk:
+    case fiSnikSnak:
+    case fiTerminal:
+    case fiElectron:
+    case fiBug:
+    case fiExplosion:
+      IsToBeAnimated = True;
+      break;
+
+    default:
+      IsToBeAnimated = False;
+      break;
+  }
+
+  return IsToBeAnimated;
+}
+
+static void CallAnimation(int si, byte bl)
+{
+  switch (bl)
+  {
+    case fiZonk:
+      subAnimateZonks(si);
+      break;
+
+    case fiInfotron:
+      subAnimateInfotrons(si);
+      break;
+
+    case fiOrangeDisk:
+      subAnimateOrangeDisks(si);
+      break;
+
+    case fiSnikSnak:
+      subAnimateSnikSnaks(si);
+      break;
+
+    case fiTerminal:
+      subAnimateTerminals(si);
+      break;
+
+    case fiElectron:
+      subAnimateElectrons(si);
+      break;
+
+    case fiBug:
+      subAnimateBugs(si);
+      break;
+
+    case fiExplosion:
+      subAnimateExplosion(si);
+      break;
+
+    default:
+      // Debug.Assert(False);
+      break;
+  }
+}
+
diff --git a/src/game_sp/DoGameStuff.h b/src/game_sp/DoGameStuff.h
new file mode 100644 (file)
index 0000000..5d97153
--- /dev/null
@@ -0,0 +1,20 @@
+// ----------------------------------------------------------------------------
+// DoGameStuff.h
+// ----------------------------------------------------------------------------
+
+#ifndef DOGAMESTUFF_H
+#define DOGAMESTUFF_H
+
+#include "vb_types.h"
+#include "vb_defs.h"
+#include "vb_vars.h"
+#include "vb_lib.h"
+
+#include "global.h"
+
+extern int subDoGameStuff();
+
+extern byte *AnimationSubTable;
+extern int *AnimationPosTable;
+
+#endif /* DOGAMESTUFF_H */
diff --git a/src/game_sp/Electrons.c b/src/game_sp/Electrons.c
new file mode 100644 (file)
index 0000000..709583c
--- /dev/null
@@ -0,0 +1,653 @@
+// ----------------------------------------------------------------------------
+// Electrons.c
+// ----------------------------------------------------------------------------
+
+#include "Electrons.h"
+
+static char *VB_Name = "modElectron";
+// --- Option Explicit
+// ==========================================================================
+//                              SUBROUTINE
+// Animate/move Electrons
+// ==========================================================================
+
+int subAnimateElectrons(int si)
+{
+  int subAnimateElectrons;
+
+  int bx, Tmp;
+
+  if (SnikSnaksElectronsFrozen == 1)
+    return subAnimateElectrons;
+
+  if (LowByte(PlayField16[si]) != fiElectron)
+    return subAnimateElectrons;
+
+  bx = HighByte(PlayField16[si]);
+  Tmp = bx / 8;
+  switch (Tmp)
+  {
+    case 0:
+      subElectronTurnLeft(si, bx); // turning, bx=0 -> point N, bx = 1 -> point NW etc.
+      break;
+
+    case 1:
+      subElectronTurnRight(si, bx); // turn right
+      break;
+
+    case 2:
+      subElectronFromBelow(si, bx); // access si from below
+      break;
+
+    case 3:
+      subElectronFromRight(si, bx); // access si from right
+      break;
+
+    case 4:
+      subElectronFromAbove(si, bx); // access si from above
+      break;
+
+    case 5:
+      subElectronFromLeft(si, bx); // access si from left
+      break;
+  }
+
+  return subAnimateElectrons;
+} // subAnimateElectrons
+
+int subDrawAnimatedElectrons(int si)
+{
+  int subDrawAnimatedElectrons;
+
+  int bx, Tmp;
+
+  // If SnikSnaksElectronsFrozen = 1 Then Exit Function
+  if (LowByte(PlayField16[si]) != fiElectron)
+    return subDrawAnimatedElectrons;
+
+  bx = HighByte(PlayField16[si]);
+  Tmp = bx / 8;
+  switch (Tmp)
+  {
+    case 0:
+      subDrawElectronTurnLeft(si, bx); // turning, bx=0 -> point N, bx = 1 -> point NW etc.
+      break;
+
+    case 1:
+      subDrawElectronTurnRight(si, bx); // turn right
+      break;
+
+    case 2:
+      subDrawElectronFromBelow(si, bx); // access si from below
+      break;
+
+    case 3:
+      subDrawElectronFromRight(si, bx); // access si from right
+      break;
+
+    case 4:
+      subDrawElectronFromAbove(si, bx); // access si from above
+      break;
+
+    case 5:
+      subDrawElectronFromLeft(si, bx); // access si from left
+      break;
+  }
+
+  return subDrawAnimatedElectrons;
+} // subDrawAnimatedElectrons
+
+int subElectronTurnLeft(int si, int bx)
+{
+  int subElectronTurnLeft;
+
+  int ax, ah, bl, dx, X, Y;
+
+  ax = (TimerVar & 3);
+  if (ax != 0)
+  {
+    if (ax == 3)
+      goto loc_g_7ACD;
+
+    return subElectronTurnLeft;
+  } // loc_g_7A9F:
+
+  // +++++++++++++++++++++++++++++++++++++++++++++++++++++
+  X = GetStretchX(si);
+  Y = GetStretchY(si);
+  StretchedSprites.BltEx(X, Y, aniElectron[bx]);
+  // +++++++++++++++++++++++++++++++++++++++++++++++++++++
+  bx = (bx + 1) & 0x7;
+  MovHighByte(&PlayField16[si], bx);
+  return subElectronTurnLeft;
+
+loc_g_7ACD:
+  bl = HighByte(PlayField16[si]);
+  if (bl == 0)
+    goto loc_g_7AE6;
+
+  if (bl == 2)
+    goto loc_g_7B05;
+
+  if (bl == 4)
+    goto loc_g_7B24;
+
+  if (bl == 6)
+    goto loc_g_7B43;
+
+  return subElectronTurnLeft;
+
+loc_g_7AE6: // pointing up
+  ax = PlayField16[si - FieldWidth];
+  if (ax == 0) // above is empty -> go up
+    goto loc_g_7AF5;
+
+  if (LowByte(ax) == fiMurphy) // above is murphy -> explode
+    ExplodeFieldSP(si);
+
+  return subElectronTurnLeft;
+
+loc_g_7AF5: // above is empty -> go up
+  PlayField16[si] = 0x1BB;
+  si = si - FieldWidth; // 1 field up
+  PlayField16[si] = 0x1018;
+  return subElectronTurnLeft;
+
+loc_g_7B05: // pointing left
+  ax = PlayField16[si - 1];
+  if (ax == 0) // left is empty -> go there
+    goto loc_g_7B14;
+
+  if (LowByte(ax) == fiMurphy) // left is murphy -> explode
+    ExplodeFieldSP(si);
+
+  return subElectronTurnLeft;
+
+loc_g_7B14: // left is empty -> go there
+  PlayField16[si] = 0x2BB;
+  si = si - 1; // 1 field left
+  PlayField16[si] = 0x1818;
+  return subElectronTurnLeft;
+
+loc_g_7B24: // pointing down
+  ax = PlayField16[si + FieldWidth];
+  if (ax == 0) // below is empty -> go down
+    goto loc_g_7B33;
+
+  if (LowByte(ax) == fiMurphy) // below is murphy -> explode
+    ExplodeFieldSP(si);
+
+  return subElectronTurnLeft;
+
+loc_g_7B33: // below is empty -> go down
+  PlayField16[si] = 0x3BB;
+  si = si + FieldWidth; // 1 field down
+  PlayField16[si] = 0x2018;
+  return subElectronTurnLeft;
+
+loc_g_7B43: // pointing Right
+  ax = PlayField16[si + 1];
+  if (ax == 0) // right is empty -> go there
+    goto loc_g_7B55;
+
+  if (LowByte(ax) == fiMurphy) // right is murphy -> explode
+    ExplodeFieldSP(si);
+
+  return subElectronTurnLeft;
+
+loc_g_7B55: // right is empty -> go there
+  PlayField16[si] = 0x4BB;
+  si = si + 1; // 1 field right
+  PlayField16[si] = 0x2818;
+
+  return subElectronTurnLeft;
+} // subElectronTurnLeft
+
+int subElectronTurnRight(int si, int bx)
+{
+  int subElectronTurnRight;
+
+  int ax, ah, bl, dx, X, Y;
+
+  ax = (TimerVar & 3);
+  if (ax != 0)
+  {
+    if (ax == 3)
+      goto loc_g_7BA3;
+
+    return subElectronTurnRight;
+  } // loc_g_7B73:
+
+  // +++++++++++++++++++++++++++++++++++++++++++++++++++++
+  X = GetStretchX(si);
+  Y = GetStretchY(si);
+  StretchedSprites.BltEx(X, Y, aniElectron[0x10 - bx]);
+  // +++++++++++++++++++++++++++++++++++++++++++++++++++++
+  bx = ((bx + 1) & 0x7) | 8;
+  MovHighByte(&PlayField16[si], bx);
+  return subElectronTurnRight;
+
+loc_g_7BA3:
+  bl = HighByte(PlayField16[si]);
+  if (bl == 0x8)
+    goto loc_g_7BBC;
+
+  if (bl == 0xA)
+    goto loc_g_7C19;
+
+  if (bl == 0xC)
+    goto loc_g_7BFA;
+
+  if (bl == 0xE)
+    goto loc_g_7BDB;
+
+  return subElectronTurnRight;
+
+loc_g_7BBC: // pointing up
+  ax = PlayField16[si - FieldWidth];
+  if (ax == 0) // above is empty -> go up
+    goto loc_g_7BCB;
+
+  if (LowByte(ax) == fiMurphy) // above is murphy -> explode
+    ExplodeFieldSP(si);
+
+  return subElectronTurnRight;
+
+loc_g_7BCB: // above is empty -> go up
+  PlayField16[si] = 0x1BB;
+  si = si - FieldWidth; // 1 field up
+  PlayField16[si] = 0x1018;
+  return subElectronTurnRight;
+
+loc_g_7BDB: // pointing left
+  ax = PlayField16[si - 1];
+  if (ax == 0) // left is empty -> go there
+    goto loc_g_7BEA;
+
+  if (LowByte(ax) == fiMurphy) // left is murphy -> explode
+    ExplodeFieldSP(si);
+
+  return subElectronTurnRight;
+
+loc_g_7BEA: // left is empty -> go there
+  PlayField16[si] = 0x2BB;
+  si = si - 1; // 1 field left
+  PlayField16[si] = 0x1818;
+  return subElectronTurnRight;
+
+loc_g_7BFA: // pointing down
+  ax = PlayField16[si + FieldWidth];
+  if (ax == 0) // below is empty -> go down
+    goto loc_g_7C09;
+
+  if (LowByte(ax) == fiMurphy) // below is murphy -> explode
+    ExplodeFieldSP(si);
+
+  return subElectronTurnRight;
+
+loc_g_7C09: // below is empty -> go down
+  PlayField16[si] = 0x3BB;
+  si = si + FieldWidth; // 1 field down
+  PlayField16[si] = 0x2018;
+  return subElectronTurnRight;
+
+loc_g_7C19: // pointing Right
+  ax = PlayField16[si + 1];
+  if (ax == 0) // right is empty -> go there
+    goto loc_g_7C2B;
+
+  if (LowByte(ax) == fiMurphy) // right is murphy -> explode
+    ExplodeFieldSP(si);
+
+  return subElectronTurnRight;
+
+loc_g_7C2B: // right is empty -> go there
+  PlayField16[si] = 0x4BB;
+  si = si + 1; // 1 field right
+  PlayField16[si] = 0x2818;
+
+  return subElectronTurnRight;
+} // subElectronTurnRight
+
+int subElectronFromBelow(int si, int bx)
+{
+  int subElectronFromBelow;
+
+  int ax, ah, bl, dx, X, Y;
+
+  bx = bx - 0xF;  // get and increment sequence#
+  // +++++++++++++++++++++++++++++++++++++++++++++++++++++
+  X = GetStretchX(si);
+  Y = GetStretchY(si + FieldWidth);
+  StretchedSprites.BltEx(X, Y, 0);
+  StretchedSprites.BltEx(X, Y - bx * TwoPixels, aniElectron[bx]);
+  // +++++++++++++++++++++++++++++++++++++++++++++++++++++
+  bl = LowByte(bx);
+  if (bl == 7 && LowByte(PlayField16[si + FieldWidth]) != fiExplosion)
+  {
+    PlayField16[si + FieldWidth] = 0; // electron left that field
+  }
+
+  if (bl < 8) // electron still goes up
+  {
+    bl = bl + 0x10;
+    MovHighByte(&PlayField16[si], bl);
+    return subElectronFromBelow;
+  } // loc_g_7C84
+
+  PlayField16[si] = 0x18; // sequence#=8 -> arrived at the new field
+  ax = PlayField16[si - 1]; // check left field
+  if (ax == 0 || LowByte(ax) == fiMurphy) // check for empty or murphy
+  {
+    MovHighByte(&PlayField16[si], 1); // start to turn left
+    return subElectronFromBelow;
+  } // loc_g_7CA4:
+
+  ax = PlayField16[si - FieldWidth]; // cannot turn left -> check above
+  if (ax == 0) // check if empty
+  {
+    PlayField16[si] = 0x1BB; // mark as "electron leaving"
+    si = si - FieldWidth; // go up!
+    PlayField16[si] = 0x1018;
+    return subElectronFromBelow;
+  }
+
+  if (LowByte(ax) == fiMurphy) // check for murphy above
+  {
+    ExplodeFieldSP(si); // Explode
+    return subElectronFromBelow;
+  } // loc_g_7CC6:
+
+  ax = PlayField16[si + 1]; // check right field
+  if (ax == 0 || LowByte(ax) == fiMurphy) // check for empty or murphy
+  {
+    MovHighByte(&PlayField16[si], 9); // start to turn right
+    return subElectronFromBelow;
+  } // loc_g_7CE0:
+
+  // else: no way to go, start turning around
+  MovHighByte(&PlayField16[si], 1);
+
+  return subElectronFromBelow;
+} // subElectronFromBelow
+
+int subElectronFromRight(int si, int bx)
+{
+  int subElectronFromRight;
+
+  int ax, ah, bl, dx, X, Y;
+
+  bx = bx - 0x17;  // get and increment sequence#
+  // +++++++++++++++++++++++++++++++++++++++++++++++++++++
+  X = GetStretchX(si + 1);
+  Y = GetStretchY(si);
+  StretchedSprites.BltEx(X, Y, 0);
+  StretchedSprites.BltEx(X - bx * TwoPixels, Y, aniElectron[bx]);
+  // +++++++++++++++++++++++++++++++++++++++++++++++++++++
+  bl = LowByte(bx);
+  if (bl == 7 && LowByte(PlayField16[si + 1]) != fiExplosion)
+  {
+    PlayField16[si + 1] = 0; // electron left that field
+  } // loc_g_7D1D:
+
+  if (bl < 8) // sniksnak still goes left
+  {
+    bl = bl + 0x18;
+    MovHighByte(&PlayField16[si], bl);
+    return subElectronFromRight;
+  } // loc_g_7D2A:
+
+  PlayField16[si] = 0x18; // sequence#=8 -> arrived at the new field
+  ax = PlayField16[si + FieldWidth]; // check below
+  if (ax == 0 || LowByte(ax) == fiMurphy) // empty or murphy?
+  {
+    MovHighByte(&PlayField16[si], 3); // yes -> turn left down
+    return subElectronFromRight;
+  } // loc_g_7D4A:
+
+  ax = PlayField16[si - 1]; // check left, etc ... see the comments on subElectronFromBelow()
+  if (ax == 0)
+  {
+    PlayField16[si] = 0x2BB;
+    si = si - 1;                // 1 field left
+    PlayField16[si] = 0x1818;
+    return subElectronFromRight;
+  } // loc_g_7D61:
+
+  if (LowByte(ax) == fiMurphy)
+  {
+    ExplodeFieldSP(si);      // Explode
+    return subElectronFromRight;
+  } // loc_g_7D6C:
+
+  ax = PlayField16[si - FieldWidth]; // check above
+  if (ax == 0 || LowByte(ax) == fiMurphy)
+  {
+    MovHighByte(&PlayField16[si], 0xF);
+    return subElectronFromRight;
+  } // loc_g_7D86:
+
+  MovHighByte(&PlayField16[si], 3);
+
+  return subElectronFromRight;
+} // subElectronFromRight
+
+int subElectronFromAbove(int si, int bx)
+{
+  int subElectronFromAbove;
+
+  int ax, ah, bl, dx, X, Y;
+
+  bx = bx - 0x1F;  // get and increment sequence#
+  // +++++++++++++++++++++++++++++++++++++++++++++++++++++
+  X = GetStretchX(si);
+  Y = GetStretchY(si - FieldWidth);
+  StretchedSprites.BltEx(X, Y, 0);
+  StretchedSprites.BltEx(X, Y + bx * TwoPixels, aniElectron[bx]);
+  // +++++++++++++++++++++++++++++++++++++++++++++++++++++
+  bl = LowByte(bx);
+  if (bl == 7 && LowByte(PlayField16[si - FieldWidth]) != fiExplosion)
+  {
+    PlayField16[si - FieldWidth] = 0; // electron left that field
+  }
+
+  if (bl < 8) // electron still goes down
+  {
+    bl = bl + 0x20;
+    MovHighByte(&PlayField16[si], bl);
+    return subElectronFromAbove;
+  } // loc_g_7DD7
+
+  PlayField16[si] = 0x18; // sequence#=8 -> arrived at the new field
+  ax = PlayField16[si + 1]; // check right
+  if (ax == 0 || LowByte(ax) == fiMurphy)
+  {
+    MovHighByte(&PlayField16[si], 5);
+    return subElectronFromAbove;
+  } // loc_g_7DF7:
+
+  ax = PlayField16[si + FieldWidth]; // check below
+  if (ax == 0)
+  {
+    PlayField16[si] = 0x3BB;
+    si = si + FieldWidth;                 // 1 field down
+    PlayField16[si] = 0x2018;
+    return subElectronFromAbove;
+  } // loc_g_7E0E:
+
+  if (LowByte(ax) == fiMurphy)
+  {
+    ExplodeFieldSP(si);        // Explode
+    return subElectronFromAbove;
+  } // loc_g_7E19:
+
+  ax = PlayField16[si - 1]; // check left
+  if (ax == 0 || LowByte(ax) == fiMurphy)
+  {
+    MovHighByte(&PlayField16[si], 0xD);
+    return subElectronFromAbove;
+  } // loc_g_7E33:
+
+  MovHighByte(&PlayField16[si], 5);
+
+  return subElectronFromAbove;
+} // subElectronFromAbove
+
+int subElectronFromLeft(int si, int bx)
+{
+  int subElectronFromLeft;
+
+  int ax, ah, bl, dx, X, Y;
+
+  bx = bx - 0x27;  // get and increment sequence#
+  // +++++++++++++++++++++++++++++++++++++++++++++++++++++
+  X = GetStretchX(si - 1);
+  Y = GetStretchY(si);
+  StretchedSprites.BltEx(X, Y, 0);
+  StretchedSprites.BltEx(X + bx * TwoPixels, Y, aniElectron[bx]);
+  // +++++++++++++++++++++++++++++++++++++++++++++++++++++
+  bl = LowByte(bx);
+  if (bl == 7 && LowByte(PlayField16[si - 1]) != fiExplosion)
+  {
+    PlayField16[si - 1] = 0; // electron left that field
+  }
+
+  if (bl < 8) // electron still goes right
+  {
+    bl = bl + 0x28;
+    MovHighByte(&PlayField16[si], bl);
+    return subElectronFromLeft;
+  } // loc_g_7E7E:
+
+  PlayField16[si] = 0x18; // sequence#=8 -> arrived at the new field
+  ax = PlayField16[si - FieldWidth]; // check above
+  if (ax == 0 || LowByte(ax) == fiMurphy)
+  {
+    MovHighByte(&PlayField16[si], 7);
+    return subElectronFromLeft;
+  } // loc_g_7E9E:
+
+  ax = PlayField16[si + 1]; // check right(straight on)
+  if (ax == 0)
+  {
+    PlayField16[si] = 0x4BB;
+    si = si + 1;                   // 1 field right
+    PlayField16[si] = 0x2818;
+    return subElectronFromLeft;
+  } // loc_g_7EB5:
+
+  if (LowByte(ax) == fiMurphy)
+  {
+    ExplodeFieldSP(si);    // Explode
+    return subElectronFromLeft;
+  } // loc_g_7EC0:
+
+  ax = PlayField16[si + FieldWidth]; // check below
+  if (ax == 0 || LowByte(ax) == fiMurphy)
+  {
+    MovHighByte(&PlayField16[si], 0xB);
+    return subElectronFromLeft;
+  } // loc_g_7A69:
+
+  MovHighByte(&PlayField16[si], 7);
+
+  return subElectronFromLeft;
+} // subElectronFromLeft
+
+int subDrawElectronTurnLeft(int si, int bx)
+{
+  int subDrawElectronTurnLeft;
+
+  int X, Y;
+
+  // +++++++++++++++++++++++++++++++++++++++++++++++++++++
+  X = GetStretchX(si);
+  Y = GetStretchY(si);
+  StretchedSprites.BltEx(X, Y, aniElectron[bx]);
+  // +++++++++++++++++++++++++++++++++++++++++++++++++++++
+
+  return subDrawElectronTurnLeft;
+}
+
+int subDrawElectronTurnRight(int si, int bx)
+{
+  int subDrawElectronTurnRight;
+
+  int X, Y;
+
+  // +++++++++++++++++++++++++++++++++++++++++++++++++++++
+  X = GetStretchX(si);
+  Y = GetStretchY(si);
+  StretchedSprites.BltEx(X, Y, aniElectron[0x10 - bx]);
+  // +++++++++++++++++++++++++++++++++++++++++++++++++++++
+
+  return subDrawElectronTurnRight;
+}
+
+int subDrawElectronFromBelow(int si, int bx)
+{
+  int subDrawElectronFromBelow;
+
+  int X, Y;
+
+  bx = bx - 0xF;  // get and increment sequence#
+  // +++++++++++++++++++++++++++++++++++++++++++++++++++++
+  X = GetStretchX(si);
+  Y = GetStretchY(si + FieldWidth);
+  StretchedSprites.BltEx(X, Y, 0);
+  StretchedSprites.BltEx(X, Y - bx * TwoPixels, aniElectron[bx]);
+  // +++++++++++++++++++++++++++++++++++++++++++++++++++++
+
+  return subDrawElectronFromBelow;
+}
+
+int subDrawElectronFromRight(int si, int bx)
+{
+  int subDrawElectronFromRight;
+
+  int X, Y;
+
+  bx = bx - 0x17;  // get and increment sequence#
+  // +++++++++++++++++++++++++++++++++++++++++++++++++++++
+  X = GetStretchX(si + 1);
+  Y = GetStretchY(si);
+  StretchedSprites.BltEx(X, Y, 0);
+  StretchedSprites.BltEx(X - bx * TwoPixels, Y, aniElectron[bx]);
+  // +++++++++++++++++++++++++++++++++++++++++++++++++++++
+
+  return subDrawElectronFromRight;
+}
+
+int subDrawElectronFromAbove(int si, int bx)
+{
+  int subDrawElectronFromAbove;
+
+  int X, Y;
+
+  bx = bx - 0x1F;  // get and increment sequence#
+  // +++++++++++++++++++++++++++++++++++++++++++++++++++++
+  X = GetStretchX(si);
+  Y = GetStretchY(si - FieldWidth);
+  StretchedSprites.BltEx(X, Y, 0);
+  StretchedSprites.BltEx(X, Y + bx * TwoPixels, aniElectron[bx]);
+  // +++++++++++++++++++++++++++++++++++++++++++++++++++++
+
+  return subDrawElectronFromAbove;
+}
+
+int subDrawElectronFromLeft(int si, int bx)
+{
+  int subDrawElectronFromLeft;
+
+  int X, Y;
+
+  bx = bx - 0x27;  // get and increment sequence#
+  // +++++++++++++++++++++++++++++++++++++++++++++++++++++
+  X = GetStretchX(si - 1);
+  Y = GetStretchY(si);
+  StretchedSprites.BltEx(X, Y, 0);
+  StretchedSprites.BltEx(X + bx * TwoPixels, Y, aniElectron[bx]);
+  // +++++++++++++++++++++++++++++++++++++++++++++++++++++
+
+  return subDrawElectronFromLeft;
+}
diff --git a/src/game_sp/Electrons.h b/src/game_sp/Electrons.h
new file mode 100644 (file)
index 0000000..5eaf289
--- /dev/null
@@ -0,0 +1,30 @@
+// ----------------------------------------------------------------------------
+// Electrons.h
+// ----------------------------------------------------------------------------
+
+#ifndef ELECTRONS_H
+#define ELECTRONS_H
+
+#include "vb_types.h"
+#include "vb_defs.h"
+#include "vb_vars.h"
+#include "vb_lib.h"
+
+#include "global.h"
+
+extern int subAnimateElectrons(int si);
+extern int subDrawAnimatedElectrons(int si);
+extern int subDrawElectronFromAbove(int si, int bx);
+extern int subDrawElectronFromBelow(int si, int bx);
+extern int subDrawElectronFromLeft(int si, int bx);
+extern int subDrawElectronFromRight(int si, int bx);
+extern int subDrawElectronTurnLeft(int si, int bx);
+extern int subDrawElectronTurnRight(int si, int bx);
+extern int subElectronFromAbove(int si, int bx);
+extern int subElectronFromBelow(int si, int bx);
+extern int subElectronFromLeft(int si, int bx);
+extern int subElectronFromRight(int si, int bx);
+extern int subElectronTurnLeft(int si, int bx);
+extern int subElectronTurnRight(int si, int bx);
+
+#endif /* ELECTRONS_H */
diff --git a/src/game_sp/ErrorReporting.c b/src/game_sp/ErrorReporting.c
new file mode 100644 (file)
index 0000000..8cd7457
--- /dev/null
@@ -0,0 +1,78 @@
+// ----------------------------------------------------------------------------
+// ErrorReporting.c
+// ----------------------------------------------------------------------------
+
+#include "ErrorReporting.h"
+
+static char * GetErrLogPath();
+static char * GetTraceLogPath();
+
+static char *VB_Name = "modErrorReporting";
+// --- Option Explicit
+
+static char *GetErrLogPath()
+{
+  static char *GetErrLogPath;
+
+  // GetErrLogPath = GET_PATH(WithSlash(App.Path), "Error.log");
+  GetErrLogPath = "Error.log";
+
+  return GetErrLogPath;
+}
+
+static char *GetTraceLogPath()
+{
+  static char *GetTraceLogPath;
+
+  // GetTraceLogPath = GET_PATH(WithSlash(App.Path), "Trace.log");
+  GetTraceLogPath = "Trace.log";
+
+  return GetTraceLogPath;
+}
+
+void Trace(char *Source, char *Message)
+{
+  // Dim Path$, FNum%, bIsOpen As Boolean
+  //  Path = GetTraceLogPath()
+  //  FNum = FreeFile
+  //  bIsOpen = False
+  //  On Error GoTo TraceEH
+  //  Open Path For Append Access Write As FNum
+  //    bIsOpen = True
+  //    ' --- Print #FNum, Now & "  " & Source & " :  " & Message
+  //  On Error GoTo 0
+  // TraceEH:
+  //  If bIsOpen Then Close FNum
+}
+
+void ReportError(char *Source, char *Message)
+{
+  char *Path;
+  int FNum;
+  boolean bIsOpen;
+
+  Path = GetErrLogPath();
+  // FNum = FreeFile();
+  bIsOpen = False;
+
+  // --- On Error GoTo ReportErrorEH
+  FNum = fopen(Path, "ab");
+  bIsOpen = True;
+  // --- Print #FNum, Now & "    SOURCE = " & Source & "    ErrMessage = " & Message
+  // --- On Error GoTo 0
+
+
+ReportErrorEH:
+  if (bIsOpen)
+    fclose(FNum);
+}
+
+void InitErrorReporting()
+{
+  char *Path;
+
+  Path = GetErrLogPath();
+  MayKill(Path);
+  Path = GetTraceLogPath();
+  MayKill(Path);
+}
diff --git a/src/game_sp/ErrorReporting.h b/src/game_sp/ErrorReporting.h
new file mode 100644 (file)
index 0000000..b5c0f51
--- /dev/null
@@ -0,0 +1,19 @@
+// ----------------------------------------------------------------------------
+// ErrorReporting.h
+// ----------------------------------------------------------------------------
+
+#ifndef ERRORREPORTING_H
+#define ERRORREPORTING_H
+
+#include "vb_types.h"
+#include "vb_defs.h"
+#include "vb_vars.h"
+#include "vb_lib.h"
+
+#include "global.h"
+
+extern void InitErrorReporting();
+extern void ReportError(char *Source, char *Message);
+extern void Trace(char *Source, char *Message);
+
+#endif /* ERRORREPORTING_H */
diff --git a/src/game_sp/Explosions.c b/src/game_sp/Explosions.c
new file mode 100644 (file)
index 0000000..b6b6ca8
--- /dev/null
@@ -0,0 +1,337 @@
+// ----------------------------------------------------------------------------
+// Explosions.c
+// ----------------------------------------------------------------------------
+
+#include "Explosions.h"
+
+static void LetExplodeFieldSP(int tsi, int cx, int dh);
+static int subExplodeInfotron(int tsi, int cx);
+static int subExplodeZonk(int tsi, int cx);
+
+static char *VB_Name = "modExplosions";
+// --- Option Explicit
+
+// ==========================================================================
+//                              SUBROUTINE
+// Animate explosion
+// ==========================================================================
+int subAnimateExplosion(int si)
+{
+  int subAnimateExplosion;
+
+  int ax, bx, bl, X, Y;
+
+  if (LowByte(PlayField16[si]) != fiExplosion)
+    return subAnimateExplosion;
+
+  ax = (TimerVar & 3);
+  if (ax != 0)
+    return subAnimateExplosion;
+
+  bl = HighByte(PlayField16[si]);
+  if ((bl & 0x80) != 0) // infotron explosion!
+    goto loc_g_28D0;
+
+  bl = bl + 1;
+  MovHighByte(&PlayField16[si], bl);
+  // ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+  X = GetStretchX(si);
+  Y = GetStretchY(si);
+  StretchedSprites.BltEx(X, Y, aniExplosion[bl]);
+  // ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+  if (bl == 8)
+  {
+    PlayField16[si] = 0;
+    ExplosionShake = 0; // nothing explodes
+  } // loc_ret_g_28CF:
+
+  return subAnimateExplosion;
+
+loc_g_28D0: // explosion produces infotron
+  bl = bl + 1;
+  if (bl == 0x89)
+  {
+    PlayField16[si] = fiInfotron;
+    MovLowByte(&ExplosionShake, 0); // nothing explodes
+    return subAnimateExplosion;
+  } // loc_g_28E3:
+
+  MovHighByte(&PlayField16[si], bl);
+  // ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+  X = GetStretchX(si);
+  Y = GetStretchY(si);
+  StretchedSprites.BltEx(X, Y, aniExplosionInfo + bl - 0x80);
+  // ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+
+  return subAnimateExplosion;
+} // subAnimateExplosion
+
+// ==========================================================================
+//                              SUBROUTINE
+// Explode
+// ==========================================================================
+
+void ExplodeFieldSP(int si)
+{
+  int ax, al, cx, dl, dh;
+
+  ax = LowByte(PlayField16[si]);
+  if (ax == fiHardWare)
+    return;
+
+  ExplosionShake = 1; // something explodes
+  if (ax == fiMurphy)
+    KillMurphyFlag = 1;
+
+  if (ax == fiElectron)
+  {
+    cx = 0x801F; // produce infotrons
+    dl = 0xF3;
+  }
+  else // loc_g_2977:
+  {
+    cx = 0x1F; // normal explosion
+    dl = 0xD;
+  } // loc_g_297C:
+
+  LetExplodeFieldSP(si - FieldWidth - 1, cx, dl);
+  LetExplodeFieldSP(si - FieldWidth, cx, dl);
+  LetExplodeFieldSP(si - FieldWidth + 1, cx, dl);
+  LetExplodeFieldSP(si - 1, cx, dl);
+  PlayField16[si] = cx;
+  LetExplodeFieldSP(si + 1, cx, dl);
+  LetExplodeFieldSP(si + FieldWidth - 1, cx, dl);
+  LetExplodeFieldSP(si + FieldWidth, cx, dl);
+  LetExplodeFieldSP(si + FieldWidth + 1, cx, dl);
+
+loc_g_2C3B:
+  subSoundFXExplosion();
+} // ExplodeFieldSP
+
+static void LetExplodeFieldSP(int tsi, int cx, int dh)
+{
+  int al;
+
+  if (tsi < (-FieldWidth))
+    return;
+
+  al = LowByte(PlayField16[tsi]);
+  switch (al)
+  {
+    case fiHardWare:
+      return;
+
+      break;
+
+    case fiOrangeDisk:
+    case fiYellowDisk:
+    case fiSnikSnak:
+      PlayField8[tsi] = dh;
+      PlayField16[tsi] = cx;
+      break;
+
+    case fiZonk:
+      subExplodeZonk(tsi, cx);
+      break;
+
+    case fiInfotron:
+      subExplodeInfotron(tsi, cx);
+      break;
+
+    case fiElectron:
+      PlayField8[tsi] = (-dh) & 0xFF;
+      PlayField16[tsi] = 0x801F;
+      break;
+
+    case fiMurphy:
+      KillMurphyFlag = 1;
+      PlayField8[tsi] = dh;
+      PlayField16[tsi] = cx;
+      break;
+
+    default:
+      PlayField16[tsi] = cx;
+      break;
+  }
+}
+
+static int subExplodeZonk(int tsi, int cx)
+{
+  static int subExplodeZonk;
+
+  int ah;
+
+  ah = HighByte(PlayField16[tsi]) & 0xF0;
+  PlayField16[tsi] = cx;
+  switch (ah)
+  {
+    case 0x10:
+    case 0x70:
+      subClearFieldDueToExplosion(tsi - FieldWidth);
+      tsi = tsi + FieldWidth;
+      if (PlayField16[tsi] == 0x9999)
+        subClearFieldDueToExplosion(tsi);
+
+      break;
+
+    case 0x20:
+      subClearFieldDueToExplosion(tsi + 1);
+      subClearFieldDueToExplosion(tsi + FieldWidth);
+      break;
+
+    case 0x30:
+      subClearFieldDueToExplosion(tsi - 1);
+      subClearFieldDueToExplosion(tsi + FieldWidth);
+      break;
+
+    case 0x50:
+      subClearFieldDueToExplosion(tsi - 1);
+      break;
+
+    case 0x60:
+      subClearFieldDueToExplosion(tsi + 1);
+      break;
+
+    case 0xFF000070: // !!! 0x70; this will never be reached! ...??
+      subClearFieldDueToExplosion(tsi + FieldWidth);
+      break;
+  }
+
+  return subExplodeZonk;
+} // subExplodeZonk
+
+static int subExplodeInfotron(int tsi, int cx)
+{
+  static int subExplodeInfotron;
+
+  int ah;
+
+  ah = HighByte(PlayField16[tsi]) & 0xF0;
+  PlayField16[tsi] = cx;
+  switch (ah)
+  {
+    case 0x10:
+    case 0x70:
+      subClearFieldDueToExplosion(tsi - FieldWidth);
+      tsi = tsi + FieldWidth;
+      if (PlayField16[tsi] == 0x9999)
+        subClearFieldDueToExplosion(tsi);
+
+      break;
+
+    case 0x20:
+      subClearFieldDueToExplosion(tsi + 1);
+      tsi = tsi + FieldWidth; // differnt from zonk version
+      if (PlayField16[tsi] == 0x9999)
+        subClearFieldDueToExplosion(tsi);
+
+      break;
+
+    case 0x30:
+      subClearFieldDueToExplosion(tsi - 1);
+      tsi = tsi + FieldWidth; // differnt from zonk version
+      if (PlayField16[tsi] == 0x9999)
+        subClearFieldDueToExplosion(tsi);
+
+      break;
+
+    case 0x50:
+      subClearFieldDueToExplosion(tsi - 1);
+      break;
+
+    case 0x60:
+      subClearFieldDueToExplosion(tsi + 1);
+      break;
+
+    case 0xFF000070: // !!! 0x70; this will never be reached! ...??
+      subClearFieldDueToExplosion(tsi + FieldWidth);
+      break;
+  }
+
+  return subExplodeInfotron;
+} // subExplodeInfotron
+
+int subClearFieldDueToExplosion(int si)
+{
+  int subClearFieldDueToExplosion;
+
+  int X, Y;
+
+  if (LowByte(PlayField16[si]) == fiExplosion)
+    return subClearFieldDueToExplosion;
+
+  PlayField16[si] = 0;
+  // ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+  X = GetStretchX(si);
+  Y = GetStretchY(si);
+  StretchedSprites.BltEx(X, Y, fiSpace);
+  // ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+
+  return subClearFieldDueToExplosion;
+} // subClearFieldDueToExplosion
+
+int subRedDiskReleaseExplosion()
+{
+  int subRedDiskReleaseExplosion;
+
+  int al, X, Y, si;
+
+  al = RedDiskReleasePhase;            // Red disk release phase
+  if (al <= 1)
+    return subRedDiskReleaseExplosion;
+
+  si = RedDiskReleaseMurphyPos;
+  if (PlayField16[si] == 0) // Release red disk
+    PlayField16[si] = fiRedDisk;
+
+  // +++++++++++++++++++++++++++++++++++++++++
+  X = GetStretchX(si);
+  Y = GetStretchY(si);
+  StretchedSprites.BltEx(X, Y, fiRedDisk);
+  // +++++++++++++++++++++++++++++++++++++++++
+  RedDiskReleasePhase = RedDiskReleasePhase + 1;
+  if (RedDiskReleasePhase >= 0x28)
+  {
+    // si = RedDiskReleaseMurphyPos           ' Red disk was released here
+    ExplodeFieldSP(si);                 // Explode
+    RedDiskReleasePhase = 0;
+  }
+
+  return subRedDiskReleaseExplosion;
+}
+
+int subFollowUpExplosions()
+{
+  int subFollowUpExplosions;
+
+  int ax, si;
+
+locloop_g_2919:
+  for (si = 0; si <= LevelMax; si++)
+  {
+    ax = ByteToInt(PlayField8[si]);
+    if (ax != 0)
+    {
+      if (ax < 0)
+      {
+        ax = ax + 1;
+        PlayField8[si] = ax & 0xFF;
+        if (ax == 0)
+        {
+          PlayField16[si] = 0xFF18;
+          ExplodeFieldSP(si);                 // Explode
+        }
+
+      }
+      else
+      {
+        ax = ax - 1;
+        PlayField8[si] = ax;
+        if (ax == 0)
+          ExplodeFieldSP(si);
+      }
+    }
+  }
+
+  return subFollowUpExplosions;
+} // subFollowUpExplosions
diff --git a/src/game_sp/Explosions.h b/src/game_sp/Explosions.h
new file mode 100644 (file)
index 0000000..16e41d5
--- /dev/null
@@ -0,0 +1,21 @@
+// ----------------------------------------------------------------------------
+// Explosions.h
+// ----------------------------------------------------------------------------
+
+#ifndef EXPLOSIONS_H
+#define EXPLOSIONS_H
+
+#include "vb_types.h"
+#include "vb_defs.h"
+#include "vb_vars.h"
+#include "vb_lib.h"
+
+#include "global.h"
+
+extern void ExplodeFieldSP(int si);
+extern int subAnimateExplosion(int si);
+extern int subClearFieldDueToExplosion(int si);
+extern int subFollowUpExplosions();
+extern int subRedDiskReleaseExplosion();
+
+#endif /* EXPLOSIONS_H */
diff --git a/src/game_sp/FakeDeclares.c b/src/game_sp/FakeDeclares.c
new file mode 100644 (file)
index 0000000..c6ed578
--- /dev/null
@@ -0,0 +1,114 @@
+// ----------------------------------------------------------------------------
+// FakeDeclares.c
+// ----------------------------------------------------------------------------
+
+#include "FakeDeclares.h"
+
+static void subUpdateHallOfFame();
+
+static char *VB_Name = "FakeDeclares";
+// --- Option Explicit
+// --- Option Compare Binary
+
+int MurphyPosIndex, MurphyXPos, MurphyYPos;
+int MurphyScreenXPos, MurphyScreenYPos;
+int MurphyExplodePos, SplitMoveFlag, RedDiskReleaseMurphyPos;
+int KillMurphyFlag, MurphyMoveCounter;
+long YawnSleepCounter;
+int MurphyVar0DAC;
+int MurphyVar0DAE;
+int MurphyVarFaceLeft;
+int ScratchGravity, GravityFlag;
+int RedDiskReleaseFlag, MovingPictureSequencePhase;
+int data_h_DemoDone, LevelStatus;
+
+int data_h_0DA7;
+int data_h_0DA8;
+int data_h_0DA9;
+int data_h_0D9E;
+int data_h_0D9F;
+int data_h_0DA0;
+int data_h_0DA1;
+int data_h_0DA2;
+int data_h_0DA4;
+int data_h_0DA5;
+int data_h_0DA6;
+
+int data_h_165A;
+int YellowDisksExploded;
+int AllowRedDiskCheat, AllowEatRightRedDiskBug;
+
+int GameBusyFlag;
+int InfotronsNeeded, TotalInfotronsNeeded;
+int RedDiskCount;
+int SnikSnaksElectronsFrozen;
+
+boolean EditFlag;
+int EditMode;
+// --- const int edDraw = 1;
+int edSelect = 2;
+int edMove = 3;
+
+int DemoFlag, data_scr_demo, demo_stopped;
+int WasDemoFlag;
+int EP_GameDemoVar0DAA;
+int RecordDemoFlag; // , DemoRecordingFlag%
+int DemoKeyCode, DemoPointer;
+long DemoOffset;
+int DemoKeyRepeatCounter;
+
+int RedDiskReleasePhase;
+int UpdatedFlag;
+
+int DebugVersionFlag, D_ModeFlag;
+int Data_SubRest, Data_SubRstFlg;
+int keyEnter;
+
+int data_SPtorunavail; // ???????
+
+int UpdateTimeFlag;
+
+// boolean bModified;
+boolean ModifiedFlag;
+
+static void subUpdateHallOfFame()
+{
+}
+
+boolean Get_ModifiedFlag()
+{
+  // boolean ModifiedFlag;
+
+  // Let_ModifiedFlag(bModified);
+  Let_ModifiedFlag(ModifiedFlag);
+
+  return ModifiedFlag;
+}
+
+void Let_ModifiedFlag(boolean NewVal)
+{
+  // If bModified = NewVal Then Exit Property
+  char *Cap;
+
+  // bModified = NewVal;
+  ModifiedFlag = NewVal;
+  if (! LevelLoaded)
+    return;
+
+  if (NewVal)
+  {
+    Cap = ""; // !!! Cap = "MegaPlex - " & StripFileName(OrigPath) & "*"
+    gSignature = "";
+    bSignatureAvailable = False;
+  }
+  else
+  {
+    Cap = ""; // !!! Cap = "MegaPlex - " & StripFileName(OrigPath)
+  }
+
+#if 0
+  if (MainForm.Caption != Cap)
+    MainForm.Caption = Cap;
+#endif
+}
+
diff --git a/src/game_sp/FakeDeclares.h b/src/game_sp/FakeDeclares.h
new file mode 100644 (file)
index 0000000..327587f
--- /dev/null
@@ -0,0 +1,69 @@
+// ----------------------------------------------------------------------------
+// FakeDeclares.h
+// ----------------------------------------------------------------------------
+
+#ifndef FAKEDECLARES_H
+#define FAKEDECLARES_H
+
+#include "vb_types.h"
+#include "vb_defs.h"
+#include "vb_vars.h"
+#include "vb_lib.h"
+
+#include "global.h"
+
+#define edDraw                         (1)
+
+extern boolean ModifiedFlag;
+extern boolean Get_ModifiedFlag();
+extern void Let_ModifiedFlag(boolean NewVal);
+
+extern boolean EditFlag;
+extern int AllowRedDiskCheat, AllowEatRightRedDiskBug;
+extern int Data_SubRest, Data_SubRstFlg;
+extern int DebugVersionFlag, D_ModeFlag;
+extern int DemoFlag, data_scr_demo, demo_stopped;
+extern int DemoKeyCode, DemoPointer;
+extern int DemoKeyRepeatCounter;
+extern int EP_GameDemoVar0DAA;
+extern int EditMode;
+extern int GameBusyFlag;
+extern int InfotronsNeeded, TotalInfotronsNeeded;
+extern int KillMurphyFlag, MurphyMoveCounter;
+extern int MurphyExplodePos, SplitMoveFlag, RedDiskReleaseMurphyPos;
+extern int MurphyPosIndex, MurphyXPos, MurphyYPos;
+extern int MurphyScreenXPos, MurphyScreenYPos;
+extern int MurphyVar0DAC;
+extern int MurphyVar0DAE;
+extern int MurphyVarFaceLeft;
+extern int RecordDemoFlag;
+extern int RedDiskCount;
+extern int RedDiskReleaseFlag, MovingPictureSequencePhase;
+extern int RedDiskReleasePhase;
+extern int ScratchGravity, GravityFlag;
+extern int SnikSnaksElectronsFrozen;
+extern int UpdateTimeFlag;
+extern int UpdatedFlag;
+extern int WasDemoFlag;
+extern int YellowDisksExploded;
+extern int data_SPtorunavail;
+extern int data_h_0D9E;
+extern int data_h_0D9F;
+extern int data_h_0DA0;
+extern int data_h_0DA1;
+extern int data_h_0DA2;
+extern int data_h_0DA4;
+extern int data_h_0DA5;
+extern int data_h_0DA6;
+extern int data_h_0DA7;
+extern int data_h_0DA8;
+extern int data_h_0DA9;
+extern int data_h_165A;
+extern int data_h_DemoDone, LevelStatus;
+extern int edMove;
+extern int edSelect;
+extern int keyEnter;
+extern long DemoOffset;
+extern long YawnSleepCounter;
+
+#endif /* FAKEDECLARES_H */
diff --git a/src/game_sp/FancyRestore.c b/src/game_sp/FancyRestore.c
new file mode 100644 (file)
index 0000000..e31dfeb
--- /dev/null
@@ -0,0 +1,22 @@
+// ----------------------------------------------------------------------------
+// FancyRestore.c
+// ----------------------------------------------------------------------------
+
+#include "FancyRestore.h"
+
+static char *VB_Name = "modFancy";
+// --- Option Explicit
+
+// ==========================================================================
+//                              SUBROUTINE
+// Restore fancy stuff from sparelevel (and destroy registers ...)
+// ==========================================================================
+
+
+int subRestoreFancy()
+{
+  int subRestoreFancy;
+
+
+  return subRestoreFancy;
+}
diff --git a/src/game_sp/FancyRestore.h b/src/game_sp/FancyRestore.h
new file mode 100644 (file)
index 0000000..3edb6d7
--- /dev/null
@@ -0,0 +1,17 @@
+// ----------------------------------------------------------------------------
+// FancyRestore.h
+// ----------------------------------------------------------------------------
+
+#ifndef FANCYRESTORE_H
+#define FANCYRESTORE_H
+
+#include "vb_types.h"
+#include "vb_defs.h"
+#include "vb_vars.h"
+#include "vb_lib.h"
+
+#include "global.h"
+
+extern int subRestoreFancy();
+
+#endif /* FANCYRESTORE_H */
diff --git a/src/game_sp/GeneralTricks.c b/src/game_sp/GeneralTricks.c
new file mode 100644 (file)
index 0000000..19de0d6
--- /dev/null
@@ -0,0 +1,149 @@
+// ----------------------------------------------------------------------------
+// GeneralTricks.c
+// ----------------------------------------------------------------------------
+
+#include "GeneralTricks.h"
+
+static char *VB_Name = "GeneralTricks_Module";
+// --- Option Explicit
+// --- Option Compare Text
+
+double ValEx(char *TS)
+{
+  double ValEx;
+
+  // Extends the Val() function for
+  // german-style number-representing strings
+  int i;
+  char *LS, *RS;
+
+  i = InStr(1, TS, ",");
+  if (i != 0)
+  {
+    LS = Left(TS, i - 1);
+    RS = Right(TS, Len(TS) - i);
+    ValEx = Val(CAT(LS, ".", RS));
+  }
+  else
+  {
+    ValEx = Val(TS);
+  }
+
+  return ValEx;
+}
+
+void INC(int *VAR, int Delta)
+{
+  *VAR = *VAR + Delta;
+}
+
+void DEC(int *VAR, int Delta)
+{
+  *VAR = *VAR - Delta;
+}
+
+char *MySplit(char *TS, char *Sep, long SCount)
+{
+  char *MySplit;
+
+  char *T;
+  long i, J, k, q, L, SL;
+  char *RA;
+
+  T = TS;
+  L = Len(TS);
+  SL = Len(Sep);
+  J = SCount;
+  if (J < 1)
+  {
+    J = 0;
+    i = 1;
+    while (i <= L)
+    {
+      k = InStr(i, T, Sep);
+      if (k < i)
+        break;
+
+      if (i < k)
+        J = J + 1;
+
+      i = k + SL;
+    }
+
+    if (i <= L)
+      J = J + 1;
+  }
+
+  if (0 < J)
+    RA = REDIM_1D(sizeof(char), 0, J + 1 - 1);
+  else
+    return MySplit;
+
+  i = 1;
+  q = 0;
+  while (i <= L)
+  {
+    k = InStr(i, T, Sep);
+    if (k < i)
+      break;
+
+    if (i < k)
+    {
+      if (J <= q + 1)
+        break;
+
+      q = q + 1;
+      RA[q] = Mid(T, i, k - i);
+    }
+
+    i = k + SL;
+  }
+
+  if (i <= L)
+  {
+    q = q + 1;
+    T = Right(T, L - i + 1);
+    do
+    {
+      if (Len(T) <= SL)
+        break;
+
+      if (Right(T, SL) == Sep)
+      {
+        T = Left(T, Len(T) - SL);
+      }
+      else
+      {
+        break;
+      }
+    }
+    while (1);
+
+    strcpy(&RA[q], T); // RA(q) = T
+  }
+
+  MySplit = RA;
+
+  return MySplit;
+}
+
+void MyReplace(char *TS, char *Pat1, char *Pat2)
+{
+  long k, SL1, SL2, TL;
+
+  TL = Len(TS);
+  SL1 = Len(Pat1);
+  SL2 = Len(Pat2);
+  k = InStr(1, TS, Pat1);
+  if (k == 0)
+    return;
+
+  do
+  {
+    TS = CAT(Left(TS, k - 1), Pat2, Right(TS, TL - k - SL1 + 1));
+    TL = TL + SL2 - SL1;
+    k = InStr(k + SL2, TS, Pat1);
+  }
+  while (!(k == 0));
+}
+
diff --git a/src/game_sp/GeneralTricks.h b/src/game_sp/GeneralTricks.h
new file mode 100644 (file)
index 0000000..e0ad48f
--- /dev/null
@@ -0,0 +1,21 @@
+// ----------------------------------------------------------------------------
+// GeneralTricks.h
+// ----------------------------------------------------------------------------
+
+#ifndef GENERALTRICKS_H
+#define GENERALTRICKS_H
+
+#include "vb_types.h"
+#include "vb_defs.h"
+#include "vb_vars.h"
+#include "vb_lib.h"
+
+#include "global.h"
+
+extern void DEC(int *VAR, int Delta);
+extern void INC(int *VAR, int Delta);
+extern void MyReplace(char *TS, char *Pat1, char *Pat2);
+extern char *MySplit(char *TS, char *Sep, long SCount);
+extern double ValEx(char *TS);
+
+#endif /* GENERALTRICKS_H */
diff --git a/src/game_sp/Globals.c b/src/game_sp/Globals.c
new file mode 100644 (file)
index 0000000..abba579
--- /dev/null
@@ -0,0 +1,423 @@
+// ----------------------------------------------------------------------------
+// Globals.c
+// ----------------------------------------------------------------------------
+
+#include "Globals.h"
+
+static void ReadDemo();
+void ReadLevel();
+
+static char *VB_Name = "modGlobals";
+// --- Option Explicit
+// --- Option Compare Text
+// --- Option Base 0
+
+// --- const long StretchWidth = 16;
+// --- const long StretchWidth2 = StretchWidth / 2;
+// --- const long BaseWidth = 16;
+// --- const int TwoPixels = 2;
+
+boolean Original;
+boolean Cracked;
+boolean Level_Arg;
+boolean EGA_Arg;
+boolean Record_Fix;
+boolean SpeedKeys;
+boolean Level_Fix;
+boolean Dead_Code;
+boolean Redundant;
+boolean Alignments;
+boolean Ctrl_Alt_Fix;
+boolean Protection;
+boolean EP_ENHANCE;
+boolean EP_DEMO;
+boolean EP_DEBUG;
+boolean EXTRASPEED;
+boolean TIMINGFIX;
+boolean SafeRecord;
+boolean Norm_Time;
+boolean EP_OLD8;
+boolean SAVEGAME;
+boolean HP_DEMO;
+boolean ScreenFix;
+boolean DemoRecordFix;
+boolean DebugSwitch;
+boolean Ver62;
+boolean Ver62test;
+boolean Ver63;
+boolean Ver64;
+
+int LevelNumber;
+char *CurPath, *OrigPath, *TmpPath;
+boolean LevelLoaded;
+long SignatureDelay;
+
+boolean bCapturePane;
+
+int FieldWidth; // = 60
+int FieldHeight; // = 24
+int HeaderSize; // = 96
+int FieldMax, LevelMax;
+long FileMax;
+int *PlayField16;
+byte *PlayField8;
+byte *DisPlayField;
+
+// Public DisplayMin%, DisplayMax%, DisplayWidth%, DisplayHeight%
+
+int TimerVar, RandomSeed;
+currency DeltaT; // Interval between two frames (in ms)
+long DeltaTPlay, DeltaTDemo;
+boolean BlockingSpeed;
+
+// --- const int posFrameCorner = 55;
+// --- const int posFrameVertical = 110;
+// --- const int posFrameHorizontal = 111;
+
+int FreezeZonks;
+
+// constants for  Fixed Fields:
+// --- const int fiSpace = 0; // &H00  space(28 = wall space ...)
+// --- const int fiZonk = 1; // &H01  zonk
+// --- const int fiBase = 2; // &H02  base
+// --- const int fiMurphy = 3; // &H03  Murphy
+// --- const int fiInfotron = 4; // &H04  infotron
+// --- const int fiRAM = 5; // &H05  small RAM chip
+// --- const int fiHardWare = 6; // &H06  hardware (square, standard pyramid shape)
+// --- const int fiExit = 7; // &H07  exit
+// --- const int fiOrangeDisk = 8; // &H08  brown/orange utility disk
+// --- const int fiPortRight = 9; // &H09  port 1 left to right
+// --- const int fiPortDown = 10; // &H0A  port 1 up to down
+// --- const int fiPortLeft = 11; // &H0B  port 1 right to left
+// --- const int fiPortUp = 12; // &H0C  port 1 down to up
+// --- const int fiSpPortRight = 13; // &H0D  port 2 left to right (gravity change)
+// --- const int fiSpPortDown = 14; // &H0E  port 2 up to down     (gravity change)
+// --- const int fiSpPortLeft = 15; // &H0F  port 2 right to left (gravity change)
+// --- const int fiSpPortUp = 16; // &H10  port 2 down to up     (gravity change)
+// --- const int fiSnikSnak = 17; // &H11  snik snak
+// --- const int fiYellowDisk = 18; // &H12  yellow utility disk
+// --- const int fiTerminal = 19; // &H13  terminal
+// --- const int fiRedDisk = 20; // &H14  red utility disk
+// --- const int fiPortUpAndDown = 21; // &H15  vertical port
+// --- const int fiPortLeftAndRight = 22; // &H16  horizontal port
+// --- const int fiPortAllDirections = 23; // &H17  horizontal + vertical port
+// --- const int fiElectron = 24; // &H18  electron
+// --- const int fiBug = 25; // &H19  bug
+// --- const int fiRAMLeft = 26; // &H1A  horizontal RAM chip, left (pin 1)
+// --- const int fiRAMRight = 27; // &H1B  horizontal RAM chip, right
+// --- const int fiHWFirst = 28; // &H1C  hardware (radial blue circular cap + coloured shapes)
+
+// Public Const fiHW1% = 29               '  29 = 1D  hardware (green signal lamp)
+// Public Const fiHW2% = 30               '  30 = 1E  hardware (blue signal lamp)
+// Public Const fiHW3% = 31               '  31 = 1F  hardware (red signal lamp)
+// Public Const fiHW4% = 32               '  32 = 20  hardware (yellow/black diagonal stripes)
+// Public Const fiHW5% = 33               '  33 = 21  hardware (yellow resistor + blue + red shapes)
+// Public Const fiHW6% = 34               '  34 = 22  hardware (horizontal red capacitor + smd shape)
+// Public Const fiHW7% = 35               '  35 = 23  hardware (red + yellow + blue horizontal resistors)
+// Public Const fiHW8% = 36               '  36 = 24  hardware (3 red vertical resistors)
+// --- const int fiHWLast = 37;             //  37 = 25  hardware (3 yellow horizontal resistors)
+// --- const int fiRAMTop = 38;             //  38 = 26  vertical RAM chip, top (pin 1)
+// --- const int fiRAMBottom = 39;          //  39 = 27  vertical RAM chip, bottom
+
+// Specials to experiment with ...
+// --- const int fiWallSpace = 40;          //  40 = 28  invisible wall (can explode, zonks don't roll off)
+// --- const int fiHWTrash1 = 41;           //  41 = 29  hardware trash
+// --- const int fiHWTrash2 = 42;           //  42 = 2A  hardware trash
+// --- const int fiHWMurphy = 43;           //  43 = 2B  hardware inverted Murphy ... (maybe nice for use?)
+
+// --- const int fiExplosion = 0x1F;
+
+// --- const int keyNone = 0;
+// --- const int keyUp = 1;
+// --- const int keyLeft = 2;
+// --- const int keyDown = 3;
+// --- const int keyRight = 4;
+// --- const int keySpaceUp = 5;
+// --- const int keySpaceLeft = 6;
+// --- const int keySpaceDown = 7;
+// --- const int keySpaceRight = 8;
+// --- const int keySpace = 9;
+
+int *aniBug, *aniZonkRollRight, *aniZonkRollLeft;
+int *aniInfotronRollRight, *aniInfotronRollLeft;
+int *aniSnikSnak, *aniElectron, *aniExplosion;
+int *aniTouchBase, *aniTouchInfotron, *aniTouchRedDisk;
+// --- const int aniExplosionInfo = 111;
+// --- const int aniSnikSnakUp = 159;
+// --- const int aniSnikSnakDown = 167;
+// --- const int aniSnikSnakLeft = 239;
+// --- const int aniSnikSnakRight = 247;
+// --- const int aniMurphyYawn = 56;
+// --- const int aniMurphySleepLeft = 71;
+// --- const int aniMurphySleepRight = 68;
+int *aniMurphyExit; // , aniMurphyFaceLeft%, aniMurphyFaceRight%
+int *aniMurphyEatLeft, *aniMurphyEatRight; // , aniMurphyEatRightRedDisk
+int *aniMurphyEatUpLeft, *aniMurphyEatUpRight, *aniSplitUpDown;
+int *aniYellowDisk, *aniOrangeDisk, *aniRedDisk;
+// --- const int aniMurphyTouchUp = 46;
+// --- const int aniMurphyTouchLeft = 95;
+// --- const int aniMurphyTouchDown = 47;
+// --- const int aniMurphyTouchRight = 94;
+int *aniEatInfotronLeft, *aniEatInfotronRight;
+// --- const int aniPushLeft = 45;
+// --- const int aniPushRight = 44;
+// --- const int aniPushUpDown = 79;
+
+void InitGlobals()
+{
+  aniBug = Array(74, 75, 76, 77, 78, 77, 76, 77, 78, 77, 76, 75, 74, 25);
+  aniZonkRollRight = Array(198, 197, 196, 195, 194, 193, 192, 1, -1);
+  aniZonkRollLeft = Array(192, 193, 194, 195, 196, 197, 198, 1, -1);
+  aniInfotronRollRight = Array(206, 205, 204, 203, 202, 201, 200, 4);
+  aniInfotronRollLeft = Array(200, 201, 202, 203, 204, 205, 206, 4);
+  aniSnikSnak = Array(121, 122, 123, 124, 125, 126, 127, 120, 121);
+  aniElectron = Array(144, 145, 146, 147, 148, 149, 150, 151, 144);
+  aniExplosion = Array(3, 103, 104, 105, 106, 107, 108, 109, 0);
+  aniTouchBase = Array(80, 81, 82, 83, 84, 85, 86, 0, -1);
+  aniTouchInfotron = Array(87, 88, 89, 91, 92, 93, 0, -1); // Only seven frames!!!!
+  aniTouchRedDisk = Array(96, 97, 98, 99, 100, 101, 102, 0, -1);
+  aniMurphyExit = Array(46, 46, 46, 46, 47, 47, 47, 47, 48, 48, 48, 48, 49, 49, 49, 49, 50, 50, 50, 50, 51, 51, 51, 51, 52, 52, 52, 52, 53, 53, 53, 53, 54, 54, 54, 54, 0, 0, 0, 0, -1);
+  aniMurphyEatLeft = Array(176, 177, 178, 179, 180, 181, 182, 183, -1);
+  aniMurphyEatRight = Array(184, 185, 186, 187, 188, 189, 190, 191, -1);
+  aniMurphyEatUpLeft = Array(183, 182, 181, 180, 179, 178, 177, 176, -1);
+  aniMurphyEatUpRight = Array(191, 190, 189, 188, 187, 186, 185, 184, -1);
+  // aniMurphyEatRightRedDisk = Array(184, 184, 185, 186, 187, 188, 189, 190, 191, -1) '9 frames!
+  aniEatInfotronLeft = Array(209, 211, 213, 215, 217, 219, 221, 223, -1);
+  aniEatInfotronRight = Array(224, 226, 228, 230, 232, 234, 236, 238, -1);
+  aniSplitUpDown = Array(3, 3, 3, 3, 3, 3, 3, 3, -1);
+  aniYellowDisk = Array(18, 18, 18, 18, 18, 18, 18, 18, -1);
+  aniOrangeDisk = Array(8, 8, 8, 8, 8, 8, 8, 8, -1);
+  aniRedDisk = Array(20, -1);
+  InitPseudoCompileFlags();
+  UserDragFlag = False;
+  AutoScrollFlag = True;
+  FreezeZonks = 0;
+  BlockingSpeed = False;
+  LevelLoaded = False;
+  FieldWidth = 60;
+  FieldHeight = 24;
+  HeaderSize = 96;
+  FieldMax = (FieldWidth * FieldHeight) + HeaderSize - 1;
+  LevelMax = (FieldWidth * FieldHeight) - 1;
+  Let_ModifiedFlag(False);
+  bPlaying = False;
+  gSignature = "";
+  bSignatureAvailable = False;
+  FirstDemoByte = 0x81;
+  MySignature = "";
+  InitErrorReporting();
+}
+
+void InitPseudoCompileFlags()
+{
+  Cracked = 1;       // If protection Then crack it
+  Level_Arg = 1;     // :number is cmd line option
+  // Level_Arg  = 0     ' Remove Level cmd line option
+  EGA_Arg = 1;       // EGA is command line option
+  Record_Fix = 1;      // Assemble with fixed Demo rec
+  SpeedKeys = 0;     // Remove Speed Keys fix
+  Level_Fix = 1;     // Assemble with Level Fix
+  Dead_Code = 0;     // Remove dead code
+  Redundant = 0;     // Remove redundant code
+  Alignments = 1;      // Assemble with alignments
+  Ctrl_Alt_Fix = 1;      // Assemble with Ctrl/Alt fix
+  Protection = 0;      // Remove protection code,do HP
+  // EP added by EP for version 5.
+  EP_ENHANCE = 1;      // Some more nice things (EP)
+  EP_DEMO = 1;       // Use .SP files for demos (EP)
+  // Including record demo!
+  EP_DEBUG = 0;      // little cmdline debugging
+  EXTRASPEED = 1;      // '@' option, superfast!
+  TIMINGFIX = 1;     // "Fixed" the timing problem..
+  // Inactive If DemoRecordFix Then1
+  SafeRecord = 1;      // skip debug keys in recording
+  Norm_Time = 1;     // force automatic speed test,
+  // save result and then do as
+  // requested from cmd line.
+  EP_OLD8 = 1;       // call old int8 from current.
+  SAVEGAME = 1;      // Allow saving to SUPAPLEX.SAV
+  HP_DEMO = 1;       // Use fixed demo routines 5.5
+  ScreenFix = 1;     // No menu-write to gamy field
+  DemoRecordFix = 1;     // Demo record timing fix on
+  DebugSwitch = 1;     // Allow Ctrl/Alt-ScrollLock
+  Ver62 = 1;       // Version 6.2 stuff
+  Ver62test = 0;     // Version 6.2 test stuff
+  Ver63 = 1;       // Version 6.3 stuff
+  Ver64 = 1;       // Version 6.4 stuff
+
+}
+
+int GetSI(int X, int Y)
+{
+  int GetSI;
+
+  GetSI = Y * FieldWidth + X;
+
+  return GetSI;
+}
+
+int GetX(int si)
+{
+  int GetX;
+
+  GetX = si % FieldWidth;
+
+  return GetX;
+}
+
+int GetY(int si)
+{
+  int GetY;
+
+  GetY = si / FieldWidth;
+
+  return GetY;
+}
+
+int GetStretchX(int si)
+{
+  int GetStretchX;
+
+  GetStretchX = StretchWidth * (si % FieldWidth);
+
+  return GetStretchX;
+}
+
+int GetStretchY(int si)
+{
+  int GetStretchY;
+
+  GetStretchY = StretchWidth * (si / FieldWidth);
+
+  return GetStretchY;
+}
+
+void ReadLevel()
+{
+  // int FNum;
+  FILE *FNum;
+  long i;
+  // byte T;
+
+  DemoAvailable = False;
+  if (STRING_IS_LIKE(CurPath, "*.mpx"))
+  {
+    ReadMPX();
+    return;
+  }
+
+  if (STRING_IS_LIKE(CurPath, "*.sp"))
+  {
+    ReadDemo();
+    return;
+  }
+
+  if (DemoFlag != 0)
+  {
+    ReadDemo();
+    return;
+  }
+
+  FileMax = 0;
+  FieldWidth = 60;
+  FieldHeight = 24;
+  HeaderSize = 96;
+  FieldMax = (FieldWidth * FieldHeight) + HeaderSize - 1;
+  LevelMax = (FieldWidth * FieldHeight) - 1;
+  PlayField8 = REDIM_1D(sizeof(byte), 0, FieldMax + 1 - 1);
+  DisPlayField = REDIM_1D(sizeof(byte), 0, FieldMax + 1 - 1);
+  // FNum = FreeFile();
+
+  // --- On Error GoTo ReadLevelEH
+  FNum = fopen(CurPath, "rb");
+  i = (LevelNumber - 1) * ((long)(FieldMax) + 1) + 1;
+  FILE_GET(FNum, i, &PlayField8, sizeof(PlayField8));
+  i = (LevelNumber) * ((long)(FieldMax) + 1) + 1 - HeaderSize;
+  FILE_GET(FNum, i, &LInfo, sizeof(LInfo)); // store level info in an extra structure
+  fclose(FNum);
+  // --- On Error GoTo 0
+
+  if (FieldMax < FileMax)
+    DemoAvailable = True;
+
+  ReadSignature();
+  PlayField16 = REDIM_1D(sizeof(int), -FieldWidth, FieldMax);
+  for (i = 0; i <= FieldMax; i++)
+  {
+    PlayField16[i] = PlayField8[i];
+    DisPlayField[i] = PlayField8[i];
+    PlayField8[i] = 0;
+  }
+
+  AnimationPosTable = REDIM_1D(sizeof(int), 0, LevelMax - 2 *FieldWidth);
+  AnimationSubTable = REDIM_1D(sizeof(byte), 0, LevelMax - 2 *FieldWidth);
+  TerminalState = REDIM_1D(sizeof(byte), FieldWidth, LevelMax - FieldWidth);
+  GravityFlag = LInfo.InitialGravity;
+  FreezeZonks = LInfo.InitialFreezeZonks;
+  subRandomize();
+  LevelLoaded = True;
+  return;
+
+#if 0
+ReadLevelEH:
+  Close();
+#endif
+}
+
+static void ReadDemo()
+{
+  // int FNum, i;
+  FILE *FNum;
+  int i;
+  // byte T;
+
+  FieldWidth = 60;
+  FieldHeight = 24;
+  HeaderSize = 96;
+  FieldMax = (FieldWidth * FieldHeight) + HeaderSize - 1;
+  LevelMax = (FieldWidth * FieldHeight) - 1;
+
+  // --- On Error GoTo ReadDemoEH
+  FileMax = FileLen(CurPath) - 1;
+  PlayField8 = REDIM_1D(sizeof(byte), 0, FileMax + 1 - 1);
+  DisPlayField = REDIM_1D(sizeof(byte), 0, FieldMax + 1 - 1);
+  // FNum = FreeFile();
+  FNum = fopen(CurPath, "rb");
+  i = (LevelNumber - 1) * ((long)(FieldMax) + 1) + 1;
+  FILE_GET(FNum, i, &PlayField8, sizeof(PlayField8));
+  i = (LevelNumber) * ((long)(FieldMax) + 1) + 1 - HeaderSize;
+  FILE_GET(FNum, i, &LInfo, sizeof(LInfo)); // store level info in an extra structure
+  fclose(FNum);
+  // --- On Error GoTo 0
+
+  if (FieldMax < FileMax)
+    DemoAvailable = True;
+
+  ReadSignature();
+  PlayField16 = REDIM_1D(sizeof(int), -FieldWidth, FieldMax);
+  for (i = 0; i <= FieldMax; i++)
+  {
+    PlayField16[i] = PlayField8[i];
+    DisPlayField[i] = PlayField8[i];
+    PlayField8[i] = 0;
+  }
+
+  AnimationPosTable = REDIM_1D(sizeof(int), 0, LevelMax - 2 *FieldWidth);
+  AnimationSubTable = REDIM_1D(sizeof(byte), 0, LevelMax - 2 *FieldWidth);
+  TerminalState = REDIM_1D(sizeof(byte), 0, FieldMax + 1 - 1);
+  DemoPointer = FieldMax + 1;
+  DemoOffset = DemoPointer;
+  DemoKeyRepeatCounter = 0;
+  // DemoFlag = 1
+  // DemoAvailable = True
+  GravityFlag = LInfo.InitialGravity;
+  FreezeZonks = LInfo.InitialFreezeZonks;
+  RandomSeed = LInfo.DemoRandomSeed;
+  LevelLoaded = True;
+  return;
+
+#if 0
+ReadDemoEH:
+  Close();
+#endif
+}
diff --git a/src/game_sp/Globals.h b/src/game_sp/Globals.h
new file mode 100644 (file)
index 0000000..64f3230
--- /dev/null
@@ -0,0 +1,152 @@
+// ----------------------------------------------------------------------------
+// Globals.h
+// ----------------------------------------------------------------------------
+
+#ifndef GLOBALS_H
+#define GLOBALS_H
+
+#include "vb_types.h"
+#include "vb_defs.h"
+#include "vb_vars.h"
+#include "vb_lib.h"
+
+#include "global.h"
+
+#define BaseWidth                      (16)
+#define StretchWidth                   (16)
+#define StretchWidth2                  (StretchWidth / 2)
+#define TwoPixels                      (2)
+#define aniExplosionInfo                       (111)
+#define aniMurphySleepLeft                     (71)
+#define aniMurphySleepRight                    (68)
+#define aniMurphyTouchDown                     (47)
+#define aniMurphyTouchLeft                     (95)
+#define aniMurphyTouchRight                    (94)
+#define aniMurphyTouchUp                       (46)
+#define aniMurphyYawn                  (56)
+#define aniPushLeft                    (45)
+#define aniPushRight                   (44)
+#define aniPushUpDown                  (79)
+#define aniSnikSnakDown                        (167)
+#define aniSnikSnakLeft                        (239)
+#define aniSnikSnakRight                       (247)
+#define aniSnikSnakUp                  (159)
+#define fiBase                         (2)
+#define fiBug                  (25)
+#define fiElectron                     (24)
+#define fiExit                         (7)
+#define fiExplosion                    (0x1F)
+#define fiHWFirst                      (28)
+#define fiHWLast                       (37)
+#define fiHWMurphy                     (43)
+#define fiHWTrash1                     (41)
+#define fiHWTrash2                     (42)
+#define fiHardWare                     (6)
+#define fiInfotron                     (4)
+#define fiMurphy                       (3)
+#define fiOrangeDisk                   (8)
+#define fiPortAllDirections                    (23)
+#define fiPortDown                     (10)
+#define fiPortLeft                     (11)
+#define fiPortLeftAndRight                     (22)
+#define fiPortRight                    (9)
+#define fiPortUp                       (12)
+#define fiPortUpAndDown                        (21)
+#define fiRAM                  (5)
+#define fiRAMBottom                    (39)
+#define fiRAMLeft                      (26)
+#define fiRAMRight                     (27)
+#define fiRAMTop                       (38)
+#define fiRedDisk                      (20)
+#define fiSnikSnak                     (17)
+#define fiSpPortDown                   (14)
+#define fiSpPortLeft                   (15)
+#define fiSpPortRight                  (13)
+#define fiSpPortUp                     (16)
+#define fiSpace                        (0)
+#define fiTerminal                     (19)
+#define fiWallSpace                    (40)
+#define fiYellowDisk                   (18)
+#define fiZonk                         (1)
+#define keyDown                        (3)
+#define keyLeft                        (2)
+#define keyNone                        (0)
+#define keyRight                       (4)
+#define keySpace                       (9)
+#define keySpaceDown                   (7)
+#define keySpaceLeft                   (6)
+#define keySpaceRight                  (8)
+#define keySpaceUp                     (5)
+#define keyUp                  (1)
+#define posFrameCorner                         (55)
+#define posFrameHorizontal                     (111)
+#define posFrameVertical                       (110)
+
+extern int GetSI(int X, int Y);
+extern int GetStretchX(int si);
+extern int GetStretchY(int si);
+extern int GetX(int si);
+extern int GetY(int si);
+extern void InitGlobals();
+extern void InitPseudoCompileFlags();
+
+extern void ReadLevel();
+
+extern boolean Alignments;
+extern boolean BlockingSpeed;
+extern boolean Cracked;
+extern boolean Ctrl_Alt_Fix;
+extern boolean Dead_Code;
+extern boolean DebugSwitch;
+extern boolean DemoRecordFix;
+extern boolean EGA_Arg;
+extern boolean EP_DEBUG;
+extern boolean EP_DEMO;
+extern boolean EP_ENHANCE;
+extern boolean EP_OLD8;
+extern boolean EXTRASPEED;
+extern boolean HP_DEMO;
+extern boolean LevelLoaded;
+extern boolean Level_Arg;
+extern boolean Level_Fix;
+extern boolean Norm_Time;
+extern boolean Original;
+extern boolean Protection;
+extern boolean Record_Fix;
+extern boolean Redundant;
+extern boolean SAVEGAME;
+extern boolean SafeRecord;
+extern boolean ScreenFix;
+extern boolean SpeedKeys;
+extern boolean TIMINGFIX;
+extern boolean Ver62;
+extern boolean Ver62test;
+extern boolean Ver63;
+extern boolean Ver64;
+extern boolean bCapturePane;
+extern byte *DisPlayField;
+extern byte *PlayField8;
+extern char *CurPath, *OrigPath, *TmpPath;
+extern currency DeltaT;
+extern int *PlayField16;
+extern int *aniBug, *aniZonkRollRight, *aniZonkRollLeft;
+extern int *aniEatInfotronLeft, *aniEatInfotronRight;
+extern int *aniInfotronRollRight, *aniInfotronRollLeft;
+extern int *aniMurphyEatLeft, *aniMurphyEatRight;
+extern int *aniMurphyEatUpLeft, *aniMurphyEatUpRight, *aniSplitUpDown;
+extern int *aniMurphyExit;
+extern int *aniSnikSnak, *aniElectron, *aniExplosion;
+extern int *aniTouchBase, *aniTouchInfotron, *aniTouchRedDisk;
+extern int *aniYellowDisk, *aniOrangeDisk, *aniRedDisk;
+extern int FieldHeight;
+extern int FieldMax, LevelMax;
+extern int FieldWidth;
+extern int FreezeZonks;
+extern int HeaderSize;
+extern int LevelNumber;
+extern int TimerVar, RandomSeed;
+extern long DeltaTPlay, DeltaTDemo;
+extern long FileMax;
+extern long SignatureDelay;
+
+#endif /* GLOBALS_H */
diff --git a/src/game_sp/Infotrons.c b/src/game_sp/Infotrons.c
new file mode 100644 (file)
index 0000000..bcede9d
--- /dev/null
@@ -0,0 +1,449 @@
+// ----------------------------------------------------------------------------
+// Infotrons.c
+// ----------------------------------------------------------------------------
+
+#include "Infotrons.h"
+
+static char *VB_Name = "modInfotron";
+// --- Option Explicit
+
+// ==========================================================================
+//                              SUBROUTINE
+// Animate Infotrons (falling)
+// ==========================================================================
+
+int subAnimateInfotrons(int si)
+{
+  int subAnimateInfotrons;
+
+  int tFld;
+
+  // PseudoRegisters:
+  int ax, bx, cx, dx, di, X, Y;
+  int ah, bh, ch, dh, al, bl, cl, dl;
+
+  tFld = PlayField16[si];
+  if ((tFld & 0xFF) != fiInfotron)
+    return subAnimateInfotrons;
+
+  if (tFld == fiInfotron)
+  {
+    ax = PlayField16[si + FieldWidth]; // select case playfield16(si+60)
+    if (ax == 0)
+      goto loc_g_11D5;
+
+    if (ax == fiZonk)
+      goto loc_g_11A6;
+
+    if (ax == fiInfotron)
+      goto loc_g_11A6;
+
+    if (ax == fiRAM)
+      goto loc_g_11A6;
+
+    return subAnimateInfotrons;
+
+loc_g_11A6: //        Case fiZonk, fiInfotron, fiRAM
+    ax = PlayField16[si + FieldWidth - 1];
+    if (ax == 0 || ax == 0x8888 || ax == 0xAAAA)
+      goto loc_g_11DC;
+
+loc_g_11BD:
+    ax = PlayField16[si + FieldWidth + 1];
+    if (ax == 0 || ax == 0x8888 || ax == 0xAAAA)
+      goto loc_g_11F2;
+
+    return subAnimateInfotrons;
+
+loc_g_11D5: //       Case fiSpace
+    MovHighByte(&PlayField16[si], 0x40);
+    goto loc_g_1207;
+
+loc_g_11DC: // roll left?
+    if (PlayField16[si - 1] == 0)
+      goto loc_g_11E5;
+
+    goto loc_g_11BD;
+
+loc_g_11E5:
+    MovHighByte(&PlayField16[si], 0x50);
+    PlayField16[si - 1] = 0x8888;
+    goto loc_g_1207;
+
+loc_g_11F2: // roll right?
+    if (PlayField16[si + 1] == 0)
+      goto loc_g_11FA;
+
+    return subAnimateInfotrons;
+
+loc_g_11FA:
+    MovHighByte(&PlayField16[si], 0x60);
+    PlayField16[si + 1] = 0x8888;
+  } // tFld = fiInfotron
+
+loc_g_1207:
+  // from now on the infotron is definitely moving,
+  // maybe the sequence is in an advanced frame
+  // or just beeing initialized due to the code above
+  bl = HighByte(PlayField16[si]);
+  bx = 0;
+  MovLowByte(&bx, bl);
+  al = bl & 0xF0;
+  if (al == 0x10) // infotron comes falling from above
+    goto loc_g_1242;
+
+  if (al == 0x20) // infotron comes rolling from right to left
+    goto loc_g_138D;
+
+  if (al == 0x30) // infotron comes rolling from left to right
+    goto loc_g_13E9;
+
+  if (al == 0x40) // infotron falls straight down
+    goto loc_g_1444;
+
+  if (al == 0x50) // infotron rolls left
+    goto loc_g_1472;
+
+  if (al == 0x60) // infotron rolls right
+    goto loc_g_14E0;
+
+  if (al == 0x70) // intermediate state
+    goto loc_g_154E;
+
+  return subAnimateInfotrons;
+
+loc_g_1242: // infotron comes falling from above
+  //      To Do: draw infotron falling from above
+  //      according to position in (bl And &H07)
+  // +++++++++++++++++++++++++++++++++++++++++++++++++++++
+  X = GetStretchX(si);
+  Y = GetStretchY(si - FieldWidth);
+  dx = bl & 0x7;
+  StretchedSprites.BltEx(X, Y, 0);
+  StretchedSprites.BltEx(X, Y + TwoPixels * (dx + 1), fiInfotron);
+  // +++++++++++++++++++++++++++++++++++++++++++++++++++++
+  bl = HighByte(PlayField16[si]) + 1;
+  if (bl == 0x16)
+  {
+    MovHighByte(&PlayField16[si], bl);
+    subCleanUpForInfotronsAbove(si - FieldWidth);
+    return subAnimateInfotrons;
+  } // loc_g_1285:
+
+  if (bl < 0x18)
+  {
+    MovHighByte(&PlayField16[si], bl);
+    return subAnimateInfotrons;
+  } // loc_g_128F:
+
+  MovHighByte(&PlayField16[si], 0); // infotron arrived at the field
+
+  // now check if the zonk may go on falling somehow
+  ax = PlayField16[si + FieldWidth];
+  if (ax == 0) // below is empty!-> go on falling
+    goto loc_g_132D;
+
+  if (ax == 0x9999) // below is only temporarily used
+    goto loc_g_132D;
+
+  if ((ax & 0xFF) == fiMurphy) // Murphy dies
+    goto loc_g_1364;
+
+  if (ax == fiRedDisk) // red disk hit
+    goto loc_g_1386;
+
+  if ((ax & 0xFF) == fiSnikSnak) // SnikSnak dies
+    goto loc_g_1386;
+
+
+  if ((ax & 0xFF) == fiElectron) // Electron cracked!
+    goto loc_g_1386;
+
+  if (ax == fiYellowDisk) // yellow disk hit
+    goto loc_g_1386;
+
+  if (ax == fiOrangeDisk) // orange disk hit
+    goto loc_g_1386;
+
+  subSoundFXZonk(); // play the zonk sound,'cause zonk hits something "hard"
+
+  if (! (ax == fiZonk || ax == fiInfotron || ax == fiRAM))
+    return subAnimateInfotrons;
+
+  // infotron rolls somewhere
+  ax = PlayField16[si + FieldWidth - 1];
+  if (ax == 0 || ax == 0x8888 || ax == 0xAAAA) // may roll left
+    goto loc_g_133A;
+
+  ax = PlayField16[si + FieldWidth + 1];
+  if (ax == 0 || ax == 0x8888 || ax == 0xAAAA) // may roll right
+    goto loc_g_1350;
+
+  return subAnimateInfotrons;
+
+loc_g_132D:     // go on falling down?
+  PlayField16[si] = 0x7004; // go into intermediate waitstate
+  PlayField16[si + FieldWidth] = 0x9999; // mark as "zonk waiting to access"
+  return subAnimateInfotrons;
+
+loc_g_133A:     // test if infotron may roll left
+  // This if(if true) jumps up far above
+  // to the according rountine for fixed infotrons!
+  if (PlayField16[si - 1] != 0) // Remarkable!!! ' loc_g_0EF4:
+    goto loc_g_11BD;
+
+  MovHighByte(&PlayField16[si], 0x50); // infotron rolls left
+  Mov(&PlayField16[si - 1], 0x8888);
+  return subAnimateInfotrons;
+
+loc_g_1350:     // test if infotron may roll right
+  if (PlayField16[si + 1] != 0)
+    return subAnimateInfotrons;
+
+  MovHighByte(&PlayField16[si], 0x60); // infotron rolls right
+  Mov(&PlayField16[si + 1], 0x8888);
+  return subAnimateInfotrons;
+
+loc_g_1364:     // Murphy dies, but not in any case
+  bl = HighByte(PlayField16[si + FieldWidth]);
+  if (bl == 0xE || bl == 0xF || bl == 0x28)
+    return subAnimateInfotrons;
+
+  if (bl == 0x29 || bl == 0x25 || bl == 0x26)
+    return subAnimateInfotrons;
+
+
+
+
+
+
+
+
+
+
+
+loc_g_1386:     // someone dies/explodes immediately
+  si = si + FieldWidth;                 // 1 field down
+  ExplodeFieldSP(si);               // Explode
+  return subAnimateInfotrons;
+
+
+
+
+
+loc_g_138D: // infotron comes rolling from right to left
+  //  To Do: draw infotron rolling from right
+  //  according to position in (bl And &H07)
+  // +++++++++++++++++++++++++++++++++++++++++++++++++++++
+  X = GetStretchX(si + 1);
+  Y = GetStretchY(si);
+  dx = (bl & 0x7) + 1;
+  StretchedSprites.BltEx(X, Y, 0);
+  StretchedSprites.BltEx(X - (TwoPixels * dx), Y, aniInfotronRollLeft[dx - 1]);
+  // +++++++++++++++++++++++++++++++++++++++++++++++++++++
+  bl = HighByte(PlayField16[si]) + 1; // get and increment sequence#
+  if (bl == 0x24)
+    PlayField16[si + 1] = 0xAAAA;
+
+  if (bl == 0x26)
+  {
+    MovHighByte(&PlayField16[si], bl);
+    subCleanUpForInfotronsAbove(si + 1);
+  }
+  else if (bl < 0x28)
+  {
+    MovHighByte(&PlayField16[si], bl);
+  }
+  else
+  {
+    PlayField16[si] = 0x7004; // go into intermediate state
+  }
+
+  return subAnimateInfotrons;
+
+loc_g_13E9: // infotron comes rolling from left to right
+  //  To Do: draw infotron rolling from left
+  //  according to position in (bl And &H07)
+  // +++++++++++++++++++++++++++++++++++++++++++++++++++++
+  X = GetStretchX(si - 1);
+  Y = GetStretchY(si);
+  dx = (bl & 0x7) + 1;
+  StretchedSprites.BltEx(X, Y, 0);
+  StretchedSprites.BltEx(X + (TwoPixels * dx), Y, aniInfotronRollRight[dx - 1]);
+  // +++++++++++++++++++++++++++++++++++++++++++++++++++++
+  bl = HighByte(PlayField16[si]) + 1;
+  if (bl == 0x34)
+    PlayField16[si - 1] = 0xAAAA;
+
+  if (bl == 0x36)
+  {
+    MovHighByte(&PlayField16[si], bl);
+    subCleanUpForInfotronsAbove(si - 1);
+  }
+  else if (bl < 0x38)
+  {
+    MovHighByte(&PlayField16[si], bl);
+  }
+  else
+  {
+    PlayField16[si] = 0x7004; // go into intermediate state
+  }
+
+  return subAnimateInfotrons;
+
+loc_g_1444: // infotron falls straight down
+  bl = bl + 1;
+  if (bl < 0x42)
+  {
+    MovHighByte(&PlayField16[si], bl);
+  }
+  else if (PlayField16[si + FieldWidth] != 0)
+  {
+    bl = bl - 1; // stay waiting
+    MovHighByte(&PlayField16[si], bl);
+  }
+  else
+  {
+    PlayField16[si] = 0xFFFF;
+    si = si + FieldWidth;                 // 1 field down
+    PlayField16[si] = 0x1004; // go falling
+  }
+
+  return subAnimateInfotrons;
+
+loc_g_1472: // infotron rolls left
+  //  To Do: draw infotron rolling to left
+  //  according to position in (bl And &H0F)
+  // +++++++++++++++++++++++++++++++++++++++++++++++++++++
+  X = GetStretchX(si);
+  Y = GetStretchY(si);
+  dx = (bl & 0xF) + 1;
+  StretchedSprites.BltEx(X, Y, 0);
+  StretchedSprites.BltEx(X - (TwoPixels * dx), Y, aniInfotronRollLeft[dx - 1]);
+  // +++++++++++++++++++++++++++++++++++++++++++++++++++++
+  bl = HighByte(PlayField16[si]) + 1; // retrieve and increment sequence#
+  if (bl < 0x52)
+  {
+    MovHighByte(&PlayField16[si], bl);
+    return subAnimateInfotrons;
+  }
+
+  if (PlayField16[si + FieldWidth - 1] != 0)
+    goto loc_g_14D9;
+
+  if (PlayField16[si - 1] != 0)
+  {
+    if (PlayField16[si - 1] != 0x8888)
+      goto loc_g_14D9;
+  }
+
+  PlayField16[si] = 0xFFFF;
+  si = si - 1;                   // 1 field left
+  PlayField16[si] = 0x2204;
+  PlayField16[si + FieldWidth] = 0x9999;
+  return subAnimateInfotrons;
+
+loc_g_14D9: // stay waiting
+  bl = bl - 1;
+  MovHighByte(&PlayField16[si], bl);
+  return subAnimateInfotrons;
+
+loc_g_14E0: // infotron rolls right
+  //  To Do: draw infotron rolling to right
+  //  according to position in (bl And &H07)
+  // +++++++++++++++++++++++++++++++++++++++++++++++++++++
+  X = GetStretchX(si);
+  Y = GetStretchY(si);
+  dx = (bl & 0x7) + 1;
+  StretchedSprites.BltEx(X, Y, 0);
+  StretchedSprites.BltEx(X + (TwoPixels * dx), Y, aniInfotronRollRight[dx - 1]);
+  // +++++++++++++++++++++++++++++++++++++++++++++++++++++
+  bl = HighByte(PlayField16[si]) + 1;
+  if (bl < 0x62)
+  {
+    MovHighByte(&PlayField16[si], bl);
+    return subAnimateInfotrons;
+  }
+
+  if (PlayField16[si + FieldWidth + 1] != 0)
+    goto loc_g_1547;
+
+  if (PlayField16[si + 1] != 0)
+  {
+    if (PlayField16[si + 1] != 0x8888)
+      goto loc_g_1547;
+  }
+
+  PlayField16[si] = 0xFFFF;
+  si = si + 1;
+  PlayField16[si] = 0x3204;
+  PlayField16[si + FieldWidth] = 0x9999;
+  return subAnimateInfotrons;
+
+loc_g_1547: // stay waiting
+  bl = bl - 1;
+  MovHighByte(&PlayField16[si], bl);
+  return subAnimateInfotrons;
+
+loc_g_154E: // intermediate state
+  ax = PlayField16[si + FieldWidth];
+  if (ax == 0 || ax == 0x9999)
+  {
+    PlayField16[si] = 0xFFFF;
+    si = si + FieldWidth;                 // 1 field down
+    PlayField16[si] = 0x1004; // start falling down
+    goto loc_g_1242;
+  }
+
+  return subAnimateInfotrons;
+} // subAnimateInfotrons
+
+int subCleanUpForInfotronsAbove(int si)
+{
+  int subCleanUpForInfotronsAbove;
+
+  int ax;
+
+  if (LowByte(PlayField16[si]) != fiExplosion)
+    PlayField16[si] = 0;
+
+  if (PlayField16[si - FieldWidth] != 0)
+  {
+    if (PlayField16[si - FieldWidth] != 0x9999)
+      return subCleanUpForInfotronsAbove;
+
+    if (LowByte(PlayField16[si - 2 * FieldWidth]) != fiZonk)
+      return subCleanUpForInfotronsAbove;
+  }
+
+  if (PlayField16[si - FieldWidth - 1] == fiInfotron)
+    goto loc_g_16FE;
+
+loc_g_16F6:
+  if (PlayField16[si - FieldWidth + 1] == fiInfotron)
+    goto loc_g_1722;
+
+  return subCleanUpForInfotronsAbove;
+
+loc_g_16FE:
+  ax = PlayField16[si - 1];
+  if (ax == fiZonk || ax == fiInfotron || ax == fiRAM)
+  {
+    PlayField16[si - FieldWidth - 1] = 0x6004;
+    PlayField16[si - FieldWidth] = 0x8888;
+    return subCleanUpForInfotronsAbove;
+  }
+
+  goto loc_g_16F6;
+
+loc_g_1722:
+  ax = PlayField16[si + 1];
+  if (ax == fiZonk || ax == fiInfotron || ax == fiRAM)
+  {
+    PlayField16[si - FieldWidth + 1] = 0x5004;
+    PlayField16[si - FieldWidth] = 0x8888;
+  }
+
+  return subCleanUpForInfotronsAbove;
+} // subCleanUpForInfotronsAbove
+
diff --git a/src/game_sp/Infotrons.h b/src/game_sp/Infotrons.h
new file mode 100644 (file)
index 0000000..7bce759
--- /dev/null
@@ -0,0 +1,18 @@
+// ----------------------------------------------------------------------------
+// Infotrons.h
+// ----------------------------------------------------------------------------
+
+#ifndef INFOTRONS_H
+#define INFOTRONS_H
+
+#include "vb_types.h"
+#include "vb_defs.h"
+#include "vb_vars.h"
+#include "vb_lib.h"
+
+#include "global.h"
+
+extern int subAnimateInfotrons(int si);
+extern int subCleanUpForInfotronsAbove(int si);
+
+#endif /* INFOTRONS_H */
diff --git a/src/game_sp/InitGameConditions.c b/src/game_sp/InitGameConditions.c
new file mode 100644 (file)
index 0000000..f1c0f2e
--- /dev/null
@@ -0,0 +1,370 @@
+// ----------------------------------------------------------------------------
+// InitGameConditions.c
+// ----------------------------------------------------------------------------
+
+#include "InitGameConditions.h"
+
+static char *VB_Name = "modInitGameConditions";
+// --- Option Explicit
+
+// ==========================================================================
+//                              SUBROUTINE
+// Init game conditions (variables)
+// ==========================================================================
+
+int subInitGameConditions()
+{
+  int subInitGameConditions;
+
+  bCapturePane = False;
+
+  MurphyVar0DAC = MurphyYPos;
+  MurphyVar0DAE = MurphyXPos;
+  MurphyVarFaceLeft = 0;
+  KillMurphyFlag = 0;            // no "kill Murphy"
+  ExitToMenuFlag = 0;
+  LeadOutCounter = 0;           // quit flag: lead-out counter
+  RedDiskCount = 0; // Red disk counter
+  ShowRedDiskCounter = 0; // show-red-disk time-out
+
+  YawnSleepCounter = 0; // Wake up sleeping Murphy
+
+  data_h_0DA7 = 0xFF;
+  data_h_0DA8 = 0xFF;
+  data_h_0DA9 = 0xFF;
+  data_h_0D9E = 1;
+  data_h_0D9F = 0;
+  data_h_0DA0 = 0;
+  data_h_0DA1 = 0;
+  data_h_0DA2 = 0;
+  data_h_0DA4 = 0;
+  data_h_0DA5 = 0;
+  data_h_0DA6 = 0;
+
+  ExplosionShake = 0; // Force explosion flag off
+
+  TerminalMaxCycles = 0x7F;
+  YellowDisksExploded = 0;
+
+  TimerVar = 0;
+  // ShowPanel = 1 ' Force Panel on
+  // MainForm.PanelVisible = True;
+  EnterRepeatCounter = 0; // restart Enter repeat counter
+  SnikSnaksElectronsFrozen = 0; // Snik-Snaks and Electr. move!
+
+  SplitMoveFlag = 0; // Reset Split-through-ports
+  RedDiskReleasePhase = 0; // (re-)enable red disk release
+  RedDiskReleaseMurphyPos = 0; // Red disk was released here
+
+
+  return subInitGameConditions;
+} // subInitGameConditions
+
+
+// ==========================================================================
+//                              SUBROUTINE
+// Locate Murphy and init location.
+// ==========================================================================
+
+int InitMurphyPos()
+{
+  int InitMurphyPos;
+
+  int si;
+
+  for (si = 0; si <= LevelMax - 1; si++)
+  {
+    if (PlayField16[si] == fiMurphy)
+      break;
+  }
+
+  InitMurphyPosB(si);
+  MurphyPosIndex = si;
+
+  return InitMurphyPos;
+} // InitMurphyPos
+
+int InitMurphyPosB(int si)
+{
+  int InitMurphyPosB;
+
+  MurphyYPos = GetStretchY(si) / Stretch;
+  MurphyXPos = GetStretchX(si) / Stretch;
+
+  MurphyScreenXPos = GetStretchX(si);          // Murphy's screen x-position
+  MurphyScreenYPos = GetStretchY(si);         // Murphy's screen y-position
+
+  // To Do: draw Murphy in location ax
+  StretchedSprites.BltEx(MurphyScreenXPos, MurphyScreenYPos, fiMurphy);
+
+  MurphyScreenXPos = MurphyScreenXPos / Stretch;
+  MurphyScreenYPos = MurphyScreenYPos / Stretch;
+
+  subCalculateScreenScrollPos();           // calculate screen start addrs
+  if (AutoScrollFlag)
+  {
+    if (bPlaying)
+    {
+      SoftScrollTo(ScreenScrollXPos, ScreenScrollYPos, 1000, 25);
+    }
+    else
+    {
+      ScrollTo(ScreenScrollXPos, ScreenScrollYPos);
+    }
+  }
+
+  return InitMurphyPosB;
+} // InitMurphyPosB
+
+// ==========================================================================
+//                              SUBROUTINE
+// Convert to easy symbols and reset Infotron count If not ThenVer62
+// ==========================================================================
+
+int subConvertToEasySymbols()
+{
+  int subConvertToEasySymbols;
+
+  int ax, bx, cx, dx, di, X, Y, i;
+  int ah, bh, ch, dh, al, bl, cl, dl, ZF;
+
+  bx = 0;
+  dx = 0;
+  cx = LevelMax + 1;
+  i = 0;
+
+loc_g_26C9:
+  ax = PlayField16[i];
+  al = LowByte(ax);
+  if (al == 0xF1) // converted explosion?
+  {
+    MovLowByte(&PlayField16[i], 0x1F);      // restore explosions
+    goto loc_g_2778;
+  }
+
+  if (LowByte(GameBusyFlag) != 1) // free screen write?
+  {
+    if (ax == fiInfotron) // Infotron? -> yes--count!
+      goto loc_g_2704;
+
+    if (ax == fiSnikSnak) // Snik Snak? -> yes--rearrange
+      goto loc_g_2713;
+
+    if (ax == fiElectron) // Electron? -> yes--rearrange
+      goto loc_g_2741;
+  }
+
+  // test for fancy RAM Chips:
+  if (ax == fiRAMLeft || ax == fiRAMRight)
+    goto loc_g_2707;
+
+  if (ax == fiRAMTop || ax == fiRAMBottom)
+    goto loc_g_2707;
+
+  if (ax < fiHWFirst) // All but deco hardware?
+    goto loc_g_26F8;
+
+  if (ax < fiRAMTop) // Decorative hardware?
+    goto loc_g_270D;
+
+loc_g_26F8:
+  if (ax < fiSpPortRight) // Gravity change ports only?
+    goto loc_g_2778;
+
+  if (ax < fiSnikSnak) // Gravity change port! 'loc_g_2702:
+    goto loc_g_276F;
+
+  goto loc_g_2778;
+
+loc_g_2704:                                     // INFOTRON
+  dx = dx + 1;                      // Count Infotrons
+  goto loc_g_2778;
+
+loc_g_2707:                                     // DECO RAM CHIPS
+  PlayField16[i] = fiRAM; // Convert to standard RAM chip
+  goto loc_g_2778;
+
+loc_g_270D:                                     // DECO HARDWARE
+  PlayField16[i] = fiHardWare; // Convert to standard hardware
+  goto loc_g_2778;
+
+loc_g_2713:                                     // SNIK-SNAK
+  if (PlayField16[i - 1] != 0) // 1 field left empty? -> no--try up
+    goto loc_g_271F;
+
+  MovHighByte(&PlayField16[i], 1); // turn left, step = NorthWest
+  goto loc_g_2778;
+
+loc_g_271F:
+  if (PlayField16[i - FieldWidth] != 0) // 1 field up empty? -> no--try right
+    goto loc_g_2730;
+
+  PlayField16[i - FieldWidth] = 0x1011; // SnikSnak accessing from below, step = 0
+  PlayField16[i] = 0xFFFF;
+  goto loc_g_2778;
+
+loc_g_2730:
+  if (PlayField16[i + 1] != 0) // 1 field right empty? -> point up
+    goto loc_g_2778;
+
+  PlayField16[i + 1] = 0x2811; // SnikSnak accessing from left, step = 0
+  PlayField16[i] = 0xFFFF;
+  goto loc_g_2778;
+
+loc_g_2741:                                     // ELECTRON
+  if (PlayField16[i - 1] != 0) // 1 field left empty? -> no--try up
+    goto loc_g_274D;
+
+  MovHighByte(&PlayField16[i], 1);
+  goto loc_g_2778;
+
+loc_g_274D:
+  if (PlayField16[i - FieldWidth] != 0) // 1 field up empty? -> no--try right
+    goto loc_g_275E;
+
+  PlayField16[i - FieldWidth] = 0x1018; // 1 field up
+  PlayField16[i] = 0xFFFF;
+  goto loc_g_2778;
+
+loc_g_275E:
+  if (PlayField16[i + 1] != 0) // 1 field right empty? -> no--point down
+    goto loc_g_2778;
+
+  PlayField16[i + 1] = 0x2818;
+  PlayField16[i] = 0xFFFF;
+  goto loc_g_2778;
+
+loc_g_276F:                                     // GRAVITY CHANGING PORTS
+  PlayField16[i] = (ax - 4) | 0x100;    // Convert to standard ports
+  goto loc_g_2778;
+
+loc_g_2778:
+  i = i + 1;                   // Next field
+  bx = bx + 1;
+  cx = cx - 1;
+  if (0 < cx) // Until all done 'loc_g_2782:
+    goto loc_g_26C9;
+
+  subConvertToEasySymbols = dx; // return InfotronCount
+
+  return subConvertToEasySymbols;
+} // subConvertToEasySymbols
+
+// ==========================================================================
+//                              SUBROUTINE
+// Reset Infotron count.  Call immediately after subConvertToEasySymbols
+// ==========================================================================
+
+int ResetInfotronsNeeded(int dx)
+{
+  int ResetInfotronsNeeded;
+
+  if (LInfo.InfotronsNeeded != 0) // Jump If equal (autodetect)
+  {
+    dx = LInfo.InfotronsNeeded;
+  }                            // loc_g_278D:
+
+  InfotronsNeeded = LowByte(dx);           // Remaining Infotrons needed
+  TotalInfotronsNeeded = InfotronsNeeded;          // Number of Infotrons needed
+  subDisplayInfotronsNeeded();
+
+  return ResetInfotronsNeeded;
+} // ResetInfotronsNeeded
+
+
+// ==========================================================================
+//                              SUBROUTINE
+// Fetch and initialize a level
+// ==========================================================================
+
+int subFetchAndInitLevelB()
+{
+  int subFetchAndInitLevelB;
+
+  boolean UpdatePlayTime;
+
+  MovLowByte(&data_SPtorunavail, 0);   // no SP file
+  data_scr_demo = 0;
+  UpdatePlayTime = (0 == demo_stopped ?  True :  True);
+  demo_stopped = 0;
+  subFetchAndInitLevelA(UpdatePlayTime);
+
+  return subFetchAndInitLevelB;
+} // subFetchAndInitLevelb
+
+int subFetchAndInitLevelA(boolean UpdatePlayTime)
+{
+  int subFetchAndInitLevelA;
+
+  if (UpdatePlayTime && (0 == demo_stopped))
+  {
+    subUpdatePlayingTime();                 // update playing time
+  }
+
+  D_ModeFlag = 0; // 1=debug D pressed (CPU use)
+  if (0 != demo_stopped) // 1=demo, 0=game
+    DemoFlag = 1;
+
+  GameBusyFlag = 0; // restore scissors too
+  subFetchAndInitLevel();   // Fetch and initialize a level
+  GameBusyFlag = 1; // no free screen write
+  if (1 <= demo_stopped)
+  {
+    if (1 == demo_stopped)
+    {
+      DemoFlag = 0; // 1=demo, 0=game
+      demo_stopped = demo_stopped + 1;
+    }
+    else
+    {
+      DemoFlag = 0; // 1=demo, 0=game
+    }
+  }
+
+  DemoKeyCode = 0; // delete last demo key!
+  if (DemoFlag != 0) // don't allow during game! only in Demo
+  {
+    DemoOffset = DemoPointer;           // init demo pointer
+    DemoKeyRepeatCounter = 1;
+    subGetNextDemoKey();                 // get next demo byte
+  }
+
+  return subFetchAndInitLevelA;
+} // subFetchAndInitLevela
+
+int subFetchAndInitLevel()
+{
+  int subFetchAndInitLevel;
+
+  int InfoCountInLevel;
+
+  Trace("modInitGameConditions", "--> subFetchAndInitLevel");
+  Trace("modInitGameConditions", "Call ReadLevel");
+  ReadLevel();                   // Read LEVELS.DAT
+  Trace("modInitGameConditions", "ReadLevel return subFetchAndInitLeveled");
+
+  if (RecordDemoFlag == 1)
+  {
+    RecDemoRandomSeed = RandomSeed;
+    // Debug.Print "FetchRec: " & Hex(RandomSeed)
+  }
+
+  //  If DemoFlag = 1 Then
+  // Debug.Print "FetchPlay: " & Hex(RandomSeed)
+  //  End If
+  GameBusyFlag = -GameBusyFlag;   // make <>1
+  Trace("modInitGameConditions", "subConvertToEasySymbols");
+  InfoCountInLevel = subConvertToEasySymbols(); // Convert to easy symbols
+  GameBusyFlag = -GameBusyFlag;     // restore
+  Trace("modInitGameConditions", "subDisplayLevel");
+  subDisplayLevel();               // Paint (Init) game field
+  subDisplayPanel();                 // Paint (Init) Panel
+  ResetInfotronsNeeded(InfoCountInLevel);  // and reset Infotron count
+  Data_SubRstFlg = 1;
+  Trace("modInitGameConditions", "subInitGameConditions");
+  subInitGameConditions();                 // Init game conditions (vars)
+  InitMurphyPos();                 // Locate Murphy + screen pos
+  Trace("modInitGameConditions", "<-- subFetchAndInitLevel");
+
+  return subFetchAndInitLevel;
+} // subFetchAndInitLevel
diff --git a/src/game_sp/InitGameConditions.h b/src/game_sp/InitGameConditions.h
new file mode 100644 (file)
index 0000000..6c3de55
--- /dev/null
@@ -0,0 +1,24 @@
+// ----------------------------------------------------------------------------
+// InitGameConditions.h
+// ----------------------------------------------------------------------------
+
+#ifndef INITGAMECONDITIONS_H
+#define INITGAMECONDITIONS_H
+
+#include "vb_types.h"
+#include "vb_defs.h"
+#include "vb_vars.h"
+#include "vb_lib.h"
+
+#include "global.h"
+
+extern int InitMurphyPos();
+extern int InitMurphyPosB(int si);
+extern int ResetInfotronsNeeded(int dx);
+extern int subConvertToEasySymbols();
+extern int subFetchAndInitLevel();
+extern int subFetchAndInitLevelA(boolean UpdatePlayTime);
+extern int subFetchAndInitLevelB();
+extern int subInitGameConditions();
+
+#endif /* INITGAMECONDITIONS_H */
diff --git a/src/game_sp/Input.c b/src/game_sp/Input.c
new file mode 100644 (file)
index 0000000..2443805
--- /dev/null
@@ -0,0 +1,155 @@
+// ----------------------------------------------------------------------------
+// Input.c
+// ----------------------------------------------------------------------------
+
+#include "Input.h"
+
+static char *VB_Name = "modInput";
+// --- Option Explicit
+
+boolean KeyState[255 + 1];
+DemoBufferObject DemoBuffer;
+
+//
+// Public KeyFlagSpace As Boolean
+// Public KeyFlagUp As Boolean
+// Public KeyFlagLeft As Boolean
+// Public KeyFlagDown As Boolean
+// Public KeyFlagRight As Boolean
+// Public KeyFlagEnter As Boolean
+// Public KeyFlagESC As Boolean
+// Public KeyFlagR As Boolean
+// Public KeyFlagRShift As Boolean
+
+int KeyScanCode7;
+
+void subCheckJoystick()
+{
+}
+
+int subCheckRightMouseButton()
+{
+  int subCheckRightMouseButton;
+
+  // return button state
+
+  return subCheckRightMouseButton;
+}
+
+int subProcessKeyboardInput()
+{
+  int subProcessKeyboardInput;
+
+  int LastKey;
+
+  //  On Error GoTo NoKeyboardAccessEH
+  //    Call DKeyboard.Acquire
+  //  On Error GoTo 0
+  //  Call DKeyboard.GetDeviceStateKeyboard(KeyState)
+  //  With KeyState
+  if (DemoFlag != 0)
+  {
+    subGetNextDemoKey();
+    if (ExitToMenuFlag != 0)
+      return subProcessKeyboardInput;
+
+  }
+  else
+  {
+    if (KeyState[vbKeySpace])
+    {
+      if (KeyState[vbKeyUp])
+      {
+        DemoKeyCode = keySpaceUp;
+      }
+      else if (KeyState[vbKeyLeft])
+      {
+        DemoKeyCode = keySpaceLeft;
+      }
+      else if (KeyState[vbKeyDown])
+      {
+        DemoKeyCode = keySpaceDown;
+      }
+      else if (KeyState[vbKeyRight])
+      {
+        DemoKeyCode = keySpaceRight;
+      }
+      else
+      {
+        DemoKeyCode = keySpace;
+      }
+
+    }
+    else
+    {
+      if (KeyState[vbKeyUp])
+      {
+        DemoKeyCode = keyUp;
+      }
+      else if (KeyState[vbKeyLeft])
+      {
+        DemoKeyCode = keyLeft;
+      }
+      else if (KeyState[vbKeyDown])
+      {
+        DemoKeyCode = keyDown;
+      }
+      else if (KeyState[vbKeyRight])
+      {
+        DemoKeyCode = keyRight;
+      }
+      else
+      {
+        DemoKeyCode = keyNone;
+      }
+    }
+  }
+
+  // demo recording
+  if (RecordDemoFlag == 1)
+    DemoBuffer.AddDemoKey(DemoKeyCode);
+
+  if (DemoKeyCode != LastKey && ! NoDisplayFlag)
+  {
+#if 0
+    MainForm.ShowKey(DemoKeyCode);
+#endif
+    LastKey = DemoKeyCode;
+  }
+
+  if (KeyState[vbKeyEscape])
+  {
+    if (BlockingSpeed)
+    {
+      //        Call MainForm.menSpeed_Click(4)
+    }
+    else
+    {
+      KillMurphyFlag = 1;
+      //        ExplodeFieldSP MurphyPosIndex
+      //        LeadOutCounter = &H20
+    }
+  }
+
+  if (KeyState[vbKeyR])
+  {
+    subFetchAndInitLevelB();
+  }
+
+  if (KeyState[vbKeyShift])
+    subDisplayRedDiskCount();
+
+#if 0
+  if (KeyState[vbKeyReturn])
+    MainForm.PanelVisible = (ShowPanel == 0);
+#endif
+
+  //  End With
+  //  Call DKeyboard.Unacquire
+  return subProcessKeyboardInput;
+
+NoKeyboardAccessEH:
+  Debug.Print("! Keyboard access");
+
+  return subProcessKeyboardInput;
+}
diff --git a/src/game_sp/Input.h b/src/game_sp/Input.h
new file mode 100644 (file)
index 0000000..2762b30
--- /dev/null
@@ -0,0 +1,23 @@
+// ----------------------------------------------------------------------------
+// Input.h
+// ----------------------------------------------------------------------------
+
+#ifndef INPUT_H
+#define INPUT_H
+
+#include "vb_types.h"
+#include "vb_defs.h"
+#include "vb_vars.h"
+#include "vb_lib.h"
+
+#include "global.h"
+
+extern void subCheckJoystick();
+extern int subCheckRightMouseButton();
+extern int subProcessKeyboardInput();
+
+extern DemoBufferObject DemoBuffer;
+extern boolean KeyState[255 + 1];
+extern int KeyScanCode7;
+
+#endif /* INPUT_H */
diff --git a/src/game_sp/LevelSetPreviewForm.c b/src/game_sp/LevelSetPreviewForm.c
new file mode 100644 (file)
index 0000000..b5d0b59
--- /dev/null
@@ -0,0 +1,41 @@
+// ----------------------------------------------------------------------------
+// LevelSetPreviewForm.c
+// ----------------------------------------------------------------------------
+
+#include "LevelSetPreviewForm.h"
+
+// --- VERSION 5.00
+// --- Begin VB.Form LevelSetPreviewForm 
+// ---    BorderStyle     =   4  'Fixed ToolWindow  // Fixed ToolWindow
+// ---    Caption         =   "Level Set Preview"
+// ---    ClientHeight    =   10860
+// ---    ClientLeft      =   4890
+// ---    ClientTop       =   2760
+// ---    ClientWidth     =   6585
+// ---    LinkTopic       =   "Form1"
+// ---    MaxButton       =   0   'False   // False
+// ---    MinButton       =   0   'False   // False
+// ---    ScaleHeight     =   724
+// ---    ScaleMode       =   3  'Pixel  // Pixel
+// ---    ScaleWidth      =   439
+// ---    ShowInTaskbar   =   0   'False   // False
+// ---    Begin VB.PictureBox pic 
+// ---       BackColor       =   &H00000000&
+// ---       Height          =   2475
+// ---       Left            =   480
+// ---       ScaleHeight     =   161
+// ---       ScaleMode       =   3  'Pixel  // Pixel
+// ---       ScaleWidth      =   349
+// ---       TabIndex        =   0
+// ---       Top             =   360
+// ---       Width           =   5295
+// ---    End
+// --- End
+
+static char *VB_Name = "LevelSetPreviewForm";
+static boolean VB_GlobalNameSpace = False;
+static boolean VB_Creatable = False;
+static boolean VB_PredeclaredId = True;
+static boolean VB_Exposed = False;
+// --- Option Explicit
+
diff --git a/src/game_sp/LevelSetPreviewForm.h b/src/game_sp/LevelSetPreviewForm.h
new file mode 100644 (file)
index 0000000..0cc8bc7
--- /dev/null
@@ -0,0 +1,15 @@
+// ----------------------------------------------------------------------------
+// LevelSetPreviewForm.h
+// ----------------------------------------------------------------------------
+
+#ifndef LEVELSETPREVIEWFORM_H
+#define LEVELSETPREVIEWFORM_H
+
+#include "vb_types.h"
+#include "vb_defs.h"
+#include "vb_vars.h"
+#include "vb_lib.h"
+
+#include "global.h"
+
+#endif /* LEVELSETPREVIEWFORM_H */
diff --git a/src/game_sp/MainForm.c b/src/game_sp/MainForm.c
new file mode 100644 (file)
index 0000000..f2fe86f
--- /dev/null
@@ -0,0 +1,3362 @@
+// ----------------------------------------------------------------------------
+// MainForm.c
+// ----------------------------------------------------------------------------
+
+#include "MainForm.h"
+
+#if 1
+
+static void DrawFrame(int Delta);
+
+#else
+
+static void CleanTempDir(char *TmpDir);
+static void CountDown(long HalfSeconds, int bDisplayBar);
+static void DrawFrame(int Delta);
+static void DrawPauseLayer(long Layer);
+static void FillFileList(char *Path);
+static void FillLevelList(char *Path, int LevelIndex);
+static void FocusTim_Timer();
+static void Form_KeyDown(int KeyCode, int Shift);
+static void Form_KeyUp(int KeyCode, int Shift);
+static void Form_Paint();
+static int GetFileNameToSave();
+static long GetHwndFromTempFileName(char *TmpFile);
+static char * GetMyTempFileName();
+static void GetSettings();
+static char * GetSpeedDescriptionFPS(currency FrameDelayUS);
+static int GetSpeedIndex(long DelayUS);
+static char * GetValidTempPath();
+static long Get_LastOpenFilter();
+static long Get_LastSaveFilter();
+static int InitSpeeds();
+static boolean InstanceStillRunning(char *TmpFile);
+static void Let_LastOpenFilter(long NewVal);
+static void Let_LastSaveFilter(long NewVal);
+static void LoadKeyIndicators();
+static void LoadMenus();
+static void PanelTim_Timer();
+static void ReStretch(float NewStretch);
+static void RestoreFrame();
+static boolean SaveAs();
+static void SaveSettings();
+static void SetScrollEdges();
+static void UpdateDeltaT();
+static void cmbFile_Click();
+static void cmbFile_KeyDown(int KeyCode, int Shift);
+static void cmbFile_KeyUp(int KeyCode, int Shift);
+static void cmbLevel_Click();
+static void cmbLevel_KeyUp(int KeyCode, int Shift);
+static void cmblevel_KeyDown(int KeyCode, int Shift);
+static void cmdPause_Click();
+static void cmdPause_MouseUp(int Button, int Shift, float X, float Y);
+static void cmdPlayAll_Click();
+static void cmdPlayAll_MouseUp(int Button, int Shift, float X, float Y);
+static void cmdPlayDemo_Click();
+static void cmdPlayDemo_MouseUp(int Button, int Shift, float X, float Y);
+static void cmdPlay_Click();
+static void cmdPlay_MouseUp(int Button, int Shift, float X, float Y);
+static void cmdRecordDemo_Click();
+static void cmdRecordDemo_MouseUp(int Button, int Shift, float X, float Y);
+static void cmdStop_Click();
+static void cmdStop_MouseUp(int Button, int Shift, float X, float Y);
+static void fpsTim_Timer();
+static void menAbout_Click();
+static void menAutoScroll_Click();
+static void menBorder_Click();
+static void menCopy_Click();
+static void menEnOff_Click();
+static void menEnOn_Click();
+static void menExit_Click();
+static void menFaster_Click();
+static void menGravOff_Click();
+static void menGravOn_Click();
+static void menNewStd_Click();
+static void menNew_Click();
+static void menOpen_Click();
+static void menOptions_Click();
+static void menPanel_Click();
+static void menPaste_Click();
+static void menPause_Click();
+static void menPlayAll_Click();
+static void menPlayDemo_Click();
+static void menPlay_Click();
+static void menReRecordDemo_Click();
+static void menRec_Click();
+static void menRemSP_Click();
+static void menRestoreBorder_Click();
+static void menSaveAs_Click();
+static void menSave_Click();
+static void menSelectAll_Click();
+static void menShowLInfo_Click();
+static void menSlower_Click();
+static void menSoundFX_Click();
+static void menStretch_Click(int Index);
+static void menToolTips_Click();
+static void menTrim_Click();
+static void menZonkOff_Click();
+static void menZonkOn_Click();
+static void picKeys_MouseUp(int Button, int Shift, float X, float Y);
+static void picMenu_Click();
+static void picPane_KeyDown(int KeyCode, int Shift);
+static void picPane_KeyUp(int KeyCode, int Shift);
+static void picPane_MouseDown(int Button, int Shift, float X, float Y);
+static void picPane_MouseMove(int Button, int Shift, float X, float Y);
+static void picPane_MouseUp(int Button, int Shift, float X, float Y);
+static void picPane_Paint();
+static void picViewPort_MouseUp(int Button, int Shift, float X, float Y);
+static void picViewPort_Paint();
+static void picViewPort_Resize();
+
+#endif
+
+void DrawField(int X, int Y);
+void DrawFieldAnimated(int X, int Y);
+void DrawFieldNoAnimated(int X, int Y);
+
+// --- VERSION 5.00
+// --- Object = "{F9043C88-F6F2-101A-A3C9-08002B2F49FB}#1.2#0"; "COMDLG32.OCX"
+// --- Begin VB.Form MainForm 
+// ---    AutoRedraw      =   -1  'True  // True
+// ---    Caption         =   "MegaPlex"
+// ---    ClientHeight    =   5850
+// ---    ClientLeft      =   2580
+// ---    ClientTop       =   2205
+// ---    ClientWidth     =   9285
+// ---    Icon            =   "MainForm.frx":0000
+// ---    LinkTopic       =   "Form1"
+// ---    ScaleHeight     =   390
+// ---    ScaleMode       =   3  'Pixel  // Pixel
+// ---    ScaleWidth      =   619
+// ---    Begin VB.Timer fpsTim 
+// ---       Enabled         =   0   'False   // False
+// ---       Interval        =   200
+// ---       Left            =   1380
+// ---       Top             =   2940
+// ---    End
+// ---    Begin VB.Timer FocusTim 
+// ---       Interval        =   50
+// ---       Left            =   1920
+// ---       Top             =   2940
+// ---    End
+// ---    Begin MSComDlg.CommonDialog cmDlg 
+// ---       Left            =   240
+// ---       Top             =   2880
+// ---       _ExtentX        =   847
+// ---       _ExtentY        =   847
+// ---       _Version        =   393216
+// ---       CancelError     =   -1  'True  // True
+// ---    End
+// ---    Begin VB.Timer PanelTim 
+// ---       Enabled         =   0   'False   // False
+// ---       Interval        =   5
+// ---       Left            =   840
+// ---       Top             =   2940
+// ---    End
+// ---    Begin VB.Frame Panel 
+// ---       Height          =   1140
+// ---       Left            =   180
+// ---       TabIndex        =   2
+// ---       Top             =   3540
+// ---       Width           =   9015
+// ---       Begin VB.CommandButton cmdPlay 
+// ---          DisabledPicture =   "MainForm.frx":0442
+// ---          DownPicture     =   "MainForm.frx":058C
+// ---          Height          =   345
+// ---          Left            =   5820
+// ---          Picture         =   "MainForm.frx":06D6
+// ---          Style           =   1  'Graphical  // Graphical
+// ---          TabIndex        =   16
+// ---          TabStop         =   0   'False   // False
+// ---          Top             =   240
+// ---          Width           =   495
+// ---       End
+// ---       Begin VB.CommandButton cmdStop 
+// ---          DisabledPicture =   "MainForm.frx":0820
+// ---          DownPicture     =   "MainForm.frx":096A
+// ---          Enabled         =   0   'False   // False
+// ---          Height          =   345
+// ---          Left            =   7020
+// ---          Picture         =   "MainForm.frx":0AB4
+// ---          Style           =   1  'Graphical  // Graphical
+// ---          TabIndex        =   15
+// ---          TabStop         =   0   'False   // False
+// ---          Top             =   240
+// ---          Width           =   495
+// ---       End
+// ---       Begin VB.CommandButton cmdPlayDemo 
+// ---          DisabledPicture =   "MainForm.frx":0BFE
+// ---          DownPicture     =   "MainForm.frx":0D48
+// ---          Enabled         =   0   'False   // False
+// ---          Height          =   345
+// ---          Left            =   7740
+// ---          Picture         =   "MainForm.frx":0E92
+// ---          Style           =   1  'Graphical  // Graphical
+// ---          TabIndex        =   14
+// ---          TabStop         =   0   'False   // False
+// ---          Top             =   240
+// ---          Width           =   495
+// ---       End
+// ---       Begin VB.CommandButton cmdPause 
+// ---          DisabledPicture =   "MainForm.frx":0FDC
+// ---          DownPicture     =   "MainForm.frx":1126
+// ---          Enabled         =   0   'False   // False
+// ---          Height          =   345
+// ---          Left            =   6420
+// ---          Picture         =   "MainForm.frx":1270
+// ---          Style           =   1  'Graphical  // Graphical
+// ---          TabIndex        =   13
+// ---          TabStop         =   0   'False   // False
+// ---          Top             =   240
+// ---          Width           =   495
+// ---       End
+// ---       Begin VB.CommandButton cmdRecordDemo 
+// ---          DisabledPicture =   "MainForm.frx":13BA
+// ---          DownPicture     =   "MainForm.frx":1504
+// ---          Height          =   345
+// ---          Left            =   8340
+// ---          Picture         =   "MainForm.frx":164E
+// ---          Style           =   1  'Graphical  // Graphical
+// ---          TabIndex        =   12
+// ---          TabStop         =   0   'False   // False
+// ---          Top             =   240
+// ---          Width           =   495
+// ---       End
+// ---       Begin VB.ComboBox cmbFile 
+// ---          BackColor       =   &H00000000&
+// ---          BeginProperty Font 
+// ---             Name            =   "Fixedsys"
+// ---             Size            =   9
+// ---             Charset         =   0
+// ---             Weight          =   400
+// ---             Underline       =   0   'False   // False
+// ---             Italic          =   0   'False   // False
+// ---             Strikethrough   =   0   'False   // False
+// ---          EndProperty
+// ---          ForeColor       =   &H00FF8080&
+// ---          Height          =   345
+// ---          Left            =   120
+// ---          Sorted          =   -1  'True  // True
+// ---          Style           =   2  'Dropdown List  // Dropdown List
+// ---          TabIndex        =   9
+// ---          Top             =   240
+// ---          Width           =   3015
+// ---       End
+// ---       Begin VB.ComboBox cmbLevel 
+// ---          BackColor       =   &H00000000&
+// ---          BeginProperty Font 
+// ---             Name            =   "Fixedsys"
+// ---             Size            =   9
+// ---             Charset         =   0
+// ---             Weight          =   400
+// ---             Underline       =   0   'False   // False
+// ---             Italic          =   0   'False   // False
+// ---             Strikethrough   =   0   'False   // False
+// ---          EndProperty
+// ---          ForeColor       =   &H00FF8080&
+// ---          Height          =   345
+// ---          Left            =   840
+// ---          Sorted          =   -1  'True  // True
+// ---          Style           =   2  'Dropdown List  // Dropdown List
+// ---          TabIndex        =   5
+// ---          Top             =   660
+// ---          Width           =   4035
+// ---       End
+// ---       Begin VB.PictureBox picKeys 
+// ---          BackColor       =   &H00008080&
+// ---          BorderStyle     =   0  'None  // None
+// ---          Height          =   330
+// ---          Left            =   5400
+// ---          ScaleHeight     =   22
+// ---          ScaleMode       =   3  'Pixel  // Pixel
+// ---          ScaleWidth      =   22
+// ---          TabIndex        =   4
+// ---          TabStop         =   0   'False   // False
+// ---          Top             =   240
+// ---          Width           =   330
+// ---          Begin VB.Shape shpKey 
+// ---             FillColor       =   &H00008000&
+// ---             FillStyle       =   0  'Solid  // Solid
+// ---             Height          =   120
+// ---             Index           =   1
+// ---             Left            =   0
+// ---             Shape           =   5  'Rounded Square  // Rounded Square
+// ---             Top             =   0
+// ---             Width           =   120
+// ---          End
+// ---       End
+// ---       Begin VB.CommandButton cmdPlayAll 
+// ---          Caption         =   "Play All Demos"
+// ---          Enabled         =   0   'False   // False
+// ---          Height          =   345
+// ---          Left            =   7380
+// ---          TabIndex        =   3
+// ---          TabStop         =   0   'False   // False
+// ---          Top             =   960
+// ---          Visible         =   0   'False   // False
+// ---          Width           =   1395
+// ---       End
+// ---       Begin VB.Shape shpProgress 
+// ---          BackColor       =   &H00800000&
+// ---          BackStyle       =   1  'Opaque  // Opaque
+// ---          Height          =   75
+// ---          Left            =   120
+// ---          Top             =   1020
+// ---          Visible         =   0   'False   // False
+// ---          Width           =   7515
+// ---       End
+// ---       Begin VB.Label lblStatus 
+// ---          Alignment       =   2  'Center  // Center
+// ---          BorderStyle     =   1  'Fixed Single  // Fixed Single
+// ---          Caption         =   "MegaPlex"
+// ---          BeginProperty Font 
+// ---             Name            =   "Fixedsys"
+// ---             Size            =   9
+// ---             Charset         =   0
+// ---             Weight          =   400
+// ---             Underline       =   0   'False   // False
+// ---             Italic          =   0   'False   // False
+// ---             Strikethrough   =   0   'False   // False
+// ---          EndProperty
+// ---          Height          =   345
+// ---          Left            =   3240
+// ---          TabIndex        =   11
+// ---          Top             =   240
+// ---          Width           =   2055
+// ---       End
+// ---       Begin VB.Image Image2 
+// ---          Height          =   240
+// ---          Left            =   6780
+// ---          Picture         =   "MainForm.frx":1BD8
+// ---          Top             =   720
+// ---          Width           =   240
+// ---       End
+// ---       Begin VB.Image Image1 
+// ---          Height          =   240
+// ---          Left            =   5880
+// ---          Picture         =   "MainForm.frx":1D22
+// ---          Top             =   720
+// ---          Width           =   240
+// ---       End
+// ---       Begin VB.Label lblFps 
+// ---          Alignment       =   2  'Center  // Center
+// ---          BackColor       =   &H00000000&
+// ---          BorderStyle     =   1  'Fixed Single  // Fixed Single
+// ---          BeginProperty Font 
+// ---             Name            =   "Fixedsys"
+// ---             Size            =   9
+// ---             Charset         =   0
+// ---             Weight          =   400
+// ---             Underline       =   0   'False   // False
+// ---             Italic          =   0   'False   // False
+// ---             Strikethrough   =   0   'False   // False
+// ---          EndProperty
+// ---          ForeColor       =   &H0000C0C0&
+// ---          Height          =   345
+// ---          Left            =   120
+// ---          TabIndex        =   10
+// ---          Top             =   660
+// ---          Width           =   615
+// ---       End
+// ---       Begin VB.Label lblInfoCount 
+// ---          Alignment       =   2  'Center  // Center
+// ---          BackColor       =   &H00000000&
+// ---          BorderStyle     =   1  'Fixed Single  // Fixed Single
+// ---          BeginProperty Font 
+// ---             Name            =   "Fixedsys"
+// ---             Size            =   9
+// ---             Charset         =   0
+// ---             Weight          =   400
+// ---             Underline       =   0   'False   // False
+// ---             Italic          =   0   'False   // False
+// ---             Strikethrough   =   0   'False   // False
+// ---          EndProperty
+// ---          ForeColor       =   &H00FF8080&
+// ---          Height          =   345
+// ---          Left            =   5040
+// ---          TabIndex        =   8
+// ---          Top             =   660
+// ---          Width           =   795
+// ---       End
+// ---       Begin VB.Label lblRedDiskCount 
+// ---          Alignment       =   2  'Center  // Center
+// ---          BackColor       =   &H00000000&
+// ---          BorderStyle     =   1  'Fixed Single  // Fixed Single
+// ---          BeginProperty Font 
+// ---             Name            =   "Fixedsys"
+// ---             Size            =   9
+// ---             Charset         =   0
+// ---             Weight          =   400
+// ---             Underline       =   0   'False   // False
+// ---             Italic          =   0   'False   // False
+// ---             Strikethrough   =   0   'False   // False
+// ---          EndProperty
+// ---          ForeColor       =   &H000000FF&
+// ---          Height          =   345
+// ---          Left            =   6240
+// ---          TabIndex        =   7
+// ---          Top             =   660
+// ---          Width           =   495
+// ---       End
+// ---       Begin VB.Label lblFrameCount 
+// ---          Alignment       =   2  'Center  // Center
+// ---          BorderStyle     =   1  'Fixed Single  // Fixed Single
+// ---          Caption         =   "0"
+// ---          BeginProperty Font 
+// ---             Name            =   "Fixedsys"
+// ---             Size            =   9
+// ---             Charset         =   0
+// ---             Weight          =   400
+// ---             Underline       =   0   'False   // False
+// ---             Italic          =   0   'False   // False
+// ---             Strikethrough   =   0   'False   // False
+// ---          EndProperty
+// ---          Height          =   345
+// ---          Left            =   7200
+// ---          TabIndex        =   6
+// ---          Top             =   660
+// ---          Width           =   1635
+// ---       End
+// ---    End
+// ---    Begin VB.PictureBox picViewPort 
+// ---       BorderStyle     =   0  'None  // None
+// ---       Height          =   2535
+// ---       Left            =   180
+// ---       ScaleHeight     =   169
+// ---       ScaleMode       =   3  'Pixel  // Pixel
+// ---       ScaleWidth      =   265
+// ---       TabIndex        =   0
+// ---       TabStop         =   0   'False   // False
+// ---       Top             =   180
+// ---       Width           =   3975
+// ---       Begin VB.PictureBox picPane 
+// ---          AutoSize        =   -1  'True  // True
+// ---          BackColor       =   &H00000000&
+// ---          BorderStyle     =   0  'None  // None
+// ---          DrawWidth       =   3
+// ---          Height          =   1635
+// ---          Left            =   240
+// ---          ScaleHeight     =   109
+// ---          ScaleMode       =   3  'Pixel  // Pixel
+// ---          ScaleWidth      =   129
+// ---          TabIndex        =   1
+// ---          Top             =   180
+// ---          Width           =   1935
+// ---       End
+// ---       Begin VB.PictureBox picFrame 
+// ---          Height          =   915
+// ---          Left            =   1320
+// ---          ScaleHeight     =   57
+// ---          ScaleMode       =   3  'Pixel  // Pixel
+// ---          ScaleWidth      =   81
+// ---          TabIndex        =   17
+// ---          TabStop         =   0   'False   // False
+// ---          Top             =   1200
+// ---          Width           =   1275
+// ---       End
+// ---    End
+// ---    Begin VB.Menu menFile 
+// ---       Caption         =   "&File"
+// ---       Begin VB.Menu menNewStd 
+// ---          Caption         =   "New S&tandard Level"
+// ---       End
+// ---       Begin VB.Menu menNew 
+// ---          Caption         =   "&New Level"
+// ---       End
+// ---       Begin VB.Menu menDash5 
+// ---          Caption         =   "-"
+// ---       End
+// ---       Begin VB.Menu menOpen 
+// ---          Caption         =   "&Open"
+// ---       End
+// ---       Begin VB.Menu menSave 
+// ---          Caption         =   "&Save"
+// ---          Shortcut        =   ^S
+// ---       End
+// ---       Begin VB.Menu menSaveAs 
+// ---          Caption         =   "Save &As ..."
+// ---       End
+// ---       Begin VB.Menu menDash4 
+// ---          Caption         =   "-"
+// ---       End
+// ---       Begin VB.Menu menExit 
+// ---          Caption         =   "E&xit"
+// ---          Shortcut        =   ^Q
+// ---       End
+// ---    End
+// ---    Begin VB.Menu menEditMain 
+// ---       Caption         =   "&Edit"
+// ---       Begin VB.Menu menEdit 
+// ---          Caption         =   "&Edit Level"
+// ---       End
+// ---       Begin VB.Menu menDash3 
+// ---          Caption         =   "-"
+// ---       End
+// ---       Begin VB.Menu menCopy 
+// ---          Caption         =   "&Copy"
+// ---          Shortcut        =   ^C
+// ---       End
+// ---       Begin VB.Menu menPaste 
+// ---          Caption         =   "&Paste"
+// ---          Shortcut        =   ^V
+// ---       End
+// ---       Begin VB.Menu menTrim 
+// ---          Caption         =   "&Trim"
+// ---          Shortcut        =   ^T
+// ---       End
+// ---       Begin VB.Menu menDash8 
+// ---          Caption         =   "-"
+// ---          Index           =   1
+// ---       End
+// ---       Begin VB.Menu menSelectAll 
+// ---          Caption         =   "Select &All"
+// ---          Shortcut        =   ^A
+// ---       End
+// ---       Begin VB.Menu menDash6 
+// ---          Caption         =   "-"
+// ---       End
+// ---       Begin VB.Menu menRestoreBorder 
+// ---          Caption         =   "Restore &border"
+// ---          Shortcut        =   ^B
+// ---       End
+// ---       Begin VB.Menu menSp 
+// ---          Caption         =   "Special Port"
+// ---          Begin VB.Menu menGravOn 
+// ---             Caption         =   "&Gravity On"
+// ---          End
+// ---          Begin VB.Menu menZonkOn 
+// ---             Caption         =   "Freeze &Zonks On"
+// ---          End
+// ---          Begin VB.Menu menEnOn 
+// ---             Caption         =   "Freeze &Enemies On"
+// ---          End
+// ---          Begin VB.Menu menDash7 
+// ---             Caption         =   "-"
+// ---          End
+// ---          Begin VB.Menu menGravOff 
+// ---             Caption         =   "Gravity &Off"
+// ---          End
+// ---          Begin VB.Menu menZonkOff 
+// ---             Caption         =   "Freeze Zon&ks Off"
+// ---          End
+// ---          Begin VB.Menu menEnOff 
+// ---             Caption         =   "Freeze E&nemies Off"
+// ---          End
+// ---          Begin VB.Menu menDash10 
+// ---             Caption         =   "-"
+// ---          End
+// ---          Begin VB.Menu menRemSP 
+// ---             Caption         =   "&Remove (Make Normal Port)"
+// ---          End
+// ---       End
+// ---    End
+// ---    Begin VB.Menu menView 
+// ---       Caption         =   "&View"
+// ---       Begin VB.Menu menZoom 
+// ---          Caption         =   "&Zoom"
+// ---          Begin VB.Menu menStretch 
+// ---             Caption         =   "0.25 : 1"
+// ---             Index           =   1
+// ---          End
+// ---       End
+// ---       Begin VB.Menu menBorder 
+// ---          Caption         =   "Show &Border"
+// ---          Checked         =   -1  'True  // True
+// ---       End
+// ---       Begin VB.Menu menPanel 
+// ---          Caption         =   "Show &Panel"
+// ---          Checked         =   -1  'True  // True
+// ---       End
+// ---       Begin VB.Menu menAutoScroll 
+// ---          Caption         =   "&Autoscroll"
+// ---          Checked         =   -1  'True  // True
+// ---       End
+// ---       Begin VB.Menu menDash9 
+// ---          Caption         =   "-"
+// ---       End
+// ---       Begin VB.Menu menShowLInfo 
+// ---          Caption         =   "Show Level &Info"
+// ---       End
+// ---    End
+// ---    Begin VB.Menu menSound 
+// ---       Caption         =   "&Sound"
+// ---       Begin VB.Menu menSoundFX 
+// ---          Caption         =   "&FX"
+// ---       End
+// ---       Begin VB.Menu menMusic 
+// ---          Caption         =   "&Music"
+// ---          Enabled         =   0   'False   // False
+// ---       End
+// ---    End
+// ---    Begin VB.Menu menSpeed 
+// ---       Caption         =   "Speed"
+// ---       Begin VB.Menu menSpeedPlay 
+// ---          Caption         =   "Game play"
+// ---          Index           =   11
+// ---          Begin VB.Menu menPlaySpeed 
+// ---             Caption         =   "1"
+// ---             Index           =   1
+// ---          End
+// ---       End
+// ---       Begin VB.Menu menSpeedDemo 
+// ---          Caption         =   "Demo playback"
+// ---          Begin VB.Menu menDemoSpeed 
+// ---             Caption         =   "1"
+// ---             Index           =   1
+// ---          End
+// ---       End
+// ---       Begin VB.Menu menSpeedDash 
+// ---          Caption         =   "-"
+// ---       End
+// ---       Begin VB.Menu menFaster 
+// ---          Caption         =   "Faster (Pg Up)"
+// ---       End
+// ---       Begin VB.Menu menSlower 
+// ---          Caption         =   "Slower (Pg Down)"
+// ---       End
+// ---    End
+// ---    Begin VB.Menu menRun 
+// ---       Caption         =   "&Play"
+// ---       Begin VB.Menu menPlay 
+// ---          Caption         =   "P&lay Game    (Space)"
+// ---       End
+// ---       Begin VB.Menu menPause 
+// ---          Caption         =   "&Pause    (P)"
+// ---          Enabled         =   0   'False   // False
+// ---       End
+// ---       Begin VB.Menu menStop 
+// ---          Caption         =   "&Stop    (Q)"
+// ---          Enabled         =   0   'False   // False
+// ---       End
+// ---       Begin VB.Menu menDash0 
+// ---          Caption         =   "-"
+// ---       End
+// ---       Begin VB.Menu menRec 
+// ---          Caption         =   "&Record Demo    (Ctrl+R)"
+// ---       End
+// ---       Begin VB.Menu menPlayDemo 
+// ---          Caption         =   "Play &Demo    (Ctrl+Space)"
+// ---       End
+// ---       Begin VB.Menu menPlayAll 
+// ---          Caption         =   "Play &All Demos"
+// ---       End
+// ---    End
+// ---    Begin VB.Menu menOptionsMain 
+// ---       Caption         =   "&Options"
+// ---       Begin VB.Menu menOptions 
+// ---          Caption         =   "&Options ..."
+// ---       End
+// ---    End
+// ---    Begin VB.Menu menHelp 
+// ---       Caption         =   "Help"
+// ---       Begin VB.Menu menToolTips 
+// ---          Caption         =   "Show &ToolTips"
+// ---       End
+// ---       Begin VB.Menu menDash1 
+// ---          Caption         =   "-"
+// ---       End
+// ---       Begin VB.Menu menAbout 
+// ---          Caption         =   "&About MegaPlex"
+// ---       End
+// ---    End
+// --- End
+
+static char *VB_Name = "MainForm";
+static boolean VB_GlobalNameSpace = False;
+static boolean VB_Creatable = False;
+static boolean VB_PredeclaredId = True;
+static boolean VB_Exposed = False;
+// --- Option Explicit
+// --- Option Compare Text
+
+long SetParent(long hWndChild, long hWndNewParent);
+long SetWindowLong(long hWnd, long nIndex, long dwNewLong);
+long GetWindowLong(long hWnd, long nIndex);
+long GetTempPath(long nBufferLength, char *lpBuffer);
+long GetWindowText(long hWnd, char *lpString, long cch);
+
+#define GWL_STYLE                      ((-16))
+#define WS_CHILD                       (0x40000000)
+#define WS_POPUP                       (0x80000000)
+
+// [UNCOMMENTED] Dim StretchWidth2&
+
+char *MpxBmp;
+int OldPointer;
+long OSX, OSY, MDX, MDY;
+int MouseButton;
+
+int PanelSeq;
+
+boolean Loaded, DemosAvailable;
+
+#define nSpeedCount                    (17)
+int SpeedsByDelayUS[nSpeedCount + 1];
+#define DefaultSpeedIndex                      (12)
+
+currency LastTick, LastFrame;
+TickCountObject T;
+
+const char *AppTitle = "MegaPlex";
+
+static char *GetSpeedDescriptionFPS(currency FrameDelayUS)
+{
+  static char *GetSpeedDescriptionFPS;
+
+  long FPS;
+
+  if (FrameDelayUS == 0)
+  {
+    GetSpeedDescriptionFPS = "Fastest possible";
+    return GetSpeedDescriptionFPS;
+  }
+
+  if (FrameDelayUS < 0)
+  {
+    GetSpeedDescriptionFPS = "! display (even faster)";
+    return GetSpeedDescriptionFPS;
+  }
+
+  FPS = 1000000 / FrameDelayUS;
+  GetSpeedDescriptionFPS = CAT(INT_TO_STR(FPS), " fps");
+  if (35 == FPS)
+    GetSpeedDescriptionFPS = CAT(GetSpeedDescriptionFPS, "(Default)");
+
+  return GetSpeedDescriptionFPS;
+}
+
+static int InitSpeeds()
+{
+  static int InitSpeeds;
+
+  SpeedsByDelayUS[1] = -1;  // no display
+  SpeedsByDelayUS[2] = 0; // fastest possible
+  SpeedsByDelayUS[3] = 1000000 / 700; // 700 fps
+  SpeedsByDelayUS[4] = 1000000 / 500; // 500 fps
+  SpeedsByDelayUS[5] = 1000000 / 350; // 350 fps
+  SpeedsByDelayUS[6] = 1000000 / 250; // 250 fps
+  SpeedsByDelayUS[7] = 1000000 / 200; // etc.
+  SpeedsByDelayUS[8] = 1000000 / 150;
+  SpeedsByDelayUS[9] = 1000000 / 100;
+  SpeedsByDelayUS[10] = 1000000 / 70;
+  SpeedsByDelayUS[11] = 1000000 / 50;
+  SpeedsByDelayUS[12] = 1000000 / 35; // default
+  SpeedsByDelayUS[13] = 1000000 / 25;
+  SpeedsByDelayUS[14] = 1000000 / 20;
+  SpeedsByDelayUS[15] = 1000000 / 10;
+  SpeedsByDelayUS[16] = 1000000 / 5;
+  SpeedsByDelayUS[17] = 1000000 / 1;
+
+  return InitSpeeds;
+}
+
+static int GetSpeedIndex(long DelayUS)
+{
+  static int GetSpeedIndex;
+
+  int i;
+  long Diff, MinDiff;
+  int MinIdx;
+
+  MinIdx = DefaultSpeedIndex;
+  MinDiff = 1000000;
+  for (i = 1; i <= nSpeedCount; i++)
+  {
+    Diff = Abs(DelayUS - SpeedsByDelayUS[i]);
+    if (Diff < MinDiff)
+    {
+      MinDiff = Diff;
+      MinIdx = i;
+    }
+  }
+
+  GetSpeedIndex = MinIdx;
+
+  return GetSpeedIndex;
+}
+
+#if 0
+
+static long Get_LastOpenFilter()
+{
+  static long LastOpenFilter;
+
+  SettingsObject s;
+
+  LastOpenFilter = s.Read("LastOpenFilter", 1);
+
+  return LastOpenFilter;
+}
+
+static void Let_LastOpenFilter(long NewVal)
+{
+  SettingsObject s;
+
+  SettingsObject_Save("LastOpenFilter", NewVal);
+}
+
+static long Get_LastSaveFilter()
+{
+  static long LastSaveFilter;
+
+  SettingsObject s;
+
+  LastSaveFilter = s.Read("LastSaveFilter", 1);
+
+  return LastSaveFilter;
+}
+
+static void Let_LastSaveFilter(long NewVal)
+{
+  SettingsObject s;
+
+  SettingsObject_Save("LastSaveFilter", NewVal);
+}
+
+#endif
+
+static void CountDown(long HalfSeconds, int bDisplayBar)
+{
+  long i;
+  int k;
+  long dT, Delta;
+  long LeftPos, TopPos, RightPos, MaxWidth; // , MaxHeight&
+
+  dT = HalfSeconds * 500;
+  Delta = dT / 200;
+  LeftPos = cmbFile.left;
+  TopPos = cmbFile.top - shpProgress.Height - cmbFile.top / 8;
+  RightPos = lblFrameCount.left + lblFrameCount.Width;
+  MaxWidth = RightPos - LeftPos;
+  // MaxHeight = lblFrameCount.Top - TopPos + lblFrameCount.Height + 4
+  if (bDisplayBar)
+  {
+    shpProgress.Move(LeftPos, TopPos, 0); // , MaxHeight
+    shpProgress.Visible = True;
+  }
+
+  for (i = 1; i <= 200; i++)
+  {
+    // lblFrameCount = i
+    if (bDisplayBar)
+    {
+      if (i < 101)
+      {
+        shpProgress.Width = MaxWidth * i / 100;
+      }
+      else
+      {
+        k = MaxWidth * (i - 100) / 100;
+        shpProgress.Move(k, TopPos, RightPos - k);
+      }
+    }
+
+    T.DelayMS(Delta, False);
+  }
+
+  shpProgress.Visible = False;
+  // lblFrameCount = 0
+}
+
+static char *GetValidTempPath()
+{
+  static char *GetValidTempPath;
+
+  char *TP;
+  long nSize, L;
+
+  GetValidTempPath = "";
+  nSize = 255;
+  TP = String(nSize, Chr(32));
+  L = GetTempPath(nSize, TP);
+  if (nSize < L)
+  {
+    // buffer was too small, retry with a properly sized buffer:
+    nSize = L;
+    TP = String(nSize, Chr(32));
+    L = GetTempPath(nSize, TP);
+  }
+
+  TP = SlashLess(left(TP, L));
+  if ((0 == L) || (! IsDir(TP)))
+  {
+    // no valid temp path can be retrieved from the system --> create our own
+    TP = CAT(WithSlash(App.Path), "Temp");
+    if (! IsDir(TP))
+    {
+
+      // --- On Error Resume Next
+      MkDir(TP);
+      if (! IS_NOTHING(&Err, sizeof(Err)))
+      {
+        MESSAGE_BOX("an error occured"); // MsgBox "cannot create directory for temporary files " & TP, vbCritical, "MegaPlex - Error";
+        return GetValidTempPath;
+      }
+
+      // --- On Error GoTo 0
+
+    }
+  }
+
+  if (IsDir(TP))
+    GetValidTempPath = TP;
+
+  return GetValidTempPath;
+}
+
+#if 0
+
+static char *GetMyTempFileName()
+{
+  static char *GetMyTempFileName;
+
+  char *T;
+
+  (char *)T = Hex(hWnd);
+  while (Len(T) < 8)
+  {
+    T = CAT("0", T);
+  }
+
+  GetMyTempFileName = CAT("tmp0x", CAT((char *)T, ".mpx"));
+
+  return GetMyTempFileName;
+}
+
+static long GetHwndFromTempFileName(char *TmpFile)
+{
+  static long GetHwndFromTempFileName;
+
+  char *FN;
+  long LP;
+  int L;
+  char *NumString;
+
+  GetHwndFromTempFileName = 0;
+  FN = StripFileName(TmpFile);
+  LP = Len("tmp0x");
+  L = Len(TmpFile);
+  if (LP < L)
+    return GetHwndFromTempFileName;
+
+  L = L - LP;
+  NumString = right(FN, L - LP);
+  if (8 < L)
+    NumString = left(NumString, 8);
+
+  NumString = CAT("&H", NumString);
+  GetHwndFromTempFileName = Val(NumString);
+
+  return GetHwndFromTempFileName;
+}
+
+static void CleanTempDir(char *TmpDir)
+{
+  char *FN, *MFN;
+
+  MFN = GetMyTempFileName();
+  MayKill(CAT(WithSlash(TmpDir), MFN));
+  FN = Dir(CAT(WithSlash(TmpDir), "tmp0x*.mpx"));
+  while (FN != "")
+  {
+    if (STRING_IS_LIKE(FN, "tmp0x*.mpx"))
+    {
+      if (! InstanceStillRunning(FN))
+        MayKill(CAT(WithSlash(TmpDir), FN));
+    }
+
+    FN = Dir_Without_Args();
+  }
+}
+
+static boolean InstanceStillRunning(char *TmpFile)
+{
+  static boolean InstanceStillRunning;
+
+  long OtherHwnd, nSize, L;
+  char *Cap;
+
+  InstanceStillRunning = False;
+  OtherHwnd = GetHwndFromTempFileName(TmpFile);
+  nSize = 255;
+  Cap = String(nSize, Chr(32));
+  L = GetWindowText(OtherHwnd, Cap, nSize);
+  if ((L == 0) || (nSize < L))
+    return InstanceStillRunning;
+
+  if (STRING_IS_LIKE(Cap, CAT(AppTitle, "*")))
+    InstanceStillRunning = True;
+
+  return InstanceStillRunning;
+}
+
+#endif
+
+void DisplayLevel()
+{
+  int X, Y;
+
+  if (! Loaded)
+    return;
+
+  if (! LevelLoaded)
+    return;
+
+#if 0
+  SetDisplayRegion();
+#endif
+
+  DrawFrame(0);
+
+#if 0
+  if (! menBorder.Checked)
+    DrawFrame(1);
+#endif
+
+  if (bPlaying)
+  {
+    for (Y = DisplayMinY; Y <= DisplayMaxY; Y++)
+    {
+      for (X = DisplayMinX; X <= DisplayMaxX; X++)
+      {
+        DrawFieldNoAnimated(X, Y);
+      }
+    }
+
+    for (Y = DisplayMinY; Y <= DisplayMaxY; Y++)
+    {
+      for (X = DisplayMinX; X <= DisplayMaxX; X++)
+      {
+        DrawFieldAnimated(X, Y);
+      }
+    }
+
+  }
+  else
+  {
+    for (Y = DisplayMinY; Y <= DisplayMaxY; Y++)
+    {
+      for (X = DisplayMinX; X <= DisplayMaxX; X++)
+      {
+        DrawField(X, Y);
+      }
+    }
+  }
+}
+
+#if 0
+
+static void cmbFile_Click()
+{
+  CurPath = CAT(StripDir(OrigPath), CAT("/", cmbFile.List(cmbFile.ListIndex)));
+  OrigPath = CurPath;
+  FillLevelList(CurPath, LevelNumber);
+  if (STRING_IS_LIKE(OrigPath, "*.mpx") || STRING_IS_LIKE(OrigPath, "*.sp"))
+  {
+    menSave.Enabled = True;
+  }
+  else
+  {
+    menSave.Enabled = False;
+  }
+}
+
+static void cmbFile_KeyDown(int KeyCode, int Shift)
+{
+  picPane_KeyDown(KeyCode, Shift);
+}
+
+static void cmbFile_KeyUp(int KeyCode, int Shift)
+{
+  picPane_KeyUp(KeyCode, Shift);
+}
+
+static int GetFileNameToSave()
+{
+  static int GetFileNameToSave;
+
+  char *T;
+
+  (char *)T = StripFileName(OrigPath);
+  if (STRING_IS_LIKE(T, "*.dat") || STRING_IS_LIKE(T, "*.d##"))
+  {
+    T = "Level" & Format(LevelNumber, "#000");
+  }
+
+  GetFileNameToSave = T;
+
+  return GetFileNameToSave;
+}
+
+static void cmbLevel_Click()
+{
+  long InfoCount;
+  boolean Oldflag;
+  int Msg;
+  long LastIndex;
+  boolean bBlock;
+
+  if (bBlock)
+    return;
+
+  // //////////////////////////////////////////////////////////////////
+  if (ModifiedFlag)
+  {
+    VbMsgBoxResult Res;
+
+    Msg = "Save changes to " & GetFileNameToSave() & " ?";
+    Res = MsgBox(Msg, vbYesNoCancel, AppTitle & " - close level");
+    if (Res == vbCancel) // fallback
+    {
+      bBlock = True;
+
+      // --- On Error Resume Next
+      cmbLevel.ListIndex = LastIndex;
+      // --- On Error GoTo 0
+
+      bBlock = False;
+      Debug.Assert cmbLevel.ListIndex = LastIndex;
+      return;
+    }
+
+    if (Res == vbYes)
+    {
+      // Dim oldCurPath$
+      // oldCurPath = CurPath
+      if (FileExists(OrigPath) && menSave.Enabled)
+      {
+        menSave_Click();
+      }
+      else
+      {
+        if (! SaveAs()) // fallback
+        {
+          bBlock = True;
+
+          // --- On Error Resume Next
+          cmbLevel.ListIndex = LastIndex;
+          // --- On Error GoTo 0
+
+          bBlock = False;
+          Debug.Assert cmbLevel.ListIndex = LastIndex;
+          return;
+        }
+      }
+
+      // CurPath = oldCurPath
+    }
+
+    Let_ModifiedFlag(False);
+    CurPath = OrigPath;
+  }
+
+  // //////////////////////////////////////////////////////////////////
+  {
+    LevelNumber = cmbLevel.ListIndex + 1;
+    DemoFlag = False;
+    if (Loaded)
+    {
+      Oldflag = NoDisplayFlag;
+      NoDisplayFlag = False;
+      subFetchAndInitLevel();
+      if ((0 < SignatureDelay) && ! (WindowState == vbMinimized))
+      {
+        Msg = LInfo.LevelTitle & vbNewLine & "(" & FieldWidth & " x " & FieldHeight & ")";
+        if (DemoAvailable && bSignatureAvailable)
+          Msg = Msg & vbNewLine & vbNewLine & gSignature;
+
+        SignatureForm.Signature = Msg;
+        SignatureForm.DelayMS = SignatureDelay;
+        int X, Y;
+
+        X = left + (Width - SignatureForm.Width) / 2;
+        Y = top + (Height - SignatureForm.Height) / 2;
+        SignatureForm.Move X, Y;
+        SignatureForm.Show vbModeless, Me;
+        Me.SetFocus;
+      }
+
+      lblStatus = "MegaPlex";
+      lblFrameCount = GetTotalFramesOfDemo();
+      if (EditFlag)
+        EdAll();
+
+      ReStretch(Stretch);
+      // picPane_Paint
+      Stage.Blt();
+      NoDisplayFlag = Oldflag;
+      LastIndex = cmbLevel.ListIndex;
+    }
+
+  }
+  menPlayDemo.Enabled = DemoAvailable;
+  cmdPlayDemo.Enabled = DemoAvailable;
+}
+
+static void cmblevel_KeyDown(int KeyCode, int Shift)
+{
+  if (GameLoopRunning != 0)
+    return;
+
+  switch (KeyCode)
+  {
+    case vbKeySpace:
+      if (menPlay.Enabled == True)
+        menPlay_Click();
+
+      break;
+
+    default:
+      picPane_KeyDown(KeyCode, Shift);
+      break;
+  }
+}
+
+static void cmbLevel_KeyUp(int KeyCode, int Shift)
+{
+  picPane_KeyUp(KeyCode, Shift);
+}
+
+static void cmdPause_Click()
+{
+  menPause_Click();
+}
+
+static void cmdPause_MouseUp(int Button, int Shift, float X, float Y)
+{
+  FocusTim.Enabled = True;
+}
+
+static void cmdPlay_Click()
+{
+  if (menPlay.Enabled)
+    menPlay_Click();
+}
+
+static void cmdPlay_MouseUp(int Button, int Shift, float X, float Y)
+{
+  FocusTim.Enabled = True;
+}
+
+static void cmdPlayAll_Click()
+{
+  menPlayAll_Click();
+}
+
+static void cmdPlayAll_MouseUp(int Button, int Shift, float X, float Y)
+{
+  FocusTim.Enabled = True;
+}
+
+static void cmdPlayDemo_Click()
+{
+  menPlayDemo_Click();
+}
+
+static void cmdPlayDemo_MouseUp(int Button, int Shift, float X, float Y)
+{
+  FocusTim.Enabled = True;
+}
+
+static void cmdRecordDemo_Click()
+{
+  if (menRec.Enabled)
+    menRec_Click();
+}
+
+static void cmdRecordDemo_MouseUp(int Button, int Shift, float X, float Y)
+{
+  FocusTim.Enabled = True;
+}
+
+static void cmdStop_Click()
+{
+  if (menStop.Enabled)
+    menStop_Click();
+}
+
+static void cmdStop_MouseUp(int Button, int Shift, float X, float Y)
+{
+  FocusTim.Enabled = True;
+}
+
+static void FocusTim_Timer()
+{
+  FocusTim.Enabled = False;
+
+  // --- On Error Resume Next
+  picPane.SetFocus;
+}
+
+static void Form_KeyDown(int KeyCode, int Shift)
+{
+  picPane_KeyDown(KeyCode, Shift);
+}
+
+static void Form_KeyUp(int KeyCode, int Shift)
+{
+  picPane_KeyUp(KeyCode, Shift);
+}
+
+#endif
+
+static void Form_Load()
+{
+#if 0
+
+  long i;
+  SettingsObject s;
+
+#endif
+
+  Loaded = False;
+  DemoFlag = 0;
+  PanelSeq = 0;
+  EditFlag = False;
+  EditMode = edMove;
+  // FMark = New MarkerObject; // (handle this later, if needed)
+  InitGlobals();
+
+#if 0
+
+  LoadMenus();
+
+  TmpPath = GetValidTempPath();
+  if (TmpPath == "")
+    exit(-1);
+
+  CleanTempDir(TmpPath);
+  TmpPath = CAT(WithSlash(TmpPath), GetMyTempFileName());
+  GetSettings();
+  ShowPanel = 1;
+
+  InitDirectX(hWnd, picPane.hWnd);
+
+  //  AllowRedDiskCheat = 1
+  MpxBmp = CAT(App.Path, "/mpx.bmp");
+  // // Set NormalSprites = New DDSpriteBuffer // (handle this later, if needed)
+  // NormalSprites.CreateFromFile MPXBMP, 16, 16
+
+  Field = REDIM_2D(sizeof(int), 0, 2 + 1 - 1, 0, 2 + 1 - 1);
+
+  picViewPort.ScaleMode = vbPixels;
+
+  PauseMode = 0;
+  //  BaseWidth = 16
+  menBorder_Click();
+  Loaded = True;
+  ReStretch(Stretch);
+  LoadKeyIndicators();
+
+  Show;
+
+  FillFileList(CurPath);
+  if (s.Read("ShowSplash", True))
+  {
+    // frmSplash.EnableTimer
+    frmSplash.Show vbModal, Me;
+  }
+
+#endif
+}
+
+#if 0
+
+static void FillLevelList(char *Path, int LevelIndex)
+{
+  long FNum, LevLen, i, iMax;
+  char *TFile;
+
+  cmbLevel.Clear;
+  if (! FileExists(Path))
+    return;
+
+  if ((STRING_IS_LIKE(Path, "*.D??")) || (STRING_IS_LIKE(Path, "*.sp")))
+  {
+    FNum = FreeFile();
+    LevLen = 1536;
+    FNum = fopen(Path, "rb");
+    {
+      i = 0;
+      FILE_GET(FNum, (long)1441 + i * LevLen, &LInfo, sizeof(LInfo));
+      cmbLevel.AddItem Format(i + 1, "#000") & "   " & LInfo.LevelTitle, i;
+      if (STRING_IS_LIKE(Path, "*.D??"))
+      {
+        while (!(EOF(FNum)))
+        {
+          i = i + 1;
+          FILE_GET(FNum, (long)1441 + i * LevLen, &LInfo, sizeof(LInfo));
+          if (EOF(FNum))
+            break;
+
+          cmbLevel.AddItem Format(i + 1, "#000") & "   " & LInfo.LevelTitle, i;
+        }
+      }
+
+      if (LevelIndex <= i && 0 < LevelIndex)
+        i = LevelIndex - 1;
+      else
+        i = 0;
+
+      cmbLevel.ListIndex = i;
+    }
+    fclose(FNum);
+  }
+  else if (STRING_IS_LIKE(Path, "*.mpx"))
+  {
+    FNum = FreeFile();
+    LevLen = 1536;
+    FNum = fopen(Path, "rb");
+    {
+      i = 0;
+      if (MpxOpen(Path))
+      {
+        for (i = 1; i <= LevelCount; i++)
+        {
+          if (! MpxLoadLInfo(CInt(i)))
+            break;
+
+          cmbLevel.AddItem Format(i, "#000") & "   " & LInfo.LevelTitle, i - 1;
+        }
+
+        MpxClose();
+      }
+
+      if (LevelIndex < i && 0 < LevelIndex)
+        i = LevelIndex - 1;
+      else
+        i = 0;
+
+      if (i < cmbLevel.ListCount)
+        cmbLevel.ListIndex = i;
+
+    }
+    fclose(FNum);
+  }
+}
+
+static void FillFileList(char *Path)
+{
+  long FNum, LevLen, i;
+  int nDemoCount;
+  char *TFile, *TPath, *OFile;
+
+  cmbFile.Clear;
+  i = 0;
+  nDemoCount = 0;
+  TPath = WithSlash(StripDir(Path));
+  OFile = StripFileName(Path);
+  TFile = Dir(TPath & "*.D??");
+  while (TFile != "")
+  {
+    if (FileLen(TPath & TFile) == 170496)
+    {
+      cmbFile.AddItem TFile;
+    }
+
+    TFile = Dir;
+  }
+
+  TFile = Dir(TPath & "*.SP");
+  while (TFile != "")
+  {
+    nDemoCount = nDemoCount + 1;
+    cmbFile.AddItem TFile;
+    TFile = Dir;
+  }
+
+  TFile = Dir(TPath & "*.mpx");
+  while (TFile != "")
+  {
+    nDemoCount = nDemoCount + 1;
+    cmbFile.AddItem TFile;
+    TFile = Dir;
+  }
+
+  i = cmbFile.ListCount - 1;
+  if (0 < cmbFile.ListCount)
+  {
+    do
+    {
+      if ((cmbFile.List(i) Like OFile) || i == 0)
+        break;
+
+      i = i - 1;
+    }
+    while (!(i < 1));
+
+    cmbFile.ListIndex = i;
+  }
+
+  DemosAvailable = (1 < nDemoCount);
+  menPlayAll.Enabled = DemosAvailable;
+  cmdPlayAll.Enabled = DemosAvailable;
+}
+
+static void LoadMenus()
+{
+  long i;
+
+  // speeds
+  menFaster.Enabled = False;
+  menSlower.Enabled = False;
+  InitSpeeds();
+  for (i = 1; i <= nSpeedCount; i++)
+  {
+    if (1 < i)
+    {
+      Load menPlaySpeed(i);
+      Load menDemoSpeed(i);
+    }
+
+    menPlaySpeed(i).Caption = GetSpeedDescriptionFPS(SpeedsByDelayUS[i]);
+    menDemoSpeed(i).Caption = GetSpeedDescriptionFPS(SpeedsByDelayUS[i]);
+  }
+
+  // zoom
+  menStretch(1).Caption = Format(0.25, "#0.00") & ";
+  1";
+  if (Stretch == 0.25)
+    menStretch(1).Checked = True;
+
+  for (i = 2; i <= 20; i++)
+  {
+    Load menStretch(i);
+    menStretch(i).Caption = Format(0.25 * i, "#0.00") & ";
+    1";
+    menStretch(i).Checked = ((i * 0.25) == Stretch);
+  }
+
+  menSp.Enabled = False;
+}
+
+//
+// Function DisplayShift&()
+// Dim X&, Y&, A&, B&, iX&, iiX&, LD&
+// Dim Sprite&
+//  DisplayShift = 0
+//    For A = 0 To picPane.ScaleWidth
+//      For Y = DisplayMinY To DisplayMaxY
+//        For X = DisplayMinX To DisplayMaxX
+//          iX = StretchWidth * X + A
+//          Sprite = Field(X, Y).SpritePos
+//          If picPane.ScaleWidth < (iX + 1) Then
+//            iX = iX - picPane.ScaleWidth
+//          Else
+//            If picPane.ScaleWidth < (iX + 1 + BaseWidth) Then
+//              iiX = iX - picPane.ScaleWidth
+//              Sprites.BitBltSprite picPane.hdc, iiX, StretchWidth * Y, Sprite
+//            End If
+//          End If
+//          Sprites.BitBltSprite picPane.hdc, iX, StretchWidth * Y, Sprite
+//        Next X
+//      Next Y
+//      DisplayShift = DisplayShift + 1
+//      'DoEvents
+//    Next A
+// End Function
+
+static void Form_Paint()
+{
+  // Debug.Print "Form_Paint()"
+}
+
+static void Form_Resize()
+{
+  long Space, NW, NH;
+  int Tmp;
+
+  if (WindowState == vbMinimized || ! Loaded)
+    return;
+
+  Space = Panel.left;
+  //  NW = ScaleWidth - 2 * Space: If NW < 0 Then NW = 0
+  //  NH = ScaleHeight - 3 * Space - cmbLevel.Height: If NH < 0 Then NH = 0
+  //  picViewPort.Move Space, Space, NW, NH
+  Tmp = (ShowPanel != 0 ?  ScaleHeight - Panel.Height :  ScaleHeight - Panel.Height);
+  if (Tmp < 0)
+    Tmp = 0;
+
+  picViewPort.Move 0, 0, ScaleWidth, Tmp;
+  //  Tmp = 2 * Space + picViewPort.Height
+  Panel.top = Tmp;
+  Panel.left = (ScaleWidth - Panel.Width) / 2;
+  //  'cmdNormal.Top = 2 * Space + picViewPort.Height
+  //  cmbLevel.Top = Tmp
+  //  lblRedDiskCount.Top = Tmp
+  //  lblInfoCount.Top = Tmp
+  //  picKeys.Top = Tmp
+  //  lblFrameCount.Top = Tmp
+  //  cmdPlayAll.Top = Tmp
+}
+
+#endif
+
+static void DrawFrame(int Delta)
+{
+  int i, LX, tY, RX, BY;
+
+  LX = -1 + Delta;
+  tY = -1 + Delta;
+  RX = FieldWidth - Delta;
+  BY = FieldHeight - Delta;
+  DrawSprite(LX, tY, posFrameCorner);
+  DrawSprite(LX, BY, posFrameCorner);
+  DrawSprite(RX, tY, posFrameCorner);
+  DrawSprite(RX, BY, posFrameCorner);
+  for (i = LX + 1; i <= RX - 1; i++)
+  {
+    DrawSprite(i, tY, posFrameHorizontal);
+    DrawSprite(i, BY, posFrameHorizontal);
+  }
+
+  for (i = tY + 1; i <= BY - 1; i++)
+  {
+    DrawSprite(LX, i, posFrameVertical);
+    DrawSprite(RX, i, posFrameVertical);
+  }
+}
+
+static void RestoreFrame()
+{
+  int i, LX, tY, RX, BY;
+
+  LX = 0;
+  tY = 0;
+  RX = FieldWidth - 1;
+  BY = FieldHeight - 1;
+  for (i = LX; i <= RX; i++)
+  {
+    DrawField(i, tY);
+    DrawField(i, BY);
+  }
+
+  for (i = tY + 1; i <= BY - 1; i++)
+  {
+    DrawField(LX, i);
+    DrawField(RX, i);
+  }
+}
+
+#if 0
+
+static void Form_Unload(int Cancel)
+{
+  EndFlag = True;
+  ExitToMenuFlag = 1;
+  if (cmdPlayAll.STRING_IS_LIKE(Caption, "Quit*"))
+  {
+    cmdPlayAll_Click();
+  }
+
+  if (menEdit.Checked)
+    menEdit_Click();
+
+  if (ModifiedFlag)
+  {
+    char *Msg;
+    VbMsgBoxResult Res;
+
+    Msg = "Save changes to " & GetFileNameToSave() & " ?";
+    Res = MsgBox(Msg, vbYesNoCancel, AppTitle & " - closing");
+    if (Res == vbCancel)
+    {
+      Cancel = -1;
+      return;
+    }
+
+    if (Res == vbYes)
+    {
+      if (FileExists(OrigPath) && menSave.Enabled)
+      {
+        menSave_Click();
+      }
+      else
+      {
+        menSaveAs_Click();
+      }
+    }
+  }
+
+  if (FileExists(TmpPath) || ModifiedFlag)
+  {
+    MayKill(TmpPath);
+    CurPath = OrigPath;
+  }
+
+  ReleaseDirectDraw();
+  SaveSettings();
+  End;
+}
+
+static void fpsTim_Timer()
+{
+  currency TickDiff;
+  int count5;
+
+  count5 = count5 + 1;
+  if (4 < count5)
+  {
+    TickDiff = T.TickDiffUS(LastTick);
+    lblFps.Caption = CLng(Round((1000000 * (TimerVar - LastFrame)) / (TickDiff), 0));
+    LastFrame = TimerVar;
+    LastTick = T.TickNow();
+    count5 = 0;
+  }
+
+  // If NoDisplayFlag Then lblFrameCount = TimerVar
+  lblFrameCount = TimerVar;
+}
+
+static void menAbout_Click()
+{
+  frmSplash.Show vbModal, Me;
+}
+
+static void menAutoScroll_Click()
+{
+  {
+    menAutoScroll.Checked = ! menAutoScroll.Checked;
+    AutoScrollFlag = menAutoScroll.Checked;
+  }
+}
+
+static void menBorder_Click()
+{
+  if (menBorder.Checked)
+  {
+    menBorder.Checked = False;
+    DisplayMinX = 1;
+    DisplayMaxX = FieldWidth - 2;
+    DisplayWidth = FieldWidth;
+    DisplayMinY = 1;
+    DisplayMaxY = FieldHeight - 2;
+    DisplayHeight = FieldHeight;
+    if (Loaded && LevelLoaded)
+      DrawFrame(1);
+
+  }
+  else
+  {
+    menBorder.Checked = True;
+    DisplayMinX = 0;
+    DisplayMaxX = FieldWidth - 1;
+    DisplayWidth = FieldWidth + 2;
+    DisplayMinY = 0;
+    DisplayMaxY = FieldHeight - 1;
+    DisplayHeight = FieldHeight + 2;
+    if (Loaded && LevelLoaded)
+      RestoreFrame();
+  }
+
+  ReStretch(Stretch);
+  // DisplayLevel True
+}
+
+void SetDisplayRegion()
+{
+  if (! menBorder.Checked)
+  {
+    DisplayMinX = 1;
+    DisplayMaxX = FieldWidth - 2;
+    DisplayWidth = FieldWidth;
+    DisplayMinY = 1;
+    DisplayMaxY = FieldHeight - 2;
+    DisplayHeight = FieldHeight;
+    if (LevelLoaded)
+      DrawFrame(1);
+
+  }
+  else
+  {
+    DisplayMinX = 0;
+    DisplayMaxX = FieldWidth - 1;
+    DisplayWidth = FieldWidth + 2;
+    DisplayMinY = 0;
+    DisplayMaxY = FieldHeight - 1;
+    DisplayHeight = FieldHeight + 2;
+    if (LevelLoaded)
+      RestoreFrame();
+  }
+}
+
+static void menCopy_Click()
+{
+  FMark.Copy;
+}
+
+void menEdit_Click()
+{
+  long L;
+
+  if (menEdit.Checked)
+  {
+    menEdit.Checked = False;
+    // leave edit mode
+    if (EditFlag)
+      Unload ToolBox;
+
+    EditFlag = False;
+    UnEdAll();
+    FMark.ShowMarker False;
+    picViewPort.MousePointer = 0;
+    if (ModifiedFlag)
+    {
+      if (! STRING_IS_LIKE(CurPath, TmpPath))
+      {
+        OrigPath = CurPath;
+        CurPath = TmpPath;
+      }
+
+      SaveMPX(TmpPath);
+    }
+
+    DisplayLevel();
+    Stage.Blt();
+  }
+  else
+  {
+    if (! LevelLoaded)
+    {
+      Beep();
+      return;
+    }
+
+    if (ModifiedFlag)
+    {
+      if (! STRING_IS_LIKE(CurPath, TmpPath))
+      {
+        OrigPath = CurPath;
+        CurPath = TmpPath;
+      }
+
+      SaveMPX(TmpPath);
+    }
+
+    subFetchAndInitLevel();
+    menEdit.Checked = True;
+    // enter edit mode
+    EditFlag = True;
+    // ScaleMode = vbTwips
+    ToolBox.Move (Width - ToolBox.Width) / 2, Height - ToolBox.Height;
+    // ScaleMode = vbPixels
+    //    L = GetWindowLong(ToolBox.hWnd, GWL_STYLE)
+    //    L = L And (Not WS_POPUP)
+    //    L = L Or WS_CHILD
+    //    SetWindowLong ToolBox.hWnd, GWL_STYLE, L
+    //    SetParent ToolBox.hWnd, hWnd
+    ToolBox.Show vbModeless, Me;
+    EdAll();
+    DisplayLevel();
+    Stage.Blt();
+    FMark.ShowMarker True;
+  }
+}
+
+static void menEnOff_Click()
+{
+  menEnOn.Checked = False;
+  menEnOff.Checked = True;
+  SpSaveMenu();
+  SpLoadMenu();
+}
+
+static void menEnOn_Click()
+{
+  menEnOn.Checked = True;
+  menEnOff.Checked = False;
+  SpSaveMenu();
+  SpLoadMenu();
+}
+
+static void menExit_Click()
+{
+  Unload Me;
+}
+
+static void menFaster_Click()
+{
+  int i;
+
+  if (! bPlaying)
+  {
+    Debug.Assert(False);
+    return;
+  }
+
+  if (DemoFlag != 0) // demoplayback
+  {
+    i = GetSpeedIndex(DeltaTDemo);
+    i = i - 1;
+    If i < 2 Then i = 2;
+    menDemoSpeed_Click (i);
+  }
+  else
+  {
+    i = GetSpeedIndex(DeltaTPlay);
+    i = i - 1;
+    If i < 2 Then i = 2;
+    menPlaySpeed_Click (i);
+  }
+}
+
+static void menSlower_Click()
+{
+  int i;
+
+  if (! bPlaying)
+  {
+    Debug.Assert(False);
+    return;
+  }
+
+  if (DemoFlag != 0) // demoplayback
+  {
+    i = GetSpeedIndex(DeltaTDemo);
+    i = i + 1;
+    If nSpeedCount < i Then i = nSpeedCount;
+    menDemoSpeed_Click (i);
+  }
+  else
+  {
+    i = GetSpeedIndex(DeltaTPlay);
+    i = i + 1;
+    If nSpeedCount < i Then i = nSpeedCount;
+    menPlaySpeed_Click (i);
+  }
+}
+
+void menPlaySpeed_Click(int Index)
+{
+  int i;
+
+  //  If NoDisplayFlag And (GameLoopRunning <> 0) Then
+  //    NoDisplayFlag = False
+  //    DisplayLevel
+  //  End If
+  //  NoDisplayFlag = False
+  for (i = menPlaySpeed.LBound; i <= menPlaySpeed.UBound; i++)
+  {
+    {
+      menPlaySpeed(i).Checked = (Index == i);
+    }
+  }
+
+  BlockingSpeed = False;
+  DeltaTPlay = SpeedsByDelayUS[Index];
+  UpdateDeltaT();
+  //  If DeltaTPlay < 0 Then
+  //    Stage.Blt
+  //    DeltaT = 0
+  //    NoDisplayFlag = True
+  //  End If
+}
+
+void menDemoSpeed_Click(int Index)
+{
+  int i;
+
+  //  If NoDisplayFlag And (GameLoopRunning <> 0) Then
+  //    NoDisplayFlag = False
+  //    DisplayLevel
+  //  End If
+  NoDisplayFlag = False;
+  for (i = menDemoSpeed.LBound; i <= menDemoSpeed.UBound; i++)
+  {
+    {
+      menDemoSpeed(i).Checked = (Index == i);
+    }
+  }
+
+  BlockingSpeed = False;
+  DeltaTDemo = SpeedsByDelayUS[Index];
+  UpdateDeltaT();
+  //  If DeltaTPlay < 0 Then
+  //    Stage.Blt
+  //    DeltaT = 0
+  //    NoDisplayFlag = True
+  //  End If
+}
+
+static void UpdateDeltaT()
+{
+  if (! bPlaying)
+    return;
+
+  DeltaT = (DemoFlag != 0 ?  DeltaTDemo :  DeltaTDemo);
+  if (DeltaT < 0)
+  {
+    Stage.Blt();
+    DeltaT = 0;
+    NoDisplayFlag = True;
+  }
+  else
+  {
+    if (NoDisplayFlag && GameLoopRunning != 0)
+    {
+      NoDisplayFlag = False;
+      DisplayLevel();
+    }
+    else
+    {
+      NoDisplayFlag = False;
+    }
+  }
+}
+
+static void menGravOff_Click()
+{
+  menGravOn.Checked = False;
+  menGravOff.Checked = True;
+  SpSaveMenu();
+  SpLoadMenu();
+}
+
+static void menGravOn_Click()
+{
+  menGravOn.Checked = True;
+  menGravOff.Checked = False;
+  SpSaveMenu();
+  SpLoadMenu();
+}
+
+static void menNew_Click()
+{
+  NewForm.Show vbModal, Me;
+  CreateLevel(FieldWidth, FieldHeight);
+  ReStretch(Stretch);
+}
+
+static void menNewStd_Click()
+{
+  CreateLevel(60, 24);
+  ReStretch(Stretch);
+}
+
+static void menOpen_Click()
+{
+  long LFilt;
+
+  {
+    // cmDlg.DefaultExt = "sp"
+
+    /*
+
+    (prevent compiler warning here due to suspected use of trigraph)
+
+    cmDlg.Filter = "All Levels (*.DAT;*.D??;*.sp;*.mpx)|*.DAT;*.D??;*.sp;*.mpx|MegaPlex Levels (*.mpx)|*.mpx" & "|Supaplex Level Sets (*.DAT;*.D??)|*.DAT;*.D??|SpeedFix Demos (*.sp)|*.sp";
+    */
+
+    LFilt = LastOpenFilter;
+    cmDlg.FilterIndex = (0 < LFilt & LFilt < 5 ?  LFilt :  LFilt);
+    if (FileExists(CurPath))
+      cmDlg.InitDir = WithSlash(StripDir(CurPath));
+
+    cmDlg.flags = cdlOFNHideReadOnly | cdlOFNLongNames;
+  }
+
+  // --- On Error GoTo menOpenEH
+  cmDlg.ShowOpen;
+  // --- On Error GoTo 0
+
+  LFilt = cmDlg.FilterIndex;
+  LastOpenFilter = LFilt;
+  CurPath = cmDlg.FileName;
+  OrigPath = CurPath;
+  FillFileList (CurPath);
+
+menOpenEH:
+}
+
+static void menOptions_Click()
+{
+  OptionsForm oFrm;
+
+  oFrm.Show vbModal, Me;
+  SaveSettings();
+  picViewPort_Resize();
+}
+
+static void menPanel_Click()
+{
+  {
+    PanelVisible = ! menPanel.Checked;
+  }
+}
+
+void Let_PanelVisible(boolean NewVal)
+{
+  boolean HidePanel;
+
+  if (HidePanel != NewVal)
+    return;
+
+  HidePanel = ! NewVal;
+  PanelTim.Enabled = True;
+}
+
+static void DrawPauseLayer(long Layer)
+{
+  DirectDrawPalette Pal;
+  PALETTEENTRY *Val;
+  long i;
+
+  // Dim X&, Y&
+  //  For Y = 0 To bmpStage.Height Step BaseWidth
+  //    For X = 0 To bmpStage.Width Step BaseWidth
+  //      Pause.TransparentDraw bmpStageHDC, X, Y, Layer
+  //    Next X
+  //  Next Y
+  //  With Stage.Surface
+  //    Set Pal = .GetPalette
+  //    for i=1 to pal.GetEntries(
+  //  Stage.Surface.SetPalette
+}
+
+static void menPaste_Click()
+{
+  FMark.Paste;
+  DisplayLevel();
+  Stage.Blt();
+}
+
+static void menPause_Click()
+{
+  StdPicture OldPic;
+  char *OldText;
+
+  PauseMode = (PauseMode != 0 ?  0 :  0);
+  if (PauseMode != 0)
+  {
+    if (IS_NOTHING(&OldPic, sizeof(OldPic)))
+      OldPic = cmdPause.Picture;
+
+    cmdPause.Picture = cmdPause.DownPicture;
+    OldText = lblStatus.Caption;
+    lblStatus = "Paused ...";
+  }
+  else
+  {
+    cmdPause.Picture = OldPic;
+    lblStatus.Caption = OldText;
+  }
+}
+
+static void menPlayAll_Click()
+{
+  long iMin, iMax, i;
+  int FNum;
+  char *LogPath, *OutStr, *ReRecPath, *SPPath;
+  boolean bEqual;
+  boolean QuitFlag;
+
+  if (cmdPlayAll.STRING_IS_LIKE(Caption, "Play) All Demos")
+  {
+    cmdPlayAll.Caption = "Quit All";
+    menPlayAll.Caption = "Quit All";
+    FocusTim.Enabled = True;
+    QuitFlag = False;
+    iMin = 0;
+    iMax = cmbFile.ListCount - 1;
+    LogPath = StripDir(CurPath) & "/Error.Log";
+    if (Dir(LogPath) != "")
+      Kill(LogPath);
+
+    for (i = iMin; i <= iMax; i++)
+    {
+      cmbFile.ListIndex = i;
+      //      If CurPath Like "*.sp" Or CurPath Like "*.mpx" Then
+      if (DemoAvailable)
+      {
+        SPPath = CurPath;
+        ReRecPath = SPPath & ".ReRec";
+        menPlayDemo_Click();
+        // SaveSP ReRecPath
+        // bEqual = FilesEqual(ReRecPath, SPPath)
+        // If bEqual Then MayKill ReRecPath
+        bEqual = True;
+        OutStr = cmbFile.List(i) & " -> ";
+        //
+        if (Val(lblFrameCount) != GetTotalFramesOfDemo())
+        {
+          OutStr = OutStr & "Error in GetTotalFramesOfDemo()! ";
+          Debug.Assert(False);
+        }
+
+        //
+        if ((LevelStatus == 1) && bEqual)
+        {
+          OutStr = OutStr & "Success";
+        }
+        else if (QuitFlag)
+        {
+          OutStr = OutStr & "All Demos (float)Canceled";
+        }
+        else
+        {
+          if (LevelStatus != 1)
+          {
+            OutStr = OutStr & "### Level Failed ### (TimerVar == " & TimerVar & ")";
+          }
+
+          if (! bEqual)
+          {
+            OutStr = OutStr & "### ReRecording is binary different ###";
+          }
+        }
+
+        FNum = FreeFile();
+        FNum = fopen(LogPath, "ab");
+        Print #FNum, OutStr;
+        fclose(FNum);
+        if (QuitFlag)
+          break;
+      }
+    }
+
+    cmdPlayAll.Caption = "Play All Demos";
+    menPlayAll.Caption = "Play All Demos";
+    SettingsObject Settings;
+
+    MySignature = Settings.Read("MySignature", "");
+    FirstDemoByte = 0x81;
+  }
+  else
+  {
+    QuitFlag = True;
+    if (menStop.Enabled)
+      menStop_Click();
+  }
+}
+
+static void menRemSP_Click()
+{
+  RemoveSP();
+  SpLoadMenu();
+}
+
+static void menRestoreBorder_Click()
+{
+  RestoreBorder();
+}
+
+static void menSave_Click()
+{
+  if (! ModifiedFlag)
+    return;
+
+  if (STRING_IS_LIKE(CurPath, TmpPath))
+    CurPath = OrigPath;
+
+  if (STRING_IS_LIKE(CurPath, "") || STRING_IS_LIKE(CurPath, "*.dat"))
+  {
+    menSaveAs_Click();
+    return;
+  }
+
+  if (STRING_IS_LIKE(CurPath, "*.sp"))
+  {
+    menSaveAs_Click();
+    return;
+  }
+
+  if (! FileExists(CurPath) || STRING_IS_LIKE(CurPath, "Untitled"))
+  {
+    menSaveAs_Click();
+    return;
+  }
+
+  SaveMPX(CurPath);
+  Let_ModifiedFlag(False);
+}
+
+static void menSaveAs_Click()
+{
+  if (SaveAs())
+    FillFileList (CurPath);
+}
+
+static boolean SaveAs()
+{
+  static boolean SaveAs;
+
+  char *FN;
+  SettingsObject s;
+
+  SaveAs = False;
+  {
+    // cmDlg.DefaultExt = "sp"
+    cmDlg.Filter = "MegaPlex Level (*.mpx)|*.mpx|SpeedFix Demo (*.sp)|*.sp";
+    cmDlg.FilterIndex = LastSaveFilter;
+    // If OrigPath Like "*.sp" Then cmDlg.FilterIndex = 1 Else cmDlg.FilterIndex = 0
+    if (FileExists(OrigPath))
+    {
+      cmDlg.InitDir = WithSlash(StripDir(OrigPath));
+      cmDlg.InitDir = s.Read("LastSaveDir", cmDlg.InitDir);
+      cmDlg.FileName = StripExtensionlessFileName(GetFileNameToSave());
+    }
+
+    cmDlg.flags = cdlOFNHideReadOnly | cdlOFNLongNames;
+  }
+
+  // --- On Error GoTo SaveAsEH
+  cmDlg.ShowSave;
+  // --- On Error GoTo 0
+
+  LastSaveFilter = cmDlg.FilterIndex;
+  FN = cmDlg.FileName;
+  SettingsObject_Save("LastSaveDir", WithSlash(StripDir(FN)));
+  if (STRING_IS_LIKE(FN, "*.sp"))
+  {
+    SaveSP(FN);
+  }
+  else if (STRING_IS_LIKE(FN, "*.mpx"))
+  {
+    SaveMPX(FN);
+  }
+
+  Let_ModifiedFlag(False);
+  SaveAs = True;
+
+SaveAsEH:
+
+  return SaveAs;
+}
+
+static void menSelectAll_Click()
+{
+  FMark.SetPoint1 0, 0;
+  FMark.SetPoint2 FieldWidth - 1, FieldHeight - 1;
+}
+
+static void menShowLInfo_Click()
+{
+  char *Msg;
+
+  Msg = LInfo.LevelTitle & vbNewLine & "(" & FieldWidth & " x " & FieldHeight & ")";
+  if (DemoAvailable && bSignatureAvailable)
+    Msg = Msg & vbNewLine & vbNewLine & gSignature;
+
+  SignatureForm.Signature = Msg;
+  SignatureForm.DelayMS = 5000;
+  int X, Y;
+
+  X = left + (Width - SignatureForm.Width) / 2;
+  Y = top + (Height - SignatureForm.Height) / 2;
+  SignatureForm.Move X, Y;
+  SignatureForm.Show vbModeless, Me;
+  Me.SetFocus;
+}
+
+static void menSoundFX_Click()
+{
+  {
+    menSoundFX.Checked = ! menSoundFX.Checked;
+    FXOnFlag = (menSoundFX.Checked ?  -1 :  -1);
+  }
+}
+
+#endif
+
+// static void menPlay_Click()
+void menPlay_Click()
+{
+
+#if 0
+
+  boolean OldEditFlag;
+
+  // Trace "MainForm", "--> menPlay_Click()"
+  if (! LevelLoaded)
+  {
+    Beep();
+    return;
+  }
+
+  SignatureForm.DelayMS = 1;
+  menPlay.Enabled = False;
+  menPause.Enabled = True;
+  menStop.Enabled = True;
+  cmdPlay.Enabled = False;
+  cmdPause.Enabled = True;
+  cmdStop.Enabled = True;
+  cmdPlayDemo.Enabled = False;
+  menPlayDemo.Enabled = False;
+  cmdRecordDemo.Enabled = False;
+  menRec.Enabled = False;
+  menFaster.Enabled = True;
+  menSlower.Enabled = True;
+  if (cmdPlayAll.STRING_IS_LIKE(Caption, "Play*"))
+  {
+    cmdPlayAll.Enabled = False;
+    menPlayAll.Enabled = False;
+  }
+
+  cmbFile.Enabled = False;
+  cmbLevel.Enabled = False;
+  OldEditFlag = EditFlag;
+  if (EditFlag)
+    menEdit_Click();
+
+  menEditMain.Enabled = False;
+  if (DemoFlag == 0 && RecordDemoFlag == 0)
+    lblStatus = "Playing";
+
+  lblFrameCount = 0;
+
+#endif
+
+  LastFrame = 0;
+  LastTick = T.TickNow;
+
+#if 0
+
+  fpsTim.Enabled = True;
+
+#endif
+
+  // DimPrimary 100
+  bPlaying = True;
+
+#if 0
+
+  UpdateDeltaT();
+
+#endif
+
+  subFetchAndInitLevelB();
+  // Trace "MainForm", "CountDown 1"
+  CountDown(2, (0 == DemoFlag));
+  // Trace "MainForm", "Call GoPlay"
+  GoPlay();
+  // Trace "MainForm", "GoPlay returned"
+
+#if 0
+
+  if (LevelStatus == 1)
+  {
+    lblStatus = "(float)Success";
+  }
+  else
+  {
+    lblStatus = "Try (float)again";
+  }
+
+#endif
+
+  // Trace "MainForm", "CountDown 1"
+  CountDown(1, False);
+  RecordDemoFlag = 0;
+
+#if 0
+  ShowKey(0);
+#endif
+
+  bPlaying = False;
+  // Trace "MainForm", "Call subFetchAndInitLevel"
+  subFetchAndInitLevel();
+  // Trace "MainForm", "subFetchAndInitLevel returned"
+  Stage.Blt();
+
+#if 0
+
+  menEditMain.Enabled = True;
+  if (OldEditFlag)
+    menEdit_Click();
+
+  // Trace "MainForm", "<-- menPlay_Click()"
+
+#endif
+
+}
+
+#if 0
+
+static void menPlayDemo_Click()
+{
+  DemoFlag = 1;
+  RecordDemoFlag = 0;
+  lblStatus = "Demo Playback";
+  menPlay_Click();
+  if (LevelStatus != 1)
+    lblStatus = "Demo Failed";
+
+  DemoFlag = 0;
+}
+
+static void menRec_Click()
+{
+  Trace("MainForm", "--> menRec_Click()");
+  if (! LevelLoaded)
+  {
+    Beep();
+    return;
+  }
+
+  RecordDemoFlag = 1;
+  DemoFlag = 0;
+  lblStatus.ForeColor = vbRed;
+  lblStatus = "Recording Demo";
+  // DemoBuffer = New DemoBufferObject; // (handle this later, if needed)
+  Debug.Assert(! IS_NOTHING(&DemoBuffer, sizeof(DemoBuffer)));
+  Trace("MainForm", "Call menPlayClick");
+  menPlay_Click();
+  Trace("MainForm", "menPlayClick returned");
+
+  lblStatus.ForeColor = vbButtonText;
+  RecordDemoFlag = 0;
+  Let_ModifiedFlag(True);
+  if (! STRING_IS_LIKE(CurPath, TmpPath))
+  {
+    OrigPath = CurPath;
+    CurPath = TmpPath;
+  }
+
+  LInfo.DemoRandomSeed = RecDemoRandomSeed;
+  Trace("MainForm", "Call SaveMPX(TmpPath)");
+  SaveMPX(TmpPath);
+  Trace("MainForm", "Set DemoBuffer == Nothing");
+  SET_TO_NOTHING(&DemoBuffer, sizeof(DemoBuffer));
+  Trace("MainForm", "Call subFetchAndInitLevel");
+  subFetchAndInitLevel();
+  cmdPlayDemo.Enabled = DemoAvailable;
+  Trace("MainForm", "<-- menRec_Click()");
+}
+
+static void menReRecordDemo_Click()
+{
+  if (! LevelLoaded)
+  {
+    Beep();
+    return;
+  }
+
+  RecordDemoFlag = 1;
+  DemoFlag = 1;
+  lblStatus.ForeColor = vbRed;
+  lblStatus = "ReRecording Demo";
+  // DemoBuffer = New DemoBufferObject; // (handle this later, if needed)
+  Debug.Assert(! IS_NOTHING(&DemoBuffer, sizeof(DemoBuffer)));
+  menPlay_Click();
+  lblStatus.ForeColor = vbButtonText;
+  RecordDemoFlag = 0;
+  Let_ModifiedFlag(True);
+  if (! STRING_IS_LIKE(CurPath, TmpPath))
+  {
+    OrigPath = CurPath;
+    CurPath = TmpPath;
+  }
+
+  LInfo.DemoRandomSeed = RecDemoRandomSeed;
+  SaveMPX(TmpPath);
+  SET_TO_NOTHING(&DemoBuffer, sizeof(DemoBuffer));
+  subFetchAndInitLevel();
+}
+
+void menStop_Click()
+{
+  EndFlag = True;
+  LeadOutCounter = 1;
+  if (PauseMode != 0)
+    menPause_Click();
+
+  fpsTim.Enabled = False;
+  fpsTim_Timer();
+  lblFps.Caption = "";
+  menRec.Enabled = True;
+  menPlay.Enabled = True;
+  menPause.Enabled = False;
+  menStop.Enabled = False;
+  cmdPlay.Enabled = True;
+  cmdPause.Enabled = False;
+  cmdStop.Enabled = False;
+  cmdRecordDemo.Enabled = True;
+  cmdPlayDemo.Enabled = DemoAvailable;
+  cmdPlayAll.Enabled = DemosAvailable;
+  menPlayDemo.Enabled = DemoAvailable;
+  menPlayAll.Enabled = DemosAvailable;
+  menFaster.Enabled = False;
+  menSlower.Enabled = False;
+  cmbFile.Enabled = True;
+  cmbLevel.Enabled = True;
+}
+
+static void menStretch_Click(int Index)
+{
+  ReStretch(0.25 * Index);
+  // DisplayLevel True
+}
+
+static void menToolTips_Click()
+{
+  {
+    menToolTips.Checked = ! menToolTips.Checked;
+    if (menToolTips.Checked)
+    {
+      cmdPlay.ToolTipText = "Play Game (Space)";
+      cmdPause.ToolTipText = "Pause (P)";
+      cmdStop.ToolTipText = "Stop (Q)";
+      cmdPlayDemo.ToolTipText = "Play demo (Ctrl+Space)";
+      cmdRecordDemo.ToolTipText = "Record demo (Ctrl+R)";
+      lblInfoCount.ToolTipText = "Number of infotrons needed";
+      lblRedDiskCount.ToolTipText = "Number of red disks";
+      cmbLevel.ToolTipText = "List of all levels in the file";
+      cmbFile.ToolTipText = "List of files in current directory";
+      lblFps.ToolTipText = "Animation speed in fps";
+      lblFrameCount.ToolTipText = "Game time in frames";
+    }
+    else
+    {
+      cmdPlay.ToolTipText = "";
+      cmdPause.ToolTipText = "";
+      cmdStop.ToolTipText = "";
+      cmdPlayDemo.ToolTipText = "";
+      cmdRecordDemo.ToolTipText = "";
+      lblInfoCount.ToolTipText = "";
+      lblRedDiskCount.ToolTipText = "";
+      cmbLevel.ToolTipText = "";
+      cmbFile.ToolTipText = "";
+      lblFps.ToolTipText = "";
+      lblFrameCount.ToolTipText = "";
+    }
+
+  }
+}
+
+static void menTrim_Click()
+{
+  LevelInfoType Tmp;
+  char *OldOPath;
+
+  OldOPath = OrigPath;
+  Tmp = LInfo;
+  Tmp.SpecialPortCount = 0; // hack: all special ports are deleted
+  menCopy_Click();
+  CreateLevel(FMark.Width, FMark.Height);
+  LInfo = Tmp;
+  OrigPath = OldOPath;
+  CurPath = OldOPath;
+  menSelectAll_Click();
+  menPaste_Click();
+  picViewPort_Resize();
+}
+
+static void menZonkOff_Click()
+{
+  menZonkOn.Checked = False;
+  menZonkOff.Checked = True;
+  SpSaveMenu();
+  SpLoadMenu();
+}
+
+static void menZonkOn_Click()
+{
+  menZonkOn.Checked = True;
+  menZonkOff.Checked = False;
+  SpSaveMenu();
+  SpLoadMenu();
+}
+
+static void PanelTim_Timer()
+{
+  int Tmp;
+
+  Tmp = Panel.Height;
+  if (PanelSeq < Panel.Height && -1 < PanelSeq)
+  {
+    PanelSeq = (ShowPanel != 0 ?  PanelSeq + 2 :  PanelSeq + 2);
+    Tmp = ScaleHeight - Tmp + PanelSeq;
+    Panel.top = Tmp;
+    picViewPort.Height = Tmp;
+  }
+  else
+  {
+    PanelTim.Enabled = False;
+    PanelSeq = (PanelSeq < 0 ?  0 :  0);
+    ShowPanel = (ShowPanel == 0 ?  1 :  1);
+    menPanel.Checked = (ShowPanel != 0);
+  }
+}
+
+static void picKeys_MouseUp(int Button, int Shift, float X, float Y)
+{
+  FocusTim.Enabled = True;
+}
+
+static void picMenu_Click()
+{
+}
+
+static void picPane_KeyDown(int KeyCode, int Shift)
+{
+  if (KeyCode < 0 || 255 < KeyCode)
+    return;
+
+  KeyState[KeyCode] = True;
+  switch (KeyCode)
+  {
+    case vbKeyControl:
+      if (MouseButton == 0 && EditFlag)
+        picPane.MousePointer = 15;
+
+      break;
+
+    case vbKeyUp:
+    case vbKeyLeft:
+    case vbKeyDown:
+    case vbKeyRight:
+    case vbKeySpace:
+      if (DemoFlag != 0)
+      {
+        DemoFlag = 0;
+        UpdateDeltaT();
+      }
+
+      break;
+
+    case vbKeyF12:
+      if (DemoFlag != 0 && 2 == Shift)
+      {
+        DemoFlag = 0;
+        UpdateDeltaT();
+      }
+
+      break;
+
+    case vbKeyF11:
+      bCapturePane = ! bCapturePane;
+      break;
+  }
+}
+
+static void picPane_KeyUp(int KeyCode, int Shift)
+{
+  if (KeyCode < 0 || 255 < KeyCode)
+    return;
+
+  KeyState[KeyCode] = False;
+  switch (KeyCode)
+  {
+    case vbKeyPageUp:
+      if (menFaster.Enabled)
+        menFaster_Click();
+
+      break;
+
+    case vbKeyPageDown:
+      if (menSlower.Enabled)
+        menSlower_Click();
+
+      break;
+
+    case vbKeySpace:
+      if (2 == Shift) // ctrl+space
+      {
+        if (menPlayDemo.Enabled)
+          menPlayDemo_Click();
+
+      }
+      else
+      {
+        if (menPlay.Enabled)
+          menPlay_Click();
+      }
+
+      break;
+
+    case vbKeyQ:
+      if (menStop.Enabled)
+        menStop_Click();
+
+      break;
+
+    case vbKeyR:
+      if (menRec.Enabled)
+        menRec_Click();
+
+      break;
+
+    case vbKeyP:
+    case vbKeyPause:
+      if (menPause.Enabled && (Shift == 0))
+        menPause_Click();
+
+      break;
+
+    case vbKeyControl:
+      if (MouseButton == 0 && EditFlag)
+        picPane.MousePointer = 0;
+      break;
+  }
+}
+
+static void picPane_MouseDown(int Button, int Shift, float X, float Y)
+{
+  int OldEdMode;
+
+  MouseButton = Button;
+  OldEdMode = EditMode;
+  if (Button != 1)
+  {
+    if (Button == 2 && Shift != 2)
+    {
+      EditMode = edSelect;
+    }
+    else
+    {
+      return;
+    }
+  }
+
+  if (Shift == 2)
+    EditMode = edMove;
+
+  OSX = ScrollX;
+  OSY = ScrollY;
+  MDX = X;
+  MDY = Y;
+  switch (EditMode)
+  {
+    case edMove:
+      picPane.MousePointer = 5; // size
+      UserDragFlag = True;
+      break;
+
+    case edDraw:
+      SetField(X, Y, ToolBox.ASpriteIndex);
+      break;
+
+    case edSelect:
+      FMark.SetPoint1 EdGetX(X), EdGetY(Y);
+      FMark.MoveMarker;
+      break;
+  }
+
+  EditMode = OldEdMode;
+}
+
+static void picPane_MouseMove(int Button, int Shift, float X, float Y)
+{
+  boolean Oldflag;
+  int OldEdMode;
+
+  OldEdMode = EditMode;
+  if (Button != 1)
+  {
+    if (EditFlag && Button == 2 && Shift != 2)
+    {
+      EditMode = edSelect;
+    }
+    else
+    {
+      return;
+    }
+  }
+
+  if (Shift == 2)
+    EditMode = edMove;
+
+  switch (EditMode)
+  {
+    case edMove:
+      Oldflag = NoDisplayFlag;
+      NoDisplayFlag = False;
+      ScrollTo(OSX - X + MDX, OSY - Y + MDY);
+      Stage.Blt();
+      NoDisplayFlag = Oldflag;
+      break;
+
+    case edDraw:
+      SetField(X, Y, ToolBox.ASpriteIndex);
+      break;
+
+    case edSelect:
+      FMark.SetPoint2 EdGetX(X), EdGetY(Y);
+      FMark.MoveMarker;
+      break;
+  }
+
+  EditMode = OldEdMode;
+}
+
+static void picPane_MouseUp(int Button, int Shift, float X, float Y)
+{
+  MouseButton = MouseButton ^ Button;
+  picPane.MousePointer = 0;
+  UserDragFlag = False;
+  if (menEditMain.Enabled && Button == 2)
+  {
+    if (MDX == X && MDY == Y)
+      PopupMenu menEditMain;
+  }
+}
+
+static void picPane_Paint()
+{
+  boolean Oldflag;
+
+  Oldflag = NoDisplayFlag;
+  NoDisplayFlag = False;
+  Stage.Blt();
+  NoDisplayFlag = Oldflag;
+}
+
+static void ReStretch(float NewStretch)
+{
+  long BW2, LW, LH, i;
+
+  if (! Loaded)
+  {
+    Stretch = NewStretch;
+    return;
+  }
+
+  MousePointer = 11;
+  SET_TO_NOTHING(&Stage, sizeof(Stage));
+  SET_TO_NOTHING(&StretchedSprites, sizeof(StretchedSprites));
+  menStretch(Stretch / 0.25).Checked = False;
+  Stretch = NewStretch;
+  menStretch(Stretch / 0.25).Checked = True;
+  //  StretchWidth = BaseWidth ' * NewStretch
+  //  StretchWidth2 = StretchWidth \ 2
+  //  TwoPixels = 2 '* Stretch
+  // StretchLoad Sprites, imgMpx.Picture, 16, 16
+  BW2 = StretchWidth / 2;
+  LW = (FieldWidth + 2) * BaseWidth; // StretchWidth
+  LH = (FieldHeight + 2) * BaseWidth; // StretchWidth
+  // i = bmpStage.CreateAtSize(LW, LH)
+  // Stage = New DDScrollBuffer; // (handle this later, if needed)
+  i = Stage.CreateAtSize(LW, LH, picPane.hWnd);
+  // Set StretchedSprites = NormalSprites.GetStretchCopy(Stretch)
+  ReLoadStretchSprites();
+  if (i == 0 || IS_NOTHING(&StretchedSprites, sizeof(StretchedSprites)))
+  {
+    // menStretch(Stretch / 0.5).Enabled = False
+    if (0.5 <= Stretch)
+      ReStretch(Stretch - 0.25);
+
+  }
+  else
+  {
+    StretchedSprites.DestXOff = 1 * BaseWidth; // StretchWidth
+    StretchedSprites.DestYOff = 1 * BaseWidth; // StretchWidth
+    Stage.DestXOff = 1 * StretchWidth;
+    Stage.DestYOff = 1 * StretchWidth;
+    StretchedSprites.DestinationSurface = Stage.Surface;
+    Stage.Cls;
+    if (Loaded && LevelLoaded)
+    {
+      SetDisplayRegion();
+      picViewPort_Resize();
+      DisplayLevel();
+    }
+
+    subCalculateScreenScrollPos();
+    ScrollTo(ScreenScrollXPos, ScreenScrollYPos);
+    Stage.Blt();
+    picPane_Paint();
+  }
+
+  MousePointer = 0;
+}
+
+static void SetScrollEdges()
+{
+  ScrollMinX = (DisplayMinX - 0.5) * Stretch * BaseWidth;
+  ScrollMinY = (DisplayMinY - 0.5) * Stretch * BaseWidth;
+  ScrollMaxX = (DisplayMaxX + 1.5) * Stretch * BaseWidth - picPane.Width;
+  ScrollMaxY = (DisplayMaxY + 1.5) * Stretch * BaseWidth - picPane.Height;
+}
+
+#endif
+
+void DrawField(int X, int Y)
+{
+  int Tmp, tsi;
+
+  tsi = GetSI(X, Y);
+  Tmp = LowByte(PlayField16[tsi]);
+  if (40 < Tmp)
+    Tmp = 0;
+
+  if (Tmp == fiRAM || Tmp == fiHardWare)
+    Tmp = DisPlayField[tsi];
+
+  if (Tmp == fiBug || Tmp == 40)
+    Tmp = DisPlayField[tsi];
+
+  if (EditFlag)
+  {
+    if (fiOrangeDisk < Tmp && Tmp < fiSnikSnak)
+      Tmp = DisPlayField[tsi];
+  }
+
+  StretchedSprites.BltEx(StretchWidth * X, StretchWidth * Y, Tmp);
+}
+
+void DrawFieldAnimated(int X, int Y)
+{
+  int Tmp, tsi;
+
+  tsi = GetSI(X, Y);
+  Tmp = LowByte(PlayField16[tsi]);
+  switch (Tmp)
+  {
+    case fiSnikSnak:
+      subDrawAnimatedSnikSnaks(tsi);
+      break;
+
+    case fiElectron:
+      subDrawAnimatedElectrons(tsi);
+      break;
+
+    default:
+      //      If 40 < Tmp Then Tmp = 0
+      //      If Tmp = fiRAM Or Tmp = fiHardWare Then Tmp = DisPlayField(tsi)
+      //      If Tmp = fiBug Or Tmp = 40 Then Tmp = DisPlayField(tsi)
+      //      If EditFlag Then
+      //        If fiOrangeDisk < Tmp And Tmp < fiSnikSnak Then Tmp = DisPlayField(tsi)
+      //      End If
+      //      StretchedSprites.BltEx StretchWidth * X, StretchWidth * Y, Tmp
+      break;
+  }
+}
+
+void DrawFieldNoAnimated(int X, int Y)
+{
+  int Tmp, tsi;
+
+  tsi = GetSI(X, Y);
+  Tmp = LowByte(PlayField16[tsi]);
+  switch (Tmp)
+  {
+    case fiSnikSnak:
+      StretchedSprites.BltEx(StretchWidth * X, StretchWidth * Y, fiSpace);
+      break;
+
+    case fiElectron:
+      StretchedSprites.BltEx(StretchWidth * X, StretchWidth * Y, fiSpace);
+      break;
+
+    default:
+      if (40 < Tmp)
+        Tmp = 0;
+
+      if (Tmp == fiRAM || Tmp == fiHardWare)
+        Tmp = DisPlayField[tsi];
+
+      if (Tmp == fiBug || Tmp == 40)
+        Tmp = DisPlayField[tsi];
+
+      if (EditFlag)
+      {
+        if (fiOrangeDisk < Tmp && Tmp < fiSnikSnak)
+          Tmp = DisPlayField[tsi];
+      }
+
+      StretchedSprites.BltEx(StretchWidth * X, StretchWidth * Y, Tmp);
+      break;
+  }
+}
+
+void DrawSprite(int X, int Y, int SpritePos)
+{
+  StretchedSprites.BltEx(StretchWidth * X, StretchWidth * Y, SpritePos);
+}
+
+#if 0
+
+void InvalidateRect(long XMin, long YMin, long XMax, long YMax)
+{
+  long X, Y;
+
+  //  For Y = YMin To YMax
+  //    For X = XMin To XMax
+  //      Field(X, Y).GraphicsValid = 0
+  //    Next X
+  //  Next Y
+}
+
+static void picViewPort_MouseUp(int Button, int Shift, float X, float Y)
+{
+  FocusTim.Enabled = True;
+}
+
+static void picViewPort_Paint()
+{
+  // Debug.Print "picViewPort_Paint()"
+}
+
+static void picViewPort_Resize()
+{
+  long bdX, bdY, PanelVisibility;
+  long X, Y, dx, dY;
+  SettingsObject s;
+  boolean B;
+
+  bdX = picFrame.Width - picFrame.ScaleWidth;
+  bdY = picFrame.Height - picFrame.ScaleHeight;
+  dx = Min(picViewPort.ScaleWidth - bdX, (DisplayWidth - 1) * Stretch * BaseWidth);
+  dx = Max(dx, 0);
+  dY = Min(picViewPort.ScaleHeight - bdX, (DisplayHeight - 1) * Stretch * BaseWidth);
+  dY = Max(dY, 0);
+  B = s.Read("LimitToOriginalFieldSize", False);
+  PanelVisibility = 24 * (Panel.Height - PanelSeq - (float)1) / Panel.Height;
+  if (B)
+  {
+    dx = Min(320 * Stretch, dx);
+    dY = Min((200 - PanelVisibility) * Stretch, dY);
+  }
+
+  X = Max((picViewPort.ScaleWidth - dx) / 2, 0);
+  Y = Max((picViewPort.ScaleHeight - dY) / 2, 0);
+  picPane.Move X, Y, dx, dY;
+  picFrame.Move X - bdX / 2, Y - bdY / 2, dx + bdX, dY + bdY;
+  SetScrollEdges();
+  ScrollTo(ScrollX, ScrollY);
+  //  SizeTim.Interval = 1
+}
+
+//
+// Private Sub SizeTim_Timer()
+// Dim wdX&, wdY&
+//  SizeTim.Interval = 0
+//  wdX = Max(0, picViewPort.ScaleWidth - picPane.Width) * Screen.TwipsPerPixelX
+//  wdY = Max(0, picViewPort.ScaleHeight - picPane.Height) * Screen.TwipsPerPixelY
+//  If (0 < wdX) Or (0 < wdY) Then
+//    Move Left, Top, Width - wdX, Height - wdY
+//  End If
+// End Sub
+
+static void LoadKeyIndicators()
+{
+  int i;
+
+  picKeys.BackColor = vbButtonFace;
+  for (i = 2; i <= 5; i++)
+  {
+    Load shpKey(i);
+  }
+
+  for (i = 1; i <= 5; i++)
+  {
+    shpKey(i).FillColor = vbButtonFace;
+    shpKey(i).Visible = True;
+  }
+
+  shpKey(1).Move 7, 0;
+  shpKey(2).Move 0, 7;
+  shpKey(3).Move 7, 14;
+  shpKey(4).Move 14, 7;
+  shpKey(5).Move 7, 7;
+}
+
+void ShowKey(int KeyVar)
+{
+  boolean State[5 + 1];
+  int i;
+  boolean Tmp;
+  long Col;
+  boolean LastState[5 + 1];
+
+  //  For i = 1 To 5
+  //    State(i) = False
+  //  Next i
+  switch (KeyVar)
+  {
+    case 0:
+      // do nothing
+      break;
+
+    case Is < 5:
+      State[KeyVar] = True;
+      break;
+
+    default:
+      State[5] = True;
+      if (KeyVar < 9)
+        State[KeyVar - 4] = True;
+      break;
+  }
+
+  for (i = 1; i <= 5; i++)
+  {
+    Tmp = State[i];
+    if (Tmp ^ LastState[i])
+    {
+      Col = (i == 5 ?  vbRed :  vbRed);
+      shpKey(i).FillColor = (Tmp ?  Col :  Col);
+      shpKey(i).Refresh;
+      LastState[i] = Tmp;
+    }
+  }
+}
+
+static void GetSettings()
+{
+  SettingsObject s;
+  char *APath;
+  long X, Y;
+  int i;
+  boolean Flag;
+
+  {
+    // last file info
+    APath = WithSlash(App.Path);
+    CurPath = s.Read("LastPath", APath);
+    OrigPath = CurPath;
+    // window width and height
+    X = s.Read("Width", Width);
+    Y = s.Read("Height", Height);
+    if (X < 0 Then X == 0: If Y < 0)
+      Y = 0;
+
+    if (Screen.Width < X)
+      X = Screen.Width;
+
+    if (Screen.Height < Y)
+      Y = Screen.Height;
+
+    Width = X;
+    Height = Y;
+    // window position and state
+    X = s.Read("Left", left);
+    Y = s.Read("Top", top);
+    if (X < 0 Then X == 0: If Y < 0)
+      Y = 0;
+
+    if (Screen.Width < (X + Width))
+      X = Screen.Width - Width;
+
+    if (Screen.Height < (Y + Height))
+      Y = Screen.Height - Height;
+
+    left = X;
+    top = Y;
+    WindowState = s.Read("WinState", vbNormal);
+    // flags/options
+    Flag = s.Read("ShowToolTips", True);
+    if (Flag)
+      menToolTips_Click();
+
+    menBorder.Checked = ! CBool(s.Read("ShowBorder", False));
+    Flag = CBool(s.Read("AutoScroll", True));
+    if (! Flag)
+    {
+      AutoScrollFlag = False;
+      menAutoScroll.Checked = False;
+    }
+
+    Flag = CBool(s.Read("SoundFX", True));
+    FXOnFlag = (Flag ?  -1 :  -1);
+    menSoundFX.Checked = Flag;
+    SignatureDelay = CLng(s.Read("SignatureDelay", 3000));
+    AllowRedDiskCheat = CInt(s.Read("AllowRedDiskCheat", 1));
+    AllowEatRightRedDiskBug = CInt(s.Read("AllowEatRightRedDiskBug", 1));
+    MySignature = s.Read("MySignature", "");
+    // speed
+    X = s.Read("FrameDelayPlay", 1000000 / 35);
+    i = GetSpeedIndex(X);
+    menPlaySpeed_Click(i);
+    X = s.Read("FrameDelayDemo", 1000000 / 35);
+    i = GetSpeedIndex(X);
+    menDemoSpeed_Click(i);
+    // Zoom
+    i = s.Read("Stretch", 4);
+    if (i < menStretch.LBound || menStretch.UBound < i)
+      i = 4;
+
+    menStretch_Click (i);
+  }
+}
+
+static void SaveSettings()
+{
+  SettingsObject s;
+  int i;
+
+  {
+    s.Save "LastPath", (ModifiedFlag ?  OrigPath :  OrigPath);
+    if (WindowState != vbMinimized)
+    {
+      s.Save "Width", Width;
+      s.Save "Height", Height;
+      s.Save "Left", left;
+      s.Save "Top", top;
+      s.Save "WinState", WindowState;
+    }
+
+    s.Save "ShowToolTips", menToolTips.Checked;
+    s.Save "ShowBorder", menBorder.Checked;
+    s.Save "AutoScroll", menAutoScroll.Checked;
+    s.Save "SoundFX", menSoundFX.Checked;
+    s.Save "SignatureDelay", SignatureDelay;
+    s.Save "AllowRedDiskCheat", AllowRedDiskCheat;
+    s.Save "AllowEatRightRedDiskBug", AllowEatRightRedDiskBug;
+    s.Save "MySignature", MySignature;
+    // speeds
+    s.Save "FrameDelayPlay", DeltaTPlay;
+    s.Save "FrameDelayDemo", DeltaTDemo;
+    // zoom
+    for (i = menStretch.LBound; i <= menStretch.UBound; i++)
+    {
+      if (menStretch(i).Checked)
+        break;
+    }
+
+    s.Save "Stretch", i;
+    //    s.Save "",
+  }
+}
+
+void ReLoadStretchSprites()
+{
+  long Tmp;
+  BitMapObject NBMP, SBMP;
+  char *tmpMpxBmp;
+
+  //  If Stretch = 1 Then
+  MpxBmp = App.Path & "/Mpx.bmp";
+  //  Else
+  //    MpxBmp = App.Path & "\Mpx" & Stretch & ".bmp"
+  //    tmpMpxBmp = App.Path & "\Mpx.bmp"
+  //    If FileExists(MpxBmp) And FileExists(tmpMpxBmp) Then
+  //      If FileDateTime(MpxBmp) < FileDateTime(tmpMpxBmp) Then
+  //        MayKill MpxBmp
+  //      End If
+  //    End If
+  //    If Not FileExists(MpxBmp) Then
+  //      MousePointer = 11
+  // //      Set NBMP = New BitMapObject // (handle this later, if needed)
+  //      tmpMpxBmp = App.Path & "\Mpx.bmp"
+  //      If Not FileExists(tmpMpxBmp) Then
+  //        ReportError "ReLoadStretchSprites", "File not found: " & tmpMpxBmp
+  //        MESSAGE_BOX("an error occured"); // MsgBox "File not found: " & tmpMpxBmp, vbCritical, "MegaPlex - Error"
+  //        End
+  //      End If
+  //      NBMP.CreateFromFile tmpMpxBmp
+  //      Set SBMP = NBMP.GetStretchCopy(Stretch)
+  //      SBMP.SaveToFile MpxBmp
+  //      Set NBMP = Nothing
+  //      Set SBMP = Nothing
+  //      MousePointer = 0
+  //    End If
+  //  End If
+  // StretchedSprites = New DDSpriteBuffer; // (handle this later, if needed)
+  if (! StretchedSprites.CreateFromFile(MpxBmp, 16, 16))
+    SET_TO_NOTHING(&StretchedSprites, sizeof(StretchedSprites));
+}
+
+void SaveSnapshot(currency Number)
+{
+  char *Path;
+
+  Path = CAT(WithSlash(App.Path), "Capture");
+  if (! IsDir(Path))
+    MkDir(Path);
+
+  Path = Path & "\" & Format(Number, "00000000") & ".bmp";
+  SavePicture CaptureWindow(picPane.hWnd, True, 0, 0, picPane.ScaleWidth, picPane.ScaleHeight), Path;
+}
+
+#endif
diff --git a/src/game_sp/MainForm.h b/src/game_sp/MainForm.h
new file mode 100644 (file)
index 0000000..b0a3459
--- /dev/null
@@ -0,0 +1,31 @@
+// ----------------------------------------------------------------------------
+// MainForm.h
+// ----------------------------------------------------------------------------
+
+#ifndef MAINFORM_H
+#define MAINFORM_H
+
+#include "vb_types.h"
+#include "vb_defs.h"
+#include "vb_vars.h"
+#include "vb_lib.h"
+
+#include "global.h"
+
+extern void DisplayLevel();
+extern void DrawField(int X, int Y);
+extern void DrawFieldAnimated(int X, int Y);
+extern void DrawFieldNoAnimated(int X, int Y);
+extern void DrawSprite(int X, int Y, int SpritePos);
+extern void InvalidateRect(long XMin, long YMin, long XMax, long YMax);
+extern void Let_PanelVisible(boolean NewVal);
+extern void ReLoadStretchSprites();
+extern void SaveSnapshot(currency Number);
+extern void SetDisplayRegion();
+extern void ShowKey(int KeyVar);
+extern void menDemoSpeed_Click(int Index);
+extern void menEdit_Click();
+extern void menPlaySpeed_Click(int Index);
+extern void menStop_Click();
+
+#endif /* MAINFORM_H */
diff --git a/src/game_sp/MainGameLoop.c b/src/game_sp/MainGameLoop.c
new file mode 100644 (file)
index 0000000..9aa59aa
--- /dev/null
@@ -0,0 +1,233 @@
+// ----------------------------------------------------------------------------
+// MainGameLoop.c
+// ----------------------------------------------------------------------------
+
+#include "MainGameLoop.h"
+
+static char *VB_Name = "modMainGameLoop";
+// --- Option Explicit
+
+int GameLoopRunning;
+boolean bPlaying;
+int LeadOutCounter, EnterRepeatCounter;
+int ForcedExitFlag;
+int ExitToMenuFlag;
+int SavedGameFlag;
+boolean UserDragFlag;
+boolean AutoScrollFlag;
+
+// ==========================================================================
+//                              SUBROUTINE
+// Play a game/demo
+// ==========================================================================
+
+int subMainGameLoop()
+{
+  int subMainGameLoop;
+
+  int al, bx;
+  TickCountObject Clock;
+  currency LastFrame;
+
+  if (DemoFlag != 0)
+  {
+    // EP set level success byte: demo, not game
+    WasDemoFlag = 1;
+    EP_GameDemoVar0DAA = 0; // demo
+  }
+  else // loc_g_1836:
+  {
+    // EP set level success byte: game, not demo
+    WasDemoFlag = 0;
+    EP_GameDemoVar0DAA = 1; // game
+  }
+
+  // RestartGameLoop:
+  //  If RecordDemoFlag = 1 Then
+  //    RecordDemoFlag = 0 ' clear Demo Recording flag
+  //    Call subDisplayPlayingTime                 ' playing time on screen
+  //    ' Record key still pressed?' >= (Ctrl-)F1 and <= (Ctrl-)F10
+  //    While &H3B <= KeyScanCode7 And KeyScanCode7 <= &H44
+  //      ' yes -> wait until released
+  //      ' should we DoEvents here???? ... depends on how ... but yes!
+  //      ' ...or we can rather poll the keyboardstate inside this loop???
+  //    Wend
+  //    Call subInitGameConditions     ' Init game conditions (vars)
+  //    If MusicOnFlag = 0 Then Call subMusicInit
+  //    WasDemoFlag = 0          ' no demo anymore
+  //    EP_GameDemoVar0DAA = 1 ' force game
+  //  End If
+
+  // This was a bug in the original Supaplex: sometimes red disks could not
+  // be released.  This happened If Murphy was killed DURING a red disk release
+  // and the next try started.
+  RedDiskReleasePhase = 0; // (re-)enable red disk release
+  UpdatedFlag = 0;
+  GameLoopRunning = 1;
+  LevelStatus = 0;
+  // ----------------------------------------------------------------------------
+  // --------------------- START OF GAME-BUSY LOOP ------------------------------
+  // ----------------------------------------------------------------------------
+
+locRepeatMainGameLoop:                           // start repeating game loop
+
+  // ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+  // FS   synchronization
+  while (PauseMode != 0)
+  {
+    DoEvents();
+  }
+
+  do
+  {
+    DoEvents(); // user may klick on menus or move the window here ...
+  }
+  while (Clock.TickDiffUS(LastFrame) < DeltaT); // wait till its time for the next frame
+
+  //   never any additional code between here!
+  LastFrame = Clock.TickNow; // store the frame time
+  //   never any additional code between here!
+  if (! NoDisplayFlag) // copy the BackBuffer(=Stage) to visible screen
+    Stage.Blt();
+
+  // FS   end of synchronization
+  // ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+  if (EndFlag)
+    goto locExitMainGameLoop;
+
+  // If DemoFlag = 0 Then Call subCheckJoystick    ' check joystick
+  // bx = subCheckRightMouseButton()                ' check (right) mouse button
+  // If bx = 2 And LeadOutCounter < 1 Then KillMurphyFlag = 1 ' lead-out busy after quit? -> kill Murphy!
+
+  //  If DebugVersionFlag <> 0 Then ' debug mode on?
+  //    If Data_SubRest <> 0 Then Data_SubRest = Data_SubRest - 1
+  //    If keyEnter <> 0 Then GoTo loc_g_186F ' Was it the Enter key? -> yes--skip! No mouse!
+  //                                          ' fixes ENTER bug If no mouse driver!
+  //    If bx <> 1 Then GoTo loc_g_186F  ' Left button=Init game field
+  //                                    ' Also Enter If no mouse!
+  //    If Data_SubRest <> 0 Then GoTo loc_g_186F
+  //    Data_SubRest = 10
+  //    Call subRestoreFancy
+  //    Call subDisplayLevel         ' Paint (Init) game field
+  //    Call subConvertToEasySymbols ' Convert to easy symbols
+  //  End If
+
+loc_g_186F:
+  subProcessKeyboardInput();                 // Check keyboard, act on keys
+  // 'HACK:
+  //  TimerVar = TimerVar + 1
+  //  DoEvents
+  //  GoTo loc_g_186F
+  // 'END HACK
+  // If RecordDemoFlag = 1 Then GoTo RestartGameLoop
+
+  // ----------------------------------------------------------------------------
+  //
+  subDoGameStuff();                 // do all game stuff
+  //
+  // ----------------------------------------------------------------------------
+
+  //  Call subDisplayPlayingTime                 ' playing time on screen
+  subCheckRestoreRedDiskCountDisplay();    // Restore panel: red-disk hole
+
+  subRedDiskReleaseExplosion();       // Red Disk release and explode
+  subFollowUpExplosions();  // every explosion may cause up to 8 following explosions
+
+  bx = subCalculateScreenScrollPos();     // calculate screen start addrs
+  ScreenPosition = bx;
+  // Now new X and new Y are calculated, and bx = screen position = ScreenPosition
+  data_h_Ytmp = ScreenScrollYPos; // copy Y for next soft scroll
+  data_h_Xtmp = ScreenScrollXPos; // copy X for next soft scroll
+  if ((! UserDragFlag) && AutoScrollFlag)
+    ScrollTowards(ScreenScrollXPos, ScreenScrollYPos);
+
+  if (ForcedExitFlag != 0) // Forced Exit?' yes--exit!
+    goto locExitMainGameLoop;
+
+  TimerVar = TimerVar + 1;
+
+#if 0
+  if (bCapturePane)
+    MainForm.SaveSnapshot(TimerVar);
+#endif
+
+  //  If Not NoDisplayFlag Then
+  //    With MainForm.lblFrameCount
+  //      .Caption = TimerVar
+  //      .Refresh
+  //    End With
+  //  End If
+  if (ExitToMenuFlag == 1)
+    goto locExitMainGameLoop;
+
+  if (LeadOutCounter == 0) // no lead-out: game busy
+    goto locRepeatMainGameLoop;
+
+  // ----------------------------------------------------------------------------
+  // ---------------------- END OF GAME-BUSY LOOP -------------------------------
+  // ----------------------------------------------------------------------------
+  LeadOutCounter = LeadOutCounter - 1;             // do more lead-out after quit
+  if (LeadOutCounter != 0) // lead-out not ready: more
+    goto locRepeatMainGameLoop;
+
+  // lead-out done: exit now
+  // ---------------------- END OF GAME-BUSY LOOP (including lead-out) ----------
+
+locExitMainGameLoop:
+  do
+  {
+    DoEvents(); // user may klick on menus or move the window here ...
+  }
+  while (Clock.TickDiffUS(LastFrame) < DeltaT); // wait till its time for the next frame
+
+  Stage.Blt(); // blit the last frame
+  GameLoopRunning = 0;
+
+#if 0
+  MainForm.menStop_Click();
+  MainForm.PanelVisible = True;
+#endif
+
+  // If DemoRecordingFlag <> 0 Then Call subCloseDemoRecordingFile ' Demo recording on? -> close opened demo file (w)
+  if (SavedGameFlag != 0) // after savegame: no update!
+  {
+    SavedGameFlag = 0;
+    return subMainGameLoop;
+  }
+
+  SavedGameFlag = 0;
+  if (UpdateTimeFlag == 0) // update time?
+    return subMainGameLoop;
+
+  if (UpdatedFlag == 0) // update playing time
+    subUpdatePlayingTime();
+
+
+  return subMainGameLoop;
+} // subMainGameLoop
+
+void subUpdatePlayingTime()
+{
+}
+
+int subCalculateScreenScrollPos()
+{
+  int subCalculateScreenScrollPos;
+
+  int ax, Ay;
+
+  if (ExplosionShake != 0)
+  {
+    subGetRandomNumber();
+  }
+
+  {
+    ax = MainForm.picPane.Width / 2;
+    Ay = MainForm.picPane.Height / 2;
+  }
+  ScreenScrollXPos = Stretch * (MurphyScreenXPos + 8) - ax;
+  ScreenScrollYPos = Stretch * (MurphyScreenYPos + 8) - Ay;
+
+  return subCalculateScreenScrollPos;
+}
+
diff --git a/src/game_sp/MainGameLoop.h b/src/game_sp/MainGameLoop.h
new file mode 100644 (file)
index 0000000..71fd430
--- /dev/null
@@ -0,0 +1,28 @@
+// ----------------------------------------------------------------------------
+// MainGameLoop.h
+// ----------------------------------------------------------------------------
+
+#ifndef MAINGAMELOOP_H
+#define MAINGAMELOOP_H
+
+#include "vb_types.h"
+#include "vb_defs.h"
+#include "vb_vars.h"
+#include "vb_lib.h"
+
+#include "global.h"
+
+extern int subCalculateScreenScrollPos();
+extern int subMainGameLoop();
+extern void subUpdatePlayingTime();
+
+extern boolean AutoScrollFlag;
+extern boolean UserDragFlag;
+extern boolean bPlaying;
+extern int ExitToMenuFlag;
+extern int ForcedExitFlag;
+extern int GameLoopRunning;
+extern int LeadOutCounter, EnterRepeatCounter;
+extern int SavedGameFlag;
+
+#endif /* MAINGAMELOOP_H */
diff --git a/src/game_sp/Makefile b/src/game_sp/Makefile
new file mode 100644 (file)
index 0000000..f6b31aa
--- /dev/null
@@ -0,0 +1,131 @@
+# =============================================================================
+# Rocks'n'Diamonds Makefile (game_sp)
+# -----------------------------------------------------------------------------
+# (c) 1995-2009 Holger Schemel <info@artsoft.org>
+# -----------------------------------------------------------------------------
+# MegaPlex version 0.5 beta release xmas 2001 by Frank Schindler,
+# based on the Speed Fix 6.3+ by Herman Perk,
+# based on original Supaplex by Michael Stopp & Philip Jespersen.
+# =============================================================================
+
+# -----------------------------------------------------------------------------
+# configuration
+# -----------------------------------------------------------------------------
+
+SRCS = main.c                  \
+       vb_lib.c                \
+       vb_vars.c               \
+                               \
+       ASM.c                   \
+       BitMapObject.c          \
+       BugsTerminals.c         \
+       Capture.c               \
+       DDScrollBuffer.c        \
+       DDSpriteBuffer.c        \
+       Demo.c                  \
+       DemoBufferObject.c      \
+       DirectDrawGlobals.c     \
+       DirectXGlobals.c        \
+       Display.c               \
+       DoGameStuff.c           \
+       Electrons.c             \
+       ErrorReporting.c        \
+       Explosions.c            \
+       FakeDeclares.c          \
+       FancyRestore.c          \
+       GeneralTricks.c         \
+       Globals.c               \
+       Infotrons.c             \
+       InitGameConditions.c    \
+       Input.c                 \
+       LevelSetPreviewForm.c   \
+       MainForm.c              \
+       MainGameLoop.c          \
+       Marker.c                \
+       Murphy.c                \
+       OrangeDisk.c            \
+       PathTools.c             \
+       SettingsObject.c        \
+       SnikSnaks.c             \
+       Sound.c                 \
+       TickCountObject.c       \
+       TopMost.c               \
+       Zonk.c                  \
+       modAnimations.c         \
+       modGeneralTricks.c      \
+       modMPX.c
+
+OBJS = main.o                  \
+       vb_lib.o                \
+       vb_vars.o               \
+                               \
+       ASM.o                   \
+       BitMapObject.o          \
+       BugsTerminals.o         \
+       Capture.o               \
+       DDScrollBuffer.o        \
+       DDSpriteBuffer.o        \
+       Demo.o                  \
+       DemoBufferObject.o      \
+       DirectDrawGlobals.o     \
+       DirectXGlobals.o        \
+       Display.o               \
+       DoGameStuff.o           \
+       Electrons.o             \
+       ErrorReporting.o        \
+       Explosions.o            \
+       FakeDeclares.o          \
+       FancyRestore.o          \
+       GeneralTricks.o         \
+       Globals.o               \
+       Infotrons.o             \
+       InitGameConditions.o    \
+       Input.o                 \
+       LevelSetPreviewForm.o   \
+       MainForm.o              \
+       MainGameLoop.o          \
+       Marker.o                \
+       Murphy.o                \
+       OrangeDisk.o            \
+       PathTools.o             \
+       SettingsObject.o        \
+       SnikSnaks.o             \
+       Sound.o                 \
+       TickCountObject.o       \
+       TopMost.o               \
+       Zonk.o                  \
+       modAnimations.o         \
+       modGeneralTricks.o      \
+       modMPX.o
+
+GAME_SP = game_sp.a
+
+
+# -----------------------------------------------------------------------------
+# build targets
+# -----------------------------------------------------------------------------
+
+all: $(GAME_SP)
+
+$(GAME_SP): $(OBJS)
+       $(AR) cru $(GAME_SP) $(OBJS)
+       $(RANLIB) $(GAME_SP)
+
+.c.o:
+       $(CC) $(PROFILING) $(CFLAGS) -c $*.c
+
+clean:
+       $(RM) $(OBJS)
+       $(RM) $(GAME_SP)
+
+
+# -----------------------------------------------------------------------------
+# development only
+# -----------------------------------------------------------------------------
+
+depend:
+       for i in $(SRCS); do $(CPP) $(CFLAGS) -M $$i; done > .depend
+
+ifeq (.depend,$(wildcard .depend))
+include .depend
+endif
diff --git a/src/game_sp/Marker.c b/src/game_sp/Marker.c
new file mode 100644 (file)
index 0000000..9f0ac94
--- /dev/null
@@ -0,0 +1,274 @@
+// ----------------------------------------------------------------------------
+// Marker.c
+// ----------------------------------------------------------------------------
+
+#include "Marker.h"
+
+static boolean IsPort(long i);
+static void LimitXY(int *X, int *Y);
+static void SortData();
+
+// --- VERSION 1.0 CLASS
+// --- BEGIN
+// ---   MultiUse = -1  'True  // True
+// ---   Persistable = 0  'NotPersistable  // NotPersistable
+// ---   DataBindingBehavior = 0  'vbNone  // vbNone
+// ---   DataSourceBehavior  = 0  'vbNone  // vbNone
+// ---   MTSTransactionMode  = 0  'NotAnMTSObject  // NotAnMTSObject
+// --- END
+
+static char *VB_Name = "MarkerObject";
+static boolean VB_GlobalNameSpace = False;
+static boolean VB_Creatable = True;
+static boolean VB_PredeclaredId = False;
+static boolean VB_Exposed = False;
+// --- Option Explicit
+
+long mIndex1, mIndex2;
+int X1, X2, Y1, Y2;
+int XMin, YMin;
+boolean mVisible;
+
+byte *SelectionData;
+
+int Marker_Get_Width()
+{
+  int Width;
+
+  Width = Abs(X2 - X1) + 1;
+
+  return Width;
+}
+
+int Marker_Get_Height()
+{
+  int Height;
+
+  Height = Abs(Y2 - Y1) + 1;
+
+  return Height;
+}
+
+int Marker_Get_Left()
+{
+  int Left;
+
+  SortData();
+  Left = XMin;
+
+  return Left;
+}
+
+int Marker_Get_Top()
+{
+  int Top;
+
+  SortData();
+  Top = YMin;
+
+  return Top;
+}
+
+static void LimitXY(int *X, int *Y)
+{
+  if (*X < DisplayMinX)
+    *X = DisplayMinX;
+
+  if (DisplayMaxX < *X)
+    *X = DisplayMaxX;
+
+  if (*Y < DisplayMinY)
+    *Y = DisplayMinY;
+
+  if (DisplayMaxY < *Y)
+    *Y = DisplayMaxY;
+}
+
+void Marker_SetPoint1(int X, int Y)
+{
+  LimitXY(&X, &Y);
+  X1 = X;
+  Y1 = Y;
+  X2 = X;
+  Y2 = Y;
+}
+
+void Marker_SetPoint2(int X, int Y)
+{
+  char *T;
+
+  LimitXY(&X, &Y);
+  X2 = X;
+  Y2 = Y;
+  T = CAT("(", Marker_Get_Width(), " x ", Marker_Get_Height(), ")");
+  MainForm.lblFrameCount = T;
+}
+
+static void SortData()
+{
+  int Tmp;
+
+  XMin = (X2 < X1 ?  X2 :  X2);
+  YMin = (Y2 < Y1 ?  Y2 :  Y2);
+}
+
+void Marker_ShowMarker(boolean ShowFlag)
+{
+  mVisible = ShowFlag;
+  Marker_MoveMarker();
+}
+
+void Marker_RefreshMarker()
+{
+  int L, T, R, B;
+  long Tmp;
+
+  if (! mVisible)
+    return;
+
+  LimitXY(&X1, &Y1);
+  LimitXY(&X2, &Y2);
+  SortData();
+  L = DigitXPos(XMin) - 1;
+  T = DigitYPos(YMin) - 1;
+  R = L + StretchWidth * Marker_Get_Width() + 1;
+  B = T + StretchWidth * Marker_Get_Height() + 1;
+  MainForm.picPane.Line(L, T, R, B, 0xFFFFFF, B);
+}
+
+void Marker_MoveMarker()
+{
+  int L, T, R, B;
+  long Tmp;
+
+  if (! mVisible)
+    return;
+
+  LimitXY(&X1, &Y1);
+  LimitXY(&X2, &Y2);
+  SortData();
+  Stage.Blt();
+  Tmp = GetSI(XMin, YMin);
+  if (Marker_Get_Width() == 1 && Marker_Get_Height() == 1 && IsPort(Tmp))
+  {
+    SpLoadMenu();
+    MainForm.menSP.Enabled = True;
+  }
+  else
+  {
+    MainForm.menSP.Enabled = False;
+  }
+}
+
+static boolean IsPort(long i)
+{
+  static boolean IsPort;
+
+  int ax;
+
+  IsPort = False;
+  ax = DisPlayField[i];
+  if (fiOrangeDisk < ax && ax < fiSnikSnak)
+    IsPort = True;
+
+  return IsPort;
+}
+
+void Marker_Copy()
+{
+  int X, Y, MaxX, MaxY;
+  long Tmp;
+  char *TPath;
+  int FNum;
+
+  SortData();
+  MaxX = Marker_Get_Width() - 1;
+  MaxY = Marker_Get_Height() - 1;
+  SelectionData = REDIM_2D(sizeof(byte), 0, MaxX + 1 - 1, 0, MaxY + 1 - 1);
+  for (Y = 0; Y <= MaxY; Y++)
+  {
+    for (X = 0; X <= MaxX; X++)
+    {
+      Tmp = FieldWidth * (YMin + Y) + XMin + X;
+
+      // --- On Error GoTo CopyEH
+      SelectionData[X, Y] = DisPlayField[Tmp];
+      // --- On Error GoTo 0
+
+    }
+  }
+
+  TPath = CAT(App.Path, "/Mpx.clp");
+  if (FileExists(TPath))
+    MayKill(TPath);
+
+  FNum = FreeFile();
+
+  // --- On Error GoTo CopyEH
+  FNum = fopen(TPath, "wb");
+  FILE_PUT(FNum, -1, &MaxX, sizeof(MaxX));
+  FILE_PUT(FNum, -1, &MaxY, sizeof(MaxY));
+  FILE_PUT(FNum, -1, &SelectionData, sizeof(SelectionData));
+  fclose(FNum);
+  SelectionData = REDIM_1D(sizeof(byte), 0, 1 - 1);
+  return;
+
+CopyEH:
+  Beep();
+}
+
+void Marker_Paste()
+{
+  int X, Y, MaxX, MaxY;
+  long Tmp;
+  char *TPath;
+  int FNum;
+
+  TPath = CAT(App.Path, "/Mpx.clp");
+  if (! FileExists(TPath))
+  {
+    Beep();
+    return;
+  }
+
+  FNum = FreeFile();
+
+  // --- On Error GoTo PasteEH
+  FNum = fopen(TPath, "rb");
+  FILE_GET(FNum, -1, &MaxX, sizeof(MaxX));
+  FILE_GET(FNum, -1, &MaxY, sizeof(MaxY));
+  SelectionData = REDIM_2D(sizeof(byte), 0, MaxX + 1 - 1, 0, MaxY + 1 - 1);
+  FILE_GET(FNum, -1, &SelectionData, sizeof(SelectionData));
+  fclose(FNum);
+  // --- On Error GoTo 0
+
+  SortData();
+  if (Marker_Get_Width() <= MaxX)
+    MaxX = Marker_Get_Width() - 1;
+
+  if (Marker_Get_Height() <= MaxY)
+    MaxY = Marker_Get_Height() - 1;
+
+  for (Y = 0; Y <= MaxY; Y++)
+  {
+    for (X = 0; X <= MaxX; X++)
+    {
+      Tmp = FieldWidth * (YMin + Y) + XMin + X;
+
+      // --- On Error GoTo PasteEH
+      DisPlayField[Tmp] = SelectionData[X, Y];
+      PlayField16[Tmp] = UnEdSprite(SelectionData[X, Y]);
+      // --- On Error GoTo 0
+
+    }
+  }
+
+  Let_ModifiedFlag(True);
+PasteEH:
+  Beep();
+}
+
+static void Class_Initialize()
+{
+  mVisible = False;
+}
diff --git a/src/game_sp/Marker.h b/src/game_sp/Marker.h
new file mode 100644 (file)
index 0000000..48fa3a1
--- /dev/null
@@ -0,0 +1,27 @@
+// ----------------------------------------------------------------------------
+// Marker.h
+// ----------------------------------------------------------------------------
+
+#ifndef MARKER_H
+#define MARKER_H
+
+#include "vb_types.h"
+#include "vb_defs.h"
+#include "vb_vars.h"
+#include "vb_lib.h"
+
+#include "global.h"
+
+extern void Marker_Copy();
+extern int Marker_Get_Height();
+extern int Marker_Get_Left();
+extern int Marker_Get_Top();
+extern int Marker_Get_Width();
+extern void Marker_MoveMarker();
+extern void Marker_Paste();
+extern void Marker_RefreshMarker();
+extern void Marker_SetPoint1(int X, int Y);
+extern void Marker_SetPoint2(int X, int Y);
+extern void Marker_ShowMarker(boolean ShowFlag);
+
+#endif /* MARKER_H */
diff --git a/src/game_sp/Murphy.c b/src/game_sp/Murphy.c
new file mode 100644 (file)
index 0000000..29de96d
--- /dev/null
@@ -0,0 +1,2344 @@
+// ----------------------------------------------------------------------------
+// Murphy.c
+// ----------------------------------------------------------------------------
+
+#include "Murphy.h"
+
+static void subEatRedDisk(int si);
+static boolean subMoveKillsMurphy(int si, int ax, int bl);
+
+static char *VB_Name = "modMurphy";
+// --- Option Explicit
+
+#define LocalStretch                   (1)
+
+// ==========================================================================
+//                              SUBROUTINE
+// Move Murphy in any direction
+// ==========================================================================
+
+int subAnimateMurphy(int si)
+{
+  int subAnimateMurphy;
+
+  int ax, al, ah, bx, bl, i, X, Y;
+  int tX, tY, tDeltaX, tDeltaY, tPos, Tmp;
+
+  // Variables that hold information about the animation sequence
+  int *dx; // an array of image positions in moving.mpx, finalized with -1
+  int dx2; // an additional image position of a second sprite, for instance: yellow disk if pushed
+  int MurphyDX, MurphyDY; // murphys move steps
+  int SeqPos; // index into dx()
+  int ClearPos; // Position to clear before blitting sprites, none=-1
+  int dxPos; // field-position  to draw dx(SeqPos)
+  int dx2Step; // position of dx2 relative to dx-position
+
+  ax = PlayField16[si];
+  al = LowByte(ax);
+  if (al != fiMurphy)
+  {
+    MurphyMoveCounter = 0;             // We have no Murphy! Exit!
+    return subAnimateMurphy;
+  }
+
+  MurphyMoveCounter = 1;             // We have a Murphy!
+  MurphyExplodePos = si;
+  if (ax != 3) // yes--go proceed moving murphy?
+    goto locProceedMovingMurphy;
+
+  // FS: reset moving sequence variables
+  MurphyDX = 0;
+  MurphyDY = 0;
+  ClearPos = si;
+  dxPos = si;
+  dx2 = -1;
+  SeqPos = 0;
+  // end of FS
+  ScratchGravity = 0; // scratch gravity off
+  if (GravityFlag != 0) // Gravity? (1=gravity on)
+  {
+    bl = LowByte(PlayField16[si - FieldWidth]); // check above
+    if (! (bl == fiPortUp || bl == fiPortUpAndDown || bl == fiPortAllDirections))
+    {
+      if (PlayField16[si + FieldWidth] == 0) // gravity on and space below!
+        ScratchGravity = 1;
+    }
+  } // loc_g_5E8B:
+
+  bl = DemoKeyCode;
+  if (bl != 0) // a key was pressed!
+    goto locKeyPressed5FCF;
+
+  RedDiskReleaseFlag = 1;
+  if (ScratchGravity != 0) // gravity pulls & space below?'-> force Space up to down
+  {
+    MurphyDY = 2;
+    goto loc_g_6364;
+  }
+
+  ax = (TimerVar & 3);
+  if (ax != 0)
+    return subAnimateMurphy;
+
+  // ------------------------------------------------------------------
+  // Murphy's YAWN & SLEEP sequence, counted down by YawnSleepCounter:
+  YawnSleepCounter = YawnSleepCounter + 1;
+  if (YawnSleepCounter == 4)
+  {
+    subCopyFieldToScreen(si, fiMurphy); // normal grin
+    return subAnimateMurphy;
+  } // loc_g_5ECE:
+
+  if (YawnSleepCounter <= 500) // loc_g_5ED7:
+    return subAnimateMurphy;
+
+  if (YawnSleepCounter <= 522)
+  {
+    bx = (YawnSleepCounter - 500) / 2;
+    subCopyFieldToScreen(si, aniMurphyYawn + bx); // yawn! and look depressed afterwards...
+    return subAnimateMurphy;
+  } // loc_g_5F00:
+
+  if (YawnSleepCounter <= 1000)
+    return subAnimateMurphy;
+
+  if (YawnSleepCounter <= 1022)
+  {
+    bx = (YawnSleepCounter - 1000) / 2;
+    subCopyFieldToScreen(si, aniMurphyYawn + bx); // yawn again!
+    return subAnimateMurphy;
+  } // loc_g_5F32:
+
+  if (YawnSleepCounter <= 1600) // loc_g_5F3B:
+    return subAnimateMurphy;
+
+  if (YawnSleepCounter <= 1622)
+  {
+    bx = (YawnSleepCounter - 1600) / 2;
+    subCopyFieldToScreen(si, aniMurphyYawn + bx); // yawn again! - third time
+    return subAnimateMurphy;
+  } // loc_g_5F64:
+
+  if (YawnSleepCounter > 1654)
+    return subAnimateMurphy;
+
+  if (PlayField16[si - 1] == 0)
+  {
+    if (PlayField16[si + 1] == 0)
+    {
+      YawnSleepCounter = 36;
+      return subAnimateMurphy;
+
+    }
+    else
+    {
+      bx = (YawnSleepCounter - 1622) / 16;
+      subCopyFieldToScreen(si, aniMurphySleepRight + bx); // go to sleep
+      return subAnimateMurphy;
+    }
+  } // loc_g_5F81:
+
+  bx = (YawnSleepCounter - 1622) / 16;
+  subCopyFieldToScreen(si, aniMurphySleepLeft + bx); // go to sleep
+  return subAnimateMurphy;
+
+  // end of YAWN-SLEEP-Sequence
+  // ------------------------------------------------------------------
+  // ==========================================================================
+  //                       (Direct Jump) a key was pressed
+  // ==========================================================================
+
+locKeyPressed5FCF:
+  if (ScratchGravity == 0)
+    goto loc_g_6003;
+
+  if (PlayField16[si + FieldWidth] != 0)
+    goto loc_g_6003;
+
+  if (bl == keyUp)
+  {
+    if (PlayField16[si - FieldWidth] == fiBase)
+      goto loc_g_6003;
+
+  }
+  else if (bl == keyLeft)
+  {
+    if (PlayField16[si - 1] == fiBase)
+      goto loc_g_6003;
+
+  }
+  else if (bl == keyRight)
+  {
+    if (PlayField16[si + 1] == fiBase)
+      goto loc_g_6003;
+  } // loc_g_6001:
+
+  bl = keyDown;                      // force moving down!
+loc_g_6003:
+  switch (bl)
+  {
+    case keyUp: // 1
+      RedDiskReleaseFlag = 0; // moving down to up ...
+      goto loc_g_6078;
+
+      break;
+
+    case keyLeft: // 2
+      RedDiskReleaseFlag = 0; // moving right to left ...
+      goto loc_g_60DA;
+
+      break;
+
+    case keyDown: // 3
+      RedDiskReleaseFlag = 0; // moving up to down ...
+      goto loc_g_6154;
+
+      break;
+
+    case keyRight: // 4
+      RedDiskReleaseFlag = 0; // moving left to right ...
+      goto loc_g_61B6;
+
+      break;
+
+    case keySpaceUp: // 5
+      RedDiskReleaseFlag = 0; // touching down to up ...
+      goto loc_g_622E;
+
+      break;
+
+    case keySpaceLeft: // 6
+      RedDiskReleaseFlag = 0; // touching right to left ...
+      goto loc_g_6258;
+
+      break;
+
+    case keySpaceDown: // 7
+      RedDiskReleaseFlag = 0; // touching up to down ...
+      goto loc_g_6288;
+
+      break;
+
+    case keySpaceRight: // 8
+      RedDiskReleaseFlag = 0; // touching left to right ...
+      goto loc_g_62B2;
+
+      break;
+
+    case keySpace: // 9
+      goto loc_g_62E2;                         // no move ...
+
+      break;
+
+    default:
+      RedDiskReleaseFlag = 0;
+      return subAnimateMurphy;
+      break;
+  }
+
+  // ==========================================================================
+  // moving down to up ...
+  // ==========================================================================
+
+loc_g_6078:
+  // FS:
+  MurphyDY = -2;
+  // end of FS
+  ax = PlayField16[si - FieldWidth];
+  al = LowByte(ax);
+  if (ax == fiSpace)
+    goto loc_g_6312;
+
+  if (ax == fiBase)
+    goto loc_g_63D3;
+
+  if (al == fiBug)
+    goto loc_g_63C2;
+
+  if (ax == fiInfotron)
+    goto loc_g_65C6;
+
+  if (ax == fiExit)
+    goto loc_g_6756;
+
+  if (al == fiTerminal)
+    goto loc_g_6817;
+
+  if (al == fiPortUp || al == fiPortUpAndDown || al == fiPortAllDirections)
+    goto loc_g_6916;
+
+  if (al == fiRedDisk)
+    goto loc_g_69A6;
+
+  if (al == fiYellowDisk)
+    goto loc_g_6AB8;
+
+  if (! subMoveKillsMurphy(si - FieldWidth, ax, bl))
+    goto loc_g_6078;
+
+  return subAnimateMurphy;
+
+  // ==========================================================================
+  // moving right to left ...
+  // ==========================================================================
+
+loc_g_60DA:
+  // FS:
+  MurphyDX = -2;
+  // end of FS
+  MurphyVarFaceLeft = 1;
+  ax = PlayField16[si - 1];
+  al = LowByte(ax);
+  if (ax == fiSpace)
+    goto loc_g_6341;
+
+  if (ax == fiBase)
+    goto loc_g_641C;
+
+  if (al == fiBug)
+    goto loc_g_640B;
+
+  if (ax == fiInfotron)
+    goto loc_g_65FE;
+
+  if (ax == fiExit)
+    goto loc_g_6756;
+
+  if (ax == fiZonk)
+    goto loc_g_679B;
+
+  if (al == fiTerminal)
+    goto loc_g_684E;
+
+  if (al == fiPortLeft || al == fiPortLeftAndRight || al == fiPortAllDirections)
+    goto loc_g_693A;
+
+  if (ax == fiRedDisk)
+    goto loc_g_69CE;
+
+  if (ax == fiYellowDisk)
+    goto loc_g_6AF1;
+
+  if (ax == fiOrangeDisk)
+    goto loc_g_6B9B;
+
+  if (! subMoveKillsMurphy(si - 1, ax, bl))
+    goto loc_g_60DA;
+
+  return subAnimateMurphy;
+
+  // ==========================================================================
+  // moving up to down ...
+  // ==========================================================================
+
+loc_g_6154:
+  // FS:
+  MurphyDY = 2;
+  // end of FS
+  ax = PlayField16[si + FieldWidth];
+  al = LowByte(ax);
+  if (ax == fiSpace)
+    goto loc_g_6364;
+
+  if (ax == fiBase)
+    goto loc_g_6459;
+
+  if (al == fiBug)
+    goto loc_g_6448;
+
+  if (ax == fiInfotron)
+    goto loc_g_662A;
+
+  if (ax == fiExit)
+    goto loc_g_6756;
+
+  if (al == fiTerminal)
+    goto loc_g_6884;
+
+  if (al == fiPortDown || al == fiPortUpAndDown || al == fiPortAllDirections)
+    goto loc_g_695E;
+
+  if (al == fiRedDisk)
+    goto loc_g_69F7;
+
+  if (al == fiYellowDisk)
+    goto loc_g_6B2A;
+
+  if (! subMoveKillsMurphy(si + FieldWidth, ax, bl))
+    goto loc_g_6154;
+
+  return subAnimateMurphy;
+
+  // ==========================================================================
+  // moving left to right ...
+  // ==========================================================================
+
+loc_g_61B6:
+  // FS:
+  MurphyDX = 2;
+  // end of FS
+  MurphyVarFaceLeft = 0;
+  ax = PlayField16[si + 1];
+  al = LowByte(ax);
+  if (ax == fiSpace)
+    goto loc_g_6399;
+
+  if (ax == fiBase)
+    goto loc_g_64A2;
+
+  if (al == fiBug)
+    goto loc_g_6491;
+
+  if (ax == fiInfotron)
+    goto loc_g_6662;
+
+  if (ax == fiExit)
+    goto loc_g_6756;
+
+  if (ax == fiZonk)
+    goto loc_g_67D4;
+
+  if (al == fiTerminal)
+    goto loc_g_68BA;
+
+  if (al == fiPortRight || al == fiPortLeftAndRight || al == fiPortAllDirections)
+    goto loc_g_6982;
+
+  if (al == fiRedDisk)
+    goto loc_g_6A1F;
+
+  if (al == fiYellowDisk)
+    goto loc_g_6B63;
+
+  if (ax == fiOrangeDisk)
+    goto loc_g_6BD3;
+
+  if (! subMoveKillsMurphy(si + 1, ax, bl))
+    goto loc_g_61B6;
+
+  return subAnimateMurphy;
+
+  // ==========================================================================
+  // touching down to up ...
+  // ==========================================================================
+
+loc_g_622E:
+  // FS:
+  ClearPos = -1;
+  dxPos = si - FieldWidth;
+  // end of FS
+  ax = PlayField16[si - FieldWidth];
+  al = LowByte(ax);
+  al = LowByte(ax);
+  if (ax == fiBase)
+    goto loc_g_64DF;
+
+  if (al == fiBug)
+    goto loc_g_64CE;
+
+  if (ax == fiInfotron)
+    goto loc_g_668E;
+
+  if (al == fiTerminal)
+    goto loc_g_6817;
+
+  if (al == fiRedDisk)
+    goto loc_g_6A48;
+
+  return subAnimateMurphy;
+
+  // ==========================================================================
+  // touching right to left ...
+  // ==========================================================================
+
+loc_g_6258:
+  // FS:
+  ClearPos = -1;
+  dxPos = si - 1;
+  // end of FS
+  MurphyVarFaceLeft = 1;
+  ax = PlayField16[si - 1];
+  al = LowByte(ax);
+  if (ax == fiBase)
+    goto loc_g_651D;
+
+  if (al == fiBug)
+    goto loc_g_650C;
+
+  if (ax == fiInfotron)
+    goto loc_g_66C0;
+
+  if (al == fiTerminal)
+    goto loc_g_684E;
+
+  if (al == fiRedDisk)
+    goto loc_g_6A64;
+
+  return subAnimateMurphy;
+
+  // ==========================================================================
+  // touching up to down ...
+  // ==========================================================================
+
+loc_g_6288:
+  // FS:
+  ClearPos = -1;
+  dxPos = si + FieldWidth;
+  // end of FS
+  ax = PlayField16[si + FieldWidth];
+  al = LowByte(ax);
+  if (ax == fiBase)
+    goto loc_g_655B;
+
+  if (al == fiBug)
+    goto loc_g_654A;
+
+  if (ax == fiInfotron)
+    goto loc_g_66F2;
+
+  if (al == fiTerminal)
+    goto loc_g_6884;
+
+  if (al == fiRedDisk)
+    goto loc_g_6A80;
+
+  return subAnimateMurphy;
+
+  // ==========================================================================
+  // touching left to right ...
+  // ==========================================================================
+
+loc_g_62B2:
+  // FS:
+  ClearPos = -1;
+  dxPos = si + 1;
+  // end of FS
+  MurphyVarFaceLeft = 0;
+  ax = PlayField16[si + 1];
+  al = LowByte(ax);
+  if (ax == fiBase)
+    goto loc_g_6599;
+
+  if (al == fiBug)
+    goto loc_g_6588;
+
+  if (ax == fiInfotron)
+    goto loc_g_6724;
+
+  if (al == fiTerminal)
+    goto loc_g_68BA;
+
+  if (al == fiRedDisk)
+    goto loc_g_6A9C;
+
+  return subAnimateMurphy;
+
+  // ==========================================================================
+  // Release Red disk: no move ...
+  // ==========================================================================
+
+loc_g_62E2:
+  // FS:
+  ClearPos = -1;
+  // end of FS
+  if (LowByte(RedDiskCount) == 0)
+    return subAnimateMurphy;
+
+  if (LowByte(RedDiskReleasePhase) != 0)
+    return subAnimateMurphy;
+
+  if (LowByte(RedDiskReleaseFlag) != 1)
+    return subAnimateMurphy;
+
+  MovHighByte(&PlayField16[si], 0x2A);
+  MovingPictureSequencePhase = 0x40; // init picture move sequence
+  dx = aniRedDisk;
+  MovLowByte(&RedDiskReleasePhase, 1);
+  Mov(&RedDiskReleaseMurphyPos, si);             // remember Murphy's location
+  goto loc_Split;
+
+  // ==========================================================================
+  // SPACE moving down to up
+  // ==========================================================================
+
+loc_g_6312:
+  dx = (MurphyVarFaceLeft == 0 ?  aniMurphyEatUpRight :  aniMurphyEatUpRight);
+  PlayField16[si - FieldWidth] = 0x103;
+  PlayField16[si] = 0x300;
+  si = si - FieldWidth;
+  goto loc_StopNoSplit;
+
+  // ==========================================================================
+  // SPACE moving right to left
+  // ==========================================================================
+
+loc_g_6341:
+  dx = aniMurphyEatLeft;
+  PlayField16[si - 1] = 0x203;
+  PlayField16[si] = 0x300;
+  si = si - 1;
+  goto loc_StopNoSplit;
+
+  // ==========================================================================
+  // SPACE moving up to down, and when gravity is pulling!
+  // ==========================================================================
+
+loc_g_6364:
+  dx = (MurphyVarFaceLeft == 0 ?  aniMurphyEatUpRight :  aniMurphyEatUpRight);
+  PlayField16[si + FieldWidth] = 0x303;
+  PlayField16[si] = 0x300;
+  si = si + FieldWidth;
+  goto loc_StopNoSplit;
+
+  // ==========================================================================
+  // SPACE moving left to right
+  // ==========================================================================
+
+loc_g_6399:
+  dx = aniMurphyEatRight;
+  PlayField16[si + 1] = 0x403;
+  PlayField16[si] = 0x300;
+  si = si + 1;
+  goto loc_StopNoSplit;
+
+  // ==========================================================================
+  // BUG moving down to up
+  // ==========================================================================
+
+loc_g_63C2:
+  if (SgnHighByte(PlayField16[si - FieldWidth]) >= 0)
+  {
+    ExplodeFieldSP(si);                 // Explode
+    return subAnimateMurphy;
+  }
+
+  PlayField16[si - FieldWidth] = fiBase;
+  // ==========================================================================
+  // BASE moving down to up
+  // ==========================================================================
+
+loc_g_63D3:
+  subSoundFXBase();
+  dx = (MurphyVarFaceLeft == 0 ?  aniMurphyEatUpRight :  aniMurphyEatUpRight);
+  PlayField16[si - FieldWidth] = 0x503;
+  PlayField16[si] = 0x300;
+  si = si - FieldWidth;
+  goto loc_StopNoSplit;
+
+  // ==========================================================================
+  // BUG moving right to left
+  // ==========================================================================
+
+loc_g_640B:
+  if (SgnHighByte(PlayField16[si - 1]) >= 0)
+  {
+    ExplodeFieldSP(si);                 // Explode
+    return subAnimateMurphy;
+  }
+
+  PlayField16[si - 1] = fiBase;
+  // ==========================================================================
+  // BASE moving right to left
+  // ==========================================================================
+
+loc_g_641C:
+  subSoundFXBase();
+  dx = aniMurphyEatLeft;
+  PlayField16[si - 1] = 0x203;
+  PlayField16[si] = 0x300;
+  si = si - 1;
+  goto loc_StopNoSplit;
+
+  // ==========================================================================
+  // BUG moving up to down
+  // ==========================================================================
+
+loc_g_6448:
+  if (SgnHighByte(PlayField16[si + FieldWidth]) >= 0)
+  {
+    ExplodeFieldSP(si);                 // Explode
+    return subAnimateMurphy;
+  }
+
+  PlayField16[si + FieldWidth] = fiBase;
+  // ==========================================================================
+  // BASE moving up to down
+  // ==========================================================================
+
+loc_g_6459:
+  subSoundFXBase();
+  dx = (MurphyVarFaceLeft == 0 ?  aniMurphyEatUpRight :  aniMurphyEatUpRight);
+  PlayField16[si + FieldWidth] = 0x703;
+  PlayField16[si] = 0x300;
+  si = si + FieldWidth;
+  goto loc_StopNoSplit;
+
+  // ==========================================================================
+  // BUG moving left to right
+  // ==========================================================================
+
+loc_g_6491:
+  if (SgnHighByte(PlayField16[si + 1]) >= 0)
+  {
+    ExplodeFieldSP(si);                 // Explode
+    return subAnimateMurphy;
+  }
+
+  PlayField16[si + 1] = fiBase;
+  // ==========================================================================
+  // BASE moving left to right
+  // ==========================================================================
+
+loc_g_64A2:
+  subSoundFXBase();
+  dx = aniMurphyEatRight;
+  PlayField16[si + 1] = 0x803;
+  PlayField16[si] = 0x300;
+  si = si + 1;
+  goto loc_StopNoSplit;
+
+  // ==========================================================================
+  // BUG touching down to up
+  // ==========================================================================
+
+loc_g_64CE:
+  if (SgnHighByte(PlayField16[si - FieldWidth]) >= 0)
+  {
+    ExplodeFieldSP(si);                 // Explode
+    return subAnimateMurphy;
+  }
+
+  PlayField16[si - FieldWidth] = fiBase;
+  // ==========================================================================
+  // BASE touching down to up
+  // ==========================================================================
+
+loc_g_64DF:
+  subCopyFieldToScreen(si, aniMurphyTouchUp);
+  subSoundFXBase();
+  dx = aniTouchBase;
+  dxPos = si - FieldWidth;
+  MovHighByte(&PlayField16[si], 0x10);
+  goto loc_StopNoSplit;
+
+  // ==========================================================================
+  // BUG touching right to left
+  // ==========================================================================
+
+loc_g_650C:
+  if (SgnHighByte(PlayField16[si - 1]) >= 0)
+  {
+    ExplodeFieldSP(si);                 // Explode
+    return subAnimateMurphy;
+  }
+
+  PlayField16[si - 1] = fiBase;
+  // ==========================================================================
+  // BASE touching right to left
+  // ==========================================================================
+
+loc_g_651D:
+  subCopyFieldToScreen(si, aniMurphyTouchLeft);
+  subSoundFXBase();
+  dx = aniTouchBase;
+  dxPos = si - 1;
+  MovHighByte(&PlayField16[si], 0x11);
+  goto loc_StopNoSplit;
+
+  // ==========================================================================
+  // BUG touching up to down
+  // ==========================================================================
+
+loc_g_654A:
+  if (SgnHighByte(PlayField16[si + FieldWidth]) >= 0)
+  {
+    ExplodeFieldSP(si);                 // Explode
+    return subAnimateMurphy;
+  }
+
+  PlayField16[si + FieldWidth] = fiBase;
+  // ==========================================================================
+  // BASE touching up to down
+  // ==========================================================================
+
+loc_g_655B:
+  subCopyFieldToScreen(si, aniMurphyTouchDown);
+  subSoundFXBase();
+  dx = aniTouchBase;
+  dxPos = si + FieldWidth;
+  MovHighByte(&PlayField16[si], 0x12);
+  goto loc_StopNoSplit;
+
+  // ==========================================================================
+  // BUG touching left to right
+  // ==========================================================================
+
+loc_g_6588:
+  if (SgnHighByte(PlayField16[si + 1]) >= 0)
+  {
+    ExplodeFieldSP(si);                 // Explode
+    return subAnimateMurphy;
+  }
+
+  PlayField16[si + 1] = fiBase;
+  // ==========================================================================
+  // BASE touching left to right
+  // ==========================================================================
+
+loc_g_6599:
+  subCopyFieldToScreen(si, aniMurphyTouchRight);
+  subSoundFXBase();
+  dx = aniTouchBase;
+  dxPos = si + 1;
+  MovHighByte(&PlayField16[si], 0x13);
+  goto loc_StopNoSplit;
+
+  // ==========================================================================
+  // INFOTRON moving down to up
+  // ==========================================================================
+
+loc_g_65C6:
+  subSoundFXInfotron();
+  dx = (MurphyVarFaceLeft == 0 ?  aniMurphyEatUpRight :  aniMurphyEatUpRight);
+  PlayField16[si - FieldWidth] = 0x903;
+  PlayField16[si] = 0x300;
+  si = si - FieldWidth;
+  goto loc_StopNoSplit;
+
+  // ==========================================================================
+  // INFOTRON moving right to left
+  // ==========================================================================
+
+loc_g_65FE:
+  subSoundFXInfotron();
+  dx = aniEatInfotronLeft;
+  dx2 = fiInfotron;
+  dx2Step = -1;
+  ClearPos = -1;
+  PlayField16[si - 1] = 0xA03;
+  PlayField16[si] = 0x300;
+  si = si - 1;
+  goto loc_StopNoSplit;
+
+  // ==========================================================================
+  // INFOTRON moving up to down
+  // ==========================================================================
+
+loc_g_662A:
+  subSoundFXInfotron();
+  dx = (MurphyVarFaceLeft == 0 ?  aniMurphyEatUpRight :  aniMurphyEatUpRight);
+  PlayField16[si + FieldWidth] = 0xB03;
+  PlayField16[si] = 0x300;
+  si = si + FieldWidth;
+  goto loc_StopNoSplit;
+
+  // ==========================================================================
+  // INFOTRON moving left to right
+  // ==========================================================================
+
+loc_g_6662:
+  subSoundFXInfotron();
+  dx = aniEatInfotronRight;
+  dx2 = fiInfotron;
+  dx2Step = 1;
+  ClearPos = -1;
+  PlayField16[si + 1] = 0xC03;
+  PlayField16[si] = 0x300;
+  si = si + 1;
+  goto loc_StopNoSplit;
+
+  // ==========================================================================
+  // INFOTRON touching down to up
+  // ==========================================================================
+
+loc_g_668E:
+  subCopyFieldToScreen(si, aniMurphyTouchUp);
+  subSoundFXInfotron();
+  dx = aniTouchInfotron;
+  MovHighByte(&PlayField16[si], 0x14);
+  MovHighByte(&PlayField16[si - FieldWidth], 0xFF);
+  goto loc_StopNoSplit;
+
+  // ==========================================================================
+  // INFOTRON touching right to left
+  // ==========================================================================
+
+loc_g_66C0:
+  subCopyFieldToScreen(si, aniMurphyTouchLeft);
+  subSoundFXInfotron();
+  dx = aniTouchInfotron;
+  MovHighByte(&PlayField16[si], 0x15);
+  MovHighByte(&PlayField16[si - 1], 0xFF);
+  goto loc_StopNoSplit;
+
+  // ==========================================================================
+  // INFOTRON touching up to down
+  // ==========================================================================
+
+loc_g_66F2:
+  subCopyFieldToScreen(si, aniMurphyTouchDown);
+  subSoundFXInfotron();
+  dx = aniTouchInfotron;
+  MovHighByte(&PlayField16[si], 0x16);
+  MovHighByte(&PlayField16[si + FieldWidth], 0xFF);
+  goto loc_StopNoSplit;
+
+  // ==========================================================================
+  // INFOTRON touching left to right
+  // ==========================================================================
+
+loc_g_6724:
+  subCopyFieldToScreen(si, aniMurphyTouchRight);
+  subSoundFXInfotron();
+  dx = aniTouchInfotron;
+  MovHighByte(&PlayField16[si], 0x17);
+  MovHighByte(&PlayField16[si + 1], 0xFF);
+  goto loc_StopNoSplit;
+
+  // ==========================================================================
+  // EXIT pressed from any direction
+  // ==========================================================================
+
+loc_g_6756:
+  // FS
+  ClearPos = -1;
+  MurphyDX = 0;
+  MurphyDY = 0;
+  // end of FS
+  if (LowByte(InfotronsNeeded) != 0)
+    return subAnimateMurphy;
+
+  subSoundFXExit();
+  data_h_DemoDone = 1; // EP set level success bytes
+  LevelStatus = 1; // set Level Status DONE
+  EP_GameDemoVar0DAA = 0; // force demo for lead-out
+  if (SavedGameFlag == 0) // saved game running?
+  {
+    if (UpdateTimeFlag != 0)    // update time?
+    {
+      UpdatedFlag = 1; // prevent double update
+      subUpdatePlayingTime();    // update playing time
+    }
+  }
+
+#if 0
+  subUpdateHallOfFame(); // update time + Hall-Of-Fame
+#endif
+
+  LeadOutCounter = 0x40;          // quit: start lead-out
+  dx = aniMurphyExit;
+  MovHighByte(&PlayField16[si], 0xD);
+  goto loc_StopNoSplit;
+
+  // ==========================================================================
+  // ZONK moving right to left
+  // ==========================================================================
+
+loc_g_679B:
+  ax = PlayField16[si - 2];
+  if (ax != 0)
+    return subAnimateMurphy;
+
+  MovHighByte(&PlayField16[si - 2], 1);
+  subCopyFieldToScreen(si, aniPushLeft); // draw pushing murphy
+  dx = aniZonkRollLeft;
+  dxPos = si - 1;
+  dx2 = aniPushLeft;
+  dx2Step = 1;
+  MovHighByte(&PlayField16[si], 0xE);
+  goto loc_MoveNoSplit;
+
+  // ==========================================================================
+  // ZONK moving left to right
+  // ==========================================================================
+
+loc_g_67D4:
+  ax = PlayField16[si + 2];
+  if (ax != 0)
+    return subAnimateMurphy;
+
+  ax = PlayField16[si + FieldWidth + 1];
+  if (ax == 0) // zonk falls
+    return subAnimateMurphy;
+
+  MovHighByte(&PlayField16[si + 2], 1);
+  subCopyFieldToScreen(si, aniPushRight); // draw pushing murphy
+  dx = aniZonkRollRight;
+  dxPos = si + 1;
+  dx2 = aniPushRight;
+  dx2Step = -1;
+  MovHighByte(&PlayField16[si], 0xF);
+  goto loc_MoveNoSplit;
+
+  // ==========================================================================
+  // TERMINAL moving/touching down to up
+  // ==========================================================================
+
+loc_g_6817:
+  subCopyFieldToScreen(si, aniMurphyTouchUp);
+  if (YellowDisksExploded != 0)
+  {
+    YawnSleepCounter = 10; // stay hypnotized
+    return subAnimateMurphy;
+  } // loc_g_6838:
+
+  subCopyFieldToScreen(si - FieldWidth, 0x88); // draw new terminal type
+  TerminalState[si - FieldWidth] = 8;
+  goto loc_g_68F0;
+
+  // ==========================================================================
+  // TERMINAL moving/touching right to left
+  // ==========================================================================
+
+loc_g_684E:
+  subCopyFieldToScreen(si, aniMurphyTouchLeft);
+  if (YellowDisksExploded != 0)
+  {
+    YawnSleepCounter = 10; // stay hypnotized
+    return subAnimateMurphy;
+  } // loc_g_6838:
+
+  subCopyFieldToScreen(si - 1, 0x88); // draw new terminal type
+  TerminalState[si - 1] = 8;
+  goto loc_g_68F0;
+
+  // ==========================================================================
+  // TERMINAL moving/touching up to down
+  // ==========================================================================
+
+loc_g_6884:
+  subCopyFieldToScreen(si, aniMurphyTouchDown);
+  if (YellowDisksExploded != 0)
+  {
+    YawnSleepCounter = 10; // stay hypnotized
+    return subAnimateMurphy;
+  } // loc_g_6838:
+
+  subCopyFieldToScreen(si + FieldWidth, 0x88); // draw new terminal type
+  TerminalState[si + FieldWidth] = 8;
+  goto loc_g_68F0;
+
+  // ==========================================================================
+  // TERMINAL moving/touching left to right
+  // ==========================================================================
+
+loc_g_68BA:
+  subCopyFieldToScreen(si, aniMurphyTouchRight);
+  if (YellowDisksExploded != 0)
+  {
+    YawnSleepCounter = 10; // stay hypnotized
+    return subAnimateMurphy;
+  } // loc_g_6838:
+
+  subCopyFieldToScreen(si + 1, 0x88); // draw new terminal type
+  TerminalState[si + 1] = 8;
+  // ==========================================================================
+  // common TERMINAL stuff moving/touching from all directions
+  // ==========================================================================
+
+loc_g_68F0:
+  TerminalMaxCycles = 7;
+  YellowDisksExploded = 1;
+  for (i = 0; i <= LevelMax; i++)
+  {
+    if (PlayField16[i] == fiYellowDisk)
+      ExplodeFieldSP (i);
+  }
+
+  return subAnimateMurphy;
+
+  // ==========================================================================
+  // PORT down to up, VERTICAL PORT, CROSS PORT all moving down to up
+  // ==========================================================================
+
+loc_g_6916:
+  if (PlayField16[si - 2 * FieldWidth] != 0)
+    return subAnimateMurphy;
+
+  dx = aniSplitUpDown;
+  dx2Step = -FieldWidth;
+  PlayField16[si] = 0x1803;
+  PlayField16[si - 2 * FieldWidth] = 0x300;
+  goto loc_StopSplit;
+
+  // ==========================================================================
+  // PORT right to left, HORIZONTAL PORT, CROSS PORT all moving right to left
+  // ==========================================================================
+
+loc_g_693A:
+  if (PlayField16[si - 2] != 0)
+    return subAnimateMurphy;
+
+  dx = aniMurphyEatLeft;
+  dx2Step = -1;
+  PlayField16[si] = 0x1903;
+  PlayField16[si - 2] = 0x300;
+  goto loc_StopSplit;
+
+  // ==========================================================================
+  // PORT up to down, VERTICAL PORT, CROSS PORT all moving up to down
+  // ==========================================================================
+
+loc_g_695E:
+  if (PlayField16[si + 2 * FieldWidth] != 0)
+    return subAnimateMurphy;
+
+  dx = aniSplitUpDown;
+  dx2Step = FieldWidth;
+  PlayField16[si] = 0x1A03;
+  PlayField16[si + 2 * FieldWidth] = 0x300;
+  goto loc_StopSplit;
+
+  // ==========================================================================
+  // PORT left to right, HORIZONTAL PORT, CROSS PORT all moving left to right
+  // ==========================================================================
+
+loc_g_6982:
+  if (PlayField16[si + 2] != 0)
+    return subAnimateMurphy;
+
+  dx = aniMurphyEatRight;
+  dx2Step = 1;
+  PlayField16[si] = 0x1B03;
+  PlayField16[si + 2] = 0x300;
+
+loc_StopSplit:
+  MovingPictureSequencePhase = 0; // stop picture move sequence
+  SplitMoveFlag = 1; // port: split movement
+  goto loc_Split;
+
+  // ==========================================================================
+  // RED DISK moving down to up
+  // ==========================================================================
+
+loc_g_69A6:
+  dx = (MurphyVarFaceLeft == 0 ?  aniMurphyEatUpRight :  aniMurphyEatUpRight);
+  PlayField16[si] = 0x1C03;
+  PlayField16[si - FieldWidth] = 0x300;
+  goto loc_StopNoSplit;
+
+  // ==========================================================================
+  // RED DISK moving right to left
+  // ==========================================================================
+
+loc_g_69CE:
+  dx = aniMurphyEatLeft;
+  PlayField16[si] = 0x300; // !!!!!! this time we move murphy at sequence-start!
+  PlayField16[si - 1] = 0x1D03;
+  si = si - 1;
+  goto loc_StopNoSplit;
+
+  // ==========================================================================
+  // RED DISK moving up to down
+  // ==========================================================================
+
+loc_g_69F7:
+  dx = (MurphyVarFaceLeft == 0 ?  aniMurphyEatUpRight :  aniMurphyEatUpRight);
+  PlayField16[si] = 0x1E03;
+  PlayField16[si + FieldWidth] = 0x300;
+  goto loc_StopNoSplit;
+
+  // ==========================================================================
+  // RED DISK moving left to right
+  // ==========================================================================
+
+loc_g_6A1F:
+  //  dx = aniMurphyEatRightRedDisk 'this sequence is 9 steps long!
+  dx = aniMurphyEatRight;
+  // --------------------------------------------------------------------------
+  // BugFix
+  // Table data_h_145A, pointed to by table data_h_105E, has a severe bug:
+  // The Red Disk sequence is 8 pictures long, but 9 are displayed, because it
+  // has 1 extra entry, which causes Murphy to end slightly shifted to the left!
+  // We may not fix the table, because then the timing of the game changes
+  // and several existing demo's do not run properly anymore.
+  // We only correct Murphies x-location here, when the sequence starts.
+  // Remember that this is not the real bug-fix, but we must live with
+  // this existing bug and correct for the consequences of it.
+  if (0 == AllowEatRightRedDiskBug) // Murphy's screen x-position
+    MurphyScreenXPos = MurphyScreenXPos - 2;
+
+  SeqPos = -1;
+  // FS: for me this means to blit the first animation frame twice
+  // end of BugFix
+  // --------------------------------------------------------------------------
+  PlayField16[si] = 0x300; // !!!!!! this time we move murphy at sequence-start!
+  PlayField16[si + 1] = 0x1F03;
+  si = si + 1;
+  goto loc_StopNoSplit;
+
+  // ==========================================================================
+  // RED DISK touching down to up
+  // ==========================================================================
+
+loc_g_6A48:
+  dx = aniTouchRedDisk;
+  MovHighByte(&PlayField16[si], 0x20);
+  MovHighByte(&PlayField16[si - FieldWidth], 3);
+  goto loc_StopNoSplit;
+
+  // ==========================================================================
+  // RED DISK touching right to left
+  // ==========================================================================
+
+loc_g_6A64:
+  dx = aniTouchRedDisk;
+  MovHighByte(&PlayField16[si], 0x21);
+  MovHighByte(&PlayField16[si - 1], 3);
+  goto loc_StopNoSplit;
+
+  // ==========================================================================
+  // RED DISK touching up to down
+  // ==========================================================================
+
+loc_g_6A80:
+  dx = aniTouchRedDisk;
+  MovHighByte(&PlayField16[si], 0x22);
+  MovHighByte(&PlayField16[si + FieldWidth], 3);
+  goto loc_StopNoSplit;
+
+  // ==========================================================================
+  // RED DISK touching left to right
+  // ==========================================================================
+
+loc_g_6A9C:
+  dx = aniTouchRedDisk;
+  MovHighByte(&PlayField16[si], 0x23);
+  MovHighByte(&PlayField16[si + 1], 3);
+
+loc_StopNoSplit:
+  MovingPictureSequencePhase = 0; // stop picture move sequence
+  goto loc_NoSplit;
+
+  // ==========================================================================
+  // YELLOW DISK moving down to up
+  // ==========================================================================
+
+loc_g_6AB8:
+  if (PlayField16[si - 2 * FieldWidth] != 0)
+    return subAnimateMurphy;
+
+  PlayField16[si - 2 * FieldWidth] = 0x1200;
+  subCopyFieldToScreen(si, aniPushRight);
+  dx = aniYellowDisk;
+  dxPos = si - FieldWidth;
+  dx2 = aniPushUpDown;
+  dx2Step = FieldWidth;
+  PlayField16[si] = 0x2403;
+  goto loc_MoveNoSplit;
+
+  // ==========================================================================
+  // YELLOW DISK moving right to left
+  // ==========================================================================
+
+loc_g_6AF1:
+  if (PlayField16[si - 2] != 0)
+    return subAnimateMurphy;
+
+  PlayField16[si - 2] = 0x1200;
+  subCopyFieldToScreen(si, aniPushLeft);
+  dx = aniYellowDisk;
+  dxPos = si - 1;
+  dx2 = aniPushLeft;
+  dx2Step = 1;
+  PlayField16[si] = 0x2503;
+  goto loc_MoveNoSplit;
+
+  // ==========================================================================
+  // YELLOW DISK moving up to down
+  // ==========================================================================
+
+loc_g_6B2A:
+  if (PlayField16[si + 2 * FieldWidth] != 0)
+    return subAnimateMurphy;
+
+  PlayField16[si + 2 * FieldWidth] = 0x1200;
+  subCopyFieldToScreen(si, aniPushRight);
+  dx = aniYellowDisk;
+  dxPos = si + FieldWidth;
+  dx2 = aniPushUpDown;
+  dx2Step = -FieldWidth;
+  PlayField16[si] = 0x2703;
+  goto loc_MoveNoSplit;
+
+  // ==========================================================================
+  // YELLOW DISK moving left to right
+  // ==========================================================================
+
+loc_g_6B63:
+  if (PlayField16[si + 2] != 0)
+    return subAnimateMurphy;
+
+  PlayField16[si + 2] = 0x1200;
+  subCopyFieldToScreen(si, aniPushRight);
+  dx = aniYellowDisk;
+  dxPos = si + 1;
+  dx2 = aniPushRight;
+  dx2Step = -1;
+  PlayField16[si] = 0x2603;
+  goto loc_MoveNoSplit;
+
+  // ==========================================================================
+  // ORANGE DISK moving right to left
+  // ==========================================================================
+
+loc_g_6B9B:
+  if (PlayField16[si - 2] != 0)
+    return subAnimateMurphy;
+
+  PlayField16[si - 2] = 0x800;
+  subCopyFieldToScreen(si, aniPushLeft);
+  dx = aniOrangeDisk;
+  dxPos = si - 1;
+  dx2 = aniPushLeft;
+  dx2Step = 1;
+  PlayField16[si] = 0x2803;
+  goto loc_MoveNoSplit;
+
+  // ==========================================================================
+  // ORANGE DISK moving left to right
+  // ==========================================================================
+
+loc_g_6BD3:
+  if (PlayField16[si + 2] != 0)
+    return subAnimateMurphy;
+
+  if (PlayField16[si + FieldWidth + 1] == 0) // falling goes before pushing
+    return subAnimateMurphy;
+
+  PlayField16[si + 2] = 0x100;
+  subCopyFieldToScreen(si, aniPushRight);
+  dx = aniOrangeDisk;
+  dxPos = si + 1;
+  dx2 = aniPushRight;
+  dx2Step = -1;
+  PlayField16[si] = 0x2903;
+  // ==========================================================================
+  // Copy screen animation action table to action work space
+  // (To paint sequence: Push Zonk/Disk / release red disk / Port passing)
+  // ==========================================================================
+
+loc_MoveNoSplit:
+  MovingPictureSequencePhase = 8; // init picture move sequence
+
+loc_NoSplit:
+  SplitMoveFlag = 0; // no port: no split movement
+
+loc_Split:
+  //  copy/store global move sequence info????????????????????????????????????
+  //  ... dont think so ...(FS)
+  // ==========================================================================
+  // Proceed with all movements
+  // ==========================================================================
+
+locProceedMovingMurphy: // proceed moving murphy
+  YawnSleepCounter = 0; // Wake up sleeping Murphy
+  ax = MovingPictureSequencePhase;            // sequence busy?
+  if (ax == 0)             // no -- start sequence!
+    goto loc_g_6C8F;
+
+  ax = ax - 1;   // next picture of sequence
+  MovingPictureSequencePhase = ax;            // store for later
+  if (ax == 0) // Sound effects
+    subSoundFXPush();
+
+  bl = HighByte(PlayField16[si]);
+  if (bl == 0xE)        // Push Zonk to left
+    goto loc_g_6F7E;
+
+  if (bl == 0xF)        // Push Zonk to right
+    goto loc_g_6FBC;
+
+  if (bl == 0x28)       // Push orange disk to left
+    goto loc_g_6FFA;
+
+  if (bl == 0x29)       // Push orange disk to right
+    goto loc_g_7038;
+
+  if (bl == 0x24)       // Push yellow disk up
+    goto loc_g_7076;
+
+  if (bl == 0x25)       // Push yellow disk to left
+    goto loc_g_70B4;
+
+  if (bl == 0x27)       // Push yellow disk down
+    goto loc_g_70F2;
+
+  if (bl == 0x26)       // Push yellow disk to right
+    goto loc_g_7130;
+
+  if (bl == 0x2A)       // Red disk release timer
+    goto loc_g_716E;
+
+  return subAnimateMurphy;
+
+  // ==========================================================================
+  // Paint frame of MOVING.DAT sequence
+  // ==========================================================================
+
+loc_g_6C8F:
+  if (SplitMoveFlag == 0)
+  {
+    // ++++++++++++++++++++++++++
+    // Begin of normal movement
+    MurphyScreenXPos = MurphyScreenXPos + MurphyDX;
+    MurphyScreenYPos = MurphyScreenYPos + MurphyDY;
+    if (! ClearPos < 0) // clear field that murphy is leaving
+      subCopyFieldToScreen(ClearPos, 0);
+
+    if (dx2 == fiInfotron) // special case of infotron moving left or right
+    {
+      tDeltaX = 0;
+      tDeltaY = 0;
+    }
+    else
+    {
+      tDeltaX = MurphyDX * LocalStretch * (SeqPos + 1);
+      tDeltaY = MurphyDY * LocalStretch * (SeqPos + 1);
+    }
+
+    X = GetStretchX(dxPos) + tDeltaX;
+    Y = GetStretchY(dxPos) + tDeltaY;
+    Tmp = (SeqPos < 0 ?  0 :  0); // 9StepBugFix!(red disk move right)
+    StretchedSprites.BltEx(X, Y, dx[Tmp]);
+    if (! dx2 < 0)
+    {
+      tPos = dxPos + dx2Step;
+      X = GetStretchX(tPos);
+      Y = GetStretchY(tPos);
+      if (dx2 == fiInfotron) // special case of infotron moving left or right
+      {
+        StretchedSprites.BltEx(X, Y, dx[SeqPos] + dx2Step);
+      }
+      else // pushing something
+      {
+        StretchedSprites.BltEx(X + tDeltaX, Y + tDeltaY, dx2);
+      }
+    }
+
+    // End of normal movement
+    // ------------------------
+  }
+  else
+  {
+    // ++++++++++++++++++++++++++++++++
+    // Begin of split movement (port)
+    MurphyScreenXPos = MurphyScreenXPos + 2 * MurphyDX;
+    MurphyScreenYPos = MurphyScreenYPos + 2 * MurphyDY;
+    subCopyFieldToScreen(ClearPos, 0); // clear the field that murphy leaves
+    tDeltaX = MurphyDX * LocalStretch * (SeqPos + 1);
+    tDeltaY = MurphyDY * LocalStretch * (SeqPos + 1);
+    X = GetStretchX(dxPos) + tDeltaX;
+    Y = GetStretchY(dxPos) + tDeltaY;
+    StretchedSprites.BltEx(X, Y, dx[SeqPos]); // plot first murphy
+    tPos = dxPos + dx2Step;
+    X = GetStretchX(tPos);
+    Y = GetStretchY(tPos);
+    StretchedSprites.BltEx(X + tDeltaX, Y + tDeltaY, dx[SeqPos]); // plot second murphy
+    StretchedSprites.BltEx(X, Y, LowByte(PlayField16[tPos])); // replot the port on top
+    // End of split movement (port)
+    // ------------------------------
+  } // loc_g_6D1E:'loc_g_6D28:
+
+  SeqPos = SeqPos + 1;
+  if (dx[SeqPos] > -1)
+    return subAnimateMurphy;
+
+  // Follow-up after movement completed     'loc_g_6D35:
+  MurphyXPos = MurphyXPos + MurphyDX;
+  MurphyYPos = MurphyYPos + MurphyDY;
+  bl = HighByte(PlayField16[si]);  // animation phase
+  MovHighByte(&PlayField16[si], 0);
+
+  if (bl == 0x1)    // space, moving up
+    goto loc_g_6EC8;
+
+  if (bl == 0x2)    // space, moving left
+    goto loc_g_6EE6;
+
+  if (bl == 0x3)    // space, moving down
+    goto loc_g_6F04;
+
+  if (bl == 0x4)    // space, moving right
+    goto loc_g_71C4;
+
+  if (bl == 0x5)    // base , moving up
+    goto loc_g_6EC8;
+
+  if (bl == 0x6)    // base , moving left -> 6 is not used, value is set to 2 instead of 6!
+    goto loc_g_6EE6;
+
+  if (bl == 0x7)    // base , moving down
+    goto loc_g_6F04;
+
+  if (bl == 0x8)    // base , moving right
+    goto loc_g_71C4;
+
+  if (bl == 0x9)    // infotron, moving up
+    goto loc_g_6EBA;
+
+  if (bl == 0xA)      // infotron, moving left
+    goto loc_g_6ED8;
+
+  if (bl == 0xB)    // infotron, moving down
+    goto loc_g_6EF6;
+
+  if (bl == 0xC)      // infotron, moving right
+    goto loc_g_71B6;
+
+  if (bl == 0xD)      // exit
+    goto loc_g_6F77;
+
+  if (bl == 0xE)      // zonk, pushing left
+    goto loc_g_6F18;
+
+  if (bl == 0xF)      // zonk, pushing right
+    goto loc_g_6F3B;
+
+  if (bl == 0x10)   // base , touching up
+    goto loc_g_71E2;
+
+  if (bl == 0x11)   // base , touching left
+    goto loc_g_71FE;
+
+  if (bl == 0x12)   // base , touching down
+    goto loc_g_721A;
+
+  if (bl == 0x13)   // base , touching right
+    goto loc_g_7236;
+
+  if (bl == 0x14)   // infotron touching up
+    goto loc_g_71D4;
+
+  if (bl == 0x15)   // infotron touching left
+    goto loc_g_71F0;
+
+  if (bl == 0x16)   // infotron touching down
+    goto loc_g_720C;
+
+  if (bl == 0x17)   // infotron touching right
+    goto loc_g_7228;
+
+  if (bl == 0x18)     // port up
+    goto loc_g_7244;
+
+  if (bl == 0x19)     // port left
+    goto loc_g_7272;
+
+  if (bl == 0x1A)     // port down
+    goto loc_g_729F;
+
+  if (bl == 0x1B)     // port right
+    goto loc_g_72CD;
+
+  if (bl == 0x1C)   // red disk, moving up
+    goto loc_g_72FA;
+
+  if (bl == 0x1D)   // red disk, moving left
+    goto loc_g_7318;
+
+  if (bl == 0x1E)   // red disk, moving down
+    goto loc_g_7333;
+
+  if (bl == 0x1F)   // red disk, moving right -> 9-Step-Bug!
+    goto loc_g_7351;
+
+  if (bl == 0x20)   // red disk, touching up
+    goto loc_g_736C;
+
+  if (bl == 0x21)   // red disk, touching left
+    goto loc_g_7381;
+
+  if (bl == 0x22)   // red disk, touching down
+    goto loc_g_7396;
+
+  if (bl == 0x23)   // red disk, touching right
+    goto loc_g_73AB;
+
+  if (bl == 0x24)     // yellow disk, pushing up
+    goto loc_g_73C0;
+
+  if (bl == 0x25)     // yellow disk, pushing left
+    goto loc_g_73DD;
+
+  if (bl == 0x26)     // yellow disk, pushing right -> order of "down" exchanged with "right"!
+    goto loc_g_7417;
+
+  if (bl == 0x27)     // yellow disk, pushing down  -> order of "down" exchanged with "right"!
+    goto loc_g_73FA;
+
+  if (bl == 0x28)     // orange disk, pushing left
+    goto loc_g_7434;
+
+  if (bl == 0x29)     // orange disk, pushing right
+    goto loc_g_7451;
+
+  if (bl == 0x2A)   // red disk, release
+    goto loc_g_747F;
+
+  ExitToMenuFlag = 1;
+  return subAnimateMurphy;
+
+  // ==========================================================================
+  //                       infotron, moving up
+  // ==========================================================================
+
+loc_g_6EBA:
+  if (0 < LowByte(InfotronsNeeded))
+    InfotronsNeeded = InfotronsNeeded - 1;
+
+  subDisplayInfotronsNeeded();
+loc_g_6EC8: // space, base
+  PlayField16[si] = fiMurphy;
+  subAdjustZonksInfotronsAboveMurphy(si + FieldWidth);
+  return subAnimateMurphy;
+
+  // ==========================================================================
+  //                       infotron, moving left
+  // ==========================================================================
+
+loc_g_6ED8:
+  if (0 < LowByte(InfotronsNeeded))
+    InfotronsNeeded = InfotronsNeeded - 1;
+
+  subDisplayInfotronsNeeded();
+loc_g_6EE6: // space, base
+  PlayField16[si] = fiMurphy;
+  subAdjustZonksInfotronsAboveMurphy(si + 1);
+  return subAnimateMurphy;
+
+  // ==========================================================================
+  //                       infotron, moving down
+  // ==========================================================================
+
+loc_g_6EF6:
+  if (0 < LowByte(InfotronsNeeded))
+    InfotronsNeeded = InfotronsNeeded - 1;
+
+  subDisplayInfotronsNeeded();
+loc_g_6F04: // space, base
+  if (LowByte(PlayField16[si - FieldWidth]) != fiExplosion)
+    PlayField16[si - FieldWidth] = 0;
+
+  PlayField16[si] = fiMurphy;
+  return subAnimateMurphy;
+
+  // ==========================================================================
+  //                       infotron, moving right
+  // ==========================================================================
+
+loc_g_71B6:
+  if (0 < LowByte(InfotronsNeeded))
+    InfotronsNeeded = InfotronsNeeded - 1;
+
+  subDisplayInfotronsNeeded();
+loc_g_71C4: // space, base
+  subAdjustZonksInfotronsAboveMurphy(si - 1);
+  PlayField16[si] = fiMurphy;
+  return subAnimateMurphy;
+
+  // ==========================================================================
+  //                       infotron, touching up
+  // ==========================================================================
+
+loc_g_71D4:
+  if (0 < LowByte(InfotronsNeeded))
+    InfotronsNeeded = InfotronsNeeded - 1;
+
+  subDisplayInfotronsNeeded();
+loc_g_71E2: // base
+  if (LowByte(PlayField16[si - FieldWidth]) != fiExplosion)
+    PlayField16[si - FieldWidth] = 0;
+
+  return subAnimateMurphy;
+
+  // ==========================================================================
+  //                       infotron, touching left
+  // ==========================================================================
+
+loc_g_71F0:
+  if (0 < LowByte(InfotronsNeeded))
+    InfotronsNeeded = InfotronsNeeded - 1;
+
+  subDisplayInfotronsNeeded();
+loc_g_71FE: // base
+  if (LowByte(PlayField16[si - 1]) != fiExplosion)
+    PlayField16[si - 1] = 0;
+
+  return subAnimateMurphy;
+
+  // ==========================================================================
+  //                       infotron, touching down
+  // ==========================================================================
+
+loc_g_720C:
+  if (0 < LowByte(InfotronsNeeded))
+    InfotronsNeeded = InfotronsNeeded - 1;
+
+  subDisplayInfotronsNeeded();
+loc_g_721A: // base
+  if (LowByte(PlayField16[si + FieldWidth]) != fiExplosion)
+    PlayField16[si + FieldWidth] = 0;
+
+  return subAnimateMurphy;
+
+  // ==========================================================================
+  //                       infotron, touching right
+  // ==========================================================================
+
+loc_g_7228:
+  if (0 < LowByte(InfotronsNeeded))
+    InfotronsNeeded = InfotronsNeeded - 1;
+
+  subDisplayInfotronsNeeded();
+loc_g_7236: // base
+  if (LowByte(PlayField16[si + 1]) != fiExplosion)
+    PlayField16[si + 1] = 0;
+
+  return subAnimateMurphy;
+
+  // ==========================================================================
+  //                       zonk, pushing left
+  // ==========================================================================
+
+loc_g_6F18:
+  if (LowByte(PlayField16[si]) != fiExplosion)
+    PlayField16[si] = 0;
+
+  PlayField16[si - 1] = fiMurphy;
+  PlayField16[si - 2] = fiZonk;
+  subExplodeSnikSnaksBelow(si - 2);
+  si = si - 1;
+  return subAnimateMurphy;
+
+  // ==========================================================================
+  //                       zonk, pushing right
+  // ==========================================================================
+
+loc_g_6F3B:
+  if (LowByte(PlayField16[si]) != fiExplosion)
+    PlayField16[si] = 0;
+
+  PlayField16[si + 1] = fiMurphy;
+  PlayField16[si + 2] = fiZonk;
+  subExplodeSnikSnaksBelow(si + 2);
+  si = si + 1;
+  return subAnimateMurphy;
+
+  // ==========================================================================
+  //                       exit
+  // ==========================================================================
+
+loc_g_6F77:
+  ExitToMenuFlag = 1;
+  return subAnimateMurphy;
+
+  // ==========================================================================
+  //               Push Zonk from right to left
+  // ==========================================================================
+
+loc_g_6F7E:
+  if (DemoKeyCode == keyLeft && PlayField16[si - 1] == fiZonk)
+    return subAnimateMurphy;
+
+  PlayField16[si] = fiMurphy; // else restore - no more zonk pushing!
+  PlayField16[si - 1] = fiZonk;
+  if (LowByte(PlayField16[si - 2]) != fiExplosion)
+    PlayField16[si - 2] = 0;
+
+  subCopyFieldToScreen(si, fiMurphy);
+  return subAnimateMurphy;
+
+  // ==========================================================================
+  //                       Push Zonk from left to right
+  // ==========================================================================
+
+loc_g_6FBC:
+  if (DemoKeyCode == keyRight && PlayField16[si + 1] == fiZonk)
+    return subAnimateMurphy;
+
+  PlayField16[si] = fiMurphy; // else restore - no more zonk pushing!
+  PlayField16[si + 1] = fiZonk;
+  if (LowByte(PlayField16[si + 2]) != fiExplosion)
+    PlayField16[si + 2] = 0;
+
+  subCopyFieldToScreen(si, fiMurphy);
+  return subAnimateMurphy;
+
+  // ==========================================================================
+  //               Push orange disk from right to left
+  // ==========================================================================
+
+loc_g_6FFA:
+  if (DemoKeyCode == keyLeft && PlayField16[si - 1] == fiOrangeDisk)
+    return subAnimateMurphy;
+
+  PlayField16[si] = fiMurphy; // else restore - no more pushing!
+  PlayField16[si - 1] = fiOrangeDisk;
+  if (LowByte(PlayField16[si - 2]) != fiExplosion)
+    PlayField16[si - 2] = 0;
+
+  subCopyFieldToScreen(si, fiMurphy);
+  return subAnimateMurphy;
+
+  // ==========================================================================
+  //               Push orange disk from left to right
+  // ==========================================================================
+
+loc_g_7038:
+  if (DemoKeyCode == keyRight && PlayField16[si + 1] == fiOrangeDisk)
+    return subAnimateMurphy;
+
+  PlayField16[si] = fiMurphy; // else restore - no more pushing!
+  PlayField16[si + 1] = fiOrangeDisk;
+  if (LowByte(PlayField16[si + 2]) != fiExplosion)
+    PlayField16[si + 2] = 0;
+
+  subCopyFieldToScreen(si, fiMurphy);
+  return subAnimateMurphy;
+
+  // ==========================================================================
+  //               Push yellow disk from down to up
+  // ==========================================================================
+
+loc_g_7076:
+  if (DemoKeyCode == keyUp && PlayField16[si - FieldWidth] == fiYellowDisk)
+    return subAnimateMurphy;
+
+  PlayField16[si] = fiMurphy; // else restore - no more pushing!
+  PlayField16[si - FieldWidth] = fiYellowDisk;
+  if (LowByte(PlayField16[si - 2 * FieldWidth]) != fiExplosion)
+    PlayField16[si - 2 * FieldWidth] = 0;
+
+  subCopyFieldToScreen(si, fiMurphy);
+  return subAnimateMurphy;
+
+  // ==========================================================================
+  //               Push yellow disk from right to left
+  // ==========================================================================
+
+loc_g_70B4:
+  if (DemoKeyCode == keyLeft && PlayField16[si - 1] == fiYellowDisk)
+    return subAnimateMurphy;
+
+  PlayField16[si] = fiMurphy; // else restore - no more pushing!
+  PlayField16[si - 1] = fiYellowDisk;
+  if (LowByte(PlayField16[si - 2]) != fiExplosion)
+    PlayField16[si - 2] = 0;
+
+  subCopyFieldToScreen(si, fiMurphy);
+  return subAnimateMurphy;
+
+  // ==========================================================================
+  //               Push yellow disk from up to down
+  // ==========================================================================
+
+loc_g_70F2:
+  if (DemoKeyCode == keyDown && PlayField16[si + FieldWidth] == fiYellowDisk)
+    return subAnimateMurphy;
+
+  PlayField16[si] = fiMurphy; // else restore - no more pushing!
+  PlayField16[si + FieldWidth] = fiYellowDisk;
+  if (LowByte(PlayField16[si + 2 * FieldWidth]) != fiExplosion)
+    PlayField16[si + 2 * FieldWidth] = 0;
+
+  subCopyFieldToScreen(si, fiMurphy);
+  return subAnimateMurphy;
+
+  // ==========================================================================
+  //               Push yellow disk from left to right
+  // ==========================================================================
+
+loc_g_7130:
+  if (DemoKeyCode == keyRight && PlayField16[si + 1] == fiYellowDisk)
+    return subAnimateMurphy;
+
+  PlayField16[si] = fiMurphy; // else restore - no more pushing!
+  PlayField16[si + 1] = fiYellowDisk;
+  if (LowByte(PlayField16[si + 2]) != fiExplosion)
+    PlayField16[si + 2] = 0;
+
+  subCopyFieldToScreen(si, fiMurphy);
+  return subAnimateMurphy;
+
+  // ==========================================================================
+  //               time red disk release (space)
+  // ==========================================================================
+
+loc_g_716E:
+  if (DemoKeyCode != keySpace)
+  {
+    PlayField16[si] = fiMurphy;
+    subCopyFieldToScreen(si, fiMurphy);
+    RedDiskReleasePhase = 0;
+  }
+  else if (MovingPictureSequencePhase == 0x20)
+  {
+    subCopyFieldToScreen(si, 43);  // anxious murphy
+    RedDiskReleasePhase = 1;
+  }
+
+  return subAnimateMurphy;
+
+  // ==========================================================================
+  // Special port down to up
+  // ==========================================================================
+
+loc_g_7244:
+  if (LowByte(PlayField16[si]) != fiExplosion)
+    PlayField16[si] = 0;
+
+  PlayField16[si - 2 * FieldWidth] = fiMurphy;
+  SplitMoveFlag = 0;
+  si = si - FieldWidth;
+  if (HighByte(PlayField16[si]) == 1)
+    subSpPortTest(si);
+
+  si = si - FieldWidth;
+  return subAnimateMurphy;
+
+  // ==========================================================================
+  // Special port right to left
+  // ==========================================================================
+
+loc_g_7272:
+  if (LowByte(PlayField16[si]) != fiExplosion)
+    PlayField16[si] = 0;
+
+  PlayField16[si - 2] = fiMurphy;
+  SplitMoveFlag = 0;
+  si = si - 1;
+  if (HighByte(PlayField16[si]) == 1)
+    subSpPortTest(si);
+
+  si = si - 1;
+  return subAnimateMurphy;
+
+  // ==========================================================================
+  // Special port up to down
+  // ==========================================================================
+
+loc_g_729F:
+  if (LowByte(PlayField16[si]) != fiExplosion)
+    PlayField16[si] = 0;
+
+  PlayField16[si + 2 * FieldWidth] = fiMurphy;
+  SplitMoveFlag = 0;
+  si = si + FieldWidth;
+  if (HighByte(PlayField16[si]) == 1)
+    subSpPortTest(si);
+
+  si = si + FieldWidth;
+  return subAnimateMurphy;
+
+  // ==========================================================================
+  // Special port left to right
+  // ==========================================================================
+
+loc_g_72CD:
+  if (LowByte(PlayField16[si]) != fiExplosion)
+    PlayField16[si] = 0;
+
+  PlayField16[si + 2] = fiMurphy;
+  SplitMoveFlag = 0;
+  si = si + 1;
+  if (HighByte(PlayField16[si]) == 1)
+    subSpPortTest(si);
+
+  si = si + 1;
+  return subAnimateMurphy;
+
+  // ==========================================================================
+  // Move Red Disk up
+  // ==========================================================================
+
+loc_g_72FA:
+  if (LowByte(PlayField16[si]) != fiExplosion)
+    PlayField16[si] = 0;
+
+  si = si - FieldWidth;
+  PlayField16[si] = fiMurphy;
+  subEatRedDisk(si); // inc+show Murphy's red disks
+  return subAnimateMurphy;
+
+  // ==========================================================================
+  // Move Red Disk left
+  // ==========================================================================
+
+loc_g_7318:
+  if (LowByte(PlayField16[si + 1]) != fiExplosion)
+    PlayField16[si + 1] = 0;
+
+  PlayField16[si] = fiMurphy;
+  subEatRedDisk(si); // inc+show Murphy's red disks
+  return subAnimateMurphy;
+
+  // ==========================================================================
+  // Move Red Disk down
+  // ==========================================================================
+
+loc_g_7333:
+  if (LowByte(PlayField16[si]) != fiExplosion)
+    PlayField16[si] = 0;
+
+  si = si + FieldWidth;
+  PlayField16[si] = fiMurphy;
+  subEatRedDisk(si); // inc+show Murphy's red disks
+  return subAnimateMurphy;
+
+  // ==========================================================================
+  // Move Red Disk right
+  // ==========================================================================
+
+loc_g_7351:
+  if (LowByte(PlayField16[si - 1]) != fiExplosion)
+    PlayField16[si - 1] = 0;
+
+  PlayField16[si] = fiMurphy;
+  subEatRedDisk(si); // inc+show Murphy's red disks
+  return subAnimateMurphy;
+
+  // ==========================================================================
+  // Eat Red Disk up
+  // ==========================================================================
+
+loc_g_736C:
+  if (LowByte(PlayField16[si - FieldWidth]) != fiExplosion)
+    PlayField16[si - FieldWidth] = 0;
+
+  subEatRedDisk(si - FieldWidth); // inc+show Murphy's red disks
+  return subAnimateMurphy;
+
+  // ==========================================================================
+  // Eat Red Disk left
+  // ==========================================================================
+
+loc_g_7381:
+  if (LowByte(PlayField16[si - 1]) != fiExplosion)
+    PlayField16[si - 1] = 0;
+
+  subEatRedDisk(si - 1); // inc+show Murphy's red disks
+  return subAnimateMurphy;
+
+  // ==========================================================================
+  // Eat Red Disk down
+  // ==========================================================================
+
+loc_g_7396:
+  if (LowByte(PlayField16[si + FieldWidth]) != fiExplosion)
+    PlayField16[si + FieldWidth] = 0;
+
+  subEatRedDisk(si + FieldWidth); // inc+show Murphy's red disks
+  return subAnimateMurphy;
+
+  // ==========================================================================
+  // Eat Red Disk right
+  // ==========================================================================
+
+loc_g_73AB:
+  if (LowByte(PlayField16[si + 1]) != fiExplosion)
+    PlayField16[si + 1] = 0;
+
+  subEatRedDisk(si + 1); // inc+show Murphy's red disks
+  return subAnimateMurphy;
+
+  // ==========================================================================
+  //                       yellow disk, pushing up
+  // ==========================================================================
+
+loc_g_73C0:
+  if (LowByte(PlayField16[si]) != fiExplosion)
+    PlayField16[si] = 0;
+
+  si = si - FieldWidth;
+  PlayField16[si] = fiMurphy;
+  PlayField16[si - FieldWidth] = fiYellowDisk;
+  return subAnimateMurphy;
+
+  // ==========================================================================
+  //                       yellow disk, pushing left
+  // ==========================================================================
+
+loc_g_73DD:
+  if (LowByte(PlayField16[si]) != fiExplosion)
+    PlayField16[si] = 0;
+
+  si = si - 1;
+  PlayField16[si] = fiMurphy;
+  PlayField16[si - 1] = fiYellowDisk;
+  return subAnimateMurphy;
+
+  // ==========================================================================
+  //                       yellow disk, pushing down
+  // ==========================================================================
+
+loc_g_73FA:
+  if (LowByte(PlayField16[si]) != fiExplosion)
+    PlayField16[si] = 0;
+
+  si = si + FieldWidth;
+  PlayField16[si] = fiMurphy;
+  PlayField16[si + FieldWidth] = fiYellowDisk;
+  return subAnimateMurphy;
+
+  // ==========================================================================
+  //                       yellow disk pushing right
+  // ==========================================================================
+
+loc_g_7417:
+  if (LowByte(PlayField16[si]) != fiExplosion)
+    PlayField16[si] = 0;
+
+  si = si + 1;
+  PlayField16[si] = fiMurphy;
+  PlayField16[si + 1] = fiYellowDisk;
+  return subAnimateMurphy;
+
+  // ==========================================================================
+  //                       orange disk, pushing left
+  // ==========================================================================
+
+loc_g_7434:
+  if (LowByte(PlayField16[si]) != fiExplosion)
+    PlayField16[si] = 0;
+
+  si = si - 1;
+  PlayField16[si] = fiMurphy;
+  PlayField16[si - 1] = fiOrangeDisk;
+  return subAnimateMurphy;
+
+  // ==========================================================================
+  //                       orange disk, pushing right
+  // ==========================================================================
+
+loc_g_7451:
+  if (LowByte(PlayField16[si]) != fiExplosion)
+    PlayField16[si] = 0;
+
+  si = si + 1;
+  PlayField16[si] = fiMurphy;
+  PlayField16[si + 1] = fiOrangeDisk;
+  if (PlayField16[si + FieldWidth + 1] == 0) // make it fall down if below is empty
+  {
+    MovHighByte(&PlayField16[si + 1], 0x20);
+    MovHighByte(&PlayField16[si + FieldWidth + 1], fiOrangeDisk);
+  }
+
+  return subAnimateMurphy;
+
+  // ==========================================================================
+  //                     Release a red disk
+  // ==========================================================================
+
+loc_g_747F:
+  PlayField16[si] = fiMurphy;
+  RedDiskReleasePhase = 2;
+  RedDiskCount = RedDiskCount - 1;
+  subDisplayRedDiskCount();
+  subSoundFXPush();                 // Sound effects
+
+  return subAnimateMurphy;
+} // subAnimateMurphy
+
+// ==========================================================================
+//                              SUBROUTINE
+// ==========================================================================
+int subExplodeSnikSnaksBelow(int si)
+{
+  int subExplodeSnikSnaksBelow;
+
+  int ax;
+
+  ax = LowByte(PlayField16[si + FieldWidth]);
+  if (ax == 0x11 || ax == 0xBB)
+    ExplodeFieldSP(si + FieldWidth);
+
+  return subExplodeSnikSnaksBelow;
+} // subExplodeSnikSnaksBelow
+
+// ==========================================================================
+//                              SUBROUTINE
+// Does pushing against an object kill Murphy?
+// ==========================================================================
+static boolean subMoveKillsMurphy(int si, int ax, int bl)
+{
+  static boolean subMoveKillsMurphy;
+
+  int al, ah;
+
+  al = LowByte(ax);
+  ah = HighByte(ax);
+  if (ax == 0xFFFF || ax == 0xAAAA || ah == 0)
+    goto loc_g_752E;
+
+  if (al == fiZonk)
+    goto loc_g_74E7;
+
+  if (al == fiExplosion)
+    goto loc_g_7530;
+
+  if (fiOrangeDisk <= al && al <= fiPortUp)
+    goto loc_g_752E;
+
+  ExplodeFieldSP(si);                 // Explode
+  subMoveKillsMurphy = True;
+  return subMoveKillsMurphy;
+
+loc_g_74E7: // zonk
+  if (bl == keyLeft)
+    goto loc_g_74F6;
+
+  if (bl == keyRight)
+    goto loc_g_7512;
+
+  ExplodeFieldSP(si);                 // Explode
+  subMoveKillsMurphy = True;
+  return subMoveKillsMurphy;
+
+loc_g_74F6: // zonk left
+  ah = ah & 0xF0;
+  if (! (ah == 0x20 || ah == 0x40 || ah == 0x50 || ah == 0x70))
+    ExplodeFieldSP(si);
+
+  subMoveKillsMurphy = True;                           // Set carry flag
+  return subMoveKillsMurphy;
+
+loc_g_7512: // zonk right
+  ah = ah & 0xF0;
+  if (! (ah == 0x30 || ah == 0x40 || ah == 0x60 || ah == 0x70))
+    ExplodeFieldSP(si);
+
+loc_g_752E: // Marked fields and Ports
+  subMoveKillsMurphy = True;                           // Set carry flag
+  return subMoveKillsMurphy;
+
+loc_g_7530: // explosion
+  if ((ah & 0x80) != 0)
+    goto loc_g_753A;
+
+  if (ah >= 4)
+    goto loc_g_753F;
+
+loc_g_753A:
+  ExplodeFieldSP(si);                 // Explode
+  subMoveKillsMurphy = True;                           // Set carry flag
+  return subMoveKillsMurphy;
+
+loc_g_753F:
+  PlayField16[si] = 0;
+  subMoveKillsMurphy = False;
+
+  return subMoveKillsMurphy;
+} // subMoveKillsMurphy
+
+// ==========================================================================
+//                              SUBROUTINE
+// Test If si 's a special (grav) port and If so Then fetch new values (see below)
+// change conditions to port specs
+// The 10-port data base is at data_h_0D28, 10 entries of 6 bytes each:
+// (hi),(lo),(gravity),(freeze zonks),(freeze enemies),(unused)
+// ==========================================================================
+int subSpPortTest(int si)
+{
+  int subSpPortTest;
+
+  int i, cx, bx;
+
+  cx = LInfo.SpecialPortCount; // number of special ports
+  for (i = 1; i <= cx; i++)
+  {
+    {
+      bx = HighByte(LInfo.SpecialPort[i].PortLocation);
+      MovHighByte(&bx, LowByte(LInfo.SpecialPort[i].PortLocation));
+      if (bx / 2 == si)
+      {
+        GravityFlag = LInfo.SpecialPort[i].Gravity;
+        FreezeZonks = LInfo.SpecialPort[i].FreezeZonks;
+        SnikSnaksElectronsFrozen = LInfo.SpecialPort[i].FreezeEnemies;
+        //        RandomTime = RandomTime Xor RandomSeed 'is RandomTime used at all? no!
+        i = cx + 1;
+      }
+
+    }
+  }
+
+  return subSpPortTest;
+} // subSpPortTest
+
+void subCopyFieldToScreen(int si, int fi)
+{
+  int X, Y;
+
+  // +++++++++++++++++++++++++++++++++++++++++
+  X = GetStretchX(si);
+  Y = GetStretchY(si);
+  StretchedSprites.BltEx(X, Y, fi);
+  // +++++++++++++++++++++++++++++++++++++++++
+}
+
+static void subEatRedDisk(int si)
+{
+  if (AllowRedDiskCheat == 0)
+  {
+    if (RedDiskReleasePhase != 0)
+    {
+      if (RedDiskReleaseMurphyPos == si)
+        return;
+    }
+  }
+
+  RedDiskCount = (RedDiskCount + 1) % 256;
+  subDisplayRedDiskCount();
+}
+
+int subAdjustZonksInfotronsAboveMurphy(int si)
+{
+  int subAdjustZonksInfotronsAboveMurphy;
+
+  int ax;
+
+  if (LowByte(PlayField16[si]) != fiExplosion)
+    PlayField16[si] = 0;
+
+  ax = PlayField16[si - FieldWidth];
+  if (ax == 0 || ax == 0x9999)
+    goto loc_g_15A8;
+
+  if (ax == fiZonk || ax == fiInfotron)
+  {
+    MovHighByte(&PlayField16[si - FieldWidth], 0x40); // make falling straigt down
+  }
+
+  return subAdjustZonksInfotronsAboveMurphy;
+
+loc_g_15A8: // empty above
+  ax = PlayField16[si - FieldWidth - 1];
+  if (ax == fiZonk || ax == fiInfotron)
+    goto loc_g_15C5;
+
+loc_g_15B6:
+  ax = PlayField16[si - FieldWidth + 1];
+  if (ax == fiZonk || ax == fiInfotron)
+    goto loc_g_15E8;
+
+  return subAdjustZonksInfotronsAboveMurphy;
+
+loc_g_15C5: // zonk/infotron above left
+  ax = PlayField16[si - 1];
+  if (! (ax == fiZonk || ax == fiInfotron || ax == fiRAM)) // continue testing right above
+    goto loc_g_15B6;
+
+  MovHighByte(&PlayField16[si - FieldWidth - 1], 0x60); // make roll right
+  PlayField16[si - FieldWidth] = 0x8888;
+  return subAdjustZonksInfotronsAboveMurphy;
+
+loc_g_15E8: // zonk/infotron above right
+  ax = PlayField16[si + 1];
+  if (ax == fiZonk || ax == fiInfotron || ax == fiRAM)
+  {
+    MovHighByte(&PlayField16[si - FieldWidth + 1], 0x50); // make roll left
+    PlayField16[si - FieldWidth] = 0x8888;
+  }
+
+  return subAdjustZonksInfotronsAboveMurphy;
+} // subAdjustZonksInfotronsAboveMurphy
diff --git a/src/game_sp/Murphy.h b/src/game_sp/Murphy.h
new file mode 100644 (file)
index 0000000..0fdafeb
--- /dev/null
@@ -0,0 +1,21 @@
+// ----------------------------------------------------------------------------
+// Murphy.h
+// ----------------------------------------------------------------------------
+
+#ifndef MURPHY_H
+#define MURPHY_H
+
+#include "vb_types.h"
+#include "vb_defs.h"
+#include "vb_vars.h"
+#include "vb_lib.h"
+
+#include "global.h"
+
+extern int subAdjustZonksInfotronsAboveMurphy(int si);
+extern int subAnimateMurphy(int si);
+extern void subCopyFieldToScreen(int si, int fi);
+extern int subExplodeSnikSnaksBelow(int si);
+extern int subSpPortTest(int si);
+
+#endif /* MURPHY_H */
diff --git a/src/game_sp/OrangeDisk.c b/src/game_sp/OrangeDisk.c
new file mode 100644 (file)
index 0000000..3a383b3
--- /dev/null
@@ -0,0 +1,86 @@
+// ----------------------------------------------------------------------------
+// OrangeDisk.c
+// ----------------------------------------------------------------------------
+
+#include "OrangeDisk.h"
+
+static char *VB_Name = "modOrangeDisk";
+// --- Option Explicit
+// ==========================================================================
+//                              SUBROUTINE
+// Animate/move orange disks (falling)
+// ==========================================================================
+
+int subAnimateOrangeDisks(int si)
+{
+  int subAnimateOrangeDisks;
+
+  int ax, bl, dx, X, Y;
+
+  ax = PlayField16[si];
+  if (LowByte(ax) != fiOrangeDisk)
+    return subAnimateOrangeDisks;
+
+  if (ax >= 0x3008) // disk is falling
+    goto loc_g_2804;
+
+  if (ax >= 0x2008) // disk is in wait state before falling
+    goto loc_g_27DA;
+
+  if (PlayField16[si + FieldWidth] == 0)
+    goto loc_g_27CF;
+
+  return subAnimateOrangeDisks;
+
+loc_g_27CF: // below is empty -> disk may start to fall
+  MovHighByte(&PlayField16[si], 0x20);
+  MovHighByte(&PlayField16[si + FieldWidth], fiOrangeDisk);
+  return subAnimateOrangeDisks;
+
+loc_g_27DA:
+  if (PlayField16[si + FieldWidth] == 0)
+  {
+    PlayField16[si] = fiOrangeDisk;
+    return subAnimateOrangeDisks;
+  } // loc_g_27E8:
+
+  bl = HighByte(PlayField16[si]) + 1;
+  if (bl == 0x22) // wait phase is finished
+    bl = 0x30;
+
+  MovHighByte(&PlayField16[si], bl);
+  return subAnimateOrangeDisks;
+
+loc_g_2804: // disk is falling
+  // +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+  dx = HighByte(PlayField16[si]) & 0x7;
+  X = GetStretchX(si);
+  Y = GetStretchY(si);
+  StretchedSprites.BltEx(X, Y, 0);
+  StretchedSprites.BltEx(X, Y + TwoPixels * (dx + 1), fiOrangeDisk);
+  // +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+  bl = HighByte(PlayField16[si]) + 1;
+  if ((bl & 0x7) != 0)
+  {
+    MovHighByte(&PlayField16[si], bl);
+    return subAnimateOrangeDisks;
+  }
+
+  PlayField16[si] = 0;
+  PlayField16[si + FieldWidth] = fiOrangeDisk;
+  si = si + FieldWidth;
+  if (PlayField16[si + FieldWidth] == 0)
+  {
+    MovHighByte(&PlayField16[si], 0x30); // go on falling down
+    MovHighByte(&PlayField16[si + FieldWidth], fiOrangeDisk);
+    return subAnimateOrangeDisks;
+  } // loc_g_2867:
+
+  if (LowByte(PlayField16[si + FieldWidth]) == fiExplosion)
+    return subAnimateOrangeDisks;
+
+  ExplodeFieldSP(si);                 // Explode
+
+  return subAnimateOrangeDisks;
+} // subAnimateOrangeDisks
+
diff --git a/src/game_sp/OrangeDisk.h b/src/game_sp/OrangeDisk.h
new file mode 100644 (file)
index 0000000..2910b1d
--- /dev/null
@@ -0,0 +1,17 @@
+// ----------------------------------------------------------------------------
+// OrangeDisk.h
+// ----------------------------------------------------------------------------
+
+#ifndef ORANGEDISK_H
+#define ORANGEDISK_H
+
+#include "vb_types.h"
+#include "vb_defs.h"
+#include "vb_vars.h"
+#include "vb_lib.h"
+
+#include "global.h"
+
+extern int subAnimateOrangeDisks(int si);
+
+#endif /* ORANGEDISK_H */
diff --git a/src/game_sp/PathTools.c b/src/game_sp/PathTools.c
new file mode 100644 (file)
index 0000000..c1aafcb
--- /dev/null
@@ -0,0 +1,300 @@
+// ----------------------------------------------------------------------------
+// PathTools.c
+// ----------------------------------------------------------------------------
+
+#include "PathTools.h"
+
+static char *VB_Name = "PathTools_Module";
+// --- Option Explicit
+// --- Option Compare Text
+
+// ###########  Quote & UnQuote ##################################################
+
+void UnQuote(char *ST)
+{
+  long L;
+
+  L = strlen(ST);
+  while (STRING_IS_LIKE(ST, "\"*"))
+  {
+    ST = Right(ST, L - 1);
+    L = L - 1;
+  }
+
+  while (STRING_IS_LIKE(ST, "*\""))
+  {
+    ST = Left(ST, L - 1);
+  }
+}
+
+void Quote(char *ST)
+{
+  if (! STRING_IS_LIKE(ST, "\"*"))
+    ST = CAT("\"", ST);
+
+  if (! STRING_IS_LIKE(ST, "*\""))
+    ST = CAT(ST, "\"");
+}
+
+char *UnQuoted(char *STRG)
+{
+  char *UnQuoted;
+
+  long L;
+  char *ST;
+
+  ST = STRG;
+  L = strlen(ST);
+  while (STRING_IS_LIKE(ST, "\"*"))
+  {
+    ST = Right(ST, L - 1);
+    L = L - 1;
+  }
+
+  while (STRING_IS_LIKE(ST, "*\""))
+  {
+    ST = Left(ST, L - 1);
+  }
+
+  UnQuoted = ST;
+
+  return UnQuoted;
+}
+
+char *Quoted(char *STRG)
+{
+  char *Quoted;
+
+  char *ST;
+
+  ST = STRG;
+  if (! STRING_IS_LIKE(ST, "\"*"))
+    ST = CAT("\"", ST);
+
+  if (! STRING_IS_LIKE(ST, "*\""))
+    ST = CAT(ST, "\"");
+
+  Quoted = ST;
+
+  return Quoted;
+}
+
+// ############ Path-/FileName-Extraction and concatanation ######################
+
+char *StripDir(char *Path)
+{
+  char *StripDir;
+
+  char *T;
+  long i;
+
+  T = StrReverse(Path);
+  i = InStr(1, T, "/");
+  if (i == 0)
+    StripDir = "";
+  else
+    StripDir = StrReverse(Right(T, strlen(T) - i));
+
+  return StripDir;
+}
+
+char *StripFileName(char *Path)
+{
+  char *StripFileName;
+
+  char *T;
+  long i;
+
+  T = StrReverse(Path);
+  if (STRING_IS_LIKE(T, "/*"))
+    T = Right(T, strlen(T) - 1);
+
+  i = InStr(1, T, "/");
+  if (i == 0)
+    i = strlen(T) + 1;
+
+  if (i < 2)
+    StripFileName = "";
+  else
+    StripFileName = StrReverse(Left(T, i - 1));
+
+  return StripFileName;
+}
+
+char *StripExtension(char *Path)
+{
+  char *StripExtension;
+
+  char *T;
+  long i, iSlash;
+
+  T = StrReverse(Path);
+  iSlash = InStr(1, T, "/");
+  i = InStr(1, T, ".");
+  if ((i < 2) || (iSlash < i))
+    StripExtension = "";
+  else
+    StripExtension = StrReverse(Left(T, i - 1));
+
+  return StripExtension;
+}
+
+char *NewExtension(char *Path, char *NewExt)
+{
+  char *NewExtension;
+
+  // NewExtension("C:\MyPath\MyFile.Old","New") returns "C:\MyPath\MyFile.New"
+  // NewExtension("C:\MyPath.dir\MyFile","New") returns "C:\MyPath\MyFile.New"
+  char *T;
+  long i, iSlash, ELen;
+
+  T = StrReverse(Path);
+  iSlash = InStr(1, T, "/");
+  i = InStr(1, T, ".");
+  if ((i < 1) || (iSlash < i))
+    ELen = 0;
+  else
+    ELen = i;
+
+  NewExtension = CAT(Left(StrReverse(T), strlen(T) - i), ".", NewExt);
+
+  return NewExtension;
+}
+
+char *StripExtensionlessFileName(char *Path)
+{
+  char *StripExtensionlessFileName;
+
+  char *T, *T2;
+  long i, iSlash;
+
+  T = StripFileName(Path);
+  T2 = StripExtension(Path);
+  StripExtensionlessFileName = Left(T, strlen(T) - strlen(T2) - (0 < strlen(T2) ?  1 :  1));
+
+  return StripExtensionlessFileName;
+}
+
+char *WithSlash(char *Path)
+{
+  char *WithSlash;
+
+  if (STRING_IS_LIKE(Path, "*/"))
+  {
+    WithSlash = Path;
+  }
+  else
+  {
+    WithSlash = CAT(Path, "/");
+  }
+
+  return WithSlash;
+}
+
+char *SlashLess(char *Path)
+{
+  char *SlashLess;
+
+  SlashLess = Path;
+  while (STRING_IS_LIKE(SlashLess, "*/"))
+  {
+    SlashLess = Left(Path, strlen(Path) - 1);
+  }
+
+  return SlashLess;
+}
+
+// ############ File-/Diresctory-Operations ######################################
+
+boolean FileExists(char *Path)
+{
+  boolean FileExists;
+
+  if ((STRING_IS_LIKE(Dir(Path), "")) || (STRING_IS_LIKE(Path, "")))
+    FileExists = False;
+  else
+    FileExists = True;
+
+  return FileExists;
+}
+
+void MayKill(char *Path)
+{
+
+  // --- On Error GoTo MayKillEH
+  Kill(Path);
+  // MayKillEH:
+}
+
+boolean IsDir(char *Path)
+{
+  boolean IsDir;
+
+
+  // --- On Error Resume Next
+  IsDir = (vbDirectory == (GetAttr(Path) & vbDirectory));
+  if (Err.Number != 0)
+    IsDir = False;
+
+  return IsDir;
+}
+
+// ######### binary comparison of files ##########################################
+
+boolean FilesEqual(char *Path1, char *Path2)
+{
+  boolean FilesEqual;
+
+  int FNum1, FNum2;
+  long nSize, i;
+  boolean b1Open, b2Open;
+  byte *bin1, *bin2;
+
+  FilesEqual = False;
+  // Debug.Assert(FileExists(Path1));
+  // Debug.Assert(FileExists(Path2));
+  if (! (FileExists(Path1) && FileExists(Path2)))
+    return FilesEqual;
+
+  nSize = FileLen(Path1);
+  if (nSize != FileLen(Path2))
+    return FilesEqual;
+
+  bin1 = REDIM_1D(sizeof(byte), 0, nSize + 1 - 1);
+  bin2 = REDIM_1D(sizeof(byte), 0, nSize + 1 - 1);
+  b1Open = False;
+  b2Open = False;
+
+  // --- On Error GoTo FilesEqualEH
+  // FNum1 = FreeFile();
+  FNum1 = fopen(Path1, "rb");
+  b1Open = True;
+  FILE_GET(FNum1, -1, &bin1, sizeof(bin1));
+  fclose(FNum1);
+  b1Open = False;
+  // FNum2 = FreeFile();
+  FNum2 = fopen(Path2, "rb");
+  b2Open = True;
+  FILE_GET(FNum2, -1, &bin2, sizeof(bin2));
+  fclose(FNum2);
+  b2Open = False;
+  // --- On Error GoTo 0
+
+  for (i = 1; i <= nSize; i++)
+  {
+    if (bin1[i] != bin2[i]) // return false
+      return FilesEqual;
+  }
+
+  FilesEqual = True;
+  return FilesEqual;
+
+FilesEqualEH:
+  if (b1Open)
+    Close(FNum1);
+
+  if (b2Open)
+    Close(FNum2);
+
+  return FilesEqual;
+}
diff --git a/src/game_sp/PathTools.h b/src/game_sp/PathTools.h
new file mode 100644 (file)
index 0000000..ce8fda4
--- /dev/null
@@ -0,0 +1,31 @@
+// ----------------------------------------------------------------------------
+// PathTools.h
+// ----------------------------------------------------------------------------
+
+#ifndef PATHTOOLS_H
+#define PATHTOOLS_H
+
+#include "vb_types.h"
+#include "vb_defs.h"
+#include "vb_vars.h"
+#include "vb_lib.h"
+
+#include "global.h"
+
+extern boolean FileExists(char *Path);
+extern boolean FilesEqual(char *Path1, char *Path2);
+extern boolean IsDir(char *Path);
+extern void MayKill(char *Path);
+extern char *NewExtension(char *Path, char *NewExt);
+extern void Quote(char *ST);
+extern char *Quoted(char *STRG);
+extern char *SlashLess(char *Path);
+extern char *StripDir(char *Path);
+extern char *StripExtension(char *Path);
+extern char *StripExtensionlessFileName(char *Path);
+extern char *StripFileName(char *Path);
+extern void UnQuote(char *ST);
+extern char *UnQuoted(char *STRG);
+extern char *WithSlash(char *Path);
+
+#endif /* PATHTOOLS_H */
diff --git a/src/game_sp/SettingsObject.c b/src/game_sp/SettingsObject.c
new file mode 100644 (file)
index 0000000..06c656b
--- /dev/null
@@ -0,0 +1,40 @@
+// ----------------------------------------------------------------------------
+// SettingsObject.c
+// ----------------------------------------------------------------------------
+
+#include "SettingsObject.h"
+
+// --- VERSION 1.0 CLASS
+// --- BEGIN
+// ---   MultiUse = -1  'True  // True
+// ---   Persistable = 0  'NotPersistable  // NotPersistable
+// ---   DataBindingBehavior = 0  'vbNone  // vbNone
+// ---   DataSourceBehavior  = 0  'vbNone  // vbNone
+// ---   MTSTransactionMode  = 0  'NotAnMTSObject  // NotAnMTSObject
+// --- END
+
+static char *VB_Name = "SettingsObject";
+static boolean VB_GlobalNameSpace = False;
+static boolean VB_Creatable = True;
+static boolean VB_PredeclaredId = False;
+static boolean VB_Exposed = False;
+// --- Option Explicit
+// --- Option Compare Text
+
+const char *AppName = "MegaPlex";
+const char *Config = "Config";
+
+void SettingsObject_Save(char *ValName, int Val)
+{
+  SaveSetting(AppName, Config, ValName, Val);
+}
+
+int SettingsObject_Read(char *ValName, int Default)
+{
+  int Read;
+
+  Read = GetSetting(AppName, Config, ValName, Default);
+
+  return Read;
+}
+
diff --git a/src/game_sp/SettingsObject.h b/src/game_sp/SettingsObject.h
new file mode 100644 (file)
index 0000000..a25e4f2
--- /dev/null
@@ -0,0 +1,18 @@
+// ----------------------------------------------------------------------------
+// SettingsObject.h
+// ----------------------------------------------------------------------------
+
+#ifndef SETTINGSOBJECT_H
+#define SETTINGSOBJECT_H
+
+#include "vb_types.h"
+#include "vb_defs.h"
+#include "vb_vars.h"
+#include "vb_lib.h"
+
+#include "global.h"
+
+extern int SettingsObject_Read(char *ValName, int Default);
+extern void SettingsObject_Save(char *ValName, int Val);
+
+#endif /* SETTINGSOBJECT_H */
diff --git a/src/game_sp/SnikSnaks.c b/src/game_sp/SnikSnaks.c
new file mode 100644 (file)
index 0000000..1321481
--- /dev/null
@@ -0,0 +1,703 @@
+// ----------------------------------------------------------------------------
+// SnikSnaks.c
+// ----------------------------------------------------------------------------
+
+#include "SnikSnaks.h"
+
+static int subDrawSnikSnakFromAbove(int si, int bx);
+static int subDrawSnikSnakFromBelow(int si, int bx);
+static int subDrawSnikSnakFromLeft(int si, int bx);
+static int subDrawSnikSnakFromRight(int si, int bx);
+static int subDrawSnikSnakTurnLeft(int si, int bx);
+static int subDrawSnikSnakTurnRight(int si, int bx);
+static int subSnikSnakFromAbove(int si, int bx);
+static int subSnikSnakFromBelow(int si, int bx);
+static int subSnikSnakFromLeft(int si, int bx);
+static int subSnikSnakFromRight(int si, int bx);
+static int subSnikSnakTurnLeft(int si, int bx);
+static int subSnikSnakTurnRight(int si, int bx);
+
+static char *VB_Name = "modSnikSnak";
+// --- Option Explicit
+// ==========================================================================
+//                              SUBROUTINE
+// Animate/move Snik-Snaks
+// ==========================================================================
+
+int subAnimateSnikSnaks(int si)
+{
+  int subAnimateSnikSnaks;
+
+  int bx, Tmp;
+
+  if (SnikSnaksElectronsFrozen == 1)
+    return subAnimateSnikSnaks;
+
+  //  If LowByte(PlayField16(si)) <> fiSnikSnak Then Exit Function
+  // Debug.Assert (LowByte(PlayField16[si]) == fiSnikSnak);
+  bx = HighByte(PlayField16[si]);
+  Tmp = bx / 8;
+  switch (Tmp)
+  {
+    case 0:
+      subSnikSnakTurnLeft(si, bx); // turning, bx=0 -> point N, bx = 1 -> point NW etc.
+      break;
+
+    case 1:
+      subSnikSnakTurnRight(si, bx); // turn right
+      break;
+
+    case 2:
+      subSnikSnakFromBelow(si, bx); // access si from below
+      break;
+
+    case 3:
+      subSnikSnakFromRight(si, bx); // access si from right
+      break;
+
+    case 4:
+      subSnikSnakFromAbove(si, bx); // access si from above
+      break;
+
+    case 5:
+      subSnikSnakFromLeft(si, bx); // access si from left
+      break;
+
+    default:
+      // Debug.Assert(False);
+      break;
+  }
+
+  return subAnimateSnikSnaks;
+} // subAnimateSnikSnaks
+
+int subDrawAnimatedSnikSnaks(int si)
+{
+  int subDrawAnimatedSnikSnaks;
+
+  int bx, Tmp;
+
+  // If SnikSnaksElectronsFrozen = 1 Then Exit Function
+  if (LowByte(PlayField16[si]) != fiSnikSnak)
+    return subDrawAnimatedSnikSnaks;
+
+  bx = HighByte(PlayField16[si]);
+  Tmp = bx / 8;
+  switch (Tmp)
+  {
+    case 0:
+      subDrawSnikSnakTurnLeft(si, bx); // turning, bx=0 -> point N, bx = 1 -> point NW etc.
+      break;
+
+    case 1:
+      subDrawSnikSnakTurnRight(si, bx); // turn right
+      break;
+
+    case 2:
+      subDrawSnikSnakFromBelow(si, bx); // access si from below
+      break;
+
+    case 3:
+      subDrawSnikSnakFromRight(si, bx); // access si from right
+      break;
+
+    case 4:
+      subDrawSnikSnakFromAbove(si, bx); // access si from above
+      break;
+
+    case 5:
+      subDrawSnikSnakFromLeft(si, bx); // access si from left
+      break;
+  }
+
+  return subDrawAnimatedSnikSnaks;
+} // subAnimateSnikSnaks
+
+static int subSnikSnakTurnLeft(int si, int bx)
+{
+  static int subSnikSnakTurnLeft;
+
+  int ax, ah, bl, dx, X, Y;
+
+  ax = (TimerVar & 3);
+  if (ax != 0)
+  {
+    if (ax == 3)
+      goto loc_g_7622;
+
+    return subSnikSnakTurnLeft;
+  } // loc_g_75E0:
+
+  // +++++++++++++++++++++++++++++++++++++++++++++++++++++
+  X = GetStretchX(si);
+  Y = GetStretchY(si);
+  StretchedSprites.BltEx(X, Y, aniSnikSnak[bx]);
+  // +++++++++++++++++++++++++++++++++++++++++++++++++++++
+  bx = (bx + 1) & 0x7;
+  MovHighByte(&PlayField16[si], bx);
+  return subSnikSnakTurnLeft;
+
+locMayExplode760A:
+  ah = HighByte(ax);
+  if (ah == 0x1B)
+    return subSnikSnakTurnLeft;
+
+  if (ah == 0x19)
+    return subSnikSnakTurnLeft;
+
+  if (ah == 0x18)
+    return subSnikSnakTurnLeft;
+
+  if (ah == 0x1A)
+    return subSnikSnakTurnLeft;
+
+  ExplodeFieldSP(si); // Explode
+  return subSnikSnakTurnLeft;
+
+loc_g_7622:
+  bl = HighByte(PlayField16[si]);
+  if (bl == 0)
+    goto loc_g_763B;
+
+  if (bl == 2)
+    goto loc_g_765E;
+
+  if (bl == 4)
+    goto loc_g_7681;
+
+  if (bl == 6)
+    goto loc_g_76A7;
+
+  return subSnikSnakTurnLeft;
+
+loc_g_763B: // pointing up
+  ax = PlayField16[si - FieldWidth];
+  if (ax == 0) // above is empty -> go up
+    goto loc_g_764E;
+
+  if (LowByte(ax) == fiMurphy) // above is murphy -> explode
+    goto locMayExplode760A;
+
+  return subSnikSnakTurnLeft;
+
+loc_g_764E: // above is empty -> go up
+  PlayField16[si] = 0x1BB;
+  si = si - FieldWidth;
+  PlayField16[si] = 0x1011;
+  return subSnikSnakTurnLeft;
+
+loc_g_765E: // pointing left
+  ax = PlayField16[si - 1];
+  if (ax == 0) // left is empty -> go there
+    goto loc_g_7671;
+
+  if (LowByte(ax) == fiMurphy) // left is murphy -> explode
+    goto locMayExplode760A;
+
+  return subSnikSnakTurnLeft;
+
+loc_g_7671: // left is empty -> go there
+  PlayField16[si] = 0x2BB;
+  si = si - 1;
+  PlayField16[si] = 0x1811;
+  return subSnikSnakTurnLeft;
+
+loc_g_7681: // pointing down
+  ax = PlayField16[si + FieldWidth];
+  if (ax == 0) // below is empty -> go down
+    goto loc_g_7697;
+
+  if (LowByte(ax) == fiMurphy) // below is murphy -> explode
+    goto locMayExplode760A;
+
+  return subSnikSnakTurnLeft;
+
+loc_g_7697: // below is empty -> go down
+  PlayField16[si] = 0x3BB;
+  si = si + FieldWidth;
+  PlayField16[si] = 0x2011;
+  return subSnikSnakTurnLeft;
+
+loc_g_76A7: // pointing Right
+  ax = PlayField16[si + 1];
+  if (ax == 0) // right is empty -> go there
+    goto loc_g_76BD;
+
+  if (LowByte(ax) == fiMurphy) // right is murphy -> explode
+    goto locMayExplode760A;
+
+  return subSnikSnakTurnLeft;
+
+loc_g_76BD: // right is empty -> go there
+  PlayField16[si] = 0x4BB;
+  si = si + 1;
+  PlayField16[si] = 0x2811;
+
+  return subSnikSnakTurnLeft;
+} // subSnikSnakTurnLeft
+
+static int subSnikSnakTurnRight(int si, int bx)
+{
+  static int subSnikSnakTurnRight;
+
+  int ax, ah, bl, dx, X, Y;
+
+  ax = (TimerVar & 3);
+  if (ax != 0)
+  {
+    if (ax == 3)
+      goto loc_g_771F;
+
+    return subSnikSnakTurnRight;
+  } // loc_g_76DB:
+
+  // +++++++++++++++++++++++++++++++++++++++++++++++++++++
+  X = GetStretchX(si);
+  Y = GetStretchY(si);
+  StretchedSprites.BltEx(X, Y, aniSnikSnak[0x10 - bx]);
+  // +++++++++++++++++++++++++++++++++++++++++++++++++++++
+  bx = ((bx + 1) & 0x7) | 8;
+  MovHighByte(&PlayField16[si], bx);
+  return subSnikSnakTurnRight;
+
+locMayExplode7707:
+  ah = HighByte(ax);
+  if (ah == 0x1B)
+    return subSnikSnakTurnRight;
+
+  if (ah == 0x19)
+    return subSnikSnakTurnRight;
+
+  if (ah == 0x18)
+    return subSnikSnakTurnRight;
+
+  if (ah == 0x1A)
+    return subSnikSnakTurnRight;
+
+  ExplodeFieldSP(si); // Explode
+  return subSnikSnakTurnRight;
+
+loc_g_771F:
+  bl = HighByte(PlayField16[si]);
+  if (bl == 0x8)
+    goto loc_g_7738;
+
+  if (bl == 0xA)
+    goto loc_g_77A4;
+
+  if (bl == 0xC)
+    goto loc_g_777E;
+
+  if (bl == 0xE)
+    goto loc_g_775B;
+
+  return subSnikSnakTurnRight;
+
+loc_g_7738: // pointing up
+  ax = PlayField16[si - FieldWidth];
+  if (ax == 0) // above is empty -> go up
+    goto loc_g_774B;
+
+  if (LowByte(ax) == fiMurphy) // above is murphy -> explode
+    goto locMayExplode7707;
+
+  return subSnikSnakTurnRight;
+
+loc_g_774B: // above is empty -> go up
+  PlayField16[si] = 0x1BB;
+  si = si - FieldWidth;
+  PlayField16[si] = 0x1011;
+  return subSnikSnakTurnRight;
+
+loc_g_775B: // pointing left
+  ax = PlayField16[si - 1];
+  if (ax == 0) // left is empty -> go there
+    goto loc_g_776E;
+
+  if (LowByte(ax) == fiMurphy) // left is murphy -> explode
+    goto locMayExplode7707;
+
+  return subSnikSnakTurnRight;
+
+loc_g_776E: // left is empty -> go there
+  PlayField16[si] = 0x2BB;
+  si = si - 1;
+  PlayField16[si] = 0x1811;
+  return subSnikSnakTurnRight;
+
+loc_g_777E: // pointing down
+  ax = PlayField16[si + FieldWidth];
+  if (ax == 0) // below is empty -> go down
+    goto loc_g_7794;
+
+  if (LowByte(ax) == fiMurphy) // below is murphy -> explode
+    goto locMayExplode7707;
+
+  return subSnikSnakTurnRight;
+
+loc_g_7794: // below is empty -> go down
+  PlayField16[si] = 0x3BB;
+  si = si + FieldWidth;
+  PlayField16[si] = 0x2011;
+  return subSnikSnakTurnRight;
+
+loc_g_77A4: // pointing Right
+  ax = PlayField16[si + 1];
+  if (ax == 0) // right is empty -> go there
+    goto loc_g_77BA;
+
+  if (LowByte(ax) == fiMurphy) // right is murphy -> explode
+    goto locMayExplode7707;
+
+  return subSnikSnakTurnRight;
+
+loc_g_77BA: // right is empty -> go there
+  PlayField16[si] = 0x4BB;
+  si = si + 1;
+  PlayField16[si] = 0x2811;
+
+  return subSnikSnakTurnRight;
+} // subSnikSnakTurnRight
+
+static int subSnikSnakFromBelow(int si, int bx)
+{
+  static int subSnikSnakFromBelow;
+
+  int ax, ah, bl, dx, X, Y;
+
+  bx = bx - 0xF;  // get and increment sequence#
+  // +++++++++++++++++++++++++++++++++++++++++++++++++++++
+  X = GetStretchX(si);
+  Y = GetStretchY(si + FieldWidth);
+  StretchedSprites.BltEx(X, Y, 0);
+  StretchedSprites.BltEx(X, Y - bx * TwoPixels, aniSnikSnakUp + bx);
+  // +++++++++++++++++++++++++++++++++++++++++++++++++++++
+  bl = LowByte(bx);
+  if (bl == 7 && LowByte(PlayField16[si + FieldWidth]) != fiExplosion)
+  {
+    PlayField16[si + FieldWidth] = 0; // sniknak left that field
+  }
+
+  if (bl < 8) // sniksnak still goes up
+  {
+    bl = bl + 0x10;
+    MovHighByte(&PlayField16[si], bl);
+    return subSnikSnakFromBelow;
+  } // loc_g_7813
+
+  PlayField16[si] = 0x11; // sequence#=8 -> arrived at the new field
+  ax = PlayField16[si - 1]; // check left field
+  if (ax == 0 || LowByte(ax) == fiMurphy) // check for empty or murphy
+  {
+    MovHighByte(&PlayField16[si], 1); // start to turn left
+    return subSnikSnakFromBelow;
+  } // loc_g_7826: and 'loc_g_7833:
+
+  ax = PlayField16[si - FieldWidth]; // cannot turn left -> check above
+  if (ax == 0) // check if empty
+  {
+    PlayField16[si] = 0x1BB; // mark as "sniksnak leaving"
+    si = si - FieldWidth; // go up!
+    PlayField16[si] = 0x1011;
+    return subSnikSnakFromBelow;
+  } // loc_g_784A:
+
+  if (LowByte(ax) == fiMurphy) // check for murphy above
+  {
+    ExplodeFieldSP(si); // Explode
+    return subSnikSnakFromBelow;
+  } // loc_g_7855:
+
+  ax = PlayField16[si + 1]; // check right field
+  if (ax == 0 || LowByte(ax) == fiMurphy) // check for empty or murphy
+  {
+    MovHighByte(&PlayField16[si], 9); // start to turn right
+    return subSnikSnakFromBelow;
+  } // loc_g_7862: and 'loc_g_786F:
+
+  // else: no way to go, start turning around
+  MovHighByte(&PlayField16[si], 1);
+
+  return subSnikSnakFromBelow;
+} // subSnikSnakFromBelow
+
+static int subSnikSnakFromRight(int si, int bx)
+{
+  static int subSnikSnakFromRight;
+
+  int ax, ah, bl, dx, X, Y;
+
+  bx = bx - 0x17;  // get and increment sequence#
+  // +++++++++++++++++++++++++++++++++++++++++++++++++++++
+  X = GetStretchX(si + 1);
+  Y = GetStretchY(si);
+  StretchedSprites.BltEx(X, Y, 0);
+  StretchedSprites.BltEx(X - bx * TwoPixels, Y, aniSnikSnakLeft + bx);
+  // +++++++++++++++++++++++++++++++++++++++++++++++++++++
+  bl = LowByte(bx);
+  if (bl == 7 && LowByte(PlayField16[si + 1]) != fiExplosion)
+  {
+    PlayField16[si + 1] = 0; // sniknak left that field
+  } // loc_g_78AC:
+
+  if (bl < 8) // sniksnak still goes left
+  {
+    bl = bl + 0x18;
+    MovHighByte(&PlayField16[si], bl);
+    return subSnikSnakFromRight;
+  } // loc_g_78B9:
+
+  PlayField16[si] = 0x11; // sequence#=8 -> arrived at the new field
+  ax = PlayField16[si + FieldWidth]; // check below
+  if (ax == 0 || LowByte(ax) == fiMurphy) // empty or murphy?
+  {
+    MovHighByte(&PlayField16[si], 3); // yes -> turn left down
+    return subSnikSnakFromRight;
+  } // loc_g_78CC: and 'loc_g_78D9:
+
+  ax = PlayField16[si - 1]; // check left, etc ... see the comments on subSnikSnakFromBelow()
+  if (ax == 0)
+  {
+    PlayField16[si] = 0x2BB;
+    si = si - 1;                // 1 field left
+    PlayField16[si] = 0x1811;
+    return subSnikSnakFromRight;
+  } // loc_g_78F0:
+
+  if (LowByte(ax) == fiMurphy)
+  {
+    ExplodeFieldSP(si);      // Explode
+    return subSnikSnakFromRight;
+  } // loc_g_78FB:
+
+  ax = PlayField16[si - FieldWidth]; // check above
+  if (ax == 0 || LowByte(ax) == fiMurphy)
+  {
+    MovHighByte(&PlayField16[si], 0xF);
+    return subSnikSnakFromRight;
+  } // loc_g_7908:loc_g_7915:
+
+  MovHighByte(&PlayField16[si], 3);
+
+  return subSnikSnakFromRight;
+} // subSnikSnakFromRight
+
+static int subSnikSnakFromAbove(int si, int bx)
+{
+  static int subSnikSnakFromAbove;
+
+  int ax, ah, bl, dx, X, Y;
+
+  bx = bx - 0x1F;  // get and increment sequence#
+  // +++++++++++++++++++++++++++++++++++++++++++++++++++++
+  X = GetStretchX(si);
+  Y = GetStretchY(si - FieldWidth);
+  StretchedSprites.BltEx(X, Y, 0);
+  StretchedSprites.BltEx(X, Y + bx * TwoPixels, aniSnikSnakDown + bx);
+  // +++++++++++++++++++++++++++++++++++++++++++++++++++++
+  bl = LowByte(bx);
+  if (bl == 7 && LowByte(PlayField16[si - FieldWidth]) != fiExplosion)
+  {
+    PlayField16[si - FieldWidth] = 0; // sniknak left that field
+  }
+
+  if (bl < 8) // sniksnak still goes down
+  {
+    bl = bl + 0x20;
+    MovHighByte(&PlayField16[si], bl);
+    return subSnikSnakFromAbove;
+  } // loc_g_7813
+
+  PlayField16[si] = 0x11; // sequence#=8 -> arrived at the new field
+  ax = PlayField16[si + 1]; // check right
+  if (ax == 0 || LowByte(ax) == fiMurphy)
+  {
+    MovHighByte(&PlayField16[si], 5);
+    return subSnikSnakFromAbove;
+  } // loc_g_7986:
+
+  ax = PlayField16[si + FieldWidth]; // check below
+  if (ax == 0)
+  {
+    PlayField16[si] = 0x3BB;
+    si = si + FieldWidth;                 // 1 field down
+    PlayField16[si] = 0x2011;
+    return subSnikSnakFromAbove;
+  } // loc_g_799D:
+
+  if (LowByte(ax) == fiMurphy)
+  {
+    ExplodeFieldSP(si);        // Explode
+    return subSnikSnakFromAbove;
+  } // loc_g_79A8:
+
+  ax = PlayField16[si - 1]; // check left
+  if (ax == 0 || LowByte(ax) == fiMurphy)
+  {
+    MovHighByte(&PlayField16[si], 0xD);
+    return subSnikSnakFromAbove;
+  } // loc_g_79C2:
+
+  MovHighByte(&PlayField16[si], 5);
+
+  return subSnikSnakFromAbove;
+} // subSnikSnakFromAbove
+
+static int subSnikSnakFromLeft(int si, int bx)
+{
+  static int subSnikSnakFromLeft;
+
+  int ax, ah, bl, dx, X, Y;
+
+  bx = bx - 0x27;  // get and increment sequence#
+  // +++++++++++++++++++++++++++++++++++++++++++++++++++++
+  X = GetStretchX(si - 1);
+  Y = GetStretchY(si);
+  StretchedSprites.BltEx(X, Y, 0);
+  StretchedSprites.BltEx(X + bx * TwoPixels, Y, aniSnikSnakRight + bx);
+  // +++++++++++++++++++++++++++++++++++++++++++++++++++++
+  bl = LowByte(bx);
+  if (bl == 7 && LowByte(PlayField16[si - 1]) != fiExplosion)
+  {
+    PlayField16[si - 1] = 0; // sniknak left that field
+  }
+
+  if (bl < 8) // sniksnak still goes right
+  {
+    bl = bl + 0x28;
+    MovHighByte(&PlayField16[si], bl);
+    return subSnikSnakFromLeft;
+  } // loc_g_78B9:
+
+  PlayField16[si] = 0x11; // sequence#=8 -> arrived at the new field
+  ax = PlayField16[si - FieldWidth]; // check above
+  if (ax == 0 || LowByte(ax) == fiMurphy)
+  {
+    MovHighByte(&PlayField16[si], 7);
+    return subSnikSnakFromLeft;
+  } // loc_g_7A2D:
+
+  ax = PlayField16[si + 1]; // check right(straight on)
+  if (ax == 0)
+  {
+    PlayField16[si] = 0x4BB;
+    si = si + 1;                   // 1 field right
+    PlayField16[si] = 0x2811;
+    return subSnikSnakFromLeft;
+  } // loc_g_7A44:
+
+  if (LowByte(ax) == fiMurphy)
+  {
+    ExplodeFieldSP(si);    // Explode
+    return subSnikSnakFromLeft;
+  } // loc_g_7A4F:
+
+  ax = PlayField16[si + FieldWidth]; // check below
+  if (ax == 0 || LowByte(ax) == fiMurphy)
+  {
+    MovHighByte(&PlayField16[si], 0xB);
+    return subSnikSnakFromLeft;
+  } // loc_g_7A69:
+
+  MovHighByte(&PlayField16[si], 7);
+
+  return subSnikSnakFromLeft;
+} // subSnikSnakFromLeft
+
+static int subDrawSnikSnakTurnLeft(int si, int bx)
+{
+  static int subDrawSnikSnakTurnLeft;
+
+  int X, Y;
+
+  // +++++++++++++++++++++++++++++++++++++++++++++++++++++
+  X = GetStretchX(si);
+  Y = GetStretchY(si);
+  StretchedSprites.BltEx(X, Y, aniSnikSnak[bx]);
+  // +++++++++++++++++++++++++++++++++++++++++++++++++++++
+
+  return subDrawSnikSnakTurnLeft;
+}
+
+static int subDrawSnikSnakTurnRight(int si, int bx)
+{
+  static int subDrawSnikSnakTurnRight;
+
+  int X, Y;
+
+  // +++++++++++++++++++++++++++++++++++++++++++++++++++++
+  X = GetStretchX(si);
+  Y = GetStretchY(si);
+  StretchedSprites.BltEx(X, Y, aniSnikSnak[0x10 - bx]);
+  // +++++++++++++++++++++++++++++++++++++++++++++++++++++
+
+  return subDrawSnikSnakTurnRight;
+}
+
+static int subDrawSnikSnakFromBelow(int si, int bx)
+{
+  static int subDrawSnikSnakFromBelow;
+
+  int X, Y;
+
+  bx = bx - 0xF; // get and anti-increment sequence#
+  // +++++++++++++++++++++++++++++++++++++++++++++++++++++
+  X = GetStretchX(si);
+  Y = GetStretchY(si + FieldWidth);
+  StretchedSprites.BltEx(X, Y, 0);
+  StretchedSprites.BltEx(X, Y - bx * TwoPixels, aniSnikSnakUp + bx);
+  // +++++++++++++++++++++++++++++++++++++++++++++++++++++
+
+  return subDrawSnikSnakFromBelow;
+}
+
+static int subDrawSnikSnakFromRight(int si, int bx)
+{
+  static int subDrawSnikSnakFromRight;
+
+  int X, Y;
+
+  bx = bx - 0x17; // get and increment sequence#
+  // +++++++++++++++++++++++++++++++++++++++++++++++++++++
+  X = GetStretchX(si + 1);
+  Y = GetStretchY(si);
+  StretchedSprites.BltEx(X, Y, 0);
+  StretchedSprites.BltEx(X - bx * TwoPixels, Y, aniSnikSnakLeft + bx);
+  // +++++++++++++++++++++++++++++++++++++++++++++++++++++
+
+  return subDrawSnikSnakFromRight;
+}
+
+static int subDrawSnikSnakFromAbove(int si, int bx)
+{
+  static int subDrawSnikSnakFromAbove;
+
+  int X, Y;
+
+  bx = bx - 0x1F; // get and increment sequence#
+  // +++++++++++++++++++++++++++++++++++++++++++++++++++++
+  X = GetStretchX(si);
+  Y = GetStretchY(si - FieldWidth);
+  StretchedSprites.BltEx(X, Y, 0);
+  StretchedSprites.BltEx(X, Y + bx * TwoPixels, aniSnikSnakDown + bx);
+  // +++++++++++++++++++++++++++++++++++++++++++++++++++++
+
+  return subDrawSnikSnakFromAbove;
+}
+
+static int subDrawSnikSnakFromLeft(int si, int bx)
+{
+  static int subDrawSnikSnakFromLeft;
+
+  int X, Y;
+
+  bx = bx - 0x27; // get and increment sequence#
+  // +++++++++++++++++++++++++++++++++++++++++++++++++++++
+  X = GetStretchX(si - 1);
+  Y = GetStretchY(si);
+  StretchedSprites.BltEx(X, Y, 0);
+  StretchedSprites.BltEx(X + bx * TwoPixels, Y, aniSnikSnakRight + bx);
+  // +++++++++++++++++++++++++++++++++++++++++++++++++++++
+
+  return subDrawSnikSnakFromLeft;
+}
diff --git a/src/game_sp/SnikSnaks.h b/src/game_sp/SnikSnaks.h
new file mode 100644 (file)
index 0000000..ddebccf
--- /dev/null
@@ -0,0 +1,18 @@
+// ----------------------------------------------------------------------------
+// SnikSnaks.h
+// ----------------------------------------------------------------------------
+
+#ifndef SNIKSNAKS_H
+#define SNIKSNAKS_H
+
+#include "vb_types.h"
+#include "vb_defs.h"
+#include "vb_vars.h"
+#include "vb_lib.h"
+
+#include "global.h"
+
+extern int subAnimateSnikSnaks(int si);
+extern int subDrawAnimatedSnikSnaks(int si);
+
+#endif /* SNIKSNAKS_H */
diff --git a/src/game_sp/Sound.c b/src/game_sp/Sound.c
new file mode 100644 (file)
index 0000000..3965e75
--- /dev/null
@@ -0,0 +1,178 @@
+// ----------------------------------------------------------------------------
+// Sound.c
+// ----------------------------------------------------------------------------
+
+#include "Sound.h"
+
+static char *VB_Name = "modSound";
+// --- Option Explicit
+
+int MusicOnFlag;
+int FXOnFlag;
+
+DirectSoundBuffer ZonkFX[1 + 1];
+DirectSoundBuffer InfotronFX[1 + 1];
+DirectSoundBuffer BugFX[1 + 1];
+DirectSoundBuffer ExplosionFX[1 + 1];
+DirectSoundBuffer PushFX;
+DirectSoundBuffer ExitFX;
+DirectSoundBuffer BaseFX;
+
+#if 0
+
+void LoadSoundFX()
+{
+  DSBUFFERDESC bufferDesc;
+  WAVEFORMATEX waveFormat;
+  char *FName;
+  int i;
+
+  bufferDesc.lFlags = DSBCAPS_CTRLFREQUENCY | DSBCAPS_CTRLPAN | DSBCAPS_CTRLVOLUME | DSBCAPS_STATIC;
+  waveFormat.nFormatTag = WAVE_FORMAT_PCM;
+  waveFormat.nChannels = 1;
+  waveFormat.lSamplesPerSec = 8000;
+  waveFormat.nBitsPerSample = 8;
+  waveFormat.nBlockAlign = waveFormat.nBitsPerSample / 8 * waveFormat.nChannels;
+  waveFormat.lAvgBytesPerSec = waveFormat.lSamplesPerSec * waveFormat.nBlockAlign;
+  FName = CAT(App.Path, "/Sound/");
+  for (i = 0; i <= 1; i++)
+  {
+    ZonkFX[i] = DSound.CreateSoundBufferFromFile(CAT(FName, "Zonk.wav"), bufferDesc, waveFormat);
+    InfotronFX[i] = DSound.CreateSoundBufferFromFile(CAT(FName, "Infotron.wav"), bufferDesc, waveFormat);
+    BugFX[i] = DSound.CreateSoundBufferFromFile(CAT(FName, "Bug.wav"), bufferDesc, waveFormat);
+    ExplosionFX[i] = DSound.CreateSoundBufferFromFile(CAT(FName, "Explosion.wav"), bufferDesc, waveFormat);
+  }
+
+  BaseFX = DSound.CreateSoundBufferFromFile(CAT(FName, "Base.wav"), bufferDesc, waveFormat);
+  ExitFX = DSound.CreateSoundBufferFromFile(CAT(FName, "Exit.wav"), bufferDesc, waveFormat);
+  PushFX = DSound.CreateSoundBufferFromFile(CAT(FName, "Push.wav"), bufferDesc, waveFormat);
+  //  FXOnFlag = 0
+}
+
+#endif
+
+void subSoundFXZonk()
+{
+  int i;
+
+  if (FXOnFlag == 0)
+    return;
+
+  for (i = 0; i <= 1; i++)
+  {
+    if (! IS_NOTHING(&ZonkFX[i], sizeof(ZonkFX[i])))
+    {
+      if (ZonkFX[i].GetStatus() != DSBSTATUS_PLAYING)
+      {
+        ZonkFX[i].Play DSBPLAY_DEFAULT;
+        break;
+      }
+    }
+  }
+}
+
+void subSoundFXBug()
+{
+  int i;
+
+  if (FXOnFlag == 0)
+    return;
+
+  for (i = 0; i <= 1; i++)
+  {
+    if (! IS_NOTHING(&BugFX[i], sizeof(BugFX[i])))
+    {
+      if (BugFX[i].GetStatus() != DSBSTATUS_PLAYING)
+      {
+        BugFX[i].Play DSBPLAY_DEFAULT;
+        break;
+      }
+    }
+  }
+}
+
+void subSoundFXInfotron()
+{
+  int i;
+
+  if (FXOnFlag == 0)
+    return;
+
+  for (i = 0; i <= 1; i++)
+  {
+    if (! IS_NOTHING(&InfotronFX[i], sizeof(InfotronFX[i])))
+    {
+      if (InfotronFX[i].GetStatus() != DSBSTATUS_PLAYING)
+      {
+        InfotronFX[i].Play DSBPLAY_DEFAULT;
+        break;
+      }
+    }
+  }
+}
+
+void subSoundFXExplosion()
+{
+  int i;
+
+  if (FXOnFlag == 0)
+    return;
+
+  for (i = 0; i <= 1; i++)
+  {
+    if (! IS_NOTHING(&ExplosionFX[i], sizeof(ExplosionFX[i])))
+    {
+      if (ExplosionFX[i].GetStatus() != DSBSTATUS_PLAYING)
+      {
+        ExplosionFX[i].Play DSBPLAY_DEFAULT;
+        break;
+      }
+    }
+  }
+}
+
+void subSoundFXBase()
+{
+  if (FXOnFlag == 0)
+    return;
+
+  if (IS_NOTHING(&BaseFX, sizeof(BaseFX)))
+    return;
+
+  if (BaseFX.GetStatus() != DSBSTATUS_PLAYING)
+  {
+    BaseFX.Play DSBPLAY_DEFAULT;
+  }
+}
+
+void subSoundFXPush()
+{
+  if (FXOnFlag == 0)
+    return;
+
+  if (IS_NOTHING(&PushFX, sizeof(PushFX)))
+    return;
+
+  if (PushFX.GetStatus() != DSBSTATUS_PLAYING)
+  {
+    PushFX.Play DSBPLAY_DEFAULT;
+  }
+}
+
+void subSoundFXExit()
+{
+  if (FXOnFlag == 0)
+    return;
+
+  if (IS_NOTHING(&ExitFX, sizeof(ExitFX)))
+    return;
+
+  if (ExitFX.GetStatus() != DSBSTATUS_PLAYING)
+  {
+    ExitFX.Play DSBPLAY_DEFAULT;
+  }
+}
+
+void subMusicInit()
+{
+}
diff --git a/src/game_sp/Sound.h b/src/game_sp/Sound.h
new file mode 100644 (file)
index 0000000..ad337a3
--- /dev/null
@@ -0,0 +1,28 @@
+// ----------------------------------------------------------------------------
+// Sound.h
+// ----------------------------------------------------------------------------
+
+#ifndef SOUND_H
+#define SOUND_H
+
+#include "vb_types.h"
+#include "vb_defs.h"
+#include "vb_vars.h"
+#include "vb_lib.h"
+
+#include "global.h"
+
+extern void LoadSoundFX();
+extern void subMusicInit();
+extern void subSoundFXBase();
+extern void subSoundFXBug();
+extern void subSoundFXExit();
+extern void subSoundFXExplosion();
+extern void subSoundFXInfotron();
+extern void subSoundFXPush();
+extern void subSoundFXZonk();
+
+extern int FXOnFlag;
+extern int MusicOnFlag;
+
+#endif /* SOUND_H */
diff --git a/src/game_sp/TickCountObject.c b/src/game_sp/TickCountObject.c
new file mode 100644 (file)
index 0000000..ed9c50e
--- /dev/null
@@ -0,0 +1,215 @@
+// ----------------------------------------------------------------------------
+// TickCountObject.c
+// ----------------------------------------------------------------------------
+
+#include "TickCountObject.h"
+
+// --- VERSION 1.0 CLASS
+// --- BEGIN
+// ---   MultiUse = -1  'True  // True
+// ---   Persistable = 0  'NotPersistable  // NotPersistable
+// ---   DataBindingBehavior = 0  'vbNone  // vbNone
+// ---   DataSourceBehavior  = 0  'vbNone  // vbNone
+// ---   MTSTransactionMode  = 0  'NotAnMTSObject  // NotAnMTSObject
+// --- END
+
+// static char *VB_Name = "TickCountObject";
+// static boolean VB_GlobalNameSpace = False;
+// static boolean VB_Creatable = True;
+// static boolean VB_PredeclaredId = False;
+// static boolean VB_Exposed = False;
+// --- Option Explicit
+
+#define LongMin                        (-(double)2147483648) // the "#" sign is a bug of the VB environment AutoFormat function but causes no real problems; don't  worry 'bout it!
+#define LongMax                        (2147483647)
+
+long GetTickCount();
+long QueryPerformanceCounter(currency lpPerformanceCount);
+long QueryPerformanceFrequency(currency lpFrequency);
+
+boolean DelayLoopActive;
+
+boolean MPause, bHighPerf;
+currency PFreq; // LARGE_INTEGER
+double sFactor, msFactor, usFactor;
+
+boolean TickCountObject_Get_Active()
+{
+  boolean Active;
+
+  Active = DelayLoopActive;
+
+  return Active;
+}
+
+boolean TickCountObject_Get_Pause()
+{
+  boolean Pause;
+
+  Pause = MPause;
+
+  return Pause;
+}
+
+void TickCountObject_Let_Pause(boolean NewVal)
+{
+  MPause = NewVal;
+}
+
+void TickCountObject_DelayMS(long MSInterval, boolean DoEventsFlag) // in ms
+{
+  currency Start;
+
+  Start = TickNow();
+  DelayLoopActive = True;
+  do
+  {
+    if (DoEventsFlag)
+      DoEvents();
+
+    if (MSInterval <= TickDiffMS(Start) && ! MPause)
+      break;
+  }
+  while (1);
+
+  DelayLoopActive = False;
+}
+
+// for compatibility with old code:
+void TickCountObject_DelayS(long SInterval, boolean DoEventsFlag) // in s
+{
+  // check if SInterval is less than 25 days ...
+  if ((int)(LongMax / 1000) <= SInterval)
+  {
+    Err.Raise(513, "Delay()", "Value Overflow");
+  }
+  else
+  {
+    TickCountObject_DelayMS((long)1000 * SInterval, DoEventsFlag);
+  }
+}
+
+currency TickCountObject_Get_TickNow()
+{
+  currency TickNow;
+
+  if (bHighPerf)
+  {
+    QueryPerformanceCounter(TickNow);
+  }
+  else
+  {
+    TickNow = GetTickCount();
+  }
+
+  return TickNow;
+}
+
+long TickCountObject_TickDiffS(currency TickStart)
+{
+  long TickDiffS;
+
+  currency NewTick, TD;
+
+  if (bHighPerf)
+  {
+    QueryPerformanceCounter(NewTick);
+    TD = (NewTick - TickStart);
+    TickDiffS = sFactor * TD;
+  }
+  else
+  {
+    NewTick = GetTickCount();
+    if (NewTick < TickStart)
+    {
+      // Overflow occured and needs to be handled
+      TickDiffS = (LongMax - TickStart) + (NewTick - LongMin) + 1;
+    }
+    else
+    {
+      TickDiffS = NewTick - TickStart;
+    }
+
+    TickDiffS = Int(TickDiffS / 1000);
+  }
+
+  return TickDiffS;
+}
+
+long TickCountObject_TickDiffMS(currency TickStart)
+{
+  long TickDiffMS;
+
+  currency NewTick, TD;
+
+  if (bHighPerf)
+  {
+    QueryPerformanceCounter(NewTick);
+    TD = (NewTick - TickStart);
+    TickDiffMS = msFactor * TD;
+  }
+  else
+  {
+    NewTick = GetTickCount();
+    if (NewTick < TickStart)
+    {
+      // Overflow occured and needs to be handled
+      TickDiffMS = (LongMax - TickStart) + (NewTick - LongMin) + 1;
+    }
+    else
+    {
+      TickDiffMS = NewTick - TickStart;
+    }
+  }
+
+  return TickDiffMS;
+}
+
+currency TickCountObject_TickDiffUS(currency TickStart)
+{
+  currency TickDiffUS;
+
+  currency NewTick, TD;
+
+  if (bHighPerf)
+  {
+    QueryPerformanceCounter(NewTick);
+    TD = (NewTick - TickStart);
+    TickDiffUS = usFactor * TD;
+  }
+  else
+  {
+    NewTick = GetTickCount();
+    if (NewTick < TickStart)
+    {
+      // Overflow occured and needs to be handled
+      TickDiffUS = ((LongMax - TickStart) + (NewTick - LongMin) + 1) * (currency)1000;
+    }
+    else
+    {
+      TickDiffUS = (NewTick - TickStart) * (currency)1000;
+    }
+  }
+
+  return TickDiffUS;
+}
+
+#if 0
+
+static void Class_Initialize()
+{
+  long L;
+
+  bHighPerf = (0 != QueryPerformanceFrequency(PFreq));
+  if (bHighPerf)
+  {
+    sFactor = (double)1 / PFreq;
+    msFactor = (double)1000 / PFreq;
+    usFactor = (double)1000000 / PFreq;
+  }
+
+  DelayLoopActive = False;
+  TickCountObject_Let_Pause(False);
+}
+
+#endif
diff --git a/src/game_sp/TickCountObject.h b/src/game_sp/TickCountObject.h
new file mode 100644 (file)
index 0000000..50a3454
--- /dev/null
@@ -0,0 +1,25 @@
+// ----------------------------------------------------------------------------
+// TickCountObject.h
+// ----------------------------------------------------------------------------
+
+#ifndef TICKCOUNTOBJECT_H
+#define TICKCOUNTOBJECT_H
+
+#include "vb_types.h"
+#include "vb_defs.h"
+#include "vb_vars.h"
+#include "vb_lib.h"
+
+#include "global.h"
+
+extern void TickCountObject_DelayMS(long MSInterval, boolean DoEventsFlag);
+extern void TickCountObject_DelayS(long SInterval, boolean DoEventsFlag);
+extern boolean TickCountObject_Get_Active();
+extern boolean TickCountObject_Get_Pause();
+extern currency TickCountObject_Get_TickNow();
+extern void TickCountObject_Let_Pause(boolean NewVal);
+extern long TickCountObject_TickDiffMS(currency TickStart);
+extern long TickCountObject_TickDiffS(currency TickStart);
+extern currency TickCountObject_TickDiffUS(currency TickStart);
+
+#endif /* TICKCOUNTOBJECT_H */
diff --git a/src/game_sp/TopMost.c b/src/game_sp/TopMost.c
new file mode 100644 (file)
index 0000000..319f0ea
--- /dev/null
@@ -0,0 +1,51 @@
+// ----------------------------------------------------------------------------
+// TopMost.c
+// ----------------------------------------------------------------------------
+
+#include "TopMost.h"
+
+// static char *VB_Name = "TopMost_Module";
+// --- Option Explicit
+// --- const int SWP_FRAMECHANGED = 0x20;
+// --- const int SWP_HIDEWINDOW = 0x80;
+// --- const int SWP_NOACTIVATE = 0x10;
+// --- const int SWP_NOCOPYBITS = 0x100;
+// --- const int SWP_NOMOVE = 0x2;
+// --- const int SWP_NOOWNERZORDER = 0x200;
+// --- const int SWP_NOREDRAW = 0x8;
+// --- const int SWP_NOSIZE = 0x1;
+// --- const int SWP_NOZORDER = 0x4;
+// --- const int SWP_SHOWWINDOW = 0x40;
+// --- const int SWP_DRAWFRAME = SWP_FRAMECHANGED;
+// --- const int SWP_NOREPOSITION = SWP_NOOWNERZORDER;
+
+// --- const int HWND_BOTTOM = 1;
+// --- const int HWND_BROADCAST = 0xFFFF;
+// --- const int HWND_DESKTOP = 0;
+// --- const int HWND_NOTOPMOST = - 2;
+// --- const int HWND_TOP = 0;
+// --- const int HWND_TOPMOST = - 1;
+
+int SetWindowPos(long h, long hb, int X, int Y, int cx, int cy, int f);
+
+void TopMost(Object obj)
+{
+  int i;
+
+  i = SetWindowPos(obj.hWnd, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOSIZE + SWP_NOMOVE);
+}
+
+void UnTopMost(Object obj)
+{
+  int i;
+
+  i = SetWindowPos(obj.hWnd, HWND_NOTOPMOST, 0, 0, 0, 0, SWP_NOSIZE + SWP_NOMOVE);
+}
+
+void HideWindow(long hWnd)
+{
+  int i;
+
+  i = SetWindowPos(hWnd, HWND_BOTTOM, 100, 100, 200, 200, SWP_HIDEWINDOW);
+}
+
diff --git a/src/game_sp/TopMost.h b/src/game_sp/TopMost.h
new file mode 100644 (file)
index 0000000..3543239
--- /dev/null
@@ -0,0 +1,38 @@
+// ----------------------------------------------------------------------------
+// TopMost.h
+// ----------------------------------------------------------------------------
+
+#ifndef TOPMOST_H
+#define TOPMOST_H
+
+#include "vb_types.h"
+#include "vb_defs.h"
+#include "vb_vars.h"
+#include "vb_lib.h"
+
+#include "global.h"
+
+#define HWND_BOTTOM                    (1)
+#define HWND_BROADCAST                         (0xFFFF)
+#define HWND_DESKTOP                   (0)
+#define HWND_NOTOPMOST                         (- 2)
+#define HWND_TOP                       (0)
+#define HWND_TOPMOST                   (- 1)
+#define SWP_DRAWFRAME                  (SWP_FRAMECHANGED)
+#define SWP_FRAMECHANGED                       (0x20)
+#define SWP_HIDEWINDOW                         (0x80)
+#define SWP_NOACTIVATE                         (0x10)
+#define SWP_NOCOPYBITS                         (0x100)
+#define SWP_NOMOVE                     (0x2)
+#define SWP_NOOWNERZORDER                      (0x200)
+#define SWP_NOREDRAW                   (0x8)
+#define SWP_NOREPOSITION                       (SWP_NOOWNERZORDER)
+#define SWP_NOSIZE                     (0x1)
+#define SWP_NOZORDER                   (0x4)
+#define SWP_SHOWWINDOW                         (0x40)
+
+extern void HideWindow(long hWnd);
+extern void TopMost(Object obj);
+extern void UnTopMost(Object obj);
+
+#endif /* TOPMOST_H */
diff --git a/src/game_sp/Zonk.c b/src/game_sp/Zonk.c
new file mode 100644 (file)
index 0000000..fc6f5d9
--- /dev/null
@@ -0,0 +1,476 @@
+// ----------------------------------------------------------------------------
+// Zonk.c
+// ----------------------------------------------------------------------------
+
+#include "Zonk.h"
+
+// static char *VB_Name = "modZonk";
+// --- Option Explicit
+
+// ==========================================================================
+//                              SUBROUTINE
+// Animate Zonks (falling)
+// ==========================================================================
+
+int subAnimateZonks(int si)
+{
+  int subAnimateZonks;
+
+  int tFld;
+
+  // PseudoRegisters:
+  // int ax, bx, cx, dx, di, X, Y;
+  int ax, bx, dx, X, Y;
+  // int ah, bh, ch, dh, al, bl, cl, dl;
+  int al, bl;
+
+  tFld = PlayField16[si];
+  if ((tFld & 0xFF) != fiZonk)
+    return subAnimateZonks;
+
+  if (tFld == fiZonk)
+  {
+    if (FreezeZonks == 2) // Do Zonks fall? (debug)
+      return subAnimateZonks;
+
+    ax = PlayField16[si + FieldWidth]; // select case playfield16(si+60)
+    if (ax == 0)
+      goto loc_g_0D64;
+
+    if (ax == fiZonk)
+      goto loc_g_0D35;
+
+    if (ax == fiInfotron)
+      goto loc_g_0D35;
+
+    if (ax == fiRAM)
+      goto loc_g_0D35;
+
+    return subAnimateZonks;
+
+loc_g_0D35: //        Case fiZonk, fiInfotron, fiRAM
+    ax = PlayField16[si + FieldWidth - 1];
+    if (ax == 0 || ax == 0x8888 || ax == 0xAAAA)
+      goto loc_g_0D6B;
+
+loc_g_0D4C:
+    ax = PlayField16[si + FieldWidth + 1];
+    if (ax == 0 || ax == 0x8888 || ax == 0xAAAA)
+      goto loc_g_0D81;
+
+    return subAnimateZonks;
+
+loc_g_0D64: //       Case fiSpace
+    MovHighByte(&PlayField16[si], 0x40);
+    goto loc_g_0DA5;
+
+loc_g_0D6B: // roll left?
+    if (PlayField16[si - 1] == 0)
+      goto loc_g_0D74;
+
+    goto loc_g_0D4C;
+
+loc_g_0D74:
+    MovHighByte(&PlayField16[si], 0x50);
+    PlayField16[si - 1] = 0x8888;
+    goto loc_g_0DA5;
+
+loc_g_0D81: // roll right?
+    if (PlayField16[si + 1] == 0)
+      goto loc_g_0D98;
+
+    if (PlayField16[si + 1] != 0x9999) // wow right is different from left!
+      return subAnimateZonks;
+
+    if (LowByte(PlayField16[si - FieldWidth + 1]) != 1)
+      return subAnimateZonks;
+
+loc_g_0D98:
+    MovHighByte(&PlayField16[si], 0x60);
+    PlayField16[si + 1] = 0x8888;
+  } // tFld = fiZonk
+
+loc_g_0DA5:
+  // from now on the zonk is definitely moving,
+  // maybe the sequence is in an advanced frame
+  // or just beeing initialized due to the code above
+  bl = HighByte(PlayField16[si]);
+  bx = 0;
+  MovLowByte(&bx, bl);
+  al = bl & 0xF0;
+  if (al == 0x10) // zonk comes falling from above
+    goto loc_g_0DE8;
+
+  if (al == 0x20) // zonk comes rolling from right to left
+    goto loc_g_0F83;
+
+  if (al == 0x30) // zonk comes rolling from left to right
+    goto loc_g_0FE8;
+
+  if (FreezeZonks == 2)
+    return subAnimateZonks;
+
+  if (al == 0x40) // zonk falls straight down
+    goto loc_g_104D;
+
+  if (al == 0x50) // zonk rolls left
+    goto loc_g_107B;
+
+  if (al == 0x60) // zonk rolls right
+    goto loc_g_10E9;
+
+  if (al == 0x70) // intermediate state
+    goto loc_g_1157;
+
+  return subAnimateZonks;
+
+loc_g_0DE8: // zonk comes falling from above
+  //      To Do: draw zonk falling from above
+  //      according to position in (bl And &H07)
+  // +++++++++++++++++++++++++++++++++++++++++++++++++++++
+  X = GetStretchX(si);
+  Y = GetStretchY(si - FieldWidth);
+  dx = bl & 0x7;
+  StretchedSprites.BltEx(X, Y, 0);
+  StretchedSprites.BltEx(X, Y + TwoPixels * (dx + 1), fiZonk);
+  // +++++++++++++++++++++++++++++++++++++++++++++++++++++
+  bl = HighByte(PlayField16[si]) + 1;
+  if (bl == 0x16)
+  {
+    MovHighByte(&PlayField16[si], bl);
+    subCleanUpForZonksAbove(si - FieldWidth);
+    return subAnimateZonks;
+  } // loc_g_0E2B:
+
+  if (bl < 0x18)
+  {
+    MovHighByte(&PlayField16[si], bl);
+    return subAnimateZonks;
+  } // loc_g_0E35:
+
+  MovHighByte(&PlayField16[si], 0); // zonk arrived at the field
+  if ((FreezeZonks & 0xFF) == 2)
+    return subAnimateZonks;
+
+  // loc_g_0E42:     // now check if the zonk may go on falling somehow
+  ax = PlayField16[si + FieldWidth];
+  if (ax == 0) // below is empty!-> go on falling 'loc_g_0E4C:
+    goto loc_g_0EDD;
+
+  if (ax == 0x9999) // below is only temporarily used ' loc_g_0E57:
+    goto loc_g_0EDD;
+
+  if ((ax & 0xFF) == fiMurphy) // Murphy dies 'loc_g_0E61:
+    goto loc_g_0F14;
+
+  if ((ax & 0xFF) == fiSnikSnak) // SnikSnak dies 'loc_g_0E6B:
+    goto loc_g_0F6E;
+
+  if (ax == 0x2BB) // loc_g_0E76:
+    goto loc_g_0F36;
+
+  if (ax == 0x4BB) // loc_g_0E81:
+    goto loc_g_0F52;
+
+  if ((ax & 0xFF) == fiElectron) // Electron cracked! 'loc_g_0E8B:
+    goto loc_g_0F6E;
+
+  if (ax == fiOrangeDisk) // OrangeDisk explodes 'loc_g_0E95:
+    goto loc_g_0F75;
+
+  subSoundFXZonk(); // play the zonk sound,'cause zonk hits something "hard"
+
+  if (! (ax == fiZonk || ax == fiInfotron || ax == fiRAM))
+    return subAnimateZonks;
+
+  // loc_g_0EAE: ' Zonk rolls somewhere
+  ax = PlayField16[si + FieldWidth - 1];
+  if (ax == 0 || ax == 0x8888 || ax == 0xAAAA) // may roll left
+    goto loc_g_0EEA;
+
+  ax = PlayField16[si + FieldWidth + 1];
+  if (ax == 0 || ax == 0x8888 || ax == 0xAAAA) // may roll right
+    goto loc_g_0F00;
+
+  return subAnimateZonks;
+
+loc_g_0EDD:     // go on falling down?
+  PlayField16[si] = 0x7001; // go into intermediate waitstate
+  PlayField16[si + FieldWidth] = 0x9999; // mark as "zonk waiting to access"
+  return subAnimateZonks;
+
+loc_g_0EEA:     // test if zonk may roll left
+  // This if(if true) jumps up far above
+  // to the according rountine for fixed zonks!
+  if (PlayField16[si - 1] != 0) // Remarkable!!! ' loc_g_0EF4:
+    goto loc_g_0D4C;
+
+  MovHighByte(&PlayField16[si], 0x50); // zonk rolls left
+  Mov(&PlayField16[si - 1], 0x8888); // mark as zonk accessing?
+  return subAnimateZonks;
+
+loc_g_0F00:     // test if zonk may roll right
+  if (PlayField16[si + 1] != 0) // loc_g_0F08:
+    return subAnimateZonks;
+
+  MovHighByte(&PlayField16[si], 0x60); // zonk rolls right
+  Mov(&PlayField16[si + 1], 0x8888); // mark as zonk accessing?
+  return subAnimateZonks;
+
+loc_g_0F14:     // Murphy dies, but not in any case
+  bl = HighByte(PlayField16[si + FieldWidth]);
+  if (bl == 0xE || bl == 0xF || bl == 0x28)
+    return subAnimateZonks;
+
+  if (bl == 0x29 || bl == 0x25 || bl == 0x26)
+    return subAnimateZonks;
+
+loc_g_0F36:     // ??
+  ax = LowByte(PlayField16[si + FieldWidth - 1]);
+  if (ax == fiElectron) // loc_g_0F43:
+    PlayField16[si + FieldWidth] = fiElectron;
+
+  if (ax != 0x1F)
+    PlayField16[si + FieldWidth - 1] = 0;
+
+  goto loc_g_0F6E;
+
+loc_g_0F52:     // ??
+  ax = LowByte(PlayField16[si + FieldWidth + 1]);
+  if (ax == fiElectron) // loc_g_0F5F:
+    PlayField16[si + FieldWidth] = fiElectron;
+
+  if (ax != 0x1F)
+    PlayField16[si + FieldWidth + 1] = 0;
+
+  goto loc_g_0F6E;
+
+loc_g_0F6E:     // someone dies/explodes
+  si = si + FieldWidth;                 // 1 field down
+  ExplodeFieldSP(si);               // Explode
+  return subAnimateZonks;
+
+loc_g_0F75:     // OrangeDisk explodes next cycle
+  si = si + FieldWidth;                 // 1 field down
+  PlayField8[si] = fiHardWare;
+  return subAnimateZonks;
+
+loc_g_0F83: // zonk comes rolling from right to left
+  //  To Do: draw zonk rolling from right
+  //  according to position in (bl And &H07)
+  // +++++++++++++++++++++++++++++++++++++++++++++++++++++
+  X = GetStretchX(si + 1);
+  Y = GetStretchY(si);
+  dx = (bl & 0x7) + 1;
+  StretchedSprites.BltEx(X, Y, 0);
+  StretchedSprites.BltEx(X - (TwoPixels * dx), Y, aniZonkRollLeft[dx - 1]);
+  // +++++++++++++++++++++++++++++++++++++++++++++++++++++
+  bl = HighByte(PlayField16[si]) + 1; // get and increment sequence#
+  if (bl == 0x24)
+    PlayField16[si + 1] = 0xAAAA;
+
+  if (bl == 0x26)
+  {
+    MovHighByte(&PlayField16[si], bl);
+    subCleanUpForZonksAbove(si + 1);
+  }
+  else if (bl < 0x28)
+  {
+    MovHighByte(&PlayField16[si], bl);
+  }
+  else
+  {
+    PlayField16[si] = 0xFFFF;
+    si = si + FieldWidth;                 // 1 field down
+    PlayField16[si] = 0x1001; // convert rolling zonk to a falling zonk
+  }
+
+  return subAnimateZonks;
+
+loc_g_0FE8: // zonk comes rolling from left to right
+  //  To Do: draw zonk rolling from left
+  //  according to position in (bl And &H07)
+  // +++++++++++++++++++++++++++++++++++++++++++++++++++++
+  X = GetStretchX(si - 1);
+  Y = GetStretchY(si);
+  dx = (bl & 0x7) + 1;
+  StretchedSprites.BltEx(X, Y, 0);
+  StretchedSprites.BltEx(X + (TwoPixels * dx), Y, aniZonkRollRight[dx - 1]);
+  // +++++++++++++++++++++++++++++++++++++++++++++++++++++
+  bl = HighByte(PlayField16[si]) + 1;
+  if (bl == 0x34)
+    PlayField16[si - 1] = 0xAAAA;
+
+  if (bl == 0x36)
+  {
+    MovHighByte(&PlayField16[si], bl);
+    subCleanUpForZonksAbove(si - 1);
+  }
+  else if (bl < 0x38)
+  {
+    MovHighByte(&PlayField16[si], bl);
+  }
+  else
+  {
+    PlayField16[si] = 0xFFFF;
+    si = si + FieldWidth;                   // 1 field down
+    PlayField16[si] = 0x1001; // convert rolling zonk to a falling zonk
+  }
+
+  return subAnimateZonks;
+
+loc_g_104D: // zonk falls straight down
+  bl = bl + 1;
+  if (bl < 0x42)
+  {
+    MovHighByte(&PlayField16[si], bl);
+  }
+  else if (PlayField16[si + FieldWidth] != 0)
+  {
+    bl = bl - 1; // stay waiting
+    MovHighByte(&PlayField16[si], bl);
+  }
+  else
+  {
+    PlayField16[si] = 0xFFFF; // mark as "zonk leaving"
+    si = si + FieldWidth;                 // 1 field down
+    PlayField16[si] = 0x1001; // go falling
+  }
+
+  return subAnimateZonks;
+
+loc_g_107B: // zonk rolls left
+  //  To Do: draw zonk rolling to left
+  //  according to position in (bl And &H0F)
+  // +++++++++++++++++++++++++++++++++++++++++++++++++++++
+  X = GetStretchX(si);
+  Y = GetStretchY(si);
+  dx = (bl & 0xF) + 1;
+  StretchedSprites.BltEx(X, Y, 0);
+  StretchedSprites.BltEx(X - (TwoPixels * dx), Y, aniZonkRollLeft[dx - 1]);
+  // +++++++++++++++++++++++++++++++++++++++++++++++++++++
+  bl = HighByte(PlayField16[si]) + 1; // retrieve and increment sequence#
+  if (bl < 0x52)
+  {
+    MovHighByte(&PlayField16[si], bl);
+    return subAnimateZonks;
+  }
+
+  if (PlayField16[si + FieldWidth - 1] != 0)
+    goto loc_g_10E2;
+
+  if (PlayField16[si - 1] != 0)
+  {
+    if (PlayField16[si - 1] != 0x8888)
+      goto loc_g_10E2;
+  } // loc_g_10C8:
+
+  PlayField16[si] = 0xFFFF;
+  si = si - 1;                   // 1 field left
+  PlayField16[si] = 0x2201;
+  PlayField16[si + FieldWidth] = 0xFFFF;
+  return subAnimateZonks;
+
+loc_g_10E2: // stay waiting
+  bl = bl - 1;
+  MovHighByte(&PlayField16[si], bl);
+  return subAnimateZonks;
+
+loc_g_10E9: // zonk rolls right
+  //  To Do: draw zonk rolling to right
+  //  according to position in (bl And &H07)
+  // +++++++++++++++++++++++++++++++++++++++++++++++++++++
+  X = GetStretchX(si);
+  Y = GetStretchY(si);
+  dx = (bl & 0x7) + 1;
+  StretchedSprites.BltEx(X, Y, 0);
+  StretchedSprites.BltEx(X + (TwoPixels * dx), Y, aniZonkRollRight[dx - 1]);
+  // +++++++++++++++++++++++++++++++++++++++++++++++++++++
+  bl = HighByte(PlayField16[si]) + 1;
+  if (bl < 0x62)
+  {
+    MovHighByte(&PlayField16[si], bl);
+    return subAnimateZonks;
+  }
+
+  if (PlayField16[si + FieldWidth + 1] != 0)
+    goto loc_g_1150;
+
+  if (PlayField16[si + 1] != 0)
+  {
+    if (PlayField16[si + 1] != 0x8888)
+      goto loc_g_1150;
+  }
+
+  PlayField16[si] = 0xFFFF;
+  si = si + 1;
+  PlayField16[si] = 0x3201;
+  PlayField16[si + FieldWidth] = 0xFFFF;
+  return subAnimateZonks;
+
+loc_g_1150: // stay waiting
+  bl = bl - 1;
+  MovHighByte(&PlayField16[si], bl);
+  return subAnimateZonks;
+
+loc_g_1157: // intermediate state
+  ax = PlayField16[si + FieldWidth];
+  if (ax == 0 || ax == 0x9999)
+  {
+    PlayField16[si] = 0xFFFF;
+    si = si + FieldWidth;                 // 1 field down
+    PlayField16[si] = 0x1001; // start falling down
+    goto loc_g_0DE8;
+  }
+
+  return subAnimateZonks;
+} // subAnimateZonks endp
+
+int subCleanUpForZonksAbove(int si)
+{
+  int subCleanUpForZonksAbove;
+
+  int ax;
+
+  if (LowByte(PlayField16[si]) != fiExplosion)
+    PlayField16[si] = 0;
+
+  if (PlayField16[si - FieldWidth] != 0)
+  {
+    if (PlayField16[si - FieldWidth] != 0x9999)
+      return subCleanUpForZonksAbove;
+
+    if (LowByte(PlayField16[si - 2 * FieldWidth]) != fiInfotron)
+      return subCleanUpForZonksAbove;
+  } // loc_g_1674:
+
+  if (PlayField16[si - FieldWidth - 1] != fiZonk)
+  {
+    if (PlayField16[si - FieldWidth + 1] != fiZonk)
+      return subCleanUpForZonksAbove;
+
+    goto loc_g_16A7;
+  }
+
+  ax = PlayField16[si - 1];
+  if (ax == fiZonk || ax == fiInfotron || ax == fiRAM)
+  {
+    PlayField16[si - FieldWidth - 1] = 0x6001;
+    PlayField16[si - FieldWidth] = 0x8888;
+    return subCleanUpForZonksAbove;
+  }
+
+  if (PlayField16[si - FieldWidth + 1] != fiZonk)
+    return subCleanUpForZonksAbove;
+
+loc_g_16A7:
+  ax = PlayField16[si + 1];
+  if (ax == fiZonk || ax == fiInfotron || ax == fiRAM)
+  {
+    PlayField16[si - FieldWidth + 1] = 0x5001;
+    PlayField16[si - FieldWidth] = 0x8888;
+  }
+
+  return subCleanUpForZonksAbove;
+} // subCleanUpForZonksAbove
+
diff --git a/src/game_sp/Zonk.h b/src/game_sp/Zonk.h
new file mode 100644 (file)
index 0000000..7e6022f
--- /dev/null
@@ -0,0 +1,18 @@
+// ----------------------------------------------------------------------------
+// Zonk.h
+// ----------------------------------------------------------------------------
+
+#ifndef ZONK_H
+#define ZONK_H
+
+#include "vb_types.h"
+#include "vb_defs.h"
+#include "vb_vars.h"
+#include "vb_lib.h"
+
+#include "global.h"
+
+extern int subAnimateZonks(int si);
+extern int subCleanUpForZonksAbove(int si);
+
+#endif /* ZONK_H */
diff --git a/src/game_sp/export.h b/src/game_sp/export.h
new file mode 100644 (file)
index 0000000..8b86c16
--- /dev/null
@@ -0,0 +1,80 @@
+#ifndef EXPORT_H
+#define EXPORT_H
+
+/* ========================================================================= */
+/* functions and definitions exported from game_sp to main program           */
+/* ========================================================================= */
+
+/* ------------------------------------------------------------------------- */
+/* constant definitions                                                      */
+/* ------------------------------------------------------------------------- */
+
+
+/* ------------------------------------------------------------------------- */
+/* data structure definitions                                                */
+/* ------------------------------------------------------------------------- */
+
+struct GlobalInfo_SP
+{
+};
+
+struct GameInfo_SP
+{
+};
+
+struct LevelInfo_SP
+{
+  int file_version;
+};
+
+struct GraphicInfo_SP
+{
+  Bitmap *bitmap;
+  int src_x, src_y;
+  int src_offset_x, src_offset_y;
+  int dst_offset_x, dst_offset_y;
+  int width, height;
+
+  Bitmap *crumbled_bitmap;
+  int crumbled_src_x, crumbled_src_y;
+  int crumbled_border_size;
+
+  boolean has_crumbled_graphics;
+  boolean preserve_background;
+
+  int unique_identifier;       /* used to identify needed screen updates */
+};
+
+struct EngineSnapshotInfo_SP
+{
+  struct GameInfo_SP game_sp;
+};
+
+
+/* ------------------------------------------------------------------------- */
+/* exported functions                                                        */
+/* ------------------------------------------------------------------------- */
+
+extern struct GlobalInfo_SP global_sp_info;
+extern struct LevelInfo_SP native_sp_level;
+extern struct GraphicInfo_SP graphic_info_sp_object[TILE_MAX][8];
+extern struct GraphicInfo_SP graphic_info_sp_player[MAX_PLAYERS][SPR_MAX][8];
+extern struct EngineSnapshotInfo_SP engine_snapshot_sp;
+
+extern void InitGameEngine_SP();
+extern void GameActions_SP(byte *, boolean);
+
+extern unsigned int InitEngineRandom_SP(long);
+
+extern void setLevelInfoToDefaults_SP();
+extern boolean LoadNativeLevel_SP(char *);
+
+extern void BackToFront_SP(void);
+extern void BlitScreenToBitmap_SP(Bitmap *);
+extern void RedrawPlayfield_SP(boolean);
+extern void DrawGameDoorValues_SP();
+
+extern void LoadEngineSnapshotValues_SP();
+extern void SaveEngineSnapshotValues_SP();
+
+#endif /* EXPORT_H */
diff --git a/src/game_sp/game_sp.h b/src/game_sp/game_sp.h
new file mode 100644 (file)
index 0000000..9551e84
--- /dev/null
@@ -0,0 +1,21 @@
+/***********************************************************
+* Artsoft Retro-Game Library                               *
+*----------------------------------------------------------*
+* (c) 1994-2006 Artsoft Entertainment                      *
+*               Holger Schemel                             *
+*               Detmolder Strasse 189                      *
+*               33604 Bielefeld                            *
+*               Germany                                    *
+*               e-mail: info@artsoft.org                   *
+*----------------------------------------------------------*
+* game_sp.h                                                *
+***********************************************************/
+
+#ifndef GAME_SP_H
+#define GAME_SP_H
+
+#define GAME_SP_VERSION_1_0_0
+
+#include "export.h"
+
+#endif /* GAME_SP_H */
diff --git a/src/game_sp/global.h b/src/game_sp/global.h
new file mode 100644 (file)
index 0000000..f6f1d53
--- /dev/null
@@ -0,0 +1,47 @@
+// ----------------------------------------------------------------------------
+// global.h
+// ----------------------------------------------------------------------------
+
+#ifndef GAME_SP_GLOBAL_H
+#define GAME_SP_GLOBAL_H
+
+#include "ASM.h"
+#include "BitMapObject.h"
+#include "BugsTerminals.h"
+#include "Capture.h"
+#include "DDScrollBuffer.h"
+#include "DDSpriteBuffer.h"
+#include "Demo.h"
+#include "DemoBufferObject.h"
+#include "DirectDrawGlobals.h"
+#include "DirectXGlobals.h"
+#include "Display.h"
+#include "DoGameStuff.h"
+#include "Electrons.h"
+#include "ErrorReporting.h"
+#include "Explosions.h"
+#include "FakeDeclares.h"
+#include "FancyRestore.h"
+#include "GeneralTricks.h"
+#include "Globals.h"
+#include "Infotrons.h"
+#include "InitGameConditions.h"
+#include "Input.h"
+#include "LevelSetPreviewForm.h"
+#include "MainForm.h"
+#include "MainGameLoop.h"
+#include "Marker.h"
+#include "Murphy.h"
+#include "OrangeDisk.h"
+#include "PathTools.h"
+#include "SettingsObject.h"
+#include "SnikSnaks.h"
+#include "Sound.h"
+#include "TickCountObject.h"
+#include "TopMost.h"
+#include "Zonk.h"
+#include "modAnimations.h"
+#include "modGeneralTricks.h"
+#include "modMPX.h"
+
+#endif /* GAME_SP_GLOBAL_H */
diff --git a/src/game_sp/main.c b/src/game_sp/main.c
new file mode 100644 (file)
index 0000000..74902a0
--- /dev/null
@@ -0,0 +1,17 @@
+
+#include "main_sp.h"
+#include "global.h"
+
+
+void InitGameEngine_SP()
+{
+  menPlay_Click();
+}
+
+void BlitScreenToBitmap_SP(Bitmap *target_bitmap)
+{
+}
+
+void GameActions_SP(byte action[MAX_PLAYERS], boolean warp_mode)
+{
+}
diff --git a/src/game_sp/main_sp.h b/src/game_sp/main_sp.h
new file mode 100644 (file)
index 0000000..127445a
--- /dev/null
@@ -0,0 +1,64 @@
+#ifndef MAIN_SP_H
+#define MAIN_SP_H
+
+/* ========================================================================= */
+/* external functions and definitions imported from main program to game_sp  */
+/* ========================================================================= */
+
+#include "../engines.h"
+
+
+/* ========================================================================= */
+/* functions and definitions that are exported from game_sp to main program  */
+/* ========================================================================= */
+
+#include "export.h"
+
+
+/* ========================================================================= */
+/* internal functions and definitions that are not exported to main program  */
+/* ========================================================================= */
+
+
+/* ------------------------------------------------------------------------- */
+/* constant definitions                                                      */
+/* ------------------------------------------------------------------------- */
+
+/* screen sizes and positions for SP engine */
+
+#define ORIG_TILEX             16
+#define ORIG_TILEY             16
+
+#define ZOOM_FACTOR            2
+
+#define TILEX                  (ORIG_TILEX             * ZOOM_FACTOR)
+#define TILEY                  (ORIG_TILEY             * ZOOM_FACTOR)
+
+#define SCR_FIELDX             17
+#define SCR_FIELDY             17
+
+/* often used screen positions */
+#define SX                     8
+#define SY                     8
+#define SXSIZE                 (SCR_FIELDX * TILEX)
+#define SYSIZE                 (SCR_FIELDY * TILEY)
+
+
+/* ------------------------------------------------------------------------- */
+/* data structure definitions                                                */
+/* ------------------------------------------------------------------------- */
+
+/* ------------------------------------------------------------------------- */
+/* exported variables                                                        */
+/* ------------------------------------------------------------------------- */
+
+extern struct LevelInfo_SP native_sp_level;
+
+extern struct GameInfo_SP game_sp;
+
+
+/* ------------------------------------------------------------------------- */
+/* exported functions                                                        */
+/* ------------------------------------------------------------------------- */
+
+#endif /* MAIN_SP_H */
diff --git a/src/game_sp/modAnimations.c b/src/game_sp/modAnimations.c
new file mode 100644 (file)
index 0000000..5cb6643
--- /dev/null
@@ -0,0 +1,69 @@
+// ----------------------------------------------------------------------------
+// modAnimations.c
+// ----------------------------------------------------------------------------
+
+#include "modAnimations.h"
+
+// static char *VB_Name = "modAnimations";
+// --- Option Explicit
+
+// ::: #ifndef HAS_SpecialPortType
+// ::: typedef struct
+// ::: {
+// :::   int PortLocation; // = 2*(x+(y*60))
+// :::   byte Gravity; // 1 = turn on, anything else (0) = turn off
+// :::   byte FreezeZonks; // 2 = turn on, anything else (0) = turn off  (1=off!)
+// :::   byte FreezeEnemies; // 1 = turn on, anything else (0) = turn off
+// :::   byte UnUsed;
+// ::: } SpecialPortType;
+// ::: #define HAS_SpecialPortType
+// ::: #endif
+
+// ::: #ifndef HAS_LevelInfoType
+// ::: typedef struct
+// ::: {
+// :::   byte UnUsed[4 + 1];
+// :::   byte InitialGravity; // 1=on, anything else (0) = off
+// :::   byte Version; // SpeedFixVersion XOR &H20
+// :::   char LevelTitle[23];
+// :::   byte InitialFreezeZonks; // 2=on, anything else (0) = off.  (1=off too!)
+// :::   byte InfotronsNeeded;
+
+// :::   // Number of Infotrons needed. 0 means that Supaplex will count the total
+// :::   // amount of Infotrons in the level, and use the low byte of that number.
+// :::   // (A multiple of 256 Infotrons will then result in 0-to-eat, etc.!)
+// :::   byte SpecialPortCount; // Maximum 10 allowed!
+// :::   SpecialPortType SpecialPort[10 + 1];
+// :::   byte SpeedByte; // = Speed XOR Highbyte(RandomSeed)
+// :::   byte CheckSumByte; // = CheckSum XOR SpeedByte
+// :::   int DemoRandomSeed;
+// ::: } LevelInfoType;
+// ::: #define HAS_LevelInfoType
+// ::: #endif
+
+DDSpriteBuffer NormalSprites;
+DDSpriteBuffer StretchedSprites;
+DDScrollBuffer Stage;
+
+byte LData[59 + 1][23 + 1];
+LevelInfoType LInfo;
+
+float Stretch; // , StretchWidth%, TwoPixels!
+
+int ScrollMinX, ScrollMaxX, ScrollMinY, ScrollMaxY;
+int ScrollX, ScrollY;
+// --- const long ScrollDelta = 1&;
+
+// Public FieldWidth&, FieldHeight&
+boolean EndFlag;
+long PauseMode;
+
+TickCountObject Clock;
+long MurphyX, MurphyY;
+
+void GoPlay()
+{
+  //  Call subFetchAndInitLevelB
+  EndFlag = False;
+  subMainGameLoop();
+}
diff --git a/src/game_sp/modAnimations.h b/src/game_sp/modAnimations.h
new file mode 100644 (file)
index 0000000..c0de60e
--- /dev/null
@@ -0,0 +1,64 @@
+// ----------------------------------------------------------------------------
+// modAnimations.h
+// ----------------------------------------------------------------------------
+
+#ifndef MODANIMATIONS_H
+#define MODANIMATIONS_H
+
+#include "vb_types.h"
+#include "vb_defs.h"
+#include "vb_vars.h"
+#include "vb_lib.h"
+
+#include "global.h"
+
+#ifndef HAS_SpecialPortType
+typedef struct
+{
+  int PortLocation; // = 2*(x+(y*60))
+  byte Gravity; // 1 = turn on, anything else (0) = turn off
+  byte FreezeZonks; // 2 = turn on, anything else (0) = turn off  (1=off!)
+  byte FreezeEnemies; // 1 = turn on, anything else (0) = turn off
+  byte UnUsed;
+} SpecialPortType;
+#define HAS_SpecialPortType
+#endif
+
+#ifndef HAS_LevelInfoType
+typedef struct
+{
+  byte UnUsed[4 + 1];
+  byte InitialGravity; // 1=on, anything else (0) = off
+  byte Version; // SpeedFixVersion XOR &H20
+  char LevelTitle[23];
+  byte InitialFreezeZonks; // 2=on, anything else (0) = off.  (1=off too!)
+  byte InfotronsNeeded;
+
+  // Number of Infotrons needed. 0 means that Supaplex will count the total
+  // amount of Infotrons in the level, and use the low byte of that number.
+  // (A multiple of 256 Infotrons will then result in 0-to-eat, etc.!)
+  byte SpecialPortCount; // Maximum 10 allowed!
+  SpecialPortType SpecialPort[10 + 1];
+  byte SpeedByte; // = Speed XOR Highbyte(RandomSeed)
+  byte CheckSumByte; // = CheckSum XOR SpeedByte
+  int DemoRandomSeed;
+} LevelInfoType;
+#define HAS_LevelInfoType
+#endif
+
+#define ScrollDelta                    ((long)1)
+
+extern void GoPlay();
+
+extern DDScrollBuffer Stage;
+extern DDSpriteBuffer NormalSprites;
+extern DDSpriteBuffer StretchedSprites;
+extern LevelInfoType LInfo;
+extern boolean EndFlag;
+extern byte LData[59 + 1][23 + 1];
+extern float Stretch;
+extern int ScrollMinX, ScrollMaxX, ScrollMinY, ScrollMaxY;
+extern int ScrollX, ScrollY;
+extern long PauseMode;
+
+#endif /* MODANIMATIONS_H */
diff --git a/src/game_sp/modGeneralTricks.c b/src/game_sp/modGeneralTricks.c
new file mode 100644 (file)
index 0000000..712ff1b
--- /dev/null
@@ -0,0 +1,69 @@
+// ----------------------------------------------------------------------------
+// modGeneralTricks.c
+// ----------------------------------------------------------------------------
+
+#include "modGeneralTricks.h"
+
+// static char *VB_Name = "modGeneralTricks";
+// --- Option Explicit
+
+void Inc(int *i)
+{
+  *i = *i + 1;
+}
+
+void Dec(int *i)
+{
+  *i = *i - 1;
+}
+
+/*
+double ValEx(char *TS)
+{
+  double ValEx;
+
+  // Extends the Val() function for
+  // german-style number-representing strings
+  int i;
+  char *LS, *RS;
+
+  i = InStr(1, TS, ",");
+  if (i != 0)
+  {
+    LS = Left(TS, i - 1);
+    RS = Right(TS, Len(TS) - i);
+    ValEx = ValCAT(LS, ".", RS);
+  }
+  else
+  {
+    ValEx = Val(TS);
+  }
+
+  return ValEx;
+}
+*/
+
+int Min(int A, int B)
+{
+  int Min;
+
+  if (A < B)
+    Min = A;
+  else
+    Min = B;
+
+  return Min;
+}
+
+int Max(int A, int B)
+{
+  int Max;
+
+  if (A < B)
+    Max = B;
+  else
+    Max = A;
+
+  return Max;
+}
+
diff --git a/src/game_sp/modGeneralTricks.h b/src/game_sp/modGeneralTricks.h
new file mode 100644 (file)
index 0000000..23bb868
--- /dev/null
@@ -0,0 +1,21 @@
+// ----------------------------------------------------------------------------
+// modGeneralTricks.h
+// ----------------------------------------------------------------------------
+
+#ifndef MODGENERALTRICKS_H
+#define MODGENERALTRICKS_H
+
+#include "vb_types.h"
+#include "vb_defs.h"
+#include "vb_vars.h"
+#include "vb_lib.h"
+
+#include "global.h"
+
+extern void Dec(int *i);
+extern void Inc(int *i);
+extern int Max(int A, int B);
+extern int Min(int A, int B);
+extern double ValEx(char *TS);
+
+#endif /* MODGENERALTRICKS_H */
diff --git a/src/game_sp/modMPX.c b/src/game_sp/modMPX.c
new file mode 100644 (file)
index 0000000..fcb564f
--- /dev/null
@@ -0,0 +1,451 @@
+// ----------------------------------------------------------------------------
+// modMPX.c
+// ----------------------------------------------------------------------------
+
+#include "modMPX.h"
+
+void ReadMPX();
+#if 0
+static void SaveMPX(char *Path);
+static void SaveSP(char *Path);
+#endif
+
+// static char *VB_Name = "modMPX";
+// --- Option Explicit
+
+char *gSignature;
+boolean bSignatureAvailable;
+
+const char MPX_ID[4] = "MPX ";
+
+// ::: #ifndef HAS_LevelDescriptor
+// ::: typedef struct
+// ::: {
+// :::   int Width;
+// :::   int Height;
+// :::   long OffSet;
+// :::   long Size;
+// ::: } LevelDescriptor;
+// ::: #define HAS_LevelDescriptor
+// ::: #endif
+
+int MPXVersion;
+int LevelCount;
+boolean DemoAvailable;
+LevelDescriptor *LDesc;
+// int OFile;
+FILE *OFile;
+
+boolean MpxOpen(char *Path)
+{
+  boolean MpxOpen;
+
+  // int i;
+  // byte T;
+  char readID[4];
+
+  MpxOpen = False;
+
+  // --- On Error GoTo OpenMPXEH
+  // OFile = FreeFile();
+  OFile = fopen(CurPath, "rb");
+  FILE_GET(OFile, -1, &readID, sizeof(readID));
+  if (readID != MPX_ID)
+    goto OpenMPXEH;
+
+  FILE_GET(OFile, -1, &MPXVersion, sizeof(MPXVersion));
+  FILE_GET(OFile, -1, &LevelCount, sizeof(LevelCount));
+  LDesc = REDIM_1D(sizeof(LevelDescriptor), 0, LevelCount + 1 - 1);
+  FILE_GET(OFile, -1, &LDesc, sizeof(LDesc));
+  MpxOpen = True;
+  return MpxOpen;
+
+OpenMPXEH:
+  fclose(OFile);
+  OFile = 0;
+
+  return MpxOpen;
+}
+
+boolean MpxLoadLInfo(int i)
+{
+  boolean MpxLoadLInfo;
+
+  long Off;
+
+  MpxLoadLInfo = False;
+  // if (OFile < 1)
+  if (OFile == 0)
+    return MpxLoadLInfo;
+
+  Off = LDesc[i].OffSet;
+  Off = Off + LDesc[i].Width * LDesc[i].Height;
+
+  // --- On Error GoTo MpxLoadLInfoEH
+  FILE_GET(OFile, Off, &LInfo, sizeof(LInfo));
+  MpxLoadLInfo = True;
+  return MpxLoadLInfo;
+
+  // MpxLoadLInfoEH:
+  fclose(OFile);
+  OFile = 0;
+
+  return MpxLoadLInfo;
+}
+
+void MpxClose()
+{
+  if (0 < OFile)
+  {
+    fclose(OFile);
+    OFile = 0;
+  }
+}
+
+void ReadMPX()
+{
+  // int FNum, i;
+  FILE *FNum;
+  int i;
+  // byte T;
+  char readID[4];
+
+  Trace("modMPX", "--> ReadMPX");
+
+  // --- On Error GoTo ReadMPXEH
+  // FNum = FreeFile();
+  Trace("modMPX", "open file");
+  FNum = fopen(CurPath, "rb");
+  FILE_GET(FNum, -1, &readID, sizeof(readID));
+  if (readID != MPX_ID)
+    goto ReadMPXEH;
+
+  FILE_GET(FNum, -1, &MPXVersion, sizeof(MPXVersion));
+  if (MPXVersion != 1)
+    goto ReadMPXEH;
+
+  FILE_GET(FNum, -1, &LevelCount, sizeof(LevelCount));
+  if (LevelCount < 1)
+    goto ReadMPXEH;
+
+  LDesc = REDIM_1D(sizeof(LevelDescriptor), 0, LevelCount + 1 - 1);
+  Trace("modMPX", "--> read LevelDescriptor");
+  FILE_GET(FNum, -1, &LDesc, sizeof(LDesc));
+  FieldWidth = LDesc[LevelNumber].Width;
+  FieldHeight = LDesc[LevelNumber].Height;
+  HeaderSize = 96;
+  FieldMax = (FieldWidth * FieldHeight) + HeaderSize - 1;
+  LevelMax = (FieldWidth * FieldHeight) - 1;
+  FileMax = LDesc[LevelNumber].Size - 1;
+  if (FileMax < FieldMax)
+    FileMax = FieldMax;
+
+  Trace("modMPX", "ReDim PlayField8");
+  PlayField8 = REDIM_1D(sizeof(byte), 0, FileMax + 1 - 1);
+  DisPlayField = REDIM_1D(sizeof(byte), 0, FieldMax + 1 - 1);
+  i = LDesc[LevelNumber].OffSet;
+  FILE_GET(FNum, i, &PlayField8, sizeof(PlayField8));
+  i = i + LevelMax + 1;
+  FILE_GET(FNum, i, &LInfo, sizeof(LInfo)); // store level info in an extra structure
+  fclose(FNum);
+  // --- On Error GoTo 0
+
+  Trace("modMPX", "file closed");
+  if (FieldMax < FileMax)
+    DemoAvailable = True;
+
+  Trace("modMPX", "read signature");
+  ReadSignature();
+  Trace("modMPX", "ReDim PlayField16");
+  PlayField16 = REDIM_1D(sizeof(int), -FieldWidth, FieldMax);
+  for (i = 0; i <= FieldMax; i++)
+  {
+    PlayField16[i] = PlayField8[i];
+    DisPlayField[i] = PlayField8[i];
+    PlayField8[i] = 0;
+  }
+
+  AnimationPosTable = REDIM_1D(sizeof(int), 0, LevelMax - 2 *FieldWidth);
+  AnimationSubTable = REDIM_1D(sizeof(byte), 0, LevelMax - 2 *FieldWidth);
+  TerminalState = REDIM_1D(sizeof(byte), 0, FieldMax + 1 - 1);
+  GravityFlag = LInfo.InitialGravity;
+  FreezeZonks = LInfo.InitialFreezeZonks;
+  DemoPointer = FieldMax + 1;
+  DemoOffset = DemoPointer;
+  DemoKeyRepeatCounter = 0;
+  if (DemoFlag != 0)
+  {
+    // Debug.Print "ReadMPX: " & Hex(LInfo.DemoRandomSeed)
+    RandomSeed = LInfo.DemoRandomSeed;
+    DemoFlag = 1;
+  }
+  else
+  {
+    subRandomize();
+  }
+
+  MainForm.SetDisplayRegion();
+  LevelLoaded = True;
+  if (CurPath != TmpPath)
+    Let_ModifiedFlag(False);
+
+  Trace("modMPX", "--> ReadMPX");
+  return;
+
+ReadMPXEH:
+  // Close();
+  fclose(FNum);
+  ReportError("modMPX", CAT("Error reading MPX file ", CurPath));
+  Trace("modMPX", "Error reading MPX file");
+  Trace("modMPX", "--> ReadMPX");
+}
+
+#if 0
+
+static void SaveMPX(char *Path)
+{
+  // int FNum, i;
+  FILE *FNum;
+  int i;
+  // byte T;
+  byte FF;
+
+  FF = 0xFF;
+  LevelNumber = 1;
+  LevelCount = 1;
+  MPXVersion = 1;
+  if ((FileMax < FieldMax) || ! IS_NOTHING(&DemoBuffer, sizeof(DemoBuffer)))
+    FileMax = FieldMax;
+
+  LDesc = REDIM_1D(sizeof(LevelDescriptor), 0, LevelCount + 1 - 1);
+  {
+    LDesc[LevelNumber].Width = FieldWidth;
+    LDesc[LevelNumber].Height = FieldHeight;
+    LDesc[LevelNumber].OffSet = 4 + 2 * strlen(INT_TO_STR(LevelCount)) +
+      LevelCount * sizeof(LDesc[1]) + 1;
+    LDesc[LevelNumber].Size = FileMax + 1;
+    if (! IS_NOTHING(&DemoBuffer, sizeof(DemoBuffer)))
+    {
+      LDesc[LevelNumber].Size = LDesc[LevelNumber].Size + DemoBuffer.Size + 2;
+      if (0 < strlen(MySignature))
+        LDesc[LevelNumber].Size = LDesc[LevelNumber].Size + strlen(MySignature) + 1;
+    }
+
+  }
+
+  // UnEdAll();
+
+  // --- On Error GoTo SaveMPXEH
+  // FNum = FreeFile();
+  if (FileExists(Path))
+    MayKill(Path);
+
+  FNum = fopen(Path, "wb");
+  FILE_PUT(FNum, -1, &MPX_ID, sizeof(MPX_ID));
+  FILE_PUT(FNum, -1, &MPXVersion, sizeof(MPXVersion));
+  FILE_PUT(FNum, -1, &LevelCount, sizeof(LevelCount));
+  FILE_PUT(FNum, -1, &LDesc, sizeof(LDesc));
+  i = LDesc[LevelNumber].OffSet;
+  FILE_PUT(FNum, i, &PlayField8, sizeof(PlayField8));
+  FILE_PUT(FNum, i, &DisPlayField, sizeof(DisPlayField));
+  i = i + LevelMax + 1;
+  FILE_PUT(FNum, i, &LInfo, sizeof(LInfo)); // store level info
+  if (! IS_NOTHING(&DemoBuffer, sizeof(DemoBuffer))) // demo was recorded
+  {
+    // Debug.Print "SaveMPX: " & Hex(LInfo.DemoRandomSeed)
+    FILE_PUT(FNum, -1, &FirstDemoByte, sizeof(FirstDemoByte));
+    if (! DemoBuffer.Serialize(FNum))
+      goto SaveMPXEH;
+
+    FILE_PUT(FNum, -1, &FF, sizeof(FF));
+    if (0 < strlen(MySignature))
+    {
+      FILE_PUT(FNum, -1, &MySignature, sizeof(MySignature));
+      FILE_PUT(FNum, -1, &FF, sizeof(FF));
+    }
+  }
+
+  fclose(FNum);
+  // --- On Error GoTo 0
+
+  CurPath = Path;
+
+  // EdAll();
+
+  if (Path != TmpPath)
+    Let_ModifiedFlag(False);
+
+  return;
+
+SaveMPXEH:
+  // Close();
+  fclose(FNum);
+}
+
+#endif
+
+#if 0
+
+static void SaveSP(char *Path)
+{
+  // int FNum, i;
+  FILE *FNum;
+  int i;
+  // byte T;
+
+  LevelNumber = 1;
+  LevelCount = 1;
+  if (! IS_NOTHING(&DemoBuffer, sizeof(DemoBuffer)))
+    LInfo.CheckSumByte = DemoBuffer.CheckSumByte;
+
+  if ((FileMax < FieldMax) || ! IS_NOTHING(&DemoBuffer, sizeof(DemoBuffer)))
+    FileMax = FieldMax;
+
+  // UnEdAll();
+
+  // --- On Error GoTo SaveSPEH
+  // FNum = FreeFile();
+  FNum = fopen(Path, "wb");
+  FILE_PUT(FNum, 1, &PlayField8, sizeof(PlayField8));
+  FILE_PUT(FNum, 1, &DisPlayField, sizeof(DisPlayField));
+  i = LevelMax + 2;
+  FILE_PUT(FNum, i, &LInfo, sizeof(LInfo)); // store level info
+  if (! IS_NOTHING(&DemoBuffer, sizeof(DemoBuffer))) // demo was recorded
+  {
+    // Debug.Print "SaveMPX: " & Hex(LInfo.DemoRandomSeed)
+    // If Not DemoBuffer.Serialize(FNum) Then GoTo SaveSPEH
+
+    // Debug.Assert(False);
+  }
+
+  fclose(FNum);
+  // --- On Error GoTo 0
+
+  CurPath = Path;
+
+  // EdAll();
+
+  if (Path != TmpPath)
+    Let_ModifiedFlag(False);
+
+  return;
+
+  // SaveSPEH:
+  // Close();
+}
+
+#endif
+
+void CreateLevel(int LWidth, int LHeight)
+{
+  long Tmp, i;
+  // byte T;
+
+  CurPath = "Untitled";
+  OrigPath = CurPath;
+  LevelNumber = 1;
+  FieldWidth = LWidth;
+  FieldHeight = LHeight;
+  HeaderSize = 96;
+  FieldMax = (FieldWidth * FieldHeight) + HeaderSize - 1;
+  LevelMax = (FieldWidth * FieldHeight) - 1;
+  FileMax = FieldMax;
+  PlayField8 = REDIM_1D(sizeof(byte), 0, FileMax + 1 - 1);
+  DisPlayField = REDIM_1D(sizeof(byte), 0, FieldMax + 1 - 1);
+  Tmp = FieldWidth * (FieldHeight - 1);
+  for (i = 0; i <= FieldWidth - 1; i++)
+  {
+    PlayField8[i] = fiHardWare;
+    PlayField8[Tmp + i] = fiHardWare;
+  }
+
+  Tmp = Tmp;
+  for (i = FieldWidth; i <= Tmp; i += FieldWidth)
+  {
+    PlayField8[i] = fiHardWare;
+    PlayField8[i - 1] = fiHardWare;
+  }
+
+  {
+    LInfo.DemoRandomSeed = 0;
+    LInfo.InfotronsNeeded = 0;
+    LInfo.InitialFreezeZonks = 0;
+    LInfo.InitialGravity = 0;
+    strcpy(LInfo.LevelTitle, "------ New Level ------");;
+    LInfo.SpecialPortCount = 0;
+    LInfo.Version = 0x74; // immitate speedfix version 5.4
+  }
+  PlayField16 = REDIM_1D(sizeof(int), -FieldWidth, FieldMax);
+  for (i = 0; i <= FieldMax; i++)
+  {
+    PlayField16[i] = PlayField8[i];
+    DisPlayField[i] = PlayField8[i];
+    PlayField8[i] = 0;
+  }
+
+  AnimationPosTable = REDIM_1D(sizeof(int), 0, LevelMax - 2 *FieldWidth);
+  AnimationSubTable = REDIM_1D(sizeof(byte), 0, LevelMax - 2 *FieldWidth);
+  TerminalState = REDIM_1D(sizeof(byte), 0, FieldMax + 1 - 1);
+  GravityFlag = LInfo.InitialGravity;
+  FreezeZonks = LInfo.InitialFreezeZonks;
+  RandomSeed = LInfo.DemoRandomSeed;
+  DemoAvailable = False;
+  SET_TO_NOTHING(&DemoBuffer, sizeof(DemoBuffer));
+  LevelLoaded = True;
+  Let_ModifiedFlag(True);
+}
+
+void ReadSignature()
+{
+  long i, iMin, iMax;
+
+  Trace("modMPX", "--> ReadSignature");
+  bSignatureAvailable = False;
+  gSignature = "";
+
+  // ##################################################### ReRecording-Test
+  if ((DemoFlag == 1) && (RecordDemoFlag == 1))
+  {
+    FirstDemoByte = PlayField8[DemoPointer];
+    MySignature = gSignature;
+  }
+
+  // ##################################################### ReRecording-Test
+
+  // gSignature = String(511, "A"): bSignatureAvailable = False: Exit Sub 'test
+  if (! (FieldMax < FileMax))
+    return;
+
+  // !!! Debug.Assert PlayField8(FileMax) = &HFF
+  Trace("modMPX", "settin iMin/Max");
+  iMin = FileMax - 512;
+  if (iMin < (FieldMax + 2))
+    iMin = FieldMax + 2;
+
+  iMax = FileMax - 1;
+  Trace("modMPX", "  For i == iMax To iMin Step -1");
+  for (i = iMax; i <= iMin; i += -1)
+  {
+    if (PlayField8[i] == 0xFF)
+      break;
+  }
+
+  if (i < iMin)
+    return;
+
+  for (i = i + 1; i <= iMax; i++)
+  {
+    gSignature = CAT(gSignature, (char)(PlayField8[i]));
+  }
+
+  // ##################################################### ReRecording-Test
+  if ((DemoFlag == 1) && (RecordDemoFlag == 1))
+    MySignature = gSignature;
+
+  // ##################################################### ReRecording-Test
+
+  if (iMin <= iMax)
+    bSignatureAvailable = True;
+
+  Trace("modMPX", "<-- ReadSignature");
+}
diff --git a/src/game_sp/modMPX.h b/src/game_sp/modMPX.h
new file mode 100644 (file)
index 0000000..bd707e2
--- /dev/null
@@ -0,0 +1,40 @@
+// ----------------------------------------------------------------------------
+// modMPX.h
+// ----------------------------------------------------------------------------
+
+#ifndef MODMPX_H
+#define MODMPX_H
+
+#include "vb_types.h"
+#include "vb_defs.h"
+#include "vb_vars.h"
+#include "vb_lib.h"
+
+#include "global.h"
+
+#ifndef HAS_LevelDescriptor
+typedef struct
+{
+  int Width;
+  int Height;
+  long OffSet;
+  long Size;
+} LevelDescriptor;
+#define HAS_LevelDescriptor
+#endif
+
+extern void CreateLevel(int LWidth, int LHeight);
+extern void MpxClose();
+extern boolean MpxLoadLInfo(int i);
+extern boolean MpxOpen(char *Path);
+extern void ReadSignature();
+
+extern void ReadMPX();
+
+extern LevelDescriptor *LDesc;
+extern boolean DemoAvailable;
+extern boolean bSignatureAvailable;
+extern char *gSignature;
+extern int LevelCount;
+
+#endif /* MODMPX_H */
diff --git a/src/game_sp/vb_defs.h b/src/game_sp/vb_defs.h
new file mode 100644 (file)
index 0000000..47ea35b
--- /dev/null
@@ -0,0 +1,83 @@
+// ----------------------------------------------------------------------------
+// vb_defs.h
+// ----------------------------------------------------------------------------
+
+#ifndef VB_DEFS_H
+#define VB_DEFS_H
+
+#define Win16                  1
+
+#ifndef False
+#define False                  0
+#define True                   (!False)
+#endif
+
+#ifndef NULL
+#define NULL                   ((void *)0)
+#endif
+
+/* these are just dummy values to prevent the compiler from complaining */
+#define VALUE_START_VB         100
+#define VALUE_START_VB_KEY     200
+#define VALUE_START_DD         300
+#define VALUE_START_DD_ERR     400
+#define VALUE_START_DS         500
+
+#define vbPicTypeBitmap                (VALUE_START_VB + 1)
+#define vbSrcCopy              (VALUE_START_VB + 2)
+#define vbTwips                        (VALUE_START_VB + 3)
+#define vbPixels               (VALUE_START_VB + 4)
+#define vbPRORPortrait         (VALUE_START_VB + 5)
+#define vbPRORLandscape                (VALUE_START_VB + 6)
+#define vbDirectory            (VALUE_START_VB + 7)
+
+#define vbKeySpace             (VALUE_START_VB_KEY + 1)
+#define vbKeyLeft              (VALUE_START_VB_KEY + 2)
+#define vbKeyRight             (VALUE_START_VB_KEY + 3)
+#define vbKeyUp                        (VALUE_START_VB_KEY + 4)
+#define vbKeyDown              (VALUE_START_VB_KEY + 5)
+#define vbKeyEscape            (VALUE_START_VB_KEY + 6)
+#define vbKeyR                 (VALUE_START_VB_KEY + 7)
+#define vbKeyReturn            (VALUE_START_VB_KEY + 8)
+#define vbKeyShift             (VALUE_START_VB_KEY + 9)
+
+#define DD_OK                  (VALUE_START_DD + 0)
+
+#define DDSD_CAPS              (VALUE_START_DD + 1)
+#define DDSD_WIDTH             (VALUE_START_DD + 2)
+#define DDSD_HEIGHT            (VALUE_START_DD + 3)
+#define DDSCL_NORMAL           (VALUE_START_DD + 4)
+#define DDBLT_WAIT             (VALUE_START_DD + 5)
+#define DDSCAPS_VIDEOMEMORY    (VALUE_START_DD + 6)
+#define DDSCAPS_OFFSCREENPLAIN (VALUE_START_DD + 7)
+#define DDSCAPS_PRIMARYSURFACE (VALUE_START_DD + 8)
+
+#define DDERR_GENERIC          (VALUE_START_DD_ERR + 1)
+#define DDERR_INVALIDCLIPLIST  (VALUE_START_DD_ERR + 2)
+#define DDERR_INVALIDOBJECT    (VALUE_START_DD_ERR + 3)
+#define DDERR_INVALIDPARAMS    (VALUE_START_DD_ERR + 4)
+#define DDERR_INVALIDRECT      (VALUE_START_DD_ERR + 5)
+#define DDERR_NOALPHAHW                (VALUE_START_DD_ERR + 6)
+#define DDERR_NOBLTHW          (VALUE_START_DD_ERR + 7)
+#define DDERR_NOCLIPLIST       (VALUE_START_DD_ERR + 8)
+#define DDERR_NODDROPSHW       (VALUE_START_DD_ERR + 9)
+#define DDERR_NOMIRRORHW       (VALUE_START_DD_ERR + 10)
+#define DDERR_NORASTEROPHW     (VALUE_START_DD_ERR + 11)
+#define DDERR_NOROTATIONHW     (VALUE_START_DD_ERR + 12)
+#define DDERR_NOSTRETCHHW      (VALUE_START_DD_ERR + 13)
+#define DDERR_NOZBUFFERHW      (VALUE_START_DD_ERR + 14)
+#define DDERR_SURFACEBUSY      (VALUE_START_DD_ERR + 15)
+#define DDERR_SURFACELOST      (VALUE_START_DD_ERR + 16)
+#define DDERR_UNSUPPORTED      (VALUE_START_DD_ERR + 17)
+#define DDERR_WASSTILLDRAWING  (VALUE_START_DD_ERR + 18)
+
+#define DSSCL_PRIORITY         (VALUE_START_DS + 1)
+#define DSBCAPS_CTRLFREQUENCY  (VALUE_START_DS + 2)
+#define DSBCAPS_CTRLPAN                (VALUE_START_DS + 3)
+#define DSBCAPS_CTRLVOLUME     (VALUE_START_DS + 4)
+#define DSBCAPS_STATIC         (VALUE_START_DS + 5)
+#define WAVE_FORMAT_PCM                (VALUE_START_DS + 6)
+#define DSBSTATUS_PLAYING      (VALUE_START_DS + 7)
+#define DSBPLAY_DEFAULT                (VALUE_START_DS + 8)
+
+#endif /* VB_DEFS_H */
diff --git a/src/game_sp/vb_lib.c b/src/game_sp/vb_lib.c
new file mode 100644 (file)
index 0000000..4b1e5cf
--- /dev/null
@@ -0,0 +1,146 @@
+// ----------------------------------------------------------------------------
+// vb_lib.c
+// ----------------------------------------------------------------------------
+
+#include "vb_types.h"
+#include "vb_defs.h"
+#include "vb_vars.h"
+#include "vb_lib.h"
+
+
+/* helper functions for constructs not supported by C */
+void *REDIM_1D(int a, int b, int c)
+{
+}
+
+void *REDIM_2D(int a, int b, int c, int d, int e)
+{
+}
+
+boolean IS_NOTHING(void *a, int b)
+{
+}
+
+void SET_TO_NOTHING(void *a, int b)
+{
+}
+
+void MESSAGE_BOX(char *a)
+{
+}
+
+
+char *CAT(const char *a, ...)
+{
+}
+
+char *GET_PATH(char *a, ...)
+{
+}
+
+char *INT_TO_STR(int a)
+{
+}
+
+
+boolean STRING_IS_LIKE(char *a, char *b)
+{
+}
+
+
+int FILE_GET(FILE *a, int b, void *c, int d)
+{
+}
+
+int FILE_PUT(FILE *a, int b, void *c, int d)
+{
+}
+
+
+/* this is just a workaround -- handle array definitions later */
+void *Array(int a, ...)
+{
+}
+
+
+/* VB functions that do not return "int" (and would cause compiler errors) */
+double Val(char *a)
+{
+}
+
+char *Left(char *a, int b)
+{
+}
+
+char *left(char *a, int b)
+{
+}
+
+char *Right(char *a, int b)
+{
+}
+
+char *right(char *a, int b)
+{
+}
+
+char *StrReverse(char *a)
+{
+}
+
+int InStr(int a, char *b, char *c)
+{
+}
+
+char *Dir(char *a)
+{
+}
+
+char *Dir_Without_Args()
+{
+}
+
+void Kill(char *a)
+{
+}
+
+char *Chr(int a)
+{
+}
+
+char *String(int a, char *b)
+{
+}
+
+void MkDir(char *a)
+{
+}
+
+char *Hex(int a)
+{
+}
+
+
+int FileLen(char *a)
+{
+}
+
+long GetTickCount()
+{
+}
+
+int GetAttr(char *a)
+{
+}
+
+void DoEvents()
+{
+}
+
+void SaveSetting(const char * a, const char *b, char *c, int d)
+{
+}
+
+long GetTempPath(long a, char *b)
+{
+}
diff --git a/src/game_sp/vb_lib.h b/src/game_sp/vb_lib.h
new file mode 100644 (file)
index 0000000..d68de81
--- /dev/null
@@ -0,0 +1,63 @@
+// ----------------------------------------------------------------------------
+// vb_lib.h
+// ----------------------------------------------------------------------------
+
+#ifndef VB_LIB_H
+#define VB_LIB_H
+
+#define Abs(x) ABS(x)
+#define Sqr(x) sqrt(x)
+
+
+/* helper functions for constructs not supported by C */
+extern void *REDIM_1D(int, int, int);
+extern void *REDIM_2D(int, int, int, int, int);
+
+extern boolean IS_NOTHING(void *, int);
+
+extern void SET_TO_NOTHING(void *, int);
+
+extern void MESSAGE_BOX(char *);
+
+extern char *CAT(const char *, ...);
+extern char *GET_PATH(char *, ...);
+extern char *INT_TO_STR(int);
+
+extern boolean STRING_IS_LIKE(char *, char *);
+
+extern int FILE_GET(FILE *, int, void *, int);
+extern int FILE_PUT(FILE *, int, void *, int);
+
+/* this is just a workaround -- handle array definitions later */
+extern void *Array(int, ...);
+
+/* VB functions that do not return "int" (and would cause compiler errors) */
+extern double Val(char *);
+extern char *Left(char *, int);
+extern char *left(char *, int);
+extern char *Right(char *, int);
+extern char *right(char *, int);
+extern char *StrReverse(char *);
+extern int InStr(int, char *, char *);
+extern char *Dir(char *);
+extern char *Dir_Without_Args();
+extern void Kill(char *);
+extern char *Chr(int);
+extern char *String(int, char *);
+extern void MkDir(char *);
+extern char *SlashLess(char *);
+extern char *Hex(int);
+
+extern int FileLen(char *);
+
+extern long GetTickCount();
+
+extern int GetAttr(char *);
+
+extern void DoEvents();
+
+extern void SaveSetting(const char *, const char *, char *, int);
+
+extern long GetTempPath(long, char *);
+
+#endif /* VB_LIB_H */
diff --git a/src/game_sp/vb_types.h b/src/game_sp/vb_types.h
new file mode 100644 (file)
index 0000000..02758fe
--- /dev/null
@@ -0,0 +1,281 @@
+// ----------------------------------------------------------------------------
+// vb_types.h
+// ----------------------------------------------------------------------------
+
+#ifndef VB_TYPES_H
+#define VB_TYPES_H
+
+#include "../libgame/types.h"
+
+
+#if 0
+typedef unsigned char boolean;
+#endif
+
+typedef double currency;
+
+#if 0
+#if !defined(PLATFORM_WIN32)
+typedef unsigned char byte;
+#endif
+#endif
+
+typedef int Variant;
+
+typedef struct
+{
+  int hWnd;
+} Object;
+
+#ifndef HAS_RECT
+typedef struct
+{
+  int left;
+  int top;
+  int right;
+  int bottom;
+} RECT;
+#define HAS_RECT
+#endif
+
+typedef struct
+{
+  char *Path;
+} vb_App;
+
+typedef struct
+{
+  void (*Assert)(boolean);
+  void (*Print)(char *);
+} vb_Debug;
+
+typedef struct
+{
+  int Number;
+  void (*Raise)(int, char *, char *);
+} vb_Err;
+
+typedef struct
+{
+  int Width;
+  int Height;
+
+  int ScaleWidth;
+  int ScaleHeight;
+  int ScaleMode;
+
+  int Orientation;
+
+  int TwipsPerPixelX;
+  int TwipsPerPixelY;
+
+  int hWnd;
+
+  int (*ScaleX)(int, int, int);
+  int (*ScaleY)(int, int, int);
+} vb_Generic_Device;
+
+typedef vb_Generic_Device vb_Screen;
+
+typedef vb_Generic_Device Form;
+typedef vb_Generic_Device Picture;
+typedef vb_Generic_Device IPicture;
+typedef vb_Generic_Device Printer;
+
+typedef struct
+{
+  int lCaps;
+} vb_Caps;
+
+typedef struct
+{
+  int LWidth;
+  int LHeight;
+  int lFlags;
+  vb_Caps ddsCaps;
+} DDSURFACEDESC2;
+
+typedef struct
+{
+  void (*SetHWnd)(long);
+} DirectDrawClipper;
+
+typedef struct
+{
+  boolean (*isLost)(void);
+  void (*GetSurfaceDesc)(DDSURFACEDESC2);
+  void (*SetClipper)(DirectDrawClipper);
+  // long (*Blt)(RECT, DirectDrawSurface7, RECT, int);
+  void (*BltColorFill)(RECT, int);
+} DirectDrawSurface7;
+
+typedef struct
+{
+  DirectDrawSurface7 (*CreateSurface)(DDSURFACEDESC2);
+  DirectDrawSurface7 (*CreateSurfaceFromFile)(char *, DDSURFACEDESC2);
+  void (*SetCooperativeLevel)(int, int);
+  DirectDrawClipper (*CreateClipper)(int);
+  void (*RestoreAllSurfaces)(void);
+} DirectDraw7;
+
+typedef struct
+{
+  int lFlags;
+} DSBUFFERDESC;
+
+typedef struct
+{
+  int nFormatTag;
+  int nChannels;
+  int lSamplesPerSec;
+  int nBitsPerSample;
+  int nBlockAlign;
+  int lAvgBytesPerSec;
+} WAVEFORMATEX;
+
+typedef struct
+{
+  int (*GetStatus)(void);
+  void (*Play)(int);
+} DirectSoundBuffer;
+
+typedef struct
+{
+  void (*SetCooperativeLevel)(long, int);
+  DirectSoundBuffer (*CreateSoundBufferFromFile)(char *, DSBUFFERDESC, WAVEFORMATEX);
+} DirectSound;
+
+typedef struct
+{
+  DirectDraw7 (*DirectDrawCreate)(char *);
+  DirectSound (*DirectSoundCreate)(char *);
+  void (*GetWindowRect)(long, RECT);
+} DirectX7;
+
+typedef struct
+{
+  int Left;
+  int Top;
+  void (*RefreshMarker)(void);
+} MarkerObject;
+
+typedef struct
+{
+  void (*DelayMS)(long, boolean);
+  double (*TickDiffUS)(double);
+  double TickNow;
+} TickCountObject;
+
+typedef struct
+{
+  int Caption;
+  void (*Refresh)(void);
+} MainForm_lblCount;
+
+typedef struct
+{
+  boolean Checked;
+  boolean Enabled;
+} MainForm_men;
+
+typedef struct
+{
+  int Width;
+  int Height;
+  void (*Line)(int, int, int, int, int, int);
+} MainForm_picPane;
+
+typedef struct
+{
+  MainForm_lblCount lblInfoCount;
+  MainForm_lblCount lblRedDiskCount;
+  void (*DisplayLevel)(void);
+  void (*DrawField)(int, int);
+  MainForm_men menGravOn;
+  MainForm_men menZonkOn;
+  MainForm_men menEnOn;
+  MainForm_men menGravOff;
+  MainForm_men menZonkOff;
+  MainForm_men menEnOff;
+  MainForm_men menRemSP;
+  MainForm_men menSP;
+  char *Caption;
+  boolean PanelVisible;
+  void (*ShowKey)(int);
+  void (*SaveSnapshot)(int);
+  void (*menStop_Click)(void);
+  MainForm_picPane picPane;
+  char *lblFrameCount;
+  void (*SetDisplayRegion)(void);
+} MainFormObject;
+
+typedef struct
+{
+  int DestXOff;
+  int DestYOff;
+
+  void (*Blt)();
+  void (*ScrollTo)(int, int);
+  void (*ScrollTowards)(int, int, double);
+  void (*SoftScrollTo)(int, int, long, int);
+
+} DDScrollBuffer;
+
+typedef struct
+{
+  void (*BltEx)(int, int, int);
+} DDSpriteBuffer;
+
+typedef struct
+{
+  void (*CreateAtSize)(long, long, long);
+  void (*Let_Palette)(long, long);
+  void (*Let_ColorIndex)(long, long, long);
+} BitMapObject;
+
+struct DemoBufferObject
+{
+  int Size;
+  byte CheckSumByte;
+  void (*SetSubBuffer)(struct DemoBufferObject *);
+  void (*AddDemoKey)(int);
+  boolean (*Serialize)(FILE *);
+};
+typedef struct DemoBufferObject DemoBufferObject;
+
+typedef struct
+{
+  int (*Read)(char *ValName, int Default);
+  void (*Save)(char *ValName, int Val);
+} SettingsObject;
+
+typedef struct
+{
+  int left;
+  int top;
+  int ListIndex;
+  char (*List)(int);
+} cmbFileObject;
+
+typedef struct
+{
+  int Width;
+  int Height;
+  boolean Visible;
+  void (*Move)(int, int, int);
+} shpProgressObject;
+
+typedef struct
+{
+  int left;
+  int Top;
+  int Width;
+  int Height;
+} lblFrameCountObject;
+
+typedef struct
+{
+  boolean Checked;
+} menBorderObject;
+
+#endif /* VB_TYPES_H */
diff --git a/src/game_sp/vb_vars.c b/src/game_sp/vb_vars.c
new file mode 100644 (file)
index 0000000..a6c17a8
--- /dev/null
@@ -0,0 +1,15 @@
+// ----------------------------------------------------------------------------
+// vb_vars.c
+// ----------------------------------------------------------------------------
+
+#include "vb_types.h"
+#include "vb_defs.h"
+#include "vb_vars.h"
+#include "vb_lib.h"
+
+vb_App App;
+vb_Err Err;
+MainFormObject MainForm;
+lblFrameCountObject lblFrameCount;
+cmbFileObject cmbFile;
+shpProgressObject shpProgress;
diff --git a/src/game_sp/vb_vars.h b/src/game_sp/vb_vars.h
new file mode 100644 (file)
index 0000000..daf359e
--- /dev/null
@@ -0,0 +1,23 @@
+// ----------------------------------------------------------------------------
+// vb_vars.h
+// ----------------------------------------------------------------------------
+
+#ifndef VB_VARS_H
+#define VB_VARS_H
+
+extern vb_Screen Screen;
+extern vb_Debug Debug;
+extern vb_Err Err;
+extern vb_App App;
+
+extern DemoBufferObject VB_OBJECT_SELF;
+
+extern MainFormObject MainForm;
+extern cmbFileObject cmbFile;
+extern shpProgressObject shpProgress;
+extern lblFrameCountObject lblFrameCount;
+extern menBorderObject menBorder;
+
+extern int hWnd;
+
+#endif /* VB_VARS_H */
index 68f1eed082c22ec8b93d9b9e902c93f65ca9849d..38a5bcbf7900b82cc6f01578cf648f97b84a6b05 100644 (file)
@@ -24,6 +24,7 @@
 
 #include "libgame/libgame.h"
 #include "game_em/game_em.h"
+#include "game_sp/game_sp.h"
 
 #include "conf_gfx.h"  /* include auto-generated data structure definitions */
 #include "conf_snd.h"  /* include auto-generated data structure definitions */
 #define PROGRAM_VERSION_MAJOR          3
 #define PROGRAM_VERSION_MINOR          2
 #define PROGRAM_VERSION_PATCH          6
-#define PROGRAM_VERSION_BUILD          1
+#define PROGRAM_VERSION_BUILD          2
 
 #define PROGRAM_TITLE_STRING           "Rocks'n'Diamonds"
 #define PROGRAM_AUTHOR_STRING          "Holger Schemel"
-#define PROGRAM_COPYRIGHT_STRING       "Copyright ©1995-2008 by Holger Schemel"
+#define PROGRAM_COPYRIGHT_STRING       "Copyright ©1995-2009 by Holger Schemel"
 #define PROGRAM_EMAIL_STRING           "info@artsoft.org"
 #define PROGRAM_WEBSITE_STRING         "http://www.artsoft.org/"
 #define PROGRAM_GAME_BY_STRING         "A Game by Artsoft Entertainment"
 #define GAME_ENGINE_TYPE_UNKNOWN       LEVEL_FILE_TYPE_UNKNOWN
 #define GAME_ENGINE_TYPE_RND           LEVEL_FILE_TYPE_RND
 #define GAME_ENGINE_TYPE_EM            LEVEL_FILE_TYPE_EM
+#define GAME_ENGINE_TYPE_SP            LEVEL_FILE_TYPE_SP
 
-#define NUM_ENGINE_TYPES               3
+#define NUM_ENGINE_TYPES               4
 
 
 struct BorderInfo