Gameplay · guide
Interactables, gathering and crafting
One channelled system for mining, looting, reading and pulling levers, with a claim that stops two players finishing the same rock — and recipes over it, whose stations are tag queries.
Edit this page on GitHubDocuments
- InteractionInstancing
- InterruptOn
- InteractionRefusal
- InteractableDefinition
- Interactable
- InteractionLibrary
- Channel
- InteractionResult
- InteractionNode
- InteractionModule
- RecipeSource
- CraftingRefusal
- RecipeItemDefinition
- RecipeDefinition
- RecipeItem
- Recipe
- CraftingResult
- CraftingLibrary
- Crafter
- CraftingModule
What it is
An InteractableDefinition is a thing you use: a node, a chest, a door, a lever, a forge. An
InteractionNode is one of them in the world — how much is left of it and who is on it. A
Recipe is inputs, a station and outputs, and a Crafter is one character's knowledge of
them.
What it is for
Doc 28 calls interaction "the grinding loop" and crafting "recipes over that". Mining a node, smelting at a forge, opening a chest, reading a book, flipping a lever and picking a herb are one system with different definitions.
Using it
Compile the two libraries, make an InteractionNode per thing in the world, and Begin, Disturb
and Complete. For crafting, Learn, CanCraft and Craft.
⚠ A shared node is claimed for the duration of a channel — without it two players both finish and it yields twice.
⚠ Interruption consumes nothing, and respawn counts from the completion that emptied it rather than from the last attempt.
⚠ Per-player instancing puts the uses on the player, which is the answer to node-stealing.
⚠ A station is a tag query, so an enchanted forge satisfies a recipe that asks for a forge.
Vixen.Gameplay.Crafting does not reference Vixen.Gameplay.Interaction: what it borrows is the
shape, not the code.
⚠ Discovery is an exact match on the ingredients, or throwing everything in the pot discovers everything. ⚠ Skill gain falls linearly to nothing across a band, or the last recipe before a cliff is the only one anybody makes.
⚠ Neither library moves anything. A node reports what it yields and a craft reports what to consume; the caller's containers do the rest.
Examples
A node and a recipe:
# Assets/World/copper-vein.vxdef!InteractableDefinitiondisplayName: Copper veintag: Interactable.Node.Oreverb: MinechannelSeconds: 3uses: 2respawnSeconds: 120yields: loot/copperrequires: [ { kind: Value, subject: Profession.Mining, comparison: AtLeast, value: 25 } ]# Assets/Recipes/copper-bar.vxdef!RecipeDefinitiondisplayName: Copper barprofession: Profession.Smithingstation: Interactable.Station.Forgeinputs: [ { item: items/copper-ore, count: 2 } ]outputs: [ { item: items/copper-bar } ]skillRequired: 0skillCap: 100skillGain: 4Mining it:
using Vixen.Gameplay;using Vixen.Gameplay.Interaction;static class Mining { public static InteractionRefusal Swing(InteractionNode vein, PlayerId who, float now) => // Claimed from here until it completes, is interrupted, or the claimant walks off. vein.Begin(who, now); public static bool Hit(InteractionNode vein) => // The definition says whether being hit stops it; nothing is consumed either way. vein.Disturb(InterruptOn.Damage); public static DefId Finish(InteractionNode vein, PlayerId who, float now) => vein.Complete(who, now, out var result) == InteractionRefusal.None ? result.Yields : DefId.None;}Crafting, and finding something by experiment:
using Vixen.Gameplay;using Vixen.Gameplay.Crafting;static class Forge { public static CraftingResult? Smelt( Crafter smith, Recipe bar, GameplayTagSet station, IReadOnlyDictionary<uint, int> holdings, ulong attempt ) => smith.Craft(bar, station, holdings, attempt, out var result) == CraftingRefusal.None ? result : null; public static Recipe? Experiment(Crafter smith, IReadOnlyList<RecipeItem> pot) => // An exact match — a superset would discover everything at once. smith.TryDiscover(pot, out var found) ? found : null;}See also
- Loot — what a node's
yieldsaddress names. - Progression — what answers a recipe's skill.
- Requirements — what gates both.