【プチコン講座】ATB風バトルシステムを構築しよう:バトルUI編

プチコン

プチコン バトルコマンド

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

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

前回「【プチコン講座】ATB風バトルシステムを構築しよう:エネミー編」でエネミー側も攻撃防御ができるようになりかなりATB風戦闘ぽくなりました。

今のままではPRINTで文字が出ていて地味ですし画面の邪魔なので今回からはバトル用のUIを実装したいと思います。

バトルUIがあるとエネミーが何の行動をしたのかもわかりやすいですし、
プレイヤーのポーションの残りがあとどれぐらいあるのかもわかりやすくなります。

基本的にUIはその名の通りユーザーとゲームをつなぐのためのインターフェースですね。

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

目次2からコーディングになります。

目次1は設計というかレイアウトの話になりますので、不要であれば飛ばしてください。

  1. バトルUIを設計してみよう
  2. ウィンドウを用意して情報をUIに表示してみよう
  3. ポップアップダメージを作る
  4. プレイヤーへのダメージをわかりやすくしよう

バトルUIを設計してみよう

まず画面を見てほしいです。

js版の時と違って画面全体にマップチップを敷きつめてしまいました。

ここのどこにUIを置くかが問題なんですよね。

画面もスクロールしないのでウィンドウを出すと結構邪魔になります。

プレイヤーのいる位置によってウィンドウの位置を変更すればいいというのも1つの手ですが
画面をよく見るとプレイヤーが行けない場所は画面周囲1マス分ありますね。

そこをうまく活用すれば邪魔じゃなくなりそうです。

こういうタイプのゲームのUIのヒントはアクションRPGにありそうですね。

ひとまず戦闘中に必要な情報を上げてみましょう。

  • プレイヤーのHPと最大HP
  • ポーションの残り数
  • 倒した・経験値獲得メッセージ表示
  • ダメージポップアップ

一度上記の要素を軽く入れたものをスクリーンショットを撮って簡単にUIを描いてみました。

プチコンバトルUI

こんなところでしょうか。

メッセージウィンドウに関してはプレイヤーが下に行ったら座標を変更せざるを得ないですね。

本来はバトル画面を実装したほうがいいのでしょうが、一旦はこのまま進めます。

プチコンBIGで作り込んでもWiiUなのであんまり意味がない、改良はプチコン4の方でやります。

この中で一番難しいのはダメージのポップアップでしょうか。

FF的な感じで言えば攻撃してエフェクトが出た後にダメージを表示するという感じです。

一旦アニメーションは抜きで攻撃した時に出るようにします。

ウィンドウを用意して情報をUIに表示してみよう

バトルUIに使うウィンドウはメッセージと右上のプレイヤーの簡易ステータスですね。

メッセージは既に作っているので流用すればOKでしょう。

右上にウィンドウを出して、プレイヤーのHPと最大HPとポーションの残り数を表示します。

このウィンドウはバトルに限らず常に出しててもいいかもしれませんね。

実装しておいてあれですが一々ステータスを開いて確認するのも面倒ですし(笑)

それでは右上にウィンドウを出してパラメーターを描写してみましょう。

ステータス画面を描写したやり方と殆ど同じなのでほぼコピペで問題ないと思います。

一応ウィンドウの位置はデータベースに追加しましょう。

ウィンドウの描写はゲーム開始時のみでも問題ありませんが、
そこだけでやっているとGCLSを呼び出したときに消えてしまいます。

そんなに重たくない処理なので毎フレーム描写でも問題ないでしょう。

重くなるまでは描写をメインループにくみこんでおいても大丈夫です。


# ウィンドウサイズ用
VAR G_WINDOW_SIZES_LEN = 16


@WINDOWSIZE
DATA 80,150,240,58,  10,10,112,77,  10,10,80,50, 10,10,80,50,  208,-32,167,42

DEF D_MINI_STATUS_DRAW

  # ローカル配列定義
  DIM WS[0]
  # グローバル配列の参照を格納
  WS = G_WINDOW_SIZES

  # ウィンドウの描写
  D_WINDOW_DRAW WS[12], WS[13], WS[14], WS[15]
  # HPの表示
  GPUTCHR WS[12]+5, WS[13]+34, G_SYSTEM_WORDS[1]+":"+ STR$(G_PLAYER_STATUS[1])+"/"+STR$(G_PLAYER_STATUS[2])
  # ポーションの表示
  GPUTCHR WS[12]+5+80, WS[13]+34, G_SYSTEM_WORDS[6]+":"+ STR$(G_PLAYER_STATUS[7])+"/10"

END

これでいい感じにウィンドウが表示されてHPとポーションが表示されたと思います。

