changed "http" to "https" in URLs
[rocksndiamonds.git] / src / files.c
index 04151ff10bbecb90ec2f92ad7e11fddf32dfaf8b..c07043450023b9650e5102c5d9a9cb45b4e29f55 100644 (file)
@@ -4,7 +4,7 @@
 // (c) 1995-2014 by Artsoft Entertainment
 //                         Holger Schemel
 //                 info@artsoft.org
-//                 http://www.artsoft.org/
+//                 https://www.artsoft.org/
 // ----------------------------------------------------------------------------
 // files.c
 // ============================================================================
@@ -768,9 +768,15 @@ static struct LevelFileConfigInfo chunk_config_ELEM[] =
     &li.android_clone_time,            10
   },
   {
-    EL_EMC_ANDROID,                    -1,
+    EL_EMC_ANDROID,                    SAVE_CONF_NEVER,
     TYPE_ELEMENT_LIST,                 CONF_VALUE_BYTES(1),
     &li.android_clone_element[0],      EL_EMPTY, NULL,
+    &li.num_android_clone_elements,    1, MAX_ANDROID_ELEMENTS_OLD
+  },
+  {
+    EL_EMC_ANDROID,                    -1,
+    TYPE_ELEMENT_LIST,                 CONF_VALUE_BYTES(2),
+    &li.android_clone_element[0],      EL_EMPTY, NULL,
     &li.num_android_clone_elements,    1, MAX_ANDROID_ELEMENTS
   },
 
@@ -809,7 +815,7 @@ static struct LevelFileConfigInfo chunk_config_ELEM[] =
   {
     EL_EMC_MAGIC_BALL,                 -1,
     TYPE_BOOLEAN,                      CONF_VALUE_8_BIT(2),
-    &li.ball_state_initial,            FALSE
+    &li.ball_active_initial,           FALSE
   },
   {
     EL_EMC_MAGIC_BALL,                 -1,
@@ -3515,14 +3521,14 @@ static void CopyNativeLevel_RND_to_EM(struct LevelInfo *level)
     { 2, 2 },
   };
   struct LevelInfo_EM *level_em = level->native_em_level;
-  struct LEVEL *cav = level_em->cav;
+  struct CAVE *cav = level_em->cav;
   int i, j, x, y;
 
   cav->width  = MIN(level->fieldx, MAX_PLAYFIELD_WIDTH);
   cav->height = MIN(level->fieldy, MAX_PLAYFIELD_HEIGHT);
 
-  cav->time_seconds     = level->time;
-  cav->required_initial = level->gems_needed;
+  cav->time_seconds    = level->time;
+  cav->gems_needed     = level->gems_needed;
 
   cav->emerald_score   = level->score[SC_EMERALD];
   cav->diamond_score   = level->score[SC_DIAMOND];
@@ -3535,20 +3541,22 @@ static void CopyNativeLevel_RND_to_EM(struct LevelInfo *level)
   cav->key_score       = level->score[SC_KEY];
   cav->exit_score      = level->score[SC_TIME_BONUS];
 
+  cav->num_eater_arrays        = level->num_yamyam_contents;
+
   for (i = 0; i < MAX_ELEMENT_CONTENTS; i++)
     for (y = 0; y < 3; y++)
       for (x = 0; x < 3; x++)
        cav->eater_array[i][y * 3 + x] =
-         map_element_RND_to_EM(level->yamyam_content[i].e[x][y]);
+         map_element_RND_to_EM_cave(level->yamyam_content[i].e[x][y]);
 
   cav->amoeba_time             = level->amoeba_speed;
-  cav->wonderwall_time_initial = level->time_magic_wall;
+  cav->wonderwall_time         = level->time_magic_wall;
   cav->wheel_time              = level->time_wheel;
 
   cav->android_move_time       = level->android_move_time;
   cav->android_clone_time      = level->android_clone_time;
   cav->ball_random             = level->ball_random;
-  cav->ball_state_initial      = level->ball_state_initial;
+  cav->ball_active             = level->ball_active_initial;
   cav->ball_time               = level->ball_time;
   cav->num_ball_arrays         = level->num_ball_contents;
 
