GTFO
Install with App

Details

Latest version
0.0.1
Last Updated
First Uploaded
Downloads
8
Likes
1
Size
277KB
Dependants

Categories

SupplyCrate

Place crates anywhere in a level through a JSON config. A crate can either hand out resource packs (ammo / medi / tool / disinfection) or swap the player's gear (primary, special, melee or tool). Each crate has a limited number of uses, can switch between several presets ("profiles") at runtime, can be turned on and off with a custom warden event, and can fire warden events when it runs out.

  • Live edit. Save the config while in a level and the crates are rebuilt immediately.
  • Optional PartialData support. ID fields such as MainLevelLayout can use PartialData GUID names.

Usage

{
  "Prefab": "Assets/MyAssets/SupplyCrate.prefab",
  "Levels": [
    {
      "MainLevelLayout": 100,                    // LevelLayoutDataBlock ID (or PartialData name)
      "Crates": [
        {
          "WorldEventObjectFilter": "AmmoCrate_A", // unique name of this crate
          "Category": "Resource",
          "Position": { "x": 12.5, "y": 0.0, "z": -40.2 },
          "Rotation": { "x": 0, "y": 90, "z": 0 },
          "ProfileList": [
            { "Index": 0, "Type": "Ammo", "PackUses": 3, "Limit": 4 }
          ]
        }
      ]
    }
  ],
  "LiveEdit": true,
  "DebugLog": false
}

Config reference

Levels

Field Type Description
MainLevelLayout uint / PartialData name The LevelLayoutDataBlock this entry applies to.
Crates array Crates spawned in this level. See Crate definition.

Crate definition

Field Type Default Description
WorldEventObjectFilter string required The crate's name. It must be unique within the level. Events use it to find the crate.
Category Resource / Gear Resource Resource hands out resource packs. Gear swaps gear. (Weapon is accepted as an old name for Gear.)
Enabled bool true Whether the crate starts enabled.
Position {x,y,z} 0,0,0 World position.
Rotation {x,y,z} 0,0,0 Euler angles in degrees.
InteractDuration float 2.5 Seconds the player has to hold the interact key. A negative value keeps the prefab's value.
ProfileList array [] Presets. The first entry in the list is active when the level starts. See below.
EventsOnUsed array of warden events [] Executed every time the crate runs out of uses. See EventsOnUsed.
TerminalItemKey string "" Optional. If set, and the prefab has an LG_GenericTerminalItem, the crate is registered as a terminal item KEY_<serial> (for example SUPPLY_CRATE_123). Leave it empty to skip.
DimensionIndex enum Reality Only used for the terminal item: the zone it is listed under.
Layer enum MainLayer Same as above.
LocalIndex enum Zone_0 Same as above.
AreaIndex int 0 Same as above. This is the area within the zone.

Profiles (common fields)

Field Type Default Description
Index int 0 The ID used by SetCrateStatus to switch to this profile. It does not need to match the profile's position in the list.
Type string required For resource crates: Ammo, Medi, Tool or Disinfect. For gear crates: Uniform or Map.
Limit int -1 Number of uses, shared by the whole team. When the count reaches 0, the crate is depleted. -1 means unlimited. Switching to a profile resets the remaining uses to its Limit.

A resource crate may only contain resource settings, and a gear crate may only contain gear settings. Any field that belongs to the other category is ignored, and a warning is written to the log.

Profiles: resource crates

{ "Index": 0, "Type": "Medi", "PackUses": 2, "Limit": 3 }
Field Type Default Description
Type Ammo / Medi / Tool / Disinfect Which pack is given. It also selects the UI sprite and the interaction title.
PackUses int 1 Number of uses in the pack the player receives. One use equals 20 ammo in the pack.
ItemID uint by type Optional override of the ItemDataBlock. The defaults are Ammo 101, Medi 102, Tool 127 and Disinfect 132.

The pack is spawned and picked up by the interacting player straight away.