常に表示を更新しているので、一度戦闘をしてみると数値の増減が確認できると思います。

これはこれでもう完成ですね。

数値の表示が出ただけで更にRPGぽくなりました!

ポップアップダメージを作る

ポップアップダメージと言いましたが、アニメーションするわけではありません。

自信があるなら作ってもらっても大丈夫ですが、
今回はダメージ与えた時に画面に表示して少ししたら消えるというものを作ってみましょう。

仕組みとしては、ダメージ計算後の値をダメージ表記用の関数に渡してあげることです。

まずは簡単な所からやりましょう。

ダメージ表示をする関数を作ります。

DEF D_BATTLE_POPUP_DAMAGE A_DAMAGE

  GPUTCHR SPVAR(G_EVENT_ID_NOW, 0), SPVAR(G_EVENT_ID_NOW, 1) - G_SZ, A_DAMAGE

END

エネミーの頭上に表示したいので座標は現在のイベントIDを基準値にして、
引数にダメージ数値を受け取って使います。

一度表示してみましょう。

ダメージを与える度に更新されます。

しかしGCLSの関係かダメージ計算のところで呼び出してしまうとプレイヤーの攻撃時だけ、
ダメージが出る前に消えてしまいます。

なのでダメージをグローバル変数に渡してダメージを与えたというフラグを立てて、
別で管理したほうがよさそうですね。

これは完全に設計ミスです。

行き当たりばったりで作っているとこうなってしまう罠に陥ります。

しかしここで挫折するのはもったいないので、禁じ手解禁ということでグローバル変数を使って逃げるという手もありです。

ようは動いて処理落ちせずバグにならなければいいのです。

コメントさえつけておけば管理もできますし、GOTOを使いまくるよりはまだいいでしょう。

グローバル変数を新たに作る前に、再利用できるものがないかを見てみましょう。

プレイヤーとエネミーのゲージと状態管理をしている配列「G_BATTLE_STATUS」がありましたね。

それを拡張してお互いに1回分の与えたダメージや受けたダメージを保持しておきましょう。

今回はエネミー側の攻撃のポップアップはしませんが、一応保存しておくと何かと役に立つと思います。

もし、ネトゲのようにダメージログとかをとっていきたいのであればこういったやり方をしておくと楽ですよ。

「G_BATTLE_STATUS」は6まで定義してましたね。

0~3は使用済みなのでお互いの与ダメ被ダメだと4つ必要になります。

今のところ偶数はプレイヤー用で奇数はエネミー用になっているのでそれに習っておけばわかりやすいですね。

何度も言いますが、こういった自分ルールはプログラミングの中でも結構重要になります。

チームでの開発の場合はやめたほうがいいかもしれませんが(笑)

それでは配列を拡張してダメージを保存するようにしてみましょう。

DIM G_BATTLE_STATUS[12]


# ダメージ計算
DEF D_BATTLE_DAMAGE A_ACTOR

  ~~~ 省略 ~~~

  # 最低でもダメージは1入るようにする
  IF DAMAGE <= 0 THEN
    DAMAGE = 1
  ENDIF

  # ダメージ保存
  IF A_ACTOR == 0 THEN
    G_BATTLE_STATUS[4] = DAMAGE
    G_BATTLE_STATUS[7] = DAMAGE
    G_BATTLE_STATUS[8] = 1
  ELSE
    G_BATTLE_STATUS[5] = DAMAGE
    G_BATTLE_STATUS[6] = DAMAGE
    G_BATTLE_STATUS[9] = 1
  ENDIF

  ~~~ 省略 ~~~
END


ダメージ計算完了後に与ダメと被ダメを保存して、ダメージを与えたフラグを立てましょう。

これでいつでもダメージを表記できるようになりました。

配列を拡張した残りの2つは何に使うかというと、ダメージの表示時間用です。

ダメージフラグがオンになったら起動してフレームのカウントをして一定フレームがたったら数字を消すといった感じでしょうか。

それではダメージポップアップ関数を改良してバトルループに組み込みましょう。


DEF D_BATTLE_POPUP_DAMAGE
  IF G_BATTLE_STATUS[8] == 0 THEN
    GFILL SPVAR(G_EVENT_ID_NOW, 0) + (G_SZ/4), SPVAR(G_EVENT_ID_NOW, 1) - (G_SZ/2),(G_EVENT_ID_NOW, 0) + G_SZ, SPVAR(G_EVENT_ID_NOW, 1), RGB(0,0,0,0)
  ELSE G_BATTLE_STATUS[8] == 1 THEN
    GFILL SPVAR(G_EVENT_ID_NOW, 0) + (G_SZ/4), SPVAR(G_EVENT_ID_NOW, 1) - (G_SZ/2),(G_EVENT_ID_NOW, 0) + G_SZ, SPVAR(G_EVENT_ID_NOW, 1), RGB(0,0,0,0)
    GPUTCHR SPVAR(G_EVENT_ID_NOW, 0) + (G_SZ/4), SPVAR(G_EVENT_ID_NOW, 1) - G_SZ, A_DAMAGE
  ENDIF
