added step delay option to custom element movement configuration
[rocksndiamonds.git] / src / editor.c
index acd199d5f243ad147ef52a58d3b69dd523ec551f..24590595e96d645f563ad4ee6e9c9fa375feed44 100644 (file)
@@ -489,6 +489,12 @@ enum
   GADGET_ID_MOVE_DELAY_RND_DOWN,
   GADGET_ID_MOVE_DELAY_RND_TEXT,
   GADGET_ID_MOVE_DELAY_RND_UP,
+  GADGET_ID_STEP_DELAY_FIX_DOWN,
+  GADGET_ID_STEP_DELAY_FIX_TEXT,
+  GADGET_ID_STEP_DELAY_FIX_UP,
+  GADGET_ID_STEP_DELAY_RND_DOWN,
+  GADGET_ID_STEP_DELAY_RND_TEXT,
+  GADGET_ID_STEP_DELAY_RND_UP,
   GADGET_ID_EXPLOSION_DELAY_DOWN,
   GADGET_ID_EXPLOSION_DELAY_TEXT,
   GADGET_ID_EXPLOSION_DELAY_UP,
@@ -559,6 +565,7 @@ enum
   // selectbox identifiers
 
   GADGET_ID_TIME_OR_STEPS,
+  GADGET_ID_TIME_SCORE_BASE,
   GADGET_ID_GAME_ENGINE_TYPE,
   GADGET_ID_LEVELSET_SAVE_MODE,
   GADGET_ID_WIND_DIRECTION,
@@ -648,6 +655,7 @@ enum
   GADGET_ID_SB_OBJECTS_NEEDED,
   GADGET_ID_AUTO_EXIT_SOKOBAN,
   GADGET_ID_SOLVED_BY_ONE_PLAYER,
+  GADGET_ID_FINISH_DIG_COLLECT,
   GADGET_ID_CONTINUOUS_SNAPPING,
   GADGET_ID_BLOCK_SNAP_FIELD,
   GADGET_ID_BLOCK_LAST_FIELD,
@@ -750,6 +758,8 @@ enum
   ED_COUNTER_ID_DROP_DELAY_RND,
   ED_COUNTER_ID_MOVE_DELAY_FIX,
   ED_COUNTER_ID_MOVE_DELAY_RND,
+  ED_COUNTER_ID_STEP_DELAY_FIX,
+  ED_COUNTER_ID_STEP_DELAY_RND,
   ED_COUNTER_ID_EXPLOSION_DELAY,
   ED_COUNTER_ID_IGNITION_DELAY,
   ED_COUNTER_ID_GROUP_CONTENT,