Profiles: gear crates

All gear references (From, To) point to a PlayerOfflineGearDataBlock. You can write either:

  • the persistentID, as a number (300) or a numeric string ("300"), or
  • the block's name, as a string ("Gear_Shelling_S49"). If several blocks share a name, the one that comes first in the DataBlock is used.

Blocks with internalEnabled: false can be used too. This lets you make weapons that cannot be picked in the lobby and can only be obtained from a crate.

Valid slots are Standard (primary), Special, Melee and Tool (Class means the same as Tool).

Uniform: everyone gets the same gear

{
  "Index": 0,
  "Type": "Uniform",
  "Limit": 4,
  "GearList": [
    { "Slot": "Standard", "To": 300 },
    { "Slot": "Special",  "To": "Gear_Mastaba_R66" }
  ]
}
  • If GearList has several entries, the slot that is swapped depends on what the player is holding. A player holding their primary gets the Standard entry, a player holding their special gets the Special entry, and so on. If the held slot is not in the list, nothing can be swapped.
  • If GearList has exactly one entry, that slot is swapped no matter what the player is holding.

Map: per-weapon replacement table

{
  "Index": 1,
  "Type": "Map",
  "Limit": 3,
  "GearMap": [
    { "From": 300,  "To": 4700 },
    { "From": 4700, "To": "Gear_Bataldo_Custom_K330" }
  ]
}
  • The plugin checks the gear the player is holding: primary, special, melee or tool.
  • The held gear is looked up in From. If it is found, it is replaced by the matching To.
  • Chains are allowed. A weapon obtained from the crate can be swapped again by another entry, for example A → B and then B → C.

Rules for both modes

  • Same slot only. From and To (Map), or Slot and To (Uniform), must belong to the same inventory slot. The slot comes from the gear's base item. Entries that break this rule are skipped, and an error is logged that names the entry and both slots, for example: Crate 'GearCrate_1': Map profile 1 GearMap[0] skipped: From 'X' is GearStandard, To 'Y' is GearSpecial
  • Entries with a missing or unknown From/To are skipped and logged.
  • If the player already has the target gear, or nothing in the table matches, the crate cannot be used. The player can still aim at it, and the prompt shows "current weapon cannot be swapped". No use is consumed.

Warden event: SetCrateStatus (Type 2000)

{
  "Type": 2000,
  "Delay": 0.0,
  "WorldEventObjectFilter": "ResourceCrate_1",
  "SustainedEventSlotIndex": 1,
  "Count": 1,
  "Enabled": true
}
Field Description
Type 2000
WorldEventObjectFilter The target crate's name.
SustainedEventSlotIndex 0 only enables or disables the crate. 1 also switches the profile to the one whose Index equals Count, and resets the remaining uses to that profile's Limit.
Count Profile Index. Only used when SustainedEventSlotIndex is 1.
Enabled true enables the crate and false disables it. This is applied every time the event fires.

Delay, Condition, WardenIntel, DialogueID, SoundID and SoundSubtitle work as they do for vanilla events.

A disabled crate cannot be used, and all of its UI turns red. Enabling it again restores its current profile and remaining uses. The event runs locally on every client, as vanilla events do, and the host then syncs the final state.

This works with or without ExtraObjectiveSetup installed. The two plugins do not conflict.


EventsOnUsed

A normal list of warden events. It runs every time the crate's remaining uses go from above 0 to 0. If a profile switch gives the crate new uses and they run out again, the events run again.


Interaction text (TextDataBlock)

All prompt text comes from TextDataBlock, looked up by name. If a block is missing, the built-in fallback is used. The resource crate IDs are the same ones LEGACY's ResourceStation uses, so a text DB that already has them works without changes.

