Juwan Park :: 세이브 파일 개수 조정 (RPG XP용)

세이브 파일 개수 조정 (RPG XP용)

◆게임 창작 관련/코드, 스크립트 :: 2015.09.08 11:55

RPG XP에서 기본 제공되는 세이브 엔진은 게임당 4개의 세이브 파일을 지원합니다.

하지만 스크립트를 고치면 RPG VX Ace처럼 16개로 설정할 수도 있습니다.
RPG VX도 스크립트를 고치면 4개를 넘어가는 세이브 파일이 가능한데 이것은 XP 버전으로 만든 것입니다.
16개 뿐만 아니라 32개나 64개도 가능합니다.

다음 스크립트를 복사해서 스크립트창(F11)의 'Main' 부분 위에 새 스크립트를 추가해 붙여넣기하시면 됩니다.

# Adjust Max Savefiles for RMXP v1.0
# RPG 만들기 XP에서 세이브 파일 개수를 조정할 수 있습니다.
#
# 만든이: 家和萬事成
# http://parkjuwan.tistory.com
#
# 기본 스크립트를 약간 수정하였습니다.

class Game_System
  #최대 세이브 파일 개수
  MAX_SAVE_FILES = 16   #default: 4
  #[주의!] 최대 세이브 파일 개수는 반드시 4의 배수로 설정해 주세요.
  #4의 배수가 아닐 경우 오류가 발생합니다.
end

class Window_SaveFile < Window_Base
  def initialize(file_index, filename)
    super(0, 64 + file_index % 4 * 104, 640, 104)
    self.contents = Bitmap.new(width - 32, height - 32)
    @file_index = file_index
    @filename = "Save" + sprintf("%02d", file_index + 1) + ".rxdata"
    @time_stamp = Time.at(0)
    @file_exist = FileTest.exist?(@filename)
    if @file_exist
      file = File.open(@filename, "r")
      @time_stamp = file.mtime
      @characters = Marshal.load(file)
      @frame_count = Marshal.load(file)
      @game_system = Marshal.load(file)
      @game_switches = Marshal.load(file)
      @game_variables = Marshal.load(file)
      @total_sec = @frame_count / Graphics.frame_rate
      file.close
    end
    refresh
    @selected = false
  end
end

class Scene_Title
  #--------------------------------------------------------------------------
  # Main Processing
  #--------------------------------------------------------------------------
  def main
    # If battle test
    if $BTEST
      battle_test
      return
    end
    # Load database
    $data_actors        = load_data("Data/Actors.rxdata")
    $data_classes       = load_data("Data/Classes.rxdata")
    $data_skills        = load_data("Data/Skills.rxdata")
    $data_items         = load_data("Data/Items.rxdata")
    $data_weapons       = load_data("Data/Weapons.rxdata")
    $data_armors        = load_data("Data/Armors.rxdata")
    $data_enemies       = load_data("Data/Enemies.rxdata")
    $data_troops        = load_data("Data/Troops.rxdata")
    $data_states        = load_data("Data/States.rxdata")
    $data_animations    = load_data("Data/Animations.rxdata")
    $data_tilesets      = load_data("Data/Tilesets.rxdata")
    $data_common_events = load_data("Data/CommonEvents.rxdata")
    $data_system        = load_data("Data/System.rxdata")
    # Make system object
    $game_system = Game_System.new
    # Make title graphic
    @sprite = Sprite.new
    @sprite.bitmap = RPG::Cache.title($data_system.title_name)
    # Make command window
    # s1: New Game, s2: Continue, s3: End
    s1 = "새로 시작"
    s2 = "이어하기"
    s3 = "종료하기"
    @command_window = Window_Command.new(192, [s1, s2, s3])
    @command_window.back_opacity = 160
    @command_window.x = 320 - @command_window.width / 2
    @command_window.y = 288
    # Continue enabled determinant
    # Check if at least one save file exists
    # If enabled, make `@continue_enabled` true; if disabled, make it false
    @continue_enabled = false
    j = Game_System::MAX_SAVE_FILES
    for i in 0..j
      if FileTest.exist?("Save" + sprintf("%02d", i + 1) + ".rxdata")
        @continue_enabled = true
      end
    end
    # If continue is enabled, move cursor to "Continue"
    # If disabled, display "Continue" text in gray
    if @continue_enabled
      @command_window.index = 1
    else
      @command_window.disable_item(1)
    end
    # Play title BGM
    $game_system.bgm_play($data_system.title_bgm)
    # Stop playing ME and BGS
    Audio.me_stop
    Audio.bgs_stop
    # Execute transition
    Graphics.transition
    # Main loop
    loop do
      # Update game screen
      Graphics.update
      # Update input information
      Input.update
      # Frame update
      update
      # Abort loop if screen is changed
      if $scene != self
        break
      end
    end
    # Prepare for transition
    Graphics.freeze
    # Dispose of command window
    @command_window.dispose
    # Dispose of title graphic
    @sprite.bitmap.dispose
    @sprite.dispose
  end
end


