#==============================================================================
#
# ■盗贼开锁(迷你游戏) □Ver1.01 □製作者:月紳士
# RPGツクールVX Ace用 RGSS3スクリプト
#
# ●…上書き ◎…エイリアス ○…新規と新規への上書き
#
# ※二次配布禁止!配布元には利用規約があります。必ずそちらを見てください。
# 作者主页:http://tsukishinshi.blog73.fc2.com/
#==============================================================================
=begin
创建一个开锁的场景,可以作为盗贼角色的迷你游戏。
#------------------------------------------------------------------------------
使用脚本(详情在下面)后显示一个开锁场景。
指针左右往返移动,当指针移动到成功区域时,玩家按下确定键可以开锁。
开启所有锁孔时,开启一个开关,代表成功开锁。
失败后,开锁器(一个物品)会被消耗
失败后还可以再次尝试,只要你还有开锁器。
你也可以使用返回键退出开锁场景。
成功/失败时,会开启/关闭一个开关。(在下面设定)
可以在事件的分支条件里使用。
#------------------------------------------------------------------------------
使用脚本显示开锁画面
call_picking(成功区域宽度, 速度, 锁孔数)
成功区域宽度 : 可以成功开锁的区域宽度。
速度 : 指针移动速度。
锁孔数 : 必须要成功多少回才能开锁。
例子:
call_picking(15, 2, 3)
这些参数决定了开锁的难易度
在测试工程时,可以使用以下操作:
上方向键 : 指针移动速度 + 0.5
下方向键 : 指针移动速度 - 0.5
左方向键 : 成功区域宽度 - 1
右方向键 : 成功区域宽度 + 1
便于你调整开锁的难易度。
建议使用变量来改变开锁的参数。
=end
module OpenLock_Of_TheThief
#==============================================================================
# □ 设定部分
#==============================================================================
PICKING_SUCCESS_SWITCH_ID = 1
## 开锁结果的开关id。
# 开锁成功后开关开启,否则开关关闭
LOCKPICK_ITEM_ID = 1
## 开锁需要的物品的id(当做开锁器),开锁需要消耗该物品
# 开锁画面中会显示开锁器物品的图标。
CLOSE_PIN_ICON_ID = 126
OPEN_PIN_ICON_ID = 125
## 未解锁锁孔和已解锁锁孔的图标index。
end
#==============================================================================
# ■ Sound
#------------------------------------------------------------------------------
# 効果音を演奏するモジュールです。グローバル変数 $data_system からデータベー
# スで設定された SE の内容を取得し、演奏します。
#==============================================================================
module Sound
# 成功时播放的音效(开锁)
def self.play_lockpicking_success
Audio.se_play("Audio/SE/Key", 80, 100)
end
# 失败时播放的音效(消耗开锁器)
def self.play_lockpicking_failure
Audio.se_play("Audio/SE/Blow5", 80, 150)
end
end
#==============================================================================
# ■ Window_OpenLock_Status
#------------------------------------------------------------------------------
# 錠前破りシーンのステータスを表示するウインドウです。
#==============================================================================
class Window_OpenLock_Status < Window_Base
#--------------------------------------------------------------------------
# ● オブジェクト初期化
#-------------------------------------------------------------------------
def initialize(x, y, width, pin)
width += standard_padding * 2
x = (Graphics.width - width) / 2 if x == :center # センタリング時
y = (Graphics.height - window_height) / 2 if y == :center # センタリング時
super(x, y, width, window_height)
self.opacity = 0
@pin = pin
create_pin
refresh
end
#--------------------------------------------------------------------------
# ● ウインドウの高さ
#--------------------------------------------------------------------------
def window_height
line_height * 4 + standard_padding * 2
end
#--------------------------------------------------------------------------
# 〇 ピンの作成
#--------------------------------------------------------------------------
def create_pin
@pin_status = Array.new(@pin, false)
end
#--------------------------------------------------------------------------
# 〇 ピンの解除
#--------------------------------------------------------------------------
def open_pin
return unless @pin_status.include?(false)
loop do
index = rand(@pin)
if @pin_status[index] == false
@pin_status[index] = true
break
end
end
refresh
end
#--------------------------------------------------------------------------
# 〇 開錠したか?
#--------------------------------------------------------------------------
def openlock?
!@pin_status.include?(false)
end
#--------------------------------------------------------------------------
# ● リフレッシュ
#--------------------------------------------------------------------------
def refresh
contents.clear
x = 0
@pin_status.each do |pin|
if pin
draw_icon(OpenLock_Of_TheThief::OPEN_PIN_ICON_ID, x, 0)
else
draw_icon(OpenLock_Of_TheThief::CLOSE_PIN_ICON_ID, x, 0)
end
x += 24
end
item = $data_items[OpenLock_Of_TheThief::LOCKPICK_ITEM_ID]
amount = $game_party.item_number(item)
x = contents_width - 40 - 35
draw_icon(item.icon_index, x, line_height * 3)
draw_text(0, line_height * 3, contents_width, line_height, "× ", 2)
draw_text(0, line_height * 3, contents_width, line_height, amount, 2)
end
end
#==============================================================================
# ■ Window_Movement_Bar
#------------------------------------------------------------------------------
# 移動するカーソルを指定された範囲で止めると成功扱いになるウインドウです。
#==============================================================================
class Window_Movement_Bar < Window_Base
#--------------------------------------------------------------------------
# ○ 公開インスタンス変数
#--------------------------------------------------------------------------
attr_accessor :speed # カーソルの移動速度
attr_reader :safe_range_width # 成功範囲の幅
#--------------------------------------------------------------------------
# ● オブジェクト初期化
#-------------------------------------------------------------------------
def initialize(x, y, width, safe_range_width, speed)
@safe_range_width = [safe_range_width, safe_range_min].max
@speed = speed
x = (Graphics.width - width) / 2 if x == :center # センタリング時
y = (Graphics.height - window_height) / 2 if y == :center # センタリング時
super(x, y, width, window_height)
create_safe_range
create_original_cursor
@handler = {}
@post = 0
self.activate
end
#--------------------------------------------------------------------------
# ● 解放
#--------------------------------------------------------------------------
def dispose
super
@original_cursor.dispose unless @original_cursor.disposed?
end
#--------------------------------------------------------------------------
# ● ウインドウの高さ
#--------------------------------------------------------------------------
def window_height
line_height + standard_padding * 2
end
#--------------------------------------------------------------------------
# 〇 カーソルの幅
#--------------------------------------------------------------------------
def cursor_width
2
end
#--------------------------------------------------------------------------
# 〇 成功範囲の最低幅
#--------------------------------------------------------------------------
def safe_range_min
cursor_width + 2
end
#--------------------------------------------------------------------------
# 〇 カーソルの移動範囲
#--------------------------------------------------------------------------
def moving_range
contents_width - cursor_width
end
#--------------------------------------------------------------------------
# 〇 成功範囲配置時に両端から離す距離
# ※ 移動範囲の両端に成功範囲が接すると簡単になってしまう為
#--------------------------------------------------------------------------
def safe_range_padding
cursor_width + 2
end
#--------------------------------------------------------------------------
# 〇 カーソル作成
#--------------------------------------------------------------------------
def create_original_cursor
@original_cursor = Sprite.new
@original_cursor.viewport = self.viewport
@original_cursor.bitmap = Bitmap.new(cursor_width, contents_height)
@original_cursor.bitmap.fill_rect(@original_cursor.bitmap.rect, crisis_color)
@original_cursor.x = self.x + standard_padding
@original_cursor.y = self.y + standard_padding
@original_cursor.z = self.z + 10
end
#--------------------------------------------------------------------------
# 〇 成功位置の作成
#--------------------------------------------------------------------------
def create_safe_range
contents.clear
first = safe_range_padding + rand(moving_range - @safe_range_width - safe_range_padding)
@safe_range = Range.new(first, first + @safe_range_width)
contents.fill_rect(0, 2, contents_width, contents_height - 4, gauge_back_color)
contents.fill_rect(@safe_range.first + cursor_width, 2, @safe_range_width - cursor_width, contents_height - 4, mp_gauge_color1)
end
#--------------------------------------------------------------------------
# ● フレーム更新
#--------------------------------------------------------------------------
def update
process_cursor_move
super
process_handling
end
#--------------------------------------------------------------------------
# 〇 カーソルの座標
#--------------------------------------------------------------------------
def cursor_post
if @post > moving_range
return (@post - moving_range * 2).abs
else
return @post
end
end
#--------------------------------------------------------------------------
# ● カーソルの移動処理
#--------------------------------------------------------------------------
def process_cursor_move
@original_cursor.x = self.x + standard_padding
@original_cursor.y = self.y + standard_padding
@original_cursor.z = self.z + 10
return unless active
@post += @speed
@post = 0 if @post > moving_range * 2
@original_cursor.x = self.x + standard_padding + cursor_post
end
#--------------------------------------------------------------------------
# ● 動作に対応するハンドラの設定
# method : ハンドラとして設定するメソッド (Method オブジェクト)
#--------------------------------------------------------------------------
def set_handler(symbol, method)
@handler[symbol] = method
end
#--------------------------------------------------------------------------
# ● ハンドラの存在確認
#--------------------------------------------------------------------------
def handle?(symbol)
@handler.include?(symbol)
end
#--------------------------------------------------------------------------
# ● ハンドラの呼び出し
#--------------------------------------------------------------------------
def call_handler(symbol)
@handler[symbol].call if handle?(symbol)
end
#--------------------------------------------------------------------------
# ● 決定やキャンセルなどのハンドリング処理
#--------------------------------------------------------------------------
def process_handling
return unless open? && active
return process_ok if ok_enabled? && Input.trigger?(:C)
return process_cancel if cancel_enabled? && Input.trigger?(:B)
return process_pagedown if handle?(:pagedown) && Input.trigger?(:R)
return process_pageup if handle?(:pageup) && Input.trigger?(:L)
return process_down if handle?(:DOWN) && Input.trigger?(:DOWN)
return process_up if handle?(:UP) && Input.trigger?(:UP)
return process_right if handle?(:RIGHT) && Input.trigger?(:RIGHT)
return process_left if handle?(:LEFT) && Input.trigger?(:LEFT)
return process_shift if handle?(:shift) && Input.trigger?(:A)
end
#--------------------------------------------------------------------------
# ● 決定処理の有効状態を取得
#--------------------------------------------------------------------------
def ok_enabled?
handle?(:ok)
end
#--------------------------------------------------------------------------
# ● キャンセル処理の有効状態を取得
#--------------------------------------------------------------------------
def cancel_enabled?
handle?(:cancel)
end
#--------------------------------------------------------------------------
# ● 決定ボタンが押されたときの処理
#--------------------------------------------------------------------------
def process_ok
Sound.play_ok
deactivate
Input.update
call_ok_handler
end
#--------------------------------------------------------------------------
# ● 決定ハンドラの呼び出し
#--------------------------------------------------------------------------
def call_ok_handler
call_handler(:ok)
end
#--------------------------------------------------------------------------
# ● キャンセルボタンが押されたときの処理
#--------------------------------------------------------------------------
def process_cancel
Sound.play_cancel
Input.update
deactivate
call_cancel_handler
end
#--------------------------------------------------------------------------
# ● キャンセルハンドラの呼び出し
#--------------------------------------------------------------------------
def call_cancel_handler
call_handler(:cancel)
end
#--------------------------------------------------------------------------
# ● L ボタン(PageUp)が押されたときの処理
#--------------------------------------------------------------------------
def process_pageup
Sound.play_cursor
Input.update
deactivate
call_handler(:pageup)
end
#--------------------------------------------------------------------------
# ● R ボタン(PageDown)が押されたときの処理
#--------------------------------------------------------------------------
def process_pagedown
Sound.play_cursor
Input.update
deactivate
call_handler(:pagedown)
end
#--------------------------------------------------------------------------
# ○ 下キーが押されたときの処理
#--------------------------------------------------------------------------
def process_down
Input.update
call_handler(:DOWN)
end
#--------------------------------------------------------------------------
# ○ 上キーが押されたときの処理
#--------------------------------------------------------------------------
def process_up
Input.update
call_handler(:UP)
end
#--------------------------------------------------------------------------
# ○ 右キーが押されたときの処理
#--------------------------------------------------------------------------
def process_right
Input.update
call_handler(:RIGHT)
end
#--------------------------------------------------------------------------
# ○ 左キーが押されたときの処理
#--------------------------------------------------------------------------
def process_left
Input.update
call_handler(:LEFT)
end
#--------------------------------------------------------------------------
# ○ A ボタン(Shift)が押されたときの処理
#--------------------------------------------------------------------------
def process_shift
Input.update
call_handler(:shift)
end
#--------------------------------------------------------------------------
# ● リフレッシュ
#--------------------------------------------------------------------------
def refresh
contents.clear
draw_all_items
end
#--------------------------------------------------------------------------
# ○ 成功範囲を狭く作り直す
#--------------------------------------------------------------------------
def safe_range_narrow
@safe_range_width = [safe_range_min, @safe_range_width - 1].max
create_safe_range
end
#--------------------------------------------------------------------------
# ○ 成功範囲を広く作り直す
#--------------------------------------------------------------------------
def safe_range_wide
@safe_range_width += 1
create_safe_range
end
end
#==============================================================================
# ■ Window_Picking
#------------------------------------------------------------------------------
# 錠前破りシーンで成否判定を行う為のウインドウです。
#==============================================================================
class Window_Picking < Window_Movement_Bar
#--------------------------------------------------------------------------
# ● 決定ボタンが押されたときの処理
#--------------------------------------------------------------------------
def process_ok
if $game_party.has_item?($data_items[OpenLock_Of_TheThief::LOCKPICK_ITEM_ID])
if @safe_range.include?(cursor_post)
Sound.play_lockpicking_success
@status_window.open_pin
Graphics.wait(20)
if @status_window.openlock?
Graphics.wait(20)
else
create_safe_range
end
else
Sound.play_lockpicking_failure
$game_party.gain_item($data_items[OpenLock_Of_TheThief::LOCKPICK_ITEM_ID], -1)
@status_window.refresh
Graphics.wait(20)
end
call_ok_handler
else
Sound.play_buzzer
end
end
#--------------------------------------------------------------------------
# ○ ステータスウインドウの設定
#--------------------------------------------------------------------------
def status_window=(status_window)
@status_window = status_window
end
end
#==============================================================================
# ■ Scene_Picking
#------------------------------------------------------------------------------
# 宝箱や扉の錠破りを行うシーンです。
#==============================================================================
class Scene_Picking < Scene_MenuBase
#--------------------------------------------------------------------------
# ● 開始処理
#--------------------------------------------------------------------------
def start
super
create_windows
end
#--------------------------------------------------------------------------
# ● 準備
#--------------------------------------------------------------------------
def prepare(width, safe_range_width, speed, pin)
@width = width
@safe_range_width = safe_range_width
@speed = speed
@pin = pin
end
#--------------------------------------------------------------------------
# ○ ウィンドウの作成
#--------------------------------------------------------------------------
def create_windows
create_status_window
create_picking_window
end
#--------------------------------------------------------------------------
# ○ ステータスウインドウの作成
#--------------------------------------------------------------------------
def create_status_window
wx = :center
wy = :center
@status_window = Window_OpenLock_Status.new(wx, wy, @width, @pin)
end
#--------------------------------------------------------------------------
# ○ 錠前破り判定ウインドウの作成
#--------------------------------------------------------------------------
def create_picking_window
wx = :center
wy = :center
@picking_window = Window_Picking.new(wx, wy, @width, @safe_range_width, @speed)
@picking_window.set_handler(:ok, method(:on_picking_window_ok))
@picking_window.set_handler(:cancel, method(:on_picking_window_cancel))
@picking_window.set_handler(:UP, method(:speed_up)) if $TEST
@picking_window.set_handler(:DOWN, method(:speed_down)) if $TEST
@picking_window.set_handler(:LEFT, method(:safe_range_narrow)) if $TEST
@picking_window.set_handler(:RIGHT, method(:safe_range_wide)) if $TEST
@picking_window.status_window = @status_window
end
#--------------------------------------------------------------------------
# ○ スピードアップ(テスト用)
#--------------------------------------------------------------------------
def speed_up
Sound.play_cursor
@picking_window.speed += 0.5
p @picking_window.speed
end
#--------------------------------------------------------------------------
# ○ スピードダウン(テスト用)
#--------------------------------------------------------------------------
def speed_down
Sound.play_cursor
@picking_window.speed = [0.5, @picking_window.speed - 0.5].max
p @picking_window.speed
end
#--------------------------------------------------------------------------
# ○ 成功範囲を狭める(テスト用)
#--------------------------------------------------------------------------
def safe_range_narrow
Sound.play_cursor
@picking_window.safe_range_narrow
p @picking_window.safe_range_width
end
#--------------------------------------------------------------------------
# ○ 成功範囲を広げる(テスト用)
#--------------------------------------------------------------------------
def safe_range_wide
Sound.play_cursor
@picking_window.safe_range_wide
p @picking_window.safe_range_width
end
#--------------------------------------------------------------------------
# ○ 錠前破り判定
#--------------------------------------------------------------------------
def on_picking_window_ok
if @status_window.openlock?
$game_switches[OpenLock_Of_TheThief::PICKING_SUCCESS_SWITCH_ID] = true
return_scene
end
end
#--------------------------------------------------------------------------
# ○ 錠前破りを止める
#--------------------------------------------------------------------------
def on_picking_window_cancel
$game_switches[OpenLock_Of_TheThief::PICKING_SUCCESS_SWITCH_ID] = false
return_scene
end
end
#==============================================================================
# ■ Game_Interpreter
#------------------------------------------------------------------------------
# イベントコマンドを実行するインタプリタです。このクラスは Game_Map クラス、
# Game_Troop クラス、Game_Event クラスの内部で使用されます。
#==============================================================================
class Game_Interpreter
#--------------------------------------------------------------------------
# ○ 錠前破りシーンの呼び出し
#--------------------------------------------------------------------------
def call_picking(safe_range_width, speed, pin)
SceneManager.call(Scene_Picking)
SceneManager.scene.prepare(200, safe_range_width, speed, pin)
Fiber.yield
end
end