fixed embarrassingly high number of x/y typos
[rocksndiamonds.git] / src / files.c
index 1f07c4894bd51a5e387e5aa62eb1042b902d8814..795aeda2befb595fc04508083404fd91e729275f 100644 (file)
@@ -1319,6 +1319,8 @@ filetype_id_list[] =
   { LEVEL_FILE_TYPE_DX,                "DX"    },
   { LEVEL_FILE_TYPE_SB,                "SB"    },
   { LEVEL_FILE_TYPE_DC,                "DC"    },
+  { LEVEL_FILE_TYPE_MM,                "MM"    },
+  { LEVEL_FILE_TYPE_MM,                "DF"    },
   { -1,                                NULL    },
 };
 
@@ -1604,6 +1606,7 @@ static void setLevelInfoToDefaults_Level(struct LevelInfo *level)
 
   level->native_em_level = &native_em_level;
   level->native_sp_level = &native_sp_level;
+  level->native_mm_level = &native_mm_level;
 
   level->file_version = FILE_VERSION_ACTUAL;
   level->game_version = GAME_VERSION_ACTUAL;
@@ -2119,6 +2122,16 @@ static void determineLevelFileInfo_Filename(struct LevelFileInfo *lfi)
     if (fileExists(lfi->filename))
       return;
   }
+  else if (leveldir_current->level_filetype != NULL)
+  {
+    int filetype = getFiletypeFromID(leveldir_current->level_filetype);
+
+    /* check for specified native level file with standard file name */
+    setLevelFileInfo_FormatLevelFilename(lfi, filetype,
+                                        "%03d.%s", nr, LEVELFILE_EXTENSION);
+    if (fileExists(lfi->filename))
+      return;
+  }
 
   /* check for native Rocks'n'Diamonds level file */
   setLevelFileInfo_FormatLevelFilename(lfi, LEVEL_FILE_TYPE_RND,
@@ -3664,7 +3677,8 @@ void CopyNativeLevel_SP_to_RND(struct LevelInfo *level)
 {
   struct LevelInfo_SP *level_sp = level->native_sp_level;
   LevelInfoType *header = &level_sp->header;
-  int i, x, y;
+  boolean num_invalid_elements = 0;
+  int i, j, x, y;
 
   level->fieldx = level_sp->width;
   level->fieldy = level_sp->height;
@@ -3677,20 +3691,39 @@ void CopyNativeLevel_SP_to_RND(struct LevelInfo *level)
       int element_new = getMappedElement(map_element_SP_to_RND(element_old));
 
       if (element_new == EL_UNKNOWN)
-       Error(ERR_WARN, "invalid element %d at position %d, %d",
+      {
+       num_invalid_elements++;
+
+       Error(ERR_DEBUG, "invalid element %d at position %d, %d",
              element_old, x, y);
+      }
 
       level->field[x][y] = element_new;
     }
   }
 
+  if (num_invalid_elements > 0)
+    Error(ERR_WARN, "found %d invalid elements%s", num_invalid_elements,
+         (!options.debug ? " (use '--debug' for more details)" : ""));
+
   for (i = 0; i < MAX_PLAYERS; i++)
     level->initial_player_gravity[i] =
       (header->InitialGravity == 1 ? TRUE : FALSE);
 
+  /* skip leading spaces */
   for (i = 0; i < SP_LEVEL_NAME_LEN; i++)
-    level->name[i] = header->LevelTitle[i];
-  level->name[SP_LEVEL_NAME_LEN] = '\0';
+    if (header->LevelTitle[i] != ' ')
+      break;
+
+  /* copy level title */
+  for (j = 0; i < SP_LEVEL_NAME_LEN; i++, j++)
+    level->name[j] = header->LevelTitle[i];
+  level->name[j] = '\0';
+
+  /* cut trailing spaces */
+  for (; j > 0; j--)
+    if (level->name[j - 1] == ' ' && level->name[j] == '\0')
+      level->name[j - 1] = '\0';
 
   level->gems_needed = header->InfotronsNeeded;
 
@@ -3820,8 +3853,8 @@ static void CopyNativeTape_SP_to_RND(struct LevelInfo *level)
 
   TapeSetDateFromEpochSeconds(getFileTimestampEpochSeconds(filename));
 
-  tape.length = 0;
-  tape.pos[tape.length].delay = 0;
+  tape.counter = 0;
+  tape.pos[tape.counter].delay = 0;
 
   for (i = 0; i < demo->length; i++)
   {
@@ -3829,41 +3862,91 @@ static void CopyNativeTape_SP_to_RND(struct LevelInfo *level)
     int demo_repeat = (demo->data[i] & 0xf0) >> 4;
     int tape_action = map_key_SP_to_RND(demo_action);
     int tape_repeat = demo_repeat + 1;
-    int tape_entries = 1;      // one new tape entry may be added
+    byte action[MAX_PLAYERS] = { tape_action, 0, 0, 0 };
+    boolean success = 0;
+    int j;
 
-    if (tape.length + tape_entries >= MAX_TAPE_LEN)
+    for (j = 0; j < tape_repeat; j++)
+      success = TapeAddAction(action);
+
+    if (!success)
     {
       Error(ERR_WARN, "SP demo truncated: size exceeds maximum tape size %d",
            MAX_TAPE_LEN);
 
       break;
     }
+  }
 
-    if (tape.pos[tape.length].delay > 0)       /* already stored action */
-    {
-      if (tape.pos[tape.length].action[0] != tape_action ||
-         tape.pos[tape.length].delay + tape_repeat >= 256)
-      {
-       tape.length++;
-       tape.pos[tape.length].delay = 0;
-      }
-      else
-      {
-       tape.pos[tape.length].delay += tape_repeat;
-      }
-    }
+  TapeHaltRecording();
+}
 
