#=========================================================================== # ◆ A1 Scripts ◆ # Win32API共通スクリプト(RGSS3) # # バージョン : 2.10 (2020/06/18) # 作者 : A1 # URL     : http://a1tktk.web.fc2.com/ #--------------------------------------------------------------------------- # 機能: # ・Win32APIを使用します #--------------------------------------------------------------------------- # 更新履歴   :2011/12/15 Ver1.00 リリース #    :2011/12/31 Ver1.10 全角のRTPインストール先対応 #    :2011/12/31 Ver1.10 INIファイルの全角対応 #    :2011/12/31 Ver1.10 定義失敗チェック関数の追加 #    :2011/12/31 Ver1.10 定義確認関数の追加 #    :2011/12/31 Ver1.10 定義失敗APIの表示対応 #    :2020/06/06 Ver2.00 Bitmap保存関連のAPIを追加 #    :2020/06/18 Ver2.10 キーコンフィグ関連の処理を修正 #    :2020/06/18 Ver2.20 パッド接続数のAPIを追加 #    :2020/06/18 Ver2.20 F12を押した際、API定義を読込しなおすように修正 #--------------------------------------------------------------------------- # 設置場所 #  なるべく上の方 # # 必要スクリプト # なし #--------------------------------------------------------------------------- # 使い方 # 定義確認関数 # $a1_win32api.defined?(関数名) # # 定義失敗チェック関数 # $a1_win32api.define_failure? # # 「定義失敗した関数リスト」に内容があると true を返します # # 「定義失敗した関数リスト」から内容を1つ取り出すメッセージウィンドウコマンド # \DF # # 取り出し続けると「定義失敗した関数リスト」が空になり # 「定義失敗チェック関数」が false を返すようになります #============================================================================== $imported ||= {} $imported["A1_Win32API"] = 2.20 #============================================================================== # ■ SceneManager #------------------------------------------------------------------------------ #  シーン遷移を管理するモジュールです。たとえばメインメニューからアイテム画面 # を呼び出し、また戻るというような階層構造を扱うことができます。 #============================================================================== module SceneManager #-------------------------------------------------------------------------- # ○ エイリアス用特異メソッド #-------------------------------------------------------------------------- class << self alias :a1_api_first_scene_class :first_scene_class end #-------------------------------------------------------------------------- # ☆ 最初のシーンクラスを取得 #-------------------------------------------------------------------------- def self.first_scene_class $a1_win32api.define_apis if $a1_win32api.api_instance.empty? a1_api_first_scene_class end end #============================================================================== # ■ A1_System::Win32Api #============================================================================== class A1_System::Win32Api #-------------------------------------------------------------------------- # ○ 定数 #-------------------------------------------------------------------------- HKEY_CURRENT_USER = 0x80000001 HKEY_LOCAL_MACHINE = 0x80000002 HKEY_USERS = 0x80000003 REG_OPTION_RESERVED = 0x0000 STANDARD_RIGHTS_READ = 0x00020000 KEY_QUERY_VALUE = 0x0001 KEY_ENUMERATE_SUB_KEYS = 0x0008 KEY_NOTIFY = 0x0010 KEY_READ = STANDARD_RIGHTS_READ | KEY_QUERY_VALUE | KEY_ENUMERATE_SUB_KEYS | KEY_NOTIFY PF_ARGB = 0x0026200A CP_UTF8 = 0xFDE9 #-------------------------------------------------------------------------- # 〇 ウィンドウの情報 #-------------------------------------------------------------------------- GAME_TITLE = load_data("Data/System.rvdata2").game_title.encode('SHIFT_JIS') #-------------------------------------------------------------------------- # ○ クラス変数 #-------------------------------------------------------------------------- @@api_instance = {} #-------------------------------------------------------------------------- # ○ オブジェクト初期化 #-------------------------------------------------------------------------- def initialize define_struct define_apis end #-------------------------------------------------------------------------- # ○ 構造体の定義 #-------------------------------------------------------------------------- def define_struct @pad_struct = Struct::new('PadState', :dwSize, :dwFlags, :dwXpos, :dwYpos, :dwZpos, :dwRpos, :dwUpos, :dwVpos, :dwButtonNumber, :dwButtons, :dwPOV, :dwReserved1, :dwReserved2) end #-------------------------------------------------------------------------- # ○ APIの定義 #-------------------------------------------------------------------------- def define_apis @failure_dll_list = [] define_api('advapi32', 'RegOpenKeyEx', %w(l p l l p), 'l') define_api('advapi32', 'RegQueryValueEx', %w(p p l p p p), 'l') define_api('advapi32', 'RegCloseKey', %w(p), 'l') define_api('kernel32', 'GetPrivateProfileString', 'pppplp', 'l') define_api('kernel32', 'WritePrivateProfileString', 'pppp', 'l') define_api('urlmon', 'URLDownloadToFile', 'ippii', 'l') define_api('unzip32', 'UnZip', 'pppl', 'l') define_api('user32', 'GetAsyncKeyState', 'l', 'l') define_api('winmm', 'joyGetPosEx', %w(l p), 'l') define_api('gdiplus', 'GdiplusStartup', 'ppi', 'i') define_api('gdiplus', 'GdipCreateBitmapFromScan0', 'iiiipp', 'i') define_api('gdiplus', 'GdipBitmapLockBits', 'ipiip', 'i') define_api('gdiplus', 'GdipBitmapUnlockBits', 'ip', 'i') define_api('kernel32', 'RtlMoveMemory', 'ppi', 'v') define_api('user32', 'GetDC', 'i', 'i') define_api('user32', 'FindWindow', 'pp', 'l') define_api('gdi32', 'StretchDIBits', 'iiiiiiiiippii', 'i') define_api('gdi32', 'BitBlt', 'iiiiiiiii', 'i') define_api('user32', 'ReleaseDC', 'ii', 'i') define_api('kernel32', 'RtlMoveMemory', 'ipi', 'v', 'RtlMoveMemoryI') define_api('gdiplus', 'GdipSaveImageToFile', 'ippp', 'i') define_api('rpcrt4', 'UuidFromString', 'pp', 'i') define_api('gdiplus', 'GdipDisposeImage', 'i', 'i') define_api('gdiplus', 'GdiplusShutdown', 'p', 'v') define_api('kernel32', 'RtlMoveMemory', 'pii', 'i', 'RtlMoveMemory_pi') define_api('kernel32', 'MultiByteToWideChar', 'iipipi', 'i') define_api('advapi32', 'GetUserName', 'pp', 'i') define_api('advapi32', 'LookupAccountName', 'ppppppp', 'i') define_api('System/A1CommonDLL','GetComputerSid', 'pi', 'i') define_api('System/A1CommonDLL','DllVersion', 'i', 'i') define_api('System/A1CommonDLL','PadConnect', 'i', 'i') end #-------------------------------------------------------------------------- # 〇 A1CommonDLLのバージョンを取得する #-------------------------------------------------------------------------- def a1_common_dll_vertion return DllVersion(0) end #-------------------------------------------------------------------------- # 〇 ゲームパッドの接続数を取得する #-------------------------------------------------------------------------- def connect_pad_num return PadConnect(0) end #-------------------------------------------------------------------------- # 〇 UUIFをStringから取得する #-------------------------------------------------------------------------- def uuid_from_string(clsid) uuid = [0].pack("i") UuidFromString(clsid, uuid) return uuid end #-------------------------------------------------------------------------- # 〇 ウィンドウハンドルを取得する #-------------------------------------------------------------------------- def game_handle return FindWindow("RGSS Player", GAME_TITLE) end #-------------------------------------------------------------------------- # 〇 バッファーに描画する #-------------------------------------------------------------------------- def buffer_blt(bitmap, buffer, rect, i) rect.y = bitmap.height - 1 - i buffer.blt(0, i, bitmap, rect) rect.y = i buffer.blt(0, bitmap.height - 1 - i, bitmap, rect) end #-------------------------------------------------------------------------- # 〇 GDI+の初期化 #-------------------------------------------------------------------------- def startup_gdiplus(token) ret = GdiplusStartup(token, [1, 0, 0, 0].pack("i4"), 0) == 0 unless ret msgbox "GDI+ の初期化に失敗しました。" end return ret end #-------------------------------------------------------------------------- # 〇 Bitmapからイメージを作成する #-------------------------------------------------------------------------- def gdip_create_image_from_bitmap(bitmap) GC.start buffer = Bitmap.new(bitmap.width, bitmap.height) rect = Rect.new(0, 0, bitmap.width, 1) (bitmap.height/2).times {|i| buffer_blt(bitmap, buffer, rect, i) } bitmap = buffer gpbmp = [0].pack("i") ret = GdipCreateBitmapFromScan0(bitmap.width, bitmap.height, 0, PF_ARGB, 0, gpbmp) return nil if ret != 0 image = gpbmp.unpack("i")[0] r = [0, 0, bitmap.width, bitmap.height].pack("i4") bd = [0, 0, 0, 0, 0, 0].pack("i6") GdipBitmapLockBits(image, r, 3, PF_ARGB, bd) GdipBitmapUnlockBits(image, bd) bd = bd.unpack("i6") line_size = (bitmap.width * 32 + 31) / 32 * 4 data = "\0".force_encoding('ASCII-8BIT') * (line_size * bitmap.height) RtlMoveMemory(data, bitmap.data, data.size) info = [40, bitmap.width, bitmap.height, (32 & 0xFFFF) | (1 << 16),0,0,0,0,0,0].pack("i10") wnddc = GetDC(game_handle) StretchDIBits(wnddc,0,bitmap.height,bitmap.width,-bitmap.height,0,0,bitmap.width,bitmap.height,info, data, 0, 0xCC0020) BitBlt(wnddc, 0, bitmap.width, bitmap.width, -bitmap.height,wnddc, 0, 0, 0xCC0020) ReleaseDC(game_handle, wnddc) RtlMoveMemoryI(bd[4], data, line_size * bitmap.height) bitmap.dispose return image end #-------------------------------------------------------------------------- # 〇 イメージをファイルに保存する #-------------------------------------------------------------------------- def gdip_save_image_to_file(image, filename, clsid) ret = GdipSaveImageToFile(image, filename, uuid_from_string(clsid), 0) msgbox "保存に失敗しました。" if ret != 0 end #-------------------------------------------------------------------------- # 〇 GDI+のイメージを解放 #-------------------------------------------------------------------------- def gdip_dispose_image(image) GdipDisposeImage(image) end #-------------------------------------------------------------------------- # 〇 GDI+をシャットダウン #-------------------------------------------------------------------------- def gdip_shutdown(token) GdiplusShutdown(token) end #-------------------------------------------------------------------------- # 〇 multiバイト文字を変換する #-------------------------------------------------------------------------- def multi_byte_to_wide_char(str) buffer = [""].pack('Z256') MultiByteToWideChar(CP_UTF8, 0, str, -1, buffer, buffer.size) return buffer end #-------------------------------------------------------------------------- # ○ 整数のポインタを作成 #-------------------------------------------------------------------------- def packdw(dw) [dw].pack('V') end #-------------------------------------------------------------------------- # ○ 整数のポインタを復元 #-------------------------------------------------------------------------- def unpackdw(dw) dw += [0].pack('V') dw.unpack('V')[0] end #-------------------------------------------------------------------------- # ○ ゲームパッドの状態を取得する #-------------------------------------------------------------------------- def pad_info info_buff = [ 52 , 0xff, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0].pack("I*") ret = joyGetPosEx(0, info_buff) info = info_buff.unpack("I*") return nil unless ret == 0 return @pad_struct.new(info[0], info[1], info[2], info[3], info[4], info[5], info[6], info[7], info[8], info[9], info[10], info[11], info[12]) end #-------------------------------------------------------------------------- # ○ キー入力状態を取得する #-------------------------------------------------------------------------- def key_state(key_code) return GetAsyncKeyState(key_code) end #-------------------------------------------------------------------------- # ○ zipを解凍する #-------------------------------------------------------------------------- def unzip(file_name) buf = "\0" * 128 UnZip(nil, file_name, buf, buf.size) end #-------------------------------------------------------------------------- # ○ Webからファイルを取得 #-------------------------------------------------------------------------- def download_web_file(url, file_name) return true if URLDownloadToFile(0, url, file_name, 0, 0) == 0 return false end #-------------------------------------------------------------------------- # ○ INIファイルに値を書き込む #-------------------------------------------------------------------------- def write_ini_value(file_name, section, key, value) ret = WritePrivateProfileString(section, key, value, file_name) return ret == 0 end #-------------------------------------------------------------------------- # ○ INIファイルから値を取得 #-------------------------------------------------------------------------- def read_ini_value(file_name, section, key) buffer_size = 256 buffer = "\0" * buffer_size buffer = buffer.encode('Shift_JIS', 'UTF-8') ret = GetPrivateProfileString(section, key, '', buffer, buffer_size, file_name) return nil if ret == 0 buffer = buffer.encode('UTF-8', 'Shift_JIS') return buffer.delete("\0") end #-------------------------------------------------------------------------- # ○ レジストリから値を取得 #-------------------------------------------------------------------------- def read_registry(key1, key2, sub_key, delete_zero = true) hKey = packdw(0) type = packdw(0) size = packdw(0) ret = RegOpenKeyEx(key1, key2, REG_OPTION_RESERVED, KEY_READ, hKey) return nil if ret != 0 hKey = unpackdw(hKey) ret = RegQueryValueEx(hKey, sub_key, 0, type, 0, size) if ret != 0 RegCloseKey(hKey) return nil end value = "\0" * unpackdw(size) value = value.encode('Shift_JIS', 'UTF-8') ret = RegQueryValueEx(hKey, sub_key, 0, type, value, size) return nil if ret != 0 value = value.encode('UTF-8', 'Shift_JIS') RegCloseKey(hKey) return delete_zero ? value.delete("\0") : value end #-------------------------------------------------------------------------- # ○ SIDを取得 #-------------------------------------------------------------------------- def get_sid buffer_size = 256 buffer = "\0" * buffer_size ret = GetComputerSid(buffer, buffer_size) return buffer.gsub("\u0000", "") end #-------------------------------------------------------------------------- # ○ ボタン割り当てを取得 #-------------------------------------------------------------------------- def get_button_assign key1 = HKEY_USERS key2 = "#{get_sid}\\SOFTWARE\\Enterbrain\\RGSS3" sub_key = "ButtonAssign" return read_registry(key1, key2, sub_key, false) end #-------------------------------------------------------------------------- # ○ RPGツクール2000のRTPのパスを取得 #-------------------------------------------------------------------------- def get_2000rtp_path key1 = HKEY_CURRENT_USER key2 = "Software\\ASCII\\RPG2000" sub_key = "RuntimePackagePath" return read_registry(key1, key2, sub_key) end #-------------------------------------------------------------------------- # ○ RPGツクール2003のRTPのパスを取得 #-------------------------------------------------------------------------- def get_2003rtp_path key1 = HKEY_CURRENT_USER key2 = "Software\\Enterbrain\\RPG2003" sub_key = "RUNTIMEPACKAGEPATH" return read_registry(key1, key2, sub_key) end #-------------------------------------------------------------------------- # ○ RPGツクールXPのRTPのパスを取得 #-------------------------------------------------------------------------- def get_xprtp_path key1 = HKEY_LOCAL_MACHINE key2 = "SOFTWARE\\Enterbrain\\RGSS\\RTP" sub_key = "Standard" return read_registry(key1, key2, sub_key) end #-------------------------------------------------------------------------- # ○ RPGツクールVXのRTPのパスを取得 #-------------------------------------------------------------------------- def get_vxrtp_path key1 = HKEY_LOCAL_MACHINE key2 = "SOFTWARE\\Enterbrain\\RGSS2\\RTP" sub_key = "RPGVX" return read_registry(key1, key2, sub_key) end #-------------------------------------------------------------------------- # ○ 定義されていないメソッドを呼ばれた時の処理 #-------------------------------------------------------------------------- def method_missing(name, *param) return unless param[0] return @@api_instance[name].call(*param) if @@api_instance[name] super(name, *param) rescue => exp exp.backtrace.shift raise(exp.class, exp.message, exp.backtrace) end #-------------------------------------------------------------------------- # ○ API 関数を定義 #-------------------------------------------------------------------------- def define_api(dllname, proc, import, export, alias_proc = nil) key = alias_proc ? alias_proc.intern : proc.intern return if @@api_instance[key] @@api_instance[key] = Win32API.new(dllname, proc, import, export) rescue @failure_dll_list.push([dllname, proc]) end #-------------------------------------------------------------------------- # ○ API定義失敗関数リスト #-------------------------------------------------------------------------- def failure_dll ret = @failure_dll_list[0] @failure_dll_list.delete_at(0) return ret end #-------------------------------------------------------------------------- # ○ API定義失敗チェック #-------------------------------------------------------------------------- def define_failure? return false if @failure_dll_list.empty? return true end #-------------------------------------------------------------------------- # ○ API定義チェック #-------------------------------------------------------------------------- def defined?(proc) key = proc.intern return @@api_instance.has_key?(key) end #-------------------------------------------------------------------------- # ○ API定義チェック(全体) #-------------------------------------------------------------------------- def api_instance return @@api_instance end end #============================================================================== # ■ Window_Base #------------------------------------------------------------------------------ #  ゲーム中の全てのウィンドウのスーパークラスです。 #============================================================================== class Window_Base < Window #-------------------------------------------------------------------------- # ☆ 制御文字の事前変換 # 実際の描画を始める前に、原則として文字列に変わるものだけを置き換える。 # 文字「\」はエスケープ文字(\e)に変換。 #-------------------------------------------------------------------------- alias a1_win32api_wm_convert_escape_characters convert_escape_characters def convert_escape_characters(text) result = a1_win32api_wm_convert_escape_characters(text) result.gsub!(/\eDF/i) { make_failure_msg } return result end #-------------------------------------------------------------------------- # ○ 失敗メッセージの作成 #-------------------------------------------------------------------------- def make_failure_msg info = $a1_win32api.failure_dll return "#{info[0]}.DLL の #{info[1]}関数" end end #============================================================================== # ■ DataManager #------------------------------------------------------------------------------ #  データベースとゲームオブジェクトを管理するモジュールです。ゲームで使用する # ほぼ全てのグローバル変数はこのモジュールで初期化されます。 #============================================================================== module DataManager #-------------------------------------------------------------------------- # ○ エイリアス用特異メソッド #-------------------------------------------------------------------------- class << self alias :a1_win32_api_game_objects :create_game_objects end #-------------------------------------------------------------------------- # ☆ 各種ゲームオブジェクトの作成 #-------------------------------------------------------------------------- def self.create_game_objects $a1_win32api ||= A1_System::Win32Api.new a1_win32_api_game_objects end end #============================================================================== # ■ Bitmap #============================================================================== class Bitmap #-------------------------------------------------------------------------- # 〇 ビットマップデータ #-------------------------------------------------------------------------- def data buffer = [0].pack('L') $a1_win32api.RtlMoveMemory_pi(buffer, object_id * 2 + 16, 4) $a1_win32api.RtlMoveMemory_pi(buffer, buffer.unpack("L")[0] + 8, 4) $a1_win32api.RtlMoveMemory_pi(buffer, buffer.unpack("L")[0] + 16, 4) return buffer.unpack("L")[0] end #-------------------------------------------------------------------------- # 〇 定数 #-------------------------------------------------------------------------- CLSID_BMP = '557CF400-1A04-11D3-9A73-0000F81EF32E' CLSID_JPEG = '557CF401-1A04-11D3-9A73-0000F81EF32E' CLSID_GIF = '557CF402-1A04-11D3-9A73-0000F81EF32E' CLSID_TIFF = '557CF405-1A04-11D3-9A73-0000F81EF32E' CLSID_PNG = '557CF406-1A04-11D3-9A73-0000F81EF32E' #-------------------------------------------------------------------------- # 〇 Bitmapをpngファイルに保存する #-------------------------------------------------------------------------- def screen_save(fn) bitmap = Bitmap.new(self.width, self.height) bitmap.fill_rect(self.rect, Color.new(255, 255, 255)) bitmap.blt(0, 0, self, self.rect) clsid = CLSID_PNG fn = "#{fn}.png" filename = $a1_win32api.multi_byte_to_wide_char(fn) token = [0].pack("i") return unless $a1_win32api.startup_gdiplus(token) image = $a1_win32api.gdip_create_image_from_bitmap(bitmap) gdip_save_image(image, filename, clsid) if image $a1_win32api.gdip_shutdown(token) bitmap.dispose GC.start end #-------------------------------------------------------------------------- # 〇 イメージを保存する #-------------------------------------------------------------------------- def gdip_save_image(image, filename, clsid) $a1_win32api.gdip_save_image_to_file(image, filename, clsid) $a1_win32api.gdip_dispose_image(image) end end