added correcting random numbers for predictable slime in BD engine
[rocksndiamonds.git] / src / editor.c
index 1d4edbfa68b066f94fa151ca332c461c0d48fb47..025de3a70c1fb5d643c6bdeb8d0c7ea55fd83ea6 100644 (file)
@@ -556,6 +556,7 @@ enum
   GADGET_ID_MAGIC_BALL_CONTENT_7,
   GADGET_ID_ANDROID_CONTENT,
   GADGET_ID_AMOEBA_CONTENT,
+  GADGET_ID_BD_SNAP_ELEMENT,
   GADGET_ID_BD_AMOEBA_CONTENT_TOO_BIG,
   GADGET_ID_BD_AMOEBA_CONTENT_ENCLOSED,
   GADGET_ID_BD_AMOEBA_2_CONTENT_TOO_BIG,
@@ -719,6 +720,11 @@ enum
   GADGET_ID_BD_AMOEBA_WAIT_FOR_HATCHING,
   GADGET_ID_BD_AMOEBA_START_IMMEDIATELY,
   GADGET_ID_BD_AMOEBA_2_EXPLODE_BY_AMOEBA,
+  GADGET_ID_BD_VOODOO_COLLECTS_DIAMONDS,
+  GADGET_ID_BD_VOODOO_HURT_KILLS_PLAYER,
+  GADGET_ID_BD_VOODOO_DIES_BY_ROCK,
+  GADGET_ID_BD_VOODOO_VANISH_BY_EXPLOSION,
+  GADGET_ID_BD_SLIME_IS_PREDICTABLE,
   GADGET_ID_ENVELOPE_AUTOWRAP,
   GADGET_ID_ENVELOPE_CENTERED,
   GADGET_ID_MM_LASER_RED,
@@ -1059,6 +1065,11 @@ enum
   ED_CHECKBUTTON_ID_BD_AMOEBA_WAIT_FOR_HATCHING,
   ED_CHECKBUTTON_ID_BD_AMOEBA_START_IMMEDIATELY,
   ED_CHECKBUTTON_ID_BD_AMOEBA_2_EXPLODE_BY_AMOEBA,
+  ED_CHECKBUTTON_ID_BD_VOODOO_COLLECTS_DIAMONDS,
+  ED_CHECKBUTTON_ID_BD_VOODOO_HURT_KILLS_PLAYER,
+  ED_CHECKBUTTON_ID_BD_VOODOO_DIES_BY_ROCK,
+  ED_CHECKBUTTON_ID_BD_VOODOO_VANISH_BY_EXPLOSION,
+  ED_CHECKBUTTON_ID_BD_SLIME_IS_PREDICTABLE,
   ED_CHECKBUTTON_ID_ENVELOPE_AUTOWRAP,
   ED_CHECKBUTTON_ID_ENVELOPE_CENTERED,
   ED_CHECKBUTTON_ID_MM_LASER_RED,
@@ -1154,6 +1165,7 @@ enum
   ED_DRAWING_ID_MAGIC_BALL_CONTENT_7,
   ED_DRAWING_ID_ANDROID_CONTENT,
   ED_DRAWING_ID_AMOEBA_CONTENT,
+  ED_DRAWING_ID_BD_SNAP_ELEMENT,
   ED_DRAWING_ID_BD_AMOEBA_CONTENT_TOO_BIG,
   ED_DRAWING_ID_BD_AMOEBA_CONTENT_ENCLOSED,
   ED_DRAWING_ID_BD_AMOEBA_2_CONTENT_TOO_BIG,
@@ -3750,6 +3762,46 @@ static struct
     NULL, NULL,
     "explodes if touched by amoeba",   "amoeba 2 explodes if touched by amoeba"
   },