@@ -839,6 +849,7 @@ enum
 enum
 {
   ED_SELECTBOX_ID_TIME_OR_STEPS,
+  ED_SELECTBOX_ID_TIME_SCORE_BASE,
   ED_SELECTBOX_ID_GAME_ENGINE_TYPE,
   ED_SELECTBOX_ID_LEVELSET_SAVE_MODE,
   ED_SELECTBOX_ID_WIND_DIRECTION,
@@ -953,6 +964,7 @@ enum
   ED_CHECKBUTTON_ID_SB_OBJECTS_NEEDED,
   ED_CHECKBUTTON_ID_AUTO_EXIT_SOKOBAN,
   ED_CHECKBUTTON_ID_SOLVED_BY_ONE_PLAYER,
+  ED_CHECKBUTTON_ID_FINISH_DIG_COLLECT,
   ED_CHECKBUTTON_ID_CONTINUOUS_SNAPPING,
   ED_CHECKBUTTON_ID_BLOCK_SNAP_FIELD,
   ED_CHECKBUTTON_ID_BLOCK_LAST_FIELD,
@@ -1408,7 +1420,7 @@ static struct
     GADGET_ID_LEVEL_TIMESCORE_DOWN,    GADGET_ID_LEVEL_TIMESCORE_UP,
     GADGET_ID_LEVEL_TIMESCORE_TEXT,    GADGET_ID_NONE,
     &level.score[SC_TIME_BONUS],
-    "score for each second/step left:",        NULL, NULL
+    "score for time or steps left:",   NULL, NULL
   },
   {
     ED_LEVEL_SETTINGS_XPOS(0),         ED_LEVEL_SETTINGS_YPOS(12),
@@ -1604,7 +1616,23 @@ static struct
     NULL,                              "+random", NULL
   },
   {
-    ED_ELEMENT_SETTINGS_XPOS(1),       ED_ELEMENT_SETTINGS_YPOS(12),
+    ED_ELEMENT_SETTINGS_XPOS(1),       ED_ELEMENT_SETTINGS_YPOS(6),
+    0,                                 999,
+    GADGET_ID_STEP_DELAY_FIX_DOWN,     GADGET_ID_STEP_DELAY_FIX_UP,
+    GADGET_ID_STEP_DELAY_FIX_TEXT,     GADGET_ID_NONE,
+    &custom_element.step_delay_fixed,
+    NULL,                              "step delay", NULL
+  },
+  {
+    -1,                                        ED_ELEMENT_SETTINGS_YPOS(6),
+    0,                                 999,
+    GADGET_ID_STEP_DELAY_RND_DOWN,     GADGET_ID_STEP_DELAY_RND_UP,
+    GADGET_ID_STEP_DELAY_RND_TEXT,     GADGET_ID_STEP_DELAY_FIX_UP,
+    &custom_element.step_delay_random,
+    NULL,                              "+random", NULL
+  },
+  {
+    ED_ELEMENT_SETTINGS_XPOS(1),       ED_ELEMENT_SETTINGS_YPOS(13),
     0,                                 999,
     GADGET_ID_EXPLOSION_DELAY_DOWN,    GADGET_ID_EXPLOSION_DELAY_UP,
     GADGET_ID_EXPLOSION_DELAY_TEXT,    GADGET_ID_NONE,
@@ -1612,7 +1640,7 @@ static struct
     NULL,                              "explosion delay", NULL
   },
   {
-    ED_ELEMENT_SETTINGS_XPOS(1),       ED_ELEMENT_SETTINGS_YPOS(13),
+    ED_ELEMENT_SETTINGS_XPOS(1),       ED_ELEMENT_SETTINGS_YPOS(14),
     0,                                 999,
     GADGET_ID_IGNITION_DELAY_DOWN,     GADGET_ID_IGNITION_DELAY_UP,
     GADGET_ID_IGNITION_DELAY_TEXT,     GADGET_ID_NONE,
@@ -1731,6 +1759,14 @@ static struct ValueTextInfo options_time_or_steps[] =
   { -1,                                NULL                            }
 };
 
+static struct ValueTextInfo options_time_score_base[] =
+{
+  { 1,                         "per second/step"               },
+  { 10,                                "per 10 seconds/steps"          },
+
+  { -1,                                NULL                            }
+};
+
 static struct ValueTextInfo options_game_engine_type[] =
 {
   { GAME_ENGINE_TYPE_RND,      "Rocks'n'Diamonds"              },
@@ -2465,6 +2501,14 @@ static struct
     &level.use_step_counter,
     NULL, NULL, "(0 => no limit)",     "time or step limit"
   },
