added option for BD1 magic wall / amoeba bug for native BD engine
authorHolger Schemel <info@artsoft.org>
Tue, 2 Apr 2024 17:55:41 +0000 (19:55 +0200)
committerHolger Schemel <info@artsoft.org>
Tue, 2 Apr 2024 17:55:41 +0000 (19:55 +0200)
src/editor.c
src/files.c
src/game_bd/bd_c64import.c
src/game_bd/bd_cave.h
src/game_bd/bd_cavedb.c
src/game_bd/bd_caveengine.c
src/main.h

index a91aba1d93ac3ea7e1dfe1429723b27b024cbdf9..1f17252a5b18cdec58d63a9460aa24824f94e8ec 100644 (file)
@@ -752,6 +752,7 @@ enum
   GADGET_ID_BD_MAGIC_WALL_ZERO_INFINITE,
   GADGET_ID_BD_MAGIC_WALL_WAIT_HATCHING,
   GADGET_ID_BD_MAGIC_WALL_STOPS_AMOEBA,
+  GADGET_ID_BD_MAGIC_WALL_BREAK_SCAN,
   GADGET_ID_BD_AMOEBA_WAIT_FOR_HATCHING,
   GADGET_ID_BD_AMOEBA_START_IMMEDIATELY,
   GADGET_ID_BD_AMOEBA_2_EXPLODE_BY_AMOEBA,
@@ -1109,6 +1110,7 @@ enum
   ED_CHECKBUTTON_ID_BD_MAGIC_WALL_ZERO_INFINITE,
   ED_CHECKBUTTON_ID_BD_MAGIC_WALL_WAIT_HATCHING,
   ED_CHECKBUTTON_ID_BD_MAGIC_WALL_STOPS_AMOEBA,
+  ED_CHECKBUTTON_ID_BD_MAGIC_WALL_BREAK_SCAN,
   ED_CHECKBUTTON_ID_BD_AMOEBA_WAIT_FOR_HATCHING,
   ED_CHECKBUTTON_ID_BD_AMOEBA_START_IMMEDIATELY,
   ED_CHECKBUTTON_ID_BD_AMOEBA_2_EXPLODE_BY_AMOEBA,
@@ -3849,6 +3851,14 @@ static struct
     NULL, NULL,
     "Stop amoeba and turn to diamonds",                "Activation changes amoeba to diamonds"
   },
