【プチコン講座】ウィンドウ生成を関数化&宝箱イベントを完成させよう

プチコン

プチコン 宝箱 からっぽ

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

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

前回「【プチコン講座】メッセージイベントに変数を組み込んでみよう」でメッセージに変数を組みわせることで宝箱の中身に対して表示を変更することが出来ました。

過去の記事でも説明しましたが、今のままだとメッセージウィンドウだけしか表現できないので、
ステータスウィンドウや選択肢ウィンドウ「はい・いいえ」等にも処理を使いまわせるように関数化します。

ウィンドウ生成の関数化は今後のゲーム作りのためにもなるので、可能な限り関数化していきます。

そして宝箱イベントの完成までやります!

それではプチコンでRPG作り第18回目を始めましょう。

  1. ウィンドウ関数をよく見てみよう
  2. ウィンドウ関数を実際に作ってみよう
  3. メッセージを表示を関数化してみよう
  4. 宝箱イベントを完成させよう

ウィンドウ関数を作ろう

メッセージを自由に表示させるためにはまずウィンドウ生成関数からメッセージ部分を切り離さなければいけません。

文字の基準位置はグローバル変数で決めておくと楽ですね。

メッセージウィンドウだけではないので数値型の配列が便利でしょうか。

添え字の何番目がどこの値なのかは判るようにちゃんとコメントを付けておきましょう。

それでは早速メッセージウィンドウの関数からウィンドウ部分だけを切り取ってみましょう。

DEF D_WINDOW_DRAW A_EVENT, A_RESERVE
  GFILL 80, 150, 320, 208 RGB(0, 21, 151)

  GBOX 79, 149, 321, 209, RGB(128,126,129)
  GBOX 78, 148, 322, 210, RGB(128,126,129)
  GBOX 77, 147, 323, 211, RGB(128,126,129)

  GPSET 78, 148,  RGB(255,255,255)
  GPSET 78, 210,  RGB(255,255,255)
  GPSET 322, 148,  RGB(255,255,255)
  GPSET 322, 210,  RGB(255,255,255)

  GLINE 77, 149, 77, 209, RGB(255,255,255)
  GLINE 76, 149, 76, 209,  RGB(128,126,129)

  GLINE 323, 149, 323, 209, RGB(255,255,255)
  GLINE 324, 149, 324, 209,  RGB(128,126,129)

  GLINE 79, 147, 321, 147, RGB(255,255,255)
  GLINE 79, 146, 321, 146, RGB(128,126,129)

  GLINE 79, 211, 321, 211, RGB(255,255,255)
  GLINE 79, 212, 321, 212, RGB(128,126,129)

END

メッセージは後で使いまわすので、一旦コメントアウトでもしておいてください。

メッセージが無くなったので関数の引数も変更されます。

引数に必要なのはX軸とY軸の始め、つまり左上と幅と高さですね。

なので引数は以下のように4つになります。

余談ですが、グラフィック命令は左上と右下の値を得て描写するのですが、
正直右下の位置を計算するのが面倒なので左上座標を決めて後は幅と高さがあれば計算できます。

DEF D_WINDOW_DRAW A_X, A_Y, A_W, A_H
~~~省略~~~
END

ウィンドウは本来スプライトにしてそれぞれにIDを持たせ、そのIDを元に操作できるようにした方が良いです。

今回作るゲームはそこまで複雑なウィンドウ操作をしないのと、GRAPHIC命令を使いたかったというのもあります。

逝ってしまえばバックグラウンドもスプライトで表現できます(BGと言われているけど根本の仕組み的にはスプライトと同じ)

後はカラーの指定もそうですね。

RPGではコンフィグでウィンドウカラーをRGB0~255の範囲で変更できるゲームが結構あります。

しかし今回は紺色固定にしておきます。

今は基本的にプチコンの仕様に乗っかっりながら作っているので、慣れて来たら好きなように組んでみると良いでしょう。

話が反れたのでウィンドウ関数作りに戻りましょう。

ウィンドウの基準値は背景にあり

ウィンドウは基本的に矩形(四角)の形になります。

なのでまずは一番バックになる背景を描写します。

引数は背景の基準値というわけですね。

それ以外のウィンドウを囲むフレームは、今は直接値を打ち込んで入れていますが
よく見てみると背景の位置を基準にして位置をずらしているだけですね。

ということは引数に「プラスマイナスいくつか」をするだけでウィンドウフレームを作れてしまうということです。

ウィンドウ関数を実際に作ってみよう

グラフィック命令を見ている限り、直線・点・矩形(塗りつぶし無し)をフレームを作るのに使っていますね。

ではその直線やらはの座標はそれらしいところに配置しているように見えて、実は一定の基準値に沿っています。

既に前項でネタバレしちゃってますけど背景の引数を基準にして動かしています。

それでは引数を元に値を変更してみましょう。

どれがどの場所を描写しているか分かりやすいようにコメントも一緒に記載しておきます。

ついでにどう変化しているかもわかりやすいように変更前の値も上にコメント化で入れてます。


DEF D_WINDOW_DRAW A_X, A_Y, A_W, A_H

  # カラー配列を定義
  VAR WC_BACK = RGB(0, 21, 151) # 背景色
  VAR WC_FRAME = RGB(128,126,129) # フレーム色
  VAR WC_HIGHLITE = 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
  #GFILL 80, 150, 320, 208 RGB(0, 21, 151)

  # 矩形フレーム描写(塗りつぶし無し矩形)
  #GBOX 79, 149, 321, 209, RGB(128,126,129)
  GBOX A_X-1, A_Y-1, EX+1, EY+1, WC_FRAME
  #GBOX 78, 148, 322, 210, RGB(128,126,129)
  GBOX A_X-2, A_Y-2, EX+2, EY+2, WC_FRAME
  # GBOX 77, 147, 323, 211, RGB(128,126,129)
  GBOX A_X-3, A_Y-3, EX+3, EY+3, WC_FRAME

  # ハイライトの角の部分(点)
  #GPSET 78, 148,  RGB(255,255,255)
  GPSET A_X-2, A_Y-2, WC_HIGHLITE
  #GPSET 78, 210,  RGB(255,255,255)
  GPSET A_X-2, EY+2, WC_HIGHLITE
  #GPSET 322, 148,  RGB(255,255,255)
  GPSET EX+2, A_Y-2, WC_HIGHLITE
  #GPSET 322, 210,  RGB(255,255,255)
  GPSET EX+2, EY+2, WC_HIGHLITE

  # ハイライトとフレームの直線部分
  #GLINE 77, 149, 77, 209, RGB(255,255,255)
  GLINE A_X-3, A_Y-1, A_X-3, EY+1, WC_HIGHLITE
  #GLINE 76, 149, 76, 209,  RGB(128,126,129)
  GLINE A_X-4, A_Y-1, A_X-4, EY+1, WC_FRAME

  #GLINE 323, 149, 323, 209, RGB(255,255,255)
  GLINE EX+3, A_Y-1, EX+3, EY+1, WC_HIGHLITE
  #GLINE 324, 149, 324, 209,  RGB(128,126,129)
  GLINE EX+4, A_Y-1, EX+4, EY+1, WC_FRAME

  #GLINE 79, 147, 321, 147, RGB(255,255,255)
  GLINE A_X-1, A_Y-3, EX+1, A_Y-3, WC_HIGHLITE
  #GLINE 79, 146, 321, 146, RGB(128,126,129)
  GLINE A_X-1, A_Y-4, EX+1, A_Y-4, WC_FRAME

  #GLINE 79, 211, 321, 211, RGB(255,255,255)
  GLINE A_X-1, EY+3, EX+1, EY+3, WC_HIGHLITE
  #GLINE 79, 212, 321, 212, RGB(128,126,129)
  GLINE A_X-1, EY+4, EX+1, EY+4, WC_FRAME

