Files
SurvivorCore/docs/content-authoring.md

151 lines
8.2 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# No-code content authoring
> 📹 **Demos:** [creating quests & achievements](https://makertube.net/w/uSGJ2MHEFjSSKxMiJBJ6Y5) · [creating mobs, weapons & ammo](https://makertube.net/w/tyn8JEMG3CaMbTXid8osdU) · [creating an item + gatherable](https://makertube.net/w/mCneurjoY3Av6yi48VsGQE) · [hunting, butchering & loot bags](https://makertube.net/w/oVJwYUhCKxA2ZvgvocdhwZ)
The engine ships **zero** items, resources, or recipes — your game supplies them. You can do this
two ways, and they coexist:
1. **From code**`SurvivorCore.Items.register{…}`, `SurvivorCore.Resources.register{…}`,
`SurvivorCore.Recipes.register{…}` before `start()` (see the demo `Boot.server.luau`).
2. **No-code, as instances** — author content in the place and the engine loads it at `start()`.
The **admin plugin's Content widget** writes exactly this for you.
## The `SurvivorCoreContent` folder
At `start()`, the engine reads `ReplicatedStorage.SurvivorCoreContent` and registers any defs found:
```
ReplicatedStorage
└─ SurvivorCoreContent
├─ Items (Folder)
│ └─ berry (Configuration) ← child Name = item id
│ • name = "Wild Berries" ← attributes = def fields
│ • stack = 20
│ • weight = 0.05
│ • category = "consumable"
├─ Weapons (Folder) ← items with category="weapon" (loaded into the Items registry)
│ └─ wood_club (Configuration)
│ • category = "weapon"
│ • toolType = "club" (lets the hotbar equip it)
│ • weaponKind = "melee" ("melee" | "bow")
│ • weaponDamage = 20
├─ Arrows (Folder) ← items with category="ammo" (loaded into the Items registry)
│ └─ heavy_arrow (Configuration)
│ • category = "ammo"
│ • ammoDamage = 1.4 (× the bow's damage)
│ • ammoDrop = 2 (× gravity = the curve)
│ • ammoRange = 140
├─ Resources (Folder)
│ └─ berry_bush (Configuration)
│ • item = "berry"
│ • hp = 4
│ • requireTool = "" (blank = bare-hand)
│ • yieldMin = 1
│ • yieldMax = 3
├─ Mobs (Folder)
│ └─ husk (Configuration)
│ • faction = "hostile" ("hostile" | "passive" | "neutral")
│ • health = 60
│ • aggroRange = 40
│ • carcassItem = "raw_meat" (hunting: blank = no carcass; see docs/mobs.md)
│ • carcassTool = "knife"
├─ Quests (Folder) ← flat single-objective quests (normalized at load)
│ └─ gather_reeds (Configuration)
│ • name = "Gather Reeds"
│ • objectiveType = "gather" ("gather" | "craft" | "kill" | "use")
│ • objectiveTarget = "reed"
│ • objectiveCount = 3
│ • rewardItem = "berry"
│ • rewardCount = 2
│ • autoStart = true
├─ Achievements (Folder) ← flat counter + threshold defs
│ └─ husk_slayer (Configuration)
│ • name = "Husk Slayer"
│ • counter = "kills_husk" (see docs/achievements.md for the counter catalogue)
│ • threshold = 3
├─ Tools (Folder) ← Tool templates the hotbar equips (named by item id)
├─ MobModels (Folder) ← rigged mob templates Mobs.spawn clones (named by mob id)
├─ Carcasses (Folder) ← carcass models spawned on mob death (named by mob id)
└─ LootBag (Model/Part) ← the death loot-bag look (optional; placeholder otherwise)
```
Each child's **Name is the id**; its **attributes are the def fields**
([`Registry.loadFromFolder`](../src/foundation/Registry.luau) copies them verbatim). This is the
same instance-config pattern the survival stats use.
## The admin plugin Content widget
Open Studio → the **SurvivorCore** toolbar → **Content**. Seven builders:
- **Items** — create an item by id, then set Name / Max stack / Weight / Category / Tool type /
Icon / Description.
- **Weapons** — create a weapon by id, then set Kind (melee/bow) / Damage / Range / Cooldown, plus
bow Draw time / Arrow speed / Max range / Ammo item. (Weapons are items with `category = "weapon"`;
they live in their own folder so this editor never collides with the Items editor.) **+ Tool model**
drops a starter `Tool` (a Handle carrying the weapon's `ToolType`/`WeaponKind`) into the world so you
can build the held look on it; move the finished Tool under `SurvivorCoreContent.Tools` (named by the
weapon id) and the hotbar clones it when the weapon is equipped.
- **Arrows / Ammo** — create an arrow type by id, then set Damage × / Drop (curve) × / Max range /
Speed × / Carry weight. A bow's *Ammo item* points at one of these. (Arrows are items with
`category = "ammo"`, in their own folder — see [combat.md](combat.md).)
- **Gatherables** — create a resource by id, then set Yields item / HP (gathers) / Tool required /
Yield min / Yield max. **+ Add to World** drops a tagged `Gatherable` node.
- **Mobs** — create a mob type by id, then set Faction / Health / Speeds / Aggro / Leash / Attack.
**+ Add to World** drops a tagged `Mob` placeholder rig (swap in your own model later).
- **Quests** — create a quest by id, then set Name / Description / Objective (type, target, count) /
Reward (item, count) / Auto-start / Requires / Turn in. **+ Quest giver** drops a tagged
`QuestGiver` post offering it (see [quests.md](quests.md)). Multi-objective chains stay
code-authored, like recipes.
- **Achievements** — create an achievement by key, then set Name / Description / Counter /
Threshold / Icon — counters are the engine's auto-derived progression counters
(see [achievements.md](achievements.md)).
Each edit is one Studio **undo** step. Behind the scenes it creates/edits the
`SurvivorCoreContent` instances above, so pressing Play registers your content with no code.
## Overrides — tune code-registered defs without code
The authoring folders above can't touch a def that was registered **from code** (the engine's
loader skips already-registered ids — code wins). The **`Overrides`** folder can:
```text
SurvivorCoreContent/
└─ Overrides (Folder) ← mirrors the category folders above
└─ Items (Folder)
└─ berry (Configuration) ← name of a CODE-registered def
• name = "Sweet Berries" (ONLY the fields you change)
• stack = 99
```
At `start()` the engine **field-merges** each override's attributes onto the registered def —
before components bind and before the client data caches publish, so tooltips/recipes/gatherables
all see the merged values. Rules:
- **Deltas-only**: an override carries only the attributes it changes; anything absent inherits
the code value. Deleting the override restores the pristine code def on the next Play.
- The **id can't be renamed** by an override, and an id matching **no registered def warns in
Output on Play** (`override 'x' matches no registered def`) — your typo backstop.
- **Quest caveat**: a code-registered quest with nested objective/reward tables ignores the flat
`objective*`/`reward*` override fields (name/description/autoStart/requires/turnIn still merge).
Overrides of no-code quests merge fully.
The admin plugin's category pages author these for you (**+ Override**, blue pill, blank = inherit)
— see [admin-plugin.md](admin-plugin.md).
## Binding a world object
A creator builds any mesh, tags it **`Gatherable`** (CollectionService), and sets a `Resource`
attribute to a resource id (e.g. `"berry_bush"`). The node inherits item/HP/tool/yield from the def.
See [harvesting.md](harvesting.md) for the full attribute list and the per-type **reaction** hooks
(shake / fell / etc.).
For creatures, tag a rigged Model (Humanoid + PrimaryPart) **`Mob`** and set `MobType` to a mob id
(e.g. `"husk"`); it inherits faction/health/speed/ranges from the def. See [mobs.md](mobs.md) and
[combat.md](combat.md).
## Tools
For a tool item, set `toolType` (e.g. `"axe"`) and `category = "tool"`. To give it a custom look,
place a `Tool` named by the item id under `SurvivorCoreContent.Tools`; otherwise the engine equips a
plain default. Trees etc. require the matching `RequireTool`.