※この記事は、前回の記事を読んでいる前提で話が進みます。まだ見ていない場合は確認してからご覧ください。 また、今回の参考データは、v2.0 のデータです。バージョンが違った場合少しデータが違ったりする可能性もありますがご了承ください。
駆け出しModder
さて、環境構築も済んで一端ではありますがModの鱗片を前項で軽く触れました。
本投稿ではもう少し深堀りしてどんな変化を加えられるのかを例付きで解説していきます。
具体的には以下の内容を解説します。
- アイテムの追加
- アイテムのステータス調整
- 追加したアイテムのレシピ追加
※弄る予定のXmlファイルは、必ずバックアップを取ってから変更を加えてください
アイテムの追加
今回は、まず本項で使用するアイテムを追加します。
その名も「石斧Mk.2」です。
今後、チュートリアル系では幾度となく石斧を弄る事となりますが、まずはその基盤となるアイテムの追加を行います。
今回対象のXmlファイルは「items.xml」です。
なお、今回からはメモ帳ではなく私が愛用しているテキストエディタ「Visual Studio Code」の画面でXmlファイルを弄りますが、基本的にはメモ帳でもできる操作しかしませんので問題ありません。
(もし画面のみやすさ等気に入ったら調べて使ってみてください)

ファイルを開くと、先頭の方に上記のデータが見つかると思います。これが今回追加するアイテムの基盤となるアイテム情報です。
今回はこのデータを一旦丸々コピペします。
コピペする範囲ですが、基本的にXmlは構造上、開始タグ~終了タグ までで1データとして扱われます。
今回の場合だと、
<item name="meleeToolRepairT0StoneAxe">
こちらが開始タグとなっています。
<の次に表示されているのが、タグ名となりますので今回の場合は item がタグ名となります。
Xmlファイルを少しずつ下へスクロールしていくと、以下の行が見つかります。

