2017年 12月9日
今回もそれなりに大変だった。
隊列の処理が意外とややこしい。
それと召還のユニットデータとステータスデータをどうするか、というのもある。
では召還から。
まず召還したユニットのユニット No.を控えておく変数を作る。
dim smnfn,6
召還されるのは隊列最大の 6を超えないはずなので配列は 6でよい(召還されたものが召還を使うのでもなければ最大は 4)
戦闘ステータス bsは、死んだユニットの場所を使うので変更無し。
ではソースを
#deffunc smon int smonf ; 召還 c=0 repeat 3,1 if fs=1 : un2=fn1(fs1+cnt) if fs=2 : un2=fn2(fs2+cnt) if un2!0 and ud(un2*udb+26)>0 : c+ loop if c=3 : return ; 隊列がいっぱい f=0 repeat ub-1,1 ; 空きユニットNo.ピック un2=cnt : ug2=un2*udb ; ユニットNo. if ud(ug2)=0 : f=1 : break loop if f=0 : return ; ユニットいっぱい if smonf=1 : cn=136 ; ゴーレム if smonf=2 : cn=169 ; ウィスプ if smonf=3 { r=rnd(3) if r=0 : cn=184 ; ゾンビ if r=1 : cn=185 ; グール if r=2 : cn=186 ; スケルトン } if smonf=4{ r=rnd(3) if r=0 : cn=187 ; インプ if r=1 : cn=196 ; デビル if r=2 : cn=200 ; デーモン } repeat udb ud(ug2+cnt)=0 ; データクリア loop ud(ug2)=cn ; cnキャラ種類 repeat 9,1 ud(ug2+cnt)=cd(cnt,cn) ; データ loop repeat 5 ud(ug2+21+cnt)=ud(ug2+1+cnt) ; ステータスデータ loop ud(ug2+26)=ud(ug2+25) ; HP repeat 2 : ud(ug2+11+cnt)=ud(ug2+21) : loop ; 攻防値 repeat 3 ; 空き戦闘ステータスにセット if fs=1 : bsg=cnt*bsb if fs=2 : bsg=(cnt+3)*bsb if bs(bsg)=0 : bs(bsg)=un2 : break loop if fs=1 { ; 隊列にセット n=ftp(fs,un) ; 召還者の隊列 switch n case 1 smn=1 if fn1(fs1+2)>0 and ud(fn1(fs1+2)*udb+26)>0 : fn1(fs1+3)=fn1(fs1+2) ; 真ん中に誰かいる fn1(fs1+2)=fn1(fs1+1) ; 一つ後ろへ詰める swbreak case 2 if fn1(fs1+1)=0 or ud(fn1(fs1+1)*udb+26)<=0 : smn=1 : swbreak ; 先頭が開いてる fn1(fs1+3)=fn1(fs1+2) : smn=2 ; 一つ後ろへ詰める swbreak case 3 smn=2 if fn1(fs1+2)=0 or ud(fn1(fs1+2)*udb+26)<=0 : swbreak ; 真ん中が開いてる場合 fn1(fs1+1)=fn1(fs1+2) : fn1(fs1+2)=0 ; 一つ前へ詰める swbreak swend fn1(fs1+smn)=un2 ; 召還 } if fs=2 { n=ftp(fs,un) ; 召還者の隊列 switch n case 1 smn=1 if fn2(fs2+2)>0 and ud(fn2(fs2+2)*udb+26)>0 : fn2(fs2+3)=fn2(fs2+2) ; 真ん中に誰かいる fn2(fs2+2)=fn2(fs2+1) ; 一つ後ろへ詰める swbreak case 2 if fn2(fs2+1)=0 or ud(fn2(fs2+1)*udb+26)<=0 : smn=1 : swbreak ; 先頭が開いてる fn2(fs2+3)=fn2(fs2+2) : smn=2 ; 一つ後ろへ詰める swbreak case 3 smn=2 if fn2(fs2+2)=0 or ud(fn2(fs2+2)*udb+26)<=0 : swbreak ; 真ん中が開いてる場合 fn2(fs2+1)=fn2(fs2+2) : fn2(fs2+2)=0 ; 一つ前へ詰める swbreak swend fn2(fs2+smn)=un2 ; 召還 } repeat 6 if smnfn(cnt)=0 : smnfn(cnt)=un2 : break; 召還un格納 loop return
まず当然ながら隊列がいっぱいの場合は召還しない。
ユニットデータは一般のデータ udの空きをそのまま使う。
そうしないと戦闘プログラムで運用できない。
その部隊の戦闘が終わったら smnfnに控えておいたユニットのデータを消す。
ソースの隊列にセットの部分で、召還者の位置を元に隊列を詰めて召還する場所を確定する。
意外とややこしいのが分かると思う。
ではテスト
光の召還、ウィル・オ・ウィスプ
召還者の前に召還される。
下の緑の表示でデバッグ確認用の smnfnを書いてる。
召還されたユニットNO.は 113だが、これはマップ全部でユニットが 112作成されてるから。
部隊が埋まるまで(といっても最大 2体という事だが)召還される。
闇の召還、デモンズゲート(悪魔召還)
3種の内ランダムで召還される。
と、いう訳で次はリザレクション(蘇生)
これの隊列処理が大変だった。
蘇生位置の隊列の変更と、召還されたものの場合は潰さないといけない、どれを詰めてどれを潰すか?
共通の法則は無いか、紙数枚に書いて丸一日思考錯誤していたが、自分にはどうにも法則は分からなかった。
結局蘇生される者の元の隊列の位置を格納しておいて参照し、その場所と現在の隊列のユニット数を元に「ベタ処理」する事にした。
dim sfn,7 ; 初期隊列un格納
dim rfn,4 ; 蘇生候補と蘇生処理時の隊列
ではソースを
#deffunc resur ; リザレクション repeat 3 : rfn(cnt)=0 : loop ; クリア if fs=1 : sfg=0 if fs=2 : sfg=3 c=0 repeat 3,1 ; 死亡者ピック rn=sfn(sfg+cnt) : if rn=0 : continue if ud(rn*udb+26)<=0 : rfn(c)=rn : c+ loop if c=0 : return ; 死亡者がいない r=rnd(c) : rn=rfn(r) ; 蘇生者選択 repeat 3,1 ; 元の隊列場所 if rn=sfn(sfg+cnt) : rt=cnt : break loop repeat 4 : rfn(cnt)=0 : loop ; rfnリセット repeat 3,1 ; 処理用隊列変数に格納 if fs=1 : un2=fn1(fs1+cnt) if fs=2 : un2=fn2(fs2+cnt) ug2=un2*udb if ud(ug2+26)>0 : rfn(cnt)=un2 loop taif=0 repeat 3,1 ; 隊列いくつ埋まっているか n=rfn(cnt) if n>0 and ud(n*udb+26)>0 : taif+ loop repeat 1 ; 隊列が3つ埋まってる場合 ---------------------------- if taif!3 : break ; 3つじゃない en1=smf(rfn(1)) : en2=smf(rfn(2)) : en3=smf(rfn(3)) ; 召還か switch rt case 1 ; 蘇生される者が1列目 ------------------------- if en1>0 : d_syo en1 : rfn(1)=rn : rsr_syo rn : swbreak ; 隊列1が召還の場合 if en2>0 and en3=0 { ; 隊列2だけ召還の場合 d_syo en2 ; 隊列2の召還を消す rfn(2)=rfn(1) : rfn(1)=rn : rsr_syo rn ; 入れ替え swbreak } if en3>0 { ; 隊列3が召還の場合 d_syo en3 ; 隊列3の召還を消す rfn(3)=rfn(2) : rfn(2)=rfn(1) : rfn(1)=rn : rsr_syo rn ; 入れ替え swbreak } swbreak case 2 ; 蘇生される者が2列目 ------------------------- ; 例外1 if rfn(3)=sfn(sfg+1) { ; 隊列3に1が入ってる en1=smf(rfn(1)) : if en1>0 : d_syo en1 ; 1の召還を削除 rfn(1)=rfn(2) : rfn(2)=rfn(3) : rfn(3)=rn : rsr_syo rn ; 入れ替え swbreak } if rfn(1)=sfn(sfg+3) { ; 隊列1に3が入ってる en3=smf(rfn(3)) : if en3>0 : d_syo en3 ; 3の召還を削除 rfn(3)=rfn(2) : rfn(2)=rfn(1) : rfn(1)=rn : rsr_syo rn ; 入れ替え swbreak } ; 例外2 if rfn(2)=sfn(sfg+1) { ; 隊列2に1が入ってる en1=smf(rfn(1)) : if en1>0 : d_syo en1 ; 1の召還を削除 rfn(1)=rfn(2) : rfn(2)=rn : rsr_syo rn ; 入れ替え swbreak } if rfn(2)=sfn(sfg+3) { ; 隊列2に3が入ってる en3=smf(rfn(3)) : if en3>0 : d_syo en3 ; 3の召還を削除 rfn(3)=rfn(2) : rfn(2)=rn : rsr_syo rn ; 入れ替え swbreak } ; その他 if en2>0 : d_syo en2 : rfn(2)=rn : rsr_syo rn ; 隊列2は召還 swbreak case 3 ; 蘇生される者が3列目 ------------------------- if en2>0 and en1=0 { ; 隊列2だけ召還の場合 d_syo en2 : rfn(2)=rfn(3) : rfn(3)=rn : rsr_syo rn ; 入れ替え swbreak } ; その他 if en1>0 { ; 隊列1、2が召還の場合 d_syo en1 ; 隊列1の召還は消す rfn(1)=rfn(2) : rfn(2)=rfn(3) : rfn(3)=rn : rsr_syo rn ; 入れ替え } swbreak swend loop dgs "en1 ",en1,15 dgs "en2 ",en2,16 dgs "en3 ",en3,17 bpk repeat 1 ; 隊列が2つ埋まってる場合 ---------------------------- if taif!2 : break ; 2つじゃない if rt=1 { ; 蘇生される者が1列目 ------------------------- if rfn(1)=0 : rfn(1)=rn : rsr_syo rn : break ; 隊列1が空 if rfn(2)=0 : rfn(2)=rfn(1) : rfn(1)=rn : rsr_syo rn : break ; 隊列2が空 rfn(3)=rfn(2) : rfn(2)=rfn(1) : rfn(1)=rn : rsr_syo rn : break ; 隊列3が空 } if rt=2 { ; 蘇生される者が2列目 ------------------------- ; 例外1 if rfn(3)>0 and rfn(3)=sfn(sfg+1) { ; 隊列3に1が入ってる if rfn(2)=0 : rfn(2)=rfn(3) : rfn(3)=rn : rsr_syo rn : break ; 隊列2が空 rfn(1)=rfn(2) : rfn(2)=rfn(3) : rfn(3)=rn : rsr_syo rn : break ; その他 } if rfn(1)>0 and rfn(1)=sfn(sfg+3) { ; 隊列1に3が入ってる if rfn(2)=0 : rfn(2)=rfn(1) : rfn(1)=rn : rsr_syo rn : break ; 隊列2が空 rfn(3)=rfn(2) : rfn(2)=rfn(1) : rfn(1)=rn : rsr_syo rn : break ; その他 } ; 例外2 if rfn(2)>0 and rfn(2)=sfn(sfg+1) { ; 隊列2に1が入ってる if rfn(3)=0 : rfn(3)=rn : rsr_syo rn : break ; 隊列3が空いてる rfn(1)=rfn(2) : rfn(2)=rn : rsr_syo rn ; 入れ替え break } if rfn(2)>0 and rfn(2)=sfn(sfg+3) { ; 隊列2に3が入ってる if rfn(1)=0 : rfn(1)=rn : rsr_syo rn : break ; 隊列1が空いてる rfn(3)=rfn(2) : rfn(2)=rn : rsr_syo rn ; 入れ替え break } ; その他 if rfn(1)=0 : rfn(1)=rfn(2) : rfn(2)=rn : rsr_syo rn : break ; 隊列1が空いてる if rfn(3)=0 : rfn(3)=rfn(2) : rfn(2)=rn : rsr_syo rn : break ; 隊列3が空いてる } if rt=3 { ; 蘇生される者が3列目 ------------------------- if rfn(3)=0 : rfn(3)=rn : rsr_syo rn : break ; 隊列1が空 if rfn(2)=0 : rfn(2)=rfn(3) : rfn(3)=rn : rsr_syo rn : break ; 隊列2が空 rfn(1)=rfn(2) : rfn(2)=rfn(3) : rfn(3)=rn : rsr_syo rn : break ; 隊列3が空 } loop repeat 1 ; 隊列が1つ埋まってる場合 ---------------------------- if taif!1 : break ; 1つじゃない if rt=1 { ; 蘇生される者が1列目 ------------------------- if rfn(1)=0 : rfn(1)=rn : rsr_syo rn : break ; 隊列1が空 if rfn(2)=0 : rfn(2)=rfn(1) : rfn(1)=rn : rsr_syo rn : break ; 隊列2が空 } if rt=2 { ; 蘇生される者が2列目 ------------------------- ; 例外1 if rfn(3)>0 and rfn(3)=sfn(sfg+1) { ; 隊列3に1が入ってる rfn(2)=rfn(3) : rfn(3)=rn : rsr_syo rn : break ; 隊列2が空 } if rfn(1)>0 and rfn(1)=sfn(sfg+3) { ; 隊列1に3が入ってる rfn(2)=rfn(1) : rfn(1)=rn : rsr_syo rn : break ; 隊列2が空 } ; 例外2 if rfn(2)>0 and rfn(2)=sfn(sfg+1) { ; 隊列2に1が入ってる rfn(1)=rfn(2) : rfn(2)=rn : rsr_syo rn : break ; 入れ替え } if rfn(2)>0 and rfn(2)=sfn(sfg+3) { ; 隊列2に3が入ってる if rfn(1)=0 : rfn(1)=rn : rsr_syo rn : break ; 入れ替え } ; その他 if rfn(2)=0 : rfn(2)=rn : rsr_syo rn : break ; 隊列2が空 if rfn(2)>0 : rfn(1)=rfn(2) ; 隊列2に召還がいる rfn(2)=rn : rsr_syo rn : break ; 入れ替え } if rt=3 { ; 蘇生される者が3列目 ------------------------- if rfn(3)=0 : rfn(3)=rn : rsr_syo rn : break ; 隊列3が空 if rfn(2)=0 : rfn(2)=rfn(3) : rfn(3)=rn : rsr_syo rn : break ; 隊列2が空 } loop repeat 3,1 ; 隊列格納 if fs=1 : fn1(fs1+cnt)=rfn(cnt) if fs=2 : fn2(fs2+cnt)=rfn(cnt) loop return
隊列の処理だけでこれだけのソースになると言う事から、いかに意外とややこしいか分かってもらえるだろう。
だからたぶん素質のあるプログラマーなら共通法則を導き出して簡素化するんだろうと思うが、自分はペーペーなのでそんなのサッパリ分からない。
まず元の隊列を格納してある変数 sfnを元に死者がいるかどうか調べ、2名死んでる場合はどちらかランダムで選ぶ。
次に同 sfnを参照して元のユニットが隊列の何番目だったかを確認する。
あ、そうそう smfというのは、そのユニットが召還かどうか調べる関数(自作命令)です。
隊列の変更はまず現在の隊列が何人いるかで処理を変える。
3人全部埋まってる場合に、召還ユニットがあれば潰す事になる。
分岐した処理それぞれで、復帰する隊列事に「ベタ処理」を敢行する。
特別なのは 2列目の処理で、2列目に 1や 3が入っていると、詰め方が特殊になる。
処理前に rfnに隊列を格納してから処理し、その後に現在の隊列 fn1、fn2に格納しなおす。
こうする事で処理ソースを一つにしている。
少し図を描こうかと思ったけど、どうにもめんどくさいので止めた。
という訳で説明はこれくらいにして後はソースで理解してもらうとして(無茶だけど)テストする。
召還とリザをセットする。
先頭がやられた
1個詰めて、召還者の前に召還をセット
その後から召還を潰してリザ
先頭が2名やられている状態で召還
そしてリザ、この場合 1列目が蘇生された模様。
と、いうような感じです。
これにて魔法は今の所コンプリートになりました。
たぶんバグてんこもりだと思うけど、追々潰していこう。
次はどうするかな?
戻ってユニットの特殊能力を整備するかな。
ではまた。