dim講座
※書きかけです。
うみ☆ぬこ - livedoor Blog(ブログ)の人が、多対多なFF風戦闘をNScripterでやりたがっている。そのためにdimを修得せねばっと言う判断は全くもって悪くない。てか素直でいい。
なので、dimについて、実践を踏みながら書いてみる。一人のためにテキストを書き起こすというのも悪くない。
なんかついでに、getparamの使い方も知りたいとのことなので、それも含めてテキストに。
ルールの想定
能力値
登場するキャラクターは敵味方問わず、以下の能力値を持つとする。
戦闘での振る舞い
- 魔法はないので、物理攻撃一辺倒である。
- 攻撃対象の選択は、プレイヤーは自由選択、敵はランダム選択。
行動順
※簡易なFF風にしてみる。
現在戦闘に参加している全てのキャラクターに対し、以下の手順を行う。
- 速度ゲージに1d6を追加する。
- 速度ゲージが100未満ならば、ここで終わり。次のキャラクターにうつる。
- 速度ゲージから100を引く。
- 行動を決定して行動する。
物理攻撃の仕方
- 攻撃側が2d6を振り、技術点に足す。-a
- 防御側が2d6を振り、技術点に足す。-b
- a>bの場合、攻撃は成功。防御側の体力点を2点減らす。
- 体力点が0以下になった場合、そのキャラクターは死亡する。
終了条件
敵味方、どちらかのサイドのキャラクターが全員死亡した場合、戦闘は終了する。
初期設定
とりあえず、プレイヤーキャラクターの名前は、ファファードとグレイマウザーくらいにしとく。
スクリプトの実際
*define ; 変数の設定 numalias hp,100 ; 体力点は100番の数値変数を使う(つもり) numalias tp,101 ; 技術点は101番の数値変数を使う(つもり) numalias dp,102 ; 運命点は102番の数値変数を使う(つもり) numalias is_use,103 ; そのキャラクター番号を使っているかどうかのフラグ。0は未使用。1以上は使用中。 numalias is_live,104 ; そのキャラクター番号のキャラクターが生きているかどうかのフラグ。0は死亡。1以上は健在。 numalias is_there,105 ; そのキャラクター番号のキャラクターがその場にいるかどうかのフラグ。0は不在。1以上は存在。デジョンとか食らうと0になります。 numalias side,106 ; そのキャラクターが敵か味方かのフラグ。0なら味方、1以上なら敵。数値によって、所属する陣営を変えて多勢力間戦闘に拡張できる(今回はしないが) numalias speed,107 ; そのキャラクターのスピードゲージ numalias name,108 ; そのキャラクターの名前のコード numalias volume,109 ; そのキャラクターの番号(あれば) numalias max_character,10 ; 一度に戦闘に参加できるキャラクターの最大数。いくらに設定してもよいが、多すぎるとメモリーが足りなくなって困る。 ; dimの設定 dim ?hp[max_character] ; 体力点の入れ物をキャラクターの数だけ用意 dim ?tp[max_character] ; 技術点の入れ物をキャラクターの数だけ用意 dim ?dp[max_character] ; 運命点の入れ物をキャラクターの数だけ用意 dim ?is_use[max_character] ; 使用フラグの入れ物をキャラクターの数だけ用意 dim ?is_live[max_character] ; 使用フラグの入れ物をキャラクターの数だけ用意 dim ?is_there[max_character] ; 使用フラグの入れ物をキャラクターの数だけ用意 dim ?side[max_character] ; 陣営フラグの入れ物をキャラクターの数だけ用意。 dim ?speed[max_character] ; スピードゲージの入れ物をキャラクターの数だけ用意。 dim ?name[max_character] ; 名前の入れ物をキャラクターの数だけ用意。 dim ?volume[max_character] ; 番号の入れ物をキャラクターの数だけ用意。 ; dim を行うと、数値変数とは別に配列変数が用意される。 ; %hpと?hp[0]は別々の存在であり、どちらかを変えてももう一方には影響しない。 ; ?hp[0]と?hp[1]も別々の存在であり、やはり相互に影響しない。 ; ?hp[n][m]と多元配列も可能だが、そこそこにしよう。メモリーは有限だ。 ; defsub は、自分で新しい命令を作るための命令である。 ; 新しい命令はサブルーチンの形で作成する。サブルーチンはreturnで終わる一連の命令である。 ; defsub diceを宣言したならば、ラベル*dicwが存在しなくてはならない。 ; getparam はサブルーチンが命令に化けるために必要な命令である。 ; サイコロ関連の新命令を作る。 defsub dice ; 任意の数のサイコロを転がす。 ; dice %50,12 ← サイコロを12個転がして、その合計を%50に格納する。 defsub d1 ; サイコロ一個を転がす。 ; d1 %75 ← サイコロを一個転がして、その合計を%75に格納する。 defsub d2 ; サイコロ二個を転がす。 defsub d3 ; サイコロ三個を転がす。 defsub dice2 ; 任意の面数の任意の数のサイコロを転がす。 ; dice2 %80,3,8 ← 8面体サイコロを三つ転がして、その合計を%80に格納する。 numalias dice_num,201 ; ふるサイコロの数 numalias dice_result,202 ; 結果を格納する変数番号を格納する変数。 numalias dice_roll,203 ; サイコロ1個 numalias dice_aspect,204 ; サイコロの面数を格納する変数。普通は6だよね? numalias dice_loop,205 ; サイコロルーチン用ループ変数。 defsub luck numalias luck_result,210 numalias luck_character,211 numalias luck_temp,212 ; 攻撃関連の新命令を作る。 defsub attack ; キャラクター番号を指定して攻撃を判定する命令。 ; attack %50,2,3 ← キャラクター番号2がキャラクター番号3を攻撃する。その結果を%50に格納する。 ; 0なら失敗、1なら成功である。 defsub damage ; キャラクター番号を指定して与えるダメージを判定する命令。 ; damage %51,2,3 ← キャラクター番号2がキャラクター番号3を殴った時のダメージ値を、%51に格納する。 numalias attack_result,170 numalias attacker,171 numalias defender,172 numalias attp,173 numalias dftp,174 numalias damage_result,175 defsub battle numalias character,150 ; 現在行動中のキャラクター番号 numalias battle_result,151 ; 戦闘の結果を格納する変数の番号 numalias character_loop,152 ; ループ用変数 numalias targetable_character,153 ; 攻撃可能キャラクターのリスト dim ?targetable_character[max_character] ; 配列変数化 numalias target,154 ; 攻撃対象キャラクター numalias character_temp,155 numalias side_num,156 numalias side_there,157 numalias battle_end,158 defsub get_name numalias get_name_result,190 numalias get_name_character,191 defsub print_character numalias print_character_num,180 game ; ちょっとしたコツだが、サブルーチンを記述する場所は、メインルーチンからは間違ってもいけない場所がよい。 ; 具体的には、*define節のgameコマンドの後などである。 ; サイコロ関係のサブルーチン *luck getparam i%luck_result,%luck_character mov %%luck_result,0 if ?dp[%luck_character]<1 return d2 %luck_temp notif ?dp[%luck_character]<%luck_temp mov %%luck_result,1 mov ?dp[%luck_character],?dp[%luck_character]-1 return *dice2 getparam i%dice_result,%dice_num,%dice_aspect goto *dice_body3 *dice getparam i%dice_result,%dice_num goto *dice_body2 *d1 mov %dice_num,1:goto *dice_body1 *d2 mov %dice_num,2:goto *dice_body1 *d3 mov %dice_num,3:goto *dice_body1 *dice_body1 getparam i%dice_result ; 結果を格納する数値変数の番号を取得する。 *dice_body2 mov %dice_aspect,6 ; 面数を6に設定 *dice_body3 mov %%dice_result,0 ; 結果を受け取る数値変数を0にする。 for %dice_loop=1 to %dice_num ; 振るサイコロの数を設定。 rnd2 %dice_roll,1,%dice_aspect ; 指定された面数のサイコロを振る。 add %%dice_result,%dice_roll ; その結果を結果に足す。 next ; forに戻って繰り返す。 return ; 攻撃の成否判定用のサブルーチン *attack getparam i%attack_result,%attacker,%defender d2 %attp:add %attp,?tp[%attacker] d2 %dftp:add %dftp,?tp[%defender] mov %%attack_result,0 if %attp > %dftp mov %%attack_result,1 return ; ダメージ量の計算用サブルーチン *damage ; 本来は、攻撃側の筋力や防御側の防具などを想定した計算式がここに入るが、今回のルールではどんな条件でも一律2点と決まっている。 ; なので引数を取るがそれとは関係なく2を返す。 getparam i%damage_result,%attacker,%defender mov %%damage_result,2 return *battle getparam i%battle_result ; 戦闘の結果を格納する数値変数の番号を取得。 ; 初期設定 ; 生きてる連中は全部いる for %character=0 to max_character if ?is_use[%character]=0 goto *battle_pre_loop mov ?is_live[%character],1 mov ?is_there[%character],1 *battle_pre_loop next mov %character,-1 ; ループ開始 *battle_loop2 ; 終了チェック ; 終了条件は、どちらかの陣営の全員が、死亡ないし不在の時。 for %character_temp=0 to max_character ; 陣営ループ mov %side_num,0 mov %side_there,0 for %character_loop=0 to max_character ; キャラクターループ if ?is_use[%character_loop]=0 break notif ?side[%character_loop]=%character_temp goto *battle_end_check_loop inc %side_num if ?is_live[%character_loop]=0 inc %side_there:goto *battle_end_check_loop if ?is_there[%character_loop]=0 inc %side_there:goto *battle_end_check_loop *battle_end_check_loop next if %side_num=0 break notif %side_num=%side_there goto *battle_end_check_loop2 mov %battle_end,1:break *battle_end_check_loop2 next notif %battle_end=0 return *battle_loop inc %character ; 行動するキャラクター番号を増やす。 if %character > max_character mov %character,0 ; もし、キャラクター番号が最大キャラクター数をこえたならば、0に戻す。 if ?is_use[%character]=0 goto *battle_loop ; 使ってないキャラクター番号なら飛ばす。 if ?is_there[%character]=0 goto *battle_loop ; 戦場からいないキャラクター番号なら飛ばす。 if ?is_live[%character]=0 goto *battle_loop ; 死亡しているキャラクター番号なら飛ばす。 d1 %speed:mov ?speed[%character],?speed[%character]+%speed ; スピードゲージを増やす。 if ?speed[%character]<100 goto *battle_loop ; スピードゲージが100以下なら、飛ばす。 ; ここにお好みでスピードゲージの表示処理を入れる。 mov ?speed[%character],?speed[%character]-100 get_name $0,%character textclear print_character %character ; 攻撃可能な敵のリストアップ for %character_loop=0 to max_character mov ?targetable_character[%character_loop],-1 next mov %targetable_character,-1 for %character_loop=0 to max_character if ?is_use[%character_loop]=0 goto *battle_next ; 未使用キャラは攻撃不可能 if ?side[%character_loop]=?side[%character] goto *battle_next ; 同じ陣営は攻撃不可能 if ?is_live[%character_loop]=0 goto *battle_next ; 死亡キャラは攻撃不可能 if ?is_there[%character_loop]=0 goto *battle_next ; 非在キャラは攻撃不可能 ; 上記のフィルターをくぐりぬけたキャラクターは攻撃対象にできる。 inc %targetable_character mov ?targetable_character[%targetable_character],%character_loop ; リストに記載 *battle_next next ; 行動の選択。 ; プレイヤーキャラクターならばプレイヤーが選択。 ; そうでなければ、ランダムターゲット攻撃を選択。 if ?side[%character]=0 goto *battle_select_action rnd2 %target,0,%targetable_character ; 攻撃対象の選択 mov %target,?targetable_character[%target] goto *battle_attack *battle_select_action selnum %20,"こうげき","とうそう" if %20=0 goto *battle_select_target $0はとうそうを試みた。 luck %20,%character if %20=1 goto *battle_runaway しかし、まわりこまれてしまった!@ goto *battle_loop *battle_runaway $0は逃げ出した!@ mov ?is_there[%character],0 goto *battle_loop2 *battle_select_target textclear for %character_loop=0 to max_character mov %character_temp,%character_loop+10 get_name $%character_temp,?targetable_character[%character_loop] next if %targetable_character=1 selnum %target,$10 if %targetable_character=2 selnum %target,$10,$11 if %targetable_character=3 selnum %target,$10,$11,$12 if %targetable_character=4 selnum %target,$10,$11,$12,$13 if %targetable_character=5 selnum %target,$10,$11,$12,$13,$14 if %targetable_character=6 selnum %target,$10,$11,$12,$13,$14,$15 if %targetable_character=7 selnum %target,$10,$11,$12,$13,$14,$15,$16 mov %target,?targetable_character[%target] *battle_attack get_name $1,%target $0は$1を攻撃した!@ print_character %target attack %20,%character,%target if %20=0 puttext "しかし、失敗してしまった!@":goto *battle_loop damage %20,%character,%target %20のダメージを与えた!@ mov ?hp[%target],?hp[%target]-%20 if ?hp[%target]>0 goto *battle_loop $1は死んだ!@ mov ?is_live[%target],0 goto *battle_loop2 *get_name getparam s%get_name_result,%get_name_character mov $%get_name_result,"(名称不明)" if %get_name_character<0 return if %get_name_character>max_character return if ?name[%get_name_character]=0 mov $%get_name_result,"ファファード" if ?name[%get_name_character]=1 mov $%get_name_result,"グレイマウザー" if ?name[%get_name_character]=2 mov $%get_name_result,"ゴブリン" if ?volume[%get_name_character]=0 return itoa2 $get_name_character,?volume[%get_name_character] add $%get_name_result,$get_name_character return *print_character getparam %print_character_num get_name $print_character_num,%print_character_num $print_character_num 技術点:?tp[%print_character_num] 体力点:?hp[%print_character_num] 運命点:?dp[%print_character_num] return *start ; 初期設定 ; ファファードとグレイマウザーを設定する。 ; 便宜上、ファファードのキャラクター番号を0、グレイマウザーのキャラクター番号を1とする。 for %0=0 to 1 ; ファファードとグレイマウザーの分、同じことを二回繰り返す。 d2 %hp:add %hp,12:mov ?hp[%0],%hp ; 体力点の設定 d1 %tp:add %tp,6:mov ?tp[%0],%tp ; 技術点の設定 d1 %dp:add %dp,6:mov ?dp[%0],%dp ; 運命点の設定 mov ?is_use[%0],1 ; 使用フラグを立てる。 mov ?is_live[%0],1 ; 健在フラグを立てる。 mov ?is_there[%0],1 ; 存在フラグを立てる。 mov ?side[%0],0 ; 陣営を0番陣営に設定する。 next ; for に戻る。 mov ?name[0],0 ; キャラクター名を「ファファード」を意味する0番に設定する。 mov ?volume[0],0 ; 番号はない。 mov ?name[1],1 ; キャラクター名を「グレイマウザー」を意味する1番に設定する。 mov ?volume[1],0 ; 番号はない。 ; とりあえずぶつける敵を設定する。 ; ゴブリン(技術点5・体力点5)を2-7匹程度。 d1 %10:inc %10 ; ゴブリンの数を%10に格納。 for %0=2 to 2+%10 ; ゴブリンの数だけキャラクターを初期化 mov ?hp[%0],5 ; 体力点の設定 mov ?tp[%0],5 ; 技術点の設定 mov ?dp[%0],0 ; 運命点の設定 mov ?is_use[%0],1 ; 使用フラグを立てる。 mov ?is_live[%0],1 ; 健在フラグを立てる。 mov ?is_there[%0],1 ; 存在フラグを立てる。 mov ?side[%0],1 ; 陣営を1番陣営(敵)に設定する。 mov ?name[%0],2 ; キャラクター名を「ゴブリン」を意味する2番に設定する。 mov ?volume[%0],%0-1 ; 量産型なので番号を設定する。 next for %0=3+%10 to max_character ; 使わないキャラクターの入れ物を使用不可にする。 mov ?is_use[%0],0 ; 使用フラグを折る。 next ; 敵と味方の設定ができたので、戦闘を開始する。 battle %25 ; 戦闘
一応動く。書きかけ。戦闘の終了条件は検出できるが、どういう条件で終わったかをチェックできないようになっている。