END

これを書いている時に気付けたのですが、
GFILLでカラーを透明に設定すれば好きな範囲のグラフィックをクリアすることができるようです。

これで他のグラフィックを消さずにダメージフォントの上書きができますね。

しかし現状だと防御されないとダメージが2のままですから上書きされたかわかり辛いですね。

プレイヤーの攻撃を乱数に差し替えてみるとよくわかります。

後、今のままだとダメージログが邪魔になってくるので消してしまいましょう。

画面に表示がでるようになったらPRINTする必要はないですね。

ダメージが残ったままなので一定時間たったら消す

ダメージが画面に残り続けてるのも変なので、一定時間経ったら消えるようにしたいです。

一定時間といっても、数字が出て1秒後ぐらいには消えてほしいです。

先ほど配列の拡張をしたときに準備した部分をフレームカウントとして使います。

ダメージフラグがオンになった時にカウント開始して、一定のフレームカウントが終わったら消すという形にすればいいでしょう。

まずはダメージフラグがオンになったときにカウントするか運数を作りましょう。

DEF D_BATTLE_POPUP_DAMAGE
  IF G_BATTLE_STATUS[8] == 0 THEN
    GFILL SPVAR(G_EVENT_ID_NOW, 0) + (G_SZ/4), SPVAR(G_EVENT_ID_NOW, 1) - (G_SZ/2),(G_EVENT_ID_NOW, 0) + G_SZ, SPVAR(G_EVENT_ID_NOW, 1), RGB(0,0,0,0)
    G_BATTLE_STATUS[10] = 0
  ELSE G_BATTLE_STATUS[8] == 1 THEN
    GFILL SPVAR(G_EVENT_ID_NOW, 0) + (G_SZ/4), SPVAR(G_EVENT_ID_NOW, 1) - (G_SZ/2),(G_EVENT_ID_NOW, 0) + G_SZ, SPVAR(G_EVENT_ID_NOW, 1), RGB(0,0,0,0)
    GPUTCHR SPVAR(G_EVENT_ID_NOW, 0) + (G_SZ/4), SPVAR(G_EVENT_ID_NOW, 1) - G_SZ, A_DAMAGE
  ENDIF

  D_BATTLE_POP_DAMAGE_COUNT
END

DEF D_BATTLE_POP_DAMAGE_COUNT
  IF G_BATTLE_STATUS[8] == 1 THEN
    G_BATTLE_STATUS[8] = 2
  ENDIF

  IF G_BATTLE_STATUS[8] == 2 THEN
    INC G_BATTLE_STATUS[10]
    IF G_BATTLE_STATUS[10] > 60 THEN
      G_BATTLE_STATUS[8] = 0
    ENDIF
  ENIDF 
END

プチコン表示結果その1

やってることはまず何もない時はほぼ何もしない状態です。

攻撃をしたらフラグが1になってダメージ表記が出た後に「D_BATTLE_DAMAGE_POP_COUNT」が呼び出され、
その中にある関数が動いてフラグが2になります。

フラグが2になったらフレームのカウントを始めて60フレーム、つまり1秒後ぐらいを越えたらフラグを0にします。

そしてフラグが0のときはフレームのカウントリセットとダメージ表記範囲の透明塗りつぶし、つまりクリアですね。

プレイヤーへのダメージをわかりやすくしよう

現状エネミー側はダメージポップアップがするので攻撃したのがわかりやすいですが、
プレイヤーへのダメージは右上の数値でしかわかり辛いですね。

なので攻撃を受けた時にプレイヤーを赤くフラッシュさせてダメージを受けたことをわかりやすくしたいです。

本来はプレイヤー側もダメージポップアップをしたいのですが、
表示する位置が頭上だとエネミーと被りますし左右と下ではしっくりきません。

HP管理もRPGの1つの要素なのでダメージを受けたという表現だけでいいでしょう。

スプライトの色を変更する命令は簡単ですが、いい感じにフラッシュさせるのは意外と難しいです。

色を変更するには「SPCOLOR」です。

プレイヤーのカラーは元々RGB(255,255,255,255)なので白くすることはできません。

スプライトを白フラッシュをさせたいときはどうするのかちょっとまだわからないですね。

