【プチコン講座】ATB風バトルシステムを構築しよう:後処理編
こんにちは。継続の錬金術士なおキーヌです。
ブログ毎日更新は158日目になります。
前回「【プチコン講座】ATB風バトルシステムを構築しよう:リザルト編」でエネミーを倒して経験値を獲得し、レベルアップを実装しました。
前回言った通り後処理をしなければいけません。
マップイベントレイヤーの数値を変更しないと見た目が消えてもそこに居続けることになるので、
倒したらちゃんと0に書き換えて通れるようにしなければいけません。
本来は0にするのではなくイベント数値はそのままでその数値は通れるようにする、
というのが理想ですが面倒なので今回は0にしておきます。
それではプチコンでRPG作り第26回目を始めましょう。
倒したらマップのイベントレイヤーを書き換えよう
現在発動しているイベントIDは「G_EV_ID_NOW」で取得できるので、
SPVARを使えばグリッド座標を取得することが出来ます。
そこで書き換えればいいだけです。
タイミングは勝った瞬間でもいいでしょう。
# バトル勝利
DEF D_BATTLE_WINNER
IF G_BATTLE_STATUS[14] == 1 THEN
VAR MAP_POS = D_GET_MAP_POSITION(SPVAR(G_EV_ID_NOW,0), SPVAR(G_EV_ID_NOW,1), 3)
G_MAP[MAP_POS] = 0
SPSTOP G_EV_ID_NOW
BEEP 13, 1200
G_BATTLE_STATUS[14] = 2
SPVAR G_EV_ID_NOW,7,255
SPCOLOR G_EV_ID_NOW RGB(255,255,0,0)
ENDIF
~~~ 省略 ~~~
END
最初の方に作った指定のグリッドのマップ配列の添え字を取得する関数を使い、
直接イベントレイヤーを書き換えてやりましょう。
本来はイベントレイヤー書き換えの関数を使うべきですが、
現状はイベントごとのIDに書き換えるだけになっているので出来ればそこを改良したほうがいいでしょう。
これで倒したら通れるようになっているはずです。
調べたイベント毎の座標に適用されるのでどこのイベントで戦っても処理できるようになりました。
後処理としては一旦これでいいかと思います。
本来ならばイベントレイヤーを0にせずに1のままにして通れるようにした方がいいのですが、
無駄に条件分岐が増えるだけなので一旦は0で対応します。
エネミーが消えた後
バトルイベント後の後処理としてはこれで終わりなのですがあまりにも短いので今後のことについて話します。
コウモリを倒した後は他のすべてのエネミーとたたかえるようになっていますね。
後は他のイベントを作ってやればいいです。
基本的にギリギリの戦闘にした方がゲームとしては楽しそうです。
コウモリも現時点では弱すぎますし経験値も多すぎます。
ゲーム開始からゲームクリアまで考えてみる
基本的に弱い敵を倒していきながらレベルを上げて上位の敵を倒していくRPGです。
レベルアップで能力の上がり方にバラツキがあるので次に倒す敵を見極めなければいけません。
防御が多く上がって攻撃があまり上がらなかった場合は、
攻撃が低く防御が高い敵を倒してレベルアップしてから防御が弱く攻撃の高い敵を倒す。
逆に攻撃が多く上がって防御があまり上がらない場合は短期決戦で、
攻撃が高く防御が低い敵を倒してレベルアップしてから防御が高く攻撃の低い敵を倒す。
この順番で倒したら確実にクリアできるというのが1つだけだとゲームとして面白くありません。
ランダム性こそがゲームの醍醐味です。
あまりランダム性を強すぎるとただの運ゲーとなってしまってよくないときもあります。
ボス戦に関して
js版の時はスケルトンがいる場所の宝箱からドラゴンキラーを取ってからじゃないと、
ボスのドラゴンに歯が立たない状態にしていました。
今回はボスがゴーストになっているので、気付いては居ると思いますが「せいすい」を
持っている状態でないと倒せないようにしたいと思います。
ただ必勝アイテムを持ってたら勝てるというわけじゃなく、
相手からのダメージを計算しつつライフポーションを活用してぎりぎり勝てるようになるというのが理想です。
モンスターの数も限られているので1画面での最大レベルは決まっていますね。
こうしたのはボス戦のバランス調整を楽にするためです。
バランス調整はプログラミングではなくただの数値の調整になるだけなので、
RPG制作プログラミング講座としてはなるべく省略したい部分です。
バランス調整に関してはこれが正しいというものが存在しないので、
各々ゲームに見合った調整をしてください。
話をボスに戻すとドラゴンキラーの場合は武器なので、ゲットしたら攻撃力を底上げして
ドラゴンの防御力を上回って攻撃が通るという感じでしたが、
せいすいの場合は攻撃力があがってしまうのはおかしいですね。
私のイメージでは剣にせいすいをぶっかけて死霊にもダメージが通るようになるという感じです。
もしくは死霊にせいすいを浴びせて物理攻撃が通るようになるという感じでしょうか。
なのでせいすいを取った時にプレイヤーのスプライト変数のどれかをTRUE(1以上)にするか、
グローバル変数か何かでフラグを作ってあげましょう。
そしてイベントIDがボスの時だけ、そのフラグをチェックしてダメージ計算に分岐点を作ります。
せいすいがない場合はいくら攻撃が高くてもダメージは0にする。
持っている場合はいつも通りダメージ計算を行うといった感じでしょう。
ゲームクリアに関して
今回のゲームクリアもボスを倒して宝箱からレアアイテムを手に入れたらクリアという形にして、
プチコンBIGによるRPG制作講座を終わりたいと思います。
階段がありますが、次のステージは今のところ作る予定はないのです。
次のステージにいくにはシーンを切り替えて色々値を初期化したり、
プレイヤーのステータスを保持して反映したり以外はやることはほとんど一緒ですからね。
クリア後は復習も兼ねて自力でステージを実装してみてください。
私が考えたのはステージクリアタイプで10階まで進んでアイテムを取って、
無事に1階まで戻ったらゲームクリアというのが面白そうです。
戻るときはモンスターを強化しておけば2倍楽しめそうですね。
アイテムもランダム化しておけば不思議なダンジョンぽいゲームにできそうです。
──プチコンBIGのRPG制作講座もいよいよ終わりに近づいています。
正直ここまで続けられたのは自分としても驚いていますね。
これまでの講座を数年前の自分に見せてあげたいです。
うだうだ言わずゲームを作って実績を残せと。
最後に前回とほとんど変化ないですが恒例のソースコードを置いておきます。
それでは。
@LABEL GAMERESET
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 = 8
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[16]
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 " は たからばこを あけた", "たからばこ には", "が はいっていた!", "からっぽ!",
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
BATTLE_MODE
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]
ELSEIF A_EVENT == 4 THEN
GPUTCHR A_X+5, A_Y+5, G_ENEMY_NAMES[A_RESERVE] + G_MSG_DATAS[4]
ELSEIF A_EVENT == 5 THEN
GPUTCHR A_X+5, A_Y+5, STR$(G_ENEMY_PARAMS[6 + (7*A_RESERVE)]) + G_MSG_DATAS[5]
ELSEIF A_EVENT == 6 THEN
GPUTCHR A_X+5, A_Y+5, G_MSG_DATAS[6] + STR$(G_PLAYER_STATUS[0]) + G_MSG_DATAS[7]
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
IF G_BATTLE_STATUS[14] <= 0
D_BATTLE_GAUGE_LOOP
D_BATTLE_GUAGE_GRAPH
D_BATTLE_ENEMY_ACTION
D_BATTLE_SELECT_COMMAND
D_BATTLE_ATTACK
D_BATTLE_PLAYER_FLASH
ELSEIF G_BATTLE_STATUS[14] >= 1
D_BATTLE_WINNER
D_BATTLE_RESULT
ENDIF
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
# バトル勝利
DEF D_BATTLE_WINNER
IF G_BATTLE_STATUS[14] == 1 THEN
VAR MAP_POS = D_GET_MAP_POSITION(SPVAR(G_EV_ID_NOW,0), SPVAR(G_EV_ID_NOW,1), 3)
G_MAP[MAP_POS] = 0
SPSTOP G_EV_ID_NOW
BEEP 13, 1200
G_BATTLE_STATUS[14] = 2
SPVAR G_EV_ID_NOW,7,255
SPCOLOR G_EV_ID_NOW RGB(255,255,0,0)
ENDIF
IF G_BATTLE_STATUS[14] == 2 THEN
IF SPVAR(G_EV_ID_NOW,7) > 0 THEN
SPVAR G_EV_ID_NOW,7, SPVAR(G_EV_ID_NOW,7)-2
IF SPVAR(G_EV_ID_NOW,7) <= 0 THEN
SPVAR G_EV_ID_NOW,7,0
ENDIF
SPCOLOR G_EV_ID_NOW RGB(SPVAR(G_EV_ID_NOW,7),SPVAR(G_EV_ID_NOW,7),0,0)
ELSE
SPHIDE G_EV_ID_NOW
G_BATTLE_STATUS[14] = 3
ENDIF
ENDIF
END
# バトルリザルト
DEF D_BATTLE_RESULT
IF G_BATTLE_STATUS[14] == 3 THEN
D_WINDOW_DRAW G_WINDOW_SIZES[0], G_WINDOW_SIZES[1], G_WINDOW_SIZES[2], G_WINDOW_SIZES[3]
G_BATTLE_STATUS[14] = 4
ELSEIF G_BATTLE_STATUS[14] == 4 THEN
D_MSG_DRAW G_WINDOW_SIZES[0], G_WINDOW_SIZES[1], 4, G_EV_ID_NOW
G_BATTLE_STATUS[14] = 5
ELSEIF G_BATTLE_STATUS[14] == 5 THEN
IF G_BTN_PRESS_COUNT[4] == 1 THEN
G_BATTLE_STATUS[14] = 6
ENDIF
ELSEIF G_BATTLE_STATUS[14] == 6 THEN
D_MSG_DRAW G_WINDOW_SIZES[0], G_WINDOW_SIZES[1]+(G_SZ/2), 5, G_EV_ID_NOW
G_BATTLE_STATUS[14] = 7
ELSEIF G_BATTLE_STATUS[14] == 7 THEN
IF G_BTN_PRESS_COUNT[4] == 1 THEN
INC G_PLAYER_STATUS[6], G_ENEMY_PARAMS[6 + (7*G_EV_ID_NOW)]
IF G_PLAYER_STATUS[6] < 10 THEN
G_BATTLE_STATUS[14] = 99
ELSE
G_BATTLE_STATUS[14] = 8
ENDIF
ENDIF
ELSEIF G_BATTLE_STATUS[14] == 8 THEN
BEEP 5, 400
D_PLAYER_LV_UP
D_MSG_DRAW G_WINDOW_SIZES[0], G_WINDOW_SIZES[1]+G_SZ, 6, G_EV_ID_NOW
G_BATTLE_STATUS[14] = 9
ELSEIF G_BATTLE_STATUS[14] == 9 THEN
IF G_BTN_PRESS_COUNT[4] == 1 THEN
G_BATTLE_STATUS[14] = 99
ENDIF
ELSEIF G_BATTLE_STATUS[14] == 99 THEN
GCLS
G_BATTLE_STATUS[14] = 0
G_SCENE_FLAG = 0
ENDIF
END
DEF D_PLAYER_LV_UP
INC G_PLAYER_STATUS[0]
INC G_PLAYER_STATUS[2], RND(3) + 5
INC G_PLAYER_STATUS[3], RND(3) + 1
INC G_PLAYER_STATUS[4], RND(3) + 1
INC G_PLAYER_STATUS[5], RND(3) + 1
END