</item> これが終了タグとなります。
<item ~~> ~ </item> までで石斧の1データとなっています。
(HTMLを触ったことがある方であればこの辺はピンと来るかもしれません)
では、石斧のデータをコピーします。(以下、少し長いです)
<item name="meleeToolRepairT0StoneAxe">
<property name="Tags" value="axe,melee,light,tool,longShaft,repairTool,miningTool,attStrength,perkMiner69r,perkMotherLode,perkTheHuntsman,canHaveCosmetic,harvestingSkill,corpseRemoval"/>
<property name="DisplayType" value="meleeRepairTool"/>
<property name="HoldType" value="32"/>
<property name="Meshfile" value="@:Other/Items/Weapons/Melee/Axe/stone_axePrefab.prefab"/>
<property name="Material" value="Mstone"/>
<property name="TintColor" value="107, 107, 71"/>
<property name="ScrapTimeOverride" value="10.0"/>
<property name="RepairTools" value="resourceRockSmall"/>
<property name="EconomicValue" value="200"/>
<property name="EconomicBundleSize" value="1"/>
<property name="TraderStageTemplate" value="baseTier0"/><!-- meleeToolRepairT0StoneAxe -->
<property name="SellableToTrader" value="false"/>
<property name="DegradationBreaksAfter" value="false"/>
<property name="SoundJammed" value="ItemNeedsRepair"/>
<property name="SoundDestroy" value="wooddestroy1"/>
<property name="ShowQuality" value="true"/>
<!-- <property name="UnlockedBy" value="perkMiner69r,craftingHarvestingTools"/> -->
<property name="Group" value="Tools/Traps,Basics"/>
<property name="RepairExpMultiplier" value="5.5"/>
<property name="SoundUnholster" value="weapon_unholster"/>
<property name="SoundHolster" value="weapon_holster"/>
<property name="SoundPickup" value="axe_stone_grab"/>
<property name="SoundPlace" value="axe_stone_place"/>
<property class="Action0">
<property name="Class" value="DynamicMelee"/>
<property name="Sphere" value=".1"/>
<property name="Sound_start" value="axe_stone_swing"/>
<property name="ToolCategory.Butcher" value="0" param1="4"/><!-- damage vs entity corpses -->
<property name="GrazeStart" value=".15"/>
<property name="GrazeEnd" value=".3"/>
<property name="SwingDegrees" value="45"/>
<property name="SwingAngle" value="135"/>
<property name="UseGrazingHits" value="true"/>
<property class="HitSounds">
<property name="Override0" value="organic" param1="stonehitorganic"/>
</property>
<property class="GrazeSounds">
<property name="Override0" value="organic" param1="metalgrazeorganic"/>
</property>
</property>
<property class="Action1"> <!-- UseAction -->
<property name="Class" value="Repair"/>
<property name="Delay" value=".64"/> <!-- Repair actions still need the delay amount -->
<property name="Repair_amount" value="100"/>
<property name="Upgrade_hit_offset" value="-1"/>
<property name="Sound_start" value="repair_block"/>
<property name="Allowed_upgrade_items" value="resourceWood,resourceClayLump,resourceSnowBall,resourceScrapIron,resourceForgedIron,resourceForgedSteel,resourceConcreteMix,resourceCobblestones,ironDoorBlockVariantHelper,ironDoorDoubleBlockVariantHelper,vaultDoor01,vaultDoor01Double,ironHatchBlockVariantHelper,vaultHatch01,cellarDoorDoubleIron,cellarDoorDoubleSteel,shuttersIronBlockVariantHelper,shuttersSteelBlockVariantHelper,resourceYuccaFibers,resourceCloth,resourceScrapPolymers,resourceNail,glassBulletproofBlockVariantHelper"/>
<property name="UsePowerAttackAnimation" value="false"/>
</property>
<effect_group name="meleeToolRepairT0StoneAxe">
<passive_effect name="AttacksPerMinute" operation="base_set" value="105" tags="perkMiner69r,axe"/>
<passive_effect name="StaminaLoss" operation="base_set" value="8" tags="primary"/>
<passive_effect name="DegradationMax" operation="base_set" value="250,500" tier="1,6" tags="perkMiner69r"/>
<passive_effect name="DegradationPerUse" operation="base_set" value="1" tags="perkMiner69r"/>
<passive_effect name="MaxRange" operation="base_set" value="2.4" tags="perkMiner69r"/>
<passive_effect name="BlockRange" operation="base_set" value="3" tags="perkMiner69r"/>
<passive_effect name="ModSlots" operation="base_set" value="1,1,1,2,2,3" tier="1,2,3,4,5,6"/>
<passive_effect name="ModPowerBonus" operation="perc_add" value=".10" tags="EntityDamage,BlockDamage"/>
<passive_effect name="ModPowerBonus" operation="base_add" value="300" tags="EconomicValue"/>
<passive_effect name="EntityDamage" operation="base_set" value="6" tags="perkMiner69r"/>
<passive_effect name="EntityDamage" operation="perc_add" value=".1,.5" tier="2,6" tags="perkMiner69r"/> <!-- tier bonus -->
<passive_effect name="BlockDamage" operation="base_set" value="22" tags="perkMiner69r"/>
<passive_effect name="BlockDamage" operation="perc_add" value=".15,.75" tier="2,6" tags="perkMiner69r"/> <!-- tier bonus -->
<display_value name="dBlockRepairAmount" value="100"/>
<passive_effect name="HarvestCount" operation="base_set" value=".7" tags="butcherHarvest"/>
<passive_effect name="DamageModifier" operation="perc_add" value="-.85" tags="earth"/>
<passive_effect name="DamageModifier" operation="perc_add" value="-.33" tags="stone"/>
<passive_effect name="DamageModifier" operation="perc_add" value="-.5" tags="metal"/>
<passive_effect name="DamageModifier" operation="base_set" value="1" tags="head,perkMiner69r" match_all_tags="true"/>
<passive_effect name="DismemberChance" operation="base_set" value=".05" tags="perkMiner69r"/>
</effect_group>
<effect_group>
<triggered_effect trigger="onSelfEquipStart" action="ModifyCVar" cvar="$minerNatHealing" operation="set" value="1">
<requirement name="ProgressionLevel" progression_name="perkStrengthMastery" operation="GTE" value="1"/>
<requirement name="!HasBuff" buff="buffLegSplinted"/>
<requirement name="!HasBuff" buff="buffLegCast"/>
<requirement name="!HasBuff" buff="buffArmSplinted"/>
<requirement name="!HasBuff" buff="buffArmCast"/>
</triggered_effect>
<triggered_effect trigger="onSelfEquipStart" action="ModifyCVar" cvar="$minerHealing" operation="set" value=".5">
<requirement name="ProgressionLevel" progression_name="perkStrengthMastery" operation="GTE" value="1"/>
</triggered_effect>
<!-- Reduce treatedAbrasionCounter when holding mining tools -->
<triggered_effect trigger="onSelfEquipStart" action="ModifyCVar" cvar="$treatedAbrasionCounter" operation="multiply" value="@$minerHealing">
<requirement name="CVarCompare" cvar="$minerHealing" operation="GT" value="0"/>
</triggered_effect>
<!-- Set a check flag when holding -->
<triggered_effect trigger="onSelfEquipStart" action="ModifyCVar" cvar="$minerCheck" operation="set" value="1">
<requirement name="CVarCompare" cvar="$minerHealing" operation="GT" value="0"/>
<requirement name="CVarCompare" cvar="$minerCheck" operation="LTE" value="0"/>
</triggered_effect>
<triggered_effect trigger="onSelfEquipStop" action="RemoveCVar" cvar="$minerHealing,$minerNatHealing,$minerCheck"/>
<triggered_effect trigger="onPerkLevelChanged" action="ModifyCVar" cvar="$minerNatHealing" operation="set" value="1">
<requirement name="ProgressionLevel" progression_name="perkStrengthMastery" operation="GTE" value="1"/>
<requirement name="!HasBuff" buff="buffLegSplinted"/>
<requirement name="!HasBuff" buff="buffLegCast"/>
<requirement name="!HasBuff" buff="buffArmSplinted"/>
<requirement name="!HasBuff" buff="buffArmCast"/>
</triggered_effect>
<triggered_effect trigger="onPerkLevelChanged" action="ModifyCVar" cvar="$minerHealing" operation="set" value=".5">
<requirement name="ProgressionLevel" progression_name="perkStrengthMastery" operation="GTE" value="1"/>
</triggered_effect>
<!-- Reduce treatedAbrasionCounter when holding mining tools -->
<triggered_effect trigger="onPerkLevelChanged" action="ModifyCVar" cvar="$treatedAbrasionCounter" operation="multiply" value="@$minerHealing">
<requirement name="CVarCompare" cvar="$minerHealing" operation="GT" value="0"/>
</triggered_effect>
<!-- Set a check flag when holding -->
<triggered_effect trigger="onPerkLevelChanged" action="ModifyCVar" cvar="$minerCheck" operation="set" value="1">
<requirement name="CVarCompare" cvar="$minerHealing" operation="GT" value="0"/>
<requirement name="CVarCompare" cvar="$minerCheck" operation="LTE" value="0"/>
</triggered_effect>
</effect_group>
</item>
…めちゃくちゃ長いですが、これで1データです。
このデータを、items.xmlに追加します。