一旦スプライトを赤くして徐々に元に戻すというやり方でやってみましょう。

フラッシュ用のカウントも必要になりましたので、またバトルステータス配列を拡張しましょう。

11番は使ってませんが、一応エネミー側も使ったと想定しておくと後から何かあったとき修正が効きやすいです。


DIM G_BATTLE_STATUS[14]

# バトルシーンループ
DEF BATTLE_MODE
  D_BATTLE_GAUGE_LOOP
  D_BATTLE_GUAGE_GRAPH
  D_BATTLE_ENEMY_ACTION
  D_BATTLE_SELECT_COMMAND
  D_BATTLE_ATTACK
  D_BATTLE_PLAYER_FLASH
END


# エネミーの行動選択
DEF D_BATTLE_ENEMY_ACTION
  IF G_BATTLE_STATUS[3] == 1 THEN
    VAR ACTION_NUM = RND(10)

    IF ACTION_NUM < 8 THEN
      PRINT "エネミーのこうげき!"
      BEEP 40, 200
      D_BATTLE_DAMAGE 1
      SPCOLOR 0, RGB(255,0,0)
      G_BATTLE_STATUS[13] = 10
    ELSE
      PRINT "エネミーのぼうぎょ!"
      D_BATTLE_GUARD 1
    ENDIF
    D_BATTLE_GUAGE_RESET 1
  ENDIF
END

# プレイヤーフラッシュ
DEF D_BATTLE_PLAYER_FLASH
  IF G_BATTLE_STATUS[13] > 0 THEN
    DEC G_BATTLE_STATUS[13]
    IF G_BATTLE_STATUS[13] > 0 THEN
      SPCOLOR 0, RGB(255,(255/G_BATTLE_STATUS[13]),(255/G_BATTLE_STATUS[13]))
    ELSE
      SPCOLOR 0, RGB(255,255,255)
    ENDIF
  ENDIF
END

エネミーが攻撃を押したときにプレイヤーを赤くし、フラッシュカウントを10にすると
フラッシュカウント関数はバトルループで回っているので赤くなったら毎フレーム元に戻そうとしてくれます。

プチコン表示結果その2

ちょっとイメージと違うフラッシュですが、一旦これで攻撃されたことが分かりやすくなりました。

なにも光ってないと右上のHPをあまり見ないということが体感でわかりました。

光るとダメージを受けたと脳が認識して右上をチラッとみるようになったので心理的にたぶん良いの出ないかと思います。

──残りは勝敗の判定とリザルト画面とレベルアップ処理ですね。

流れ的に順番に作れそうです。

まずはゲームオーバーを作って、勝利後に経験値を増やしてレベルアップ処理といったところでしょうか。

これらが終わったらバトルシステム作りは一旦終了です。

バトルが終わったらほぼ出来上がったようなものです。

最後には特殊なバトルを作ろうと思います。

最後に恒例のソースコードを置いておきます。

それでは。

ACLS

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

# シーンフラグ
VAR G_SCENE_FLAG = 0
VAR G_STATUS_FLAG = FALSE

# イベント用
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 = 16
DIM G_WINDOW_SIZES[0]

# カーソル用
VAR G_CURSOR_X = 0
VAR G_CURSOR_Y = 0
VAR G_CURSOR_N = 0
VAR G_CURSOR_POS_LEN = 3
DIM G_CURSOR_POS[0]

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

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

# エネミー用
VAR G_ENEMY_NAMES_LEN = 5
DIM G_ENEMY_NAMES[0]
VAR G_ENEMY_PARAMS_LEN = 35
DIM G_ENEMY_PARAMS[0]
DIM G_ENEMY_BATTLE_PARAMS[7]

# メッセージ用
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

# バトル用
DIM G_BATTLE_STATUS[14]
DIM G_BATTLE_GUARD_FLAG[2]



#------------------
# データベース定義
#------------------
# 開始時に読み込む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

# コウモリイベントデータ
@EVENT001
DATA 3,  4,1,0, 3,1,0, 0,1,1
@EVENT001_1
DATA 1,  0,0,0


# 宝箱イベントデータ
@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,  10,10,112,77,  10,10,80,50,  208,-32,167,42

# カーソル用
@SELECTDATA
DATA 3,5,15

# エネミーパラメータ用
@ENEMYPARAMS
DATA 1,4,3,1,3,2,20
DATA 2,8,3,1,3,2,20
DATA 3,12,3,1,3,2,20
DATA 4,16,3,1,3,2,20
DATA 5,30,3,1,3,2,20

# ステータスウィンドウ用ワード
@SYSTEMWORD
DATA "Lv", "HP", "こうげき", "ぼうぎょ", "すばやさ", "けいけんち", "ポーション"
# アイテム名リスト
@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