+  {
+    ED_CHECKBUTTON_ID_BD_MAGIC_WALL_BREAK_SCAN,
+    ED_ELEMENT_SETTINGS_XPOS(0),               ED_ELEMENT_SETTINGS_YPOS(5),
+    GADGET_ID_BD_MAGIC_WALL_BREAK_SCAN,                GADGET_ID_NONE,
+    &level.bd_magic_wall_break_scan,
+    NULL, NULL,
+    "Emulate amoeba bug in BD1",               "Use buggy BD1 behavior"
+  },
   {
     ED_CHECKBUTTON_ID_BD_AMOEBA_WAIT_FOR_HATCHING,
     ED_ELEMENT_SETTINGS_XPOS(0),               ED_ELEMENT_SETTINGS_YPOS(1),
@@ -4487,7 +4497,7 @@ static struct
 
   {
     ED_DRAWING_ID_BD_MAGIC_WALL_DIAMOND_TO,
-    ED_AREA_1X1_SETTINGS_XPOS(0),              ED_AREA_1X1_SETTINGS_YPOS(5),
+    ED_AREA_1X1_SETTINGS_XPOS(0),              ED_AREA_1X1_SETTINGS_YPOS(6),
     ED_AREA_1X1_SETTINGS_XOFF,                 ED_AREA_1X1_SETTINGS_YOFF,
     GADGET_ID_BD_MAGIC_WALL_DIAMOND_TO,                GADGET_ID_NONE,
     &level.bd_magic_wall_diamond_to,           1, 1,
@@ -4495,7 +4505,7 @@ static struct
   },
   {
     ED_DRAWING_ID_BD_MAGIC_WALL_ROCK_TO,
-    ED_AREA_1X1_SETTINGS_XPOS(0),              ED_AREA_1X1_SETTINGS_YPOS(6),
+    ED_AREA_1X1_SETTINGS_XPOS(0),              ED_AREA_1X1_SETTINGS_YPOS(7),
     ED_AREA_1X1_SETTINGS_XOFF,                 ED_AREA_1X1_SETTINGS_YOFF,
     GADGET_ID_BD_MAGIC_WALL_ROCK_TO,           GADGET_ID_NONE,
     &level.bd_magic_wall_rock_to,              1, 1,
@@ -4503,7 +4513,7 @@ static struct
   },
   {
     ED_DRAWING_ID_BD_MAGIC_WALL_MEGA_ROCK_TO,
-    ED_AREA_1X1_SETTINGS_XPOS(0),              ED_AREA_1X1_SETTINGS_YPOS(7),
+    ED_AREA_1X1_SETTINGS_XPOS(0),              ED_AREA_1X1_SETTINGS_YPOS(8),
     ED_AREA_1X1_SETTINGS_XOFF,                 ED_AREA_1X1_SETTINGS_YOFF,
     GADGET_ID_BD_MAGIC_WALL_MEGA_ROCK_TO,      GADGET_ID_NONE,
     &level.bd_magic_wall_mega_rock_to,         1, 1,
@@ -4511,7 +4521,7 @@ static struct
   },
   {
     ED_DRAWING_ID_BD_MAGIC_WALL_NUT_TO,
-    ED_AREA_1X1_SETTINGS_XPOS(0),              ED_AREA_1X1_SETTINGS_YPOS(8),
+    ED_AREA_1X1_SETTINGS_XPOS(0),              ED_AREA_1X1_SETTINGS_YPOS(9),
     ED_AREA_1X1_SETTINGS_XOFF,                 ED_AREA_1X1_SETTINGS_YOFF,
     GADGET_ID_BD_MAGIC_WALL_NUT_TO,            GADGET_ID_NONE,
     &level.bd_magic_wall_nut_to,               1, 1,
@@ -4519,7 +4529,7 @@ static struct
   },
   {
     ED_DRAWING_ID_BD_MAGIC_WALL_NITRO_PACK_TO,
-    ED_AREA_1X1_SETTINGS_XPOS(0),              ED_AREA_1X1_SETTINGS_YPOS(9),
+    ED_AREA_1X1_SETTINGS_XPOS(0),              ED_AREA_1X1_SETTINGS_YPOS(10),
     ED_AREA_1X1_SETTINGS_XOFF,                 ED_AREA_1X1_SETTINGS_YOFF,
     GADGET_ID_BD_MAGIC_WALL_NITRO_PACK_TO,     GADGET_ID_NONE,
     &level.bd_magic_wall_nitro_pack_to,                1, 1,
@@ -4527,7 +4537,7 @@ static struct
   },
   {
     ED_DRAWING_ID_BD_MAGIC_WALL_FLYING_DIAMOND_TO,
-    ED_AREA_1X1_SETTINGS_XPOS(0),              ED_AREA_1X1_SETTINGS_YPOS(10),
+    ED_AREA_1X1_SETTINGS_XPOS(0),              ED_AREA_1X1_SETTINGS_YPOS(11),
     ED_AREA_1X1_SETTINGS_XOFF,                 ED_AREA_1X1_SETTINGS_YOFF,
     GADGET_ID_BD_MAGIC_WALL_FLYING_DIAMOND_TO, GADGET_ID_NONE,
     &level.bd_magic_wall_flying_diamond_to,    1, 1,
@@ -4535,7 +4545,7 @@ static struct
   },
   {
     ED_DRAWING_ID_BD_MAGIC_WALL_FLYING_ROCK_TO,
-    ED_AREA_1X1_SETTINGS_XPOS(0),              ED_AREA_1X1_SETTINGS_YPOS(11),
+    ED_AREA_1X1_SETTINGS_XPOS(0),              ED_AREA_1X1_SETTINGS_YPOS(12),
     ED_AREA_1X1_SETTINGS_XOFF,                 ED_AREA_1X1_SETTINGS_YOFF,
     GADGET_ID_BD_MAGIC_WALL_FLYING_ROCK_TO,    GADGET_ID_NONE,
     &level.bd_magic_wall_flying_rock_to,       1, 1,
@@ -11938,6 +11948,7 @@ static void DrawPropertiesConfig(void)
     MapCheckbuttonGadget(ED_CHECKBUTTON_ID_BD_MAGIC_WALL_ZERO_INFINITE);
     MapCheckbuttonGadget(ED_CHECKBUTTON_ID_BD_MAGIC_WALL_WAIT_HATCHING);
     MapCheckbuttonGadget(ED_CHECKBUTTON_ID_BD_MAGIC_WALL_STOPS_AMOEBA);
+    MapCheckbuttonGadget(ED_CHECKBUTTON_ID_BD_MAGIC_WALL_BREAK_SCAN);
 
     MapDrawingArea(ED_DRAWING_ID_BD_MAGIC_WALL_DIAMOND_TO);
     MapDrawingArea(ED_DRAWING_ID_BD_MAGIC_WALL_ROCK_TO);
index 25943b63f123b597870bcc4a56141b6d48997023..040a94481794c49ae1eff1418d2ffd22759d1c95 100644 (file)
@@ -742,6 +742,11 @@ static struct LevelFileConfigInfo chunk_config_ELEM[] =
     TYPE_BOOLEAN,                      CONF_VALUE_8_BIT(3),
     &li.bd_magic_wall_zero_infinite,   TRUE
   },
+  {
+    EL_BD_MAGIC_WALL,                  -1,
+    TYPE_BOOLEAN,                      CONF_VALUE_8_BIT(4),
+    &li.bd_magic_wall_break_scan,      FALSE
+  },
   {
     EL_BD_MAGIC_WALL,                  -1,
     TYPE_ELEMENT,                      CONF_VALUE_16_BIT(1),
@@ -4272,6 +4277,7 @@ static void CopyNativeLevel_RND_to_BD(struct LevelInfo *level)
   cave->magic_timer_zero_is_infinite   = level->bd_magic_wall_zero_infinite;
   cave->magic_timer_wait_for_hatching  = level->bd_magic_wall_wait_hatching;
   cave->magic_wall_stops_amoeba                = level->bd_magic_wall_stops_amoeba;
+  cave->magic_wall_breakscan           = level->bd_magic_wall_break_scan;
 
   cave->magic_diamond_to               = LEVEL_TO_CAVE(level->bd_magic_wall_diamond_to);
   cave->magic_stone_to                 = LEVEL_TO_CAVE(level->bd_magic_wall_rock_to);
@@ -4436,6 +4442,7 @@ static void CopyNativeLevel_BD_to_RND(struct LevelInfo *level)
   level->bd_magic_wall_zero_infinite   = cave->magic_timer_zero_is_infinite;
   level->bd_magic_wall_wait_hatching   = cave->magic_timer_wait_for_hatching;
   level->bd_magic_wall_stops_amoeba    = cave->magic_wall_stops_amoeba;
+  level->bd_magic_wall_break_scan      = cave->magic_wall_breakscan;
 
   level->bd_magic_wall_diamond_to      = CAVE_TO_LEVEL(cave->magic_diamond_to);
   level->bd_magic_wall_rock_to         = CAVE_TO_LEVEL(cave->magic_stone_to);
index 61486da72d855af6564beb56174f165116e78a60..9047c75fe4ce9a084da573ca2742e5e5d07cf4fe 100644 (file)
@@ -221,6 +221,7 @@ GdPropertyDefault gd_defaults_bd1[] =
   {CAVE_OFFSET(intermission_instantlife), TRUE},
   {CAVE_OFFSET(intermission_rewardlife), FALSE},
   {CAVE_OFFSET(magic_wall_stops_amoeba), TRUE},
+  {CAVE_OFFSET(magic_wall_breakscan), TRUE},
   {CAVE_OFFSET(magic_timer_zero_is_infinite), TRUE},
   {CAVE_OFFSET(magic_timer_wait_for_hatching), FALSE},
   {CAVE_OFFSET(pushing_stone_prob), 250000},
index d8f4559175d8e93f900d9a0c13f8022122ea1d5c..483b54feafcaafdcf99d6ed4d72753ddc8b23585 100644 (file)
@@ -394,6 +394,8 @@ typedef struct _gd_cave
   int level_magic_wall_time[5];         // magic wall 'on' state for each level (seconds)
   boolean magic_wall_stops_amoeba;      // Turning on magic wall changes amoeba to diamonds.
                                         // Original BD: yes, constkit: no
+  boolean magic_wall_breakscan;                // Currently this setting enabled will turn the amoeba to
+                                        // an enclosed state. To implement buggy BD1 behaviour.
   boolean magic_timer_zero_is_infinite;        // magic wall timer 0 is interpreted as infinite
   boolean magic_timer_wait_for_hatching;// magic wall timer does not start before player's birth
   boolean magic_wall_sound;             // magic wall has sound
@@ -587,6 +589,7 @@ typedef struct _gd_cave
   int amoeba_2_max_count;               // selected amoeba 2 threshold for this level
   GdAmoebaState amoeba_state;           // state of amoeba 1
   GdAmoebaState amoeba_2_state;         // state of amoeba 2
+  boolean convert_amoeba_this_frame;    // To implement BD1 buggy amoeba+magic wall behaviour.
   int magic_wall_time;                  // magic wall 'on' state for seconds
   int slime_permeability;               // true random slime
   int slime_permeability_c64;           // Appearing in bd 2
index b54eff89e2e434274d165331eb25c712c4a3d521..a00de067ea1ffe5ae00b7373d0a73157d5c80ec1 100644 (file)
@@ -550,6 +550,7 @@ const GdStructDescriptor gd_cave_properties[] =
   {"MagicWallProperties.zeroisinfinite", GD_TYPE_BOOLEAN, 0, N_("Milling time 0 is infinite"), CAVE_OFFSET(magic_timer_zero_is_infinite), 1, N_("This determines if the magic wall timer 0 is interpreted as infinite.")},
   {"MagicWallProperties.waitforhatching", GD_TYPE_BOOLEAN, 0, N_("Timer waits for hatching"), CAVE_OFFSET(magic_timer_wait_for_hatching), 1, N_("This determines if the magic wall timer starts before the player appearing. Magic can always be activated before that; but if this is set to true, the timer will not start.")},
   {"MagicWallProperties.convertamoeba", GD_TYPE_BOOLEAN, 0, N_("Stops amoeba"), CAVE_OFFSET(magic_wall_stops_amoeba), 1, N_("When the magic wall is activated, it can convert amoeba into diamonds.")},
+  {"MagicWallProperties.breakscan", GD_TYPE_BOOLEAN, 0, N_("BD1 amoeba bug"), CAVE_OFFSET(magic_wall_breakscan), 1, N_("This setting emulates the BD1 bug, where a stone or a diamond falling into a magic wall sometimes caused the active amoeba to convert into a diamond. The rule is: if all amoeba cells above or left to the point where the stone or the diamond falls into the magic wall are enclosed, the amoeba is converted. The timing implications of the bug are not emulated.")},
   {"", GD_LABEL, 0, N_("Conversions")},
   {"MagicWallProperties", GD_TYPE_ELEMENT, 0, N_("Diamond to"), CAVE_OFFSET(magic_diamond_to), 1, N_("As a special effect, magic walls can convert diamonds to any other element.")},
   {"MagicWallProperties", GD_TYPE_ELEMENT, 0, N_("Stone to"), CAVE_OFFSET(magic_stone_to), 1, N_("As a special effect, magic walls can convert stones to any other element.")},
index 46c97e57551043390c027b787f9cacadbfeff6a6..e221ca7784551455c8e7e5d376129f8c31dac05b 100644 (file)
@@ -1371,6 +1371,9 @@ static boolean do_fall_try_magic(GdCave *cave, int x, int y,
     // active or non-active or anything, element falling in will always disappear
     store(cave, x, y, O_SPACE);
 
+    if (cave->magic_wall_breakscan && cave->amoeba_state == GD_AM_AWAKE)
+      cave->convert_amoeba_this_frame = TRUE;
+
     return TRUE;
   }
   else
@@ -1604,6 +1607,9 @@ void gd_cave_iterate(GdCave *cave, GdDirection player_move, boolean player_fire,
   // score collected this frame
   cave->score = 0;
 
+  // to implement buggy bd1 amoeba+magic wall behaviour
+  cave->convert_amoeba_this_frame = FALSE;
+
   // suicide only kills the active player
   // player_x, player_y was set by the previous iterate routine, or the cave setup.
   // we must check if there is a player or not - he may have exploded or something like that
@@ -2847,6 +2853,13 @@ void gd_cave_iterate(GdCave *cave, GdDirection player_move, boolean player_fire,
          // ============================================================================
 
        case O_AMOEBA:
+         // emulating BD1 amoeba+magic wall bug
+         if (cave->convert_amoeba_this_frame && amoeba_found_enclosed)
+         {
+           store(cave, x, y, cave->amoeba_enclosed_effect);
+           break;
+         }
+
          amoeba_count++;
          switch (cave->amoeba_state)
          {
index 4472b912575e4337dafbbf20700bd9f6a73df8ba..13d92656d537b2a3410edc1ea9bd003bd6c9a8bf 100644 (file)
@@ -3665,6 +3665,7 @@ struct LevelInfo
   boolean bd_magic_wall_zero_infinite; // BD magic wall with timer of zero runs infinitely
   boolean bd_magic_wall_wait_hatching; // BD magic wall waits for player's birth
   boolean bd_magic_wall_stops_amoeba;  // BD magic wall can stop amoeba and turn to diamonds
+  boolean bd_magic_wall_break_scan;    // BD magic wall setting to implement buggy BD1 behaviour
   int bd_magic_wall_diamond_to;                // BD magic wall turns diamonds to specified element
   int bd_magic_wall_rock_to;           // BD magic wall turns rocks to specified element
   int bd_magic_wall_mega_rock_to;      // BD magic wall turns mega rocks to specified element