+  {
+    ED_CHECKBUTTON_ID_BD_VOODOO_COLLECTS_DIAMONDS,
+    ED_ELEMENT_SETTINGS_XPOS(0),       ED_ELEMENT_SETTINGS_YPOS(0),
+    GADGET_ID_BD_VOODOO_COLLECTS_DIAMONDS, GADGET_ID_NONE,
+    &level.bd_voodoo_collects_diamonds,
+    NULL, NULL,
+    "can collect diamonds",            "can collect diamonds for the player"
+  },
+  {
+    ED_CHECKBUTTON_ID_BD_VOODOO_HURT_KILLS_PLAYER,
+    ED_ELEMENT_SETTINGS_XPOS(0),       ED_ELEMENT_SETTINGS_YPOS(1),
+    GADGET_ID_BD_VOODOO_HURT_KILLS_PLAYER, GADGET_ID_NONE,
+    &level.bd_voodoo_hurt_kills_player,
+    NULL, NULL,
+    "player is killed if hurt",                "if hurt in any way, player is killed"
+  },
+  {
+    ED_CHECKBUTTON_ID_BD_VOODOO_DIES_BY_ROCK,
+    ED_ELEMENT_SETTINGS_XPOS(0),       ED_ELEMENT_SETTINGS_YPOS(2),
+    GADGET_ID_BD_VOODOO_DIES_BY_ROCK,  GADGET_ID_NONE,
+    &level.bd_voodoo_dies_by_rock,
+    NULL, NULL,
+    "killed by falling rock",          "can be killed by a falling rock"
+  },
+  {
+    ED_CHECKBUTTON_ID_BD_VOODOO_VANISH_BY_EXPLOSION,
+    ED_ELEMENT_SETTINGS_XPOS(0),       ED_ELEMENT_SETTINGS_YPOS(3),
+    GADGET_ID_BD_VOODOO_VANISH_BY_EXPLOSION, GADGET_ID_NONE,
+    &level.bd_voodoo_vanish_by_explosion,
+    NULL, NULL,
+    "disappears in explosions",                "can be destroyed by explosions"
+  },
+  {
+    ED_CHECKBUTTON_ID_BD_SLIME_IS_PREDICTABLE,
+    ED_ELEMENT_SETTINGS_XPOS(0),       ED_ELEMENT_SETTINGS_YPOS(0),
+    GADGET_ID_BD_SLIME_IS_PREDICTABLE, GADGET_ID_NONE,
+    &level.bd_slime_is_predictable,
+    NULL, NULL,
+    "slime is predictable",            "use predictable random numbers"
+  },
   {
     ED_CHECKBUTTON_ID_ENVELOPE_AUTOWRAP,
     ED_ELEMENT_SETTINGS_XPOS(0),       ED_ELEMENT_SETTINGS_YPOS(1),
@@ -4221,7 +4273,18 @@ static struct
     "content:", NULL, NULL, NULL,      "amoeba content"
   },
 
-  // ---------- BD amoeba content ------------------------------------------------
+  // ---------- BD snap element -----------------------------------------------
+
+  {
+    ED_DRAWING_ID_BD_SNAP_ELEMENT,
+    ED_AREA_1X1_SETTINGS_XPOS(0),      ED_AREA_1X1_SETTINGS_YPOS(5),
+    ED_AREA_1X1_SETTINGS_XOFF,         ED_AREA_1X1_SETTINGS_YOFF,
+    GADGET_ID_BD_SNAP_ELEMENT,         GADGET_ID_NONE,
+    &level.bd_snap_element,            1, 1,
+    "snap element:", NULL, NULL, NULL, "element created when snapping"
+  },
+
+  // ---------- BD amoeba content ---------------------------------------------
 
   {
     ED_DRAWING_ID_BD_AMOEBA_CONTENT_TOO_BIG,
@@ -4240,7 +4303,7 @@ static struct
     "if enclosed, changes to:", NULL, NULL, NULL,      "BD amoeba content if enclosed"
   },
 