# 配列初期化
FILL G_ENEMY_BATTLE_PARAMS, 0
FILL G_BATTLE_GUARD_FLAG, 0



# 各種データの読み込み
D_DB_LOAD 0, G_PLAYER_STATUS_LEN, G_PLAYER_STATUS
D_DB_LOAD,1, G_WINDOW_SIZES_LEN, G_WINDOW_SIZES
D_DB_LOAD 2, G_CURSOR_POS_LEN, G_CURSOR_POS
D_DB_LOAD 3, G_ENEMY_PARANS_LEN, G_ENEMY_PARANS
D_DB_LOAD 4, G_SYSTEM_WORDS_LEN, G_SYSTEM_WORDS
D_DB_LOAD 5, G_ITEM_NAMES_LEN, G_ITEM_NAMES
D_DB_LOAD 6, G_ENEMY_NAMES_LEN, G_ENEMY_NAMES
D_DB_LOAD 7, 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
  ELSEIF G_SCENE_FLAG == 2 THEN
    D_STATUS_MODE
  ELSEIF G_SCENE_FLAG == 3 THEN
    D_BATTLE_SCENE_LOOP
  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ボタンが押されたよ!"
    G_SCENE_FLAG = 2
  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

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

  D_EV_SELECT_ A_ID

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

# イベントID毎のイベントキュー作成
DEF D_EV_SELECT A_ID

  IF A_ID != 0 THEN
    # IDラベル作成
    VAR LABEL$ = "@EVENT" + FORMAT$("%03D", A_ID)

    VAR EV_COUNT = 0
    VAR EV_DATA = 0

    IF SPVAR(A_ID, 4) == 0 THEN
      RESTORE LABEL$
    ELSEIF SPVAR(A_ID, 4) == 1 THEN
      RESTORE LABEL$ + "_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
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
      INC G_PLAYER_STATUS[7], RESERVE
    ENDIF
  ELSEIF TYPE == 3 THEN
    IF EVENT == 1 THEN
      SPSET G_EV_ID_NOW, RESERVE
    ENDIF
  ELSEIF TYPE == 4 THEN
    D_BATTLE_BEFORE_SETTINGS EVENT
    G_SCENE_FLAG = 3
  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 < 4 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 @ENEMYPARAMS
  ELSEIF A_ID == 4 THEN
    RESTPRE @SELECTDATA
  ELSEIF A_ID == 5 THEN
    RESTORE @ITEMNAME
  ELSEIF A_ID == 6 THEN
    RESTORE @ENEMYNAME
  ELSEIF A_ID == 7 THEN
    RESTPRE @MESSAGEDATA
  ENDIF

  FOR G_I=0 to A_LEN-1
    IF A_ID < 4 THEN
      READ ARY_WORD
      PUSH A_ARY, ARY_WORD
    ELSE
      READ ARY_WORD$
      PUSH A_ARY, ARY_WORD$
    ENDIF
  NEXT
END

# ステータスウィンドウ描写
DEF D_STATUS_WINDOW_DRAW
  # ローカル配列定義
  VAR STATUS = ""
  DIM WS[0]
  # グローバル配列の参照を格納
  WS = G_WINDOW_SIZES

  # ウィンドウの描写
  D_WINDOW_DRAW WS[4], WS[5], WS[6], WS[7]

  # ステータス文字の描写
  FOR G_I = 0 TO G_SYSTEM_WORDS_LEN-1
    # ステータス文字の描写準備
    IF G_I == 0 THEN
      STATUS = G_SYSTEM_WORDS[G_I]+":"+ STR$(G_PLAYER_STATUS[0])
    ELSEIF G_I == 1 THEN
      STATUS = G_SYSTEM_WORDS[G_I]+":"+ STR$(G_PLAYER_STATUS[1])+"/"+STR$(G_PLAYER_STATUS[2])
    ELSEIF G_I == 2 THEN
      STATUS = G_SYSTEM_WORDS[G_I]+":"+ STR$(G_PLAYER_STATUS[3])
    ELSEIF G_I == 3 THEN
      STATUS = G_SYSTEM_WORDS[G_I]+":"+ STR$(G_PLAYER_STATUS[4])
    ELSEIF G_I == 4 THEN
      STATUS = G_SYSTEM_WORDS[G_I]+":"+ STR$(G_PLAYER_STATUS[5])
    ELSEIF G_I == 5 THEN
      STATUS = G_SYSTEM_WORDS[G_I]+":"+ STR$(G_PLAYER_STATUS[6])+"/999"
    ELSEIF G_I == 6 THEN
      STATUS = G_SYSTEM_WORDS[G_I]+":"+ STR$(G_PLAYER_STATUS[7])
    ENDIF

    # 実際のステータスの描写
    GPUCHR  WS[4]+5, WS[5]+5 + (G_I*10), STATUS
  NEXT