+  {
+    -1,                                        ED_LEVEL_SETTINGS_YPOS(10),
+    GADGET_ID_TIME_SCORE_BASE,         GADGET_ID_LEVEL_TIMESCORE_UP,
+    -1,
+    options_time_score_base,
+    &level.time_score_base,
+    NULL, NULL, NULL,                  "time score for 1 or 10 seconds/steps"
+  },
   {
     ED_LEVEL_SETTINGS_XPOS(0),         ED_LEVEL_SETTINGS_YPOS(11),
     GADGET_ID_GAME_ENGINE_TYPE,                GADGET_ID_NONE,
@@ -2582,7 +2626,7 @@ static struct
     NULL, "            can", ":",      "leave behind or change element"
   },
   {
-    -1,                                        ED_ELEMENT_SETTINGS_YPOS(7),
+    -1,                                        ED_ELEMENT_SETTINGS_YPOS(8),
     GADGET_ID_CUSTOM_SMASH_TARGETS,    GADGET_ID_CUSTOM_CAN_SMASH,
     -1,
     options_smash_targets,
@@ -2590,7 +2634,7 @@ static struct
     NULL, "can smash", NULL,           "elements that can be smashed"
   },
   {
-    ED_ELEMENT_SETTINGS_XPOS(1),       ED_ELEMENT_SETTINGS_YPOS(8),
+    ED_ELEMENT_SETTINGS_XPOS(1),       ED_ELEMENT_SETTINGS_YPOS(9),
     GADGET_ID_CUSTOM_SLIPPERY_TYPE,    GADGET_ID_NONE,
     -1,
     options_slippery_type,
@@ -2598,7 +2642,7 @@ static struct
     NULL, "slippery", NULL,            "where other elements fall down"
   },
   {
-    ED_ELEMENT_SETTINGS_XPOS(1),       ED_ELEMENT_SETTINGS_YPOS(9),
+    ED_ELEMENT_SETTINGS_XPOS(1),       ED_ELEMENT_SETTINGS_YPOS(10),
     GADGET_ID_CUSTOM_DEADLINESS,       GADGET_ID_NONE,
     -1,
     options_deadliness,
@@ -2606,7 +2650,7 @@ static struct
     NULL, "deadly when", NULL,         "deadliness of element"
   },
   {
-    ED_ELEMENT_SETTINGS_XPOS(1),       ED_ELEMENT_SETTINGS_YPOS(10),
+    ED_ELEMENT_SETTINGS_XPOS(1),       ED_ELEMENT_SETTINGS_YPOS(11),
     GADGET_ID_CUSTOM_EXPLOSION_TYPE,   GADGET_ID_NONE,
     -1,
     options_explosion_type,
@@ -3110,6 +3154,13 @@ static struct
     NULL, NULL,
     "only one player must enter exit", "level solved by first player in exit"
   },