@@ -3559,33 +3567,31 @@ static void CopyNativeLevel_RND_to_EM(struct LevelInfo *level)
   cav->lenses_time             = level->lenses_time;
   cav->magnify_time            = level->magnify_time;
 
-  cav->wind_direction_initial =
+  cav->wind_direction =
     map_direction_RND_to_EM(level->wind_direction_initial);
-  cav->wind_cnt_initial = (level->wind_direction_initial != MV_NONE ?
-                          cav->wind_time : 0);
 
   for (i = 0; i < MAX_ELEMENT_CONTENTS; i++)
     for (j = 0; j < 8; j++)
       cav->ball_array[i][j] =
-       map_element_RND_to_EM(level->
-                             ball_content[i].e[ball_xy[j][0]][ball_xy[j][1]]);
+       map_element_RND_to_EM_cave(level->ball_content[i].
+                                  e[ball_xy[j][0]][ball_xy[j][1]]);
 
   map_android_clone_elements_RND_to_EM(level);
 
-  // first fill the complete playfield with the default border element
+  // first fill the complete playfield with the empty space element
   for (y = 0; y < EM_MAX_CAVE_HEIGHT; y++)
     for (x = 0; x < EM_MAX_CAVE_WIDTH; x++)
-      cav->cave_raw[x][y] = Zborder;
+      cav->cave[x][y] = Cblank;
 
   // then copy the real level contents from level file into the playfield
   for (y = 0; y < cav->height; y++) for (x = 0; x < cav->width; x++)
   {
-    int new_element = map_element_RND_to_EM(level->field[x][y]);
+    int new_element = map_element_RND_to_EM_cave(level->field[x][y]);
 
     if (level->field[x][y] == EL_AMOEBA_DEAD)
-      new_element = map_element_RND_to_EM(EL_AMOEBA_WET);
+      new_element = map_element_RND_to_EM_cave(EL_AMOEBA_WET);
 
-    cav->cave_raw[x][y] = new_element;
+    cav->cave[x][y] = new_element;
   }
 
   for (i = 0; i < MAX_PLAYERS; i++)
@@ -3604,7 +3610,7 @@ static void CopyNativeLevel_RND_to_EM(struct LevelInfo *level)
       cav->player_x[player_nr] = x;
       cav->player_y[player_nr] = y;
 
-      cav->cave_raw[x][y] = map_element_RND_to_EM(EL_EMPTY);
+      cav->cave[x][y] = map_element_RND_to_EM_cave(EL_EMPTY);
     }
   }
 }
@@ -3623,14 +3629,14 @@ static void CopyNativeLevel_EM_to_RND(struct LevelInfo *level)
     { 2, 2 },
   };
   struct LevelInfo_EM *level_em = level->native_em_level;
-  struct LEVEL *cav = level_em->cav;
+  struct CAVE *cav = level_em->cav;
   int i, j, x, y;
 
   level->fieldx = MIN(cav->width,  MAX_LEV_FIELDX);
   level->fieldy = MIN(cav->height, MAX_LEV_FIELDY);
 
   level->time        = cav->time_seconds;
-  level->gems_needed = cav->required_initial;
+  level->gems_needed = cav->gems_needed;
 
   sprintf(level->name, "Level %d", level->file_info.nr);
 
@@ -3645,22 +3651,22 @@ static void CopyNativeLevel_EM_to_RND(struct LevelInfo *level)
   level->score[SC_KEY]         = cav->key_score;
   level->score[SC_TIME_BONUS]  = cav->exit_score;
 
-  level->num_yamyam_contents = MAX_ELEMENT_CONTENTS;
+  level->num_yamyam_contents   = cav->num_eater_arrays;
 
-  for (i = 0; i < level->num_yamyam_contents; i++)
+  for (i = 0; i < MAX_ELEMENT_CONTENTS; i++)
     for (y = 0; y < 3; y++)
       for (x = 0; x < 3; x++)
        level->yamyam_content[i].e[x][y] =