END

# ウィンドウトグル
DEF D_STATUS_WINDOW_TOGGLE
  # フラグを反転させる
  G_STATUS_FLAG = NOT G_STATUS_FLAG

  # フラグによって開くか閉じるかを決める
  IF STATUS_FLAG THEN
    D_STATUS_WINDOW_DRAW
  ELSE
    GCLS
  ENDIF
END

# ステータスモード
DEF D_STATUS_MODE
  # 初回にステータスウィンドウフラグをONにしておく
  IF NOT G_STATUS_FLAG THEN
    D_STATUS_WINDOW_TOGGLE
  ENDIF

  # Xボタン監視
  IF G_BTN_PRESS_COUNT[6] == 1 THEN
    D_STATUS_WINDOW_TOGGLE
  ENDIF

END

# バトルシーンループ
DEF BATTLE_MODE
  D_BATTLE_GAUGE_LOOP
  D_BATTLE_GUAGE_GRAPH
  D_BATTLE_ENEMY_ACTION
  D_BATTLE_SELECT_COMMAND
  D_BATTLE_ATTACK
  D_BATTLE_PLAYER_FLASH
END

# ゲージループ
DEF D_BATTLE_GAUGE_LOOP
  # プレイヤーゲージ
  IF G_BATTLE_STATUS[0] < 180 THEN
    INC G_BATTLE_STATUS[0]
  ELSEIF G_BATTLE_STATUS[2] == 0 THEN
    BEEP 7, 600
    INC G_BATTLE_STATUS[2]
  ENDIF

  # エネミーゲージ
  IF G_BATTLE_STATUS[1] < 360 THEN
    INC G_BATTLE_STATUS[1]
  ELSEIF G_BATTLE_STATUS[3] != 0 THEN
    BEEP 7, 600
    INC G_BATTLE_STATUS[3]
  ENDIF
END


# ゲージグラフィック表示
DEF D_BATTLE_GUAGE_GRAPH
  # 背景として下地を黒く塗りつぶす
  GFILL SPVAR(0,0)-2, SPVAR(0,1)+G_SZ+2, SPVAR(0,0)+G_SZ+2, SPVAR(0,1)+G_SZ+5, RGB(255,255,255)
  GFILL SPVAR(0,0)-1, SPVAR(0,1)+G_SZ+1, SPVAR(0,0)+G_SZ+1, SPVAR(0,1)+G_SZ+4, RGB(0,0,0)
  VAR INC_GUAGE = FLOOR( G_BATTLE_STATUS[0] / 180 * G_SZ )
  GLINE SPVAR(0,0) , SPVAR(0,1)+G_SZ, SPVAR(0,0) + INC_GUAGE , SPVAR(0,1)+G_SZ+3, 
END

# バトルゲージリセット
DEF D_BATTLE_GUAGE_RESET A_ACTOR
  IF A_ACTOR == 0 THEN
    G_BATTLE_STATUS[0] = 0
    G_BATTLE_STATUS[2] = 0
  ELSE
    G_BATTLE_STATUS[1] = 0
    G_BATTLE_STATUS[3] = 0
  ENDIF
  G_BATTLE_GUARD_FLAG[A_ACTOR] 
END

# プレイヤーの行動選択
DEF D_BATTLE_ATTACK
  VAR SELECT_SUCCESS = FALSE

  IF G_BATTLE_STATUS[2] == 1 THEN
    IF G_BTN_PRESS_COUNT[4] == 1 THEN

      IF G_CURSOR_N == 0 THEN
        BEEP 103, 300
        D_BATTLE_DAMAGE 0
        SELECT_SUCSESS = TRUE
      ELSE IF G_CURSOR_N == 1 THEN
        PRINT "ぼうぎょ!"
        BEEP 86, 600, 127
        D_BATTLE_GUARD 0
        SELECT_SUCSESS = TRUE
      ENDIF
      ELSE IF G_CURSOR_N == 2 THEN
        IF G_PLAYER_STATUS[7] >= 1 THEN
          PRINT "かいふく!"
          BEEP 106, 200
          D_BATTLE_CURE
          SELECT_SUCSESS = TRUE
        ENDIF
      ENDIF

      IF SELECT_SUCCESS THEN
        GCLS
        D_BATTLE_GUAGE_RESET 0
        G_CURSOR_N = 0
      ELSE
        BEEP 0, -500, 127
      ENDIF

    ENDIF
  ENDIF  