-  // ---------- BD amoeba 2 content ------------------------------------------------
+  // ---------- BD amoeba 2 content -------------------------------------------
 
   {
     ED_DRAWING_ID_BD_AMOEBA_2_CONTENT_TOO_BIG,
@@ -10787,12 +10850,18 @@ static void DrawPropertiesInfo(void)
 #define TEXT_GAME_OF_LIFE_3    "Min neighbours to create"
 #define TEXT_GAME_OF_LIFE_4    "Max neighbours to create"
 #define TEXT_TIME_BONUS                "Extra time to solve level"
+#define TEXT_TIME_PENALTY      "Time penalty if destroyed"
+#define TEXT_PERMEABILITY_RATE "slime permeability rate"
+#define TEXT_PERMEABILITY_BITS "slime permeability bits"
+#define TEXT_RANDOM_SEED       "slime random number seed"
 
 static struct
 {
   int element;
   int *value;
   char *text;
+  int min_value;
+  int max_value;
 } elements_with_counter[] =
 {
   { EL_EMERALD,                        &level.score[SC_EMERALD],               TEXT_COLLECTING         },
@@ -10877,12 +10946,16 @@ static struct
   { EL_EMC_DRIPPER,            &level.amoeba_speed,                    TEXT_AMOEBA_SPEED       },
   { EL_BD_AMOEBA,              &level.bd_amoeba_threshold_too_big,     TEXT_AMOEBA_THRESHOED   },
   { EL_BD_AMOEBA,              &level.bd_amoeba_slow_growth_time,      TEXT_AMOEBA_SLOW_TIME   },
-  { EL_BD_AMOEBA,              &level.bd_amoeba_slow_growth_rate,      TEXT_AMOEBA_SLOW_RATE   },
-  { EL_BD_AMOEBA,              &level.bd_amoeba_fast_growth_rate,      TEXT_AMOEBA_FAST_RATE   },
+  { EL_BD_AMOEBA,              &level.bd_amoeba_slow_growth_rate,      TEXT_AMOEBA_SLOW_RATE,
+                               0, 100                                                          },
+  { EL_BD_AMOEBA,              &level.bd_amoeba_fast_growth_rate,      TEXT_AMOEBA_FAST_RATE,
+                               0, 100                                                          },
   { EL_BD_AMOEBA_2,            &level.bd_amoeba_2_threshold_too_big,   TEXT_AMOEBA_THRESHOED   },
   { EL_BD_AMOEBA_2,            &level.bd_amoeba_2_slow_growth_time,    TEXT_AMOEBA_SLOW_TIME   },
-  { EL_BD_AMOEBA_2,            &level.bd_amoeba_2_slow_growth_rate,    TEXT_AMOEBA_SLOW_RATE   },
-  { EL_BD_AMOEBA_2,            &level.bd_amoeba_2_fast_growth_rate,    TEXT_AMOEBA_FAST_RATE   },
+  { EL_BD_AMOEBA_2,            &level.bd_amoeba_2_slow_growth_rate,    TEXT_AMOEBA_SLOW_RATE,
+                               0, 100                                                          },
+  { EL_BD_AMOEBA_2,            &level.bd_amoeba_2_fast_growth_rate,    TEXT_AMOEBA_FAST_RATE,
+                               0, 100                                                          },
   { EL_MAGIC_WALL,             &level.time_magic_wall,                 TEXT_DURATION           },
   { EL_BD_MAGIC_WALL,          &level.time_magic_wall,                 TEXT_DURATION           },
   { EL_DC_MAGIC_WALL,          &level.time_magic_wall,                 TEXT_DURATION           },
@@ -10893,17 +10966,26 @@ static struct
   { EL_LIGHT_SWITCH_ACTIVE,    &level.time_light,                      TEXT_DURATION           },
   { EL_SHIELD_NORMAL,          &level.shield_normal_time,              TEXT_DURATION           },
   { EL_SHIELD_DEADLY,          &level.shield_deadly_time,              TEXT_DURATION           },
-  { EL_BD_CLOCK,               &level.bd_clock_extra_time,             TEXT_TIME_BONUS         },
+  { EL_BD_CLOCK,               &level.bd_clock_extra_time,             TEXT_TIME_BONUS,
+                               -100, 100                                                       },
+  { EL_BD_VOODOO_DOLL,         &level.bd_voodoo_penalty_time,          TEXT_TIME_PENALTY,
+                               0, 100                                                          },
+  { EL_BD_SLIME,               &level.bd_slime_permeability_rate,      TEXT_PERMEABILITY_RATE,
+                               0, 100                                                          },
+  { EL_BD_SLIME,               &level.bd_slime_permeability_bits_c64,  TEXT_PERMEABILITY_BITS,
+                               0, 255                                                          },
+  { EL_BD_SLIME,               &level.bd_slime_random_seed_c64,        TEXT_RANDOM_SEED,
+                               -1, 65535                                                       },
   { EL_EXTRA_TIME,             &level.extra_time,                      TEXT_TIME_BONUS         },
   { EL_TIME_ORB_FULL,          &level.time_orb_time,                   TEXT_TIME_BONUS         },
-  { EL_GAME_OF_LIFE,           &level.game_of_life[0],                 TEXT_GAME_OF_LIFE_1     },
-  { EL_GAME_OF_LIFE,           &level.game_of_life[1],                 TEXT_GAME_OF_LIFE_2     },
-  { EL_GAME_OF_LIFE,           &level.game_of_life[2],                 TEXT_GAME_OF_LIFE_3     },
-  { EL_GAME_OF_LIFE,           &level.game_of_life[3],                 TEXT_GAME_OF_LIFE_4     },
-  { EL_BIOMAZE,                        &level.biomaze[0],                      TEXT_GAME_OF_LIFE_1     },
-  { EL_BIOMAZE,                        &level.biomaze[1],                      TEXT_GAME_OF_LIFE_2     },
-  { EL_BIOMAZE,                        &level.biomaze[2],                      TEXT_GAME_OF_LIFE_3     },
-  { EL_BIOMAZE,                        &level.biomaze[3],                      TEXT_GAME_OF_LIFE_4     },
+  { EL_GAME_OF_LIFE,           &level.game_of_life[0],                 TEXT_GAME_OF_LIFE_1,0,8 },
+  { EL_GAME_OF_LIFE,           &level.game_of_life[1],                 TEXT_GAME_OF_LIFE_2,0,8 },
+  { EL_GAME_OF_LIFE,           &level.game_of_life[2],                 TEXT_GAME_OF_LIFE_3,0,8 },
+  { EL_GAME_OF_LIFE,           &level.game_of_life[3],                 TEXT_GAME_OF_LIFE_4,0,8 },
+  { EL_BIOMAZE,                        &level.biomaze[0],                      TEXT_GAME_OF_LIFE_1,0,8 },
+  { EL_BIOMAZE,                        &level.biomaze[1],                      TEXT_GAME_OF_LIFE_2,0,8 },
+  { EL_BIOMAZE,                        &level.biomaze[2],                      TEXT_GAME_OF_LIFE_3,0,8 },
+  { EL_BIOMAZE,                        &level.biomaze[3],                      TEXT_GAME_OF_LIFE_4,0,8 },
   { EL_EMC_ANDROID,            &level.android_move_time,               TEXT_MOVE_SPEED         },
   { EL_EMC_ANDROID,            &level.android_clone_time,              TEXT_CLONE_SPEED        },
   { EL_EMC_MAGIC_BALL,         &level.ball_time,                       TEXT_BALL_DELAY         },
@@ -10953,7 +11035,8 @@ static boolean checkPropertiesConfig(int element)
       MAYBE_DONT_COLLIDE_WITH(element) ||
       element == EL_BD_ROCK ||
       element == EL_BD_MEGA_ROCK ||
-      element == EL_BD_SWEET)
+      element == EL_BD_SWEET ||
+      element == EL_BD_VOODOO_DOLL)
   {
     return TRUE;
   }
