アイテムスポーンシステム

コレクションとディストリビューショ

コレクションにおいては、各エントリの判定は他のエントリから独立して行われます。したがって、各エントリに関連付けられた確率は「絶対的」なものとなり、0~1の範囲で扱われます。なお、JSONファイル内では、これを0から100までの値を用いた%として記述します。

確率が0(または負の値)の場合、そのエントリが選ばれることはありません。逆に100%に設定した場合は、常に選ばれるようになります。既定値が100に設定されているのは、それが最も汎用的な数値だからです。もし既定値が0であれば、そのエントリは最初から記述する必要がない(削除しても同じである)ことになってしまいます。

ディストリビューションは、現行のシステムと同様の「重み付けリスト」です。リストの中から厳密に1つのエントリだけが選択されます。各エントリの確率は、他のエントリの確率との比較による「相対的」なものになります。確率が0(または負の値)の場合、そのエントリが選ばれることはありません。

具体的な例を挙げましょう。アイテムAの確率を30、アイテムBの確率を20に設定したと仮定します。このとき、AとBの組み合わせ(全4パターン)が発生する確率は以下のようになります。:

組み合わせ コレクション ディストリビューション
AもBも出ない 56% 0%
Aのみ出る 24% 60%
Bのみ出る 14% 40%
AとBの両方が出る 6% 0%

フォーマット

基本フォーマットは以下の通りです:

{
    "type": "item_group",
    "subtype": "<subtype>",
    "id": "<some name>",
    "ammo": <some number>,
    "magazine": <some number>,
    "purge": <true/false>,
    "delete": [ ... ],
    "entries": [ ... ]
}

purge はオプション項目です。これは、そのアイテムグループにおいて「以前に定義された内容」をすべて消去するかどうかを指定するbool値です。 subtype もオプション項目で、collection または distributionを指定できます。未指定の場合はデフォルトでoldが適用されます。これは、そのアイテムグループが旧来の形式(技術的にはディストリビューション)を使用していることを示します。

なお、ammo(弾薬)や magazine(マガジン)を使用する際にはいくつかの注意すべき点 があります。

エントリ配列

entries リストには各エントリを記述しますが、それぞれ以下のいずれかの形式をとることができます:

  1. Item

    { "item": "<item-id>", ... }
    
  2. Group

    { "group": "<group-id>", ... }
    
  3. Distribution

    {
      "distribution": [
        "An array of entries, each of which can match any of these 4 formats"
      ]
    }
    
  4. Collection

    {
      "collection": [
        "An array of entries, each of which can match any of these 4 formats"
      ]
    }
    

ゲーム側は、itemまたは group のどちらの値が存在するかに基づいて、そのエントリが「単体アイテム」を指しているのか、それとも「別のアイテムグループへの参照」であるのかを判断します。

各エントリには、さらに追加の値を設定できます (上の例では ...と表記されている箇所です)。これらを使用することで、生成されるアイテムに詳細なプロパティを付与できます。:

"damage": <number>|<array>,
"damage-min": <number>,
"damage-max": <number>,
"count": <number>|<array>,
"count-min": <number>,
"count-max": <number>,
"charges": <number>|<array>,
"charges-min": <number>,
"charges-max": <number>,
"active": "<bool>"
"contents-item": "<item-id>" (can be a string or an array of strings),
"contents-group": "<group-id>" (can be a string or an array of strings),
"ammo-item": "<ammo-item-id>",
"ammo-group": "<group-id>",
"container-item": "<container-item-id>",
"container-group": "<group-id>",

contents (中身)は、生成されたアイテムの内部アイテムとして追加されます。その際、それらが実際にアイテム内に収まるかどうか(容積などの制限)のチェックは行われません。これにより、「本が入った水」の中に「スチールフレーム」があり、さらにその中に「死体」が入っている……といった特殊な構成も可能になります。

count (個数)を指定すると、アイテム生成が繰り返されます。実行されるたびに新しいアイテムが個別に生成されます。

charges: (充填量/弾薬数): min(最小値)のみを設定してmax(最大値)を省略した場合、ゲーム側はコンテナの容量や弾薬/マガジンの装弾数に基づいて最大値を算出します。maxを容量以上に設定した場合は、自動的に最大容量まで値が引き下げられます。また、maxのみを設定してminを省略した場合は、minは0として扱われます。