END

こんな感じでしょうか。

リテラルを変数化してみると基準値から絶対値(4)までしか変化ないのがよくわかりますね。

これに伴うウィンドウの基準点の配列とデータベースを用意してデータベースロード関数を変更しましょう。


# 変数宣言
VAR G_WINDOW_SIZES_LEN = 4
DIM G_WINDOW_SIZEZ[0]

~~~省略~~~

# データベース定義
@WINDOWSIZE
DATA 80, 150, 240, 58

~~~省略~~~

# データベースロード関数
DEF D_DB_LOAD A_ID, A_LEN, A_ARY

  IF A_ID < 2 THEN
    VAR ARY_WORD = 0
  ELSE
    VAR ARY_WORD = ""
  ENDIF

  IF A_ID == 0 THEN
    RESTORE @PLAYER_INIT_STATUS
  ELSEIF A_ID == 1 THEN
    RESTORE @WINDOWSIZE
  ELSEIF A_ID == 2 THEN
    RESTORE @SYSTEMWORD
  ELSEIF A_ID == 3 THEN
    RESTORE @ITEMNAME
  ELSEIF A_ID == 4 THEN
    RESTORE @ENEMYNAME
  ELSEIF A_ID == 5 THEN
    RESTPRE @MESSAGEDATA
  ENDIF

  FOR G_I=0 to A_LEN-1
    READ ARY_WORD
    PUSH A_ARY, ARY_WORDS
  NEXT
END

増やすたびにデータベースロードの関数を変更するのは面倒ですよね。

今回はやりませんが、こういった明らかに非効率な部分は効率化するために、
グローバル変数を利用するのもありですね。

なるべくグローバル変数は使いたくないですが、見やすさと作業量を犠牲にしてまで突き詰めるべきではありません。

確かに組み込みプログラミングとかになるとそういった効率化はしないとだめですが、
プチコンは容量はたくさんあるので作りやすいほうを基準に考えてプログラミングした方が良いでしょう。

突き詰めるのはスキルが上がってからで大丈夫です。

最後にイベントキューのところのウィンドウ表示関数の引数が前のままになっているので、
作ったデータベースを元に値を渡してみましょう。

DEF D_SHIFT_EV_DATA
  VAR TYPE = SHIFT(G_EV_QUEUE)
  VAR EVENT = SHIFT(G_EV_QUEUE)
  VAR RESERVE = SHIFT(G_EV_QUEUE)

  PRINT "[イベント かいし]"
  PRINT "===================="

  IF TYPE == 1 THEN
    D_WINDOW_DRAW G_WINDOW_SISEZ[0], G_WINDOW_SISEZ[1], G_WINDOW_SISEZ[2], G_WINDOW_SISEZ[3]
    G_EV_Q_FLAG = 1
  ELSEIF TYPE == 2 THEN
  ELSEIF TYPE == 3 THEN
  ELSEIF TYPE == 10 THEN
  ENDIF

  PRINT "-------------------"

  IF LEN(G_EV_QUEUE) <= 0 THEN
    G_SCENE_FLAG = 0
  ENDIF
END

それでは一度宝箱を調べてみましょう。

問題なく今まで通りウィンドウが表示されていればOKです。

メッセージは今コメントアウトしているので表示してなくて大丈夫でしょう。

ここまで来たら次はメッセージを順番に表示するだけで宝箱イベントが完成しますね。

それでは続けてメッセージを表示する関数を作成しましょう。

メッセージを表示を関数化してみよう

メッセージ表示って一口に言っても色んな方法があります。

メッセージ送りをした後改行して続けて表示したり、1回ウィンドウ内容をクリアして表示したり。

後者の1回クリアして表示する方が作るのは楽ですが、
1つ前に何が行われていたのかわかり辛くなりユーザーに優しいとは言えません。

メッセージログ機能を実装すればいいと思いますが、そんな高機能なものはまだ作りません。

とりあえず一旦難しいことはスッ飛ばしてウィンドウ内容を1回クリアして、
文字を表示するというやり方で1回宝箱イベント完成を目指しましょう。


DEF D_MSG_DRAW A_X, A_Y, A_EVENT A_RESERVE
  IF A_EVENT == 1 THEN
    GPUTCHR A_X+5, A_Y+5, "プレイヤー" + G_MSG_DATAS[0]
  ELSEIF A_EVENT == 2 THEN
    GPUTCHR A_X+5, A_Y+5, G_MSG_DATAS[1] + G_ITEMS_NAMES[A_RESERVE] + G_MSG_DATAS[2]
  ENDIF
END

メッセージの表示座標はウィンドウ描写のXYともに+5にしています。

現状座標が同じになっているのはそのうち修正しますが、
結構コードがさし変わっちゃうので一旦このままでいきます。

座標の次に受け取っているのはイベントナンバーですね。

ここにたどり着いているのはメッセージという証拠ですから、
このイベントナンバーでメッセージのどれを表示するかという分岐をします。

1のときは「プレイヤーはたからばこをあけた」と表示されます。

2のときは「なんと!(アイテム名)がはいっていた!」と表示されます。

そしてそのアイテム名のところは3つ目の値によってアイテムナンバーから引き取られます。

現在は「イベントタイプ」「イベント内容」「イベント詳細」といった感じのイベントデータになっていますが、
作っている内にこの3つじゃ絶対に足りなくなってきます。

そしてその1つのイベントの項目が増える程、分岐点を作らなければいけません。

なので初心者の頃はこういった少ない要素でゲームを作ってみたほうがいいでしょう。

