mirror of
https://github.com/bakustarver/rpgmakermlinux-cicpoffs.git
synced 2025-03-28 14:56:21 +01:00
1080 lines
46 KiB
Ruby
1080 lines
46 KiB
Ruby
# ===========================================================================
|
|
# ★ WF-RGSS Scripts ★
|
|
# 共通スクリプト(XP/VX/VXAce両対応版)
|
|
# バージョン : rev-29 (2013-3-26)
|
|
# 作者 : A Crying Minister (WHITE-FLUTE)
|
|
# サポート先URI: http://www.whiteflute.org/wfrgss/
|
|
# ---------------------------------------------------------------------------
|
|
# 機能:
|
|
# ・このセクションより後ろのスクリプトでSyntaxError が発生しても
|
|
# 別の例外にすりかえられるため、詳細情報が削除されなくなります。
|
|
# (VXAceでは標準で削除されなくなりました。)
|
|
# ・SyntaxErrorの情報をファイルに書き出します。
|
|
# ・不用意なデバッグモードへの遷移を防止します。
|
|
# (元からデバッグモードの場合は問題ありません。)
|
|
# ・不正なデバッグモードへの遷移を阻害します。
|
|
# ・デバッグコンソールを表示しデバッグしやすくします。
|
|
# ---------------------------------------------------------------------------
|
|
# 影響:
|
|
# ・外部コマンド実行など一部の組み込み関数が未定義になります。
|
|
# ・例外 SyntaxError は作成できません。(XP/VX)
|
|
# (※ ScriptSyntaxError にすりかえられます。)
|
|
# ---------------------------------------------------------------------------
|
|
# 設置場所:一番最初のセクション(Game_Temp(XP)/モジュール(VX/VXAce)よりも前)
|
|
# 必要スクリプト:
|
|
# ・共通実行スクリプト(VXAce は、Exit-EXで置き換える事ができます。)
|
|
# 注意事項:
|
|
# 共通実行スクリプトをMainセクションに上書きして利用することを推奨します。
|
|
# ===========================================================================
|
|
BEGIN {
|
|
|
|
module WFRGSS
|
|
# -------------------------------------------------------------------------
|
|
# ● 調整ポイント
|
|
# -------------------------------------------------------------------------
|
|
# デバッグモード遷移を阻害するかを設定します。
|
|
# 確実に保護できるわけではありませんので過信は禁物です。
|
|
|
|
DEBUG_CHECK = true
|
|
|
|
# -------------------------------------------------------------------------
|
|
# デバッグモード時、デバッグコンソールを表示します。
|
|
# (VXAceでは設定に関わらず標準装備されています。)
|
|
|
|
DEBUG_CONSOLE = false
|
|
|
|
# -------------------------------------------------------------------------
|
|
# リリースモード時、デバッグメッセージを消去します。
|
|
|
|
DELETE_DEBUG_MESSAGE = false
|
|
|
|
# -------------------------------------------------------------------------
|
|
# XPのみ。 デバッグフラグをVX/VXAce準拠に修正するか?
|
|
# (!)スクリプト対応が必要となります。
|
|
|
|
DEBUG_FLAG_CHANGE = false
|
|
|
|
|
|
# -------------------------------------------------------------------------
|
|
# 調整ポイント終わり
|
|
# -------------------------------------------------------------------------
|
|
end
|
|
|
|
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# ● 例外定義
|
|
# ---------------------------------------------------------------------------
|
|
|
|
# 継承例外
|
|
class InheritanceError < Exception;end
|
|
|
|
# Mix-in 例外
|
|
class IncludeError < Exception;end
|
|
|
|
# 仮想クラス、メソッドの使用
|
|
class AbstractError < NotImplementedError;end
|
|
|
|
# ◆ バグ検出
|
|
# バグ以外、絶対にありえない状態になったときに発生させてください。
|
|
# ※ バグ報告を行うためのものなので途中で破棄してはいけません。
|
|
class BugDetected < Exception;end
|
|
|
|
# ◆ 内部バグ報告用
|
|
# これは、WFRGSS でバグしかありえない状態に陥ったときに発生します。
|
|
# ※ バグ報告を行うためのものなので途中で破棄してはいけません。
|
|
class InternalBugDetected < BugDetected;end
|
|
|
|
# イベント階層が深すぎる場合
|
|
class EventDeepError < SystemStackError;end
|
|
|
|
# 初期化失敗
|
|
class InitializeError < TypeError;end
|
|
|
|
# アサーション失敗
|
|
class AssertionError < Exception;end
|
|
|
|
# ◆ 例外 Hangup
|
|
# ハングアップしたとみなされたときに投げられる例外。
|
|
# 深い階層からでは捉えられないことがあるため、注意が必要
|
|
# RPGVX/VXAceにはありませんが、XPとの互換性を保つため、設定しています。
|
|
class Hangup < Exception;end
|
|
|
|
# ◆ 例外 Reset
|
|
# Graphics.update の呼び出し時にF12が押されていると投げられる例外。(XP)
|
|
# F12 が押されていると投げられる例外(VX)
|
|
# これがセクション外に出ると
|
|
# 最初のセクションから再び実行をやり直そうとします。
|
|
# この操作は、組み込みクラスのメソッドにて、
|
|
# alias や undef が使われていると
|
|
# 不具合の元になります。
|
|
class Reset < Exception;end
|
|
|
|
# セキュリティ違反
|
|
class SecurityHazard < Exception;end
|
|
|
|
# RPGXP互換性のため
|
|
if WFRGSS::DEBUG_FLAG_CHANGE
|
|
$TEST = $DEBUG
|
|
$DEBUG = false
|
|
else
|
|
$TEST = false unless $TEST
|
|
end
|
|
|
|
module WFRGSS
|
|
@@debug = ($TEST or $DEBUG)
|
|
def self.check
|
|
debug = ($TEST or $DEBUG)
|
|
if debug != @@debug or (@@debug and
|
|
(FileTest.file?("Game.rgssad") or FileTest.file?("Game.rgss2a") or
|
|
FileTest.file?("Game.rgss3a")))
|
|
raise(SecurityHazard ,"Insecure - debug flag can't be change.")
|
|
end
|
|
end
|
|
end
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# ◆◆ デバッグモード阻止対策
|
|
# ---------------------------------------------------------------------------
|
|
# デバッグモード防止策
|
|
if defined? untrace_var
|
|
undef untrace_var
|
|
# デバッグモードでない場合、デバッグモードへの遷移を禁止する
|
|
proc = Proc.new {
|
|
if $DEBUG
|
|
$DEBUG = false
|
|
$TEST = false
|
|
$BTEST = false
|
|
raise(SecurityHazard ,"Insecure - debug flag can't be change.", caller(1))
|
|
end
|
|
}
|
|
trace_var( :$DEBUG , proc )
|
|
trace_var( :$-d , proc ) # $DEBUG の別名
|
|
proc = nil
|
|
|
|
# デバッグモードでない場合、デバッグモードへの遷移を禁止する
|
|
proc = Proc.new {
|
|
if $TEST
|
|
$DEBUG = false
|
|
$TEST = false
|
|
$BTEST = false
|
|
raise(SecurityHazard ,"Insecure - debug flag can't be change.", caller(1))
|
|
end
|
|
}
|
|
trace_var( :$TEST , proc ) # RPGVX デバッグフラグ
|
|
proc = nil
|
|
|
|
# 戦闘テストで無い場合、戦闘テストへの遷移を禁止する
|
|
proc = Proc.new {
|
|
if $BTEST
|
|
$DEBUG = false
|
|
$TEST = false
|
|
$BTEST = false
|
|
raise(SecurityHazard ,"Insecure - battle test flag can't be change.",
|
|
caller(1))
|
|
end
|
|
}
|
|
trace_var( :$BTEST , proc )
|
|
proc = nil
|
|
end
|
|
|
|
unless defined? ScriptSyntaxError
|
|
# RGSSでは、本来持っているSyntaxErrorの詳細情報をすべて削除してしまい、
|
|
# デバッグが非常に困難になってしまいます。
|
|
# そのために用意されている例外です。
|
|
# ※特にイベントスクリプト上でSyntaxErrorを出すととても悲惨なことに…
|
|
# 「スクリプト実行中に SyntaxError が発生しました。」だけで
|
|
# すぐに修正できるのでしょうか?
|
|
class ScriptSyntaxError < Exception;end
|
|
# -------------------------------------------------------------------------
|
|
# ◆ 組み込み例外クラス SyntaxError <obsolete>
|
|
# -------------------------------------------------------------------------
|
|
# RGSSでは、本来持っているSyntaxErrorの詳細情報をすべて削除してしまうため、
|
|
# SyntaxError のコンストラクタを乗っ取って別の例外にすりかえています。
|
|
# ※ SyntaxError のインスタンスは作成できません。
|
|
class SyntaxError < ScriptError
|
|
ERROR = Hash.new
|
|
end
|
|
class << SyntaxError
|
|
#--------------------------------------------------------------------------
|
|
# ◆ (!※継承禁止※!)
|
|
#--------------------------------------------------------------------------
|
|
def SyntaxError.inherited( subclass )
|
|
raise( InheritanceError ,
|
|
"can't inherit class #{subclass} from #{self}" , caller(1) )
|
|
end
|
|
private_class_method(:inherited)
|
|
unless defined? BasicObject
|
|
undef allocate
|
|
undef new
|
|
#------------------------------------------------------------------------
|
|
# ◆ 強制的に別の例外にすりかえる
|
|
#------------------------------------------------------------------------
|
|
def new( errors , *args )
|
|
error_message = make_error_message(errors)
|
|
error_message_dump(error_message)
|
|
ScriptSyntaxError.new(error_message)
|
|
end
|
|
else
|
|
alias __wfrgss__new__ new unless $!
|
|
def new( errors , *args )
|
|
error_message = make_error_message(errors)
|
|
error_message_dump(error_message)
|
|
__wfrgss__new__(errors)
|
|
end
|
|
end
|
|
private
|
|
#----------------------------------------------------------------------------
|
|
# ◆(内部専用)◆ エラーメッセージ作成
|
|
#----------------------------------------------------------------------------
|
|
def make_error_message( error_message )
|
|
extra = ""
|
|
unless (error_message[/^(?:Section)?{?(\d+)}?:(\d+):/]).nil?
|
|
nums = $1.to_i # セクションを拾い出した場合
|
|
extra = $RGSS_SCRIPTS.at(nums).at(1)
|
|
unless $2.nil?
|
|
lines = $2.to_i
|
|
unless ($RGSS_SCRIPTS.at(nums).at(3)).nil?
|
|
details = show_details_source_code( nums , lines )
|
|
unless details.empty?
|
|
error_message += "\n** script source code:\n#{details}"
|
|
else
|
|
error_message +=
|
|
"\n** script source code:#{lines} unknown data.\n"
|
|
end
|
|
end
|
|
end
|
|
end
|
|
error_message.gsub!(/^(?:Section)?{?(\d+)}?:/){"( #{extra} ):#{$1}:lines "}
|
|
error_message
|
|
end
|
|
#--------------------------------------------------------------------------
|
|
# ◆(内部専用)◆ 情報を書きこみ
|
|
#--------------------------------------------------------------------------
|
|
def error_message_dump(error_message)
|
|
e = Zlib::crc32(error_message)
|
|
return if SyntaxError::ERROR[e]
|
|
SyntaxError::ERROR[e] = true
|
|
File.open("syntaxerror.txt","a") do | file |
|
|
file.write("*SyntaxError - " +
|
|
(Time.now).strftime("%Y-%m-%d %H:%M:%S (%A)") + "\n")
|
|
file.write( "#{error_message}\n" )
|
|
end
|
|
end
|
|
#--------------------------------------------------------------------------
|
|
# ◆(内部専用)◆ ソースコード位置読み込み
|
|
#--------------------------------------------------------------------------
|
|
def show_details_source_code( nums , lines )
|
|
details = ""
|
|
splitstr = ($RGSS_SCRIPTS.at(nums).at(3)).split(/\r\n/)
|
|
if lines < 4
|
|
ranges = ( 0...( lines + 3 ))
|
|
else
|
|
ranges = (( lines - 4 )...( lines + 3 ))
|
|
end
|
|
for i in ranges
|
|
unless (splitstr.at(i)).nil?
|
|
if i != (lines - 1)
|
|
details += "|" + splitstr.at(i) + "\n"
|
|
else
|
|
details += ">" + splitstr.at(i) + "\n"
|
|
end
|
|
else
|
|
details += "[End of File]\n"
|
|
break
|
|
end
|
|
end
|
|
splitstr = nil
|
|
rpgvxace? ? details.force_encoding("UTF-8") : details
|
|
end
|
|
end
|
|
|
|
|
|
# -------------------------------------------------------------------------
|
|
# ◆ RGSS 組み込みモジュール Graphics
|
|
# -------------------------------------------------------------------------
|
|
|
|
class << Graphics
|
|
#------------------------------------------------------------------------
|
|
# ◆ リセットを無視する Graphics.update
|
|
#------------------------------------------------------------------------
|
|
def Graphics.safe_update
|
|
begin
|
|
update
|
|
rescue Reset
|
|
# リセット操作を無視する。
|
|
# ただしカーソルアニメーションなどが巻き戻される。
|
|
nil
|
|
end
|
|
end
|
|
|
|
if WFRGSS::DEBUG_CHECK
|
|
#------------------------------------------------------------------------
|
|
# ◆ Graphics.update にチェックを加える
|
|
#------------------------------------------------------------------------
|
|
alias ___original__update___ update
|
|
def Graphics.update
|
|
WFRGSS.check
|
|
___original__update___
|
|
end
|
|
private(:___original__update___)
|
|
end
|
|
end
|
|
|
|
module Graphics
|
|
# -----------------------------------------------------------------------
|
|
# ◆ クラス変数
|
|
# -----------------------------------------------------------------------
|
|
@@rate = 0
|
|
@@count = 0
|
|
# -----------------------------------------------------------------------
|
|
# ◆ フレームレートを一時的に変更
|
|
# -----------------------------------------------------------------------
|
|
def self.frame_workset( frame_rates )
|
|
@@rate = Graphics.frame_rate
|
|
@@count = Graphics.frame_count
|
|
Graphics.frame_rate = frame_rates
|
|
end
|
|
# -----------------------------------------------------------------------
|
|
# ◆ フレームレートを元に戻す
|
|
# -----------------------------------------------------------------------
|
|
def self.frame_restore
|
|
cnt = Graphics.frame_count - @@count
|
|
cnt *= @@rate
|
|
cnt /= Graphics.frame_rate
|
|
Graphics.frame_count = @@count + cnt
|
|
Graphics.frame_rate = @@rate
|
|
end
|
|
# -----------------------------------------------------------------------
|
|
# ◆ 解像度横の幅(VX/VXAceでは無視される)
|
|
# -----------------------------------------------------------------------
|
|
unless defined? Graphics.width
|
|
def self.width
|
|
640
|
|
end
|
|
end
|
|
# -----------------------------------------------------------------------
|
|
# ◆ 解像度縦の幅(VX/VXAceでは無視される)
|
|
# -----------------------------------------------------------------------
|
|
unless defined? Graphics.height
|
|
def self.height
|
|
480
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# ◆ 組み込みモジュール GC
|
|
# ---------------------------------------------------------------------------
|
|
module GC
|
|
module_function
|
|
#--------------------------------------------------------------------------
|
|
# ◆ 安全にガーベージコレクションを行う
|
|
#--------------------------------------------------------------------------
|
|
def update_start
|
|
Graphics.safe_update
|
|
start
|
|
Graphics.safe_update
|
|
end
|
|
end
|
|
|
|
}
|
|
|
|
unless defined? Abstract
|
|
# -----------------------------------------------------------------------------
|
|
# ◆◆ 組み込みクラス Class
|
|
# -----------------------------------------------------------------------------
|
|
class Class
|
|
# ---------------------------------------------------------------------------
|
|
# ◆ クラス変数
|
|
# ---------------------------------------------------------------------------
|
|
@@_abstract_class = Hash.new
|
|
# ---------------------------------------------------------------------------
|
|
# ◆ 抽象クラス追加
|
|
# ---------------------------------------------------------------------------
|
|
def self.abstract_class( klass )
|
|
__failure_type_call__( klass ) unless klass.is_a?(Class)
|
|
unless @@_abstract_class[klass.__id__]
|
|
@@_abstract_class[klass.__id__] = klass
|
|
end
|
|
end
|
|
# ---------------------------------------------------------------------------
|
|
# ◆ 抽象クラス判定
|
|
# ---------------------------------------------------------------------------
|
|
def self.abstract?( klass )
|
|
@@_abstract_class[klass.__id__]
|
|
end
|
|
end
|
|
|
|
module Abstract
|
|
# ---------------------------------------------------------------------------
|
|
# ◆ 抽象化
|
|
# ---------------------------------------------------------------------------
|
|
def self.included( klass )
|
|
if klass.include?(FinalClass)
|
|
# FinalClass モジュールが既にインクルードされている
|
|
raise( IncludeError ,
|
|
"can't include #{klass} from #{self}" , caller(1) )
|
|
end
|
|
Class.abstract_class( klass )
|
|
klass.extend(Abstract_Class__)
|
|
end
|
|
private_class_method(:included)
|
|
end
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# ◆ 抽象化 ※ 特異メソッド専用 ※
|
|
# ---------------------------------------------------------------------------
|
|
module Abstract_Class__
|
|
# -------------------------------------------------------------------------
|
|
# ◆ ※ 抽象クラス
|
|
# -------------------------------------------------------------------------
|
|
def allocate
|
|
return super unless Class.abstract?( self )
|
|
raise( AbstractError ,
|
|
"class #{self} cannot use it because of the abstraction class.",
|
|
caller(1) )
|
|
end
|
|
# -------------------------------------------------------------------------
|
|
# ◆ ※ 抽象クラス
|
|
# -------------------------------------------------------------------------
|
|
def new( *args )
|
|
return super unless Class.abstract?( self )
|
|
raise( AbstractError ,
|
|
"class #{self} cannot use it because of the abstraction class.",
|
|
caller(1) )
|
|
end
|
|
# -------------------------------------------------------------------------
|
|
# ◆ ※ Mix-in 制限
|
|
# -------------------------------------------------------------------------
|
|
def self.included( klass )
|
|
unless self.is_a?(Class)
|
|
raise( IncludeError ,
|
|
"can't include #{klass} from #{self}" , caller(1) )
|
|
end
|
|
end
|
|
end
|
|
|
|
module FinalClass
|
|
# ---------------------------------------------------------------------------
|
|
# ◆ 継承できないクラス
|
|
# ---------------------------------------------------------------------------
|
|
def self.included( klass )
|
|
if Class.abstract?( klass )
|
|
# Abstract モジュールが既にインクルードされている
|
|
raise( IncludeError ,
|
|
"can't include #{klass} from #{self}" , caller(1) )
|
|
end
|
|
klass.module_eval(<<-End)
|
|
def self.inherited( subclass )
|
|
raise( InheritanceError ,
|
|
sprintf(\"can't inherit class %s from %s\",subclass.inspect,
|
|
self.inspect ) , caller(1) )
|
|
end
|
|
private_class_method(:inherited)
|
|
End
|
|
end
|
|
private_class_method(:included)
|
|
end
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# ◆ 組み込みモジュール Kernel
|
|
# ---------------------------------------------------------------------------
|
|
|
|
module Kernel
|
|
# ---------------------------------------------------------------------------
|
|
# ◆ 危険な関数を未定義に設定
|
|
# ---------------------------------------------------------------------------
|
|
# 外部コマンド読み込みなど危険な操作は明示的に禁止にします。
|
|
# ※ これらのコマンドの必要性が(通常は)ないうえ、
|
|
# 危険(システム破壊をもたらすことがある)なため取り外しています。
|
|
# ※ もし、これらを使用する場合は、効果と危険性を考慮してください。
|
|
# ---------------------------------------------------------------------------
|
|
# 外部コマンドを実行する。
|
|
undef ` #` # 外部コマンドを実行する。
|
|
undef exec # 外部コマンドを実行する 制御を返さない。
|
|
undef fork # サブシェルを生成する。
|
|
undef system # 外部コマンドを実行する。
|
|
undef abort # 後処理を行わずに強制終了する。後処理が必要な時に困る。
|
|
undef exit! # abort と同じ。
|
|
undef open # コマンドが実行できる。(ファイルを開くならIO.openを用いる)
|
|
#--------------------------------------------------------------------------
|
|
private
|
|
#--------------------------------------------------------------------------
|
|
# ◆ RPGVX/VXAce かどうか
|
|
#--------------------------------------------------------------------------
|
|
def rpgvx?
|
|
defined? Graphics.resize_screen
|
|
end
|
|
#--------------------------------------------------------------------------
|
|
# ◆ RPGVXAce かどうか
|
|
#--------------------------------------------------------------------------
|
|
def rpgvxace?
|
|
defined? BasicObject
|
|
end
|
|
#--------------------------------------------------------------------------
|
|
# ◆ RGSSのバージョン
|
|
#--------------------------------------------------------------------------
|
|
def rgss_version
|
|
rpgvx? ? (rpgvxace? ? 3 : 2 ) : 1
|
|
end
|
|
#--------------------------------------------------------------------------
|
|
# ◆ テストモードかどうか
|
|
#--------------------------------------------------------------------------
|
|
def debug?
|
|
$DEBUG or $TEST
|
|
end
|
|
#--------------------------------------------------------------------------
|
|
# ◆ デバッグコンソール
|
|
#--------------------------------------------------------------------------
|
|
if WFRGSS::DEBUG_CONSOLE and debug? and (not rpgvxace?)
|
|
unless $@
|
|
$VERBOSE = true
|
|
alias wfrgss_p p
|
|
Win32API.new("kernel32","AllocConsole",'v','l').call
|
|
$stdout.reopen("conout$","w")
|
|
def p(*a)
|
|
a.each{|v|$stdout.puts(String.utf82ansi(v.inspect))}
|
|
end
|
|
end
|
|
elsif WFRGSS::DELETE_DEBUG_MESSAGE
|
|
unless $@
|
|
alias display_p p
|
|
def p(*a)
|
|
# 何も出力しない
|
|
end
|
|
end
|
|
end
|
|
#--------------------------------------------------------------------------
|
|
# ◆ 例外セット
|
|
# 例外を発生させます。
|
|
#--------------------------------------------------------------------------
|
|
# ◆ method_missing と同様
|
|
#--------------------------------------------------------------------------
|
|
def __failure_method_call__( method_name , *args )
|
|
raise( NoMethodError ,
|
|
"undefined method `#{method_name}' for #{self}" , caller(2) )
|
|
end
|
|
#--------------------------------------------------------------------------
|
|
# ◆ オーバーライドが必要
|
|
#--------------------------------------------------------------------------
|
|
def __override_required_call__( method_name , *args )
|
|
raise( AbstractError ,
|
|
"It is necessary to do override to use method `#{method_name}'" +
|
|
" of this class #{self}. " +
|
|
"(or, it tried to call the method of a super-class.)" , caller(2))
|
|
end
|
|
#--------------------------------------------------------------------------
|
|
# ◆ 例外 TypeErrorを発生させる
|
|
#--------------------------------------------------------------------------
|
|
def __failure_type_call__( object_type )
|
|
e = ( object_type.class ).to_s
|
|
raise( TypeError , "no implicit conversion from #{e}" , caller(2) )
|
|
end
|
|
#--------------------------------------------------------------------------
|
|
# ◆ 例外 RangeErrorを発生させる ( num が Numeric でない場合はBugDetected )
|
|
#--------------------------------------------------------------------------
|
|
def __outof_range_call__( num , str , call_value = 2 )
|
|
if num.is_a?(Numeric)
|
|
if str.is_a?(String)
|
|
raise( RangeError , "#{num} out of range of #{str}",caller(call_value))
|
|
else
|
|
e = ( str.class ).to_s
|
|
raise(TypeError,"no implicit conversion from #{e}",caller(call_value))
|
|
end
|
|
else
|
|
e = ( num.class ).to_s
|
|
raise( BugDetected, "[BUG] no implicit conversion from #{e} (TypeError)",
|
|
caller(1))
|
|
end
|
|
end
|
|
#--------------------------------------------------------------------------
|
|
# ◆ 例外 ArgumentErrorを発生させる ( str が String でない場合はBugDetected )
|
|
#--------------------------------------------------------------------------
|
|
def __invalid_value_call__( str , value , call_value = 2 )
|
|
if str.is_a?(String)
|
|
raise( ArgumentError , "invalid #{str} for #{value.to_s}")
|
|
else
|
|
e = ( str.class ).to_s
|
|
raise( BugDetected, "[BUG] no implicit conversion from #{e} (TypeError)",
|
|
caller(1))
|
|
end
|
|
end
|
|
#--------------------------------------------------------------------------
|
|
# ◆ 例外 SecurityErrorを発生させる ( str が String でない場合はBugDetected )
|
|
#--------------------------------------------------------------------------
|
|
def __insecure_call__( str )
|
|
if str.is_a?(String)
|
|
raise( SecurityError , "Insecure operation - #{str}" , caller(2) )
|
|
else
|
|
e = ( str.class ).to_s
|
|
raise( BugDetected, "[BUG] no implicit conversion from #{e} (TypeError)",
|
|
caller(1))
|
|
end
|
|
end
|
|
#--------------------------------------------------------------------------
|
|
# ◆ バグを報告する。 ( str が String でない場合も BugDetected )
|
|
#--------------------------------------------------------------------------
|
|
def __report_bug( str )
|
|
if str.is_a?(String)
|
|
raise( BugDetected , str , caller(1))
|
|
else
|
|
e = ( str.class ).to_s
|
|
raise( BugDetected ,
|
|
"[BUG] no implicit conversion from #{e} (TypeError)" , caller(1) )
|
|
end
|
|
end
|
|
#--------------------------------------------------------------------------
|
|
# ◆ バグを報告する。(異常な値を検出)
|
|
#--------------------------------------------------------------------------
|
|
def __report_bug_invalid_value( value )
|
|
raise( BugDetected , "[BUG] invalid value for #{value}", caller(1))
|
|
end
|
|
#--------------------------------------------------------------------------
|
|
# ◆※!※◆ WF-RGSS の バグを報告する。
|
|
# ※ このメソッドは WF-RGSS 内部バグを報告するためのものです。
|
|
# ※ カスタマイズ時にバグを報告したい場合は、
|
|
# __report_bug( str ) を使用してください。
|
|
#--------------------------------------------------------------------------
|
|
def __report_internal_bug( str )
|
|
if str.is_a?(String)
|
|
raise( InternalBugDetected , str , caller(1))
|
|
else
|
|
e = ( str.class ).to_s
|
|
raise( InternalBugDetected ,
|
|
"[BUG] no implicit conversion from #{e} (TypeError)" , caller(1) )
|
|
end
|
|
end
|
|
#--------------------------------------------------------------------------
|
|
# ◆ チェック関連メソッド
|
|
# 型や範囲をチェックします。
|
|
#--------------------------------------------------------------------------
|
|
# ◆ 型が合わない場合、例外 TypeErrorを発生させる
|
|
# (※ klass が異常な場合はBugDetected )
|
|
#--------------------------------------------------------------------------
|
|
def _type_check_( object_type , klass , call_value = 2 )
|
|
begin
|
|
return if object_type.is_a?(klass)
|
|
e = ( object_type.class ).to_s
|
|
raise( TypeError,"no implicit conversion from #{e}")
|
|
rescue TypeError => errobj
|
|
# 例外の報告位置をすりかえる
|
|
if errobj.message[/^no/].nil?
|
|
raise( BugDetected , "[BUG] #{errobj.message} (TypeError)",caller(1))
|
|
else
|
|
raise( TypeError , errobj.message , caller(call_value))
|
|
end
|
|
end
|
|
end
|
|
#--------------------------------------------------------------------------
|
|
# ◆ Fixnum の範囲を検証する ※範囲が異常なら例外を発生させる
|
|
#--------------------------------------------------------------------------
|
|
def _fixnum_range_check( value , minimum , maximum )
|
|
__failure_type_call__( value , 3 ) unless value.is_a?(Fixnum)
|
|
unless value >= minimum and value <= maximum
|
|
# 範囲外のため、例外を発生させる
|
|
call_ary = caller(1)
|
|
if call_ary.size > 0
|
|
sections = call_ary.at(0)
|
|
str = sections + " ( range #{minimum} .. #{maximum} )"
|
|
else
|
|
str = "caller method (unknown) ( range #{minimum} .. #{maximum} )"
|
|
end
|
|
__outof_range_call__( value , str , 3 )
|
|
end
|
|
end
|
|
#--------------------------------------------------------------------------
|
|
# ◆ Integer の範囲にまとめる (※処理速度が求められる箇所では用いない)
|
|
# ※異常範囲が認められていない場合は、↑のメソッドを用いること
|
|
#--------------------------------------------------------------------------
|
|
def _integer_range_value( value , minimum , maximum )
|
|
__failure_type_call__( value , 3 ) unless value.is_a?(Integer)
|
|
if value < minimum
|
|
return minimum
|
|
elsif value > maximum
|
|
return maximum
|
|
else
|
|
return value
|
|
end
|
|
end
|
|
# ---------------------------------------------------------------------------
|
|
# 可視性を変更
|
|
public
|
|
# これ以降はモジュール関数として定義
|
|
module_function
|
|
# ---------------------------------------------------------------------------
|
|
# ◆ 真 を検証
|
|
# ---------------------------------------------------------------------------
|
|
def assert_if( value )
|
|
unless value
|
|
raise(AssertionError,"Assertion Failed (false for true)",caller(1))
|
|
end
|
|
end
|
|
# ---------------------------------------------------------------------------
|
|
# ◆ 偽 を検証
|
|
# ---------------------------------------------------------------------------
|
|
def assert_unless( value )
|
|
if value
|
|
raise(AssertionError,"Assertion Failed (true for false)",caller(1))
|
|
end
|
|
end
|
|
end
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# ◆ 組み込みクラス Object
|
|
# ---------------------------------------------------------------------------
|
|
class Object
|
|
# 可視性を変更
|
|
private
|
|
#--------------------------------------------------------------------------
|
|
# ◆ Mix-in禁止を実装
|
|
#--------------------------------------------------------------------------
|
|
def self.__cannot_mixin( klass )
|
|
raise( IncludeError ,
|
|
"can't include #{klass} from #{self}" , caller(2) )
|
|
end
|
|
#--------------------------------------------------------------------------
|
|
# ◆ 継承禁止を実装
|
|
#--------------------------------------------------------------------------
|
|
def self.__cannot_inherited( subclass )
|
|
raise( InheritanceError ,
|
|
"can't inherit class #{subclass} from #{self}" , caller(2) )
|
|
end
|
|
#--------------------------------------------------------------------------
|
|
# ◆ 抽象クラス (かならず継承が必要となる)
|
|
#--------------------------------------------------------------------------
|
|
def __abstract_class( target )
|
|
klass = self.class
|
|
unless target.is_a?(Class) or target.is_a?(Module)
|
|
__report_bug("[BUG] class or modules required (TypeError)")
|
|
end
|
|
until ( klass = klass.superclass ) == Object
|
|
return if klass == target
|
|
end
|
|
raise( AbstractError ,
|
|
"class #{target} cannot use it because of the abstraction class.",
|
|
caller(2) )
|
|
end
|
|
end
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# ◆ 組み込みクラス String
|
|
# ---------------------------------------------------------------------------
|
|
class String
|
|
# ---------------------------------------------------------------------------
|
|
# ◆ 定数
|
|
# ---------------------------------------------------------------------------
|
|
CP_ACP = 0 # ANSI コード
|
|
CP_UTF7 = 65000 # UTF-7 コード
|
|
CP_UTF8 = 65001 # UTF-8 コード
|
|
EMPTY_STR = "".freeze
|
|
#--------------------------------------------------------------------------
|
|
# ◆ クラス変数
|
|
#--------------------------------------------------------------------------
|
|
@@rm = Win32API.new('kernel32','RtlZeroMemory',%w(p l),'l').freeze
|
|
# 文字列をワイド文字列(Unicode)にマップするAPI
|
|
@@mb2wc = Win32API.new('kernel32',
|
|
'MultiByteToWideChar', %w(i l p i p i), 'l').freeze
|
|
# ワイド文字列を新しい文字列にマップするAPI
|
|
@@wc2mb = Win32API.new('kernel32',
|
|
'WideCharToMultiByte', %w(i l p i p i p p), 'l').freeze
|
|
#--------------------------------------------------------------------------
|
|
# ◆ クリア
|
|
#--------------------------------------------------------------------------
|
|
unless rpgvxace?
|
|
def clear
|
|
@@rm.call( self , self.size )
|
|
self.replace("")
|
|
end
|
|
end
|
|
#--------------------------------------------------------------------------
|
|
# ◆ エンコード
|
|
#--------------------------------------------------------------------------
|
|
def encode_by_
|
|
for i in 0...self.size
|
|
self[i] = 256 - self[i]
|
|
end
|
|
end
|
|
#--------------------------------------------------------------------------
|
|
# ◆ UTF-8 → ANSI 変換
|
|
#--------------------------------------------------------------------------
|
|
unless rpgvxace?
|
|
def self.utf82ansi(str)
|
|
to_multibyte(to_widechar(str, CP_UTF8), CP_ACP)
|
|
end
|
|
else
|
|
def self.utf82ansi(str)
|
|
result = to_multibyte(to_widechar(str, CP_UTF8), CP_ACP)
|
|
result.empty? ? result : result.force_encoding("ASCII-8BIT")
|
|
end
|
|
end
|
|
#--------------------------------------------------------------------------
|
|
# ◆ ANSI → UTF-8 変換
|
|
#--------------------------------------------------------------------------
|
|
unless rpgvxace?
|
|
def self.ansi2utf8( str )
|
|
to_multibyte( to_widechar( str , CP_ACP ) , CP_UTF8 )
|
|
end
|
|
else
|
|
def self.ansi2utf8( str )
|
|
to_multibyte(to_widechar(str,CP_ACP),CP_UTF8).force_encoding("UTF-8")
|
|
end
|
|
end
|
|
private # 可視性を private に変更
|
|
#--------------------------------------------------------------------------
|
|
# ◆(内部専用)◆ ワイド文字列( Unicode ) へ変換
|
|
#--------------------------------------------------------------------------
|
|
def self.to_widechar(str, codepage)
|
|
puts "vvvvxzz"
|
|
# Convert the string from the specified encoding to UTF-16 (which is Ruby's default wide character encoding)
|
|
return ""
|
|
end
|
|
private_class_method(:to_widechar)
|
|
#--------------------------------------------------------------------------
|
|
# ◆(内部専用)◆ ワイド文字列( Unicode ) から 文字列を取得する
|
|
#--------------------------------------------------------------------------
|
|
def self.to_multibyte(str, codepage)
|
|
# Convert a wide character string (UTF-16) to a multi-byte encoding (e.g., UTF-8 or Windows-1252)
|
|
return ""
|
|
end
|
|
private_class_method(:to_multibyte)
|
|
end
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# ◆ モジュール ErrorLogWriter
|
|
# ---------------------------------------------------------------------------
|
|
|
|
module ErrorLogWriter
|
|
#--------------------------------------------------------------------------
|
|
# ◆(内部専用)◆ Mix-in 禁止
|
|
#--------------------------------------------------------------------------
|
|
def self.included( klass )
|
|
__cannot_mixin( klass )
|
|
end
|
|
private_class_method(:included)
|
|
|
|
ERROR_SECTION_NUM = (/^(?:Section)?{?(\d+)}?:/).freeze
|
|
ERROR_SECTION = (/^(?:Section)?{?\d+}?:/).freeze
|
|
DOUBLE_CRLF = (/\n\n/).freeze
|
|
# -------------------------------------------------------------------------
|
|
# ◆ エラー情報を記録 ( DEBUG のみ )
|
|
# -------------------------------------------------------------------------
|
|
def self.write( errobj )
|
|
return unless debug?
|
|
begin
|
|
begin
|
|
Graphics.safe_update
|
|
rescue SecurityHazard
|
|
end
|
|
sleep(0.1)
|
|
File.open("errors.txt","a") do | file |
|
|
file.write("*Error - " +
|
|
(Time.now).strftime("%Y-%m-%d %H:%M:%S (%A)") + "\n")
|
|
file.write( "Exception : #{errobj.class}\n" )
|
|
file.write( errobj.message )
|
|
unless $@.nil? and $@.empty?
|
|
backtrace = ""
|
|
for str in $@.dup
|
|
unless (str[ERROR_SECTION_NUM]).nil?
|
|
extra = $RGSS_SCRIPTS.at($1.to_i).at(1)
|
|
str.gsub!(ERROR_SECTION) { "( " + extra + " ):" }
|
|
end
|
|
backtrace += str
|
|
end
|
|
file.write( "\ntrace:\n" + $@.inspect + "\n" )
|
|
end
|
|
end
|
|
rescue Exception => errs
|
|
raise( errs ,
|
|
errs.message + "\n (" + (errobj.class).to_s + " )\n" + errobj.message )
|
|
end
|
|
end
|
|
end
|
|
|
|
end
|
|
def hook_exit(arg,arg2,arg3,arg4)
|
|
# puts arg,arg2,arg3,arg4
|
|
puts "Exporting [#{arg}] ##{arg2}: #{arg3} #{arg4}"
|
|
# Simulate what the hookExit function might do
|
|
# puts "Simulated hookExit called with parameter:"
|
|
# You can add more simulated behavior here, like logging, altering global variables, etc.
|
|
end
|
|
module MessageBox
|
|
#----------------------------------------------------------------------------
|
|
# ◆(内部専用)◆ Mix-in 禁止
|
|
#----------------------------------------------------------------------------
|
|
def self.included( klass )
|
|
raise( IncludeError , "can't include #{klass} from #{self}" , caller(1) )
|
|
end
|
|
private_class_method(:included)
|
|
# ---------------------------------------------------------------------------
|
|
# ◆ 定数
|
|
# ---------------------------------------------------------------------------
|
|
MB_OK = 0x0 #
|
|
MB_OKCANCEL = 0x1 #
|
|
MB_ABORTRETRYIGNORE = 0x2 #
|
|
MB_YESNOCANCEL = 0x3 #
|
|
MB_YESNO = 0x4 #
|
|
MB_RETRYCANCEL = 0x5 #
|
|
|
|
MB_ICONERROR = 0x10 # エラー
|
|
MB_ICONQUESTION = 0x20 # 問い合わせ
|
|
MB_ICONWARNING = 0x30 # 警告
|
|
MB_ICONINFORMATION = 0x40 # 情報
|
|
MB_SYSTEMMODAL = 0x1000 # システムモーダル
|
|
MB_TASKMODAL = 0x2000 # タスクモーダル
|
|
MB_TOPMOST = 0x040000 # 最前面
|
|
MB_FATAL = 0x042010 # 致命的エラー用
|
|
MB_WARN = 0x042030 # 警告
|
|
|
|
IDOK = 1
|
|
IDCANCEL = 2
|
|
IDABORT = 3
|
|
IDRETRY = 4
|
|
IDIGNORE = 5
|
|
IDYES = 6
|
|
IDNO = 7
|
|
# ---------------------------------------------------------------------------
|
|
# ◆ 内部使用定数
|
|
# ---------------------------------------------------------------------------
|
|
ERROR_SECTION_NUM = (/^(?:Section)?{?(\d+)}?:/).freeze
|
|
ERROR_SECTION = (/^(?:Section)?{?\d+}?:/).freeze
|
|
DOUBLE_CRLF = (/\n\n/).freeze
|
|
|
|
begin
|
|
# メッセージボックス
|
|
@@mb = method(:hook_exit)
|
|
rescue Exception
|
|
# 取得失敗
|
|
Script_Deleter.finalizer
|
|
raise( LoadError , "cannot read modules.(user32.dll)",caller(0))
|
|
end
|
|
begin
|
|
# ini ファイルから、セクションのキーを取得するAPI
|
|
@@gpps = Win32API.new('kernel32',
|
|
'GetPrivateProfileStringA',%w(p p p p l p),'l').freeze
|
|
rescue Exception
|
|
# 取得失敗
|
|
Script_Deleter.finalizer
|
|
raise( LoadError , "cannot read modules.(kernel32.dll)",caller(0))
|
|
end
|
|
#--------------------------------------------------------------------------
|
|
# ◆(!要注意メソッド!)◆ メッセージボックスを表示
|
|
# ※警告 :例外 Hangup 対策をかならず行うこと!
|
|
#--------------------------------------------------------------------------
|
|
def self.messagebox( message , title , type )
|
|
begin
|
|
# 停止対策用
|
|
begin
|
|
Graphics.safe_update
|
|
rescue SecurityHazard
|
|
end
|
|
@@mb.call(0, String.utf82ansi( message ), String.utf82ansi( title ),type)
|
|
rescue Hangup
|
|
nil # !※例外時にここを通過せずに外部に投げられる恐れあり
|
|
ensure
|
|
# !※例外時にここを通過せずに外部に投げられる恐れあり
|
|
begin
|
|
Graphics.safe_update
|
|
rescue SecurityHazard
|
|
end
|
|
end
|
|
end
|
|
#--------------------------------------------------------------------------
|
|
# ◆(!特定外使用禁止!)◆ 致命的エラーを通知
|
|
# ※警告 :例外 Hangup 対策をかならず行うこと!
|
|
#--------------------------------------------------------------------------
|
|
def self.fatalerror( errobj )
|
|
begin
|
|
ErrorLogWriter.write( errobj )
|
|
error_message , tracer = error_message_setup( errobj )
|
|
# 瞬間消去
|
|
Graphics.transition(0)
|
|
Audio.bgm_stop
|
|
Audio.bgs_stop
|
|
Audio.me_stop
|
|
Audio.se_stop
|
|
if debug? and ( not (tracer[/^(?:Section)?{?(\d+)}?:(\d+)/]).nil? )
|
|
# セクションを拾い出した場合
|
|
nums = $1.to_i
|
|
extra = $RGSS_SCRIPTS.at(nums).at(1)
|
|
lines = $2.to_i
|
|
tracer = "#{extra} の #{lines} 行目で、\n"
|
|
error_message = tracer + error_message
|
|
end
|
|
title = "\x00" * 256
|
|
@@gpps.call( 'Game' , 'Title' , '' , title , 255 , '.\\Game.ini' )
|
|
title = String.ansi2utf8(title)
|
|
title.tr("\x00","")
|
|
# マウスカーソルを表示
|
|
Input.mouse_show if Input.method_defined?(:mouse_show)
|
|
# メッセージボックス
|
|
puts error_message , title , MB_FATAL
|
|
messagebox( error_message , title , MB_FATAL )
|
|
rescue Hangup
|
|
nil # !※例外時にここを通過せずに外部に投げられる恐れあり
|
|
end
|
|
rescue Hangup
|
|
nil
|
|
end
|
|
# ---------------------------------------------------------------------------
|
|
# ◆ 異常終了のメッセージを整形
|
|
# ---------------------------------------------------------------------------
|
|
def self.error_message_setup( errobj )
|
|
Graphics.freeze
|
|
begin
|
|
Graphics.safe_update
|
|
rescue SecurityHazard
|
|
end
|
|
_message = ""
|
|
# バックトレースを記憶する
|
|
unless $@.nil? or ($@.at(0)).nil?
|
|
tracer = ($@.at(0)).dup
|
|
# バックトレースを解析する
|
|
backtrace = ""
|
|
i = 0
|
|
for str in $@.dup
|
|
unless (str[ERROR_SECTION_NUM]).nil?
|
|
extra = $RGSS_SCRIPTS.at($1.to_i).at(1)
|
|
str.gsub!(ERROR_SECTION) { "( " + extra + " ):" }
|
|
end
|
|
backtrace += str
|
|
end
|
|
unless errobj.is_a?(SystemStackError)
|
|
if rpgvxace?
|
|
_message = errobj.message.force_encoding("UTF-8") +
|
|
"\n** backtrace:\n" + backtrace
|
|
else
|
|
_message = errobj.message + "\n** backtrace:\n" + backtrace
|
|
end
|
|
end
|
|
else
|
|
tracer = "" # バックトレース取得失敗
|
|
if rpgvxace?
|
|
_message = errobj.message.force_encoding("UTF-8")
|
|
else
|
|
_message = errobj.message
|
|
end
|
|
end
|
|
until (_message[DOUBLE_CRLF]).nil?
|
|
_message.gsub!(DOUBLE_CRLF){ "\n" }
|
|
end
|
|
if debug?
|
|
_message = "解決できない例外 " + (errobj.class).inspect +
|
|
" が発生したため、処理を継続できません。\n" +
|
|
_message
|
|
else
|
|
_message = "解決できない例外 " + (errobj.class).inspect +
|
|
" が発生したため、処理を継続できませんでした。\n" +
|
|
"お手数をおかけして申し訳ありません。\n\n詳細情報:\n" +
|
|
_message
|
|
end
|
|
return _message, tracer
|
|
end
|
|
end
|
|
|
|
# RGSS2 環境だと、リセットは阻止できない。
|
|
if $@ and WFRGSS::DEBUG_CONSOLE and debug?
|
|
p "例外 Reset が外部へ投げられました。"
|
|
end
|