class Scene_File
  MAX_SAVE_FILES = Game_System::MAX_SAVE_FILES
  
  #--------------------------------------------------------------------------
  # Object Initialization
  # help_text : text string shown in the help window
  #--------------------------------------------------------------------------
  def initialize(help_text)
    @help_text = help_text
  end
  #--------------------------------------------------------------------------
  # Main Processing
  #--------------------------------------------------------------------------
  def main
    # Make help window
    @help_window = Window_Help.new
    @help_window.set_text(@help_text)
    # Make save file window
    @savefile_windows = []
    j = MAX_SAVE_FILES - 1
    for i in 0..j
      @savefile_windows.push(Window_SaveFile.new(i, make_filename(i)))
    end
    # Select last file to be operated
    @file_index = $game_temp.last_file_index
    @savefile_windows[@file_index].selected = true
    # 나머지 창 투명처리
    for i in 0..j
      if (@file_index / 4).floor != (i / 4).floor
      @savefile_windows[i].visible = false
      end
    end
    # Execute transition
    Graphics.transition
    # Main loop
    loop do
      # Update game screen
      Graphics.update
      # Update input information
      Input.update
      # Frame update
      update
      # Abort loop if screen is changed
      if $scene != self
        break
      end
    end
    # Prepare for transition
    Graphics.freeze
    # Dispose of windows
    @help_window.dispose
    for i in @savefile_windows
      i.dispose
    end
  end
  #--------------------------------------------------------------------------
  # Frame Update
  #--------------------------------------------------------------------------
  def update
    # Update windows
    @help_window.update
    for i in @savefile_windows
      i.update
    end
    j = MAX_SAVE_FILES - 1
    # If C button was pressed
    if Input.trigger?(Input::C)
      # Call method: on_decision (defined by the subclasses)
      on_decision(make_filename(@file_index))
      $game_temp.last_file_index = @file_index
      return
    end
    # If B button was pressed
    if Input.trigger?(Input::B)
      # Call method: on_cancel (defined by the subclasses)
      on_cancel
      return
    end
    # If the down directional button was pressed
    if Input.repeat?(Input::DOWN)
      # If the down directional button pressed down is not a repeat,
      # or cursor position is more in front than MAX - 1
      old_index = @file_index
      if Input.trigger?(Input::DOWN) or @file_index < j
        # Play cursor SE
        $game_system.se_play($data_system.cursor_se)
        # Move cursor down
        @savefile_windows[@file_index].selected = false
        @file_index = (@file_index + 1) % MAX_SAVE_FILES
        @savefile_windows[@file_index].selected = true
        refresh_visible(@file_index, old_index)
        return
      end
    end
    # If the up directional button was pressed
    if Input.repeat?(Input::UP)
      # If the up directional button pressed down is not a repeat、
      # or cursor position is more in back than 0
      old_index = @file_index
      if Input.trigger?(Input::UP) or @file_index > 0
        # Play cursor SE
        $game_system.se_play($data_system.cursor_se)
        # Move cursor up
        @savefile_windows[@file_index].selected = false
        @file_index = (@file_index + j) % MAX_SAVE_FILES
        @savefile_windows[@file_index].selected = true
        refresh_visible(@file_index, old_index)
        return
      end
    end
    # Page Down
    if Input.repeat?(Input::R)
      old_index = @file_index
      if @file_index < j
        # Play cursor SE
        $game_system.se_play($data_system.cursor_se)
        # Move cursor down * 4
        @savefile_windows[@file_index].selected = false
        @file_index = (@file_index + 4)
        @file_index = j if @file_index > j
        @savefile_windows[@file_index].selected = true
        refresh_visible(@file_index, old_index)
        return
      end
    end
    # Page Up
    if Input.repeat?(Input::L)
      old_index = @file_index
      if @file_index > 0
        # Play cursor SE
        $game_system.se_play($data_system.cursor_se)
        # Move cursor up * 4
        @savefile_windows[@file_index].selected = false
        @file_index = (@file_index - 4)
        @file_index = 0 if @file_index < 0
        @savefile_windows[@file_index].selected = true
        refresh_visible(@file_index, old_index)
        return
      end
    end
  end
  #--------------------------------------------------------------------------
  # Refresh visible
  #--------------------------------------------------------------------------
  def refresh_visible(new_index, old_index)
    ii = (new_index / 4).floor * 4
    jj = (old_index / 4).floor * 4
    if ii != jj
      for i in 0..3
        @savefile_windows[ii+i].visible = true
        @savefile_windows[jj+i].visible = false
      end
    end
  end
  #--------------------------------------------------------------------------
  # Make File Name
  # file_index : save file index (0-M) M = MAX - 1
  #--------------------------------------------------------------------------
  def make_filename(file_index)
    return "Save" + sprintf("%02d", file_index + 1) + ".rxdata"
  end
end

이 방법은 RPG XP에서만 가능합니다. RPG VX와 Ace의 경우는 맞게 바꾼 스크립트가 별도로 있습니다. [VX] [VXA]
또한, 독자적인 세이브 엔진을 사용하는 경우 이 스크립트를 사용하지 않는 것을 권장합니다.

이 스크립트를 적용하기 전에 저장한 세이브 파일은 숫자 앞에 0을 붙이는 것으로 이름을 바꾸면 제대로 읽을 수 있습니다.
(예: Save1.rxdata → Save01.rxdata)

적용할 경우 아래 스샷처럼 됩니다.



예제 파일은 다음과 같습니다.

AdjustMaxSavefiles(XP).zip

스크립트만 추출한 파일은 다음과 같습니다.

adjust_max_savefiles_for_xp.rb

Today 5    Yday 37    Tot 65,556
Juwan Park
Juwan Park's blog is powered by Daum and TISTORY.
Contemporary Blue for TISTORY.
Designed by Juwan Park. Creative Commons License
▲ TOP