#==============================================================================
# [PS0]截图存档
# Window_SaveFile_Plus
#------------------------------------------------------------------------------
# 一种带有截图的存档,同时可以自定义存档数量。
#==============================================================================
# [核心脚本]
# - 快速储存Bitmap的Marshal By 柳之一
#------------------------------------------------------------------------------
# [更新记录]
# - 2012.02.16 By 各种压力的猫君
# * 修正地图边缘时截图不完整的错误
# - 2012.01.28 By 各种压力的猫君
# * 去掉效率较差的双线性缩放算法;
# * 新增存档管理功能(F5键,复制/移动/删除存档)
# - 2011.12.27 By 各种压力的猫君
# * 补上截图阴影;
# * 新增“不缩放”截图(推荐使用,尤其是大分辨率);
# * 修正选择不存在的存档时存档列表窗口卡死以及奇怪的SE;
# * 新增“存档中”提示窗口、覆盖存档提示、删除存档功能(Z键,对应键盘D)
# - 2011.12.26 By 各种压力的猫君
# * 功能齐全的测试版
# - 2011.12.16 By 各种压力的猫君
# * 移植至RGSS3,遵循PS0协议;
# * 丰富自定义选项,整合双线性插值算法精简版
# - 2008.05.26 By 沉影不器
# * 蓝本(VX新截图存档)
#------------------------------------------------------------------------------
# [使用方法]
# - 删除原Scene_File、Window_SaveFile 并将本脚本插入到原Scene_File位置。
# - 或者直接将本脚本插入到MAIN以上,并确保本脚本位于上述两个脚本以下。
#==============================================================================
$_PS0 = {} if $_PS0 == nil
$_PS0["Window_SaveFile_Plus"] = 20120216
#==============================================================================
# [PS0] 通用配置模块
#==============================================================================
module PS0
module Window_SaveFile_Plus
# 最大存档数(范围正整数)
MAX_SAVE = 16
# 存档目录(默认值 "Saves/";根目录 "")
SAVE_DIR = "Saves/"
# 无存档时显示的文字
NO_DATA = "无存档"
# 保存时显示的信息
SAVE_NOW = "存档中..."
# 复制存档时的帮助文字
HELP_COPY = "要复制到哪个位置?"
# 移动存档时的帮助文字
HELP_MOVE = "要移动到哪个位置?"
# 是否显示存档中窗口(true:显示;false:不显示)
# - 分辨率较大时建议显示
SHOW_SAVE_NOW = false
# 截图缩放使用的插值算法
# - "NN" 最邻近(速度最快,质量最差,RM默认算法)
# - "NZ" 不缩放(速度快,质量好,以主角为中心切边,非全屏)
Zoom_Type = "NZ"
# 双线性插值能获得更好的截图缩放质量,但所需时间较最邻近插值更长。
# 缩略图尺寸(范围整数,单位像素)
# - VA默认分辨率(544×416)推荐使用340×260
# - VA最大分辨率(640×480)推荐使用425×325
# - 本脚本兼容分辨率解放,窗口大小将自动计算。
# 请自行计算截图分辨率,注意要确保宽高比一致,
# 若使用“不缩放”模式则可以不保持一致。
Thumbnail_Width = 340 # 宽度
Thumbnail_Height = 260 # 高度
# 缩略图位置微调(范围整数,单位像素)
Thumbnail_ox = -2 # 横向
Thumbnail_oy = -2-32 # 纵向
# 各窗口切换时的渐变帧数
TRANS_DURATION = 5
end
end
#==============================================================================
# [核心脚本] 快速储存Bitmap的Marshal By 柳之一
#==============================================================================
class Font
def marshal_dump
end
def marshal_load(obj)
end
end
class Bitmap
RtlMoveMemory_pi = Win32API.new('kernel32', 'RtlMoveMemory', 'pii', 'i')
RtlMoveMemory_ip = Win32API.new('kernel32', 'RtlMoveMemory', 'ipi', 'i')
def _dump(limit)
data = "rgba" * width * height
RtlMoveMemory_pi.call(data, address, data.length)
[width, height, Zlib::Deflate.deflate(data)].pack("LLa*")
end
def self._load(str)
w, h, zdata = str.unpack("LLa*")
b = self.new(w, h)
RtlMoveMemory_ip.call(b.address, Zlib::Inflate.inflate(zdata), w * h * 4)
return b
end
def address
buffer, ad = "rgba", 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_Temp
#==============================================================================
class Game_Temp
attr_accessor :save_bitmap
attr_accessor :save_snapshoot
alias new_initialize initialize
def initialize
new_initialize
@save_bitmap = Bitmap.new(1, 1)
@save_snapshoot = Bitmap.new(1, 1)
end
end
#==============================================================================
# ■ SceneManager
#==============================================================================
module SceneManager
def self.snapshot_for_save
$game_temp.save_bitmap = Graphics.snap_to_bitmap
unless FileTest.exist?(PS0::Window_SaveFile_Plus::SAVE_DIR)
Dir.mkdir(PS0::Window_SaveFile_Plus::SAVE_DIR)
end
end
end
#==============================================================================
# ■ Scene_Map
#==============================================================================
class Scene_Map < Scene_Base
alias save_terminate terminate
def terminate
SceneManager.snapshot_for_save
save_terminate
end
end
#==============================================================================
# ■ DataManager
#==============================================================================
module DataManager
def self.save_file_exists?
!Dir.glob(PS0::Window_SaveFile_Plus::SAVE_DIR + 'Save*.rvdata2').empty?
end
def self.make_filename(index)
sprintf(PS0::Window_SaveFile_Plus::SAVE_DIR + "Save%02d.rvdata2", index + 1)
end
#--------------------------------------------------------------------------
# ● セーブヘッダの作成
#--------------------------------------------------------------------------
def self.make_save_header
d_rect = Rect.new(0, 0, PS0::Window_SaveFile_Plus::Thumbnail_Width,
PS0::Window_SaveFile_Plus::Thumbnail_Height)
case PS0::Window_SaveFile_Plus::Zoom_Type
when "NN"
s_rect = $game_temp.save_bitmap.rect
$game_temp.save_snapshoot = Bitmap.new(d_rect.width, d_rect.height)
$game_temp.save_snapshoot.stretch_blt(d_rect, $game_temp.save_bitmap, s_rect)
when "NZ"
x = [$game_player.screen_x - d_rect.width/2, 0].max
x = [x, Graphics.width - d_rect.width].min
y = [$game_player.screen_y - d_rect.height/2, 0].max
y = [y, Graphics.height - d_rect.height].min
s_rect = Rect.new(x, y, d_rect.width, d_rect.height)
$game_temp.save_snapshoot = Bitmap.new(d_rect.width, d_rect.height)
$game_temp.save_snapshoot.blt(0, 0, $game_temp.save_bitmap, s_rect)
end
header = {}
header[:characters] = $game_party.characters_for_savefile
header[:playtime_s] = $game_system.playtime_s
header[:snapshoot] = $game_temp.save_snapshoot
header
end
#--------------------------------------------------------------------------
# ● セーブの実行
#--------------------------------------------------------------------------
def self.save_game(index)
saving_window = Window_Saving.new
Graphics.update
begin
save_game_without_rescue(index)
rescue
delete_save_file(index)
false
end
saving_window.dispose
return true
end
end
#==============================================================================
# ■ Window_Yes_Or_No
#------------------------------------------------------------------------------
# 提供“是”、“否”两个选项的窗口(替换、删除存档用)
#==============================================================================
class Window_Yes_Or_No < Window_HorzCommand
#--------------------------------------------------------------------------
# ● オブジェクト初期化
#--------------------------------------------------------------------------
def initialize(yes, no)
@yes = yes
@no = no
super(130, 0)
self.visible = false
self.active = false
@index = 0
end
#--------------------------------------------------------------------------
# ● 桁数の取得
#--------------------------------------------------------------------------
def col_max
return 2
end
#--------------------------------------------------------------------------
# ● コマンドリストの作成
#--------------------------------------------------------------------------
def make_command_list
add_command(@yes, :yes)
add_command(@no, :cancel)
end
#--------------------------------------------------------------------------
# ● 決定ボタンが押されたときの処理
#--------------------------------------------------------------------------
def process_ok
Input.update
call_ok_handler
end
#--------------------------------------------------------------------------
# ● 按下取消键时的处理
#--------------------------------------------------------------------------
def process_cancel
Input.update
call_cancel_handler
end
#--------------------------------------------------------------------------
# ● 启用窗口
#--------------------------------------------------------------------------
def activate
temp = self.y + self.height - Graphics.height
if temp > 0
self.y -= (temp + 12)
end
self.active = true
self
end
end
#==============================================================================
# ■ Window_Saving
#------------------------------------------------------------------------------
# 显示保存信息的窗口
#==============================================================================
class Window_Saving < Window_Base
#--------------------------------------------------------------------------
# ● オブジェクト初期化
#--------------------------------------------------------------------------
def initialize
w = PS0::Window_SaveFile_Plus::SAVE_NOW.length * 16 + 32
x = (Graphics.width - w)/2
y = (Graphics.height - fitting_height(1))/2
super(x, y, w, fitting_height(1))
self.visible = PS0::Window_SaveFile_Plus::SHOW_SAVE_NOW
draw_text_ex(4, 0, PS0::Window_SaveFile_Plus::SAVE_NOW)
end
end
#==============================================================================
# ■ Window_SaveManagerCommand
#------------------------------------------------------------------------------
# 存档管理窗口
#==============================================================================
class Window_SaveManagerCommand < Window_Command
#--------------------------------------------------------------------------
# ● 初始化对象
#--------------------------------------------------------------------------
def initialize(*args)
@copy, @move, @delete, @cancel = args[0..3]
super(130, 0)
self.visible = false
self.active = false
@index = 0
end
#--------------------------------------------------------------------------
# ● 获取窗口的宽度
#--------------------------------------------------------------------------
def window_width
return 100
end
#--------------------------------------------------------------------------
# ● 获取项目数
#--------------------------------------------------------------------------
def item_max
return 4
end
#--------------------------------------------------------------------------
# ● 生成指令列表
#--------------------------------------------------------------------------
def make_command_list
add_command(@copy, :copy )
add_command(@move, :move )
add_command(@delete, :delete)
add_command(@cancel, :cancel)
end
#--------------------------------------------------------------------------
# ● 按下确定键时的处理
#--------------------------------------------------------------------------
def process_ok
Input.update
call_ok_handler
end
#--------------------------------------------------------------------------
# ● 启用窗口
#--------------------------------------------------------------------------
def activate
temp = self.y + self.height - Graphics.height
if temp > 0
self.y -= (temp + 12)
end
self.active = true
self
end
end
#==============================================================================
# ■ Window_FileCommand
#------------------------------------------------------------------------------
# 截图存档左侧的选择窗口。
#==============================================================================
class Window_FileCommand < Window_Command
#--------------------------------------------------------------------------
# ● オブジェクト初期化
#--------------------------------------------------------------------------
def initialize
super(0, 0)
end
#--------------------------------------------------------------------------
# ● ウィンドウ幅の取得
#--------------------------------------------------------------------------
def window_height
return Graphics.height-fitting_height(1)
end
#--------------------------------------------------------------------------
# ● 表示行数の取得
#--------------------------------------------------------------------------
def visible_line_number
item_max
end
#--------------------------------------------------------------------------
# ● コマンドリストの作成
#--------------------------------------------------------------------------
def make_command_list
add_main_commands
end
#--------------------------------------------------------------------------
# ● 主要コマンドをリストに追加
#--------------------------------------------------------------------------
def add_main_commands
for i in 1..PS0::Window_SaveFile_Plus::MAX_SAVE
if i < 10
text = Vocab::File + " 0" + i.to_s
else
text = Vocab::File + " " + i.to_s
end
add_command(text, :file)
end
end
#--------------------------------------------------------------------------
# ● 決定ボタンが押されたときの処理
#--------------------------------------------------------------------------
def process_ok
end
end
#==============================================================================
# ■ Window_SaveFile
#------------------------------------------------------------------------------
# セーブ画面およびロード画面で表示する、セーブファイルのウィンドウです。
#==============================================================================
class Window_SaveFile < Window_Base
#--------------------------------------------------------------------------
# ● オブジェクト初期化
# index : セーブファイルのインデックス
#--------------------------------------------------------------------------
def initialize(index)
super(160, 0, Graphics.width-160, Graphics.height-fitting_height(1))
@file_index = index
@selected = true
refresh
end
#--------------------------------------------------------------------------
# ● リフレッシュ
#--------------------------------------------------------------------------
def refresh
contents.clear
change_color(normal_color)
w = (self.width-PS0::Window_SaveFile_Plus::Thumbnail_Width-16)/2
h = (self.height-PS0::Window_SaveFile_Plus::Thumbnail_Height-16)/2
width = w + PS0::Window_SaveFile_Plus::Thumbnail_ox
height = h + PS0::Window_SaveFile_Plus::Thumbnail_oy
draw_shadow(width+5, height+5)
draw_text((self.width-32-PS0::Window_SaveFile_Plus::NO_DATA.length*16)/2,
self.height/2-32, PS0::Window_SaveFile_Plus::NO_DATA.length*32,
line_height, PS0::Window_SaveFile_Plus::NO_DATA)
draw_party_characters(32, Graphics.height-fitting_height(1)-32)
draw_playtime(-10, contents.height - line_height-10, contents.width - 4, 2)
draw_snapshoot(width, height)
end
#--------------------------------------------------------------------------
# ● パーティキャラの描画
#--------------------------------------------------------------------------
def draw_party_characters(x, y)
header = DataManager.load_header(@file_index)
return unless header
header[:characters].each_with_index do |data, i|
draw_character(data[0], data[1], x + i * 48, y)
end
end
#--------------------------------------------------------------------------
# ● プレイ時間の描画
#--------------------------------------------------------------------------
def draw_playtime(x, y, width, align)
header = DataManager.load_header(@file_index)
return unless header
draw_text(x, y, width, line_height, header[:playtime_s], 2)
end
#--------------------------------------------------------------------------
# ● 绘制截图
#--------------------------------------------------------------------------
def draw_snapshoot(x, y)
header = DataManager.load_header(@file_index)
return unless header
bitmap = header[:snapshoot]
contents.blt(x, y, bitmap, bitmap.rect)
bitmap.dispose
end
#--------------------------------------------------------------------------
# ● 绘制阴影
#--------------------------------------------------------------------------
def draw_shadow(x, y)
header = DataManager.load_header(@file_index)
return unless header
contents.fill_rect(x, y, PS0::Window_SaveFile_Plus::Thumbnail_Width,
PS0::Window_SaveFile_Plus::Thumbnail_Height, Color.new(0, 0, 0))
contents.blur
end
end
#==============================================================================
# ■ Scene_File
#------------------------------------------------------------------------------
# セーブ画面とロード画面の共通処理を行うクラスです。
#==============================================================================
class Scene_File < Scene_MenuBase
#--------------------------------------------------------------------------
# ● 開始処理
#--------------------------------------------------------------------------
def start
super
create_help_window
create_savefile_viewport
create_command_window
create_savefile_window
create_manager_window
create_replace_window
create_delete_window
end
#--------------------------------------------------------------------------
# ● 終了処理
#--------------------------------------------------------------------------
def terminate
super
@savefile_viewport.dispose
@savefile_window.dispose
@command_window.dispose
@window_manager.dispose
@window_replace.dispose
@window_delete.dispose
end
#--------------------------------------------------------------------------
# ● フレーム更新
#--------------------------------------------------------------------------
def update
super
update_savefile_selection
end
#--------------------------------------------------------------------------
# ● 创建替换窗口
#--------------------------------------------------------------------------
def create_replace_window
@window_replace = Window_Yes_Or_No.new("替换", "取消")
@window_replace.set_handler(:yes, method(:do_replace))
@window_replace.set_handler(:cancel, method(:do_cancel))
end
#--------------------------------------------------------------------------
# ● 创建删除窗口
#--------------------------------------------------------------------------
def create_delete_window
@window_delete = Window_Yes_Or_No.new("删除", "取消")
@window_delete.set_handler(:yes, method(:do_delete))
@window_delete.set_handler(:cancel, method(:do_return_manager))
@window_delete.x += 40
end
#--------------------------------------------------------------------------
# ● 创建管理窗口
#--------------------------------------------------------------------------
def create_manager_window
@window_manager = Window_SaveManagerCommand.new("复制", "移动", "删除", "取消")
@window_manager.set_handler(:copy , method(:on_copy?))
@window_manager.set_handler(:move , method(:on_move?))
@window_manager.set_handler(:delete, method(:on_delete?))
@window_manager.set_handler(:cancel, method(:do_cancel))
end
#--------------------------------------------------------------------------
# ● ヘルプウィンドウの作成
#--------------------------------------------------------------------------
def create_help_window
@help_window = Window_Help.new(1)
@help_window.set_text(help_window_text)
end
#--------------------------------------------------------------------------
# ● ヘルプウィンドウのテキストを取得
#--------------------------------------------------------------------------
def help_window_text
return ""
end
#--------------------------------------------------------------------------
# ● セーブファイルビューポートの作成
#--------------------------------------------------------------------------
def create_savefile_viewport
@savefile_viewport = Viewport.new
@savefile_viewport.rect.y = @help_window.height
@savefile_viewport.rect.height -= @help_window.height
end
#--------------------------------------------------------------------------
# ● セーブファイルウィンドウの作成
#--------------------------------------------------------------------------
def create_savefile_window
@savefile_window = Window_SaveFile.new(@index)
@savefile_window.viewport = @savefile_viewport
end
#--------------------------------------------------------------------------
# ● 生成存档列表窗口
#--------------------------------------------------------------------------
def create_command_window
@command_window = Window_FileCommand.new
@command_window.index = first_savefile_index
@index = @command_window.index
@command_window.viewport = @savefile_viewport
@command_window.set_handler(:file, method(:on_savefile_ok))
end
#--------------------------------------------------------------------------
# ● セーブファイル選択の更新
#--------------------------------------------------------------------------
def update_savefile_selection
if @source_index != nil
if Input.trigger?(:C)
if @index == @source_index
Sound.play_buzzer
elsif FileTest.exist?(DataManager.make_filename(@index))
Graphics.freeze
@command_window.deactivate
@window_replace.y = 72 + @index * 24
@window_replace.activate
@window_replace.visible = true
@window_replace.refresh
Sound.play_ok
Graphics.transition(PS0::Window_SaveFile_Plus::TRANS_DURATION)
else
return on_copy_ok
end
elsif Input.trigger?(:B)
return do_return_manager
end
else
if Input.trigger?(:C)
if self.is_a?(Scene_Save) and FileTest.exist?(DataManager.make_filename(@index))
Graphics.freeze
@command_window.deactivate
@window_replace.y = 72 + @index * 24
@window_replace.activate
@window_replace.visible = true
@window_replace.refresh
Sound.play_ok
Graphics.transition(PS0::Window_SaveFile_Plus::TRANS_DURATION)
else
return on_savefile_ok
end
elsif Input.trigger?(:B)
return on_savefile_cancel
elsif Input.trigger?(:F5)
unless @window_manager.active == true or
@window_delete.active == true or
@window_replace.active == true
return on_manager?
end
end
end
@need_refresh = true if @index != @command_window.index
if @need_refresh
Graphics.freeze
@index = @command_window.index
@savefile_window.dispose
create_savefile_window
@need_refresh = false
Graphics.transition(PS0::Window_SaveFile_Plus::TRANS_DURATION)
end
end
#--------------------------------------------------------------------------
# ● セーブファイル[決定]
#--------------------------------------------------------------------------
def on_savefile_ok
end
#--------------------------------------------------------------------------
# ● セーブファイル[キャンセル]
#--------------------------------------------------------------------------
def on_savefile_cancel
Sound.play_cancel
return_scene
end
#--------------------------------------------------------------------------
# ● セーブファイル[決定]
#--------------------------------------------------------------------------
def on_copy_ok
Graphics.freeze
source_name = DataManager.make_filename(@source_index)
new_name = DataManager.make_filename(@index)
case @source_type
when "copy"
# 复制存档文件(API)
Win32API.new('kernel32',"CopyFileA",'ppl','').call(source_name,new_name,0)
when "move"
# 重命名存档
File.rename(source_name, new_name)
end
# 返回
@help_window.set_text(help_window_text)
@source_index = nil
do_return_savelist
end
#--------------------------------------------------------------------------
# ● セーブファイル[复制]
#--------------------------------------------------------------------------
def on_copy?
Graphics.freeze
@help_window.set_text(PS0::Window_SaveFile_Plus::HELP_COPY)
@source_index = @index
@source_type = "copy"
do_return_savelist
end
#--------------------------------------------------------------------------
# ● セーブファイル[移动]
#--------------------------------------------------------------------------
def on_move?
Graphics.freeze
@help_window.set_text(PS0::Window_SaveFile_Plus::HELP_MOVE)
@source_index = @index
@source_type = "move"
do_return_savelist
end
#--------------------------------------------------------------------------
# ● セーブファイル[管理]
#--------------------------------------------------------------------------
def on_manager?
if FileTest.exist?(DataManager.make_filename(@index))
Graphics.freeze
@command_window.deactivate
@window_manager.y = 72 + @index * 24
@window_manager.activate
@window_manager.visible = true
@window_manager.refresh
Sound.play_ok
Graphics.transition(PS0::Window_SaveFile_Plus::TRANS_DURATION)
else
Sound.play_buzzer
end
end
#--------------------------------------------------------------------------
# ● セーブファイル[删除]
#--------------------------------------------------------------------------
def on_delete?
Graphics.freeze
@window_manager.deactivate
@command_window.deactivate
@window_delete.y = 72 + 72 + @index * 24
@window_delete.activate
@window_delete.visible = true
@window_delete.refresh
Sound.play_ok
Graphics.transition(PS0::Window_SaveFile_Plus::TRANS_DURATION)
end
#--------------------------------------------------------------------------
# ● 删除
#--------------------------------------------------------------------------
def do_delete
Graphics.freeze
File.delete(DataManager.make_filename(@index))
@window_delete.index = 0
@window_manager.index = 0
@window_delete.visible = false
@window_manager.visible = false
@window_delete.deactivate
@window_manager.deactivate
@command_window.activate
@need_refresh = true
Sound.play_save
if DataManager.save_file_exists?
Graphics.transition(PS0::Window_SaveFile_Plus::TRANS_DURATION)
else
return_scene
end
end
#--------------------------------------------------------------------------
# ● 替换
#--------------------------------------------------------------------------
def do_replace
Graphics.freeze
if @source_index != nil
return on_copy_ok
else
return on_savefile_ok
end
@window_replace.visible = false
@window_replace.deactivate
@need_refresh = true
end
#--------------------------------------------------------------------------
# ● 取消
#--------------------------------------------------------------------------
def do_cancel
Graphics.freeze
Sound.play_cancel
@window_delete.index = 0
@window_replace.index = 0
@window_manager.index = 0
@window_delete.visible = false
@window_replace.visible = false
@window_manager.visible = false
@window_delete.deactivate
@window_replace.deactivate
@window_manager.deactivate
@command_window.activate
Graphics.transition(PS0::Window_SaveFile_Plus::TRANS_DURATION)
end
#--------------------------------------------------------------------------
# ● 返回管理菜单
#--------------------------------------------------------------------------
def do_return_manager
Graphics.freeze
@help_window.set_text(help_window_text)
@command_window.index = @source_index unless @source_index == nil
@source_index = nil
@source_type = nil
@command_window.deactivate
@window_delete.index = 0
@window_replace.index = 0
@window_delete.visible = false
@window_replace.visible = false
@window_delete.deactivate
@window_replace.deactivate
@window_manager.y = 72 + @index * 24
@window_manager.activate
@window_manager.visible = true
@window_manager.refresh
Sound.play_cancel
Graphics.transition(PS0::Window_SaveFile_Plus::TRANS_DURATION)
end
#--------------------------------------------------------------------------
# ● 返回文件列表(复制、移动 用)
#--------------------------------------------------------------------------
def do_return_savelist
@window_manager.visible = false
@window_manager.deactivate
@command_window.activate
@need_refresh = true
Sound.play_ok
end
end
#==============================================================================
# [PS0] End of Script
#==============================================================================