【プチコン4講座】RPGのステータス画面を実装しよう

プチコン4

プチコン4 ステータス画面

こんにちは。継続の錬金術士なおキーヌです。

ブログ毎日更新は180日目になります。

前回「【プチコン4講座】ウィンドウ生成を関数化」でウィンドウを自由に生成できるようになりました。

ウィンドウを自由に生成できるようになると、好きなところにウィンドウが出せるので
ドラクエのような「はい」「いいえ」選択肢ウィンドウを作ったりできますね。

今回はウィンドウ生成関数を利用してステータス画面を作ってみようと思います。

すでに用意しているステータスを描写するだけなので、ココまでやってこれた人はすぐにできるはずです。

それではプチコン4でRPG作りその16回目始めましょう。

  1. ウィンドウ関数で好きな場所に生成してみよう
  2. ステータスウィンドウを描写してみよう
  3. Xボタンでステータスウィンドウを開閉しよう
  4. ウィンドウにステータスを描写してみよう

ウィンドウ関数で好きな場所に生成してみよう

XとYとWidthとHeightの数値渡して実行すれば好きなところにウィンドウを描写できるようになりましたね。

せっかくなので自由な場所にウィンドウを描写してみましょう。

D_WindowDraw 0, 0, 50,50
D_WindowDraw 100, 0, 50,300
D_WindowDraw 50, 100, 100,20

プチコン4表示結果その1

ループを利用してウィンドウ生成関数を呼び出したら、懐かしのブラクラみたいなことができますね(笑)

ドラクエもFFもメニュー画面を表示する時、
1つだけではなく複数のウィンドウが表示されているのがわかると思います。

ゲーム作りを意識していないとあまりそういう考えにはなりませんね。

FF1であれば

  • クリスタルの取得状況
  • パーティそれぞれのウィンドウ
  • ギルウィンドウ
  • 選択肢ウィンドウ

と複数のウィンドウを確認できます。

あとは必要な場所に応じてウィンドウの上に情報を描写するだけですね。

自由にウィンドウが作られるようになったということはメニュー画面も作れるようになったということです。

ステータスウィンドウを描写してみよう

それでは本番に入りましょう。

ステータスを描写するにはメッセージを描写するための命令が必要になりますね。

幸い、ステータスは表示文字も実際のステータスも配列にしています。

表示文字列と実際のデータの配列数が同じであればループの時の数値を添字に渡せば
理想の文字と実データが表示するのが楽になります。

ステータス画面の作り方の考え方はBIGの時に解説しましたので

【プチコン講座】ステータスウィンドウを実装してみよう

を参照してください。

それではステータスウィンドウ作りの準備をしましょう。

プチコンBIGのときと同じものを作っていきます。

G_WindowSize[8] = [80,150,240,58,  10,10,112,77]

' ステータスウィンドウ描写
def D_StatusWindowDraw
  D_WindowDraw G_WindowSize[4], G_WindowSize[5], G_WindowSize[6], G_WindowSize[7]
end

さっきはテキトーにウィンドウを出しましたが、作ったステータスウィンドウ描写関数を動かしてみましょう。

プチコン4表示結果その2

このウィンドウにステータスを描写していきます。

Xボタンでステータスウィンドウを開閉しよう

ステータスを描写するためのウィンドウは用意出来たので、
Xボタンを押したときにこのウィンドウを開くようにしてみましょう。

ボタンの実装の時にXボタンでメッセージウィンドウを開いて、Yボタンで閉じるというのは既に実行済みなので簡単ですね。

'──────────────────────────
' シーン管理
'──────────────────────────
def D_GameSceneManager
  var direct = D_Controller()
  case G_SceneFlag
    when 0
      ' マップシーン
      D_SpriteGridMove 0, direct
      ' イベントキュー監視
      if LEN(G_EvQueue) > 0 then
        G_SceneFlag = 1
    when 1
      ' イベントシーン
      D_EventScene direct
    when 2
      ' ステータス画面
      D_StatusScene
  endcase
end