この、</items> の上に挿入します。
なぜ</items>の上に入れるかというと、このファイル全体のアイテム群を纏める<items>というタグで括られた中に、<item>が複数含まれている形式の為です
<items>
<item></item>
<item></item>
</items>
↑のような構造になっています。

現在、このような状態になっていると思います。(長いので省略 部分は実際には長ったらしいデータがあると思ってください)
このまま起動すると、同じ名称のアイテムが2つ存在することになってしまいエラーとなるので、
<item name="meleeToolRepairT0StoneAxe">
追加した方の名称を変えます。
<item name="meleeToolRepairT0StoneAxe">
↓
<item name="meleeToolRepairT0StoneAxe_2">

ここまで出来たら、上書き保存してゲームを起動します。
起動したら、F1を押して、「cm」と入力して「Enter」を押してください。
(この手順でゲームモードがクリエイティブモードへ変更されます。同じ手順をもう一度実行するとクリエイティブモードが解除されます)
そして「Uボタン」を押してください、するとクリエイティブモードメニューが出てきます。

このページが開いたら、画面上部の検索ウィンドウ(虫眼鏡マークの右)に、先ほど作成したアイテムの名称「meleeToolRepairT0StoneAxe_2」を入力してください。

な、なんか名前のないアイテムがあるッ?!
と、思ったはずですがこれで正解です。
こちらは、7dtdのXml仕様に関係してくるのですが、7dtdではアイテムやブロック名と同じ名前の画像ファイルがゲームアセット内に存在する場合、自動でアイテムアイコンを設定してくれるという仕様があります。
今回の場合、本来だと石斧の画像名は「meleeToolRepairT0StoneAxe」となっていたので、デフォルトの石斧には画像がちゃんと設定されていました。
では同じようなアイテムを複数追加するのは実質不可能では?と思いそうなのですがそれを解決する手段が存在します。
それは、「アイテムのプロパティにアイコン名を設定するプロパティを設定する」です。
アイテムプロパティというのは、石斧のアイテム情報の中にも多分に含まれているのですが、