この機能追加したほうがいいかなって時に改良すればOKです。

実際に今の時代のゲーム会社でゲーム作るときはそうはいかないでしょうが……

慣れて来たら事前設計を組んでからプログラミングしたほうが効率もよくなりますが、
最初のうちはそういうことは気にせず純粋にプログラミングを楽しみましょう。

次に、シフトイベントキューの関数に先ほど作った関数をいれて調整しましょう。

DEF D_SHIFT_EV_DATA
  VAR TYPE = SHIFT(G_EV_QUEUE)
  VAR EVENT = SHIFT(G_EV_QUEUE)
  VAR RESERVE = SHIFT(G_EV_QUEUE)

  PRINT "[イベント かいし]"
  PRINT "===================="

  IF TYPE == 1 THEN
    GCLS
    D_WINDOW_DRAW G_WINDOW_SISEZ[0], G_WINDOW_SISEZ[1], G_WINDOW_SISEZ[2], G_WINDOW_SISEZ[3]
    D_MSG_DRAW G_WINDOW_SISEZ[0], G_WINDOW_SISEZ[1], EVENT RESERVE
    G_EV_Q_FLAG = 1
  ELSEIF TYPE == 2 THEN
  ELSEIF TYPE == 3 THEN
  ELSEIF TYPE == 10 THEN
  ENDIF

  PRINT "-------------------"

  IF LEN(G_EV_QUEUE) <= 0 THEN
    GCLS
    G_SCENE_FLAG = 0
  ENDIF
END

プチコン 結果

それでは実行して宝箱を調べてみましょう。

……どうでしょうか?

2つ目の文字が表示されなかったのではないでしょうか?

それもそのはずで、このシフトイベントキュー関数の最後を見てもらうとわかるのですが、
最後のイベントを取り出してここの関数が呼ばれて、この関数が呼び出された時にはキューの数が0になっています。

関数の最後を見てもらうとわかるのですが、キューが0以下の時はグラフィックをクリアしてシーンをマップに戻しています。

なので最後のメッセージイベントが実行された瞬間に消えてしまったのです。

これは設計上あまりよろしくないのですが、回避する方法はあります。

答えを言ってしまうと、イベントリストの最後にイベント終了を知らせるイベントを入れるわけです。

イベント終了のイベントはなにもしないという状態になります。

その時はまだキューが残っているので、メッセージ送りの待機中モードになるため最後のメッセージも表示されます。

メッセージ送りをしたら次はキューが無くなっているのでウィンドウが画面から消えてマップ画面に戻ります。

他にも色々方法はあると思うのですが、イベントリストにイベントの終わりを知らせるものを入れておくのは結構重要になってきます。

例えば特定の条件になっている時にイベント終了のイベントがあった場合、
条件によってそのままイベントを呼び出したりすることに派生できます。

それではイベントの終わりを追加してみましょう。

@EVENT006
DATA 7,  10,95,400  3,1,1  2,1,1  1,1,0, 10,12,0  1,2,0,  0,0,0

後のために他の数値も変更しました。

アイテムを入手したメッセージの時にも音を出したかったので、
アイテム入手メッセージの前に「10,12,0」を増やしました。

後で説明しますが、最初の効果音を鳴らす2つ目の数値を95にして3つ目の数値を400にしました。

これは後で説明します。

次に2つ目のスプライト変更のイベント、「3,1,1」を「3,1,268」にしています。

これもスプライト変更の項目で説明します。

そして3つ目も「2,1,0」から「2,0,1」に変更しました。

これはアイテム増減命令にしたいので0個目のアイテムを1つ追加。

つまりポーションを1つ追加するということになります。

それと最後に「0,0,0」を追加しました。

一番最初の5だった数字も数が2つ増えているので7にするのを忘れないでください。

先ほども言いましたが、イベントタイプの0はイベントの終わりという意味にしたかったので、
今までイベントを1から開始にしていました。

そしてこのイベントタイプが0の時に全部0なら完全にイベント終了。

他の数値なら別のイベントを呼び出す。

みたいな感じにしても面白いかもしれませんね。

それで実行してみましょう。

プチコン 結果

……せいすいを手に入れることはできましたでしょうか?

画像ではライフポーションになっていますが、数値を変えただけです。

これで理想通りの動きになったはずです。

宝箱1つにここまでしんどいのか……って思うかもしれませんが出来た時の達成感はすさまじいものだと思います。

さて、ここまで出来たのであとは音を鳴らして箱を開けた画像に切り替えて実際にアイテムを入手する処理を加えるだけですね!

宝箱イベントを完成させよう

現在メッセージしか作っていませんが、プチコンには音を鳴らす命令とスプライトを変更する命令は1行でかけますので、簡単に組み込んで宝箱イベントを完成させてみましょう。

やっていることはイベントキューから取り出してそれぞれの命令を実行しているだけですね。

  • 宝箱を開けた音を鳴らす
  • 閉じ宝箱から開け宝箱に画像を変更
  • 実際にアイテムを入手して個数を増やす
  • メッセージ発動1(メッセージ送り待ち)
  • アイテムを手に入れたを開けた音を鳴らす
  • メッセージ発動2(メッセージ送り待ち)
  • イベント終了

1つずつ確実に完成させてきましょう!

音を鳴らす

まずは宝箱を開けた時とアイテムを入手した時に音が鳴るようにしてみましょう。

プチコンで音を鳴らすのはすごく簡単です

BEEP [数字]

これだけです。
ダイレクトモードで音の確認もできますし、スマイルツールでも確認できます。

自分の好きな宝箱が開いた音を実装してみましょう。

個人的にはデフォルトの音源だと

BEEP 95, 400

ぐらいが宝箱を開いたときの音になるんじゃないでしょうか?

後ろの400、先ほどイベントの内容を弄ったときにありましたね。

音イベントの時の3番目の数値はピッチの変更という感じにしました。

ついでに2番目はBEEPの数値と合わせました。

10,95,400 というイベントは「DIGという効果音をピッチ400上げて再生する」ということになりますね。

後はアイテムを入手した時の効果音はというと

BEEP 12

でいいでしょうか。

ピッチはそのままでいいので3つ目の数字も0でいいです。

なのでイベントは10,12,0

になります。

それではイベントキューで音が鳴るようにしてみましょう。

