rnd-20100107-2-src
[rocksndiamonds.git] / src / files.c
index 80037699fc8ae90aacadcca7c13d8fc04d1cb747..a969861edebc5eca093742203a1ef693fedf7e52 100644 (file)
@@ -1959,9 +1959,33 @@ static void determineLevelFileInfo_Filename(struct LevelFileInfo *lfi)
   /* special case: level number is negative => check for level template file */
   if (nr < 0)
   {
+#if 1
+    /* global variable "leveldir_current" must be modified in the loop below */
+    LevelDirTree *leveldir_current_last = leveldir_current;
+
+    /* check for template level in path from current to topmost tree node */
+
+    while (leveldir_current != NULL)
+    {
+      setLevelFileInfo_FormatLevelFilename(lfi, LEVEL_FILE_TYPE_RND,
+                                          "template.%s", LEVELFILE_EXTENSION);
+
+      if (fileExists(lfi->filename))
+       break;
+
+      leveldir_current = leveldir_current->node_parent;
+    }
+
+    /* restore global variable "leveldir_current" modified in above loop */
+    leveldir_current = leveldir_current_last;
+
+#else
+
     setLevelFileInfo_FormatLevelFilename(lfi, LEVEL_FILE_TYPE_RND,
                                         "template.%s", LEVELFILE_EXTENSION);
 
+#endif
+
     /* no fallback if template file not existing */
     return;
   }
@@ -3042,8 +3066,12 @@ static void LoadLevelFromFileInfo_RND(struct LevelInfo *level,
   {
     level->no_valid_file = TRUE;
 
+#if 1
+    Error(ERR_WARN, "cannot read level '%s' -- using empty level", filename);
+#else
     if (level != &level_template)
       Error(ERR_WARN, "cannot read level '%s' -- using empty level", filename);
+#endif
 
     return;
   }
@@ -4184,7 +4212,7 @@ void CopyNativeLevel_RND_to_SP(struct LevelInfo *level)
   LevelInfoType *header = &level_sp->header;
   int i, x, y;
 
-  level_sp->width = level->fieldx;
+  level_sp->width  = level->fieldx;
   level_sp->height = level->fieldy;
 
   for (x = 0; x < level->fieldx; x++)
@@ -4216,7 +4244,67 @@ void CopyNativeLevel_RND_to_SP(struct LevelInfo *level)
 
   header->InfotronsNeeded = level->gems_needed;
 
-  /* !!! ADD SPECIAL PORT DATABASE STUFF !!! */
+  header->SpecialPortCount = 0;
+
+  for (x = 0; x < level->fieldx; x++) for (y = 0; y < level->fieldy; y++)
+  {
+    boolean gravity_port_found = FALSE;
+    boolean gravity_port_valid = FALSE;
+    int gravity_port_flag;
+    int gravity_port_base_element;
+    int element = level->field[x][y];
+
+    if (element >= EL_SP_GRAVITY_ON_PORT_RIGHT &&
+       element <= EL_SP_GRAVITY_ON_PORT_UP)
+    {
+      gravity_port_found = TRUE;
+      gravity_port_valid = TRUE;
+      gravity_port_flag = 1;
+      gravity_port_base_element = EL_SP_GRAVITY_ON_PORT_RIGHT;
+    }
+    else if (element >= EL_SP_GRAVITY_OFF_PORT_RIGHT &&
+            element <= EL_SP_GRAVITY_OFF_PORT_UP)
+    {
+      gravity_port_found = TRUE;
+      gravity_port_valid = TRUE;
+      gravity_port_flag = 0;
+      gravity_port_base_element = EL_SP_GRAVITY_OFF_PORT_RIGHT;
+    }
+    else if (element >= EL_SP_GRAVITY_PORT_RIGHT &&
+            element <= EL_SP_GRAVITY_PORT_UP)
+    {
+      /* change R'n'D style gravity inverting special port to normal port
+        (there are no gravity inverting ports in native Supaplex engine) */
+
+      gravity_port_found = TRUE;
+      gravity_port_valid = FALSE;
+      gravity_port_base_element = EL_SP_GRAVITY_PORT_RIGHT;
+    }
+
+    if (gravity_port_found)
+    {
+      if (gravity_port_valid &&
+         header->SpecialPortCount < SP_MAX_SPECIAL_PORTS)
+      {
+       SpecialPortType *port = &header->SpecialPort[header->SpecialPortCount];
+
+       port->PortLocation = (y * level->fieldx + x) * 2;
+       port->Gravity = gravity_port_flag;
+
+       element += EL_SP_GRAVITY_PORT_RIGHT - gravity_port_base_element;
+
+       header->SpecialPortCount++;
+      }
+      else
+      {
+       /* change special gravity port to normal port */
+
+       element += EL_SP_PORT_RIGHT - gravity_port_base_element;
+      }
+
+      level_sp->playfield[x][y] = element - EL_SP_START;
+    }
+  }
 }
 
 void CopyNativeLevel_SP_to_RND(struct LevelInfo *level)