' ABXYボタン処理
def D_RightButtonProcess A_B, A_Type
  var BtnPush = 0

  case A_Type
    when #B_RUP
      BtnPush = 1 << #B_RUP
    when #B_RDOWN
      BtnPush = 1 << #B_RDOWN
    when #B_RLEFT
      BtnPush = 1 << #B_RLEFT
    when #B_RRIGHT
      BtnPush = 1 << #B_RRIGHT
  endcase

  if (A_B AND BtnPush ) > O then
    D_BtnPressCount A_Type
    if G_BtnPressCount[A_Type] == 1 then
      case A_Type
        when #B_RUP
          case G_SceneFlag
            when 0
              G_SceneFlag = 2
          endcase
        when #B_RDOWN
        when #B_RLEFT
        when #B_RRIGHT
          D_EvCheck 0, SPVAR(0, "Direct")
      endcase
    endif
  else
    if G_BtnPressCount[A_Type] >= 1 then
       G_BtnPressCount[A_Type] = 0
    endif
  endif
end

'──────────────────────────
' ┠─ ▼ ステータス処理関連
'━━━━━━━━━━━━━━━━━━━━━━━━━━
' ステータスシーン
def D_StatusScene
  if G_OpenStatusFlag == #FALSE then
    D_StatusWindowDraw
    G_OpenStatusFlag = #TRUE
  else
    if G_BtnPressCount[0] == 1 then
      GCLS
      G_OpenStatusFlag = #FALSE
      G_OpenMsgFlag = #FALSE
      G_SceneFlag = 0
    endif
  endif
end

プチコン4表示結果その3

これでXボタンを押すとステータスシーンに突入して他の操作が効かなくなり、
もう一度Xボタンを押すとウィンドウが消えてマップシーンに戻ります。

ウィンドウ関数が呼ばれた時にTRUEになっているので、
ウィンドウオープンフラグもちゃんとFALSEにしておきましょう。

これで自由にステータス画面に移ることが出来ました。

ウィンドウにステータスを描写してみよう

ステータスを表示するための準備が整ったので、最後はステータスを描写してステータス画面を完成させましょう。

やることは至ってシンプルで、ウィンドウを描写した後にステータスを描写していくだけです。

簡単ですね!

今プチコンBIGの方をみて4で再現してみたのですが別にループじゃなくてもよかったですね。

仲間がいた場合はループを利用すべきだとは思いますが、
今回は仲間は居ないので直接指定でいいです。

では早速ステータスを描写してみましょう。

' ステータスウィンドウ描写
def D_StatusWindowDraw
 ' ウィンドウの描写
  D_WindowDraw G_WindowSize[4], G_WindowSize[5], G_WindowSize[6], G_WindowSize[7]

 ' 実際のステータスの描写
  GPUTCHR  G_WindowSize[4]+5, G_WindowSize[5]+5,    G_SystemWord$[0]+":"+ STR$(G_PlayerStatus[0]),8,RGB(255,255,255),1
  GPUTCHR  G_WindowSize[4]+5, G_WindowSize[5]+5+10, G_SystemWord$[1]+":"+ STR$(G_PlayerStatus[1])+"/"+STR$(G_PlayerStatus[2]),8,RGB(255,255,255),1
  GPUTCHR  G_WindowSize[4]+5, G_WindowSize[5]+5+20, G_SystemWord$[2]+":"+ STR$(G_PlayerStatus[3]),8,RGB(255,255,255),1
  GPUTCHR  G_WindowSize[4]+5, G_WindowSize[5]+5+30, G_SystemWord$[3]+":"+ STR$(G_PlayerStatus[4]),8,RGB(255,255,255),1
  GPUTCHR  G_WindowSize[4]+5, G_WindowSize[5]+5+40, G_SystemWord$[4]+":"+ STR$(G_PlayerStatus[5]),8,RGB(255,255,255),1
  GPUTCHR  G_WindowSize[4]+5, G_WindowSize[5]+5+50, G_SystemWord$[5]+":"+ STR$(G_PlayerStatus[6])+"/999",8,RGB(255,255,255),1
  GPUTCHR  G_WindowSize[4]+5, G_WindowSize[5]+5+60, G_SystemWord$[6]+":"+ STR$(G_PlayerStatus[7]),8,RGB(255,255,255),1