active: (起動状態): trueに設定すると、アイテムは生成された瞬間に起動状態になります。注意点として、これはアイテムグループ全体に対しては機能しません。アイテムグループ内の個々のアイテムに対してのみ有効です。

active Usage example

[
  {
    "id": "test_grenade",
    "type": "item_group",
    "subtype": "collection",
    "items": [{ "item": "grenade_act", "prob": 100, "active": true }]
  },
  {
    "type": "mapgen",
    "method": "json",
    "om_terrain": "shelter_roof",
    "weight": 100,
    "object": {
      // ...
      "place_items": [{ "item": "test_grenade", "x": 12, "y": 12, "chance": 100, "repeat": 1 }],
      "place_item": [{ "item": "grenade_act", "x": 15, "y": 15, "chance": 100, "active": true }]
    }
  }
]
"damage-min": 0,
"damage-max": 3,
"count": 4
"charges": [10, 100]

この設定では4つのアイテムが生成されますが、損傷(damage)の値はアイテムごとに個別に判定(ロール)されるため、それぞれ損傷度合いが異なる可能性があります。各アイテムは10から100の範囲(両端の値を含む)で「充填量(charges / つまり弾薬)」を保持します。もしそのアイテムが弾薬を保持するためにマガジンを必要とする種類であれば、システム側が自動的にマガジンを追加します。charges、count、damage に対して配列(必ず2つの要素を含める必要があります)を使用することは、最小値(min)と最大値(max)を明示的に記述することと同義です。言い換えれば、"count": [a, b] という記述は、"count-min": a, "count-max": b と記述したのと同じ結果をもたらします。

まずコンテナの状態がチェックされ、アイテムがその中に格納されます。その際、アイテムの充填量はコンテナの容量に合わせて、上限が制限されたり、逆に容量いっぱいまで増加したりするように調整されます。

Delete array

delete リストには各エントリを記述しますが、それぞれ以下のいずれかの形式をとることができます:

  1. Item

    { "item": "<item-id>" }
    
  2. Group

    { "group": "<group-id>" }
    

これらのIDを持つ、それまでに定義されたすべてのアイテムがリストから削除されます。指定したIDが存在しなくてもエラーは表示されず、そのまま処理がスキップされます(これは、おそらく他のModによって既に削除されているためです)。

弾薬とマガジン

アイテムを弾薬やマガジンの「あり・なし」の状態で生成させる方法をいくつか紹介します(なお、entries 配列内の銃器やマガジンに対して ammo-item を指定することで、デフォルト以外の弾薬タイプを使用させることも可能です):

  • アイテムグループ全体に対して弾薬/マガジンの出現確率を指定する アイテム グループ全体に設定を適用します。ammo は各エントリが「フル装填(満タン)」の状態で生成される確率(%)を指定します(このとき、マガジンが必要な銃器等であれば自動的に追加されます)。magazine は各エントリがマガジンを装着した状態で生成される確率(%)を指定します。これらは未指定の場合、どちらも既定値は0となります。

    ammo(弾薬)および magazine(マガジン)の設定は、ツール、銃器、マガジンにのみ適用される点に注意してください。さらに、以下のいずれかに該当するツールには適用されません。

    • エントリ内で、生成時の弾薬量が明示的に指定されているツール。
    • アイテム自体のJSON定義において、初期装弾数が「ランダムな値」または 「0以外の固定値」に設定されているツール。

    もし、あなたのアイテムグループから別のアイテムグループを参照している場合、参照先グループ側の ammo/magazine 確率は無視され、代わりにあなたのグループ側の設定が使用されます。

  • entries配列内で chargescharges-min、または charges-max を使用してください。必要に応じて、既定のマガジンが自動的に追加されます。

Shortcuts

以下の記述:

"items": [ "<id-1>", [ "<id-2>", 10 ] ]

は、次の記述と同じ意味になります:

"entries": [ { "item": "<id-1>" }, { "item": "<id-2>", "prob": 10 } ]

言い換えれば、「単一の文字列」はアイテムIDを指し、「配列(文字列1つと数値1つを含むもの)」はアイテムIDと出現確率を指します。

これは、アイテムグループの場合も同様です:

"groups": [ "<id-1>", [ "<id-2>", 10 ] ]