DEF D_SHIFT_EV_DATA
  VAR TYPE = SHIFT(G_EV_QUEUE)
  VAR EVENT = SHIFT(G_EV_QUEUE)
  VAR RESERVE = SHIFT(G_EV_QUEUE)

  PRINT "[イベント かいし]"
  PRINT "===================="

  IF TYPE == 1 THEN
    GCLS
    D_WINDOW_DRAW G_WINDOW_SISEZ[0], G_WINDOW_SISEZ[1], G_WINDOW_SISEZ[2], G_WINDOW_SISEZ[3]
    D_MSG_DRAW G_WINDOW_SISEZ[0], G_WINDOW_SISEZ[1], EVENT RESERVE
    G_EV_Q_FLAG = 1
  ELSEIF TYPE == 2 THEN
  ELSEIF TYPE == 3 THEN
  ELSEIF TYPE == 10 THEN
    BEEP EVENT, RESERVE
  ENDIF

  PRINT "-------------------"

  IF LEN(G_EV_QUEUE) <= 0 THEN
    GCLS
    G_SCENE_FLAG = 0
  ENDIF
END

イベントタイプ10のところに分岐しました。

BEPP命令を1行増やしただけです。

基本的にBEEP命令を呼び出すだけなので今のところ関数にしなくてもよさそうですね。

それでは実行して宝箱を調べてみましょう。

……どうでしょうか?

めっちゃゲームぽくなったのではないでしょうか?

次は宝箱を調べた瞬間に宝箱のグラフィックを開けたものに変更してみましょう。

スプライトの画像を変更する

スプライトの画像を変更するのは凄く楽です。

調べた時にイベントのIDを得ることが出来るので、そのイベントID使って
イベントに合わせてグラフィックを変更すればOKです。

しかしイベントを取得した時移行はもうイベントIDが分からない状態になってしまっているので、
グローバル変数でもいいですしプレイヤー用のスプライト変数でもいいですから、
発動させたイベントのIDを保持しておきましょう。

今回はスプライト変数は敵味方ともに揃えたいのでグローバル変数にしておきます。

実際にやってみましょう。

VAR G_EV_ID_NOW = 0


# イベントリストからイベントキューへ挿入
DEF D_GET_EV_DATA A_ID
  VAR EV_COUNT = 0
  VAR EV_DATA = 0

  IF A_ID == 6 THEN
    RESTORE @EVENT006
    READ EV_COUNT
    FOR G_I=1 TO (EV_COUNT * 3)-1
      READ EV_DATA
      PUSH G_EV_QUEUE, EV_DATA
    NEXT
  ENDIF

  IF LEN(G_EV_QUEUE) > 0 THEN
    G_EV_ID_NOW = A_ID
    G_SCENE_FLAG = 1
  ENDIF
END

イベントキューを取り出せたときにIDを保管しておくようにするといいでしょう。

関数の最初にやってしまうとイベントが何もなかった場合でも保持してしまいます。

これもゲームシステムによって変わりますが、今回はイベントが見つかったときだけ保持にします。

これでイベント実行中のスプライトIDを判別することが出来るようになりました。

スプライトのグラフィック変更イベントを組み込んでみましょう

DEF D_SHIFT_EV_DATA
  VAR TYPE = SHIFT(G_EV_QUEUE)
  VAR EVENT = SHIFT(G_EV_QUEUE)
  VAR RESERVE = SHIFT(G_EV_QUEUE)

  PRINT "[イベント かいし]"
  PRINT "===================="

  IF TYPE == 1 THEN
    GCLS
    D_WINDOW_DRAW G_WINDOW_SISEZ[0], G_WINDOW_SISEZ[1], G_WINDOW_SISEZ[2], G_WINDOW_SISEZ[3]
    D_MSG_DRAW G_WINDOW_SISEZ[0], G_WINDOW_SISEZ[1], EVENT RESERVE
    G_EV_Q_FLAG = 1
  ELSEIF TYPE == 2 THEN
  ELSEIF TYPE == 3 THEN
    IF EVENT == 1 THEN
      SPSET G_EV_ID_NOW, RESERVE
    ENDIF
  ELSEIF TYPE == 10 THEN
    BEEP EVENT, RESERVE
  ENDIF

  PRINT "-------------------"

  IF LEN(G_EV_QUEUE) <= 0 THEN
    GCLS
    G_SCENE_FLAG = 0
  ENDIF
END

これで宝箱が開くようになったはずです。

イベント番号で分岐しているのは他のスプライト命令をする為なので今は特に気にしなくても大丈夫です。

実際にアイテムを入手して個数を増やす

次にイベントタイプ「2」でアイテムを増やすイベントを作ります。

このイベントは内部数値を変更するだけなので特に画面に表示されるわけではないので、
数値が変わったかは一旦PRINT命令で表示するようにしましょう。

まずはこれを見てください。

@PLAYER_INIT_STATUS
DATA 1,20,20,3,2,3,0,1

データベースを構築した時にあったものですね。

これは見ての通りプレイヤーの初期ステータスです。

左から「Lv」「HP」「MAXHP」「攻撃力」「防御力」「素早さ」「取得経験値」「ポーションの数」

となっています。

つまり増減させたいのはこれを読み込んだ配列「G_PLAYER_STATUS[7]」ですね

入手する前と後でPRINTで表示してみましょう。

DEF D_SHIFT_EV_DATA
  VAR TYPE = SHIFT(G_EV_QUEUE)
  VAR EVENT = SHIFT(G_EV_QUEUE)
  VAR RESERVE = SHIFT(G_EV_QUEUE)

  PRINT "[イベント かいし]"
  PRINT "===================="

  IF TYPE == 1 THEN
    GCLS
    D_WINDOW_DRAW G_WINDOW_SISEZ[0], G_WINDOW_SISEZ[1], G_WINDOW_SISEZ[2], G_WINDOW_SISEZ[3]
    D_MSG_DRAW G_WINDOW_SISEZ[0], G_WINDOW_SISEZ[1], EVENT RESERVE
    G_EV_Q_FLAG = 1
  ELSEIF TYPE == 2 THEN
    IF EVENT == 1 THEN
     PRINT "ポーションのかず:" + STR$(G_PLAYER_STATUS[7])
      INC G_PLAYER_STATUS[7], RESERVE
     PRINT "ポーションのかず:" + STR$(G_PLAYER_STATUS[7])
    ENDIF
  ELSEIF TYPE == 3 THEN
    IF EVENT == 1 THEN
      SPSET G_EV_ID_NOW, RESERVE
    ENDIF
  ELSEIF TYPE == 10 THEN
    BEEP EVENT, RESERVE
  ENDIF

  PRINT "-------------------"

  IF LEN(G_EV_QUEUE) <= 0 THEN
    GCLS
    G_SCENE_FLAG = 0
  ENDIF
END

イベントタイプ2も分岐していますが、他のアイテムを追加する時に必要になるので一応付けています。

今はポーションと聖水しかないのでいらないのですが、ついでです。

無限ライフポーション現象をどうするか

