=begin DQ風メッセージ表示スクリプト このスクリプトは、DQみたく文字は1文字づつ表示し 1つの文章は上にスクロールするメッセージウィンドウです。 選択肢と数値入力は別ウィンドウで表示されます。 ※RGSSWIKIに公開されていたものをVX用に再構築。 ・制御文字はVXのデフォルトにしか対応しません。 ・性質的に顔グラとの相性が極めて悪いので、顔グラに対応していません。  エディタ内で設定した顔グラは一切表示されません。 ・自動改行機能は排除しました。 ・インデントを自動作成します。文中に"「"がある場合は以降の文章はそれに合わせて  表示開始位置が揃えられます。 ・デフォスクリプトの戦闘シーンの文章表示処理が特殊で、対応できていません。  戦闘メッセージはデフォルトのままです。 =end #============================================================================== # ■ Array # 追加 #============================================================================== class Array #-------------------------------------------------------------------------- # ● 配列内の要素の和を得る(文字列のみ) #-------------------------------------------------------------------------- def addition a = "" for i in self a += i end return a end end #============================================================================== # ■ Game_Message #============================================================================== class Game_Message #-------------------------------------------------------------------------- # ● 公開インスタンス変数 #-------------------------------------------------------------------------- attr_accessor :choice_parameters # 選択肢 パラメーター #-------------------------------------------------------------------------- # ● オブジェクト初期化 #-------------------------------------------------------------------------- alias choice_parameters_initialize initialize def initialize choice_parameters_initialize @choice_parameters = nil end end #============================================================================== # ■ Game_Interpreter #============================================================================== class Game_Interpreter #-------------------------------------------------------------------------- # ● 選択肢のセットアップ #-------------------------------------------------------------------------- def setup_choices(parameters) # choice_max に選択肢の項目数を設定 $game_message.choice_max = parameters[0].size # choice_parameters に選択肢を設定 $game_message.choice_parameters = parameters[0] # キャンセルの場合の処理を設定 $game_message.choice_cancel_type = parameters[1] # コールバックを設定 current_indent = @list[@index].indent $game_message.choice_proc = Proc.new { |n| @branch[current_indent] = n } end #-------------------------------------------------------------------------- # ● 文章の表示 #-------------------------------------------------------------------------- alias dqm_command_101 command_101 def command_101 if $game_temp.in_battle dqm_command_101 else # ほかの文章が texts に設定済みの場合 return false unless $game_message.texts.empty? # メッセージ終了待機中フラグおよびコールバックを設定 @message_waiting = true $game_message.main_proc = Proc.new { @message_waiting = false } # texts に 1 行目を設定 $game_message.texts.push @list[@index].parameters[0] + "\x00" line_count = 1 loop do # 次のイベントコマンドが文章 2 行目以降の場合 if @list[@index+1].code == 401 # texts に 2 行目以降を追加 $game_message.texts.push @list[@index+1].parameters[0] + "\x00" line_count += 1 # イベントコマンドが文章 2 行目以降ではない場合 else # 次のイベントコマンドが選択肢の表示の場合 if @list[@index+1].code == 102 # インデックスを進める @index += 1 # 選択肢のセットアップ $game_message.choice_start = line_count setup_choices(@list[@index].parameters) # 次のイベントコマンドが数値入力の処理の場合 elsif @list[@index+1].code == 103 # インデックスを進める @index += 1 # 数値入力のセットアップ $game_message.num_input_variable_id = @list[@index].parameters[0] $game_message.num_input_digits_max = @list[@index].parameters[1] end return true end @index += 1 end end end end #============================================================================== # ■ Window_Message #------------------------------------------------------------------------------ # 文章表示に使うメッセージウィンドウです。(Sprite_Message専用) #============================================================================== class Window_Message < Window_Base #-------------------------------------------------------------------------- # ● オブジェクト初期化 #-------------------------------------------------------------------------- def initialize line_height = 24 # 1行の高さ line_max = 4 # 表示行数 super(0, 288, 544, (line_height * line_max) + 32) self.visible = false self.z = 9998 self.active = false @fade_in = false @fade_out = false @contents_showing = false # メッセージスプライトを作成 @sprite_message = Sprite_Message.new(self,line_max) create_back_sprite end #-------------------------------------------------------------------------- # ● 解放 #-------------------------------------------------------------------------- def dispose terminate_message $game_message.texts = [] @input_number_window.dispose if @input_number_window != nil # メッセージスプライトを開放 @sprite_message.dispose @back_sprite.dispose super end #-------------------------------------------------------------------------- # ● 背景スプライトの作成 #-------------------------------------------------------------------------- def create_back_sprite @back_sprite = Sprite.new @back_sprite.bitmap = Cache.system("MessageBack") @back_sprite.visible = (@background == 1) @back_sprite.z = 190 end #-------------------------------------------------------------------------- # ● ゴールドウィンドウの作成 #-------------------------------------------------------------------------- def create_gold_window @gold_window = Window_Gold.new(384, 0) @gold_window.x = 544 - @gold_window.width if $game_temp.in_battle @gold_window.y = 192 else @gold_window.y = self.y >= 128 ? 0 : 384 end @gold_window.opacity = 255 @gold_window.back_opacity = 255 end #-------------------------------------------------------------------------- # ● メッセージ終了処理 #-------------------------------------------------------------------------- def terminate_message self.active = false self.pause = false @sprite_message.terminate_message # 表示中フラグをクリア @contents_showing = false # メッセージ コールバックを呼ぶ $game_message.main_proc.call if $game_message.main_proc != nil $game_message.clear # ゴールドウィンドウを開放 if @gold_window != nil @gold_window.dispose @gold_window = nil end # 選択肢ウィンドウを開放 if @command_window != nil @command_window.dispose @command_window = nil end end #-------------------------------------------------------------------------- # ● リフレッシュ #-------------------------------------------------------------------------- def refresh # 表示待ちのメッセージがある場合 unless $game_message.texts.empty? for i in $game_message.texts i.slice!(/./m) if i.slice(/./m) == "\x00" end text = $game_message.texts.addition @sprite_message.message = convert_special_char(text) end # 選択肢の場合 if $game_message.choice_max > 0 # 選択肢ウィンドウを作成 @command_window = Window_Message_Command.new @command_window.visible = false @command_window.active = false layout_window @command_window end # 数値入力の場合 if $game_message.num_input_variable_id > 0 @input_number_window = Window_Message_InputNumber.new @input_number_window.visible = false @input_number_window.active = false layout_window @input_number_window end end #-------------------------------------------------------------------------- # ● 特殊文字の変換 #-------------------------------------------------------------------------- def convert_special_char(text) text.gsub!(/\\V\[([0-9]+)\]/i) { $game_variables[$1.to_i] } text.gsub!(/\\V\[([0-9]+)\]/i) { $game_variables[$1.to_i] } text.gsub!(/\\N\[([0-9]+)\]/i) { $game_actors[$1.to_i].name } text.gsub!(/\\C\[([0-9]+)\]/i) { "\x01[#{$1}]" } text.gsub!(/\\G/) { "\x02" } text.gsub!(/\\\./) { "\x03" } text.gsub!(/\\\|/) { "\x04" } text.gsub!(/\\!/) { "\x05" } text.gsub!(/\\>/) { "\x06" } text.gsub!(/\\ 0 and $game_message.choice_cancel_type > 0 Sound.play_cancel $game_message.choice_proc.call($game_message.choice_cancel_type - 1) terminate_message end end # 決定 if Input.trigger?(Input::C) if $game_message.choice_max > 0 Sound.play_decision $game_message.choice_proc.call(@command_window.index) end terminate_message end end #-------------------------------------------------------------------------- # ● 数値入力の更新 #-------------------------------------------------------------------------- def update_number_window @input_number_window.visible = true @input_number_window.active = true @input_number_window.update if Input.trigger?(Input::C) Sound.play_decision $game_variables[$game_message.num_input_variable_id] = @input_number_window.number $game_map.need_refresh = true @input_number_window.dispose @input_number_window = nil terminate_message end end #-------------------------------------------------------------------------- # ● 次の内容の更新 #-------------------------------------------------------------------------- def update_message_next @contents_showing = true $game_message.visible = true reset_window refresh Graphics.frame_reset @fade_in = true if not self.visible self.visible = true self.contents_opacity = 0 end #-------------------------------------------------------------------------- # ● 終了時の更新 #-------------------------------------------------------------------------- def update_message_end @fade_out = true self.opacity -= 48 @sprite_message.fade_out if self.opacity == 0 self.visible = false @fade_out = false $game_message.visible = false @sprite_message.visible = false @sprite_message.clear end end end #============================================================================== # ■ Window_Message_Command #------------------------------------------------------------------------------ # メッセージ表示中にコマンド選択を行うウィンドウです。 #============================================================================== class Window_Message_Command < Window_Command #-------------------------------------------------------------------------- # ● オブジェクト初期化 #-------------------------------------------------------------------------- def initialize name_test = Bitmap.new(640,32) max_width = 0 $game_message.choice_parameters.each do |name| max_width = [max_width,name_test.text_size(name).width].max end name_test.dispose super(max_width + 40,$game_message.choice_parameters) self.back_opacity = 255 end end #============================================================================== # ■ Sprite_Message #------------------------------------------------------------------------------ # メッセージをドラクエ風にスクロールさせるためのスプライトです。 #============================================================================== class Sprite_Message < Sprite # インデント INDENT = true #-------------------------------------------------------------------------- # ● オブジェクト初期化 #-------------------------------------------------------------------------- def initialize(window,line_max) super() width = window.width - 32 height = window.height - 32 self.bitmap = Bitmap.new(width, height * 2) self.visible = false self.x = window.x + 16 self.y = window.y + 16 self.z = 9999 self.src_rect.height = height @line_height = height / line_max # 一行の高さ @message_speed = 0 # メッセージスピード @pause_skip = false # メッセージスキップ @scroll_speed = 10 # スクロールスピード @skip_scroll_speed = 1 # スキップ時のスクロールスピード @gold = false clear end #-------------------------------------------------------------------------- # ● メッセージ表示中かどうか #-------------------------------------------------------------------------- def showing? return (@scroll_up != 0 or @message.size != 0) end #-------------------------------------------------------------------------- # ● スプライトクリア #-------------------------------------------------------------------------- def clear self.bitmap.clear self.src_rect.y = 0 @message = "" # 表示メッセージ @cx = 0 # カレント描画位置x @cy = 0 # カレント描画位置y @ay = 0 # 表示を開始した描画位置y @scroll_up = 0 # スクロール用カウンタ @indent = 0 # インデント文字列 @wait_count = 0 @pause = false @line_show_fast = false @pause_skip = false @gold = false end #-------------------------------------------------------------------------- # ● フェードイン #-------------------------------------------------------------------------- def fade_in self.visible = true if not self.visible self.opacity += 24 end #-------------------------------------------------------------------------- # ● フェードアウト #-------------------------------------------------------------------------- def fade_out self.opacity -= 48 if self.opacity == 0 self.visible = false clear end end #-------------------------------------------------------------------------- # ● 解放 #-------------------------------------------------------------------------- def dispose self.bitmap.dispose if self.bitmap != nil super end #-------------------------------------------------------------------------- # ● メッセージ終了処理 #-------------------------------------------------------------------------- def terminate_message self.bitmap.font.color = text_color(0) @pause_skip = false end #-------------------------------------------------------------------------- # ● メッセージ設定 #-------------------------------------------------------------------------- def message=(text) @message = text.dup @ay = @cy # 表示行を保存 end #-------------------------------------------------------------------------- # ● スクロールスピードの取得 #-------------------------------------------------------------------------- def scroll_speed return @scroll_speed end #-------------------------------------------------------------------------- # ● ビットマップ初期化 #-------------------------------------------------------------------------- def bitmap_initialize # スクロール終了しメッセージが全て表示されている場合 if @scroll_up <= 0 and @message.size == 0 # スクロールした部分をビットマップの一番上にしてスクロール位置を初期化 @scroll_up = 0 r = self.bitmap.rect r.y = @ay bmp = self.bitmap.dup self.bitmap.clear self.bitmap.blt(0, 0, bmp, r) self.src_rect.y = 0 bmp.dispose @cy = @cy - @ay @ay = 0 @indent = 0 @cx = 0 end end #-------------------------------------------------------------------------- # ● スクロール処理 #-------------------------------------------------------------------------- def update_scroll # スクロール if @scroll_up > 0 n = 0 if self.scroll_speed != 0 n = @line_height / self.scroll_speed else n = @line_height end n = 1 if n <= 0 self.src_rect.y += n @scroll_up -= n bitmap_initialize return true end return false end #-------------------------------------------------------------------------- # ● フレーム更新 #-------------------------------------------------------------------------- def update if @wait_count > 0 @wait_count -= 1 return end if @pause @pause = false if Input.trigger?(Input::C) return end super # スクロール return if update_scroll # 表示範囲を超えている場合、入るまでスクロールさせる if (self.src_rect.y + self.src_rect.height) <= @cy @scroll_up += @line_height return end if @line_show_fast # メッセージ瞬間表示 draw_message(@message.size) @line_show_fast elsif @message_speed <= 0 # メッセージ描画 @message_wait = @message_speed.abs draw_message() else draw_message(@message_speed.abs) end # 表示メッセージなし if @message.size == 0 # 表示したメッセージが一番上に来るようにスクロールさせる @scroll_up = @ay - self.src_rect.y bitmap_initialize return end end #-------------------------------------------------------------------------- # ● ゴールドウインドウ表示フラグ #-------------------------------------------------------------------------- def gold? return @gold end #-------------------------------------------------------------------------- # ● ゴールドウインドウ表示フラグの変更 #-------------------------------------------------------------------------- def not_gold @gold = false end #-------------------------------------------------------------------------- # ● 入力待ちしないか #-------------------------------------------------------------------------- def skip? return @pause_skip end #-------------------------------------------------------------------------- # ● 待機中フラグ #-------------------------------------------------------------------------- def pause? return @pause end #-------------------------------------------------------------------------- # ● メッセージを描画 #-------------------------------------------------------------------------- def draw_message(n=0) for i in 0 .. n # c に 1 文字を取得 c = get_char() if not c.nil? if not draw_char(c) return end end end end #-------------------------------------------------------------------------- # ● メッセージを全て描画する #-------------------------------------------------------------------------- def draw_message_all while(not @message.empty?) # c に 1 文字を取得 c = get_char() if not c.nil? draw_char(c) end end end #-------------------------------------------------------------------------- # ● 改行処理 #-------------------------------------------------------------------------- def new_line # @cyに文字の高さを加算 @cy += @line_height # @cxは先頭 @cx = @indent end #-------------------------------------------------------------------------- # ● 1文字取得 #-------------------------------------------------------------------------- def get_char return @message.slice!(/./m) end #-------------------------------------------------------------------------- # ● 1文字描画 #-------------------------------------------------------------------------- def draw_char(c) case c when nil # 描画すべき文字がない terminate_message when "\x00" # 改行 new_line when "\x01" # \C[n] (文字色変更) @message.sub!(/\[([0-9]+)\]/, "") self.bitmap.font.color = text_color($1.to_i) when "\x02" # \G (所持金表示) @gold = true when "\x03" # \. (ウェイト 1/4 秒) @wait_count = 15 when "\x04" # \| (ウェイト 1 秒) @wait_count = 60 when "\x05" # \! (入力待ち) @pause = true when "\x06" # \> (瞬間表示 ON) @line_show_fast = true when "\x07" # \< (瞬間表示 OFF) @line_show_fast = false when "\x08" # \^ (入力待ちなし) @pause_skip = true else # 普通の文字 self.bitmap.draw_text(@cx, @cy, 40, @line_height, c) c_width = self.bitmap.text_size(c).width @cx += c_width @indent = @cx if c == '「' && INDENT end return true end #-------------------------------------------------------------------------- # ● 文字色取得 # n : 文字色番号 (0〜31) #-------------------------------------------------------------------------- def text_color(n) x = 64 + (n % 8) * 8 y = 96 + (n / 8) * 8 return Cache.system("Window").get_pixel(x, y) end end #============================================================================== # ■ Adjust_Window_Module #------------------------------------------------------------------------------ # ウィンドウ位置調節モジュール #============================================================================== module Adjust_Window_Module # 上に並べる def tile_layout_top(window) window.y = self.y - window.height end # 下に並べる def tile_layout_bottom(window) window.y = self.y + self.height end # 左に揃える def adjust_window_left(window) window.x = self.x + self.width - window.width end # 右に揃える def adjust_window_right(window) window.x = self.x end end class Window_Base include Adjust_Window_Module end #============================================================================== # ■ Window_Message_InputNumber #------------------------------------------------------------------------------ # メッセージ表示中に数値入力を行うウィンドウです。 #============================================================================== class Window_Message_InputNumber < Window_NumberInput #-------------------------------------------------------------------------- # ● オブジェクト初期化 #-------------------------------------------------------------------------- def initialize super @number = $game_variables[$game_message.num_input_variable_id] end end # バトル中はデフォのメッセージを使用。 # 方法が思いつかなかったので再定義しているクラスを別名で定義する。 #============================================================================== # ■ Window_Message #============================================================================== class Window_Message_Defo < Window_Selectable MAX_LINE = 4 def initialize super(0, 288, 544, 128) self.z = 200 self.active = false self.index = -1 self.openness = 0 @opening = false @closing = false @text = nil @contents_x = 0 @contents_y = 0 @line_count = 0 @wait_count = 0 @background = 0 @position = 2 @show_fast = false @line_show_fast = false @pause_skip = false create_gold_window create_number_input_window create_back_sprite end def dispose super dispose_gold_window dispose_number_input_window dispose_back_sprite end def update super update_gold_window update_number_input_window update_back_sprite update_show_fast unless @opening or @closing if @wait_count > 0 @wait_count -= 1 elsif self.pause input_pause elsif self.active input_choice elsif @number_input_window.visible input_number elsif @text != nil update_message elsif continue? start_message open $game_message.visible = true else close $game_message.visible = @closing end end end def create_gold_window @gold_window = Window_Gold.new(384, 0) @gold_window.openness = 0 end def create_number_input_window @number_input_window = Window_NumberInput.new @number_input_window.visible = false end def create_back_sprite @back_sprite = Sprite.new @back_sprite.bitmap = Cache.system("MessageBack") @back_sprite.visible = (@background == 1) @back_sprite.z = 190 end def dispose_gold_window @gold_window.dispose end def dispose_number_input_window @number_input_window.dispose end def dispose_back_sprite @back_sprite.dispose end def update_gold_window @gold_window.update end def update_number_input_window @number_input_window.update end def update_back_sprite @back_sprite.visible = (@background == 1) @back_sprite.y = y - 16 @back_sprite.opacity = openness @back_sprite.update end def update_show_fast if self.pause or self.openness < 255 @show_fast = false elsif Input.trigger?(Input::C) and @wait_count < 2 @show_fast = true elsif not Input.press?(Input::C) @show_fast = false end if @show_fast and @wait_count > 0 @wait_count -= 1 end end def continue? return true if $game_message.num_input_variable_id > 0 return false if $game_message.texts.empty? if self.openness > 0 and not $game_temp.in_battle return false if @background != $game_message.background return false if @position != $game_message.position end return true end def start_message @text = "" for i in 0...$game_message.texts.size @text += "  " if i >= $game_message.choice_start @text += $game_message.texts[i].clone + "\x00" end @item_max = $game_message.choice_max convert_special_characters reset_window new_page end def new_page contents.clear if $game_message.face_name.empty? @contents_x = 0 else name = $game_message.face_name index = $game_message.face_index draw_face(name, index, 0, 0) @contents_x = 112 end @contents_y = 0 @line_count = 0 @show_fast = false @line_show_fast = false @pause_skip = false contents.font.color = text_color(0) end def new_line if $game_message.face_name.empty? @contents_x = 0 else @contents_x = 112 end @contents_y += WLH @line_count += 1 @line_show_fast = false end def convert_special_characters @text.gsub!(/\\V\[([0-9]+)\]/i) { $game_variables[$1.to_i] } @text.gsub!(/\\V\[([0-9]+)\]/i) { $game_variables[$1.to_i] } @text.gsub!(/\\N\[([0-9]+)\]/i) { $game_actors[$1.to_i].name } @text.gsub!(/\\C\[([0-9]+)\]/i) { "\x01[#{$1}]" } @text.gsub!(/\\G/) { "\x02" } @text.gsub!(/\\\./) { "\x03" } @text.gsub!(/\\\|/) { "\x04" } @text.gsub!(/\\!/) { "\x05" } @text.gsub!(/\\>/) { "\x06" } @text.gsub!(/\\= MAX_LINE unless @text.empty? self.pause = true break end end when "\x01" @text.sub!(/\[([0-9]+)\]/, "") contents.font.color = text_color($1.to_i) next when "\x02" @gold_window.refresh @gold_window.open when "\x03" @wait_count = 15 break when "\x04" @wait_count = 60 break when "\x05" self.pause = true break when "\x06" @line_show_fast = true when "\x07" @line_show_fast = false when "\x08" @pause_skip = true else contents.draw_text(@contents_x, @contents_y, 40, WLH, c) c_width = contents.text_size(c).width @contents_x += c_width end break unless @show_fast or @line_show_fast end end def finish_message if $game_message.choice_max > 0 start_choice elsif $game_message.num_input_variable_id > 0 start_number_input elsif @pause_skip terminate_message else self.pause = true end @wait_count = 10 @text = nil end def start_choice self.active = true self.index = 0 end def start_number_input digits_max = $game_message.num_input_digits_max number = $game_variables[$game_message.num_input_variable_id] @number_input_window.digits_max = digits_max @number_input_window.number = number if $game_message.face_name.empty? @number_input_window.x = x else @number_input_window.x = x + 112 end @number_input_window.y = y + @contents_y @number_input_window.active = true @number_input_window.visible = true @number_input_window.update end def update_cursor if @index >= 0 x = $game_message.face_name.empty? ? 0 : 112 y = ($game_message.choice_start + @index) * WLH self.cursor_rect.set(x, y, contents.width - x, WLH) else self.cursor_rect.empty end end def input_pause if Input.trigger?(Input::B) or Input.trigger?(Input::C) self.pause = false if @text != nil and not @text.empty? new_page if @line_count >= MAX_LINE else terminate_message end end end def input_choice if Input.trigger?(Input::B) if $game_message.choice_cancel_type > 0 Sound.play_cancel $game_message.choice_proc.call($game_message.choice_cancel_type - 1) terminate_message end elsif Input.trigger?(Input::C) Sound.play_decision $game_message.choice_proc.call(self.index) terminate_message end end def input_number if Input.trigger?(Input::C) Sound.play_decision $game_variables[$game_message.num_input_variable_id] = @number_input_window.number $game_map.need_refresh = true terminate_message end end end #============================================================================== # ■ Window_BattleMessage #============================================================================== class Window_BattleMessage < Window_Message_Defo def initialize super self.openness = 255 @lines = [] refresh end def dispose super end def update super end def open end def close end def reset_window end def clear @lines.clear refresh end def line_number return @lines.size end def back_one @lines.pop refresh end def back_to(line_number) while @lines.size > line_number @lines.pop end refresh end def add_instant_text(text) @lines.push(text) refresh end def replace_instant_text(text) @lines.pop @lines.push(text) refresh end def last_instant_text return @lines[-1] end def refresh self.contents.clear for i in 0...@lines.size draw_line(i) end end def draw_line(index) rect = Rect.new(0, 0, 0, 0) rect.x += 4 rect.y += index * WLH rect.width = contents.width - 8 rect.height = WLH self.contents.clear_rect(rect) self.contents.font.color = normal_color self.contents.draw_text(rect, @lines[index]) end end