end

変数とか使ってもうちょっとシンプルに書けたかもしれないです。

まぁ問題なく描写出来たらいいでしょう。

プチコン4表示結果その4

これでステータス描写が完了しました。

ポーションの数をステータスウィンドウで確認できるようになったので、
宝箱でポーションを手に入れた時のPRINTは消してしまいましょう。

最後にちゃんとステータスが反映されているか確認してみましょう。

プチコン4表示結果その5

やったぜ。

──次回からバトルシステム構築編に突入します。

BIGの時は手探りでここまでやってきたので時間がかかりましたが、
流石に連続でやってるとバトルまでスムーズにたどり着きました。

問題はここからです。

バトルシステムは毎回新しいことをしようと思っていて、
今回はバトル専用画面を設けて作っていくつもりです。

時間が限られているので、あまり大がかりなものは作れませんが
少しぐらいは楽しめるバトルを構築したいものですね。

最後に今回の完成版ソースコードを置いておきます。

それでは

'──────────────────────────
' ▼ 動作モード設定:変数宣言は必須
'──────────────────────────
OPTION STRICT
'──────────────────────────
' ▼ 画面のクリア
'──────────────────────────
ACLS
'──────────────────────────
' ▼ 定数・構造体の定義
'──────────────────────────
CONST #CSZ = 16
ENUM #LAYER_MAP1=0,#LAYER_MAP2,#LAYER_EV

'──────────────────────────
' ▼ 変数・配列の定義
'──────────────────────────
' ┠─ 汎用変数
'━━━━━━━━━━━━━━━━━━━━━━━━━━
var G_I = 0, G_J = 0, ¥
G_BGW = 0, G_BGH = 0
' ゲームループを制御するフラグ
var G_GameLoopFlag = #TRUE
'──────────────────────────
' ┠─ マップシーン用変数
'━━━━━━━━━━━━━━━━━━━━━━━━━━
' 空配列宣言
DIM G_MapData[]
'──────────────────────────
' ┠─ スプライト用変数
'━━━━━━━━━━━━━━━━━━━━━━━━━━
' アニメーション開始スプライト定義No配列
var G_SpEvStep = 4
DIM G_SpAnimNo[] = [500,1040,920,1000,980,1080,1020,269,269,269,269]
'──────────────────────────
' ┠─ ウィンドウ用変数
'━━━━━━━━━━━━━━━━━━━━━━━━━━
G_OpenStatusFlag = #FALSE
G_OpenMsgFlag = #FALSE

'──────────────────────────
' ┠─ イベント用変数
'━━━━━━━━━━━━━━━━━━━━━━━━━━
var G_EvMsgStopFlag = #FALSE
var G_EvNow = 0

' プレイヤー含むイベント初期設定
DIM G_EvId[] = [0,1,0,0,\
  1,5,5,0,\
  2,4,11,0,\
  3,23,13,0,\
  4,13,3,0,\
  5,8,2,0,\
  6,22,4,0,\
  7,6,7,1,\
  8,21,9,1,\
  9,3,11,1,\
  10,22,2,1\
  ]

' イベントキュー
DIM G_EvQueue[]

' 各イベントデータ(ラベル管理
'──────────────────────────
@Event007
DATA 7,  10,95,400  3,1,268  2,0,1  1,1,0,  10,12,0  1,2,0, 0,1,1
@Event007_1
DATA 2,  1,3,0,  0,0,0

'──────────────────────────
' ┠─ データベース
'━━━━━━━━━━━━━━━━━━━━━━━━━━
DIM G_PlayerStatus[8] = [1,20,20,3,2,3,0,1]

DIM G_SystemWord$[7] = ["Lv", "HP", "こうげき", "ぼうぎょ", "すばやさ", "けいけんち", "ポーション"]

DIM G_ItemName$[2] = ["ライフポーション", "せいすい"]