このままでは一度宝箱を開けてイベントが終わって、もう一度宝箱を調べたらまたライフポーションを入手してしまいます。

イベントレイヤーから数値をリセットしてもいいのですが、
もう一度宝箱を調べたらイベント発動とかいうものを作りたい場合イベントIDがないと困りますね。

プチコンではスプライトに専用の変数を持つことはもう知ってますよね?

まだ全部使っていないのでその変数の一部を利用してしまいましょう。

その値によって取り出すイベントを変更すれば好きなように切り替えられます。

こうすれば余計なイベントレイヤーを書き換える処理もなくなります。

もし終わったイベントの見た目もイベントも残したいけどすり抜けられるようにするようなイベントの場合は、イベントレイヤーを書き換えないといけません。

衝突判定にこのイベントがこの数値の時はすり抜けられるというものを付け加えてもいいですが、ナンセンスです。

イベントリストの最後にタイプ0でイベント終了宣言をしていたと思います。

あれを使ってスプライト変数を書き換えるようにしてしまうのが今のところ最適かもしれません。

それではイベント後のメッセージの追加とイベント終了時にスプライト変数を変更するかどうかを作ってみましょう。

スプライト変数は数値「4」がまだ使っていないのでこれをスプライト毎のイベント切り替えナンバーにしましょう。


VAR G_MSG_DATAS_LEN = 4

@MESSAGEDATA
DATA "は たからばこを あけた", "たからばこ には", "が はいっていた!", "からっぽ!"

@EVENT006
DATA 7,  10,95,400  3,1,1  2,1,1  1,1,0, 10,12,0  1,2,0,  0,1,1
@EVENT006_1
DATA 2,  1,3,1,  0,0,0


# イベントリストからイベントキューへ挿入
DEF D_GET_EV_DATA A_ID
  VAR EV_COUNT = 0
  VAR EV_DATA = 0

  IF A_ID == 6 THEN
    IF SPVAR(A_ID, 4) == 0 THEN
      RESTORE @EVENT006
    ELSEIF SPVAR(A_ID, 4) == 1 THEN
      RESTORE @EVENT006_1
    ENDIF
    READ EV_COUNT
    FOR G_I=1 TO (EV_COUNT * 3)-1
      READ EV_DATA
      PUSH G_EV_QUEUE, EV_DATA
    NEXT
  ENDIF

  IF LEN(G_EV_QUEUE) > 0 THEN
    G_SCENE_FLAG = 1
  ENDIF
END

DEF D_SHIFT_EV_DATA
  VAR TYPE = SHIFT(G_EV_QUEUE)
  VAR EVENT = SHIFT(G_EV_QUEUE)
  VAR RESERVE = SHIFT(G_EV_QUEUE)

  IF TYPE== 0 THEN
    IF EVENT == 1 THEN
      SPVAR G_EV_ID_NOW, 4, RESERVE
    ENDIF
  ELSEIF TYPE == 1 THEN
    GCLS
    D_WINDOW_DRAW G_WINDOW_SISEZ[0], G_WINDOW_SISEZ[1], G_WINDOW_SISEZ[2], G_WINDOW_SISEZ[3]
    D_MSG_DRAW G_WINDOW_SISEZ[0], G_WINDOW_SISEZ[1], EVENT RESERVE
    G_EV_Q_FLAG = 1
  ELSEIF TYPE == 2 THEN
    IF EVENT == 1 THEN
     PRINT G_PLAYER_STATUS[7] 
      G_PLAYER_STATUS[7] += RESERVE
     PRINT G_PLAYER_STATUS[7] 
    ENDIF
  ELSEIF TYPE == 3 THEN
    IF EVENT == 1 THEN
      SPSET G_EV_ID_NOW, RESERVE
    ENDIF
  ELSEIF TYPE == 10 THEN
    BEEP EVENT, RESERVE
  ENDIF

  IF LEN(G_EV_QUEUE) <= 0 THEN
    GCLS
    G_SCENE_FLAG = 0
  ENDIF
END

DEF D_MSG_DRAW A_X, A_Y, A_EVENT A_RESERVE
  IF A_EVENT == 1 THEN
    GPUTCHR A_X+5, A_Y+5, "プレイヤー" + G_MSG_DATAS[0]
  ELSEIF A_EVENT == 2 THEN
    GPUTCHR A_X+5, A_Y+5, G_MSG_DATAS[1] + G_ITEMS_NAMES[A_RESERVE] + G_MSG_DATAS[2]
  ELSEIF A_EVENT == 3 THEN
    GPUTCHR A_X+5, A_Y+5, G_MSG_DATAS[3]
  ENDIF
END

ちょっと長いですが、変更点はそれほど多くありません。

それでは実行して宝箱を調べてみましょう。

プチコン 結果

1回目はそのまま通り宝箱からアイテムを取得。

2回目以降は「からっぽ!」とメッセージが出るだけ

やっと宝箱イベントは完成しましたね!

な、長かった……本当にお疲れ様でした!

プログラミングからゲームを作ると宝箱を開けるだけでもこんな時間がかかるのですから、
RPGツクールの偉大さをわかっていただけるかと思います。

ここまでできてしまえばNPCとの会話なんかももう簡単に実装できますね。

しかしまだ宝箱1つしか作れていません!

これからステータス画面やモンスターのイベント、つまりバトルシーンの作成も残っているのでまだ先は少し長いですね。

ですが確実に1歩を踏み出しました。

くじけずに頑張りましょう!継続は力なり!

ここまで出来たらプログラミング経験値もかなりたまってきてるんじゃないでしょうか?

プログラミングの自信を持つためには作り上げることが大事です。

作り上げて始めてLvアップイベントが発動するのです!

──次回はステータス画面を作ってみます。

javascriptで作っていた時は画面の右に専用のウィンドウがあったのですが、
プチコンは画面全体がマップにしていますので、メニューを開くシステムが必要です。

やることはそこまで難しくはありません。

現状ウィンドウはメッセージウィンドウにしか使っていませんので、
ウィンドウ生成をまずは関数化してしまいましょう。

ウィンドウ関数には左上の座標と横幅と縦幅を渡すだけで好きなサイズのウィンドウを作られるようにするのが理想ですね。

グラフィックで直接値を打ってウィンドウを作っていましたが、
基準値を決めておいけば引数の値から計算して自動的に作成されます。

最後に恒例のここまでのソースコードを張り付けておきます。

地味に使っていない変数があったり順番が乱雑になったので少し削ったり並び変えたりしていますが、
基本的に今回のコードをすべて丸写しすれば動きます。

それでは。

ACLS

#------------------
# 変数定義
#------------------
VAR G_STOP_FLAG = TRUE # ゲームループフラグ
VAR G_I # 汎用変数

