2014/12/17
■ [変愚蛮怒/スポイラー]generate_hmap()関数及びgenerate_fracave()関数による洞窟生成@変愚(前編)
本記事はRoguelike Advent Calendar 2014の17日目として作成しました。
はじめに
2014年12月現在の変愚蛮怒において、部屋生成は16種類(リンク先は旧15種類)に分けられて処理されている。(16番目の街生成は別途リンク)
その中でも特に処理が複雑なのがbuild_type9()関数による「fracave」生成処理である。名前の通り'plasma fractal'っぽいなにかで自然の洞穴のような形状を作り出すこの処置は、正直追うのがシャレにならんほど面倒くさく、アルゴリズムの解説も英文で数十行に渡り淡々と描かれている。
しかし折角のアドベンドカレンダー企画であるし、これを機に追ってみることで後学に役立てようと思う。
build_type9()の処理は大別して3種の流れで構成されている。
- 部屋生成範囲と初期定数値の決定
- generate_hmap()による範囲内の「閾値」算出
- generate_fracave()による地形IDの決定
今回全編はこのうちの上二つについて、単純にソースコードの流れのみを追ってみた。
grad値、roug値、cutoff値の決定
- grad値を1,2,4,8いずれかの値に等確率に指定。
- roug値を1d8×1d4に設定。
- cutoff値を2d(部屋のXサイズ/4)+2d(部屋のYサイズ/4)に指定
- 部屋の中心座標(x0, y0)、サイズ(xsize, ysize)、grad値、roug値、cutoff値を引数にgenerate_hmap()関数をコールする
fill_data_type構造体の定義
generate_hmap()及びgenerate_fracave()関数はそれぞれroom.c内にstaticに宣言された fill_data_type構造体にアクセスして、情報を供給し合っている。要素は以下の通り
/* area size */ int xmin; int ymin; int xmax; int ymax; /* cutoffs */ int c1; int c2; int c3; /* features to fill with */ int feat1; int feat2; int feat3; int info1; int info2; int info3; /* number of filled squares */ int amount;
generate_hmap()関数の処理
- 部屋のサイズはX,Y共に4以上、254以下に修正する(Paranoiaな行為、らしい)
- xsize/2, ysize/2 をxhsizeとyhsizeに代入
- xhsize*2, yhsize*2 をxsizeとysizeに代入して端数切り上げの偶数値にする
- fill_data.xmin, fill_data.ymin, fill_data.ymin, fill_data.ymax を x0, y0からxsize, yhsizeの加減算で指定して、処理範囲を決める
- fill_data.c1にcutoff値を代入
- diagsize値に362を代入(≒sqrt(2)*256を意識とのこと)
- maxsize値を処理範囲のX,Yサイズどちらか大きい方に指定。
- 範囲内のfill_dataで定められた座標範囲のfeat値を-1、CAVE_ICKYフラグをFALSEにする形で初期化する。
- 四隅のfeat値にmaxsize値を代入,中央のfeat値に0を代入。
- xstep, xhstep, xxsize値に xsize*256、ystep, yhstep, yysize値に ysize*256を代入(256倍のゲタをはかせて二進数小数点値を8桁まで確保している)
- xhstep, yhstepどちらかの値が256より大きい間以下の処理を繰り返す
- xstep, ystepにxhstep, yhstepを代入
- xhstep /= 2, yhstep /= 2
- xstep2, ystep2, xhstep2, yhstep2にそれぞれ xstep, ystep, xhstep, yhstepを/256した値を代入する(はかせたゲタを解除した値をダンジョンの座標に用いる)
- xstepからxxsize-xhstepの間をxstep刻みで(i)、ystepからyysizeの間をystep刻みで(j)として以下の処理を繰り返す。
- ii=i / 256 + fill_data.xmin、jj=j / 256 + fill_data.yminとする
- ii,jjのfeat値が-1ならば(まだfeat値を代入していないならば)以下のように値を入れる。
- xhstep2がgrd以下ならば1d(maxsize)を代入する。
- さもなくば左右のマスの値の平均値+(1d(ystep2) - yhstep2) * roug / 16)を代入する。
- これらの代入値はfill_data.xmin, fill_data.xmax, fill_data.ymin, fill_data.xmax,と同値でなおかつfill_data.c1より小さいならば、fill_data.c1+1に上書きされる。
- ystepからyysize-yhstepの間をystep刻みで(j)、xstepからxxsizeの間をxstep刻みで(i)として以下の処理を繰り返す。
- ii=i / 256 + fill_data.xmin、jj=j / 256 + fill_data.yminとする
- ii,jjのfeat値が-1ならば(まだfeat値を代入していないならば)以下のように値を入れる。
- xhstep2がgrd以下ならば1d(maxsize)を代入する。
- さもなくば上下のマスの値の平均値+(1d(ystep2) - yhstep2) * roug / 16)を代入する。
- これらの代入値はfill_data.xmin, fill_data.xmax, fill_data.ymin, fill_data.xmax,と同値でなおかつfill_data.c1より小さいならば、fill_data.c1+1に上書きされる。
- xstepからxxsize-xhstepの間をxstep刻みで(i)、ystepからyysize-yhstepの間をystep刻みで(j)として以下の処理を繰り返す。
- ii=i / 256 + fill_data.xmin、jj=j / 256 + fill_data.yminとする
- ii,jjのfeat値が-1ならば(まだfeat値を代入していないならば)以下のように値を入れる。
- xhstep2がgrd以下ならば1d(maxsize)を代入する。
- さもなくば上下左右のマスの値の平均値+(1d(xstep2) - xhstep2) * (diagsize / 16) / 256 * roug)を代入する。
- これらの代入値はfill_data.xmin, fill_data.xmax, fill_data.ymin, fill_data.xmax,と同値でなおかつfill_data.c1より小さいならば、fill_data.c1+1に上書きされる。
閑話
全く訳の分からない有様だと思う。筆者自身限られた時間で何となくイメージがつきかけているものの、やはり実際にデバッグトレース機能を通じて閾値が埋まっていかないと具体的には答えきれない。 次回以降で残りのgenerate_fracave()の処理の流れと処理の具体例を図解で細かく解説できればと思う。
すいません許して下さい!何でもはしませんから!
■ [ヴィーヤウトゥムノ] ショゴス/Shoggoth (L.Dark 'j')
=== Num:685 Lev:44 Rar:2 Spd:+30 Hp:1000 Ac:80 Exp:2500 「古のもの」によって創造された、黒くネバネバした巨大な多細胞の原形質。不 定形であり、いかなる器官も自由に作り出すことができる。「テケリ・リ」とい う独特の鳴き声をあげる。水陸両棲の、無愛想で不機嫌な召し使い。もともと知 性は低かったが、次第に主人である「古のもの」を模倣するようになり、反抗し て滅ぼした。「悪臭放つ虹色に輝く悪夢じみた可塑性のある柱が... 原形質の泡 の無定形の塊が、自らかすかに輝き、わたくしたちに向かいあう、トンネルを満 たす前部のいたることろに、緑がかった光を放つ疣のような何万もの一時的な眼 を構成したり消したりしながら、あわてふためくペンギンたちを押しつぶし、同 類とともに邪悪にもすべてをとりさったなめらかな床をずるずるすべってきたの だった。なおも不気味な嘲笑うような声「テケリ・リ!テケリ・リ!」が聞こ え...」(H・P・ラヴクラフト、大瀧啓裕訳「恐怖の山脈にて」『ラヴクラフト 全集4』、創元推理文庫、pp.300-301) それは通常地下 44 階で出現し、信じ難いほど素早く動いている。この狂気を誘 う邪悪なるデーモンを倒すことは 1 レベルのキャラクタにとって 約36666.67 ポ イントの経験となる。それは AC80 の防御力と 1000 の体力がある。それはドア を打ち破り、水を渡り、弱いモンスターを倒し、アイテムを壊すことができる。 それは素早く体力を回復する。それには明るい光でダメージを与えられる。それ は酸と稲妻と炎と冷気と毒と暗黒とプラズマとテレポートの耐性を持っている。 それは進化しない。それは恐怖を感じないし、混乱しないし、眠らされない。そ れは侵入者をしばらくは見ており、 1000 フィート先から侵入者に気付くことが ある。それは 5d6 のダメージで体当たりして酸を飛ばし、 5d6 のダメージで体 当たりして酸を飛ばし、 5d6 のダメージで体当たりして酸を飛ばし、 9d9 のダ メージで体当たりして攻撃する。
鬼畜大佐『ロムンクァリィ』
究 極 汚 物(クソ加速+クソ打撃)
アッキ=ニンジャ『ウルウェン』
訴 訟 不 可 避(クソHP+クソ耐性)