DIM G_EnemyName$[6] = ["リトルバット", "ゴブリン", "スケルトン", "ラミア", "マミー", "ゴースト"]

DIM G_Message$[6] = [" は たからばこを あけた", "たからばこ には ", " が はいっていた!","からっぽ!"]

G_WindowSize[8] = [80,150,240,58,  10,10,112,77]

'──────────────────────────
' ┠─ コントローラー用配列
'━━━━━━━━━━━━━━━━━━━━━━━━━━
’ ボタンカウント配列
G_BtnPressCount[4]

'──────────────────────────
' ▼ プログラム初期化処理
'──────────────────────────
D_GAME_INITIALIZE
'──────────────────────────
' ゲームループ開始
'──────────────────────────
loop
  'シーン管理呼び出し
  D_GameSceneManager
  ' ゲームループフラグ監視
  if !G_GameLoopFlag then BREAK
  ' フレームレート安定
  VSYNC 1
endloop

'──────────────────────────
' シーン管理
'──────────────────────────
def D_GameSceneManager
  var direct = D_Controller()
  case G_SceneFlag
    when 0
      ' マップシーン
      D_SpriteGridMove 0, direct
      ' イベントキュー監視
      if LEN(G_EvQueue) > 0 then
        G_SceneFlag = 1
    when 1
      ' イベントシーン
      D_EventScene direct
    when 2
      ' ステータス画面
      D_StatusScene
  endcase
end

'──────────────────────────
' ▼ 関数の定義
'──────────────────────────
' ┠─ ▼ 初期化関連
'━━━━━━━━━━━━━━━━━━━━━━━━━━
def D_GameInitialize
  ' マップデータのロード
  D_MapInitialize "MAP001.DAT"
  ' マップデータの描写
  'D_MapDraw
  ' スプライトの初期化
  for G_I=0 to LEN(G_EvId)-1 step G_SpEvStep
    D_SpInitialize G_EvId[G_I]
  next
  ' レイヤーのセッティング
  D_ScreenLayerSettings
end

' ▼ スクリーンレイヤー変更
'──────────────────────────
def D_ScreenLayerSettings
  TLAYER 0, 4
  for G_I = 0 to LEN(G_SpAnimNo)-1
    SPLAYER G_I, 3
  next
  GTARGET 0
end

'──────────────────────────
' ┗━┓ ▼ マップ関連
'━━━━━━━━━━━━━━━━━━━━━━━━━━
def D_MapInitialize A_FILENAME$
  ' マップデータファイル読み込み
  G_MAPDATA = LOADV(A_FILENAME$)

  ' マップデータ配列の先頭2つを取り出す
  G_BGW = SHIFT(G_MapData)
  G_BGH = SHIFT(G_MapData)
end
'──────────────────────────
'   ┗━┳━ ▼ マップデータ描写
'━━━━━━━━━━━━━━━━━━━━━━━━━━
' マップデータの描写関数
def D_MapDraw
  ' マップチップ配列を描写
  for G_J = 0 to G_BGH-1
    for G_I = 0 to G_BGW-1
      ' ローカル変数CPに計算した値を入れる 
      var cp = G_I + ( G_J * G_BGW )
      ' CASE文でMAPDATA[CP]の内容に応じて処理を切り替える
      case G_MapDat[cp]
        ' 0のとき
        when 0:
          ' 地面を表示
          TPUT 0, G_I, G_J, CHR(&HE8C9)
        ' 1のとき
        when 1:
          ' 木を表示
          TPUT 0, G_I, G_J, CHR(&HE8CA)
      endcase
    next
  next
end