# シーンフラグ
VAR G_SCENE_FLAG = 0

# イベント用
VAR G_EV_Q_FLAG = 0 # イベントキューがあるかどうか
DIM G_EV_ID[32] # イベント用情報の配列(初回DATA読み込み用)
VAR G_EV_ID_NOW = 0 # 現在のイベントナンバー
VAR G_EV_STEP = 4 # 1つのイベントデータ数
DIM G_EV_QUEUE[0] # イベントキュー配列

# プレイヤー用
VAR G_PLAYER_NAME$ = ""
VAR G_PLAYER_STATUS_LEN = 8
DIM G_PLAYER_STATUS[0]

# ウィンドウサイズ用
VAR G_WINDOW_SIZES_LEN = 4
DIM G_WINDOW_SIZES[0]

# アイテム名用
VAR G_ITEMS_NAMES_LEN = 2
DIM G_ITEMS_NAMES[0]

# システムワード
VAR G_SYSTEM_WORDS_LEN = 10
DIM G_SYSTEM_WORDS[0]

# 敵用
VAR G_ENEMY_NAMES_LEN = 5
DIM G_ENEMY_NAMES[0]

# メッセージ用
VAR G_MSG_DATAS_LEN = 4
DIM G_MSG_DATAS[0]

# ボタン分の配列を用意
DIM G_BTN_PRESS_COUNT[13] # 全ボタンカウント配列
FILL G_BTN_PRESS_COUNT,0 # 一応定義したボタン配列を0で初期化しておく

# BG関連
VAR G_OX = 0, G_OY = 0 # BG読み込みのオフセット
VAR G_SZ=16, G_MW, G_MH # チップサイズ、マップ幅、マップ高さ
VAR G_BGW = CEIL(400/G_SZ), G_BGH = CEIL(240/G_SZ) # BG読み込み準備
DIM G_MAP[0] # マップレイヤー4枚+イベントレイヤー分

# スプライト用
VAR G_SP_PLAYER = 0 # PLAYERスプライトNo.
DIM G_SP_ANIM_NO[9] # スプライトアニメーション初期値変数 添え字=ID


#------------------
# データベース定義
#------------------
# 開始時に読み込むDATA軍(ラベル付けたほうが安全かもしれない
DATA 500,1040,920,1000,980,1020,269,269,269
DATA 1,5,5,2,  2,23,13,2,  3,4,11,2,  4,13,3,2,  5,22,4,2
DATA 6,6,7,1,  7,3,11,1,  8,22,3,1

# 宝箱イベントデータ
@EVENT006
DATA 7,  10,95,400  3,1,268  2,0,1  1,1,0, 10,12,0  1,2,0,  0,1,1
@EVENT006_1
DATA 2,  1,3,0,  0,0,0

# プレイヤー初期ステータス
@PLAYER_INIT_STATUS
DATA 1,20,20,3,2,3,0,1

# ウィンドウサイズ用
@WINDOWSIZE
DATA 80, 150, 240, 58

# ステータスウィンドウ用ワード
@SYSTEMWORD
DATA "STATUS", "ポーション", "ヶ", "Lv", "HP", "STR", "DEF", "AGI", "EXP", "NEXT"

# アイテム名リスト
@ITEMDATA
DATA "ライフポーション", "せいすい"

# モンスター名リスト
@ENEMYNAME
DATA "リトルバット", "ゴブリン", "スケルトン", "マミー", "ゴースト"

# 定型文リスト
@MESSAGEDATA
DATA "は たからばこを あけた", "たからばこ には", "が はいっていた!", "からっぽ!"

# アニメーション配列初期値代入
D_FIRST_DATA_READ G_SP_ANIM_NO
# イベントID,X座標,Y座標代入
D_FIRST_DATA_READ G_EV_ID

# マップデータ準備
LOAD "DAT:TEST", G_MAP, 0 # マップデータのロード
G_MW = SHIFT(G_MAP) # 読み込んだデータ配列の0個目を配列から切り離して取得(1638415という数字が入ってる)
G_MH = G_MW AND &HFFFF : G_MW = G_MW >> 16 AND &HFFFF # 取り出したデータからシフト演算やらビット演算をする

# マップデータ描写
FOR G_I=0 TO 3
  BGSCREEN G_I, G_BGW, G_BGH, G_SZ # 1画面分のBG
  BGOFS 0,0,4-G_I
  BGLOAD I, -G_OX, ( -G_OY - ( G_I * G_MH )), G_MW, G_MH * ( G_I + 1 ), G_MAP # マップ描写
NEXT

# プレイヤー配置
D_SP_SETUP G_SP_PLAYER, 1, 0

# イベント配置
FOR G_I=0 TO LEN(G_EV_ID)-1 STEP G_EV_STEP
  D_SP_SETUP G_EV_ID[G_I], G_EV_ID[G_I+1], EV_ID[G_I+2]
NEXT

# 各種データの読み込み
D_DB_LOAD 0, G_PLAYER_STATUS_LEN, G_PLAYER_STATUS
D_DB_LOAD 1, G_SYSTEM_WORDS_LEN, G_SYSTEM_WORDS
D_DB_LOAD 2, G_ITEM_NAMES_LEN, G_ITEM_NAMES
D_DB_LOAD 3, G_ENEMY_NAMES_LEN, G_ENEMY_NAMES
D_DB_LOAD 4, G_MSG_DATAS_LEN, G_MSD_DATAS

# グラフィック画面を一番手前に
GPRIO 0

# ゲームループ
WHILE G_STOP_FLAG
  D_SCENE_PARENT
  VSYNC 1
WEND

# シーンの大元
DEF SCENE_PARENT

  IF G_SCENE_FLAG == 0 THEN
    D_CTRL_MAP_MODE
  ELSEIF G_SCENE_FLAG == 1 THEN
    IF G_EV_Q_FLAG == 0 THEN
      D_SHIFT_EV_DATA
    ELSEIF EV_Q_FLAG == 1 THEN
      D_EV_STOP_A_BTN
    ENDIF
  ENDIF

  D_BTN_PRESS

END

