実装に際して、適宜他テーブルの解説・導入を行っていく予定です。
最終的にはMODとして出せる程度にまで作り込みますが、
段階的に機能を実装して、その見え方と問題点を順に確認していきます。
前回はhexに商品と売買を行う"機能"を実装しましたが、
今回は主に"外見"に該当する部分を作り込みます。
(2015/10/17追記)
※本稿はVer1.1より前の時点で記述したものです。
現在、以降のデータはneogame.xmlから各テーブルごとのxmlに分割されていますので、
特に記載がない限り、データは各テーブルと同名のxmlを参照してください。
今回の目標
前回ラストで提示した目標は、
・このキャンプをランダム配置ではないHexとして設定する
・キャンプをもう少し店らしく見せる工夫をする
ですが、MOD的にはどこを弄る必要があるか、先にまとめておきます。
Hexを特定のものとして設定するには、
・Hexのグラフィックを用意する
・"hextypes"テーブルでHexを設定する
・"maps"テーブルにHexの位置を書き込む
この3つが必要になります。
キャンプを店らしく見せる(厳密には"店"ではありませんが)には、
進入時にイベントを発生させて、
そこで売買が出来ることを通知すれば十分だと判断しました。
では、次項より順に確認・解説を交えつつ実装します。
Hexのグラフィックを追加する
Hexのグラフィックですが、後述の"hextypes"テーブルの仕様から
"新規Hexに既存のグラフィックをそのまま流用する"ことは出来なさそうです。
さらに、Hexのグラフィックは単体ではなく、
1枚の画像に全Hexのグラフィックが並べて描かれています。
さらに、時間帯によって
HexSheetSummerDay.png
HexSheetSummerDusk.png
HexSheetSummerMorning.png
HexSheetSummerNight.png
の4枚の画像が必要になるため、
それぞれに追加グラフィックを用意する必要があります。
画像には、奇数行に通常のHex画像、
偶数行にコントラスト低めのHexが描かれています。
この2つを、視界内/視界外で描き分けるために使っているようです。
このHex一覧画像と"hextypes"テーブルを見比べた結果、
左上がid1番、次が2番…と順に定義されているようです。
そこで、今回は38番(最後から2番目)に設定して使うことにしました。
適当にそれらしい情景を別画像として作成し、
左の草原Hexをコピーした上から貼り付けて使っています。
40番以降を設定する場合、
そのまま列を追加して使えるかどうかは分かりません。
とりあえず、1つ2つなら末尾の空きを使えば問題なさそうです。
"hextypes"テーブルの設定
"hextypes"テーブルは、各Hexの情報を記録しています。
細かい設定内容は省きますが、今回は見た目を弄りたいだけなので
基本的には画像に合わせたidを取得すれば問題ありません。
あと気を使うべき点は、nTerrainCostやvLightLevelsあたりでしょうか?
実際のデータは以下のように設定しました。
<table name="hextypes">基本的には見た目さえ変わればいい、という前提ですので
<column name="id">38</column>
<column name="strName">Hunter's Camp</column>
<column name="strDesc">Hunter's Camp</column>
<column name="nTerrainCost">1</column>
<column name="nVizLimiter">0</column>
<column name="nVizIncrease">0</column>
<column name="nTreasureID">3</column>
<column name="bPassable">1</column>
<column name="nScavengeInitialID">3</column>
<column name="nScavengeItemsIDPerHour">3</column>
<column name="nCampItems">5</column>
<column name="vLightLevels">0.8,1.0,1.0,1.0,0.8,0.8</column>
<column name="nDefaultCampID">517</column>
<column name="nMinRange">3</column>
<column name="nMaxRange">5</column>
<column name="vCondIDs"></column>
</table>
特に変わったことはしていません。
次は、このHexを実際にマップに配置します。
"maps"テーブルを書き換える
"maps"テーブルには、マップの全hexが配列(数字の羅列)で書かれています。
この中で、前回決めたキャンプの位置に38番のhexを配置します。
実際に使用されているマップは、idが"2"の"maps"テーブルです。
今回はこれを上書きして使用することになります。
(id1のテーブルはテスト用に作ったマップのようです)
ここで重要なのは、ここに記述する数値は"hextypes"テーブルのidではなく、
そのidから1を引いた数値、つまり今回は"37"と記述する必要があります。
今回はCryoを起点とするため、そのidも変わることを意識して書き換えます。
Cryoに割り当てられたidは"9"なので、
テーブル内で"8"と書かれた部分を探します。
3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3上下左右をかなり省略していますが、Cryo周辺は大体このような構成になっています。
3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3
3,3,3,3,3,3,3,3,3,3,36,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3
3,3,3,3,30,3,3,3,3,4,36,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3
3,3,3,3,3,3,3,3,3,3,8,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3
3,3,3,3,3,3,3,3,3,7,36,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3
3,3,3,3,3,3,3,3,3,3,4,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3
3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3
1桁と2桁のidが混在しているため、記述する場所がズレないようによく確認しましょう。
赤い8がCryoの位置、オレンジの3がキャンプを配置したHexの座標です。
さっそくこれを"(Mod定義名):37"に書き変えてテストしてみます。
…あれ?
というわけで、該当Hexが"deep water"(id=1のhex)になっています。
マップの変更と書き換えたhex画像は既存の上書き("0"フォルダ)なので、
マップからhexの画像が読み込めない、ということは無さそうです。
現在、"hextypes"テーブルはMODフォルダ側に記述していますが、
"maps"("0"フォルダ)→"hextypes"(MODフォルダ)→hex画像("0"フォルダ)
という呼び出しの流れのどこかに不都合があるのかもしれません。
ここで数日色々と試していたのですが、
最後に"hextypes"を"0"フォルダ側xmlに記述してやると…
(同時に"maps"テーブルの表記もただの"37"に変更しています)
出来た!(かなり見づらいですが)
というわけで、今回もなんとなくで問題解決、デバッグ終了となりました。
ちなみに、全部MODフォルダ側で記述した場合は
やっぱり"deep water"のままだった気がします。
進入時のイベントを作成する
これで指定したhexにキャンプがある、と言うことは分かるようになりましたが
そこで売買が出来ることをプレイヤーに知らせるため、
"encounters"テーブルを追加してイベントを発生させます。
encounter本体の内容はこんな感じにしてみました。
(文章には適当に改行を入れてあります)
<table name="encounters">単発使い捨てのイベントなので、特に設定すべき項目は多くありません。
<column name="id">9999</column>
<column name="strName">Hunter's Camp</column>
<column name="strDesc">
Near the Cryo, you found a thin pillar of smoke
at middle of plains.
Maybe there's a trap, but... at least that filthy beast
isn't there, so you approaches.
And... you found a small camp of a old hunter.
He offers log seat by the fire for free,
but any other thing costs some money.</column>
<column name="strImg">EncHunterCamp.png</column>
<column name="nTreasureID">0:3</column>
<column name="nRemoveTreasureID">0:3</column>
<column name="aConditions">0:1</column>
<column name="aPreConditions"></column>
<column name="fPrice">0</column>
<column name="aResponses">=0:1x1x0x0x0</column>
<column name="aMinimapHexes">22x162=Hunter's Camp</column>
<column name="bRemoveCreatures">0</column>
<column name="bRemoveUsed">0</column>
<column name="nItemsID">0:3</column>
<column name="nCreatureID">0:0</column>
<column name="ptCreatureHex">0,0</column>
<column name="ptTeleport">0,0</column>
<column name="ptEditor">-3948,-2376</column>
<column name="nType">0</column>
<column name="fLootChance">0</column>
<column name="fAccidentChance">0</column>
<column name="fCreatureChance">0</column>
<column name="vAccidents">0:1</column>
<column name="vLoot">3</column>
</table>
ただ、MODフォルダ側なのでいつも通り"0:"を適当に記述して、
aMinimapHexesに座標と名前を記述して、
ミニマップにキャンプの位置が記録されるようにしています。
あと、わりと重要なポイントですが…
encounter文章の改行にはCR+LFを入力する必要があるようです。
よく分からなければ既存の文章からコピペして使ってください。
イベントの発生トリガーを定義するのは、"encountertriggers"テーブルです。
設定内容により発生条件はある程度弄れますが、
今回は、"このhexに踏み込んだとき、1回だけ"という条件で定義します。
<table name="encountertriggers">特定の座標に踏み込んだらイベント発生、なので
<column name="id">99</column>
<column name="strName">Hunter's Camp</column>
<column name="nEncounterID">9999</column>
<column name="fChance">1</column>
<column name="bLocBased">1</column>
<column name="bDateBased">0</column>
<column name="bHexBased">0</column>
<column name="bUnique">1</column>
<column name="bAIPassable">1</column>
<column name="aArea">22,162,0</column>
<column name="dateMin">1000-0-1-0</column>
<column name="dateMax">9999-11-31-23</column>
<column name="aHexTypes">38</column>
</table>
bLocBasedを1にし、aAreaに座標を記述します。
Zom Zom'sやDMCのような、周辺エリア到着時に発生するイベントなら、
座標の3つ目の数字で範囲を設定できます。
1度限りのイベントにするにはbUniqueを1にします。
campは1つしかないので、"bLocBased"が1であれば
"bHexBased"は0でも問題ありません。
逆に、同じような複数の店を定義して初回だけイベント、的な設定なら
"bHexBased"を1に、"bLocBased"を0にします。
この時はaHexTypesも忘れずに記述しておきましょう。
ここで設定すれば、イベントは初回のみ表示されるようになっていますが
"この場所を訪れた"というconditionを作成して、
イベントを"発生させない"フラグとすることも可能です。
これで"イベント"と"イベントのトリガー"が揃ったので
実際にテストしてみます。
キャンプに踏み込むと…
こんな感じに画像とテキストが表示されています。
文章の内容は、
"何か煙が見えたから行ってみたら
猟師のじっちゃんがキャンプ張ってた
休憩タダだけど何か欲しいなら金出せって言ってるよ"
みたいな感じになっているはずです。
今回は最低限それっぽく見えるだけの要素しか入れていませんが、
メッセージを工夫したり、会話や行動が行えるようにするなど
手を入れる余地はいくらでもあります。
キャンプをそれらしく飾ってみる
ここまでの作業で、大体やるべきことはやった…と言えますが、
最後に少しだけキャンプを飾ってみます。
hexやencounterの画像に描いたたき火ですが、
せっかくなのでこのhexそのものにも常設で置いてみることにします。
DMCのsprawlにあるドラム缶式のたき火のように、
劣化せずにずっと点いているものを配置します。
(売買用Hexなのでクラフトには使えませんが…)
<table name="itemtypes">(中略)
<column name="id">999</column>
<column name="nGroupID">777</column>
<column name="nSubgroupID">0</column>
<column name="strName">well built campfire</column>
<column name="strDesc">hunter's campfire</column>
<column name="fDegradePerHour">0</column>(後略)
<column name="fEquipDegradePerHour">0</column>
<column name="fDegradePerUse">0</column>
<column name="vDegradeTreasureIDs">0:3,0:3</column>
<column name="aEquipConditions"></column>
<column name="aPossessConditions">200=0:25,208=0:25</column>
この手の暖房アイテムを作成するときは、
aPossessConditionsに
25(Warmed by campfire)か70(Warmed by a small flame)を設定します。
このとき"0:"を忘れると、エラーが出ない代わりに効果も発生しませんでした。
上のaEquipConditionsは装備時に発生する効果を記述していますので、
Possess(所有する)は装備していない状態で発生する効果を設定するようです。
"="を挟んで、右辺は発生するconditionのid、
左辺は装備時なら装備箇所を設定していたので
この場合は"アイテムがどこにあるか"的なものを設定しているようです。
この"200"と"208"はこちらの資料によると、
"200"が"GROUND"(地面)、"208"は"CAMP"(キャンプ画面)で、
Hexに置いて効果の出るもの(寝袋なども)はこの2つを指定しているようです。
差別化するために専用グラフィックを用意し、
商品配置用のtreasuretablesに追記します。
ここでテストプレイしてみると…
商品に交じってcampfireが配置され、
"Warmed by campfire"のconditionが追加されています。
ここまでは問題なく動くようですが、テスト中に妙な現象が発生しました。
そのへんの水場で生成した水が…
すべて鑑定済みになっています。
キャンプに立ち寄る前は未鑑定だったので、
間違いなくこのMOD由来のバグです。
試しにcampfireを外してみると、このバグは発生しなくなります。
複合的な条件で発生したバグ(か仕様かは分かりませんが)のようですが、
せっかく作ったcampfireですし、あまり外したくはありません。
バグをそのまま残すのも問題ですし、
次項で原因を突き止めて修正していきます。
アイテム自動鑑定バグの修正
さて、ここからは原因の追究ですが…
十中八九、"tresuretable"テーブルの"bIdentify"が関係していそうです。
かと言って、"bIdentify"をすべて0にするとベリーが未鑑定になってしまいます。
この場だけの対応であれば、それほど被害は大きくないのですが…
やはり手探りでも正しい対処をきっちりしておいた方が良さそうです。
(バニラのxmlを熟読中…)
色々と確認&試行錯誤してみた結果、
商品のtreasuretableを分ける場合は
商品全体を管理するテーブル(barterhexesに指定するもの)はbIdentifyを1に、
他はbIdentifyを0に設定すれば良さそうな感じでした。
ただし、バニラから呼び出している"中身入り水ボトル"を追加するテーブルは
bIdentifyが1のままですが…問題なく動作しています。
これで、無事にバグが修正されたことを確認できました。
今回のまとめ
というわけで、今回もどうにか(手探りですが)MODらしきものが完成しました。
barterhexes、treasuretable、hextypes、maps、
itemtypes、encounters、encountertriggers…と
今回分はかなり手広くテーブルを扱ってみましたが、
やはりデバッグ作業も複雑で時間が掛かるものになってしまいました。
特にイベント関係は翻訳記事も書いていますが、
複雑になればなるほどその流れを追うのがかなり面倒になってきます。
よく分からないバグに遭遇したり、設定関係で混乱しそうになった時は
設定、条件、テーブル参照の流れなどを意識して確認すると良さそうです。
特に、MODフォルダか"0"フォルダのどちらで定義するかは
0:の記述関係も含めて、細かいバグの起こりやすいポイントだと思います。
NEO ScavengerのMODは、実装そのものは非常に簡単ですが
仕様の公開や情報共有がまだまだ不足しているため、
結局こういう"手探りで何か作ってみる"のが上達のための最善手ではないでしょうか?
(もちろん、バニラやMODのxmlを熟読するのもいい方法ですが)
ついでに、今回のサンプルMODも適当にDL可能な感じにまとめておきました。
今回はわりと端折ったり変更したりが多かったので
(一応これなら動いた、という意味で)MOD制作の参考にしてやってください。
ダウンロード:
https://sites.google.com/site/acfilestorage/nsmod/hunter_camp_V2.zip
バグや問題があれば、コメント等でお知らせください。
機能追加…は性質上ありませんが、バグ(と記事)の修正は対応します。
0 件のコメント:
コメントを投稿