END

# プレイヤーのコマンドウィンドウ表示
DEF D_BATTLE_SELECT_COMMAND
  DIM WS = G_WINDOW_SIZES
  IF G_BATTLE_STATUS[2] == 1 THEN
    G_BATTLE_STATUS[2] = 2
    G_CURSOR_X = WS[8] + G_CURSOR_POS[0]
    G_CURSOR_X = WS[9] + G_CURSOR_POS[1]
    D_WINDOW_DRAW WS[8], WS[9], WS[10], WS[11]
    GPUTCHR WS[8] + G_CURSOR_POS[1] + (G_SZ/2), WS[9] + G_CURSOR_POS[0], "こうげき"
    GPUTCHR WS[8] + G_CURSOR_POS[1] + (G_SZ/2), WS[9] + (G_CURSOR_POS[1]*2) + (G_SZ/2), "ぼうぎょ"
    GPUTCHR WS[8] + G_CURSOR_POS[1] + (G_SZ/2), WS[9] + (G_CURSOR_POS[1]*3) + G_SZ, "かいふく"
    BREPEAT #UP, 30, 5
    BREPEAT #DOWN, 30, 5
  ELSEIF G_BATTLE_STATUS[2] == 2 THEN
    GPUTCHR G_CURSOR_X, G_CURSOR_Y, "|>",RGB(0,21,151)
    VAR B = BUTTON(1)
    IF (B AND #UP) > 0 THEN
      DEC G_CURSOR_Y, G_CURSOR_POS[2]
      DEC G_CURSOR_N
      IF G_CURSOR_Y < WS[9] + G_CURSOR_POS[1] THEN
        G_CURSOR_Y = WS[9] + G_CURSOR_POS[1] + (G_CURSOR_POS[2]*2)
        G_CURSOR_N = 2
      ENDIF
      BEEP 9, 400
    ELSEIF (B AND #DOWN) > 0 THEN
      INC G_CURSOR_Y, G_CURSOR_POS[2]
      INC G_CURSOR_N
      IF G_CURSOR_Y > WS[9] + G_CURSOR_POS[1] + (G_CURSOR_POS[2]*2) THEN
        G_CURSOR_Y = WS[9] + G_CURSOR_POS[1]
        G_CURSOR_N = 0
      ENDIF
      BEEP 9, 400
    ENDIF
    GPUTCHR G_CURSOR_X, G_CURSOR_Y, "|>",RGB(255,255,255)
  ENDIF  
END

# 戦闘準備関数
DEF D_BATTLE_BEFORE_SETTINGS A_ID
  # エネミーステータス初期化
  VAR ST_POS = (A_ID-1) * LEN(G_ENEMY_BATTLE_PARAMS)
  FOR G_I=0 TO LEN(G_ENEMY_BATTLE_PARAMS)-1
    G_ENEMY_BATTLE_PARAMS[G_I] = G_ENEMY_PARAMS[ G_I + ST_POS] 
  NEXT
END

# ダメージ計算
DEF D_BATTLE_DAMAGE A_ACTOR

  VAR DAMAGE = 0

  IF A_ACTOR == 0 THEN
    PRINT "エネミーHP @ダメージまえ:" + STR$(G_ENEMY_BATTLE_PARAMS[1])
    DAMAGE = G_PLAYER_STATUS[3] - ( G_ENEMY_BATTLE_PARAMS[3] + ( G_ENEMY_BATTLE_PARAMS[3] * G_BATTLE_GUARD_FLAG[A_ACTOR] ))
  ELSE
    PRINT "プレイヤーHP @ダメージまえ:" + STR$(G_PLAYER_STATUS[1])
    DAMAGE = G_ENEMY_BATTLE_PARAMS[2] - ( G_PLAYER_STATUS[4] + ( G_PLAYER_STATUS[4] * G_BATTLE_GUARD_FLAG[A_ACTOR] ))
  ENDIF

  # 最低でもダメージは1入るようにする
  IF DAMAGE <= 0 THEN
    DAMAGE = 1
  ENDIF

  # ダメージ保存
  IF A_ACTOR == 0 THEN
    G_BATTLE_STATUS[4] = DAMAGE
    G_BATTLE_STATUS[7] = DAMAGE
    G_BATTLE_STATUS[8] = 1
  ELSE
    G_BATTLE_STATUS[5] = DAMAGE
    G_BATTLE_STATUS[6] = DAMAGE
    G_BATTLE_STATUS[9] = 1
  ENDIF

  IF A_ACTOR == 0 THEN
    DEC G_ENEMY_BATTLE_PARAMS[1], DAMAGE
    IF G_ENEMY_BATTLE_PARAMS[1] <= 0
      PRINT "エネミーをたおしたぞ!"
    ENDIF
    PRINT "エネミーHP @ダメージあと:" + STR$(G_ENEMY_BATTLE_PARAMS[1])
  ELSE
    DEC G_PLAYER_STATUS[1], DAMAGE
    IF G_PLAYER_STATUS[1] <= 0
      PRINT "GAME OVER!"
    ENDIF
    PRINT "プレイヤーHP @ダメージあと:" + STR$(G_PLAYER_STATUS[1])
  ENDIF
END


# ぼうぎょ関数
DEF  D_BATTLE_GURAD A_ID
  G_BATTLE_GUARD_FLAG[A_ID] = 1
END

# かいふく関数
DEF  D_BATTLE_CURE
  DEC G_PLAYER_STATUS[7]
  G_PLAYER_STATUS[1] = G_PLAYER_STATUS[2]
END

# エネミーの行動選択
DEF D_BATTLE_ENEMY_ACTION
  IF G_BATTLE_STATUS[3] == 1 THEN
    VAR ACTION_NUM = RND(10)

    IF ACTION_NUM < 8 THEN
      PRINT "エネミーのこうげき!"
      BEEP 40, 200
      D_BATTLE_DAMAGE 1
      SPCOLOR 0, RGB(255,0,0)
      G_BATTLE_STATUS[13] = 10
    ELSE
      PRINT "エネミーのぼうぎょ!"
      D_BATTLE_GUARD 1
    ENDIF
    D_BATTLE_GUAGE_RESET 1
  ENDIF
END

# ミニウィンドウ表示
DEF D_MINI_STATUS_DRAW

  # ローカル配列定義
  DIM WS[0]
  # グローバル配列の参照を格納
  WS = G_WINDOW_SIZES

  # ウィンドウの描写
  D_WINDOW_DRAW WS[12], WS[13], WS[14], WS[15]
  # HPの表示
  GPUTCHR WS[12]+5, WS[13]+34, G_SYSTEM_WORDS[1]+":"+ STR$(G_PLAYER_STATUS[1])+"/"+STR$(G_PLAYER_STATUS[2])
  # ポーションの表示
  GPUTCHR WS[12]+5+80, WS[13]+34, G_SYSTEM_WORDS[6]+":"+ STR$(G_PLAYER_STATUS[7])+"/10"

END

# ダメージポップアップ
DEF D_BATTLE_POPUP_DAMAGE
  IF G_BATTLE_STATUS[8] == 0 THEN
    GFILL SPVAR(G_EVENT_ID_NOW, 0) + (G_SZ/4), SPVAR(G_EVENT_ID_NOW, 1) - (G_SZ/2),(G_EVENT_ID_NOW, 0) + G_SZ, SPVAR(G_EVENT_ID_NOW, 1), RGB(0,0,0,0)
    G_BATTLE_STATUS[10] = 0
  ELSE G_BATTLE_STATUS[8] == 1 THEN
    GFILL SPVAR(G_EVENT_ID_NOW, 0) + (G_SZ/4), SPVAR(G_EVENT_ID_NOW, 1) - (G_SZ/2),(G_EVENT_ID_NOW, 0) + G_SZ, SPVAR(G_EVENT_ID_NOW, 1), RGB(0,0,0,0)
    GPUTCHR SPVAR(G_EVENT_ID_NOW, 0) + (G_SZ/4), SPVAR(G_EVENT_ID_NOW, 1) - G_SZ, A_DAMAGE
  ENDIF

  D_BATTLE_POP_DAMAGE_COUNT
END

# ダメージポップアップカウント
DEF D_BATTLE_POP_DAMAGE_COUNT
  IF G_BATTLE_STATUS[8] == 1 THEN
    G_BATTLE_STATUS[8] = 2
  ENDIF

  IF G_BATTLE_STATUS[8] == 2 THEN
    INC G_BATTLE_STATUS[10]
    IF G_BATTLE_STATUS[10] > 60 THEN
      G_BATTLE_STATUS[8] = 0
    ENDIF
  ENIDF 
END

# プレイヤーフラッシュ
DEF D_BATTLE_PLAYER_FLASH
  IF G_BATTLE_STATUS[13] > 0 THEN
    DEC G_BATTLE_STATUS[13]
    IF G_BATTLE_STATUS[13] > 0 THEN
      SPCOLOR 0, RGB(255,(255/G_BATTLE_STATUS[13]),(255/G_BATTLE_STATUS[13]))
    ELSE
      SPCOLOR 0, RGB(255,255,255)
    ENDIF
  ENDIF
END