#****************************************************************************** # # * Custom Menu Base # # -------------------------------------------------------------------------- # バージョン : 1.0.0 # 対 応 : RPGツクールVX Ace : RGSS3 # 制 作 者 : CACAO # 配 布 元 : http://cacaosoft.web.fc2.com/ # -------------------------------------------------------------------------- # == 概 要 == # # : カスタムメニューのベーススクリプトです。 # # -------------------------------------------------------------------------- # == 注意事項 == # # ※ このスクリプトは、なるべく下のほうのに導入してください。 # ※ カスタムメニュー関連のスクリプトより上に導入してください。 # # #****************************************************************************** #============================================================================== # ◆ ユーザー設定 #============================================================================== module CAO module CM #-------------------------------------------------------------------------- # ◇ メニュー項目の設定 #-------------------------------------------------------------------------- COMMAND_ITEMS = {} COMMAND_ITEMS[:item] = { :name => "Item", :command => Scene_Item, :help => 'Use item.' } COMMAND_ITEMS[:skill] = { :name => "Skill", :personal => Scene_Skill, :help => 'Use skill.' } COMMAND_ITEMS[:equip] = { :name => "Equip", :personal => Scene_Equip, :help => 'Change equipment.' } COMMAND_ITEMS[:status] = { :name => "Status", :personal => Scene_Status, :help => 'Check status.' } COMMAND_ITEMS[:formation] = { :name => "Formation", :command => :command_formation, :enable => :formation_enabled, :help => 'Rearrange the party.' } COMMAND_ITEMS[:game_end] = { :name => "End Game", :command => Scene_End, :help => 'Quit the game.' } COMMAND_ITEMS[:file] = { :name => "File", :sub => :sub_file, :help => 'Save or load the game.' } COMMAND_ITEMS[:save] = { :name => "Save", :command => Scene_Save, :enable => "!$game_system.save_disabled", :help => 'Save the game.' } COMMAND_ITEMS[:load] = { :name => "Load", :command => Scene_Load, :enable => "DataManager.save_file_exists?", :help => 'Load the game.' } COMMAND_ITEMS[:sample] = { :name => "Options", :sub => :sub_sample, :help => 'Volume settings and game quit.' } COMMAND_ITEMS[:common] = { :name => "Common Event", :command => 'start_common_event(2)', :enable => "!$game_switches[3]", :help => 'Execute common event.' } COMMAND_ITEMS[:levelup] = { :name => "Level Up", :personal => 'start_common_event(1)', :enable => "$game_variables[1] != 2", :refresh => [:status], :help => 'Common event sample after actor selection.' } COMMAND_ITEMS[:switch] = { :name => [3, "Switch ON", "Switch OFF"], :command => "$game_switches[3] ^= true", :refresh => [:command, :text], :help => 'Operate the switch.' } COMMAND_ITEMS[:variable] = { :name => ['"EV Variable #{$game_variables[1]}"'], :command => "$game_variables[1] = ($game_variables[1] + 1) % 3", :refresh => [:command, :text], :help => 'Operate EV variables.' } COMMAND_ITEMS[:medal] = { :name => TMMEDAL::COMMAND_MEDAL, :command => :command_medal, :enable => :medal_enabled, :hide => 'TMMEDAL::HIDE_COMMAND && !medal_enabled' } COMMAND_ITEMS[:audio] = { :name => "Volume Settings", :command => HZM_VXA::AudioVol::Scene_VolConfig, } #-------------------------------------------------------------------------- # ◇ 表示項目の設定 #-------------------------------------------------------------------------- COMMANDS = {} COMMANDS[:main] = # 必須 [:item, :skill, :equip, :status, :formation, :medal, :file, :sample] COMMANDS[:sub_file] = [:save, :load] COMMANDS[:sub_sample] = [:audio, :language, :game_end] #-------------------------------------------------------------------------- # ◇ 残りHPで顔グラを変化させる #-------------------------------------------------------------------------- EXPRESSIVE_RATE = [] #-------------------------------------------------------------------------- # ◇ 立ち絵のファイル名 #-------------------------------------------------------------------------- PORTRAIT_NAME = "MActor%d" #-------------------------------------------------------------------------- # ◇ 背景画像 #-------------------------------------------------------------------------- # 前景画像(最前面に表示されます。) FILE_FOREGROUND = nil # 背景画像(デフォルトのマップ画像と入れ替えます。) FILE_BACKGROUND = nil # アニメ画像 ["ファイル名", vx, vy, 最背面?] BACKIMAGE = nil #-------------------------------------------------------------------------- # ◇ システム文字の有無 #-------------------------------------------------------------------------- VISIBLE_SYSTEM = true #-------------------------------------------------------------------------- # ◇ 用語設定 #-------------------------------------------------------------------------- VOCABS = {} VOCABS[:gold] = "Money" VOCABS[:exp] = "EXP" VOCABS[:exp_a] = "EXP" end # module CM end # module CAO #/////////////////////////////////////////////////////////////////////////////# # # # 下記のスクリプトを変更する必要はありません。 # # # #/////////////////////////////////////////////////////////////////////////////# class CustomizeError < Exception; end class Game_MenuItem #-------------------------------------------------------------------------- # ● #-------------------------------------------------------------------------- attr_reader :symbol attr_reader :sub attr_reader :enable attr_reader :refresh #-------------------------------------------------------------------------- # ● #-------------------------------------------------------------------------- def initialize(symbol, params = {}) @symbol = symbol # 項目の識別子 @name = params[:name] || "" # 項目名 @help = params[:help] || "" # ヘルプ @icon = params[:icon] # アイコン番号 @scene = params[:scene] # 項目処理 シーン遷移 @command = params[:command] # 項目処理 コマンド実行 @personal = params[:personal] # 項目処理 アクター選択 @sub = params[:sub] # 項目処理 サブコマンド case [@scene, @command, @personal, @sub].count {|o| o } when 0; raise CustomizeError, "項目処理が設定されていません。" when 1 # Do Nothing else; raise CustomizeError, "複数の項目処理が設定されています。" end @enable = params[:enable] || true # 選択の可否 @hide = params[:hide] || false # 非表示の有無 @refresh = params[:refresh] || [] # 項目処理後に再描画 end #-------------------------------------------------------------------------- # ● #-------------------------------------------------------------------------- def _convert_value(obj) if obj.is_a?(Array) case obj[0] when String result = eval(obj[0], ::TOPLEVEL_BINDING) return result if obj.size == 1 return obj[result ? 1 : 2] if result == !!result return obj[result + 1] when Integer if obj.size == 3 return obj[$game_switches[obj[0]] ? 1 : 2] else return obj[$game_variables[obj[0]]] end else raise "must not happen" end else return obj end end private :_convert_value #-------------------------------------------------------------------------- # ● #-------------------------------------------------------------------------- def name return _convert_value(@name) end #-------------------------------------------------------------------------- # ● #-------------------------------------------------------------------------- def help return _convert_value(@help) end alias description help #-------------------------------------------------------------------------- # ● #-------------------------------------------------------------------------- def icon_index return _convert_value(@icon) end #-------------------------------------------------------------------------- # ● #-------------------------------------------------------------------------- def handler return :command_ok if @scene return @command if @command && @command.is_a?(Symbol) return :command_ok if @command return @personal if @personal && @personal.is_a?(Symbol) return :command_personal if @personal return :command_sub if @sub raise "must not happen" end #-------------------------------------------------------------------------- # ● #-------------------------------------------------------------------------- def exec # # ここでエラーが発生した場合、項目の設定が間違っている可能性があります。 # 項目処理の設定を確認してください。 # # エラーメッセージを確認の上、設定を修正してください。 # つづり間違いや文法が間違っている可能性があります。 # if @scene case @scene when Class return SceneManager.call(@scene.untaint) when Symbol return SceneManager.call(Kernel.const_get(@scene).untaint) when String return SceneManager.call(eval(@scene, ::TOPLEVEL_BINDING).untaint) end else command = @command || @personal case command when Class return SceneManager.call(command.untaint) when String return SceneManager.scene.instance_eval(command) end end raise "must not happen" end #-------------------------------------------------------------------------- # ● #-------------------------------------------------------------------------- def hide? # # ここでエラーが発生した場合、項目の設定が間違っている可能性があります。 # オプションの :hide の設定を確認してください。 # case @hide when true, false return @hide when String return eval(@hide, ::TOPLEVEL_BINDING) else raise "must not happen" end end #-------------------------------------------------------------------------- # ● #-------------------------------------------------------------------------- def personal? return @personal && true end #-------------------------------------------------------------------------- # ● #-------------------------------------------------------------------------- def refresh? return !@refresh.empty? end end class Scene_Menu #-------------------------------------------------------------------------- # ○ 開始処理 #-------------------------------------------------------------------------- def start super create_command_window create_status_window create_option_window end #-------------------------------------------------------------------------- # ○ フレーム更新 #-------------------------------------------------------------------------- def update super update_backimage update_command_window update_status_window update_option_window end #-------------------------------------------------------------------------- # ○ 終了処理 #-------------------------------------------------------------------------- def terminate super dispose_command_window dispose_status_window dispose_option_window end #-------------------------------------------------------------------------- # ○ 背景の作成 #-------------------------------------------------------------------------- def create_background create_backimage if CAO::CM::BACKIMAGE && CAO::CM::BACKIMAGE[3] if CAO::CM::FILE_BACKGROUND @background_sprite = Sprite.new @background_sprite.bitmap = Cache.system(CAO::CM::FILE_BACKGROUND) else super end create_backimage if CAO::CM::BACKIMAGE && !CAO::CM::BACKIMAGE[3] if CAO::CM::FILE_FOREGROUND @foreground_sprite = Sprite.new @foreground_sprite.z = 1000 @foreground_sprite.bitmap = Cache.system(CAO::CM::FILE_FOREGROUND) end end #-------------------------------------------------------------------------- # ○ 背景の解放 #-------------------------------------------------------------------------- def dispose_background super @backimage_sprite.dispose if @backimage_sprite @foreground_sprite.dispose if @foreground_sprite end #-------------------------------------------------------------------------- # ● #-------------------------------------------------------------------------- def create_backimage return unless CAO::CM::BACKIMAGE @backimage_sprite = Plane.new @backimage_sprite.bitmap = Cache.system(CAO::CM::BACKIMAGE[0]) end #-------------------------------------------------------------------------- # ● #-------------------------------------------------------------------------- def update_backimage return unless @backimage_sprite return unless CAO::CM::BACKIMAGE[1] && CAO::CM::BACKIMAGE[2] @backimage_sprite.ox -= CAO::CM::BACKIMAGE[1] @backimage_sprite.oy -= CAO::CM::BACKIMAGE[2] end #-------------------------------------------------------------------------- # ● コマンドウィンドウの作成 #-------------------------------------------------------------------------- def create_command_window # Do Nothing end #-------------------------------------------------------------------------- # ● ステータスウィンドウの作成 #-------------------------------------------------------------------------- def create_status_window # Do Nothing end #-------------------------------------------------------------------------- # ● オプションウィンドウの作成 #-------------------------------------------------------------------------- def create_option_window # Do Nothing end #-------------------------------------------------------------------------- # ● コマンドウィンドウの更新 #-------------------------------------------------------------------------- def update_command_window # Do Nothing end #-------------------------------------------------------------------------- # ● ステータスウィンドウの更新 #-------------------------------------------------------------------------- def update_status_window # Do Nothing end #-------------------------------------------------------------------------- # ● オプションウィンドウの更新 #-------------------------------------------------------------------------- def update_option_window # Do Nothing end #-------------------------------------------------------------------------- # ● コマンドウィンドウの解放 #-------------------------------------------------------------------------- def dispose_command_window # Do Nothing end #-------------------------------------------------------------------------- # ● ステータスウィンドウの解放 #-------------------------------------------------------------------------- def dispose_status_window # Do Nothing end #-------------------------------------------------------------------------- # ● オプションウィンドウの解放 #-------------------------------------------------------------------------- def dispose_option_window # Do Nothing end #-------------------------------------------------------------------------- # ● コマンド [決定] #-------------------------------------------------------------------------- def command_ok @command_window.current_exec @command_window.activate check_common_event check_refresh_window(@command_window.current_data) end #-------------------------------------------------------------------------- # ○ 個人コマンド [決定] #-------------------------------------------------------------------------- def on_personal_ok command_ok end #-------------------------------------------------------------------------- # ● コモンイベント予約判定 # イベントの呼び出しが予約されているならマップ画面へ遷移する。 #-------------------------------------------------------------------------- def check_common_event SceneManager.goto(Scene_Map) if $game_temp.common_event_reserved? end #-------------------------------------------------------------------------- # ● 項目処理後のリフレッシュ #-------------------------------------------------------------------------- def check_refresh_window(command) # Do Nothing end #-------------------------------------------------------------------------- # ● コモンベントの実行 #-------------------------------------------------------------------------- def start_common_event(common_event_id) if @status_window && @status_window.index >= 0 $game_party.menu_actor = $game_party.members[@status_window.index] end interpreter = Scene_Menu::Game_Interpreter.new interpreter.setup($data_common_events[common_event_id].list) interpreter.update while interpreter.running? end end class Scene_Menu::Game_Interpreter < ::Game_Interpreter #-------------------------------------------------------------------------- # ● #-------------------------------------------------------------------------- undef command_101 # 文章の表示 undef command_102 # 選択肢の表示 undef command_103 # 数値入力の処理 undef command_104 # アイテム選択の処理 undef command_105 # スクロール文章の表示 undef command_201 # 場所移動 undef command_204 # マップのスクロール undef command_205 # 移動ルートの設定 undef command_217 # 隊列メンバーの集合 undef command_261 # ムービーの再生 undef command_301 # バトルの処理 undef command_351 # メニュー画面を開く end class Window_CustomMenuCommand < Window_MenuCommand #-------------------------------------------------------------------------- # ● オブジェクト初期化 #-------------------------------------------------------------------------- def initialize(ident) @ident = ident super() end #-------------------------------------------------------------------------- # ● ウィンドウ内容の幅を計算 #-------------------------------------------------------------------------- def contents_width (item_width + spacing) * col_max - spacing end #-------------------------------------------------------------------------- # ● 横に項目が並ぶときの空白の幅を取得 #-------------------------------------------------------------------------- def spacing return 8 end #-------------------------------------------------------------------------- # ● コマンドリストの作成 #-------------------------------------------------------------------------- def make_command_list return unless @ident unless CAO::CM::COMMANDS[@ident] raise CustomizeError, "識別子 :#{@ident} のメニューコマンドの設定がありません。(COMMANDS)" end CAO::CM::COMMANDS[@ident].each do |symbol| unless CAO::CM::COMMAND_ITEMS[symbol] puts "識別子 :#{symbol} の項目の設定がありません。(COMMAND_ITEMS)" next end item = Game_MenuItem.new(symbol, CAO::CM::COMMAND_ITEMS[symbol]) @list << item unless item.hide? end end #-------------------------------------------------------------------------- # ● コマンド名の取得 #-------------------------------------------------------------------------- def command_name(index) @list[index].name end #-------------------------------------------------------------------------- # ● コマンドの有効状態を取得 #-------------------------------------------------------------------------- def command_enabled?(index) param = @list[index].enable return false if @list[index].personal? && !$game_party.exists return true if param == true return false if param == false return eval(param.to_s) if param.is_a?(Symbol) || param.is_a?(String) raise "must not happen" end #-------------------------------------------------------------------------- # ● コマンドアイコン番号の取得 #-------------------------------------------------------------------------- def command_icon_index(index) return @list[index].icon_index end #-------------------------------------------------------------------------- # ● 選択項目のコマンドデータを取得 #-------------------------------------------------------------------------- def current_data index >= 0 ? @list[index] : nil end #-------------------------------------------------------------------------- # ● 選択項目の有効状態を取得 #-------------------------------------------------------------------------- def current_item_enabled? index >= 0 ? command_enabled?(index) : false end #-------------------------------------------------------------------------- # ● 選択項目のシンボルを取得 #-------------------------------------------------------------------------- def current_symbol current_data ? current_data.symbol : nil end #-------------------------------------------------------------------------- # ● 選択項目の実行 #-------------------------------------------------------------------------- def current_exec current_data.exec end #-------------------------------------------------------------------------- # ● 指定されたシンボルを持つコマンドにカーソルを移動 #-------------------------------------------------------------------------- def select_symbol(symbol) @list.each_index {|i| select(i) if @list[i].symbol == symbol } end #-------------------------------------------------------------------------- # ● #-------------------------------------------------------------------------- def clear_handler @handler = {} end #-------------------------------------------------------------------------- # ● 動作に対応するハンドラの設定 #-------------------------------------------------------------------------- def set_handlers(obj) # # ここでエラーが発生した場合、項目の設定が間違っている可能性があります。 # 項目処理の設定を確認してください。 # # NameError : undefined method `○○' for class `Scene_Menu' # つづりが間違っていないか確認してください。 # # NameError : undefined method `command_sub' for class `Scene_Menu' # 『サブコマンド』スクリプトが未導入の可能性があります。 # @list.each {|cmd| @handler[cmd.symbol] = obj.method(cmd.handler) } end #-------------------------------------------------------------------------- # ● カーソルを下に移動 #-------------------------------------------------------------------------- def cursor_down(wrap = false) if index < item_max - col_max || (wrap && col_max == 1) select((index + col_max) % item_max) elsif col_max != 1 && index < (item_max.to_f/col_max).ceil*col_max-col_max select(item_max - 1) end end #-------------------------------------------------------------------------- # ● 項目の描画 #-------------------------------------------------------------------------- def draw_item(index) rect = item_rect(index) enabled = command_enabled?(index) if command_icon_index(index) draw_icon(command_icon_index(index), rect.x, rect.y, enabled) rect.x += 26 rect.width -= 28 else rect.x += 4 rect.width -= 8 end change_color(normal_color, enabled) draw_text(rect, command_name(index), alignment) end #-------------------------------------------------------------------------- # ● リフレッシュ #-------------------------------------------------------------------------- def refresh self.contents.clear draw_all_items end end class Game_Actor #-------------------------------------------------------------------------- # ● 公開インスタンス変数 #-------------------------------------------------------------------------- attr_accessor :portrait_name # 立ち絵 ファイル名 #-------------------------------------------------------------------------- # ● 立ち絵のファイル名を取得 #-------------------------------------------------------------------------- def portrait_name return @portrait_name if @portrait_name return sprintf(CAO::CM::PORTRAIT_NAME, self.id, self.expression_index) end #-------------------------------------------------------------------------- # ● 表情のインデックス #-------------------------------------------------------------------------- def expression_index rate = (self.hp_rate * 100).ceil index = CAO::CM::EXPRESSIVE_RATE.index {|r| r < rate } return index || CAO::CM::EXPRESSIVE_RATE.size end #-------------------------------------------------------------------------- # ● 経験値の割合を取得 #-------------------------------------------------------------------------- def cm_exp_rate return 1.0 if max_level? return self.cm_accumulated_exp / self.cm_requisite_exp.to_f end #-------------------------------------------------------------------------- # ● レベルアップに必要な経験値を取得 #-------------------------------------------------------------------------- def cm_requisite_exp return self.next_level_exp - self.current_level_exp end #-------------------------------------------------------------------------- # ● 現在のレベルでの経験値を取得 #-------------------------------------------------------------------------- def cm_accumulated_exp return self.exp - self.current_level_exp end #-------------------------------------------------------------------------- # ● レベルアップに必要な残りの経験値を取得 #-------------------------------------------------------------------------- def cm_remaining_exp return self.next_level_exp - self.exp end end class CAO::CM::Canvas include CAO::CM #-------------------------------------------------------------------------- # ● 公開インスタンス変数 #-------------------------------------------------------------------------- attr_reader :window attr_reader :bitmap #-------------------------------------------------------------------------- # ● オブジェクト初期化 #-------------------------------------------------------------------------- def initialize(obj) case obj when Window @window = obj @bitmap = obj.contents when Bitmap @window = nil @bitmap = obj else raise TypeError, "wrong argument type #{obj.class} (expected Bitmap or Window)" end end #-------------------------------------------------------------------------- # ● #-------------------------------------------------------------------------- def contents return @window ? @window.contents : @bitmap end #-------------------------------------------------------------------------- # ● #-------------------------------------------------------------------------- def draw_actor_items(actor, x, y, list) # # メニューステータスの設定が間違っている可能性があります。 # 表示項目の設定を確認してください。 # # TypeError # 引数の型(数値や文字列など)が間違っています。 # 設定がずれているかもしれません。 # 設定は必ず [シンボル, 数値, 数値, ... ] の形で始まります。 # 識別子とx座標とy座標の設定は省略できません。 # # ArgumentError : wrong number of arguments # 引数の数が間違っています。 # オプション部分の設定に間違いがないか確認してください。 # list.each do |params| symbol = params[0] argv = params[1, params.size] xx, yy = argv[0], argv[1] unless METHODS_NAME[symbol] puts "識別子 :#{symbol} の処理は定義されていません。" next end unless xx && yy raise CustomizeError, "描画する座標が設定されていません。" end begin opt = (argv.size <= 2) ? [] : argv[2, argv.size - 2] eval("#{METHODS_NAME[symbol]}(actor, x + xx, y + yy, *opt)") rescue msg = "{ Actor(#{actor.respond_to?(:id)&&actor.id}) " msg << "Symbol(:#{symbol}) Method(#{METHODS_NAME[symbol]}) }\n" msg << $!.message raise $!, msg, $!.backtrace end end end #-------------------------------------------------------------------------- # ● #-------------------------------------------------------------------------- METHODS_NAME = {} METHODS_NAME[:w_chara] = '@window.draw_actor_graphics' METHODS_NAME[:w_face] = '@window.draw_actor_face' METHODS_NAME[:w_name] = '@window.draw_actor_name' METHODS_NAME[:w_class] = '@window.draw_actor_class' METHODS_NAME[:w_nick] = '@window.draw_actor_nickname' METHODS_NAME[:w_level] = '@window.draw_actor_level' METHODS_NAME[:w_state] = '@window.draw_actor_icons' METHODS_NAME[:w_hp] = '@window.draw_actor_hp' METHODS_NAME[:w_mp] = '@window.draw_actor_mp' METHODS_NAME[:w_tp] = '@window.draw_actor_tp' if CAO::CM::EXPRESSIVE_RATE.empty? METHODS_NAME[:face] = :draw_actor_face else METHODS_NAME[:face] = :draw_actor_expression end METHODS_NAME[:chara] = :draw_actor_graphic METHODS_NAME[:name] = :draw_actor_name METHODS_NAME[:class] = :draw_actor_class METHODS_NAME[:nick] = :draw_actor_nickname METHODS_NAME[:level] = :draw_actor_level METHODS_NAME[:lv_g] = :draw_actor_level_g METHODS_NAME[:state] = :draw_actor_icons METHODS_NAME[:hp] = :draw_actor_hp METHODS_NAME[:mp] = :draw_actor_mp METHODS_NAME[:tp] = :draw_actor_tp METHODS_NAME[:exp] = :draw_actor_exp METHODS_NAME[:param] = :draw_actor_param METHODS_NAME[:icon] = :draw_actor_icon METHODS_NAME[:bust] = :draw_actor_portrait METHODS_NAME[:fill] = :draw_actor_rect METHODS_NAME[:pict] = :draw_actor_picture METHODS_NAME[:text] = :draw_actor_text METHODS_NAME[:num] = :draw_actor_number #-------------------------------------------------------------------------- # ● 定数 #-------------------------------------------------------------------------- COLOR_AIB_1 = Color.new(0, 0, 0) # アクターアイコンの縁の色 COLOR_AIB_2 = Color.new(255, 255, 255) # アクターアイコンの背景色 #-------------------------------------------------------------------------- # ● 行の高さを取得 #-------------------------------------------------------------------------- def line_height return 24 end #-------------------------------------------------------------------------- # ● 半透明描画用のアルファ値を取得 #-------------------------------------------------------------------------- def translucent_alpha return 160 end #-------------------------------------------------------------------------- # ● #-------------------------------------------------------------------------- def str2color(value) case value when Color return value when Array return Color.new(*value) when Integer num = value when Symbol, String text = value.to_s.sub(/^(0x|x)/, "") case text.size when 1; text = text * 6 << 'FF' when 2; text = text[0] * 6 << text[1] * 2 when 3; text = text[0] * 2 << text[1] * 2 << text[2] * 2 << 'FF' when 4; text = text[0] * 2 << text[1] * 2 << text[2] * 2 << text[3] * 2 when 6; text = text[0, 6] << 'FF' end num = eval("0x#{text}") end return Color.new(num >> 24, num >> 16 & 255, num >> 8 & 255, num & 255) end #-------------------------------------------------------------------------- # ● 文字色取得 # n : 文字色番号(0..31) #-------------------------------------------------------------------------- def text_color(n, enabled = true) color = Cache.system("Window").get_pixel(64+(n%8)*8, 96+(n/8)*8) color.alpha = translucent_alpha unless enabled return color end #-------------------------------------------------------------------------- # ● 各種文字色の取得 #-------------------------------------------------------------------------- def normal_color; text_color(0); end; # 通常 def system_color; text_color(16); end; # システム def crisis_color; text_color(17); end; # ピンチ def knockout_color; text_color(18); end; # 戦闘不能 def gauge_back_color; text_color(19); end; # ゲージ背景 def hp_gauge_color1; text_color(20); end; # HP ゲージ 1 def hp_gauge_color2; text_color(21); end; # HP ゲージ 2 def mp_gauge_color1; text_color(22); end; # MP ゲージ 1 def mp_gauge_color2; text_color(23); end; # MP ゲージ 2 def mp_cost_color; text_color(23); end; # 消費 MP def power_up_color; text_color(24); end; # 装備 パワーアップ def power_down_color; text_color(25); end; # 装備 パワーダウン def tp_gauge_color1; text_color(28); end; # TP ゲージ 1 def tp_gauge_color2; text_color(29); end; # TP ゲージ 2 def tp_cost_color; text_color(29); end; # 消費 TP def exp_gauge_color1; text_color(30); end; # EXP ゲージ 1 def exp_gauge_color2; text_color(31); end; # EXP ゲージ 2 #-------------------------------------------------------------------------- # ● 保留項目の背景色を取得 #-------------------------------------------------------------------------- def pending_color Cache.system("Window").get_pixel(80, 80) end #-------------------------------------------------------------------------- # ● テキスト描画色の変更 #-------------------------------------------------------------------------- def change_color(color, enabled = true) if block_given? last_color = self.contents.font.color.dup change_color(color, enabled) yield self.contents.font.color = last_color else self.contents.font.color.set(color) self.contents.font.color.alpha = translucent_alpha unless enabled end end #-------------------------------------------------------------------------- # ● テキストサイズの変更 #-------------------------------------------------------------------------- def change_size(size) if block_given? last_size = self.contents.font.size change_size(size) yield self.contents.font.size = last_size else self.contents.font.size = size end end #-------------------------------------------------------------------------- # ● テキストの描画 #-------------------------------------------------------------------------- def draw_text(*args) contents.draw_text(*args) end #-------------------------------------------------------------------------- # ● テキストサイズの取得 #-------------------------------------------------------------------------- def text_size(str) contents.text_size(str) end #-------------------------------------------------------------------------- # ● 制御文字つきテキストの描画 #-------------------------------------------------------------------------- def draw_text_ex(x, y, text) reset_font_settings text = convert_escape_characters(text) pos = {:x => x, :y => y, :new_x => x, :height => calc_line_height(text)} process_character(text.slice!(0, 1), text, pos) until text.empty? end #-------------------------------------------------------------------------- # ● フォント設定のリセット #-------------------------------------------------------------------------- def reset_font_settings change_color(normal_color) contents.font.size = Font.default_size contents.font.bold = Font.default_bold contents.font.italic = Font.default_italic end #-------------------------------------------------------------------------- # ● 制御文字の事前変換 # 実際の描画を始める前に、原則として文字列に変わるものだけを置き換える。 # 文字「\」はエスケープ文字(\e)に変換。 #-------------------------------------------------------------------------- def convert_escape_characters(text) result = text.to_s.clone result.gsub!(/\r\n/) { "\n" } result.gsub!(/\\/) { "\e" } result.gsub!(/\e\e/) { "\\" } result.gsub!(/\e({+)/i) { "\e{" * $1.count("{") } result.gsub!(/\e(}+)/i) { "\e}" * $1.count("}") } result.gsub!(/\eV\[(\d+)\]/i) { $game_variables[$1.to_i] } result.gsub!(/\eV\[(\d+)\]/i) { $game_variables[$1.to_i] } result.gsub!(/\eS\[(\d+),(.*?),(.*?)\]/i) { $game_switches[$1.to_i]?$2:$3 } result.gsub!(/\eN\[(\d+)\]/i) { actor_name($1.to_i) } result.gsub!(/\eP\[(\d+)\]/i) { party_member_name($1.to_i) } result.gsub!(/\eG/i) { Vocab::currency_unit } result.gsub!(/\e\$/) { $game_party.gold } result.gsub!(/\eW/) { $game_party.steps } result.gsub!(/\eT\[(.+?)\]/i) { play_time($1) } result.gsub!(/\eT/i) { play_time } result.gsub!(/\en/) { "\n" } result.gsub!(/<%(.*?)%>/) { eval($1) } result end #-------------------------------------------------------------------------- # ● アクター n 番の名前を取得 #-------------------------------------------------------------------------- def actor_name(n) actor = n >= 1 ? $game_actors[n] : nil actor ? actor.name : "" end #-------------------------------------------------------------------------- # ● パーティメンバー n 番の名前を取得 #-------------------------------------------------------------------------- def party_member_name(n) actor = n >= 1 ? $game_party.members[n - 1] : nil actor ? actor.name : "" end #-------------------------------------------------------------------------- # ● を取得 #-------------------------------------------------------------------------- def play_time(format = '%3d:%02d:%02d') total = Graphics.frame_count / Graphics.frame_rate return sprintf(format, (total / 3600), (total / 60 % 60), (total % 60), (total / 60), total) end #-------------------------------------------------------------------------- # ● 文字の処理 # c : 文字 # text : 描画処理中の文字列バッファ(必要なら破壊的に変更) # pos : 描画位置 {:x, :y, :new_x, :height} #-------------------------------------------------------------------------- def process_character(c, text, pos) case c when "\n" # 改行 process_new_line(text, pos) when "\e" # 制御文字 process_escape_character(obtain_escape_code(text), text, pos) else # 普通の文字 process_normal_character(c, pos) end end #-------------------------------------------------------------------------- # ● 通常文字の処理 #-------------------------------------------------------------------------- def process_normal_character(c, pos) text_width = text_size(c).width draw_text(pos[:x], pos[:y], text_width * 2, pos[:height], c) pos[:x] += text_width end #-------------------------------------------------------------------------- # ● 改行文字の処理 #-------------------------------------------------------------------------- def process_new_line(text, pos) pos[:x] = pos[:new_x] pos[:y] += pos[:height] pos[:height] = calc_line_height(text) end #-------------------------------------------------------------------------- # ● 制御文字の本体を破壊的に取得 #-------------------------------------------------------------------------- def obtain_escape_code(text) text.slice!(/^[\$\.\|\^!><\{\}\\]|^[A-Z]+/i) end #-------------------------------------------------------------------------- # ● 制御文字の引数を破壊的に取得 #-------------------------------------------------------------------------- def obtain_escape_param(text) text.slice!(/^\[-?\d+\]/)[/-?\d+/].to_i rescue 0 end #-------------------------------------------------------------------------- # ● #-------------------------------------------------------------------------- def obtain_escape_value(text, value) text.slice!(/^\[([+-]?)(\d+)\]/i) return value + $2.to_i if $1 == '+' return value - $2.to_i if $1 == '-' return $2.to_i end #-------------------------------------------------------------------------- # ● 制御文字の処理 # code : 制御文字の本体部分(「\C[1]」なら「C」) #-------------------------------------------------------------------------- def process_escape_character(code, text, pos) case code.upcase when 'C' change_color(text_color(obtain_escape_param(text))) when 'I' process_draw_icon(obtain_escape_param(text), pos) when '{' make_font_bigger when '}' make_font_smaller when 'X' pos[:x] = obtain_escape_value(text, pos[:x]) when 'Y' pos[:y] = obtain_escape_value(text, pos[:y]) when 'L' process_draw_line(text, pos) end end #-------------------------------------------------------------------------- # ● 制御文字によるライン描画の処理 #-------------------------------------------------------------------------- def process_draw_line(text, pos) if text.slice!(/^\[(\d+)\s*,\s*(\d+)(?:\s*,\s*([AFHTMBXS]+))?\]/i) x, y, w, h, params = pos[:x], pos[:y], $1.to_i, $2.to_i, ($3 || "") # 描画幅を文字サイズから (A:自動,F:全角,H:半角) case params when /A/i; w = text_size(text[0, w]).width when /F/i; w = text_size(" " * w).width when /H/i; w = text_size(" " * w).width end # 線の描画位置 (t:上,m:中,b:下, デフォルトは下) unless params[/T/i] if params[/M/i] y += (pos[:height] + h) / 2 else y += pos[:height] - h end end # 影の描画 if params[/S/i] w -= 1 color = gauge_back_color color.alpha = translucent_alpha self.contents.fill_rect(x + 1, y + 1, w, h, color) end # 線の描画 self.contents.fill_rect(x, y, w, h, self.contents.font.color) # x座標を進める x += w if params[/X/i] elsif text.slice!(/^\[([0-9, ]+?)(0x[0-9A-F]+)?\]/i) color = $2 param = $1.sub(/, *$/, '').split(',').map {|s| s.to_i } if param.is_a?(Array) && param.size == 4 if color draw_fill_rect(*param, str2color(color)) else self.contents.fill_rect(*param, self.contents.font.color) end end end end #-------------------------------------------------------------------------- # ● 制御文字によるアイコン描画の処理 #-------------------------------------------------------------------------- def process_draw_icon(icon_index, pos) draw_icon(icon_index, pos[:x], pos[:y] + (pos[:height] - 24) / 2) pos[:x] += 24 end #-------------------------------------------------------------------------- # ● フォントを大きくする #-------------------------------------------------------------------------- def make_font_bigger contents.font.size += 4 if contents.font.size <= 92 end #-------------------------------------------------------------------------- # ● フォントを小さくする #-------------------------------------------------------------------------- def make_font_smaller contents.font.size -= 4 if contents.font.size >= 10 end #-------------------------------------------------------------------------- # ● 行の高さを計算 # restore_font_size : 計算後にフォントサイズを元に戻す #-------------------------------------------------------------------------- def calc_line_height(text, restore_font_size = true) result = [line_height, contents.font.size].max last_font_size = contents.font.size text.slice(/^.*$/).scan(/\e[\{\}]/).each do |esc| make_font_bigger if esc == "\e{" make_font_smaller if esc == "\e}" result = [result, contents.font.size].max end contents.font.size = last_font_size if restore_font_size result end #-------------------------------------------------------------------------- # ● #-------------------------------------------------------------------------- def draw_fill_rect(x, y, width, height, color) bitmap = Bitmap.new(width, height) bitmap.fill_rect(bitmap.rect, color) self.contents.blt(x, y, bitmap, bitmap.rect) bitmap.dispose end #-------------------------------------------------------------------------- # ● ゲージの描画 # rate : 割合(1.0 で満タン) # color1 : グラデーション 左端 # color2 : グラデーション 右端 #-------------------------------------------------------------------------- def draw_gauge(x, y, width, rate, color1, color2) fill_w = (width * rate).to_i gauge_y = y + line_height - 8 contents.fill_rect(x, gauge_y, width, 6, gauge_back_color) contents.gradient_fill_rect(x, gauge_y, fill_w, 6, color1, color2) end #-------------------------------------------------------------------------- # ● アイコンの描画 #-------------------------------------------------------------------------- def draw_icon(icon_index, x, y, enabled = true) bitmap = Cache.system("Iconset") rect = Rect.new(icon_index % 16 * 24, icon_index / 16 * 24, 24, 24) contents.blt(x, y, bitmap, rect, enabled ? 255 : translucent_alpha) end #-------------------------------------------------------------------------- # ● 顔グラフィックの描画 #-------------------------------------------------------------------------- def draw_face(face_name, face_index, x, y, size = 96, enabled = true) bitmap = Cache.face(face_name) dest_rect = Rect.new(x, y, 96, 96) src_rect = Rect.new(face_index % 4 * 96, face_index / 4 * 96, 96, 96) opacity = enabled ? 255 : translucent_alpha case size when Integer src_rect.x += (96 - size) / 2 src_rect.y += (96 - size) / 2 src_rect.width = size src_rect.height = size contents.blt(x, y, bitmap, src_rect, opacity) when Array case size.size when 1 dest_rect.width, dest_rect.height = size[0], size[0] when 2 dest_rect.width, dest_rect.height = size[0], size[1] when 4 dest_rect.width, dest_rect.height = size[2], size[3] src_rect.width, src_rect.height = size[2], size[3] src_rect.x, src_rect.y = src_rect.x + size[0], src_rect.y + size[1] else raise "wrong number of elements (#{size.size} of 2)" end contents.stretch_blt(dest_rect, bitmap, src_rect, opacity) else raise TypeError, "wrong argument type #{size.class} (expected Integer or Array)" end end #-------------------------------------------------------------------------- # ● 歩行グラフィックの描画 #-------------------------------------------------------------------------- def draw_character(character_name, character_index, x, y) return unless character_name bitmap = Cache.character(character_name) sign = character_name[/^[\!\$]./] if sign && sign.include?('$') cw = bitmap.width / 3 ch = bitmap.height / 4 else cw = bitmap.width / 12 ch = bitmap.height / 8 end n = character_index src_rect = Rect.new((n%4*3+1)*cw, (n/4*4)*ch, cw, ch) contents.blt(x - cw / 2, y - ch, bitmap, src_rect) end #-------------------------------------------------------------------------- # ● HP の文字色を取得 #-------------------------------------------------------------------------- def hp_color(actor) return knockout_color if actor.hp == 0 return crisis_color if actor.hp < actor.mhp / 4 return normal_color end #-------------------------------------------------------------------------- # ● MP の文字色を取得 #-------------------------------------------------------------------------- def mp_color(actor) return crisis_color if actor.mp < actor.mmp / 4 return normal_color end #-------------------------------------------------------------------------- # ● TP の文字色を取得 #-------------------------------------------------------------------------- def tp_color(actor) return normal_color end #-------------------------------------------------------------------------- # ● アクターの歩行グラフィック描画 #-------------------------------------------------------------------------- def draw_actor_graphic(actor, x, y) draw_character(actor.character_name, actor.character_index, x, y) end #-------------------------------------------------------------------------- # ● アクターの顔グラフィック描画 #-------------------------------------------------------------------------- def draw_actor_face(actor, x, y, size = 96) draw_face(actor.face_name, actor.face_index, x, y, size) end #-------------------------------------------------------------------------- # ● アクターの表情グラフィック描画 #-------------------------------------------------------------------------- def draw_actor_expression(actor, x, y, size = 96) draw_face(actor.face_name, actor.expression_index, x, y, size) end #-------------------------------------------------------------------------- # ● 歩行アイコンの描画 # enabled : 有効フラグ。false のとき半透明で描画 #-------------------------------------------------------------------------- def draw_actor_icon(actor, x, y, enabled = true) return unless actor self.contents.fill_rect(x, y, 24, 24, COLOR_AIB_1) self.contents.fill_rect(x + 1, y + 1, 22, 22, COLOR_AIB_2) return unless actor.character_name return if actor.character_name.empty? bitmap = Cache.character(actor.character_name) sign = actor.character_name[/^[\!\$]./] if sign != nil and sign.include?('$') cw = bitmap.width / 3 ch = bitmap.height / 4 else cw = bitmap.width / 12 ch = bitmap.height / 8 end n = actor.character_index src_rect = Rect.new((n%4*3+1)*cw, (n/4*4)*ch, 20, 20) src_rect.x += (cw - src_rect.width) / 2 src_rect.y += (ch - src_rect.height) / 4 opacity = (enabled ? 255 : translucent_alpha) self.contents.blt(x + 2, y + 2, bitmap, src_rect, opacity) end #-------------------------------------------------------------------------- # ● 立ち絵の描画 #-------------------------------------------------------------------------- def draw_actor_portrait(actor, x, y, enabled = true) return unless actor bitmap = Cache.picture(actor.portrait_name) opacity = (enabled ? 255 : translucent_alpha) self.contents.blt(x, y, bitmap, bitmap.rect, opacity) end #-------------------------------------------------------------------------- # ● の描画 # [:pict, x, y, "file", "script"] # [:pict, x, y, ["file","file"], "script"] #-------------------------------------------------------------------------- def draw_actor_picture(actor, x, y, file, script = nil) return unless actor battler, alternate = file if script filename = (eval(script) ? battler : alternate) else filename = (actor.battle_member? ? battler : alternate) || battler end if filename && !filename.empty? bitmap = Cache.picture(filename % actor.id) self.contents.blt(x, y, bitmap, bitmap.rect) end end #-------------------------------------------------------------------------- # ● の描画 #-------------------------------------------------------------------------- def draw_actor_text(actor, x, y, text, script = nil) return if script && !eval(script) draw_text_ex(x, y, text.gsub(/\\{(\w+?)}/) { actor.__send__($1) }) end #-------------------------------------------------------------------------- # ● の描画 #-------------------------------------------------------------------------- def draw_actor_number(actor, x, y, num, file) bitmap = Cache.picture(file) r_num = Rect.new(0, 0, bitmap.width / 13, bitmap.height) param = String(num.is_a?(String) ? eval(num) : num) param.split(//).each_with_index do |c,i| case c when ' '; next when '+'; index = 10 when '-'; index = 11 when /\d/; index = Integer(c) else; index = 12 end r_num.x = r_num.width * index self.contents.blt(x + r_num.width * i, y, bitmap, r_num) end end #-------------------------------------------------------------------------- # ● 名前の描画 #-------------------------------------------------------------------------- def draw_actor_name(actor, x, y, width = 124) change_color(hp_color(actor)) draw_text(x, y, width, line_height, actor.name) end #-------------------------------------------------------------------------- # ● 職業の描画 #-------------------------------------------------------------------------- def draw_actor_class(actor, x, y, width = 124) change_color(normal_color) draw_text(x, y, width, line_height, actor.class.name) end #-------------------------------------------------------------------------- # ● 二つ名の描画 #-------------------------------------------------------------------------- def draw_actor_nickname(actor, x, y, width = 124) change_color(normal_color) draw_text(x, y, width, line_height, actor.nickname) end #-------------------------------------------------------------------------- # ● レベルの描画 #-------------------------------------------------------------------------- def draw_actor_level(actor, x, y, width = 64) if VISIBLE_SYSTEM change_color(system_color) draw_text(x, y, 32, line_height, Vocab::level_a) end change_color(normal_color) draw_text(x + width - 32, y, 32, line_height, actor.level, 2) end #-------------------------------------------------------------------------- # ● レベルの描画 (経験値ゲージ付) #-------------------------------------------------------------------------- def draw_actor_level_g(actor, x, y, width = 64) draw_gauge(x,y,width,actor.cm_exp_rate,exp_gauge_color1,exp_gauge_color2) if VISIBLE_SYSTEM change_color(system_color) draw_text(x, y, 32, line_height, Vocab::level_a) end change_color(tp_color(actor)) draw_text(x + width - 32, y, 32, line_height, actor.level, 2) end #-------------------------------------------------------------------------- # ● ステートおよび強化/弱体のアイコンを描画 #-------------------------------------------------------------------------- def draw_actor_icons(actor, x, y, width = 96, align = 0) icons = (actor.state_icons + actor.buff_icons)[0, width / 24] case align when 0; left = 0 when 1; left = (width - icons.size * 24) / 2 when 2; left = (width - icons.size * 24) end icons.each_with_index {|n, i| draw_icon(n, x + left + 24 * i, y) } end #-------------------------------------------------------------------------- # ● 現在値/最大値を分数形式で描画 #-------------------------------------------------------------------------- def draw_current_and_max_values(x, y, width, current, max, color1, color2) change_color(color1) xr = x + width if width < 96 draw_text(xr - 40, y, 42, line_height, current, 2) else draw_text(xr - 92, y, 42, line_height, current, 2) change_color(color2) draw_text(xr - 52, y, 12, line_height, "/", 2) draw_text(xr - 42, y, 42, line_height, max, 2) end end #-------------------------------------------------------------------------- # ● HP の描画 #-------------------------------------------------------------------------- def draw_actor_hp(actor, x, y, width = 124) draw_gauge(x, y, width, actor.hp_rate, hp_gauge_color1, hp_gauge_color2) if VISIBLE_SYSTEM change_color(system_color) draw_text(x, y, 30, line_height, Vocab::hp_a) end draw_current_and_max_values(x, y, width, actor.hp, actor.mhp, hp_color(actor), normal_color) end #-------------------------------------------------------------------------- # ● MP の描画 #-------------------------------------------------------------------------- def draw_actor_mp(actor, x, y, width = 124) draw_gauge(x, y, width, actor.mp_rate, mp_gauge_color1, mp_gauge_color2) if VISIBLE_SYSTEM change_color(system_color) draw_text(x, y, 30, line_height, Vocab::mp_a) end draw_current_and_max_values(x, y, width, actor.mp, actor.mmp, mp_color(actor), normal_color) end #-------------------------------------------------------------------------- # ● TP の描画 #-------------------------------------------------------------------------- def draw_actor_tp(actor, x, y, width = 124) draw_gauge(x, y, width, actor.tp_rate, tp_gauge_color1, tp_gauge_color2) if VISIBLE_SYSTEM change_color(system_color) draw_text(x, y, 30, line_height, Vocab::tp_a) end change_color(tp_color(actor)) draw_text(x + width - 42, y, 42, line_height, actor.tp.to_i, 2) end #-------------------------------------------------------------------------- # ● #-------------------------------------------------------------------------- def actor_exp_rate(actor) return 1.0 if actor.max_level? exp_rate = actor.exp - actor.exp_for_level(actor.level).to_f exp_rate /= actor.next_level_exp - actor.exp_for_level(actor.level) return exp_rate end #-------------------------------------------------------------------------- # ● 経験値の描画 #-------------------------------------------------------------------------- def draw_actor_exp(actor, x, y, width = 124) draw_gauge(x,y,width,actor.cm_exp_rate,exp_gauge_color1,exp_gauge_color2) if VISIBLE_SYSTEM change_color(system_color) draw_text(x, y, 30, line_height, VOCABS[:exp_a]) end change_color(tp_color(actor)) draw_text(x + width - 42, y, 42, line_height, actor.cm_remaining_exp, 2) end #-------------------------------------------------------------------------- # ● 経験値情報の描画 #-------------------------------------------------------------------------- def draw_actor_exp_info(actor, x, y, width = 124) s1 = actor.max_level? ? "-------" : actor.exp s2 = actor.max_level? ? "-------" : actor.cm_remaining_exp s_next = sprintf(Vocab::ExpNext, Vocab::level) change_color(system_color) draw_text(x, y + line_height * 0, 180, line_height, Vocab::ExpTotal) draw_text(x, y + line_height * 2, 180, line_height, s_next) change_color(normal_color) draw_text(x, y + line_height * 1, 180, line_height, s1, 2) draw_text(x, y + line_height * 3, 180, line_height, s2, 2) end #-------------------------------------------------------------------------- # ● 能力値の描画 #-------------------------------------------------------------------------- def draw_actor_param(actor, x, y, param_id, width = 124) if param_id < 0 || param_id > 7 raise ArgumentError, "能力値の ID は 0 から 7 までの数値です。" end if VISIBLE_SYSTEM change_color(system_color) draw_text(x, y, width, line_height, Vocab::param(param_id)) end change_color(normal_color) draw_text(x, y, width, line_height, actor.param(param_id), 2) end #-------------------------------------------------------------------------- # ● 矩形の描画 #-------------------------------------------------------------------------- def draw_actor_rect(actor, x, y, w, h, color, script = nil) return if script && !eval(script) draw_fill_rect(x, y, w, h, str2color(color)) end #-------------------------------------------------------------------------- # ● アイテム名の描画 #-------------------------------------------------------------------------- def draw_item_name(item, x, y, width = 172, enabled = true) return unless item draw_icon(item.icon_index, x, y, enabled) change_color(normal_color, enabled) draw_text(x + 24, y, width, line_height, item.name) end #-------------------------------------------------------------------------- # ● 通貨単位つき数値(所持金など)の描画 #-------------------------------------------------------------------------- def draw_currency_value(value, name, unit, x, y, width) cx = text_size(unit).width change_color(normal_color) draw_text(x, y, width - cx - 2, line_height, value, 2) if VISIBLE_SYSTEM change_color(system_color) draw_text(x, y, width, line_height, name) draw_text(x, y, width, line_height, unit, 2) end end #-------------------------------------------------------------------------- # ● 通貨単位つき数値(所持金など)の描画 #-------------------------------------------------------------------------- def draw_gold(x, y, width) draw_currency_value( $game_party.gold, VOCABS[:gold], Vocab::currency_unit, x, y, width) end end