-    if (tape.pos[tape.length].delay == 0)      /* store new action */
-    {
-      tape.pos[tape.length].action[0] = tape_action;
-      tape.pos[tape.length].delay = tape_repeat;
-    }
-  }
 
-  tape.length++;
+/* ------------------------------------------------------------------------- */
+/* functions for loading MM level                                            */
+/* ------------------------------------------------------------------------- */
 
-  tape.length_frames  = GetTapeLengthFrames();
-  tape.length_seconds = GetTapeLengthSeconds();
+void CopyNativeLevel_RND_to_MM(struct LevelInfo *level)
+{
+  struct LevelInfo_MM *level_mm = level->native_mm_level;
+  int x, y;
+
+  level_mm->file_version = level->file_version;
+  level_mm->game_version = level->game_version;
+  level_mm->encoding_16bit_field = level->encoding_16bit_field;
+
+  level_mm->fieldx = MIN(level->fieldx, MM_MAX_PLAYFIELD_WIDTH);
+  level_mm->fieldy = MIN(level->fieldy, MM_MAX_PLAYFIELD_HEIGHT);
+
+  level_mm->time = level->time;
+  level_mm->kettles_needed = level->gems_needed;
+  level_mm->auto_count_kettles = FALSE;
+  level_mm->laser_red = FALSE;
+  level_mm->laser_green = FALSE;
+  level_mm->laser_blue = TRUE;
+
+  strcpy(level_mm->name, level->name);
+  strcpy(level_mm->author, level->author);
+
+  level_mm->score[SC_PACMAN]     = level->score[SC_PACMAN];
+  level_mm->score[SC_KEY]        = level->score[SC_PACMAN];
+  level_mm->score[SC_TIME_BONUS] = level->score[SC_TIME_BONUS];
+
+  level_mm->amoeba_speed = level->amoeba_speed;
+  level_mm->time_fuse = 0;
+
+  for (x = 0; x < level->fieldx; x++)
+    for (y = 0; y < level->fieldy; y++)
+      level_mm->field[x][y] = map_element_RND_to_MM(level->field[x][y]);
+}
+
+void CopyNativeLevel_MM_to_RND(struct LevelInfo *level)
+{
+  struct LevelInfo_MM *level_mm = level->native_mm_level;
+  int x, y;
+
+  level->file_version = level_mm->file_version;
+  level->game_version = level_mm->game_version;
+  level->encoding_16bit_field = level_mm->encoding_16bit_field;
+
+  level->fieldx = MIN(level_mm->fieldx, MAX_LEV_FIELDX);
+  level->fieldy = MIN(level_mm->fieldy, MAX_LEV_FIELDY);
+
+  level->time = level_mm->time;
+  level->gems_needed = level_mm->kettles_needed;
+
+  strcpy(level->name, level_mm->name);
+  strcpy(level->author, level_mm->author);
+
+  level->score[SC_PACMAN]     = level_mm->score[SC_PACMAN];
+  level->score[SC_KEY]        = level_mm->score[SC_PACMAN];
+  level->score[SC_TIME_BONUS] = level_mm->score[SC_TIME_BONUS];
+
+  level->amoeba_speed = level_mm->amoeba_speed;
+
+  for (x = 0; x < level->fieldx; x++)
+    for (y = 0; y < level->fieldy; y++)
+      level->field[x][y] = map_element_MM_to_RND(level_mm->field[x][y]);
 }
 
 