-         map_element_EM_to_RND(cav->eater_array[i][y * 3 + x]);
+         map_element_EM_to_RND_cave(cav->eater_array[i][y * 3 + x]);
 
   level->amoeba_speed          = cav->amoeba_time;
-  level->time_magic_wall       = cav->wonderwall_time_initial;
+  level->time_magic_wall       = cav->wonderwall_time;
   level->time_wheel            = cav->wheel_time;
 
   level->android_move_time     = cav->android_move_time;
   level->android_clone_time    = cav->android_clone_time;
   level->ball_random           = cav->ball_random;
-  level->ball_state_initial    = cav->ball_state_initial;
+  level->ball_active_initial   = cav->ball_active;
   level->ball_time             = cav->ball_time;
   level->num_ball_contents     = cav->num_ball_arrays;
 
@@ -3672,19 +3678,19 @@ static void CopyNativeLevel_EM_to_RND(struct LevelInfo *level)
   level->magnify_time          = cav->magnify_time;
 
   level->wind_direction_initial =
-    map_direction_EM_to_RND(cav->wind_direction_initial);
+    map_direction_EM_to_RND(cav->wind_direction);
 
   for (i = 0; i < MAX_ELEMENT_CONTENTS; i++)
     for (j = 0; j < 8; j++)
       level->ball_content[i].e[ball_xy[j][0]][ball_xy[j][1]] =
-       map_element_EM_to_RND(cav->ball_array[i][j]);
+       map_element_EM_to_RND_cave(cav->ball_array[i][j]);
 
   map_android_clone_elements_EM_to_RND(level);
 
   // convert the playfield (some elements need special treatment)
   for (y = 0; y < level->fieldy; y++) for (x = 0; x < level->fieldx; x++)
   {
-    int new_element = map_element_EM_to_RND(cav->cave_raw[x][y]);
+    int new_element = map_element_EM_to_RND_cave(cav->cave[x][y]);
 
     if (new_element == EL_AMOEBA_WET && level->amoeba_speed == 0)
       new_element = EL_AMOEBA_DEAD;
@@ -3982,7 +3988,7 @@ 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;
-    byte action[MAX_PLAYERS] = { tape_action, 0, 0, 0 };
+    byte action[MAX_TAPE_ACTIONS] = { tape_action };
     boolean success = 0;
     int j;
 
@@ -6788,8 +6794,8 @@ static int SaveLevel_BODY(FILE *file, struct LevelInfo *level)
   int chunk_size = 0;
   int x, y;
 
-  for (y = 0; y < level->fieldy; y++) 
-    for (x = 0; x < level->fieldx; x++) 
+  for (y = 0; y < level->fieldy; y++)
+    for (x = 0; x < level->fieldx; x++)
       if (level->encoding_16bit_field)
        chunk_size += putFile16BitBE(file, level->field[x][y]);
       else
@@ -7615,6 +7621,42 @@ static void setTapeInfoToDefaults(void)
   tape.no_valid_file = FALSE;
 }
 
+static int getTapePosSize(struct TapeInfo *tape)
+{
+  int tape_pos_size = 0;
+
+  if (tape->use_key_actions)
+    tape_pos_size += tape->num_participating_players;
+
+  if (tape->use_mouse_actions)
+    tape_pos_size += 3;                // x and y position and mouse button mask
+
+  tape_pos_size += 1;          // tape action delay value
+
+  return tape_pos_size;
+}
+
+static void setTapeActionFlags(struct TapeInfo *tape, int value)
+{
+  tape->use_key_actions = FALSE;
+  tape->use_mouse_actions = FALSE;
+
+  if (value != TAPE_USE_MOUSE_ACTIONS_ONLY)
+    tape->use_key_actions = TRUE;
+
+  if (value != TAPE_USE_KEY_ACTIONS_ONLY)
+    tape->use_mouse_actions = TRUE;
+}
+
+static int getTapeActionValue(struct TapeInfo *tape)
+{
+  return (tape->use_key_actions &&
+         tape->use_mouse_actions ? TAPE_USE_KEY_AND_MOUSE_ACTIONS :
+         tape->use_key_actions   ? TAPE_USE_KEY_ACTIONS_ONLY :
+         tape->use_mouse_actions ? TAPE_USE_MOUSE_ACTIONS_ONLY :
+         TAPE_ACTIONS_DEFAULT);
+}
+
 static int LoadTape_VERS(File *file, int chunk_size, struct TapeInfo *tape)
 {
   tape->file_version = getFileVersion(file);
@@ -7650,7 +7692,7 @@ static int LoadTape_HEAD(File *file, int chunk_size, struct TapeInfo *tape)
       }
     }
 