@@ -11037,8 +11120,7 @@ static void DrawPropertiesConfig(void)
     int xpos = ED_ELEMENT_SETTINGS_X(0);
     int ypos = ED_ELEMENT_SETTINGS_Y(0) + ED_GADGET_SMALL_DISTANCE;
 
-    PrintInfoText("No configuration options available.",
-                 FONT_TEXT_1, xpos, ypos);
+    PrintInfoText("No configuration options available.", FONT_TEXT_1, xpos, ypos);
 
     return;
   }
@@ -11046,71 +11128,58 @@ static void DrawPropertiesConfig(void)
   // check if there are elements where a value can be chosen for
   for (i = 0; elements_with_counter[i].element != -1; i++)
   {
-    if (elements_with_counter[i].element == properties_element)
-    {
-      // special case: score for extra diamonds only available in BD game engine
-      if (elements_with_counter[i].element == EL_BD_DIAMOND &&
-         elements_with_counter[i].value == &level.score[SC_DIAMOND_EXTRA] &&
-         level.game_engine_type != GAME_ENGINE_TYPE_BD)
-       continue;
+    if (elements_with_counter[i].element != properties_element)
+      continue;
 
-      // special case: some amoeba counters only available in BD game engine
-      if (elements_with_counter[i].element == EL_BD_AMOEBA &&
-         elements_with_counter[i].value != &level.amoeba_speed &&
-         level.game_engine_type != GAME_ENGINE_TYPE_BD)
-       continue;
+    // special case: score for extra diamonds only available in BD game engine
+    if (elements_with_counter[i].element == EL_BD_DIAMOND &&
+       elements_with_counter[i].value == &level.score[SC_DIAMOND_EXTRA] &&
+       level.game_engine_type != GAME_ENGINE_TYPE_BD)
+      continue;
 
-      // special case: some amoeba counters only available in R'n'D game engine
-      if (elements_with_counter[i].element == EL_BD_AMOEBA &&
-         elements_with_counter[i].value == &level.amoeba_speed &&
-         level.game_engine_type == GAME_ENGINE_TYPE_BD)
-       continue;
+    // special case: some amoeba counters only available in BD game engine
+    if (elements_with_counter[i].element == EL_BD_AMOEBA &&
+       elements_with_counter[i].value != &level.amoeba_speed &&
+       level.game_engine_type != GAME_ENGINE_TYPE_BD)
+      continue;
 
-      int counter_id = ED_COUNTER_ID_ELEMENT_VALUE1 + num_element_counters;
+    // special case: some amoeba counters only available in R'n'D game engine
+    if (elements_with_counter[i].element == EL_BD_AMOEBA &&
+       elements_with_counter[i].value == &level.amoeba_speed &&
+       level.game_engine_type == GAME_ENGINE_TYPE_BD)
+      continue;
 
-      counterbutton_info[counter_id].y =
-       ED_ELEMENT_SETTINGS_YPOS(
-               (HAS_EDITOR_CONTENT(properties_element)      ? 1 : 0) +
-               (CAN_GROW(properties_element)                ? 1 : 0) +
-               (COULD_MOVE_INTO_ACID(properties_element)    ? 1 : 0) +
-               (MAYBE_DONT_COLLIDE_WITH(properties_element) ? 1 : 0) +
-               (properties_element == EL_EMC_MAGIC_BALL     ? 2 : 0) +
-               num_element_counters);
+    int counter_id = ED_COUNTER_ID_ELEMENT_VALUE1 + num_element_counters;
 
-      // special case: set amoeba counters for BD game engine separately
-      if ((properties_element == EL_BD_AMOEBA && level.game_engine_type == GAME_ENGINE_TYPE_BD) ||
-         (properties_element == EL_BD_AMOEBA_2))
-       counterbutton_info[counter_id].y =
-         ED_ELEMENT_SETTINGS_YPOS(3 + num_element_counters);
+    counterbutton_info[counter_id].y =
+      ED_ELEMENT_SETTINGS_YPOS((HAS_EDITOR_CONTENT(properties_element)      ? 1 : 0) +
+                              (CAN_GROW(properties_element)                ? 1 : 0) +
+                              (COULD_MOVE_INTO_ACID(properties_element)    ? 1 : 0) +
+                              (MAYBE_DONT_COLLIDE_WITH(properties_element) ? 1 : 0) +
+                              (properties_element == EL_BD_VOODOO_DOLL     ? 4 : 0) +
+                              (properties_element == EL_BD_SLIME           ? 1 : 0) +
+                              (properties_element == EL_EMC_MAGIC_BALL     ? 2 : 0) +
+                              num_element_counters);
 
-      counterbutton_info[counter_id].value = elements_with_counter[i].value;
-      counterbutton_info[counter_id].text_right = elements_with_counter[i].text;
+    // special case: set amoeba counters for BD game engine separately
+    if ((properties_element == EL_BD_AMOEBA && level.game_engine_type == GAME_ENGINE_TYPE_BD) ||
+       (properties_element == EL_BD_AMOEBA_2))
+      counterbutton_info[counter_id].y = ED_ELEMENT_SETTINGS_YPOS(3 + num_element_counters);
 
-      if (properties_element == EL_GAME_OF_LIFE ||
-         properties_element == EL_BIOMAZE)
-      {
-       counterbutton_info[counter_id].min_value = 0;   // min neighbours
-       counterbutton_info[counter_id].max_value = 8;   // max neighbours
-      }
-      else if (strEqual(elements_with_counter[i].text, TEXT_AMOEBA_SLOW_RATE) ||
-              strEqual(elements_with_counter[i].text, TEXT_AMOEBA_FAST_RATE))
-      {
-       counterbutton_info[counter_id].min_value = 0;   // min percent
-       counterbutton_info[counter_id].max_value = 100; // max percent
-      }
-      else
-      {
-       // !!! CHANGE THIS FOR CERTAIN ELEMENTS !!!
-       counterbutton_info[counter_id].min_value = MIN_SCORE;
-       counterbutton_info[counter_id].max_value = MAX_SCORE;
-      }
+    counterbutton_info[counter_id].value      = elements_with_counter[i].value;
+    counterbutton_info[counter_id].text_right = elements_with_counter[i].text;
+    counterbutton_info[counter_id].min_value  = elements_with_counter[i].min_value;
+    counterbutton_info[counter_id].max_value  = elements_with_counter[i].max_value;
 
-      MapCounterButtons(counter_id);
+    // default: counter values between 0 and 999
+    if (counterbutton_info[counter_id].max_value == 0)
+      counterbutton_info[counter_id].max_value = 999;
 
-      num_element_counters++;
-      if (num_element_counters >= max_num_element_counters)
-       break;
-    }
+    MapCounterButtons(counter_id);
+
+    num_element_counters++;
+    if (num_element_counters >= max_num_element_counters)
+      break;
   }
 
   if (HAS_EDITOR_CONTENT(properties_element))
