This script let you customize some aspects of save files. You can have as much save files as you want, change the filename, extension and directory of the files and have a confirmation window before loading or overwriting a file. This script also modifies the File scene and adds a detail window that displays party members stats, gold, map name and a preview of the location.
# Vocabulary
Vocab::SaveMessage = "Save to which file?"
Vocab::LoadMessage = "Load which file?"
Vocab::File = 'File'
Vocab::NoFile = 'Empty'
Vocab::FileConfirm = 'Are you sure you want to %s this file?'
module Advanced_Files
# Maximum number of files
Max_Files = 80
# Filename
Name = 'Save'
# File extension
Extension = 'rvdata'
# File directory (Automatically creates the directory)
Directory = 'Save'
# Use file confirmation
Confirmation = true
# Smooth Scroll
Smooth_Scroll = true
# Scroll Speed (The higher the faster)
Scroll_Speed = 30
# Use a picture for location name instead of text
Location_Name_Picture = false
end
#==============================================================================
# ** Font
#==============================================================================
class Font
def marshal_dump;end
def marshal_load(obj);end
end
class Bitmap
# Win32API
RtlMoveMemory_pi = Win32API.new('kernel32', 'RtlMoveMemory', 'pii', 'i')
RtlMoveMemory_ip = Win32API.new('kernel32', 'RtlMoveMemory', 'ipi', 'i')
#--------------------------------------------------------------------------
# * Dump
#--------------------------------------------------------------------------
def _dump(limit)
data = "rgba" * width * height
RtlMoveMemory_pi.call(data, address, data.length)
[width, height, Zlib::Deflate.deflate(data)].pack("LLa*")
end
#--------------------------------------------------------------------------
# * Loas
#--------------------------------------------------------------------------
def self._load(str)
w, h, zdata = str.unpack("LLa*"); b = new(w, h)
RtlMoveMemory_ip.call(b.address, Zlib::Inflate.inflate(zdata), w * h * 4); b
end
#--------------------------------------------------------------------------
# * Address
#--------------------------------------------------------------------------
def address
buffer, ad = "xxxx", object_id * 2 + 16
RtlMoveMemory_pi.call(buffer, ad, 4); ad = buffer.unpack("L")[0] + 8
RtlMoveMemory_pi.call(buffer, ad, 4); ad = buffer.unpack("L")[0] + 16
RtlMoveMemory_pi.call(buffer, ad, 4); return buffer.unpack("L")[0]
end
end
#==============================================================================
# ** Game_System
#------------------------------------------------------------------------------
# This class handles system-related data. Also manages vehicles and BGM, etc.
# The instance of this class is referenced by $game_system.
#==============================================================================
class Game_System
#--------------------------------------------------------------------------
# * Public Instance Variables
#--------------------------------------------------------------------------
attr_accessor :background_bitmap
attr_accessor :map_name
#--------------------------------------------------------------------------
# * Alias Listing
#--------------------------------------------------------------------------
alias dargor_advanced_files_system_initialize initialize
#--------------------------------------------------------------------------
# * Object Initialization
#--------------------------------------------------------------------------
def initialize
dargor_advanced_files_system_initialize
@background_bitmap = nil
@map_name = ''
end
end
#==============================================================================
# ** Game_Map
#------------------------------------------------------------------------------
# This class handles maps. It includes scrolling and passage determination
# functions. The instance of this class is referenced by $game_map.
#==============================================================================
class Game_Map
#--------------------------------------------------------------------------
# * Get Map ID
#--------------------------------------------------------------------------
def name
map_infos = load_data("Data/MapInfos.rvdata")
name = map_infos[@map_id].name
return name
end
end
#==============================================================================
# ** Window_MapPreview
#------------------------------------------------------------------------------
# This window displays a map preview in the File screen.
#==============================================================================
class Window_MapPreview < Window_Base
#--------------------------------------------------------------------------
# * Object Initialization
#--------------------------------------------------------------------------
def initialize
super(272, 212,264,196)
self.visible = false
end
#--------------------------------------------------------------------------
# * Load Game Data
#--------------------------------------------------------------------------
def load_gamedata(filename)
@filename = filename
@time_stamp = Time.at(0)
@file_exist = FileTest.exist?(@filename)
if @file_exist
file = File.open(@filename, "r")
@time_stamp = file.mtime
begin
@characters = Marshal.load(file)
@frame_count = Marshal.load(file)
@last_bgm = Marshal.load(file)
@last_bgs = Marshal.load(file)
@game_system = Marshal.load(file)
@game_message = Marshal.load(file)
@game_switches = Marshal.load(file)
@game_variables = Marshal.load(file)
@game_self_switches = Marshal.load(file)
@game_actors = Marshal.load(file)
@game_party = Marshal.load(file)
@game_troop = Marshal.load(file)
@game_map = Marshal.load(file)
@game_player = Marshal.load(file)
@total_sec = @frame_count / Graphics.frame_rate
rescue
@file_exist = false
ensure
file.close
end
end
refresh
end
#--------------------------------------------------------------------------
# * Refresh
#--------------------------------------------------------------------------
def refresh
self.contents.clear
return unless @file_exist
name = @game_system.map_name
if Advanced_Files::Location_Name_Picture
bitmap = Cache.picture(name)
self.contents.blt(4,4,bitmap,bitmap.rect)
else
self.contents.draw_text(4,4,272,WLH,name)
end
self.contents.blt(4,32,@game_system.background_bitmap,Rect.new(160,128,224,128))
end
end
#==============================================================================
# ** Window_FileDetail
#------------------------------------------------------------------------------
# This window displays file details in the File screen.
#==============================================================================
class Window_FileDetail < Window_Base
#--------------------------------------------------------------------------
# * Object Initialization
#--------------------------------------------------------------------------
def initialize
super(0,202,544,214)
self.visible = false
end
#--------------------------------------------------------------------------
# * Load Game Data
#--------------------------------------------------------------------------
def load_gamedata(filename)
@filename = filename
@time_stamp = Time.at(0)
@file_exist = FileTest.exist?(@filename)
if @file_exist
file = File.open(@filename, "r")
@time_stamp = file.mtime
begin
@characters = Marshal.load(file)
@frame_count = Marshal.load(file)
@last_bgm = Marshal.load(file)
@last_bgs = Marshal.load(file)
@game_system = Marshal.load(file)
@game_message = Marshal.load(file)
@game_switches = Marshal.load(file)
@game_variables = Marshal.load(file)
@game_self_switches = Marshal.load(file)
@game_actors = Marshal.load(file)
@game_party = Marshal.load(file)
@game_troop = Marshal.load(file)
@game_map = Marshal.load(file)
@game_player = Marshal.load(file)
@total_sec = @frame_count / Graphics.frame_rate
rescue
@file_exist = false
ensure
file.close
end
end
refresh
end
#--------------------------------------------------------------------------
# * Refresh
#--------------------------------------------------------------------------
def refresh
self.contents.clear
return unless @file_exist
for i in 0...@game_party.members.size
member = @game_party.members[i]
draw_actor_name(member,4,i * WLH)
draw_actor_hp(member,96,i * WLH)
end
end
end
#==============================================================================
# ** Window_FileGold
#------------------------------------------------------------------------------
# This window displays the amount of gold in the File screen.
#==============================================================================
#==============================================================================
# ** Window_SaveFile
#------------------------------------------------------------------------------
# This window displays save files on the save and load screens.
#==============================================================================
class Window_SaveFile < Window_Base
MAX_FILES = Advanced_Files::Max_Files
#--------------------------------------------------------------------------
# * Public Instance Variables
#--------------------------------------------------------------------------
attr_reader :file_index
MAX_FILES = Advanced_Files::Max_Files
#--------------------------------------------------------------------------
# * Alias Listing
#--------------------------------------------------------------------------
alias dargor_vx_advanced_files_window_refresh refresh
#--------------------------------------------------------------------------
# * Object Initialization
# file_index : save file index (0-3)
# filename : filename
#--------------------------------------------------------------------------
def initialize(file_index, filename)
super(0, file_index % MAX_FILES * 90, 544, 90)
@file_index = file_index
@filename = filename
load_gamedata
refresh
@selected = false
end
#--------------------------------------------------------------------------
# * Refresh
#--------------------------------------------------------------------------
def refresh
dargor_vx_advanced_files_window_refresh
unless @file_exist
y = (self.height / 2)-(WLH / 2)
self.contents.draw_text(0,y,508,WLH,Vocab::NoFile,2)
end
end
end
#==============================================================================
# ** Scene_Title
#------------------------------------------------------------------------------
# This class performs the title screen processing.
#==============================================================================
class Scene_Title < Scene_Base
#--------------------------------------------------------------------------
# * Determine if Continue is Enabled
#--------------------------------------------------------------------------
def check_continue
name = Advanced_Files::Name
extension = Advanced_Files::Extension
directory = Advanced_Files::Directory
unless FileTest.directory?(directory)
Dir.mkdir(directory)
end
@continue_enabled = (Dir.glob("#{directory}/#{name}*.#{extension}").size > 0)
end
end
#==============================================================================
# ** Scene_File
#------------------------------------------------------------------------------
# This class performs the save and load screen processing.
#==============================================================================
class Scene_File < Scene_Base
MAX_FILES = Advanced_Files::Max_Files
#--------------------------------------------------------------------------
# * Alias Listing
#--------------------------------------------------------------------------
alias dargor_vx_advanced_files_scene_file_start start
alias dargor_vx_advanced_files_scene_file_terminate terminate
alias dargor_vx_advanced_files_scene_file_update update
alias dargor_vx_advanced_files_scene_file_update_savefile_windows update_savefile_windows
#--------------------------------------------------------------------------
# * Create Save File Window
#--------------------------------------------------------------------------
def create_savefile_windows
@savefile_windows = []
@file_viewport = Viewport.new(0,56,544,416)
@file_viewport.z = 500
@old_top_row = 0
@speed = 0
for i in 0...MAX_FILES
@savefile_windows.push(Window_SaveFile.new(i, make_filename(i)))
@savefile_windows[i].viewport = @file_viewport
end
@item_max = MAX_FILES
end
#--------------------------------------------------------------------------
# * Start Processing
#--------------------------------------------------------------------------
def start
dargor_vx_advanced_files_scene_file_start
create_command_window
@detail_window = Window_FileDetail.new
@map_window = Window_MapPreview.new
@gold_window = Window_FileGold.new
end
#--------------------------------------------------------------------------
# * Terminate Processing
#--------------------------------------------------------------------------
def terminate
dargor_vx_advanced_files_scene_file_terminate
@command_window.dispose
@detail_window.dispose
@map_window.dispose
@gold_window.dispose
end
#--------------------------------------------------------------------------
# * Create Command Window
#--------------------------------------------------------------------------
def create_command_window
@command_window = Window_Command.new(544,['Yes','No'],2)
@command_window.active = false
@command_window.visible = false
@command_window.y = 56
@command_window.z = 501
end
#--------------------------------------------------------------------------
# * Frame Update
#--------------------------------------------------------------------------
def update
@command_window.update
@detail_window.update
@map_window.update
@gold_window.update
@detail_window.visible = @command_window.visible
@map_window.visible = @command_window.visible
@gold_window.visible = @command_window.visible
if @command_window.active
update_command_window
return
end
dargor_vx_advanced_files_scene_file_update
end
#--------------------------------------------------------------------------
# * Frame Update (Command Window)
#--------------------------------------------------------------------------
def update_command_window
unless $game_map.nil?
@spriteset.update unless @spriteset.nil?
end
if Input.trigger?(Input::C)
case @command_window.index
when 0
if @saving
Sound.play_save
do_save
else
Sound.play_load
do_load
end
when 1
Sound.play_cancel
close_confirmation_window
end
end
end
#--------------------------------------------------------------------------
# * Open Confirmation Window
#--------------------------------------------------------------------------
def open_confirmation_window
window_to_top
for window in @savefile_windows
window.visible = false unless window.file_index == @index
end
mode = @saving ? 'overwrite' : 'load'
text = sprintf(Vocab::FileConfirm, mode)
@help_window.set_text(text)
@detail_window.load_gamedata(@savefile_windows[@index].filename)
@map_window.load_gamedata(@savefile_windows[@index].filename)
@gold_window.load_gamedata(@savefile_windows[@index].filename)
@command_window.visible = true
@command_window.active = true
end
#--------------------------------------------------------------------------
# * Close Confirmation Window
#--------------------------------------------------------------------------
def close_confirmation_window
self.top_row = @old_top_row
for window in @savefile_windows
window.visible = true
end
if @saving
text = Vocab::SaveMessage
else
text = Vocab::LoadMessage
end
@help_window.set_text(text)
@command_window.visible = false
@command_window.active = false
end
#--------------------------------------------------------------------------
# * Get Top Row
#--------------------------------------------------------------------------
def top_row
return @file_viewport.oy / 90
end
#--------------------------------------------------------------------------
# * Get Top Row
#--------------------------------------------------------------------------
def top_row=(index)
@file_viewport.oy = index * 90
end
#--------------------------------------------------------------------------
# * Get Bottom Row
#--------------------------------------------------------------------------
def bottom_row
return top_row + 3
end
#--------------------------------------------------------------------------
# * Get Top Row
#--------------------------------------------------------------------------
def window_to_top
@file_viewport.oy = @index * 90
@file_viewport.oy -= 56
end
#--------------------------------------------------------------------------
# * Confirm Save File
#--------------------------------------------------------------------------
def determine_savefile
if @saving
if @savefile_windows[@index].file_exist
if Advanced_Files::Confirmation
Sound.play_decision
open_confirmation_window
else
Sound.play_save
do_save
end
else
Sound.play_save
do_save
end
else
if @savefile_windows[@index].file_exist
if Advanced_Files::Confirmation
Sound.play_decision
open_confirmation_window
else
Sound.play_load
do_load
end
else
Sound.play_buzzer
return
end
end
$game_temp.last_file_index = @index
end
#--------------------------------------------------------------------------
# * Update Save File Window
#--------------------------------------------------------------------------
def update_savefile_windows
dargor_vx_advanced_files_scene_file_update_savefile_windows
# Update file viewport
if @index < top_row
if Advanced_Files::Smooth_Scroll
loop do
Graphics.update
Input.update
if Graphics.frame_count % 30 == 0
@speed = [[@speed + 1, 6].min, 0].max
end
dist = 5 * (Advanced_Files::Scroll_Speed + @speed)
@file_viewport.oy = [[@file_viewport.oy - dist, MAX_FILES * 90].min, @index * 90].max
break if @file_viewport.oy == @index * 90
end
else
@file_viewport.oy = @index * 90
end
elsif @index > bottom_row
if Advanced_Files::Smooth_Scroll
loop do
Graphics.update
Input.update
if Graphics.frame_count % 30 == 0
@speed = [[@speed + 1, 6].min, 0].max
end
dist = 5 * (Advanced_Files::Scroll_Speed + @speed)
@file_viewport.oy = [[@file_viewport.oy + dist, 0].max, (@index - 3) * 90].min
break if @file_viewport.oy == (@index - 3) * 90
end
else
@file_viewport.oy = (@index - 3) * 90
end
else
@speed = [[@speed - 1, 0].max, 6].min
end
end
#--------------------------------------------------------------------------
# * Create Filename
# file_index : save file index (0-3)
#--------------------------------------------------------------------------
def make_filename(file_index)
name = Advanced_Files::Name
extension = Advanced_Files::Extension
directory = Advanced_Files::Directory
unless FileTest.directory?(directory)
Dir.mkdir(directory)
end
return "#{directory}/#{name}#{file_index + 1}.#{extension}"
end
end
#==============================================================================
# ** Scene_Map
#------------------------------------------------------------------------------
# This class performs the map screen processing.
#==============================================================================
class Scene_Map
#--------------------------------------------------------------------------
# * Alias Listing
#--------------------------------------------------------------------------
alias dargor_vx_advanced_files_map_call_menu call_menu
alias dargor_vx_advanced_files_map_call_save call_save
#--------------------------------------------------------------------------
# * Switch to Menu Screen
#--------------------------------------------------------------------------
def call_menu
$game_system.background_bitmap = Graphics.snap_to_bitmap
$game_system.map_name = $game_map.name
dargor_vx_advanced_files_map_call_menu
end
#--------------------------------------------------------------------------
# * Switch to Menu Screen
#--------------------------------------------------------------------------
def call_save
$game_system.background_bitmap = Graphics.snap_to_bitmap
$game_system.map_name = $game_map.name
dargor_vx_advanced_files_map_call_save
end
end
Credits and Thanks
Part of the credits goes to Yeyinde for the Bitmap dump/load methods