name Used for Fallback
InGame.InteractionPrompt.AmmoStation Ammo crate title AMMUNITION STATION
InGame.InteractionPrompt.MediStation Medi crate title HEALTH STATION
InGame.InteractionPrompt.ToolStation Tool crate title TOOL STATION
InGame.InteractionPrompt.DisinfectionStation Disinfect crate title DISINFECTION STATION
InGame.OnAdditionalInteractionText.ResourceStation Text after the key prompt on resource crates TO REPLENISH
InGame.InteractionPrompt.WeaponStation.Swap Gear crate title when a swap is possible. {0} is the current gear and {1} is the target gear. 将 {0} 换为 {1}
InGame.InteractionPrompt.WeaponStation.CannotSwap Gear crate title when no swap is possible 当前武器无法交换
InGame.OnAdditionalInteractionText.WeaponStation Text after the key prompt on gear crates 以交换
InGame.OnAdditionalInteractionText.SupplyCrate.Uses Remaining uses. {0} is the remaining count and {1} is the profile Limit. Only shown when Limit ≥ 0. ({0}/{1})

Gear names come from the gear's ArchetypeDataBlock.PublicName, so they are localized. Melee and other gear without an archetype use GearCategoryDataBlock.PublicName.

A ready-to-paste set of TextDataBlock entries with English and Simplified Chinese is included as SupplyCrate_TextDataBlock.json. Pick persistentIDs that do not collide with your own text DB.


Examples

1. A medi crate that stays locked until a door opens

Crate:

{
  "WorldEventObjectFilter": "MediCrate_B",
  "Category": "Resource",
  "Enabled": false,
  "Position": { "x": 0, "y": 0, "z": 0 },
  "ProfileList": [ { "Index": 0, "Type": "Medi", "PackUses": 2, "Limit": 2 } ]
}

In the door's EventsOnDoorOpen:

{ "Type": 2000, "WorldEventObjectFilter": "MediCrate_B", "Enabled": true }

2. One crate that turns into another type

The ammo crate starts on profile 0. When it runs out it switches itself to tool packs (profile 1) after 30 seconds:

{
  "WorldEventObjectFilter": "Depot_1",
  "Category": "Resource",
  "Position": { "x": 0, "y": 0, "z": 0 },
  "ProfileList": [
    { "Index": 0, "Type": "Ammo", "PackUses": 3, "Limit": 4 },
    { "Index": 1, "Type": "Tool", "PackUses": 2, "Limit": 2 }
  ],
  "EventsOnUsed": [
    { "Type": 2000, "Delay": 30.0, "WorldEventObjectFilter": "Depot_1",
      "SustainedEventSlotIndex": 1, "Count": 1, "Enabled": true }
  ]
}

When profile 1 is used up as well, the event fires again and switches back to profile 1. The result is a tool-pack crate that refills every 30 seconds.

3. Gear upgrade path

{
  "WorldEventObjectFilter": "Armory",
  "Category": "Gear",
  "Position": { "x": 0, "y": 0, "z": 0 },
  "ProfileList": [
    {
      "Index": 0, "Type": "Map", "Limit": -1,
      "GearMap": [
        { "From": "Gear_Pistol_T1", "To": "Gear_Pistol_T2" },
        { "From": "Gear_Pistol_T2", "To": "Gear_Pistol_T3" }
      ]
    }
  ]
}

Each visit upgrades the held pistol one tier, with no limit. Gear_Pistol_T2 and T3 can be internalEnabled: false, so they only come from the crate.

4. Give everyone the same loadout

{
  "Index": 0, "Type": "Uniform", "Limit": 4,
  "GearList": [
    { "Slot": "Standard", "To": "Gear_Event_Rifle" },
    { "Slot": "Special",  "To": "Gear_Event_Shotgun" },
    { "Slot": "Melee",    "To": "Gear_Event_Hammer" },
    { "Slot": "Tool",     "To": "Gear_Event_Sentry" }
  ]
}

Each player swaps the slot they are holding. With Limit: 4, a team of four can swap one slot each, or one player can swap all four.

Thunderstore development is made possible with ads. Please consider making an exception to your adblock.