class Scene_ADV #------------------------------------------ # 初期化処理 #------------------------------------------ def initialize(filename, scene = Scene_Map.new) # マップ BGM を記憶し、BGM を停止 @bgm = $game_system.playing_bgm $game_system.bgm_stop # 本番ではオブジェクトファイルからしか読み込まない @read_type = true; # 前のシーンを保存 @scene = scene; # 読み込んでいる行の内容 @line = String.new; # 実行するコマンド @command = Hash.new; # シナリオデータを読み込む @lines = Array.new; loadfile(filename); # 背景レイヤーの作成 @background = RPG::Sprite.new; @background.x = 0; @background.y = 0; @background.z = 0; # 最下層 # ピクチャ @pictures = Array.new; @pic_msg = Array.new; # イベント時に使うパラメータを保持しておく配列 # 左右にスプライトを作っておく @chara = {"left" => {"base" => RPG::Sprite.new, "face" => RPG::Sprite.new, "basefile" => String.new, "facefile" => String.new, "x" => -50}, "right" => {"base" => RPG::Sprite.new, "face" => RPG::Sprite.new, "basefile" => String.new, "facefile" => String.new, "x" => -50} }; # メッセージウィンドウの作成 @message_window = Window_Message.new; # アクティブな方(left or right or nil) @active = nil; # マクロ @def = Hash.new; # 基本マクロ if($__gloval_adv_def == nil) $__gloval_adv_def = Hash.new; end # メッセージ @message = Array.new; # 使用するトランジション @transition = ""; # 消去フラグ @clear = nil; # イベントフラグ @event = false; # キャラの座標補正 @plus = {"left" => {"x" => 0, "y" => 0}, "right" => {"x" => 0, "y" => 0}}; # 選択肢の保存(デフォルト) @select = Array.new; # 選択肢文字列の保存 @select_var = 99; # 選択肢インデクスを保存しておく変数番号 #ウェイト @wait_count = 0; # ロードフラグ @load = nil; end #------------------------------------------ # ファイルからデータを読み込む #------------------------------------------ def loadfile(filename) # ファイルが存在しないか本番がオブジェクトファイルのみしか認めてなかったら if(FileTest.exist?("Data/Scenario/"+filename+".txt") == false or (@read_type == true and $DEBUG != true)) lines = load_data("Data/Scenario/"+filename+".rxdata"); # @linesに追加 for line in lines.reverse @lines.unshift(line); end # ファイルが存在したら開く elsif(FileTest.exist?("Data/Scenario/"+filename+".txt")) file = File.open("Data/Scenario/"+filename+".txt", "r") # 読み込んで lines = file.readlines(); # ファイルを閉じる file.close; # @linesに追加 for line in lines.reverse @lines.unshift(line); end # ついでに.rxdataにして保存 save_data(@lines, "Data/Scenario/"+filename+".rxdata"); # それいがいはエラー else p("Scene_ADVエラー:ファイルが見つかりません("+filename+")"); end end #------------------------------------------ # 解放祭り #------------------------------------------ def dispose # 左右キャラの解放 @chara["left"]["base"].dispose; @chara["left"]["face"].dispose; @chara["right"]["base"].dispose; @chara["right"]["face"].dispose; # 背景レイヤーの解放 @background.dispose; # メッセージウィンドウお疲れ様 @message_window.dispose; # 前の BGM に戻す $game_system.bgm_play(@bgm) end #------------------------------------------ # メイン(基本的にはループだけ) #------------------------------------------ def main #前のシーンがScene_ADVじゃなかったら if @scene.class != self.class # トランジション実行 Graphics.transition; end loop do # ゲーム画面を更新 Graphics.update; # 入力情報を更新 Input.update; # フレーム更新 update; # 画面が切り替わったらループを中断(イベント中はゆるさん!) if $scene != self and @event == false break; end end # トランジション準備 Graphics.freeze # 色々解放 dispose; end #------------------------------------------ # 更新 #------------------------------------------ def update # 基本部分更新 basic_update; # エフェクト中なら更新 if @effect effect_update; return; end # ウェイト中だったら if @wait_count > 0 @wait_count -= 1; return end # イベント中なら更新 if @event event_update; return; end # シナリオ終了フラグ立ってたら終わらせる if @scenario_end $scene = @scene; return; end # それ以外なら次の行へ process; end #------------------------------------------ # 基本更新 #------------------------------------------ def basic_update # メッセージウィンドウの更新 @message_window.update; end #------------------------------------------ # エフェクト更新 #------------------------------------------ def effect_update @chara["left"]["base"].update; @chara["left"]["face"].update; @chara["right"]["base"].update; @chara["right"]["face"].update; # 全部エフェクトおわったらお疲れ様 if(@chara["left"]["base"].effect? or @chara["left"]["face"].effect? or @chara["right"]["base"].effect? or @chara["right"]["face"].effect?) else @effect = false; end end #------------------------------------------ # イベント更新 #------------------------------------------ def event_update # メッセージの配列を全部やる if(@message.empty? == false and @message_window.active == false) msg = @message.shift; message(msg[0], msg[1], msg[2], msg[3], msg[4], msg[5], msg[6], msg[7]); #コマンドウィンドウがあったら elsif(@command_window != nil and @message_window.visible == false) # コマンドウィンドウがあるときはメッセージウィンドウイラネ。 @message_window.visible = false; @command_window.visible = true; # コマンドウィンドウを更新 @command_window.update # C ボタンが押された場合 if Input.trigger?(Input::C) $game_variables[@select_var] = @command_window.index; @command_window.dispose; @command_window = nil; end # ロードフラグが立ってたら elsif(@load != nil and @message_window.active == false) # スプライト隠し @chara["left"]["base"].visible = false; @chara["left"]["face"].visible = false; @chara["right"]["base"].visible = false; @chara["right"]["face"].visible = false; @message_window.visible = false; # トランジション準備 Graphics.freeze; $scene = Scene_ADV.new(@load, self); $scene.main; # トランジション実行 Graphics.transition; @load = nil; end # イベント脱出は全てのイベントが終わってから if(@message_window.active == false and @message.empty? == true and @command_window == nil and @load == nil) @event = false; @message_window.visible = false; # 消去フラグ if(@clear != nil) clear(@clear); @clear = nil; end # ピクチャの表示など while temp = @pic_msg.shift num = temp.shift; filename = (temp[0] == nil) ? "" : temp[0]; # 既にスプライトがあったらdisposeする if @pictures[num].type == RPG::Sprite @pictures[num].dispose; end # ピクチャを作る @pictures[num] = RPG::Sprite.new; @pictures[num].bitmap = RPG::Cache.picture(filename); # xとyの原点指定は中央指定その他ができるようにする if(temp[1] == "center") ox = 320 - @pictures[num].bitmap.width / 2; elsif(temp[1] == "right") ox = 640 - @pictures[num].bitmap.width else ox = 0; end if(temp[2] == "center") oy = 240 - @pictures[num].bitmap.height / 2; elsif(temp[2] == "bottom") oy = 480 - @pictures[num].bitmap.height; else oy = 0; end @pictures[num].x = ox + ((temp[3] == nil or temp[3] == "") ? 0 : temp[3].to_i); @pictures[num].y = oy + ((temp[4] == nil or temp[4] == "") ? 0 : temp[4].to_i); @pictures[num].opacity = ((temp[5] == nil or temp[5] == "") ? 255 : temp[5].to_i); end end end #------------------------------------------ # 処理部分 #------------------------------------------ def process # コマンドをクリア @command.clear; # ファイルの中身から1行読み込む while((line = @lines.shift) != nil) # 構文解析して真が帰ってきたらbreak if(parse(line, @command)) break; end end # ファイルの中身が空になったら終了フラグ立てる if @lines.empty? # まだメッセージが残ってたらイベントフラグを立てる if @message.empty? == false @event = true; end @scenario_end = true; end # コマンド実行 command(@command); end #------------------------------------------ # 構文解析モドキ #------------------------------------------ def parse(line, cmd) # 空行かコメント行だったら次へ if /^(?:\s*|\#.*)$/ =~ line return false; end # マクロを元にもどす line.gsub!(/\$\[([^\]]+)\]/){ ($__gloval_adv_def.include?($1) ? $__gloval_adv_def[$1] : (@def.include?($1) ? @def[$1] : "")) } # ゲーム変数を使う line.gsub!(/\$V\[(\d+)\]/){ $game_variables[$1.to_i]; } # スイッチを使う line.gsub!(/\$S\[(\d+)\]/){ ($game_switches[$1.to_i] == true) ? "on" : "off"; } # コマンドだったらコマンドに、メッセージでもコマンドに if /^\$([a-z_]+)\s+(.*)$/ =~ line cmd["cmd"] = $1; cmd["val"] = $2; return true; else cmd["cmd"] = "msg"; cmd["val"] = line; return true; end end #------------------------------------------ # コマンド実行 #------------------------------------------ def command(cmd) # ハッシュが空ならそのまま終わり if cmd.empty? return; end # メッセージだけ別 if cmd["cmd"] == "msg" base = (@active != nil) ? @chara[@active]["basefile"] : nil; face = (@active != nil) ? @chara[@active]["facefile"] : nil; plus_x = (@active != nil) ? @plus[@active]["x"] : 0; plus_y = (@active != nil) ? @plus[@active]["y"] : 0; @message.push([cmd["val"], @active, face, base, plus_x, plus_y]); return; # メッセージ→非メッセージにトリガ # elsif @message.empty? == false else @event = true; end # コマンドの種類によって処理を変える case cmd["cmd"] # アクティブのキャラ変更 when "active" @active = (/^(left|right)$/ =~ cmd["val"]) ? $1 : nil; # 背景変更(自動トランジション) when "back" Graphics.freeze; @background.bitmap = RPG::Cache.picture(cmd["val"]); if @transition == "" Graphics.transition(20); else Graphics.transition(40, "Graphics/Transitions/" + @transition); end # 画面をクリアして新背景に when "clear" Graphics.freeze; clear("left"); clear("right"); @background.bitmap = RPG::Cache.picture(cmd["val"]); if @transition == "" Graphics.transition(20); else Graphics.transition(40, "Graphics/Transitions/" + @transition); end # キャラのグラフィック設定 when "left_base" @chara["left"]["basefile"] = cmd["val"]; @active = "left"; when "left_face" @chara["left"]["facefile"] = cmd["val"]; @active = "left"; when "right_base" @chara["right"]["basefile"] = cmd["val"]; @active = "right"; when "right_face" @chara["right"]["facefile"] = cmd["val"]; @active = "right"; # キャラ消去 when "dispose" # クリアフラグを立てる pos = cmd["val"]; @clear = pos; @active = nil; # 位置調整 when "left_x" @plus["left"]["x"] = cmd["val"].to_i; when "left_y" @plus["left"]["y"] = cmd["val"].to_i; when "right_x" @plus["right"]["x"] = cmd["val"].to_i; when "right_y" @plus["right"]["y"] = cmd["val"].to_i; # ピクチャ when "picture" # 書式を確認 if(/^(\d+)=\[(.*)\]\s*$/ =~ cmd["val"]) num = $1.to_i; temp = Array.new; temp = $2.split(/\]\[/) temp.unshift(num); @pic_msg.push(temp); end # ブロック処理 when "block" # 複数コマンドをコマンド毎に分ける @block = cmd["val"].split(/\s*;\s*/); # 分けたコマンドを@linesの先頭にいれる @lines[0, 0] = @block; # 基本マクロ設定(bdef あいう=[えおか]みたいなかんじで) when "bdef" if /^([^=]+)=\[(.*)\]$/ =~ cmd["val"] $__gloval_adv_def[$1] = $2; end # マクロ設定(def あいう=[えおか]みたいなかんじで) when "def" if /^([^=]+)=\[(.*)\]$/ =~ cmd["val"] @def[$1] = $2; end # BGM変更 when "bgm" $game_system.bgm_play(RPG::AudioFile.new(cmd["val"], 100, 100)); # SE when "se" $game_system.se_play(RPG::AudioFile.new(cmd["val"], 80, 100)) # トランジションセット when "set_transition" @transition = cmd["val"]; # トランジション when "transition" case cmd["val"] when "run" if @transition == "" Graphics.transition(20); else Graphics.transition(40, "Graphics/Transitions/" + @transition); end when "freeze" Graphics.freeze; end # スイッチ when "switch" # 形式があってれば if(/(\d+)=\[(on|off)\]/.match(cmd["val"])) # スイッチを変更 $game_switches[$1.to_i] = ($2 == "on"); end # 変数 when "var" # 形式があってれば if(/(\d+)=\[(\d+)\]/.match(cmd["val"])) # スイッチを変更 $game_variables[$1.to_i] = $2.to_i; end # ウェイト when "wait" @wait_count = cmd["val"].to_i; # 選択肢 when "select" @select = Array.new; cmd["val"].scan(/{([^}]*)}/){@select.push($1)}; @command_window = Window_Command.new(300, @select); @command_window.back_opacity = 160 @command_window.x = 320 - @command_window.width / 2 @command_window.y = 240 - @command_window.height / 2 @command_window.visible = false; @event = true; event_update; # 選択肢の結果を保存しておく変数 when "select_var" @select_var = cmd["val"].to_i; # 条件分岐 when "if" tmp_cmd = Hash.new; # コマンドを条件/真/偽に分ける param = Array.new; cmd["val"].scan(/{([^}]*)}/){param.push($1)}; # 条件の判定(eval) res = eval(param[0]); # 実行 if(parse(res ? param[1] : param[2], tmp_cmd)) command(tmp_cmd); end # シナリオロード when "load" @load = cmd["val"]; @event = true; # シナリオリード when "read" loadfile(cmd["val"]); @scenario_end = false; # rubyスクリプトを実行 when "eval" eval cmd["val"]; # デバッグ when "debug" p(eval(cmd["val"])); end end #----------------------------------------- # キャラクタ表示スプライトをクリアする #----------------------------------------- def clear(position) @chara[position]["base"].bitmap.dispose; @chara[position]["face"].bitmap.dispose; @chara[position]["basefile"] = nil; @chara[position]["facefile"] = nil; end #----------------------------------------- # X座標を算出する(指定座標,ビットマップ,場所) #----------------------------------------- def pos_x(base, sprite, pos) # 右だったら if(pos == "right") sprite.x = (640 - base - sprite.bitmap.width); # 左だったら else sprite.x = base; end end #----------------------------------------- # メッセージを表示させるフラグ #(セリフ、メッセージ表示場所、絵、背景、x補正、y補正、メッセージの縦位置、枠の有無) #----------------------------------------- def message(message, position=nil, image=nil, back=nil, plus_x=0, plus_y=0, vpos="bottom", frame="on") $game_temp.message_text = message.gsub(/\[\\n\]/, "\n"); # メッセージウィンドウの表示場所 if position == "left" $c_FacePos = "l"; elsif position == "right" $c_FacePos = "r"; else $c_FacePos = "" end if vpos == "bottom" $game_system.message_position = 2; elsif vpos == "center" $game_system.message_position = 1; elsif vpos == "top" $game_system.message_position = 0; end $game_system.message_frame = (frame == "on") ? 1 : 0; # イメージを表示させる if position != nil # 背景から if back != nil @chara[position]["base"].bitmap = RPG::Cache.picture(back); @chara[position]["base"].z = 40; # 背景だから後ろに @chara[position]["base"].x = pos_x(@chara[position]["x"], @chara[position]["base"], position) + plus_x; @chara[position]["base"].y = 480 - @chara[position]["base"].bitmap.height + plus_y; #画面下にフィット @chara[position]["base"].visible = true; # 見える様に end # 表情とか if image != nil @chara[position]["face"].bitmap = RPG::Cache.picture(image); @chara[position]["face"].z = 30; # 背景より上に @chara[position]["face"].x = pos_x(@chara[position]["x"], @chara[position]["face"], position) + plus_x; @chara[position]["face"].y = 480 - @chara[position]["face"].bitmap.height + plus_y; #画面下にフィット @chara[position]["face"].visible = true; # 見える様に end end # メッセージウィンドウをアクティブに @message_window.active = true; end end