この形式では、生成されるアイテムに詳細なプロパティを付与することはできません。また、出現確率を省略できるのは、collection 形式のエントリのみです!

"entries"、"items"、"groups" の各メンバーが存在する場合、それらの内容はすべて追加されます。そのため、例えば以下のような記述では、アイテム <id-1> がアイテムグループ内に2回出現することになります。

{
  "items": ["<id-1>"],
  "entries": [{ "item": "<id-1>" }]
}

もう一つの例を挙げます。アイテムグループ「milk」は、(milk_containers から選ばれた)容器を生成し、その中にミルクを入れます(このとき特定の charges 値が定義されていないため、容器に収まる最大量が入った状態で生成されます)。

{
    "type" : "item_group",
    "id": "milk_containers",
    "subtype": "distribution",
    "items": [
    "bottle_plastic", "bottle_glass", "flask_glass",
    "jar_glass", "jar_3l_glass", "flask_hip", "55gal_drum"
    ]
},
{
    "type" : "item_group",
    "id": "milk",
    "subtype": "distribution",
    "entries": [
        { "item": "milk", "container-group": "milk_containers" }
    ]
},

インライン・アイテムグループ

特定の場所では、グループIDを指定する代わりに、アイテムグループをその場に直接定義することができます。このグループには公開された(参照可能な)IDが存在しないため(内部的には非特定、またはランダムなIDが割り振られます)、他からこのグループを参照することはできません。これは、そのグループが使用される場所に対して非常に限定的であり、他で再利用されることが決してない場合に最も有用です。

例として、モンスターの死亡時ドロップ(MONSTER オブジェクト内の death_drops エントリ、詳細は こちらを参照) でこの手法が使えます。そのモンスターが極めて特殊な場合(例:特別なロボットや、ユニークなエンドゲームモンスターなど)、死亡時に出現するアイテムの構成は(その形式のままでは)他のどのグループにも登場しません。

そのため、以下のスニペットのように記述できます:

{
    "type": "item_group",
    "id": "specific_group_id",
    "subtype": "distribution",
    "items": [ "a", "b" ]
},
{
    "death_drops": "specific_group_id"
}

(これ)は、以下と同じ意味になります:

{
  "death_drops": {
    "subtype": "distribution",
    "items": ["a", "b"]
  }
}

インライングループは他のグループと同様に読み込まれ、前述のすべてのプロパティを使用することができます。その際、type および id メンバーは常に無視されます。

また、完全なJSONオブジェクト形式({ ... })の代わりに、JSON配列形式([ ... ])で記述することも可能です。その場合、既定のサブタイプが適用され、配列の内容は前述の entries 配列として読み込まれます。この配列の各エントリは、JSONオブジェクトの必要があります:

{
  "death_drops": [
    { "item": "rag", "damage": 2 },
    { "item": "bowling_ball" }
  ]
}

備考

テスト

作成したアイテムグループは、ゲーム内でテストすることができます:

  1. セーブデータをロードし、デバッグメニューを呼び出します。

    ヒント: デバッグメニューにキーを割り当てていない場合や、忘れてしまった場合は、 ESC 1の順に押すことで呼び出せます。

  2. 「Test Item Group」を選択します。

  3. デバッグしたいアイテムグループを選択します。

    選択すると、ゲーム内でそのグループのアイテム生成が100回試行され、生成されたアイテムがカウントされます。その後、出現頻度の高い順にソートして表示されます。

    ヒント: デバッグメニュー内では、 /キーを使ってあらゆる項目をフィルタリングできます。

アイテムグループ EMPTY_GROUP にアイテムを追加してはいけません。このグループは、システム上グループIDが必要なものの、アイテムを一切出現させたくない場合に使用するためのものです。このグループからアイテムが生成されることはありません。

SUS

アイテムグループにアイテムを追加する際は、SUSアイテムグループ を探すか、あるいは新規に作成することを検討してください。SUSアイテムグループとは、特定の収納家具の中に生成されるであろうアイテムを、現実的で妥当な配分でまとめたコレクションのことです。SUSは「特定用途の収納」の略称です。アイテムグループを特定用途の収納ごとに整理する目的の一つは、保守や拡張が容易な「再利用可能なテーブル」を普及させることにあります。

SUSアイテムグループは /data/json/itemgroups/SUS で確認できます。