+  {
+    ED_ELEMENT_SETTINGS_XPOS(0),       ED_ELEMENT_SETTINGS_YPOS(3),
+    GADGET_ID_FINISH_DIG_COLLECT,      GADGET_ID_NONE,
+    &level.finish_dig_collect,
+    NULL, NULL,
+    "CE action on finished dig/collect", "only finished dig/collect triggers CE"
+  },
   {
     ED_ELEMENT_SETTINGS_XPOS(0),       ED_ELEMENT_SETTINGS_YPOS(9),
     GADGET_ID_CONTINUOUS_SNAPPING,     GADGET_ID_NONE,
@@ -3341,56 +3392,56 @@ static struct
     NULL,                              "element can move with some pattern"
   },
   {
-    ED_ELEMENT_SETTINGS_XPOS(0),       ED_ELEMENT_SETTINGS_YPOS(7),
+    ED_ELEMENT_SETTINGS_XPOS(0),       ED_ELEMENT_SETTINGS_YPOS(8),
     GADGET_ID_CUSTOM_CAN_FALL,         GADGET_ID_NONE,
     &custom_element_properties[EP_CAN_FALL],
     NULL, NULL,
     "can fall",                                "element can fall down"
   },
   {
-    -1,                                        ED_ELEMENT_SETTINGS_YPOS(7),
+    -1,                                        ED_ELEMENT_SETTINGS_YPOS(8),
     GADGET_ID_CUSTOM_CAN_SMASH,                GADGET_ID_CUSTOM_CAN_FALL,
     &custom_element_properties[EP_CAN_SMASH],
     NULL, " ",
     NULL,                              "element can smash other elements"
   },
   {
-    ED_ELEMENT_SETTINGS_XPOS(0),       ED_ELEMENT_SETTINGS_YPOS(8),
+    ED_ELEMENT_SETTINGS_XPOS(0),       ED_ELEMENT_SETTINGS_YPOS(9),
     GADGET_ID_CUSTOM_SLIPPERY,         GADGET_ID_NONE,
     &custom_element_properties[EP_SLIPPERY],
     NULL, NULL,
     NULL,                              "other elements can fall down from it"
   },
   {
-    ED_ELEMENT_SETTINGS_XPOS(0),       ED_ELEMENT_SETTINGS_YPOS(9),
+    ED_ELEMENT_SETTINGS_XPOS(0),       ED_ELEMENT_SETTINGS_YPOS(10),
     GADGET_ID_CUSTOM_DEADLY,           GADGET_ID_NONE,
     &custom_element_properties[EP_DEADLY],
     NULL, NULL,
     NULL,                              "element can kill the player"
   },
   {
-    ED_ELEMENT_SETTINGS_XPOS(0),       ED_ELEMENT_SETTINGS_YPOS(10),
+    ED_ELEMENT_SETTINGS_XPOS(0),       ED_ELEMENT_SETTINGS_YPOS(11),
     GADGET_ID_CUSTOM_CAN_EXPLODE,      GADGET_ID_NONE,
     &custom_element_properties[EP_CAN_EXPLODE],
     NULL, NULL,
     NULL,                              "element can explode"
   },
   {
-    ED_ELEMENT_SETTINGS_XPOS(1),       ED_ELEMENT_SETTINGS_YPOS(11),
+    ED_ELEMENT_SETTINGS_XPOS(1),       ED_ELEMENT_SETTINGS_YPOS(12),
     GADGET_ID_CUSTOM_EXPLODE_FIRE,     GADGET_ID_NONE,
     &custom_element_properties[EP_EXPLODES_BY_FIRE],
     NULL, NULL,
     "by fire",                         "element can explode by fire/explosion"
   },
   {
-    -1,                                        ED_ELEMENT_SETTINGS_YPOS(11),
+    -1,                                        ED_ELEMENT_SETTINGS_YPOS(12),
     GADGET_ID_CUSTOM_EXPLODE_SMASH,    GADGET_ID_CUSTOM_EXPLODE_FIRE,
     &custom_element_properties[EP_EXPLODES_SMASHED],
     NULL, " ",
     "smashed",                         "element can explode when smashed"
   },
   {
-    -1,                                        ED_ELEMENT_SETTINGS_YPOS(11),
+    -1,                                        ED_ELEMENT_SETTINGS_YPOS(12),
     GADGET_ID_CUSTOM_EXPLODE_IMPACT,   GADGET_ID_CUSTOM_EXPLODE_SMASH,
     &custom_element_properties[EP_EXPLODES_IMPACT],
     NULL, " ",
@@ -3681,7 +3732,7 @@ static struct
   // ---------- custom content (when exploding) -------------------------------
 
   {
-    -1,                                        ED_AREA_3X3_SETTINGS_YPOS(10),
+    -1,                                        ED_AREA_3X3_SETTINGS_YPOS(11),
     0,                                 ED_AREA_3X3_SETTINGS_YOFF,
     GADGET_ID_CUSTOM_CONTENT,          GADGET_ID_NONE, // align three rows
     &custom_element.content.e[0][0],   3, 3,
@@ -7722,7 +7773,7 @@ static boolean PrepareSavingIntoPersonalLevelSet(void)
     return TRUE;
   }
 
-  if (!Request("This level is read only! "
+  if (!Request("This level is read-only! "
               "Save into personal level set?", REQ_ASK))
     return FALSE;
 
@@ -9983,6 +10034,7 @@ static void DrawPropertiesConfig(void)
 
       // draw checkbutton gadgets
       MapCheckbuttonGadget(ED_CHECKBUTTON_ID_USE_INITIAL_INVENTORY);
+      MapCheckbuttonGadget(ED_CHECKBUTTON_ID_FINISH_DIG_COLLECT);
 
       // draw counter gadgets
       MapCounterButtons(ED_COUNTER_ID_INVENTORY_SIZE);
@@ -10007,7 +10059,7 @@ static void DrawPropertiesConfig(void)
     checkbutton_info[ED_CHECKBUTTON_ID_CAN_MOVE_INTO_ACID].x =
       ED_ELEMENT_SETTINGS_XPOS(IS_CUSTOM_ELEMENT(properties_element) ? 1 : 0);
     checkbutton_info[ED_CHECKBUTTON_ID_CAN_MOVE_INTO_ACID].y =
-      ED_ELEMENT_SETTINGS_YPOS(IS_CUSTOM_ELEMENT(properties_element) ? 6 :
+      ED_ELEMENT_SETTINGS_YPOS(IS_CUSTOM_ELEMENT(properties_element) ? 7 :
                               IS_BALLOON_ELEMENT(properties_element) ||
                               HAS_EDITOR_CONTENT(properties_element) ? 1 : 0);
 
@@ -12734,6 +12786,43 @@ static void WrapLevel(int dx, int dy)
   CopyLevelToUndoBuffer(UNDO_ACCUMULATE);
 }
 
+static void DrawAreaElementHighlight(boolean highlighted)
+{
+  DrawEditorLevel(ed_fieldx, ed_fieldy, level_xpos, level_ypos);
+
+  if (!highlighted)
+    return;
+
+  int x, y;
+
+  for (x = 0; x < ed_fieldx; x++)
+  {
+    for (y = 0; y < ed_fieldy; y++)
+    {
+      int lx = x + level_xpos;
+      int ly = y + level_ypos;
+
+      if (!IN_LEV_FIELD(lx, ly))
+       continue;
+
+      if (Tile[lx][ly] != new_element1)
+       continue;
+
+      int sx = SX + x * ed_tilesize;
+      int sy = SY + y * ed_tilesize;
+      int from_sx = sx;
+      int from_sy = sy;
+      int to_sx = sx + ed_tilesize - 1;
+      int to_sy = sy + ed_tilesize - 1;
+
+      DrawSimpleWhiteLine(drawto, from_sx, from_sy, to_sx,   from_sy);
+      DrawSimpleWhiteLine(drawto, to_sx,   from_sy, to_sx,   to_sy);
+      DrawSimpleWhiteLine(drawto, to_sx,   to_sy,   from_sx, to_sy);
+      DrawSimpleWhiteLine(drawto, from_sx, to_sy,   from_sx, from_sy);
+    }
+  }
+}
+
 static void CopyLevelTemplateToUserLevelSet(char *levelset_subdir)
 {
   char *template_filename_old = getLocalLevelTemplateFilename();
@@ -13345,7 +13434,7 @@ static void HandleTextbuttonGadgets(struct GadgetInfo *gi)
     if (levelset_save_mode == LEVELSET_SAVE_MODE_UPDATE &&
        leveldir_current->readonly)
     {
-      Request("This level set is read only!", REQ_CONFIRM);
+      Request("This level set is read-only!", REQ_CONFIRM);
 
       return;
     }
@@ -13806,7 +13895,7 @@ static void HandleControlButtons(struct GadgetInfo *gi)
       }
       else
       {
-       ChangeEditModeWindow(last_edit_mode);
+       ChangeEditModeWindow(ED_MODE_DRAWING);
 
        ClickOnGadget(level_editor_gadget[last_level_drawing_function],
                      MB_LEFTBUTTON);
@@ -13971,7 +14060,7 @@ static void HandleControlButtons(struct GadgetInfo *gi)
       }
       else
       {
-       ChangeEditModeWindow(last_edit_mode);
+       ChangeEditModeWindow(ED_MODE_DRAWING);
       }
       break;
 
@@ -14308,7 +14397,7 @@ void HandleLevelEditorKeyInput(Key key)
          ClickOnGadget(level_editor_gadget[i], button);
 }
 
-void HandleLevelEditorIdle(void)
+static void HandleLevelEditorIdle_Properties(void)
 {
   int element_border = graphic_info[IMG_EDITOR_ELEMENT_BORDER].border_size;
   int x = editor.settings.element_graphic.x + element_border;
@@ -14317,9 +14406,6 @@ void HandleLevelEditorIdle(void)
   unsigned int action_delay_value = GameFrameDelay;
   int i;
 
-  if (edit_mode != ED_MODE_PROPERTIES)
-    return;
-
   if (!DelayReached(&action_delay, action_delay_value))
     return;
 
@@ -14338,6 +14424,29 @@ void HandleLevelEditorIdle(void)
   FrameCounter++;      // increase animation frame counter
 }
 
+static void HandleLevelEditorIdle_Drawing(void)
+{
+  static boolean last_highlighted = FALSE;
+  boolean highlighted = (GetKeyModState() & KMOD_Alt);
+
+  if (highlighted != last_highlighted)
+  {
+    DrawAreaElementHighlight(highlighted);
+
+    last_highlighted = highlighted;
+
+    redraw_mask |= REDRAW_FIELD;
+  }
+}
+
+void HandleLevelEditorIdle(void)
+{
+  if (edit_mode == ED_MODE_PROPERTIES)
+    HandleLevelEditorIdle_Properties();
+  else if (edit_mode == ED_MODE_DRAWING)
+    HandleLevelEditorIdle_Drawing();
+}
+
 static void ClearEditorGadgetInfoText(void)
 {
   DrawBackground(INFOTEXT_XPOS, INFOTEXT_YPOS, INFOTEXT_XSIZE, INFOTEXT_YSIZE);