Interactions & Containers
A prompt appears when you are close enough and the conditions pass; pressing it runs a list of instructions. Chests are that same mechanism pointed at a container of items — including the awkward part, which is deciding who gets the stack when two players reach for it at once.
One mechanism, two components
PlayerInteractor sits on the player and scans a sphere around them for anything interactable. InteractableBehaviour sits on the thing being interacted with and describes what happens. The player component finds the nearest candidate — one prompt at a time, never a pile of them — and drives it.
InteractableBehaviour is one of the four scripting event sources, so it has the same shape as the others: an optional list of conditions that gate it, and a list of instructionsthat run when it fires. The interacting player is the rule's Target. See Behaviours & Rules for the vocabulary.
The interactable
| Field | Type | Default | What it does |
|---|---|---|---|
description | string | "New Interactable" | What this rule is for. An authoring label, shown only in the Inspector. |
promptRoot | GameObject | — | The world prompt — a billboarded child object — shown while a local player is in range and the conditions pass. |
promptText | string | "[E] Interact" | Base prompt text. Hold and multi-press progress is appended while you are activating it. |
activation | InteractionActivation | Press | How much input the interaction requires: a press, a hold, or several presses in a row. |
holdSeconds | float | 1 | Hold only: seconds the button must be held. Progress shows as a percentage on the prompt. |
pressCount | int | 3 | Multi Press only: presses required. Progress shows as (n/N) on the prompt. |
multiPressInterval | float | 0.8 | Multi Press only: maximum seconds between presses before the count resets. |
conditions | List<ConditionBase> | — | Optional gate: every condition must pass, or the prompt hides entirely. Empty means always interactable. |
onInteract | List<InstructionBase> | — | Runs when the interaction completes. The interacting player is the rule's Target. |
And on the player side, one field worth knowing about:
| Field | Type | Default | What it does |
|---|---|---|---|
radius | float | 1.75 | Scan radius around the character's root. This is reach — how close a player must be before any prompt appears. |
playerInput | PlayerInput | — | The player's input component. Leave empty and it is found on the same object at startup. |
Containers
A container is a WorldInventory: a fixed number of slots holding item stacks, sitting on a chest, a crate, a corpse, a vending machine. It is filled from two sources that combine — a guaranteed list that is always present, and a loot table that is rolled.
| Field | Type | Default | What it does |
|---|---|---|---|
slotCount | int | 6 | How many stacks this container can hold. |
guaranteedItems | List<GuaranteedLoot> | — | Items always present on every fill, before the loot table rolls. Each entry is an item and a count. |
lootTable | LootTable | — | The randomized part of the contents — rolled deterministically on every machine. |
lootSeed | int | 0 | Seed salt, so two identical chests standing in one scene roll different loot. |
exclusiveAccess | bool | false | Only one player may have this container open at a time; others are blocked, and cannot take, until it closes. Off is free-for-all looting. |
promptFormat | string | "[E] Open ({0})" | Prompt written to the sibling InteractableBehaviour. {0} is the non-empty stack count. |
promptEmptyText | string | "[E] Open (empty)" | Prompt shown while the container is empty. |
Loot tables
A LootTableasset is a weighted pool plus a number of rolls. Each roll picks one entry in proportion to its weight and produces a count somewhere in that entry's range.
| Field | Type | Default | What it does |
|---|---|---|---|
entries | Entry[] | — | The weighted pool. Each entry names an item, its weight, and the minimum and maximum count it yields. |
rolls | int | 3 | How many times the pool is drawn from per fill. |
Entry.weight | float | 1 | Relative likelihood of this entry being picked. Weights are relative to each other, not percentages. |
Entry.minCount | int | 1 | Fewest of this item a single roll can yield. |
Entry.maxCount | int | 1 | Most of this item a single roll can yield. |
Building a chest
Author the loot
Create → Party Core Kit → Inventory → Loot Table. Add entries with weights and count ranges.Put the two components on the chest
WorldInventoryfor the contents, and anInteractableBehaviournext to it for the prompt. Assign the loot table, and any guaranteed items.Point the interaction at the container
Add an Open Container instruction to the interactable'sonInteractlist — it is under World / Containersin the picker. That opens — or closes, if it is already showing this container — the interacting player's container window.Decide who may loot it
TickexclusiveAccessfor one-at-a-time chests; leave it off for free-for-all. This is a design decision the kit deliberately does not make for you.
Three stock instructions cover the container verbs, and they are all composable with conditions the same way anything else is:
| Field | Type | What it does |
|---|---|---|
Open Container | instruction | Opens the container window for the interacting player — a grid of the container's items with a details pane, click to take. Pressing again closes it. |
Take From Container | instruction | Takes the next stack straight into the player's inventory, with no window at all. This is the grab-all shape: a corpse you sweep, a bag you scoop up. |
Deposit Into Container | instruction | Puts a player-held stack into the container — clicking an inventory item while the chest is open. The mirror of taking. |
Interacting from code
Most interactions never need code. Where they do — a cutscene that presses a button, a bot that opens a door — the interactor exposes exactly two things, and it is worth reading them together:
using Curitor.PartyCoreKit.Scripting;
using UnityEngine;
public class ScriptedDoorOpener : MonoBehaviour
{
[SerializeField] private PlayerInteractor interactor;
private void OpenWhateverIsInFront()
{
// What would the prompt be pointing at right now?
if (interactor.Nearest == null) return;
// Take the wheel: real player input stops driving this interactor.
interactor.SetProgrammaticControl(true);
// Then press -- and release, since a Hold interaction needs both.
interactor.SetInteractPressed(true);
}
private void Release()
{
interactor.SetInteractPressed(false);
interactor.SetProgrammaticControl(false);
}
}