-    tape->use_mouse = (getFile8Bit(file) == 1 ? TRUE : FALSE);
+    setTapeActionFlags(tape, getFile8Bit(file));
 
     ReadUnusedBytesFromFile(file, TAPE_CHUNK_HEAD_UNUSED);
 
@@ -7687,8 +7729,7 @@ static int LoadTape_INFO(File *file, int chunk_size, struct TapeInfo *tape)
 static int LoadTape_BODY(File *file, int chunk_size, struct TapeInfo *tape)
 {
   int i, j;
-  int tape_pos_size =
-    (tape->use_mouse ? 3 : tape->num_participating_players) + 1;
+  int tape_pos_size = getTapePosSize(tape);
   int chunk_size_expected = tape_pos_size * tape->length;
 
   if (chunk_size_expected != chunk_size)
@@ -7706,20 +7747,12 @@ static int LoadTape_BODY(File *file, int chunk_size, struct TapeInfo *tape)
 
       // tape too large; read and ignore remaining tape data from this chunk
       for (;i < tape->length; i++)
-       ReadUnusedBytesFromFile(file, tape->num_participating_players + 1);
+       ReadUnusedBytesFromFile(file, tape_pos_size);
 
       break;
     }
 
-    if (tape->use_mouse)
-    {
-      tape->pos[i].action[TAPE_ACTION_LX]     = getFile8Bit(file);
-      tape->pos[i].action[TAPE_ACTION_LY]     = getFile8Bit(file);
-      tape->pos[i].action[TAPE_ACTION_BUTTON] = getFile8Bit(file);
-
-      tape->pos[i].action[TAPE_ACTION_UNUSED] = 0;
-    }
-    else
+    if (tape->use_key_actions)
     {
       for (j = 0; j < MAX_PLAYERS; j++)
       {
@@ -7730,6 +7763,13 @@ static int LoadTape_BODY(File *file, int chunk_size, struct TapeInfo *tape)
       }
     }
 
+    if (tape->use_mouse_actions)
+    {
+      tape->pos[i].action[TAPE_ACTION_LX]     = getFile8Bit(file);
+      tape->pos[i].action[TAPE_ACTION_LY]     = getFile8Bit(file);
+      tape->pos[i].action[TAPE_ACTION_BUTTON] = getFile8Bit(file);
+    }
+
     tape->pos[i].delay = getFile8Bit(file);
 
     if (tape->file_version == FILE_VERSION_1_0)
@@ -8053,7 +8093,7 @@ static void SaveTape_HEAD(FILE *file, struct TapeInfo *tape)
 
   putFile8Bit(file, store_participating_players);
 
-  putFile8Bit(file, (tape->use_mouse ? 1 : 0));
+  putFile8Bit(file, getTapeActionValue(tape));
 
   // unused bytes not at the end here for 4-byte alignment of engine_version
   WriteUnusedBytesToFile(file, TAPE_CHUNK_HEAD_UNUSED);
