Ejemplo n.º 1
0
void clear_board(struct board *cur_board)
{
  int i;
  int num_robots_active = cur_board->num_robots_active;
  int num_scrolls = cur_board->num_scrolls;
  int num_sensors = cur_board->num_sensors;
  struct robot **robot_list = cur_board->robot_list;
  struct robot **robot_name_list = cur_board->robot_list_name_sorted;
  struct robot *cur_robot;
  struct scroll **scroll_list = cur_board->scroll_list;
  struct sensor **sensor_list = cur_board->sensor_list;

  free(cur_board->level_id);
  free(cur_board->level_param);
  free(cur_board->level_color);
  free(cur_board->level_under_id);
  free(cur_board->level_under_param);
  free(cur_board->level_under_color);

  if(cur_board->overlay_mode)
  {
    free(cur_board->overlay);
    free(cur_board->overlay_color);
  }

  for(i = 0; i < num_robots_active; i++)
  {
    cur_robot = robot_name_list[i];
    clear_robot(cur_robot);
  }

  free(robot_name_list);
  free(robot_list);

  for(i = 1; i <= num_scrolls; i++)
    if(scroll_list[i])
      clear_scroll(scroll_list[i]);

  free(scroll_list);

  for(i = 1; i <= num_sensors; i++)
    if(sensor_list[i])
      clear_sensor(sensor_list[i]);

  free(sensor_list);
  free(cur_board);
}
Ejemplo n.º 2
0
__editor_maybe_static int load_board_direct(struct board *cur_board,
 FILE *fp, int data_size, int savegame, int version)
{
  int num_robots, num_scrolls, num_sensors, num_robots_active;
  int overlay_mode, size, board_width, board_height, i;
  int viewport_x, viewport_y, viewport_width, viewport_height;
  int truncated = 0;

  struct robot *cur_robot;
  struct scroll *cur_scroll;
  struct sensor *cur_sensor;

  char *test_buffer;

  int board_location = ftell(fp);

  cur_board->num_robots = 0;
  cur_board->num_robots_allocated = 0;
  cur_board->num_robots_active = 0;
  cur_board->num_scrolls = 0;
  cur_board->num_scrolls_allocated = 0;
  cur_board->num_sensors = 0;
  cur_board->num_sensors_allocated = 0;
  cur_board->robot_list = NULL;
  cur_board->robot_list_name_sorted = NULL;
  cur_board->sensor_list = NULL;
  cur_board->scroll_list = NULL;

  // Initialize some fields that may no longer be loaded
  // from the board file itself..

  cur_board->last_key = '?';
  cur_board->num_input = 0;
  cur_board->input_size = 0;
  cur_board->input_string[0] = 0;
  cur_board->player_last_dir = 0x10;
  cur_board->bottom_mesg[0] = 0;
  cur_board->b_mesg_timer = 0;
  cur_board->lazwall_start = 7;
  cur_board->b_mesg_row = 24;
  cur_board->b_mesg_col = -1;
  cur_board->scroll_x = 0;
  cur_board->scroll_y = 0;
  cur_board->locked_x = -1;
  cur_board->locked_y = -1;
  cur_board->volume = 255;
  cur_board->volume_inc = 0;
  cur_board->volume_target = 255;

  // board_mode, unused
  if(fgetc(fp) == EOF)
  {
    val_error(WORLD_BOARD_MISSING, board_location);
    return VAL_MISSING;
  }

  overlay_mode = fgetc(fp);

  if(!overlay_mode)
  {
    int overlay_width;
    int overlay_height;

    overlay_mode = fgetc(fp);
    overlay_width = fgetw(fp);
    overlay_height = fgetw(fp);

    size = overlay_width * overlay_height;

    if((size < 1) || (size > MAX_BOARD_SIZE))
      goto err_invalid;

    cur_board->overlay = cmalloc(size);
    cur_board->overlay_color = cmalloc(size);

    if(load_RLE2_plane(cur_board->overlay, fp, size))
      goto err_freeoverlay;

    test_buffer = cmalloc(1024);
    free(test_buffer);

    // Skip sizes
    if(fseek(fp, 4, SEEK_CUR) ||
     load_RLE2_plane(cur_board->overlay_color, fp, size))
      goto err_freeoverlay;

    test_buffer = cmalloc(1024);
    free(test_buffer);
  }
  else
  {
    overlay_mode = 0;
    // Undo that last get
    fseek(fp, -1, SEEK_CUR);
  }

  cur_board->overlay_mode = overlay_mode;

  board_width = fgetw(fp);
  board_height = fgetw(fp);
  cur_board->board_width = board_width;
  cur_board->board_height = board_height;

  size = board_width * board_height;

  if((size < 1) || (size > MAX_BOARD_SIZE))
    goto err_freeoverlay;

  cur_board->level_id = cmalloc(size);
  cur_board->level_color = cmalloc(size);
  cur_board->level_param = cmalloc(size);
  cur_board->level_under_id = cmalloc(size);
  cur_board->level_under_color = cmalloc(size);
  cur_board->level_under_param = cmalloc(size);

  if(load_RLE2_plane(cur_board->level_id, fp, size))
    goto err_freeboard;

  if(fseek(fp, 4, SEEK_CUR) ||
   load_RLE2_plane(cur_board->level_color, fp, size))
    goto err_freeboard;

  if(fseek(fp, 4, SEEK_CUR) ||
   load_RLE2_plane(cur_board->level_param, fp, size))
    goto err_freeboard;

  if(fseek(fp, 4, SEEK_CUR) ||
   load_RLE2_plane(cur_board->level_under_id, fp, size))
    goto err_freeboard;

  if(fseek(fp, 4, SEEK_CUR) ||
   load_RLE2_plane(cur_board->level_under_color, fp, size))
    goto err_freeboard;

  if(fseek(fp, 4, SEEK_CUR) ||
   load_RLE2_plane(cur_board->level_under_param, fp, size))
    goto err_freeboard;

  // Load board parameters

  if(version < 0x0253)
  {
    fread(cur_board->mod_playing, LEGACY_MOD_FILENAME_MAX, 1, fp);
    cur_board->mod_playing[LEGACY_MOD_FILENAME_MAX] = 0;
  }
  else
  {
    size_t len = fgetw(fp);
    if(len >= MAX_PATH)
      len = MAX_PATH - 1;

    fread(cur_board->mod_playing, len, 1, fp);
    cur_board->mod_playing[len] = 0;
  }

  viewport_x = fgetc(fp);
  viewport_y = fgetc(fp);
  viewport_width = fgetc(fp);
  viewport_height = fgetc(fp);

  if(
   (viewport_x < 0) || (viewport_x > 79) ||
   (viewport_y < 0) || (viewport_y > 24) ||
   (viewport_width < 1) || (viewport_width > 80) ||
   (viewport_height < 1) || (viewport_height > 25))
    goto err_invalid;

  cur_board->viewport_x = viewport_x;
  cur_board->viewport_y = viewport_y;
  cur_board->viewport_width = viewport_width;
  cur_board->viewport_height = viewport_height;
  cur_board->can_shoot = fgetc(fp);
  cur_board->can_bomb = fgetc(fp);
  cur_board->fire_burn_brown = fgetc(fp);
  cur_board->fire_burn_space = fgetc(fp);
  cur_board->fire_burn_fakes = fgetc(fp);
  cur_board->fire_burn_trees = fgetc(fp);
  cur_board->explosions_leave = fgetc(fp);
  cur_board->save_mode = fgetc(fp);
  cur_board->forest_becomes = fgetc(fp);
  cur_board->collect_bombs = fgetc(fp);
  cur_board->fire_burns = fgetc(fp);

  for(i = 0; i < 4; i++)
  {
    cur_board->board_dir[i] = fgetc(fp);
  }

  cur_board->restart_if_zapped = fgetc(fp);
  cur_board->time_limit = fgetw(fp);

  if(version < 0x0253)
  {
    cur_board->last_key = fgetc(fp);
    cur_board->num_input = fgetw(fp);
    cur_board->input_size = fgetc(fp);

    fread(cur_board->input_string, LEGACY_INPUT_STRING_MAX + 1, 1, fp);
    cur_board->input_string[LEGACY_INPUT_STRING_MAX] = 0;

    cur_board->player_last_dir = fgetc(fp);

    fread(cur_board->bottom_mesg, LEGACY_BOTTOM_MESG_MAX + 1, 1, fp);
    cur_board->bottom_mesg[LEGACY_BOTTOM_MESG_MAX] = 0;

    cur_board->b_mesg_timer = fgetc(fp);
    cur_board->lazwall_start = fgetc(fp);
    cur_board->b_mesg_row = fgetc(fp);
    cur_board->b_mesg_col = (signed char)fgetc(fp);
    cur_board->scroll_x = (signed short)fgetw(fp);
    cur_board->scroll_y = (signed short)fgetw(fp);
    cur_board->locked_x = (signed short)fgetw(fp);
    cur_board->locked_y = (signed short)fgetw(fp);
  }
  else if(savegame)
  {
    size_t len;

    cur_board->last_key = fgetc(fp);
    cur_board->num_input = fgetw(fp);
    cur_board->input_size = fgetw(fp);

    len = fgetw(fp);
    if(len >= ROBOT_MAX_TR)
      len = ROBOT_MAX_TR - 1;

    fread(cur_board->input_string, len, 1, fp);
    cur_board->input_string[len] = 0;

    cur_board->player_last_dir = fgetc(fp);

    len = fgetw(fp);
    if(len >= ROBOT_MAX_TR)
      len = ROBOT_MAX_TR - 1;

    fread(cur_board->bottom_mesg, len, 1, fp);
    cur_board->bottom_mesg[len] = 0;

    cur_board->b_mesg_timer = fgetc(fp);
    cur_board->lazwall_start = fgetc(fp);
    cur_board->b_mesg_row = fgetc(fp);
    cur_board->b_mesg_col = (signed char)fgetc(fp);
    cur_board->scroll_x = (signed short)fgetw(fp);
    cur_board->scroll_y = (signed short)fgetw(fp);
    cur_board->locked_x = (signed short)fgetw(fp);
    cur_board->locked_y = (signed short)fgetw(fp);
  }

  cur_board->player_ns_locked = fgetc(fp);
  cur_board->player_ew_locked = fgetc(fp);
  cur_board->player_attack_locked = fgetc(fp);

  if(version < 0x0253 || savegame)
  {
    cur_board->volume = fgetc(fp);
    cur_board->volume_inc = fgetc(fp);
    cur_board->volume_target = fgetc(fp);
  }


  /***************/
  /* Load robots */
  /***************/
  num_robots = fgetc(fp);
  num_robots_active = 0;

  if(num_robots == EOF)
    truncated = 1;

  // EOF/crazy value check
  if((num_robots < 0) || (num_robots > 255) || (num_robots > size))
    goto board_scan;

  cur_board->robot_list = ccalloc(num_robots + 1, sizeof(struct robot *));
  // Also allocate for name sorted list
  cur_board->robot_list_name_sorted =
   ccalloc(num_robots, sizeof(struct robot *));

  // Any null objects being placed will later be optimized out

  if(num_robots)
  {
    for(i = 1; i <= num_robots; i++)
    {
      // Make sure there's robots to load here
      int length_check = fgetw(fp);
      fseek(fp, -2, SEEK_CUR);
      if(length_check < 0)
      {
        // Send off the error and then tell validation to shut up for now
        val_error(WORLD_ROBOT_MISSING, ftell(fp));
        set_validation_suppression(1);
        truncated = 1;
      }

      cur_robot = load_robot_allocate(fp, savegame, version);
      if(cur_robot->used)
      {
        cur_board->robot_list[i] = cur_robot;
        cur_board->robot_list_name_sorted[num_robots_active] = cur_robot;
        num_robots_active++;
      }
      else
      {
        // We don't need no null robot
        clear_robot(cur_robot);
        cur_board->robot_list[i] = NULL;
      }
    }
  }

  set_validation_suppression(-1);

  if(num_robots_active > 0)
  {
    if(num_robots_active != num_robots)
    {
      cur_board->robot_list_name_sorted =
       crealloc(cur_board->robot_list_name_sorted,
       sizeof(struct robot *) * num_robots_active);
    }
    qsort(cur_board->robot_list_name_sorted, num_robots_active,
     sizeof(struct robot *), cmp_robots);
  }
  else
  {
    free(cur_board->robot_list_name_sorted);
    cur_board->robot_list_name_sorted = NULL;
  }

  cur_board->num_robots = num_robots;
  cur_board->num_robots_allocated = num_robots;
  cur_board->num_robots_active = num_robots_active;


  /****************/
  /* Load scrolls */
  /****************/
  num_scrolls = fgetc(fp);

  if(num_scrolls == EOF)
    truncated = 1;

  if((num_scrolls < 0) || (num_scrolls > 255) || (num_robots + num_scrolls > size))
    goto board_scan;

  cur_board->scroll_list = ccalloc(num_scrolls + 1, sizeof(struct scroll *));

  if(num_scrolls)
  {
    for(i = 1; i <= num_scrolls; i++)
    {
      cur_scroll = load_scroll_allocate(fp);
      if(cur_scroll->used)
        cur_board->scroll_list[i] = cur_scroll;
      else
        clear_scroll(cur_scroll);
    }
  }

  cur_board->num_scrolls = num_scrolls;
  cur_board->num_scrolls_allocated = num_scrolls;


  /****************/
  /* Load sensors */
  /****************/
  num_sensors = fgetc(fp);

  if(num_sensors == EOF)
    truncated = 1;

  if((num_sensors < 0) || (num_sensors > 255) ||
   (num_scrolls + num_sensors + num_robots > size))
    goto board_scan;

  cur_board->sensor_list = ccalloc(num_sensors + 1, sizeof(struct sensor *));

  if(num_sensors)
  {
    for(i = 1; i <= num_sensors; i++)
    {
      cur_sensor = load_sensor_allocate(fp);
      if(cur_sensor->used)
        cur_board->sensor_list[i] = cur_sensor;
      else
        clear_sensor(cur_sensor);
    }
  }

  cur_board->num_sensors = num_sensors;
  cur_board->num_sensors_allocated = num_sensors;


board_scan:
  // Now do a board scan to make sure there aren't more than the data told us.
  {
    int robot_count = 0, scroll_count = 0, sensor_count = 0;
    char err_mesg[80] = { 0 };

    for(i = 0; i < (board_width * board_height); i++)
    {
      if(cur_board->level_id[i] > 127)
        cur_board->level_id[i] = CUSTOM_BLOCK;

      if(cur_board->level_under_id[i] > 127)
        cur_board->level_under_id[i] = CUSTOM_FLOOR;

      switch(cur_board->level_id[i])
      {
        case ROBOT:
        case ROBOT_PUSHABLE:
        {
          robot_count++;
          if(robot_count > cur_board->num_robots)
          {
            cur_board->level_id[i] = CUSTOM_BLOCK;
            cur_board->level_param[i] = 'R';
            cur_board->level_color[i] = 0xCF;
          }
          break;
        }
        case SIGN:
        case SCROLL:
        {
          scroll_count++;
          if(scroll_count > cur_board->num_scrolls)
          {
            cur_board->level_id[i] = CUSTOM_BLOCK;
            cur_board->level_param[i] = 'S';
            cur_board->level_color[i] = 0xCF;
          }
        }
        case SENSOR:
        {
          // Wait, I forgot.  Nobody cares about sensors.
          //sensor_count++;
          if(sensor_count > cur_board->num_sensors)
          {
            cur_board->level_id[i] = CUSTOM_FLOOR;
            cur_board->level_param[i] = 'S';
            cur_board->level_color[i] = 0xDF;
          }
        }
      }
    }
    if(robot_count > cur_board->num_robots)
    {
      snprintf(err_mesg, 80, "Board @ %Xh: found %i robots; expected %i",
       board_location, robot_count, cur_board->num_robots);
      error(err_mesg, 1, 8, 0);
    }
    if(scroll_count > cur_board->num_scrolls)
    {
      snprintf(err_mesg, 80, "Board @ %Xh: found %i scrolls/signs; expected %i",
       board_location, scroll_count, cur_board->num_scrolls);
      error(err_mesg, 1, 8, 0);
    }
    // This won't be reached but I'll leave it anyway.
    if(sensor_count > cur_board->num_sensors)
    {
      snprintf(err_mesg, 80, "Board @ %Xh: found %i sensors; expected %i",
       board_location, sensor_count, cur_board->num_sensors);
      error(err_mesg, 1, 8, 0);
    }
    if(err_mesg[0])
      error("Any extra robots/scrolls/signs were replaced", 1, 8, 0);

  }

  if(truncated == 1)
    val_error(WORLD_BOARD_TRUNCATED_SAFE, board_location);

  return VAL_SUCCESS;

err_freeboard:
  free(cur_board->level_id);
  free(cur_board->level_color);
  free(cur_board->level_param);
  free(cur_board->level_under_id);
  free(cur_board->level_under_color);
  free(cur_board->level_under_param);

err_freeoverlay:
  if(overlay_mode)
  {
    free(cur_board->overlay);
    free(cur_board->overlay_color);
  }

err_invalid:
  val_error(WORLD_BOARD_CORRUPT, board_location);
  return VAL_INVALID;
}
Ejemplo n.º 3
0
static int load_mzm_common(struct world *mzx_world, const void *buffer, int file_length, int start_x,
 int start_y, int mode, int savegame, char *name)
{
  const unsigned char *bufferPtr = buffer;
  char magic_string[5];
  int storage_mode;
  int width, height;
  int savegame_mode;
  int num_robots;
  int robots_location;

  int data_start;
  int expected_data_size;

  // MegaZeux 2.83 is the last version that won't save the ver,
  // so if we don't have a ver, just act like it's 2.83
  int mzm_world_version = 0x0253;

  if (file_length < 4)
    goto err_invalid;

  memcpy(magic_string, bufferPtr, 4);
  bufferPtr += 4;

  magic_string[4] = 0;

  if(!strncmp(magic_string, "MZMX", 4))
  {
    // An MZM1 file is always storage mode 0
    storage_mode = 0;
    savegame_mode = 0;
    num_robots = 0;
    robots_location = 0;
    if (file_length < 16) goto err_invalid;
    width = mem_getc(&bufferPtr);
    height = mem_getc(&bufferPtr);
    bufferPtr += 10;
  }
  else

  if(!strncmp(magic_string, "MZM2", 4))
  {
    if (file_length < 16) goto err_invalid;
    width = mem_getw(&bufferPtr);
    height = mem_getw(&bufferPtr);
    robots_location = mem_getd(&bufferPtr);
    num_robots = mem_getc(&bufferPtr);
    storage_mode = mem_getc(&bufferPtr);
    savegame_mode = mem_getc(&bufferPtr);
    bufferPtr += 1;
  }
  else

  if(!strncmp(magic_string, "MZM3", 4))
  {
    if (file_length < 20) goto err_invalid;
    // MZM3 is like MZM2, except the robots are stored as source code if
    // savegame_mode is 0 and version >= VERSION_PROGRAM_SOURCE.
    width = mem_getw(&bufferPtr);
    height = mem_getw(&bufferPtr);
    robots_location = mem_getd(&bufferPtr);
    num_robots = mem_getc(&bufferPtr);
    storage_mode = mem_getc(&bufferPtr);
    savegame_mode = mem_getc(&bufferPtr);
    mzm_world_version = mem_getw(&bufferPtr);
    bufferPtr += 3;
  }

  else
    goto err_invalid;

  data_start = bufferPtr - (const unsigned char *)buffer;
  expected_data_size = (width * height) * (storage_mode ? 2 : 6);

  // Validate
  if(
    (savegame_mode > 1) || (savegame_mode < 0) // Invalid save mode
    || (storage_mode > 1) || (storage_mode < 0) // Invalid storage mode
    || (file_length - data_start < expected_data_size) // not enough space to store data
    || (file_length < robots_location) // The end of file is before the robot offset
    || (robots_location && (expected_data_size + data_start > robots_location)) // robots offset before data end
    )
    goto err_invalid;

  // If the mzm version is newer than the MZX version, show a message and continue.
  if(mzm_world_version > WORLD_VERSION)
  {
    error_message(E_MZM_FILE_VERSION_TOO_RECENT, mzm_world_version, name);
  }

  // If the MZM is a save MZM but we're not loading at runtime, show a message and continue.
  if(savegame_mode > savegame)
  {
    error_message(E_MZM_FILE_FROM_SAVEGAME, 0, name);
  }

  switch(mode)
  {
    // Write to board
    case 0:
    {
      struct board *src_board = mzx_world->current_board;
      int board_width = src_board->board_width;
      int board_height = src_board->board_height;
      int effective_width = width;
      int effective_height = height;
      int file_line_skip;
      int line_skip;
      int x, y;
      int offset = start_x + (start_y * board_width);
      char *level_id = src_board->level_id;
      char *level_param = src_board->level_param;
      char *level_color = src_board->level_color;
      char *level_under_id = src_board->level_under_id;
      char *level_under_param = src_board->level_under_param;
      char *level_under_color = src_board->level_under_color;
      enum thing src_id;

      // Clip

      if((effective_width + start_x) >= board_width)
        effective_width = board_width - start_x;

      if((effective_height + start_y) >= board_height)
        effective_height = board_height - start_y;

      line_skip = board_width - effective_width;

      switch(storage_mode)
      {
        case 0:
        {
          // Board style, write as is
          enum thing current_id;
          int current_robot_loaded = 0;
          int robot_x_locations[256];
          int robot_y_locations[256];
          int width_difference;
          int i;

          width_difference = width - effective_width;

          for(y = 0; y < effective_height; y++)
          {
            for(x = 0; x < effective_width; x++, offset++)
            {
              current_id = (enum thing)mem_getc(&bufferPtr);

              if(current_id >= SENSOR)
              {
                if(is_robot(current_id))
                {
                  robot_x_locations[current_robot_loaded] = x + start_x;
                  robot_y_locations[current_robot_loaded] = y + start_y;
                  current_robot_loaded++;
                }
                // Wipe a bunch of crap we don't want in MZMs with spaces
                else
                  current_id = 0;
              }

              src_id = (enum thing)level_id[offset];

              if(src_id >= SENSOR)
              {
                if(src_id == SENSOR)
                  clear_sensor_id(src_board, level_param[offset]);
                else

                if(is_signscroll(src_id))
                  clear_scroll_id(src_board, level_param[offset]);
                else

                if(is_robot(src_id))
                  clear_robot_id(src_board, level_param[offset]);
              }

              // Don't allow the player to be overwritten
              if(src_id != PLAYER)
              {
                level_id[offset] = current_id;
                level_param[offset] = mem_getc(&bufferPtr);
                level_color[offset] = mem_getc(&bufferPtr);
                level_under_id[offset] = mem_getc(&bufferPtr);
                level_under_param[offset] = mem_getc(&bufferPtr);
                level_under_color[offset] = mem_getc(&bufferPtr);

                // We don't want this on the under layer, thanks
                if(level_under_id[offset] >= SENSOR)
                {
                  level_under_id[offset] = 0;
                  level_under_param[offset] = 0;
                  level_under_color[offset] = 7;
                }
              }
              else
              {
                bufferPtr += 5;
              }
            }

            offset += line_skip;

            // Gotta run through and mark the next robots to be skipped
            for(i = 0; i < width_difference; i++)
            {
              current_id = (enum thing)mem_getc(&bufferPtr);
              bufferPtr += 5;

              if(is_robot(current_id))
              {
                robot_x_locations[current_robot_loaded] = -1;
                current_robot_loaded++;
              }
            }
          }

          for(i = current_robot_loaded; i < num_robots; i++)
          {
            robot_x_locations[i] = -1;
          }

          if(num_robots)
          {
            struct zip_archive *zp;
            unsigned int file_id;
            unsigned int robot_id;
            int result;

            struct robot *cur_robot;
            int current_x, current_y;
            int offset;
            int new_param;
            int robot_calculated_size = 0;
            int robot_partial_size = 0;
            int current_position;
            int dummy = 0;

            // We suppress the errors that will generally occur here and barely
            // error check the zip functions. Why? This needs to run all the way
            // through, regardless of whether it finds errors. Otherwise, we'll
            // get invalid robots with ID=0 littered around the board.

            set_error_suppression(E_WORLD_ROBOT_MISSING, 1);
            set_error_suppression(E_BOARD_ROBOT_CORRUPT, 1);

            // Reset the error count.
            get_and_reset_error_count();

            if(mzm_world_version <= WORLD_LEGACY_FORMAT_VERSION)
            {
              robot_partial_size =
               legacy_calculate_partial_robot_size(savegame_mode,
               mzm_world_version);

              bufferPtr = buffer;
              bufferPtr += robots_location;
              zp = NULL;
            }

            else
            {
              zp = zip_open_mem_read(buffer, file_length);
              zip_read_directory(zp);
              assign_fprops(zp, 1);
            }

            // If we're loading a "runtime MZM" then it means that we're loading
            // bytecode. And to do this we must both be in-game and must be
            // running the same version this was made in. But since loading
            // dynamically created MZMs in the editor is still useful, we'll just
            // dummy out the robots.

            if((savegame_mode > savegame) ||
              (WORLD_VERSION < mzm_world_version))
            {
              dummy = 1;
            }

            for(i = 0; i < num_robots; i++)
            {
              cur_robot = cmalloc(sizeof(struct robot));

              current_x = robot_x_locations[i];
              current_y = robot_y_locations[i];

              // TODO: Skipped legacy robots aren't checked for, so the loaded
              // chars for dummy robots on clipped MZMs might be off. This
              // shouldn't matter too often though.

              if(mzm_world_version <= WORLD_LEGACY_FORMAT_VERSION)
              {
                create_blank_robot(cur_robot);

                current_position = bufferPtr - (const unsigned char *)buffer;

                // If we fail, we have to continue, or robots won't be dummied
                // correctly. In this case, seek to the end.

                if(current_position + robot_partial_size <= file_length)
                {
                  robot_calculated_size =
                   legacy_load_robot_calculate_size(bufferPtr, savegame_mode,
                   mzm_world_version);

                  if(current_position + robot_calculated_size <= file_length)
                  {
                    legacy_load_robot_from_memory(mzx_world, cur_robot, bufferPtr,
                     savegame_mode, mzm_world_version, (int)current_position);
                  }
                  else
                  {
                    bufferPtr = (const unsigned char*)buffer + file_length;
                    dummy = 1;
                  }
                }
                else
                {
                  bufferPtr = (const unsigned char*)buffer + file_length;
                  dummy = 1;
                }

                bufferPtr += robot_calculated_size;
              }

              // Search the zip until a robot is found.
              else do
              {
                result = zip_get_next_prop(zp, &file_id, NULL, &robot_id);

                if(result != ZIP_SUCCESS)
                {
                  // We have to continue, or we'll get screwed up robots.
                  create_blank_robot(cur_robot);
                  create_blank_robot_program(cur_robot);
                  dummy = 1;
                  break;
                }
                else

                if(file_id != FPROP_ROBOT || (int)robot_id < i)
                {
                  // Not a robot or is a skipped robot
                  zip_skip_file(zp);
                }
                else

                if((int)robot_id > i)
                {
                  // There's a robot missing.
                  create_blank_robot(cur_robot);
                  create_blank_robot_program(cur_robot);
                  break;
                }

                else
                {
                  load_robot(mzx_world, cur_robot, zp, savegame_mode,
                   mzm_world_version);
                  break;
                }
              }
              while(1);

              if(dummy)
              {
                // Unfortunately, getting the actual character for the robot is
                // kind of a lot of work right now. We have to load it then
                // throw it away.

                // If this is from a futer version and the format changed, we'll
                // just end up with an 'R' char, but this shouldn't happen again
                if(current_x != -1)
                {
                  offset = current_x + (current_y * board_width);
                  level_id[offset] = CUSTOM_BLOCK;
                  level_param[offset] = cur_robot->robot_char;
                }
                clear_robot(cur_robot);
              }

              else
              {
                cur_robot->world_version = mzx_world->version;
                cur_robot->xpos = current_x;
                cur_robot->ypos = current_y;

#ifdef CONFIG_DEBYTECODE
                // If we're loading source code at runtime, we need to compile it
                if(savegame_mode < savegame)
                  prepare_robot_bytecode(mzx_world, cur_robot);
#endif

                if(current_x != -1)
                {
                  new_param = find_free_robot(src_board);
                  offset = current_x + (current_y * board_width);

                  if(new_param != -1)
                  {
                    if((enum thing)level_id[offset] != PLAYER)
                    {
                      add_robot_name_entry(src_board, cur_robot,
                        cur_robot->robot_name);
                      src_board->robot_list[new_param] = cur_robot;
                      cur_robot->xpos = current_x;
                      cur_robot->ypos = current_y;
                      level_param[offset] = new_param;
                    }
                    else
                    {
                      clear_robot(cur_robot);
                    }
                  }
                  else
                  {
                    clear_robot(cur_robot);
                    level_id[offset] = 0;
                    level_param[offset] = 0;
                    level_color[offset] = 7;
                  }
                }
                else
                {
                  clear_robot(cur_robot);
                }
              }
            }

            if(mzm_world_version > WORLD_LEGACY_FORMAT_VERSION)
            {
              zip_close(zp, NULL);
            }

            // If any errors were encountered, report
            if(get_and_reset_error_count())
              goto err_robots;
          }
          break;
        }

        case 1:
        {
          // Compact style; expand to customblocks
          // Board style, write as is

          file_line_skip = (width - effective_width) * 2;

          for(y = 0; y < effective_height; y++)
          {
            for(x = 0; x < effective_width; x++, offset++)
            {
              src_id = (enum thing)level_id[offset];

              if(src_id == SENSOR)
                clear_sensor_id(src_board, level_param[offset]);
              else

              if(is_signscroll(src_id))
                clear_scroll_id(src_board, level_param[offset]);
              else

              if(is_robot(src_id))
                clear_robot_id(src_board, level_param[offset]);

              // Don't allow the player to be overwritten
              if(src_id != PLAYER)
              {
                level_id[offset] = CUSTOM_BLOCK;
                level_param[offset] = mem_getc(&bufferPtr);
                level_color[offset] = mem_getc(&bufferPtr);
                level_under_id[offset] = 0;
                level_under_param[offset] = 0;
                level_under_color[offset] = 0;
              }
              else
              {
                bufferPtr += 2;
              }
            }

            offset += line_skip;
            bufferPtr += file_line_skip;
          }
          break;
        }
      }
      break;
    }

    // Overlay/vlayer
    case 1:
    case 2:
    {
      struct board *src_board = mzx_world->current_board;
      int dest_width = src_board->board_width;
      int dest_height = src_board->board_height;
      char *dest_chars;
      char *dest_colors;
      int effective_width = width;
      int effective_height = height;
      int file_line_skip;
      int line_skip;
      int x, y;
      int offset;

      if(mode == 1)
      {
        // Overlay
        if(!src_board->overlay_mode)
          setup_overlay(src_board, 3);

        dest_chars = src_board->overlay;
        dest_colors = src_board->overlay_color;
        dest_width = src_board->board_width;
        dest_height = src_board->board_height;
      }
      else
      {
        // Vlayer
        dest_chars = mzx_world->vlayer_chars;
        dest_colors = mzx_world->vlayer_colors;
        dest_width = mzx_world->vlayer_width;
        dest_height = mzx_world->vlayer_height;
      }

      offset = start_x + (start_y * dest_width);

      // Clip

      if((effective_width + start_x) >= dest_width)
        effective_width = dest_width - start_x;

      if((effective_height + start_y) >= dest_height)
        effective_height = dest_height - start_y;

      line_skip = dest_width - effective_width;

      switch(storage_mode)
      {
        case 0:
        {
          // Coming from board storage; for now use param as char

          file_line_skip = (width - effective_width) * 6;

          for(y = 0; y < effective_height; y++)
          {
            for(x = 0; x < effective_width; x++, offset++)
            {
              // Skip ID
              bufferPtr += 1;
              dest_chars[offset] = mem_getc(&bufferPtr);
              dest_colors[offset] = mem_getc(&bufferPtr);
              // Skip under parts
              bufferPtr += 3;
            }

            offset += line_skip;
            bufferPtr += file_line_skip;
          }
          break;
        }

        case 1:
        {
          // Coming from layer storage; transfer directly

          file_line_skip = (width - effective_width) * 2;

          for(y = 0; y < effective_height; y++)
          {
            for(x = 0; x < effective_width; x++, offset++)
            {
              dest_chars[offset] = mem_getc(&bufferPtr);
              dest_colors[offset] = mem_getc(&bufferPtr);
            }

            offset += line_skip;
            bufferPtr += file_line_skip;
          }
          break;
        }

      }
      break;
    }
  }

  // Clear none of the validation error suppressions:
  // 1) in combination with poor practice, they could lock MZX,
  // 2) they'll get reset after reloading the world.
  return 0;

err_robots:
  // The main file loaded fine, but there was a problem handling robots
  error_message(E_MZM_ROBOT_CORRUPT, 0, name);
  return 0;

err_invalid:
  error_message(E_MZM_FILE_INVALID, 0, name);
  return -1;
}
Ejemplo n.º 4
0
__editor_maybe_static void load_board_direct(struct board *cur_board,
 FILE *fp, int savegame, int version)
{
  int num_robots, num_scrolls, num_sensors, num_robots_active;
  int overlay_mode, size, board_width, board_height, i;

  struct robot *cur_robot;
  struct scroll *cur_scroll;
  struct sensor *cur_sensor;

  char *test_buffer;

  // Initialize some fields that may no longer be loaded
  // from the board file itself..

  cur_board->last_key = '?';
  cur_board->num_input = 0;
  cur_board->input_size = 0;
  cur_board->input_string[0] = 0;
  cur_board->player_last_dir = 0x10;
  cur_board->bottom_mesg[0] = 0;
  cur_board->b_mesg_timer = 0;
  cur_board->lazwall_start = 7;
  cur_board->b_mesg_row = 24;
  cur_board->b_mesg_col = -1;
  cur_board->scroll_x = 0;
  cur_board->scroll_y = 0;
  cur_board->locked_x = -1;
  cur_board->locked_y = -1;
  cur_board->volume = 255;
  cur_board->volume_inc = 0;
  cur_board->volume_target = 255;

  // board_mode, unused
  fgetc(fp);

  overlay_mode = fgetc(fp);

  if(!overlay_mode)
  {
    int overlay_width;
    int overlay_height;

    overlay_mode = fgetc(fp);
    overlay_width = fgetw(fp);
    overlay_height = fgetw(fp);

    size = overlay_width * overlay_height;

    cur_board->overlay = cmalloc(size);
    cur_board->overlay_color = cmalloc(size);

    load_RLE2_plane(cur_board->overlay, fp, size);
    test_buffer = cmalloc(1024);
    free(test_buffer);

    // Skip sizes
    fseek(fp, 4, SEEK_CUR);
    load_RLE2_plane(cur_board->overlay_color, fp, size);
    test_buffer = cmalloc(1024);
    free(test_buffer);
  }
  else
  {
    overlay_mode = 0;
    // Undo that last get
    fseek(fp, -1, SEEK_CUR);
  }

  cur_board->overlay_mode = overlay_mode;

  board_width = fgetw(fp);
  board_height = fgetw(fp);
  cur_board->board_width = board_width;
  cur_board->board_height = board_height;

  size = board_width * board_height;

  cur_board->level_id = cmalloc(size);
  cur_board->level_color = cmalloc(size);
  cur_board->level_param = cmalloc(size);
  cur_board->level_under_id = cmalloc(size);
  cur_board->level_under_color = cmalloc(size);
  cur_board->level_under_param = cmalloc(size);

  load_RLE2_plane(cur_board->level_id, fp, size);
  fseek(fp, 4, SEEK_CUR);
  load_RLE2_plane(cur_board->level_color, fp, size);
  fseek(fp, 4, SEEK_CUR);
  load_RLE2_plane(cur_board->level_param, fp, size);
  fseek(fp, 4, SEEK_CUR);
  load_RLE2_plane(cur_board->level_under_id, fp, size);
  fseek(fp, 4, SEEK_CUR);
  load_RLE2_plane(cur_board->level_under_color, fp, size);
  fseek(fp, 4, SEEK_CUR);
  load_RLE2_plane(cur_board->level_under_param, fp, size);

  // Load board parameters

  if(version < 0x0253)
  {
    fread(cur_board->mod_playing, LEGACY_MOD_FILENAME_MAX, 1, fp);
    cur_board->mod_playing[LEGACY_MOD_FILENAME_MAX] = 0;
  }
  else
  {
    size_t len = fgetw(fp);
    if(len >= MAX_PATH)
      len = MAX_PATH - 1;

    fread(cur_board->mod_playing, len, 1, fp);
    cur_board->mod_playing[len] = 0;
  }

  cur_board->viewport_x = fgetc(fp);
  cur_board->viewport_y = fgetc(fp);
  cur_board->viewport_width = fgetc(fp);
  cur_board->viewport_height = fgetc(fp);
  cur_board->can_shoot = fgetc(fp);
  cur_board->can_bomb = fgetc(fp);
  cur_board->fire_burn_brown = fgetc(fp);
  cur_board->fire_burn_space = fgetc(fp);
  cur_board->fire_burn_fakes = fgetc(fp);
  cur_board->fire_burn_trees = fgetc(fp);
  cur_board->explosions_leave = fgetc(fp);
  cur_board->save_mode = fgetc(fp);
  cur_board->forest_becomes = fgetc(fp);
  cur_board->collect_bombs = fgetc(fp);
  cur_board->fire_burns = fgetc(fp);

  for(i = 0; i < 4; i++)
  {
    cur_board->board_dir[i] = fgetc(fp);
  }

  cur_board->restart_if_zapped = fgetc(fp);
  cur_board->time_limit = fgetw(fp);

  if(version < 0x0253)
  {
    cur_board->last_key = fgetc(fp);
    cur_board->num_input = fgetw(fp);
    cur_board->input_size = fgetc(fp);

    fread(cur_board->input_string, LEGACY_INPUT_STRING_MAX + 1, 1, fp);
    cur_board->input_string[LEGACY_INPUT_STRING_MAX] = 0;

    cur_board->player_last_dir = fgetc(fp);

    fread(cur_board->bottom_mesg, LEGACY_BOTTOM_MESG_MAX + 1, 1, fp);
    cur_board->bottom_mesg[LEGACY_BOTTOM_MESG_MAX] = 0;

    cur_board->b_mesg_timer = fgetc(fp);
    cur_board->lazwall_start = fgetc(fp);
    cur_board->b_mesg_row = fgetc(fp);
    cur_board->b_mesg_col = (signed char)fgetc(fp);
    cur_board->scroll_x = (signed short)fgetw(fp);
    cur_board->scroll_y = (signed short)fgetw(fp);
    cur_board->locked_x = (signed short)fgetw(fp);
    cur_board->locked_y = (signed short)fgetw(fp);
  }
  else if(savegame)
  {
    size_t len;

    cur_board->last_key = fgetc(fp);
    cur_board->num_input = fgetw(fp);
    cur_board->input_size = fgetw(fp);

    len = fgetw(fp);
    if(len >= ROBOT_MAX_TR)
      len = ROBOT_MAX_TR - 1;

    fread(cur_board->input_string, len, 1, fp);
    cur_board->input_string[len] = 0;

    cur_board->player_last_dir = fgetc(fp);

    len = fgetw(fp);
    if(len >= ROBOT_MAX_TR)
      len = ROBOT_MAX_TR - 1;

    fread(cur_board->bottom_mesg, len, 1, fp);
    cur_board->bottom_mesg[len] = 0;

    cur_board->b_mesg_timer = fgetc(fp);
    cur_board->lazwall_start = fgetc(fp);
    cur_board->b_mesg_row = fgetc(fp);
    cur_board->b_mesg_col = (signed char)fgetc(fp);
    cur_board->scroll_x = (signed short)fgetw(fp);
    cur_board->scroll_y = (signed short)fgetw(fp);
    cur_board->locked_x = (signed short)fgetw(fp);
    cur_board->locked_y = (signed short)fgetw(fp);
  }

  cur_board->player_ns_locked = fgetc(fp);
  cur_board->player_ew_locked = fgetc(fp);
  cur_board->player_attack_locked = fgetc(fp);

  if(version < 0x0253 || savegame)
  {
    cur_board->volume = fgetc(fp);
    cur_board->volume_inc = fgetc(fp);
    cur_board->volume_target = fgetc(fp);
  }

  // Load robots
  num_robots = fgetc(fp);
  num_robots_active = 0;

  cur_board->robot_list = ccalloc(num_robots + 1, sizeof(struct robot *));
  // Also allocate for name sorted list
  cur_board->robot_list_name_sorted =
   ccalloc(num_robots, sizeof(struct robot *));

  // Any null objects being placed will later be optimized out

  if(num_robots)
  {
    for(i = 1; i <= num_robots; i++)
    {
      cur_robot = load_robot_allocate(fp, savegame, version);
      if(cur_robot->used)
      {
        cur_board->robot_list[i] = cur_robot;
        cur_board->robot_list_name_sorted[num_robots_active] = cur_robot;
        num_robots_active++;
      }
      else
      {
        // We don't need no null robot
        clear_robot(cur_robot);
        cur_board->robot_list[i] = NULL;
      }
    }
  }

  if(num_robots_active)
  {
    if(num_robots_active != num_robots)
    {
      cur_board->robot_list_name_sorted =
       crealloc(cur_board->robot_list_name_sorted,
       sizeof(struct robot *) * num_robots_active);
    }
    qsort(cur_board->robot_list_name_sorted, num_robots_active,
     sizeof(struct robot *), cmp_robots);
  }
  else
  {
    free(cur_board->robot_list_name_sorted);
    cur_board->robot_list_name_sorted = NULL;
  }

  cur_board->num_robots = num_robots;
  cur_board->num_robots_allocated = num_robots;
  cur_board->num_robots_active = num_robots_active;

  // Load scrolls
  num_scrolls = fgetc(fp);
  cur_board->scroll_list = ccalloc(num_scrolls + 1, sizeof(struct scroll *));

  if(num_scrolls)
  {
    for(i = 1; i <= num_scrolls; i++)
    {
      cur_scroll = load_scroll_allocate(fp);
      if(cur_scroll->used)
        cur_board->scroll_list[i] = cur_scroll;
      else
        clear_scroll(cur_scroll);
    }
  }

  cur_board->num_scrolls = num_scrolls;
  cur_board->num_scrolls_allocated = num_scrolls;

  // Load sensors
  num_sensors = fgetc(fp);
  cur_board->sensor_list = ccalloc(num_sensors + 1, sizeof(struct sensor *));

  if(num_sensors)
  {
    for(i = 1; i <= num_sensors; i++)
    {
      cur_sensor = load_sensor_allocate(fp);
      if(cur_sensor->used)
        cur_board->sensor_list[i] = cur_sensor;
      else
        clear_sensor(cur_sensor);
    }
  }

  cur_board->num_sensors = num_sensors;
  cur_board->num_sensors_allocated = num_sensors;
}