@@ -11255,6 +11324,9 @@ static void DrawPropertiesConfig(void)
     // draw counter gadgets
     MapCounterButtons(ED_COUNTER_ID_BD_PUSHING_PROB);
     MapCounterButtons(ED_COUNTER_ID_BD_PUSHING_PROB_WITH_SWEET);
+
+    // draw drawing area gadgets
+    MapDrawingArea(ED_DRAWING_ID_BD_SNAP_ELEMENT);
   }
 
   if (properties_element == EL_BD_ROCK && level.game_engine_type == GAME_ENGINE_TYPE_BD)
@@ -11280,6 +11352,19 @@ static void DrawPropertiesConfig(void)
     MapCheckbuttonGadget(ED_CHECKBUTTON_ID_BD_PUSH_MEGA_ROCK_WITH_SWEET);
   }
 
+  if (properties_element == EL_BD_VOODOO_DOLL)
+  {
+    MapCheckbuttonGadget(ED_CHECKBUTTON_ID_BD_VOODOO_COLLECTS_DIAMONDS);
+    MapCheckbuttonGadget(ED_CHECKBUTTON_ID_BD_VOODOO_HURT_KILLS_PLAYER);
+    MapCheckbuttonGadget(ED_CHECKBUTTON_ID_BD_VOODOO_DIES_BY_ROCK);
+    MapCheckbuttonGadget(ED_CHECKBUTTON_ID_BD_VOODOO_VANISH_BY_EXPLOSION);
+  }
+
+  if (properties_element == EL_BD_SLIME)
+  {
+    MapCheckbuttonGadget(ED_CHECKBUTTON_ID_BD_SLIME_IS_PREDICTABLE);
+  }
+
   if (properties_element == EL_BD_MAGIC_WALL)
   {
     MapCheckbuttonGadget(ED_CHECKBUTTON_ID_BD_MAGIC_WALL_WAIT_HATCHING);