mirror of
https://github.com/TemujinCalidius/SurvivorCore.git
synced 2026-08-14 09:02:29 +00:00
Wire the demo video (makertube uSGJ2MHEFjSSKxMiJBJ6Y5) into quests.md, achievements.md, content-authoring.md and admin-plugin.md, and feature it in the landing page's video grid (replacing the oldest embed; that video stays linked from docs/inventory.md). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
82 lines
3.2 KiB
Markdown
82 lines
3.2 KiB
Markdown
# Achievements
|
|
|
|
> 📹 **Demo:** [quests, achievements & the no-code editors in action](https://makertube.net/w/uSGJ2MHEFjSSKxMiJBJ6Y5)
|
|
|
|
The achievement system ([`src/systems/Achievements.luau`](../src/systems/Achievements.luau)) tracks
|
|
**milestones**: always-on counters that unlock a badge (once) when they cross a threshold — with a
|
|
toast and an Achievements menu tab. The architecture is ported from The Counter Earth's proven
|
|
achievement service, made content-free.
|
|
|
|
> Progress is **session-scoped** (Player attributes) — persistence (DataStore) is a future system.
|
|
|
|
## Defining an achievement
|
|
|
|
Defs are **flat** — the same shape in code and [no-code](content-authoring.md):
|
|
|
|
```lua
|
|
SurvivorCore.Achievements.register({
|
|
key = "husk_slayer",
|
|
name = "Husk Slayer",
|
|
description = "Slay 3 husks.",
|
|
counter = "kills_husk", -- which counter unlocks it (see the catalogue below)
|
|
threshold = 3,
|
|
-- icon = "rbxassetid://…",
|
|
})
|
|
```
|
|
|
|
## The Progression stream
|
|
|
|
One shared layer ([`src/systems/Progression.luau`](../src/systems/Progression.luau)) subscribes to
|
|
the EventBridge and translates gameplay events into `(player, kind, target, amount)` progress —
|
|
consumed by **both** achievements (counters) and [quests](quests.md) (objectives). Built-in:
|
|
|
|
| Event | kind | target | amount |
|
|
|---|---|---|---|
|
|
| `gather:hit` | `gather` | the item id | amount granted |
|
|
| `craft:end` | `craft` | the output item id | output count |
|
|
| `mob:died` (with a killer) | `kill` | the mob type | 1 |
|
|
| `item:use` | `use` | the item id | 1 |
|
|
| `quest:completed` | `quest` | the quest id | 1 |
|
|
|
|
### Counter catalogue (the naming rule)
|
|
|
|
Every progress tick bumps `"<kind>s_total"` and `"<kind>s_<target>"`:
|
|
|
|
`gathers_total` · `gathers_reed` · `crafts_total` · `crafts_reed_basket` · `kills_total` ·
|
|
`kills_husk` · `uses_total` · `uses_berry` · `quests_total` · `quests_<questId>` — author any
|
|
achievement against any of these, no code.
|
|
|
|
### Custom events & counters (code)
|
|
|
|
```lua
|
|
-- Teach the stream a game event (then author achievements against boss counters):
|
|
SurvivorCore.Progression.map("myGame:bossDown", function(player, data)
|
|
return "kill", data.bossId, 1
|
|
end)
|
|
|
|
-- Or bump a bespoke counter / award directly:
|
|
SurvivorCore.Achievements.addCount(player, "shrines_visited", 1)
|
|
SurvivorCore.Achievements.award(player, "secret_cave")
|
|
```
|
|
|
|
## Runtime API
|
|
|
|
`SurvivorCore.Achievements` (registry always; runtime ops after `start()`): `award(player, key)`,
|
|
`addCount(player, counterId, n?)`, `isUnlocked(player, key)`, `getState(player)`. Unlocks fire the
|
|
`achievement:unlocked` hook + EventBridge event and a toast (config-gated).
|
|
|
|
## The Achievements tab & data
|
|
|
|
The menu's **Achievements** tab (key **J**) lists every def with a progress bar toward its
|
|
threshold; unlocked rows go gold. Defs replicate via `SurvivorCoreAchievementData`; per-player state
|
|
is the `AchievementState` JSON attribute (`{ c = { [counter] = n }, u = { [key] = true } }`) — both
|
|
readable via [`src/shared/AchievementData.luau`](../src/shared/AchievementData.luau).
|
|
|
|
## Tuning
|
|
|
|
`Config.override("Achievements", { Toasts = true })`.
|
|
|
|
---
|
|
|
|
See also: [Quests](quests.md) · [No-code content](content-authoring.md) · [Extending](extending.md).
|