@@ -6331,6 +6419,40 @@ static void LoadLevelFromFileInfo_DC(struct LevelInfo *level,
 /* functions for loading SB level                                            */
 /* ------------------------------------------------------------------------- */
 
+#if 1
+
+static boolean check_special_flags(char *flag)
+{
+#if 0
+  printf("::: '%s', '%s', '%s'\n",
+        flag,
+        options.special_flags,
+        leveldir_current->special_flags);
+#endif
+
+  if (strEqual(options.special_flags, flag) ||
+      strEqual(leveldir_current->special_flags, flag))
+    return TRUE;
+
+  return FALSE;
+}
+
+#else
+
+#define SPECIAL_FLAG_LOAD_XSB_TO_CES   (1 << 0)
+
+static unsigned long get_special_flags(char *flags_string)
+{
+  unsigned long flags_value = 0;
+
+  if (strEqual(flags_string, "load_xsb_to_ces"))
+    flags_value = SPECIAL_FLAG_LOAD_XSB_TO_CES;
+
+  return flags_value;
+}
+
+#endif
+
 int getMappedElement_SB(int element_ascii, boolean use_ces)
 {
   static struct
@@ -6376,7 +6498,11 @@ static void LoadLevelFromFileInfo_SB(struct LevelInfo *level,
   boolean reading_playfield = FALSE;
   boolean got_valid_playfield_line = FALSE;
   boolean invalid_playfield_char = FALSE;
-  boolean load_xsb_to_ces = options.cmd_switches & CMD_SWITCH_LOAD_XSB_TO_CES;
+#if 1
+  boolean load_xsb_to_ces = check_special_flags("load_xsb_to_ces");
+#else
+  boolean load_xsb_to_ces = options.special_flags & SPECIAL_FLAG_LOAD_XSB_TO_CES;
+#endif
   int file_level_nr = 0;
   int line_nr = 0;
   int x, y;
@@ -6621,13 +6747,41 @@ static void LoadLevelFromFileInfo_SB(struct LevelInfo *level,
                     level->field, level->fieldx, level->fieldy);
   }
 
+  /* set special level settings for Sokoban levels */
+
+  level->time = 0;
+  level->use_step_counter = TRUE;
+
   if (load_xsb_to_ces)
   {
-    level->time = 0;
-    level->use_step_counter = TRUE;
-
     level->initial_player_stepsize[0] = STEPSIZE_SLOW;
 
+    /* fill smaller playfields with padding "beyond border wall" elements */
+    if (level->fieldx < SCR_FIELDX ||
+       level->fieldy < SCR_FIELDY)
+    {
+      short field[level->fieldx][level->fieldy];
+      int new_fieldx = MAX(level->fieldx, SCR_FIELDX);
+      int new_fieldy = MAX(level->fieldy, SCR_FIELDY);
+      int pos_fieldx = (new_fieldx - level->fieldx) / 2;
+      int pos_fieldy = (new_fieldy - level->fieldy) / 2;
+
+      /* copy old playfield (which is smaller than the visible area) */
+      for (y = 0; y < level->fieldy; y++) for (x = 0; x < level->fieldx; x++)
+       field[x][y] = level->field[x][y];
+
+      /* fill new, larger playfield with "beyond border wall" elements */
+      for (y = 0; y < new_fieldy; y++) for (x = 0; x < new_fieldx; x++)
+       level->field[x][y] = getMappedElement_SB('_', load_xsb_to_ces);
+
+      /* copy the old playfield to the middle of the new playfield */
+      for (y = 0; y < level->fieldy; y++) for (x = 0; x < level->fieldx; x++)
+       level->field[pos_fieldx + x][pos_fieldy + y] = field[x][y];
+
+      level->fieldx = new_fieldx;
+      level->fieldy = new_fieldy;
+    }
+
     level->use_custom_template = TRUE;
   }
 }