@@ -5896,12 +5979,22 @@ static void LoadLevelFromFileInfo_SP(struct LevelInfo *level,
     level->no_valid_file = TRUE;
 }
 
+static void LoadLevelFromFileInfo_MM(struct LevelInfo *level,
+                                    struct LevelFileInfo *level_file_info,
+                                    boolean level_info_only)
+{
+  if (!LoadNativeLevel_MM(level_file_info->filename, level_info_only))
+    level->no_valid_file = TRUE;
+}
+
 void CopyNativeLevel_RND_to_Native(struct LevelInfo *level)
 {
   if (level->game_engine_type == GAME_ENGINE_TYPE_EM)
     CopyNativeLevel_RND_to_EM(level);
   else if (level->game_engine_type == GAME_ENGINE_TYPE_SP)
     CopyNativeLevel_RND_to_SP(level);
+  else if (level->game_engine_type == GAME_ENGINE_TYPE_MM)
+    CopyNativeLevel_RND_to_MM(level);
 }
 
 void CopyNativeLevel_Native_to_RND(struct LevelInfo *level)
@@ -5910,6 +6003,8 @@ void CopyNativeLevel_Native_to_RND(struct LevelInfo *level)
     CopyNativeLevel_EM_to_RND(level);
   else if (level->game_engine_type == GAME_ENGINE_TYPE_SP)
     CopyNativeLevel_SP_to_RND(level);
+  else if (level->game_engine_type == GAME_ENGINE_TYPE_MM)
+    CopyNativeLevel_MM_to_RND(level);
 }
 
 void SaveNativeLevel(struct LevelInfo *level)
@@ -5954,6 +6049,11 @@ static void LoadLevelFromFileInfo(struct LevelInfo *level,
       level->game_engine_type = GAME_ENGINE_TYPE_SP;
       break;
 
+    case LEVEL_FILE_TYPE_MM:
+      LoadLevelFromFileInfo_MM(level, level_file_info, level_info_only);
+      level->game_engine_type = GAME_ENGINE_TYPE_MM;
+      break;
+
     case LEVEL_FILE_TYPE_DC:
       LoadLevelFromFileInfo_DC(level, level_file_info, level_info_only);
       break;
@@ -8243,6 +8343,8 @@ static struct TokenInfo editor_cascade_setup_tokens[] =
   { TYPE_SWITCH, &seci.el_sp,          "editor.cascade.el_sp"          },
   { TYPE_SWITCH, &seci.el_dc,          "editor.cascade.el_dc"          },
   { TYPE_SWITCH, &seci.el_dx,          "editor.cascade.el_dx"          },
+  { TYPE_SWITCH, &seci.el_mm,          "editor.cascade.el_mm"          },
+  { TYPE_SWITCH, &seci.el_df,          "editor.cascade.el_df"          },
   { TYPE_SWITCH, &seci.el_chars,       "editor.cascade.el_chars"       },
   { TYPE_SWITCH, &seci.el_steel_chars, "editor.cascade.el_steel_chars" },
   { TYPE_SWITCH, &seci.el_ce,          "editor.cascade.el_ce"          },
@@ -8436,6 +8538,10 @@ static void setSetupInfoToDefaults(struct SetupInfo *si)
   si->editor.el_supaplex               = TRUE;
   si->editor.el_diamond_caves          = TRUE;
   si->editor.el_dx_boulderdash         = TRUE;
+
+  si->editor.el_mirror_magic           = TRUE;
+  si->editor.el_deflektor              = TRUE;
+
   si->editor.el_chars                  = TRUE;
   si->editor.el_steel_chars            = TRUE;
 
@@ -8571,6 +8677,9 @@ static void setSetupInfoToDefaults_EditorCascade(struct SetupInfo *si)
   si->editor_cascade.el_dc             = TRUE;
   si->editor_cascade.el_dx             = TRUE;
 
+  si->editor_cascade.el_mm             = TRUE;
+  si->editor_cascade.el_df             = TRUE;
+
   si->editor_cascade.el_chars          = FALSE;
   si->editor_cascade.el_steel_chars    = FALSE;
   si->editor_cascade.el_ce             = FALSE;