この辺の、<property から始まるデータが対象となります。
今回は一旦アイテムを追加することに焦点を置くため、詳しい説明は省きますが、以下を追加するとアイテムアイコンが設定されます。
<property name="CustomIcon" value="meleeToolRepairT0StoneAxe"/>

一旦ここではこれを入れたらアイコンが設定される というのだけ認識いただければ問題ありません。
(軽くだけ補足すると、CustomIcon = アイコンを設定する というパラメータで、そのアイコンの名前がvalue= の中身となっています。 つまり石斧のアイテム名を入れている為石斧のアイコンが設定されるような挙動となります)
上記を設定したら、一度ゲームと閉じるか「終了」を押してワールドから退出し、ワールドに入りなおしてください。

そして、再度クリエイティブモードへ変更し、Uボタンを押してアイテム名を入力すると…

無事、アイコンが設定されました。
これで、新規アイテムの追加が完了しました。(アイテム名が英語表記の件に関しては、後日投稿予定のModlet化対応の際に説明します)
アイテムのステータス調整
次は、先ほど追加したアイテムのステータスを調整してみます。
現状だと、石斧と全く同じ性能の名前が英語のアイテムが追加されただけにすぎません。
差別化する為に攻撃力・ブロックへのダメージを変更してみようと思います。
先ほど追加したアイテムの下部のほうに、
<effect_group name=”meleeToolRepairT0StoneAxe”> というタグで括られたデータが存在します。
この中に存在する、以下の項目を変更していきます。

<passive_effect name="EntityDamage" operation="base_set" value="6" tags="perkMiner69r"/>
<passive_effect name="BlockDamage" operation="base_set" value="22" tags="perkMiner69r"/>
上記の2項目のvalue の値を変更します。
- EntityDamage: 攻撃力
- BlockDamage: ブロックへのダメージ
今回はEntityDamageを100, BlockDamageを50に設定してみます。

上書き保存して、ゲームを起動しなおします。


ちゃんと近接ダメージと対物ダメージが変わっていますね。
アイテムのステータス調整は基本的にはvalueの値を修正するだけで変わってくれるので、一気に改造している感が出てきます。
追加したアイテムのレシピ追加
さて、現在まででアイテムを追加し、そのアイテムのステータスを調整してきました。
ですが、まだレシピが設定されていないのでゲーム内で使用することができません。

(検索しても出てこない)
次は今回追加したアイテムのレシピを追加してみます。
まずは前回少し触った「recipes.xml」を開き、石斧のレシピを検索します。

検索で引っかかったら、<recipe>~</recipe>までを丸々コピーして、先ほど同様ファイルの下のほうへペースト(</recipes> より上)
レシピの名前を「meleeToolRepairT0StoneAxe」 -> 「meleeToolRepairT0StoneAxe_2」へ変更する

<recipe name="meleeToolRepairT0StoneAxe_2" count="1" tags="craftingHarvestingTools,packMuleCrafting">
<ingredient name="resourceRockSmall" count="2"/>
<ingredient name="resourceYuccaFibers" count="2"/>
<ingredient name="resourceWood" count="2"/>
</recipe>
そして、ゲームを起動しなおしてレシピ検索すると…

はい、追加されました。
これで正真正銘、オリジナルの石斧をゲーム内に追加することができました。
もはやこれはもうModと言っても差し支えないと思います。
余白
テキスト量が多くて書くのが大変でした。
今回は結構本格的にアイテムの追加・ステータスの調整・レシピの設定 と、そのままゲーム内で遊べるデータまで実装してみました。
正直これだけでも発想次第では色々データを追加してゲーム体験を大幅に変えるものを作れるとは思いますが、それにはまだまだ知識量が足りておらずやりたいことの実現が難しいかもしれません。
ただ、本稿でおそらく気になったであろう、アイテム名が英語のままなのが引っ掛かっているかと思います。現段階でも名称を設定しようと思えば設定できるのですが、次に投稿する内容を理解する上で余計な知識になってしまいそうなので意図的に省きました。
(どうしても今追加したい場合、軽く説明するとLocalization.txt というファイルがConfigフォルダ内に存在するのですが、そのファイルの末尾に適切に設定すると反映されます。が、データ量が膨大でファイルをそっ閉じすると思います)
Mod制作への第一歩は、次回の投稿でおそらく終わります。
が、次の内容は(専門知識しらない人からしたら)ラスボスレベルの難解さだと思います。
なるべく丁寧に説明を記載するつもりですが、気合で乗り切って貰えればと思います。
(そこを乗り越えれば、楽しいModderライフが待っている、かもしれない?)
コメント