@@ -8080,19 +8120,20 @@ static void SaveTape_BODY(FILE *file, struct TapeInfo *tape)
 
   for (i = 0; i < tape->length; i++)
   {
-    if (tape->use_mouse)
-    {
-      putFile8Bit(file, tape->pos[i].action[TAPE_ACTION_LX]);
-      putFile8Bit(file, tape->pos[i].action[TAPE_ACTION_LY]);
-      putFile8Bit(file, tape->pos[i].action[TAPE_ACTION_BUTTON]);
-    }
-    else
+    if (tape->use_key_actions)
     {
       for (j = 0; j < MAX_PLAYERS; j++)
        if (tape->player_participates[j])
          putFile8Bit(file, tape->pos[i].action[j]);
     }
 
+    if (tape->use_mouse_actions)
+    {
+      putFile8Bit(file, tape->pos[i].action[TAPE_ACTION_LX]);
+      putFile8Bit(file, tape->pos[i].action[TAPE_ACTION_LY]);
+      putFile8Bit(file, tape->pos[i].action[TAPE_ACTION_BUTTON]);
+    }
+
     putFile8Bit(file, tape->pos[i].delay);
   }
 }
@@ -8101,7 +8142,6 @@ void SaveTape(int nr)
 {
   char *filename = getTapeFilename(nr);
   FILE *file;
-  int num_participating_players = 0;
   int tape_pos_size;
   int info_chunk_size;
   int body_chunk_size;
@@ -8118,12 +8158,14 @@ void SaveTape(int nr)
   tape.file_version = FILE_VERSION_ACTUAL;
   tape.game_version = GAME_VERSION_ACTUAL;
 
+  tape.num_participating_players = 0;
+
   // count number of participating players
   for (i = 0; i < MAX_PLAYERS; i++)
     if (tape.player_participates[i])
-      num_participating_players++;
+      tape.num_participating_players++;
 
-  tape_pos_size = (tape.use_mouse ? 3 : num_participating_players) + 1;
+  tape_pos_size = getTapePosSize(&tape);
 
   info_chunk_size = 2 + (strlen(tape.level_identifier) + 1) + 2;
   body_chunk_size = tape_pos_size * tape.length;
@@ -8361,6 +8403,10 @@ static struct TokenInfo global_setup_tokens[] =
     TYPE_SWITCH,
     &setup.scroll_delay,                       "scroll_delay"
   },
+  {
+    TYPE_SWITCH,
+    &setup.forced_scroll_delay,                        "forced_scroll_delay"
+  },
   {
     TYPE_INTEGER,
     &setup.scroll_delay_value,                 "scroll_delay_value"
@@ -8461,6 +8507,10 @@ static struct TokenInfo global_setup_tokens[] =
     TYPE_SWITCH,
     &setup.prefer_aga_graphics,                        "prefer_aga_graphics"
   },
+  {
+    TYPE_SWITCH,
+    &setup.prefer_lowpass_sounds,              "prefer_lowpass_sounds"
+  },
   {
     TYPE_SWITCH,
     &setup.game_speed_extended,                        "game_speed_extended"
@@ -9106,6 +9156,7 @@ static void setSetupInfoToDefaults(struct SetupInfo *si)
   si->sound_simple = TRUE;
   si->toons = TRUE;
   si->scroll_delay = TRUE;
+  si->forced_scroll_delay = FALSE;
   si->scroll_delay_value = STD_SCROLL_DELAY;
   si->engine_snapshot_mode = getStringCopy(STR_SNAPSHOT_MODE_DEFAULT);
   si->engine_snapshot_memory = SNAPSHOT_MEMORY_DEFAULT;
@@ -9131,6 +9182,7 @@ static void setSetupInfoToDefaults(struct SetupInfo *si)
   si->quick_switch = FALSE;
   si->input_on_focus = FALSE;
   si->prefer_aga_graphics = TRUE;
+  si->prefer_lowpass_sounds = FALSE;
   si->game_speed_extended = FALSE;
   si->game_frame_delay = GAME_FRAME_DELAY;
   si->sp_show_border_elements = FALSE;
@@ -10300,6 +10352,9 @@ int get_parameter_value(char *value_raw, char *suffix, int type)
     if (string_has_parameter(value, "reverse"))
       result |= STYLE_REVERSE;
 
+    if (string_has_parameter(value, "block_clicks"))
+      result |= STYLE_BLOCK;
+
     if (string_has_parameter(value, "passthrough_clicks"))
       result |= STYLE_PASSTHROUGH;