'──────────────────────────
' ┠─ コントローラー関連
'━━━━━━━━━━━━━━━━━━━━━━━━━━
' コントローラー関数
def D_Controller()
  var B = BUTTON(0)
  var direct = -1

  ' 十字キー監視
  direct = D_LeftButtonProcess(B, #B_LUP, direct)
  direct = D_LeftButtonProcess(B, #B_LDOWN, direct)
  direct = D_LeftButtonProcess(B, #B_LLEFT, direct)
  direct = D_LeftButtonProcess(B, #B_LRIGHT, direct)

  ' ABXY監視
  D_RightButtonProcess B, #B_RUP
  D_RightButtonProcess B, #B_RDOWN
  D_RightButtonProcess B, #B_RLEFT
  D_RightButtonProcess B, #B_RRIGHT

  return direct
end

' 十字キー処理
def D_LeftButtonProcess(A_B, A_Type, A_NowDirect)

  if A_NowDirect > -1 then
   return A_NowDirect
  endif

  var BtnPush = 0
  var direct = -1

  ' 方向を保持
  case A_Type
    when #B_LUP
      BtnPush = 1 << #B_LUP
      direct = #B_RUP
    when #B_LDOWN
      BtnPush = 1 << #B_LDOWN
      direct = #B_RDOWN
    when #B_LLEFT
      BtnPush = 1 << #B_LLEFT
      direct = #B_RLEFT
    when #B_LRIGHT
      BtnPush = 1 << #B_LRIGHT
      direct = #B_RRIGHT
  endcase

  ' 押されていたら方向を返し押されていなければ-1を返す
  if (B and BtnPush) > O then
    return direct
  else
    direct = -1
    return direct
  endif
end

' ABXYボタン処理
def D_RightButtonProcess A_B, A_Type
  var BtnPush = 0

  case A_Type
    when #B_RUP
      BtnPush = 1 << #B_RUP
    when #B_RDOWN
      BtnPush = 1 << #B_RDOWN
    when #B_RLEFT
      BtnPush = 1 << #B_RLEFT
    when #B_RRIGHT
      BtnPush = 1 << #B_RRIGHT
  endcase

  if (A_B AND BtnPush ) > O then
    D_BtnPressCount A_Type
    if G_BtnPressCount[A_Type] == 1 then
      case A_Type
        when #B_RUP
          case G_SceneFlag
            when 0
              G_SceneFlag = 2
          endcase
        when #B_RDOWN
        when #B_RLEFT
        when #B_RRIGHT
          D_EvCheck 0, SPVAR(0, "Direct")
      endcase
    endif
  else
    if G_BtnPressCount[A_Type] >= 1 then
       G_BtnPressCount[A_Type] = 0
    endif
  endif
end

' ボタンカウント関数
def D_BtnPressCount A_Button
  if G_BtnPressCount[A_Button] < 256 then 
    INC G_BtnPressCount[A_Button]
  endif
end


'──────────────────────────
' ┠─ ▼ スプライト関連
'━━━━━━━━━━━━━━━━━━━━━━━━━━
' スプライト初期化
'──────────────────────────
def D_SpInitialize A_Id
  SPSET A_Id, 500
  SPVAR A_Id, "X", G_EvId[G_SpEvStep * A_Id + 1] * #CSZ
  SPVAR A_Id, "Y", G_EvId[G_SpEvStep * A_Id + 2] * #CSZ
  SPVAR A_Id, "Direct", -1
  SPVAR A_Id, "MoveFlag", 0
  SPVAR A_Id, "EventPage", 0
  SPOFS A_Id, SPVAR(A_Id,"X"), SPVAR(A_Id,"Y")

  D_MapArrayReWrite A_Id, SPVAR(A_Id, "Direct"), 1, #LAYER_EV

  if G_EvId[G_SpEvStep * A_Id + 3] != -1 then
    SPANIM A_Id, "I",\
    20,spAnimNo[A_Id],\
    20,spAnimNo[A_Id]+1,\
    20,spAnimNo[A_Id]+2,\
    20,spAnimNo[A_Id]+3,\
    G_EvId[G_SpEvStep * A_Id + 3]
  endif
end

' スプライトの移動
def D_SpriteGridMove A_Id, A_Direct

  if SPVAR(A_Id,"MoveFlag") == 1 then 
    case SPVAR(A_Id,"Direct")
    when #B_RUP
      SPVAR A_Id, "Y", SPVAR(A_Id, "Y") - 1
    when #B_RDOWN
      SPVAR A_Id, "Y", SPVAR(A_Id, "Y") + 1
    when #B_RLEFT
      SPVAR A_Id, "X", SPVAR(A_Id, "X") - 1
    when #B_RRIGHT
      SPVAR A_Id, "X", SPVAR(A_Id, "X") + 1
    endcase

    ' キャラクターの移動
    SPOFS A_Id, SPVAR(A_Id,"X"), SPVAR(A_Id,"Y")

    ' 割った余りが0になったら動きを止める
    if SPVAR(A_Id, "X") MOD #CSZ == 0 && SPVAR(A_Id, "Y") MOD #CSZ == 0 then
      SPVAR A_Id, "MoveFlag", 0
    endif
  else
    if A_Direct >= 0 then
      ' 現在のグリッド座標にアクセスするマップ配列添え字を取得
      var pos = D_GetMapPosition(SPVAR(A_Id, "X"), SPVAR(A_Id, "Y"), 0)
      ' 移動の可否関係なく向きは変更しておく
      SPVAR 0, "Direct", A_ Direct
      ' 向かう先が移動可能かどうかを調べる(MAPレイヤー&イベントレイヤー)
      if D_CheckCollision(pos, SPVAR(A_Id, "Direct")) == #TRUE then
        SPVAR A_Id, "MoveFlag", 1
      endif
    endif
  endif
end


'──────────────────────────
' ┠─ ▼ 衝突判定関連
'━━━━━━━━━━━━━━━━━━━━━━━━━━
' ドット座標をグリッド座標に変換
def D_GetGridXY(A_XY)
  return A_XY / #CSZ
end

' グリッド座標とレイヤーを与えてマップ配列の値を取得する
def D_GetMapPosition(A_X, A_Y, A_LAYER)
  var gridX = D_GetGridXY(A_X)
  var gridX = D_GetGridXY(A_Y)

  VAR layerNo = (G_BGW * G_BGH) * A_LAYER

  IF A_Y <= 0 then
    return gridX + layerNo
  ELSE
    return gridX +  (GRIX_Y * G_BGW)) + layerNo
  ENDIF

END

' 進む先のグリッドが移動可能かどうかを調べる
DEF D_CheckCollision(A_Pos, A_Direct)
  var sumPos = 0
  var evPos = 0

  sumPos = D_GetMapArrayLayerNo(A_Pos, #LAYER_MAP1) + D_GetGridDirectPoint(A_Direct)
  evPos  = D_GetMapArrayLayerNo(A_Pos, #LAYER_EV) + D_GetGridDirectPoint(A_Direct)

  if G_MapData[sumPos] == 0 then
    if G_MapData[evPos] == 0 then
      return #TRUE
    endif
  endif
  return #FALSE 
END

' 方向定数から1歩前のグリッド座標を得るための値を得る
def D_GetGridDirectPoint(A_Direct)
  var direct = 0
  case A_Direct
    when #B_RUP
      direct = -G_BGW
    when #B_RDOWN
      direct = G_BGW
    when #B_RLEFT
      direct = -1
    when #B_RRIGHT
      direct = 1
  endcase
  return direct
end

' マップ配列添字生成
def D_GetMapArrayLayerNo(A_Pos,A_Layer)
  ' 与えられた位置に対してレイヤーを考慮した配列添字を返す
  return A_Pos + ((G_BGW * G_BGH) * A_Layer)
end

' マップ配列書き換え(レイヤー指定
def D_MapArrayReWrite A_Id, A_Direct, A_Flag, A_Layer
  var pos = D_GetMapPosition(SPVAR(A_Id,"X"), SPVAR(A_Id,"Y), A_Layer)

  if A_Flag > 0 then
    if A_Direct >= 0 then
      var afterPos = pos + D_GetGridDirectPoint(A_Direct)
      G_MapData[afterPos] = A_Id
    else
      G_MapData[pos] = A_Id
    endif
  else
    var beforePos = pos - D_GetGridDirectPoint(A_Direct)
    G_MapData[beforePos] = 0
  endif
end

'──────────────────────────
' ┠─ ▼ イベント判定関連
'━━━━━━━━━━━━━━━━━━━━━━━━━━
' 前方のイベントをチェックする
def D_EvCheck A_Id, A_Direct

  if G_SceneFlag == 0 then
    var pos = D_GetMapPosition(SPVAR(A_Id,"X"), SPVAR(A_Id,"Y"), #LAYER_EV)
    var afterPos = pos + D_GetGridDirectPoint(A_Direct)

    var evId = G_MapData[afterPos]

    D_GetEvData evId
  endif
end

'──────────────────────────
' ┠─ ▼ イベント処理関連
'━━━━━━━━━━━━━━━━━━━━━━━━━━
def D_EventScene A_Direct
  if G_EvMsgStopFlag == #FALSE then
    D_ShiftEvData
  else
    D_MsgStopCheck
  endif
end

' イベントキュー処理
'──────────────────────────
def D_ShiftEvData
  var type = SHIFT(G_EvQueue)
  var event = SHIFT(G_EvQueue)
  var reserve = SHIFT(G_EvQueue)

  case type
    when 0
      ' メッセージウィンドウが開いている時に0イベントが来たらフラグをOFFにする
      if G_OpenMsgFlag == #TRUE then
        GCLS
        G_OpenMsgFlag = #FALSE
      endif

      ' イベントによって
      case event
        when 1
          SPVAR G_EvIdNow, "EvPage", reserve
      endcase
    when 1
      if G_OpenMsgFlag == #FALSE then
        D_WindowDraw G_WindowSize[0], G_WindowSize[1], G_WindowSize[2], G_WindowSize[3]
      endif
      D_MessageDraw event, reserve
      G_EvMsgStopFlag = #TRUE
    when 2
      if event == 0 then
        INC G_PlayerStatus[7], reserve
      endif
    when 3
      if event == 1 then
        SPCHR G_EvIdNow, reserve
      endif
    when 10
      ' SEを鳴らす
      BEEP event, reserve
  endcase

  if LEN(G_EvQueue) <= 0 then
    G_SceneFlag = 0
  endif
end

' メッセージ送り待ち
'──────────────────────────
def D_MsgStopCheck
  if G_BtnPressCount[3] == 1 then
    G_EvMsgStopFlag
  endif
endif

' イベントデータ取り出してキューに格納
'──────────────────────────
def D_GetEvData A_Id
  var evCount = 0
  var evData = 0

  case A_Id
    when 7
      if SPVAR(A_Id, "EvPage") == 0 then
        RESTORE @Event007
      elseif SPVAR(A_Id, "EvPage") == 1 then
        RESTORE @Event007_1
      endif
      READ evCount
      for G_I=1 to (evCount * 3)-1
        READ evData
        PUSH G_EvQueue, evData
      next
  endcase

  if LEN(G_EvQueue) > 0 then
    G_EvIdNow = A_Id
    G_SceneFlag = 1
  endif
end
'──────────────────────────
' ┠─ ▼ メッセージ処理関連
'━━━━━━━━━━━━━━━━━━━━━━━━━━
' ウィンドウ生成
'──────────────────────────
def D_WindowDraw A_X, A_Y, A_W, A_H
  ' カラー配列を定義
  var WC_Back = RGB(0, 21, 151) ' 背景色
  var WC_Frame = RGB(128,126,129) ' フレーム色
  var WC_Highlight = RGB(255,255,255) ' ハイライト色

  ' 右下を計算
  var EX = A_W + A_X
  var EY = A_H + A_Y

  ' 背景描写(塗りつぶし有り矩形)
  GFILL A_X, A_Y, EX, EY, WC_Back

  ' 矩形フレーム描写(塗りつぶし無し矩形)
  GBOX A_X-1, A_Y-1, EX+1, EY+1, WC_Frame
  GBOX A_X-2, A_Y-2, EX+2, EY+2, WC_Frame
  GBOX A_X-3, A_Y-3, EX+3, EY+3, WC_Frame

  ' ハイライトの角の部分(点)
  GPSET A_X-2, A_Y-2, WC_Highlight
  GPSET A_X-2, EY+2, WC_Highlight
  GPSET EX+2, A_Y-2, WC_Highlight
  GPSET EX+2, EY+2, WC_Highlight

  ' ハイライトとフレームの直線部分
  GLINE A_X-3, A_Y-1, A_X-3, EY+1, WC_Highlight
  GLINE A_X-4, A_Y-1, A_X-4, EY+1, WC_Frame

  GLINE EX+3, A_Y-1, EX+3, EY+1, WC_Highlight
  GLINE EX+4, A_Y-1, EX+4, EY+1, WC_Frame

  GLINE A_X-1, A_Y-3, EX+1, A_Y-3, WC_Highlight
  GLINE A_X-1, A_Y-4, EX+1, A_Y-4, WC_Frame

  GLINE A_X-1, EY+3, EX+1, EY+3, WC_Highlight
  GLINE A_X-1, EY+4, EX+1, EY+4, WC_Frame

  G_OpenMsgFlag = #TRUE
end
' メッセージ描写
'──────────────────────────
def D_MessageDraw A_Ev, A_Re
  case A_Ev
    when 1
      GPUTCHR 85, 155, "プレイヤー"+ G_Message$[0],8,RGB(255,255,255),1
    when 2
      GPUTCHR 85, 165, G_Message$[1]+ G_ItemName$[A_Re] +G_Message$[2],8,RGB(255,255,255),1
    when 3
      GPUTCHR 85, 155, G_Message$[3],8,RGB(255,255,255),1
  endcase
end
'──────────────────────────
' ┠─ ▼ ステータス処理関連
'━━━━━━━━━━━━━━━━━━━━━━━━━━
' ステータスシーン
def D_StatusScene
  if G_OpenStatusFlag == #FALSE then
    D_StatusWindowDraw
    G_OpenStatusFlag = #TRUE
  else
    if G_BtnPressCount[0] == 1 then
      GCLS
      G_OpenStatusFlag = #FALSE
      G_OpenMsgFlag = #FALSE
      G_SceneFlag = 0
    endif
  endif
end

' ステータスウィンドウ描写
'──────────────────────────
def D_StatusWindowDraw
 ' ウィンドウの描写
  D_WindowDraw G_WindowSize[4], G_WindowSize[5], G_WindowSize[6], G_WindowSize[7]

 ' 実際のステータスの描写
  GPUTCHR  G_WindowSize[4]+5, G_WindowSize[5]+5,    G_SystemWord$[0]+":"+ STR$(G_PlayerStatus[0]),8,RGB(255,255,255),1
  GPUTCHR  G_WindowSize[4]+5, G_WindowSize[5]+5+10, G_SystemWord$[1]+":"+ STR$(G_PlayerStatus[1])+"/"+STR$(G_PlayerStatus[2]),8,RGB(255,255,255),1
  GPUTCHR  G_WindowSize[4]+5, G_WindowSize[5]+5+20, G_SystemWord$[2]+":"+ STR$(G_PlayerStatus[3]),8,RGB(255,255,255),1
  GPUTCHR  G_WindowSize[4]+5, G_WindowSize[5]+5+30, G_SystemWord$[3]+":"+ STR$(G_PlayerStatus[4]),8,RGB(255,255,255),1
  GPUTCHR  G_WindowSize[4]+5, G_WindowSize[5]+5+40, G_SystemWord$[4]+":"+ STR$(G_PlayerStatus[5]),8,RGB(255,255,255),1
  GPUTCHR  G_WindowSize[4]+5, G_WindowSize[5]+5+50, G_SystemWord$[5]+":"+ STR$(G_PlayerStatus[6])+"/999",8,RGB(255,255,255),1
  GPUTCHR  G_WindowSize[4]+5, G_WindowSize[5]+5+60, G_SystemWord$[6]+":"+ STR$(G_PlayerStatus[7]),8,RGB(255,255,255),1
end