# マップ用コントローラー関数
DEF D_CTRL_MAP_MODE
  IF SPVAR(SP_PLAYER, 2) != 1 THEN
    VAR B = BUTTON()
    IF (B AND #UP) > 0 THEN
      IF D_CHECK_COLLISION(G_SP_PLAYER, #UP) == 1 THEN
        D_DIRECTION_MOVE SP_PLAYER, #UP
      ENDIF
    ELSEIF (B AND #DOWN) > 0 THEN
      IF D_CHECK_COLLISION(G_SP_PLAYER, #DOWN) == 1 THEN
        D_DIRECTION_MOVE SP_PLAYER, #DOWN
      ENDIF
    ELSEIF (B AND #LEFT) > 0 THEN
      IF D_CHECK_COLLISION(G_SP_PLAYER, #LEFT) == 1 THEN
        D_DIRECTION_MOVE SP_PLAYER, #LEFT
      ENDIF
    ELSEIF (B AND #RIGHT) > 0 THEN
      IF D_CHECK_COLLISION(G_SP_PLAYER, #RIGHT) == 1 THEN
        D_DIRECTION_MOVE SP_PLAYER, #RIGHT
      ENDIF
    ENDIF
  ELSE
    D_GRID_MOVE SP_PLAYER, (SPVAR SP_PLAYER, 3)
  ENDIF

  # 移動中もボタンを押せるようにしておく
  IF G_BTN_PRESS_COUNT[4] == 1 THEN
    PRINT "Aボタンが押されたよ!"
    D_EV_CHECK G_SP_PLAYER SPVAR(G_SP_PLAYER, 3)
  ENDIF

  IF G_BTN_PRESS_COUNT[6] == 1 THEN
    PRINT "Xボタンが押されたよ!"
  ENDIF
END


# 向きと移動フラグを設定
DEF D_DIRECTION_MOVE A_SPRITE_NO, A_SPRITE_DIRECTION
  SPVAR A_SPRITE_NO, 2, 1
  SPVAR A_SPRITE_NO, 3, A_DIRECTION
END

# 向いている方向に止まるまで歩き続ける(グリッド移動)
DEF D_GRID_MOVE SPRITE_NO, SPRITE_DIRECTION
  # 渡されたスプライトと向きによって移動方向を決定
  IF SPRITE_DIRECTION == #UP THEN
    SPVAR SPRITE_NO, 1, (SPVAR SPRITE_NO, 1) - 1
  ELSEIF SPRITE_DIRECTION == #DOWN THEN
    SPVAR SPRITE_NO, 1, (SPVAR SPRITE_NO, 1) + 1
  ELSEIF SPRITE_DIRECTION == #LEFT THEN
    SPVAR SPRITE_NO, 0, (SPVAR SPRITE_NO, 0) - 1
  ELSEIF SPRITE_DIRECTION == #RIGHT THEN
    SPVAR SPRITE_NO, 0, (SPVAR SPRITE_NO, 0) + 1
  ENDIF

  # 移動させる
  SPOFS SPRITE_NO,(SPVAR SPRITE_NO, 0),(SPVAR SPRITE_NO, 1)

  # 割った余りが0になったら動きを止める
  IF (SPVAR SPRITE_NO, 0) MOD G_SZ == 0 && (SPVAR G_SPRITE_NO, 1) MOD G_SZ == 0 THEN
    SPVAR G_SPRITE_NO, 2, 0
  ENDIF

END

# ドット座標からグリッド座標に変換
DEF D_GET_GRID_XY(A_X_OR_Y)
  RETURN A_X_OR_Y / G_SZ
END

# MAP配列のどこにいるかチェック
DEF D_GET_MAP_POSITION(A_X, A_Y, A_LAYER)
  VAR RETURN_POS = 0
  VAR GRID_X = D_GET_GRID_XY(A_X)
  VAR GRID_Y = D_GET_GRID_XY(A_Y)

  VAR PULS_LAYER = (G_MW * G_MH) * A_LAYER

  IF A_Y <= 0 THEN
    RETURN_POS = GRID_X + PLUS_LAYER
  ELSE
    RETURN_POS = (GRID_X + (GRID_Y * G_MW)) + PLUS_LAYER
  ENDIF

  RETURN RETURN_POS
END

# 当たり判定チェック
DEF D_CHECK_COLLISION(A_NO, A_DIRECTION)
  VAR MP1_SUM_POS = 0
  VAR EV_SUM_POS = 0

  VAR DIRECT = D_GET_DIRECT_POINT(A_DIRECTION)

  VAR MAP_POS = D_GET_MAP_POSITION(SPVAR(A_NO,0), SPVAR(A_NO,1), 1)
  VAR EVENT_POS = D_GET_MAP_POSITION(SPVAR(A_NO,0), SPVAR(A_NO,1), 3)

  MP1_SUM_POS = MAP_POS + DIRECT
  EV_SUM_POS = EVENT_POS + DIRECT

  IF G_MAP[MP1_SUM_POS] == 0 THEN
    IF G_MAP[EV_SUM_POS] == 0 THEN
      D_EV_LAYER_REWRITE A_NO, A_DIRECTION, 1
      RETURN 1
    ELSE
      RETURN 0
    ENDIF
  ELSE
    RETURN 0
  ENDIF
END

# スプライトセットアップ
DEF D_SP_SETUP A_NO, A_X, A_Y
  VAR F = 20
  VAR ANIM = G_SP_ANIM_NO[A_NO]

  SPSET A_NO ANIM
  SPVAR A_NO 0, G_SZ * A_X
  SPVAR A_NO 1, G_SZ * A_Y
  SPVAR A_NO 2, 0
  SPVAR A_NO 3, #DOWN
  SPOFS A_NO SPVAR(A_NO,0), SPVAR(A_NO,1),1

  D_EV_LAYER_REWRITE A_NO, 0, 1

  IF A_NO == 0 || G_EV_ID[(G_EV_STEP * A_NO)-1] == 2 THEN
    SPANIM A_NO, "I", F,ANIM, F,ANIM+1, F,ANIM+2, F,ANIM+3, 0 
  ENDIF
END

# イベントレイヤー書き換え
DEF D_EV_LAYER_REWRITE A_NO, A_DIRECT, A_FLAG

  VAR POS = D_GET_MAP_POSITION(SPVAR(A_NO,0), SPVAR(A_NO,1), 3)

  IF A_FLAG > 0 THEN
    IF A_DIRECT > 0 THEN
      VAR AFTER_POS = POS + D_GET_DIRECT_POINT(A_DIRECT)
      G_MAP[AFTER_POS] = A_NO
    ELSE
      G_MAP[POS] = A_NO
    ENDIF
  ELSE
    VAR BEFORE_POS = POS - D_GET_DIRECT_POINT(A_DIRECT)
    G_MAP[BEFORE_POS] = 0
  ENDIF

END

# 方向定数から1歩前のグリッド座標を得るための値を得る
DEF D_GET_DIRECT_POINT(A_DIRECTION)
  IF A_DIRECTION == #UP THEN
    RETURN DIRECT = -MW
  ELSEIF A_DIRECTION == #DOWN THEN
    RETURN DIRECT = MW
  ELSEIF A_DIRECTION == #LEFT THEN
    RETURN DIRECT = -1
  ELSEIF A_DIRECTION == #RIGHT THEN
    RETURN DIRECT = 1
  ENDIF
END

# DATA初期読み込み
DEF D_FIRST_DATA_READ A_ARRAY
  FOR G_I=0 TO LEN(G_EV_ID)-1
    VAR N=0: READ N
    G_EV_ID[G_I] = N
  NEXT
END

# ボタンカウント関数
DEF D_BTN_PRESS_COUNT
  VAR B = BUTTON()

  # Aボタンカウント
  IF (B AND #A) > 0 THEN
    IF G_BTN_PRESS_COUNT[4] < 255 THEN 
      INC G_BTN_PRESS_COUNT[4]
    ENDIF
  ELSE
    # 1回でも離されたらカウントリセット
    G_BTN_PRESS_COUNT[4] = 0
  ENDIF

  # Xボタンカウント
  IF (B AND #X) > 0 THEN
    IF G_BTN_PRESS_COUNT[6] < 255 THEN 
      INC G_BTN_PRESS_COUNT[6]
    ENDIF
  ELSE
    # 1回でも離されたらカウントリセット
    G_BTN_PRESS_COUNT[6] = 0
  ENDIF

END

# 前方のイベントをチェックする
DEF D_EV_CHECK A_NO A_DIRECT

  VAR POS = D_GET_MAP_POSITION(SPVAR(A_NO,0), SPVAR(A_NO,1), 3)
  VAR AFTER_POS = POS + D_GET_DIRECT_POINT(A_DIRECT)

  VAR EV_ID = G_MAP[AFTER_POS]

 D_GET_EV_DATA EV_ID
END

# イベントリストからイベントキューへ挿入
DEF D_GET_EV_DATA A_ID
  VAR EV_COUNT = 0
  VAR EV_DATA = 0

  IF A_ID == 6 THEN
    IF SPVAR(A_ID, 4) == 0 THEN
      RESTORE @EVENT006
    ELSEIF SPVAR(A_ID, 4) == 1 THEN
      RESTORE @EVENT006_1
    ENDIF
    READ EV_COUNT
    FOR G_I=1 TO (EV_COUNT * 3)-1
      READ EV_DATA
      PUSH G_EV_QUEUE, EV_DATA
    NEXT
  ENDIF

  IF LEN(G_EV_QUEUE) > 0 THEN
    G_EV_ID_NOW = A_ID
    G_SCENE_FLAG = 1
  ENDIF
END

# イベントキュー取り出し
DEF D_SHIFT_EV_DATA
  VAR TYPE = SHIFT(G_EV_QUEUE)
  VAR EVENT = SHIFT(G_EV_QUEUE)
  VAR RESERVE = SHIFT(G_EV_QUEUE)

  IF TYPE== 0 THEN
    IF EVENT == 1 THEN
      SPVAR G_EV_ID_NOW, 4, RESERVE
    ENDIF
  ELSEIF TYPE == 1 THEN
    GCLS
    D_WINDOW_DRAW G_WINDOW_SIZES[0], G_WINDOW_SIZES[1], G_WINDOW_SIZES[2], G_WINDOW_SIZES[3]
    D_MSG_DRAW G_WINDOW_SIZES[0], G_WINDOW_SIZES[1], EVENT RESERVE
    G_EV_Q_FLAG = 1
  ELSEIF TYPE == 2 THEN
    IF EVENT == 1 THEN
     PRINT "ポーションのかず:" + STR$(G_PLAYER_STATUS[7])
      INC G_PLAYER_STATUS[7], RESERVE
     PRINT "ポーションのかず:" + STR$(G_PLAYER_STATUS[7])
    ENDIF
  ELSEIF TYPE == 3 THEN
    IF EVENT == 1 THEN
      SPSET G_EV_ID_NOW, RESERVE
    ENDIF
  ELSEIF TYPE == 10 THEN
    BEEP EVENT, RESERVE
  ENDIF

  IF LEN(G_EV_QUEUE) <= 0 THEN
    GCLS
    G_SCENE_FLAG = 0
  ENDIF
END

# ウィンドウクリエイター
DEF D_WINDOW_DRAW A_X, A_Y, A_W, A_H

  # カラー配列を定義
  VAR WC_BACK = RGB(0, 21, 151) # 背景色
  VAR WC_FRAME = RGB(128,126,129) # フレーム色
  VAR WC_HIGHLITE = 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_HIGHLITE
  GPSET A_X-2, EY+2, WC_HIGHLITE
  GPSET EX+2, A_Y-2, WC_HIGHLITE
  GPSET EX+2, EY+2, WC_HIGHLITE

  # ハイライトとフレームの直線部分
  GLINE A_X-3, A_Y-1, A_X-3, EY+1, WC_HIGHLITE
  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_HIGHLITE
  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_HIGHLITE
  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_HIGHLITE
  GLINE A_X-1, EY+4, EX+1, EY+4, WC_FRAME

END

# メッセージ送り用
DEF D_EV_STOP_A_BTN
  IF G_BTN_PRESS_COUNT[4] == 1 THEN
    G_EV_Q_FLAG = 0
  ENDIF
END

# メッセージイベント
DEF D_MSG_DRAW A_X, A_Y, A_EVENT A_RESERVE
  IF A_EVENT == 1 THEN
    GPUTCHR A_X+5, A_Y+5, "プレイヤー" + G_MSG_DATAS[0]
  ELSEIF A_EVENT == 2 THEN
    GPUTCHR A_X+5, A_Y+5, G_MSG_DATAS[1] + G_ITEMS_NAMES[A_RESERVE] + G_MSG_DATAS[2]
  ELSEIF A_EVENT == 3 THEN
    GPUTCHR A_X+5, A_Y+5, G_MSG_DATAS[3]
  ENDIF
END

# データベースローダー
DEF D_DB_LOAD A_ID, A_LEN, A_ARY

  IF A_ID == 0 THEN
    VAR ARY_WORD = 0
  ELSE
    VAR ARY_WORD = ""
  ENDIF

  IF A_ID == 0 THEN
    RESTORE @PLAYER_INIT_STATUS
  ELSEIF A_ID == 1 THEN
    RESTORE @SYSTEMWORD
  ELSEIF A_ID == 2 THEN
    RESTORE @ITEMNAME
  ELSEIF A_ID == 3 THEN
    RESTORE @ENEMYNAME
  ELSEIF A_ID == 4 THEN
    RESTPRE @MESSAGEDATA
  ENDIF

  FOR G_I=0 to A_LEN-1
    READ ARY_WORD
    PUSH A_ARY, ARY_WORDS
    # 読み込み確認用
    PRINT A_ARY[G_I]
  NEXT
END