Add TOML reference docs for all world data types
- world/MANIFEST.md: manifest.toml and directory layout - world/races/RACES.md: race schema (stats, body, natural, resistances, etc.) - world/classes/CLASSES.md: class schema (base_stats, growth, hidden, guild) - world/guilds/GUILDS.md: guild schema and [growth] - world/spells/SPELLS.md: spell schema and types - world/town/REGION.md: region.toml - world/town/rooms/ROOMS.md: room schema and exits - world/town/npcs/NPCS.md: NPC schema, race/class resolution - world/town/objects/OBJECTS.md: object schema and [stats] Made-with: Cursor
This commit is contained in:
34
world/MANIFEST.md
Normal file
34
world/MANIFEST.md
Normal file
@@ -0,0 +1,34 @@
|
||||
# World Manifest Reference
|
||||
|
||||
The file `world/manifest.toml` defines the world identity and spawn location. There is exactly one manifest per world.
|
||||
|
||||
## Fields
|
||||
|
||||
| Field | Type | Required | Description |
|
||||
|-------|------|----------|-------------|
|
||||
| `name` | string | Yes | World name (e.g. shown at login). |
|
||||
| `spawn_room` | string | Yes | Full room ID where new characters and respawned dead characters appear (e.g. `"town:town_square"`). Must reference an existing room. |
|
||||
|
||||
## Example
|
||||
|
||||
```toml
|
||||
name = "The Shattered Realm"
|
||||
spawn_room = "town:town_square"
|
||||
```
|
||||
|
||||
## Directory layout
|
||||
|
||||
The loader expects (under `world/`):
|
||||
|
||||
- `manifest.toml` — this file
|
||||
- `races/*.toml` — race definitions (see `races/RACES.md`)
|
||||
- `classes/*.toml` — class definitions (see `classes/CLASSES.md`)
|
||||
- `guilds/*.toml` — guild definitions (see `guilds/GUILDS.md`)
|
||||
- `spells/*.toml` — spell definitions (see `spells/SPELLS.md`)
|
||||
- `<region>/` — one folder per region (e.g. `town/`), each containing:
|
||||
- `region.toml` — region metadata (see `town/REGION.md`)
|
||||
- `rooms/*.toml` — rooms (see `town/rooms/ROOMS.md`)
|
||||
- `npcs/*.toml` — NPCs (see `town/npcs/NPCS.md`)
|
||||
- `objects/*.toml` — objects (see `town/objects/OBJECTS.md`)
|
||||
|
||||
Folder names `races`, `classes`, `guilds`, and `spells` are reserved; other top-level directories are treated as regions.
|
||||
64
world/classes/CLASSES.md
Normal file
64
world/classes/CLASSES.md
Normal file
@@ -0,0 +1,64 @@
|
||||
# Class TOML Reference
|
||||
|
||||
Each file in `world/classes/` defines one class. The filename (without `.toml`) becomes the class ID with prefix `class:` (e.g. `warrior.toml` → `class:warrior`).
|
||||
|
||||
## Top-level fields
|
||||
|
||||
| Field | Type | Required | Default | Description |
|
||||
|-------|------|----------|---------|-------------|
|
||||
| `name` | string | Yes | — | Display name of the class. |
|
||||
| `description` | string | Yes | — | Short description shown in chargen. |
|
||||
| `hidden` | boolean | No | `false` | If `true`, the class does not appear in character creation. Use for NPC-only classes (e.g. Peasant, Creature). |
|
||||
| `guild` | string | No | — | Guild ID (e.g. `"guild:warriors_guild"`). If set, new characters who choose this class automatically join this guild at level 1 and receive that guild’s base mana/endurance. |
|
||||
|
||||
## `[base_stats]` — Starting stats at level 1
|
||||
|
||||
| Field | Type | Required | Default | Description |
|
||||
|-------|------|----------|---------|-------------|
|
||||
| `max_hp` | integer | No | `0` | Base maximum HP before race/stat modifiers. |
|
||||
| `attack` | integer | No | `0` | Base attack before modifiers. |
|
||||
| `defense` | integer | No | `0` | Base defense before modifiers. |
|
||||
|
||||
## `[growth]` — Per-level gains
|
||||
|
||||
| Field | Type | Required | Default | Description |
|
||||
|-------|------|----------|---------|-------------|
|
||||
| `hp_per_level` | integer | No | `0` | HP added each level. |
|
||||
| `attack_per_level` | integer | No | `0` | Attack added each level. |
|
||||
| `defense_per_level` | integer | No | `0` | Defense added each level. |
|
||||
|
||||
## Minimal example (hidden NPC class)
|
||||
|
||||
```toml
|
||||
name = "Peasant"
|
||||
description = "A common folk with no particular training."
|
||||
hidden = true
|
||||
|
||||
[base_stats]
|
||||
max_hp = 50
|
||||
attack = 4
|
||||
defense = 4
|
||||
|
||||
[growth]
|
||||
hp_per_level = 5
|
||||
attack_per_level = 1
|
||||
defense_per_level = 1
|
||||
```
|
||||
|
||||
## Example with guild (playable class)
|
||||
|
||||
```toml
|
||||
name = "Warrior"
|
||||
description = "Masters of arms and armor."
|
||||
guild = "guild:warriors_guild"
|
||||
|
||||
[base_stats]
|
||||
max_hp = 120
|
||||
attack = 14
|
||||
defense = 12
|
||||
|
||||
[growth]
|
||||
hp_per_level = 15
|
||||
attack_per_level = 3
|
||||
defense_per_level = 2
|
||||
```
|
||||
58
world/guilds/GUILDS.md
Normal file
58
world/guilds/GUILDS.md
Normal file
@@ -0,0 +1,58 @@
|
||||
# Guild TOML Reference
|
||||
|
||||
Each file in `world/guilds/` defines one guild. The filename (without `.toml`) becomes the guild ID with prefix `guild:` (e.g. `warriors_guild.toml` → `guild:warriors_guild`).
|
||||
|
||||
## Top-level fields
|
||||
|
||||
Put these **before** any `[section]` headers so they are not parsed as part of a table.
|
||||
|
||||
| Field | Type | Required | Default | Description |
|
||||
|-------|------|----------|---------|-------------|
|
||||
| `name` | string | Yes | — | Display name of the guild. |
|
||||
| `description` | string | Yes | — | Short description. |
|
||||
| `max_level` | integer | No | `50` | Maximum guild level. |
|
||||
| `resource` | string | No | `"mana"` | Primary resource: `"mana"` or `"endurance"`. |
|
||||
| `base_mana` | integer | No | `0` | Mana granted when joining (and per new member level if used). |
|
||||
| `base_endurance` | integer | No | `0` | Endurance granted when joining. |
|
||||
| `spells` | array of strings | No | `[]` | Spell IDs (e.g. `"spell:power_strike"`) this guild grants. Order can matter for display. |
|
||||
| `min_player_level` | integer | No | `0` | Minimum character level required to join. |
|
||||
| `race_restricted` | array of strings | No | `[]` | Race IDs (e.g. `"race:dragon"`) that cannot join this guild. |
|
||||
|
||||
## `[growth]` — Per guild-level gains
|
||||
|
||||
| Field | Type | Required | Default | Description |
|
||||
|-------|------|----------|---------|-------------|
|
||||
| `hp_per_level` | integer | No | `0` | HP per guild level. |
|
||||
| `mana_per_level` | integer | No | `0` | Mana per guild level. |
|
||||
| `endurance_per_level` | integer | No | `0` | Endurance per guild level. |
|
||||
| `attack_per_level` | integer | No | `0` | Attack per guild level. |
|
||||
| `defense_per_level` | integer | No | `0` | Defense per guild level. |
|
||||
|
||||
## Important: TOML layout
|
||||
|
||||
Top-level keys such as `spells`, `min_player_level`, and `race_restricted` must appear **before** the `[growth]` section. Otherwise they are parsed as part of `[growth]` and ignored.
|
||||
|
||||
## Example
|
||||
|
||||
```toml
|
||||
name = "Warriors Guild"
|
||||
description = "Masters of martial combat."
|
||||
max_level = 50
|
||||
resource = "endurance"
|
||||
base_mana = 0
|
||||
base_endurance = 50
|
||||
spells = ["spell:power_strike", "spell:battle_cry", "spell:shield_wall", "spell:whirlwind"]
|
||||
min_player_level = 0
|
||||
race_restricted = []
|
||||
|
||||
[growth]
|
||||
hp_per_level = 8
|
||||
mana_per_level = 0
|
||||
endurance_per_level = 5
|
||||
attack_per_level = 2
|
||||
defense_per_level = 1
|
||||
```
|
||||
|
||||
## Spell IDs
|
||||
|
||||
Spell IDs are the spell’s file stem with prefix `spell:` (e.g. `world/spells/power_strike.toml` → `spell:power_strike`). Spells are defined in `world/spells/*.toml`; see `world/spells/SPELLS.md`.
|
||||
117
world/races/RACES.md
Normal file
117
world/races/RACES.md
Normal file
@@ -0,0 +1,117 @@
|
||||
# Race TOML Reference
|
||||
|
||||
Each file in `world/races/` defines one race. The filename (without `.toml`) becomes the race ID with prefix `race:` (e.g. `human.toml` → `race:human`).
|
||||
|
||||
## Top-level fields
|
||||
|
||||
| Field | Type | Required | Default | Description |
|
||||
|-------|------|----------|---------|-------------|
|
||||
| `name` | string | Yes | — | Display name of the race. |
|
||||
| `description` | string | Yes | — | Short description shown in chargen and elsewhere. |
|
||||
| `metarace` | string | No | — | Category (e.g. `"animal"`, `"draconic"`). Used for flavour and filtering; NPCs without a fixed race are chosen from races that are not hidden (metarace does not exclude them from random NPC pool). |
|
||||
| `hidden` | boolean | No | `false` | If `true`, the race does not appear in character creation. Use for NPC-only races (e.g. Beast). |
|
||||
| `default_class` | string | No | — | Class ID (e.g. `"class:peasant"`) used as the default class for NPCs of this race when the NPC has no fixed class. Omit for “random compatible class” (e.g. Dragon). |
|
||||
|
||||
## `[stats]` — Stat modifiers
|
||||
|
||||
All values are integers applied as modifiers (e.g. +1, -2). Defaults are `0` if omitted.
|
||||
|
||||
| Field | Description |
|
||||
|-------|-------------|
|
||||
| `strength` | STR modifier. |
|
||||
| `dexterity` | DEX modifier. |
|
||||
| `constitution` | CON modifier. |
|
||||
| `intelligence` | INT modifier. |
|
||||
| `wisdom` | WIS modifier. |
|
||||
| `perception` | PER modifier. |
|
||||
| `charisma` | CHA modifier. |
|
||||
|
||||
## `[body]`
|
||||
|
||||
| Field | Type | Required | Default | Description |
|
||||
|-------|------|----------|---------|-------------|
|
||||
| `size` | string | No | `"medium"` | One of: `"tiny"`, `"small"`, `"medium"`, `"large"`, `"huge"`. Flavour and potential future rules. |
|
||||
| `weight` | integer | No | `0` | Weight in arbitrary units. |
|
||||
| `slots` | array of strings | No | humanoid default | Equipment slot names this race can use. If empty, default humanoid slots are used: `head`, `neck`, `torso`, `legs`, `feet`, `main_hand`, `off_hand`, `finger`, `finger`. |
|
||||
|
||||
## `[natural]` — Natural armor and attacks
|
||||
|
||||
| Field | Type | Required | Default | Description |
|
||||
|-------|------|----------|---------|-------------|
|
||||
| `armor` | integer | No | `0` | Natural armor bonus added to defense. |
|
||||
|
||||
### `[natural.attacks.<name>]`
|
||||
|
||||
Each key under `natural.attacks` defines one natural attack (e.g. `bite`, `claw`, `fire_breath`).
|
||||
|
||||
| Field | Type | Required | Default | Description |
|
||||
|-------|------|----------|---------|-------------|
|
||||
| `damage` | integer | No | `0` | Base damage. |
|
||||
| `type` | string | No | `"physical"` | Damage type (e.g. `"physical"`, `"fire"`, `"magical"`). |
|
||||
| `cooldown_ticks` | integer | No | — | If set, minimum ticks between uses of this attack. |
|
||||
|
||||
## `[resistances]`
|
||||
|
||||
Map of damage type → multiplier (float).
|
||||
|
||||
- `0.0` = immune
|
||||
- `1.0` = normal
|
||||
- `1.5` = vulnerable (e.g. 50% more damage)
|
||||
- `< 1.0` = resistant (e.g. `0.5` = half damage)
|
||||
|
||||
Example: `fire = 0.0`, `cold = 1.5`, `physical = 0.7`
|
||||
|
||||
## `traits` and `disadvantages`
|
||||
|
||||
Top-level arrays of strings (free-form). Shown in chargen and used for flavour.
|
||||
|
||||
- `traits` — e.g. `["darkvision", "lucky"]`
|
||||
- `disadvantages` — e.g. `["light_sensitivity"]`
|
||||
|
||||
## `[regen]` — Regeneration multipliers
|
||||
|
||||
Multipliers applied to passive HP/mana/endurance regen. Float; default `1.0`.
|
||||
|
||||
| Field | Description |
|
||||
|-------|-------------|
|
||||
| `hp` | HP regen multiplier. |
|
||||
| `mana` | Mana regen multiplier. |
|
||||
| `endurance` | Endurance regen multiplier. |
|
||||
|
||||
## `[guild_compatibility]`
|
||||
|
||||
Used when picking a random class for NPCs (and potentially future guild rules). Guild IDs in each list are string identifiers (e.g. `"guild:warriors_guild"`).
|
||||
|
||||
| Field | Description |
|
||||
|-------|-------------|
|
||||
| `good` | Guilds this race is well suited to. |
|
||||
| `average` | Guilds with no special modifier. |
|
||||
| `poor` | Guilds this race is poorly suited to. |
|
||||
| `restricted` | Guilds this race cannot join. |
|
||||
|
||||
All default to empty arrays.
|
||||
|
||||
## `[misc]`
|
||||
|
||||
| Field | Type | Required | Default | Description |
|
||||
|-------|------|----------|---------|-------------|
|
||||
| `lifespan` | integer | No | — | Flavour lifespan. |
|
||||
| `diet` | string | No | — | Flavour diet (e.g. `"omnivore"`, `"carnivore"`). |
|
||||
| `xp_rate` | float | No | `1.0` | Multiplier for XP gain (e.g. `0.7` = slower leveling). |
|
||||
| `natural_terrain` | array of strings | No | `[]` | Flavour terrain list. |
|
||||
| `vision` | array of strings | No | `[]` | Vision types (e.g. `["normal", "darkvision", "infravision"]`). |
|
||||
|
||||
## Minimal example
|
||||
|
||||
```toml
|
||||
name = "Human"
|
||||
description = "Versatile and adaptable."
|
||||
default_class = "class:peasant"
|
||||
|
||||
[stats]
|
||||
charisma = 1
|
||||
```
|
||||
|
||||
## Full example (excerpt)
|
||||
|
||||
See `dragon.toml` for a race using body slots, natural attacks, resistances, regen, and guild compatibility.
|
||||
85
world/spells/SPELLS.md
Normal file
85
world/spells/SPELLS.md
Normal file
@@ -0,0 +1,85 @@
|
||||
# Spell TOML Reference
|
||||
|
||||
Each file in `world/spells/` defines one spell or skill. The filename (without `.toml`) becomes the spell ID with prefix `spell:` (e.g. `magic_missile.toml` → `spell:magic_missile`). Spells are referenced from guilds in `world/guilds/*.toml`.
|
||||
|
||||
## Top-level fields
|
||||
|
||||
| Field | Type | Required | Default | Description |
|
||||
|-------|------|----------|---------|-------------|
|
||||
| `name` | string | Yes | — | Display name. |
|
||||
| `description` | string | Yes | — | Short description shown in `spells` and `guild info`. |
|
||||
| `spell_type` | string | No | `"offensive"` | One of: `"offensive"`, `"heal"`, `"utility"`. Affects when and how the spell can be used (e.g. heal/utility out of combat; offensive usually in combat). |
|
||||
| `damage` | integer | No | `0` | Base damage for offensive spells. |
|
||||
| `heal` | integer | No | `0` | HP restored for heal spells. |
|
||||
| `damage_type` | string | No | `"magical"` | Damage type (e.g. `"physical"`, `"fire"`, `"magical"`, `"holy"`, `"poison"`). |
|
||||
| `cost_mana` | integer | No | `0` | Mana cost to cast. |
|
||||
| `cost_endurance` | integer | No | `0` | Endurance cost to cast. |
|
||||
| `cooldown_ticks` | integer | No | `0` | Ticks before the spell can be used again. |
|
||||
| `casting_ticks` | integer | No | `0` | Ticks before the spell resolves (future use; currently casting is one tick). |
|
||||
| `min_guild_level` | integer | No | `0` | Minimum guild level required to know/use this spell. |
|
||||
| `effect` | string | No | — | Status effect kind applied (e.g. `"poison"`, `"regen"`, `"defense_up"`). |
|
||||
| `effect_duration` | integer | No | `0` | Duration of the effect in ticks. |
|
||||
| `effect_magnitude` | integer | No | `0` | Magnitude (e.g. damage per tick for poison, heal per tick for regen). |
|
||||
|
||||
## Spell types
|
||||
|
||||
- **offensive** — Deals damage to current combat target. Requires combat; blocked out of combat.
|
||||
- **heal** — Restores HP. Can be used in or out of combat; out of combat resolves immediately.
|
||||
- **utility** — Buffs, cleanses, etc. Can apply status effects; out of combat resolves immediately.
|
||||
|
||||
## Examples
|
||||
|
||||
**Offensive (mana):**
|
||||
|
||||
```toml
|
||||
name = "Magic Missile"
|
||||
description = "Hurl bolts of pure arcane energy."
|
||||
spell_type = "offensive"
|
||||
damage = 15
|
||||
damage_type = "magical"
|
||||
cost_mana = 10
|
||||
cooldown_ticks = 1
|
||||
min_guild_level = 1
|
||||
```
|
||||
|
||||
**Heal:**
|
||||
|
||||
```toml
|
||||
name = "Heal"
|
||||
description = "Channel divine energy to mend wounds."
|
||||
spell_type = "heal"
|
||||
heal = 25
|
||||
cost_mana = 15
|
||||
cooldown_ticks = 2
|
||||
min_guild_level = 1
|
||||
```
|
||||
|
||||
**Utility with effect:**
|
||||
|
||||
```toml
|
||||
name = "Battle Cry"
|
||||
description = "A thunderous war shout that steels your resolve."
|
||||
spell_type = "utility"
|
||||
cost_endurance = 10
|
||||
cooldown_ticks = 10
|
||||
min_guild_level = 3
|
||||
effect = "regen"
|
||||
effect_duration = 5
|
||||
effect_magnitude = 4
|
||||
```
|
||||
|
||||
**Offensive with DoT:**
|
||||
|
||||
```toml
|
||||
name = "Poison Blade"
|
||||
description = "Coat your weapon with virulent toxin."
|
||||
spell_type = "offensive"
|
||||
damage = 8
|
||||
damage_type = "poison"
|
||||
cost_endurance = 10
|
||||
cooldown_ticks = 6
|
||||
min_guild_level = 3
|
||||
effect = "poison"
|
||||
effect_duration = 4
|
||||
effect_magnitude = 3
|
||||
```
|
||||
28
world/town/REGION.md
Normal file
28
world/town/REGION.md
Normal file
@@ -0,0 +1,28 @@
|
||||
# Region TOML Reference
|
||||
|
||||
Each region is a directory under `world/` (e.g. `world/town/`) containing a `region.toml` file. The directory name is the region ID (e.g. `town`). Room, NPC, and object IDs in this region are prefixed with `"<region>:"` (e.g. `town:tavern`).
|
||||
|
||||
## Fields
|
||||
|
||||
| Field | Type | Required | Description |
|
||||
|-------|------|----------|-------------|
|
||||
| `name` | string | Yes | Display name of the region (e.g. for logs or future use). |
|
||||
|
||||
Additional keys (e.g. `description`) may be present in the file; only `name` is required by the loader.
|
||||
|
||||
## Example
|
||||
|
||||
```toml
|
||||
name = "Thornwall"
|
||||
description = "A fortified trading town at the crossroads of the known world."
|
||||
```
|
||||
|
||||
## Region contents
|
||||
|
||||
Place TOML files in these subdirectories of the region folder:
|
||||
|
||||
- `rooms/*.toml` — room definitions (see `rooms/ROOMS.md`)
|
||||
- `npcs/*.toml` — NPC definitions (see `npcs/NPCS.md`)
|
||||
- `objects/*.toml` — object definitions (see `objects/OBJECTS.md`)
|
||||
|
||||
The server loads all regions whose folder contains a `region.toml` file.
|
||||
89
world/town/npcs/NPCS.md
Normal file
89
world/town/npcs/NPCS.md
Normal file
@@ -0,0 +1,89 @@
|
||||
# NPC TOML Reference
|
||||
|
||||
Each file in a region’s `npcs/` folder (e.g. `world/town/npcs/`) defines one NPC template. The NPC ID is `"<region>:<filename_stem>"` (e.g. `barkeep.toml` in region `town` → `town:barkeep`). Race and class are resolved at **spawn time** (and again on respawn if not fixed); omit them for random selection.
|
||||
|
||||
## Top-level fields
|
||||
|
||||
| Field | Type | Required | Default | Description |
|
||||
|-------|------|----------|---------|-------------|
|
||||
| `name` | string | Yes | — | Display name. |
|
||||
| `description` | string | Yes | — | Shown when the player looks at or examines the NPC. |
|
||||
| `room` | string | Yes | — | Full room ID where the NPC appears (e.g. `"town:tavern"`). |
|
||||
| `base_attitude` | string | No | `"neutral"` | One of: `friendly`, `neutral`, `wary`, `aggressive`, `hostile`. Hostile NPCs auto-engage players in the room. |
|
||||
| `faction` | string | No | — | Optional faction ID for attitude grouping. |
|
||||
| `race` | string | No | — | Race ID (e.g. `"race:beast"`, `"race:human"`). If omitted, a random non-hidden race is chosen at each spawn/respawn. |
|
||||
| `class` | string | No | — | Class ID (e.g. `"class:peasant"`, `"class:rogue"`). If omitted, the race’s `default_class` is used, or a random compatible non-hidden class. |
|
||||
| `respawn_secs` | integer | No | — | If set, the NPC respawns this many seconds after death. Race/class are re-rolled on respawn unless fixed above. |
|
||||
| `dialogue` | table | No | — | See below. |
|
||||
| `combat` | table | No | — | If set, the NPC can be attacked and has combat stats. If omitted, the NPC has default combat stats when attacked. |
|
||||
|
||||
## `[dialogue]`
|
||||
|
||||
| Field | Type | Required | Default | Description |
|
||||
|-------|------|----------|---------|-------------|
|
||||
| `greeting` | string | No | — | Line shown when a player uses `talk` on this NPC (only if attitude allows talking). |
|
||||
|
||||
## `[combat]`
|
||||
|
||||
| Field | Type | Required | Default | Description |
|
||||
|-------|------|----------|---------|-------------|
|
||||
| `max_hp` | integer | Yes | — | Maximum HP. |
|
||||
| `attack` | integer | Yes | — | Attack value. |
|
||||
| `defense` | integer | Yes | — | Defense value. |
|
||||
| `xp_reward` | integer | No | `0` | XP awarded when the NPC is killed. |
|
||||
|
||||
## Examples
|
||||
|
||||
**Fixed race/class (e.g. animal):**
|
||||
|
||||
```toml
|
||||
name = "Giant Rat"
|
||||
description = "A mangy rat the size of a small dog."
|
||||
room = "town:cellar"
|
||||
base_attitude = "hostile"
|
||||
race = "race:beast"
|
||||
class = "class:creature"
|
||||
respawn_secs = 60
|
||||
|
||||
[combat]
|
||||
max_hp = 25
|
||||
attack = 6
|
||||
defense = 2
|
||||
xp_reward = 15
|
||||
```
|
||||
|
||||
**Random race, fixed class (e.g. barkeep):**
|
||||
|
||||
```toml
|
||||
name = "Grizzled Barkeep"
|
||||
description = "A weathered man with thick forearms."
|
||||
room = "town:tavern"
|
||||
base_attitude = "friendly"
|
||||
|
||||
[dialogue]
|
||||
greeting = "Welcome to The Rusty Tankard."
|
||||
```
|
||||
|
||||
(No `race` or `class` → random race each spawn, default class from race, e.g. Peasant for humanoids.)
|
||||
|
||||
**Fixed class, random race:**
|
||||
|
||||
```toml
|
||||
name = "Shadowy Thief"
|
||||
description = "A cloaked figure lurking in the darkness."
|
||||
room = "town:dark_alley"
|
||||
base_attitude = "aggressive"
|
||||
faction = "underworld"
|
||||
class = "class:rogue"
|
||||
respawn_secs = 90
|
||||
|
||||
[combat]
|
||||
max_hp = 45
|
||||
attack = 12
|
||||
defense = 6
|
||||
xp_reward = 35
|
||||
```
|
||||
|
||||
## Display
|
||||
|
||||
`look <npc>` and `examine <npc>` show the NPC’s **resolved** race and class (from the current spawn instance).
|
||||
80
world/town/objects/OBJECTS.md
Normal file
80
world/town/objects/OBJECTS.md
Normal file
@@ -0,0 +1,80 @@
|
||||
# Object TOML Reference
|
||||
|
||||
Each file in a region’s `objects/` folder (e.g. `world/town/objects/`) defines one object type. The object ID is `"<region>:<filename_stem>"` (e.g. `rusty_sword.toml` in region `town` → `town:rusty_sword`).
|
||||
|
||||
## Top-level fields
|
||||
|
||||
| Field | Type | Required | Default | Description |
|
||||
|-------|------|----------|---------|-------------|
|
||||
| `name` | string | Yes | — | Display name. |
|
||||
| `description` | string | Yes | — | Shown when the player looks at or examines the object. |
|
||||
| `room` | string | No | — | Full room ID where the object is placed (e.g. `"town:forge"`). If omitted, the object does not appear in the world until given by script or placed elsewhere. |
|
||||
| `kind` | string | No | — | Flavour/legacy: e.g. `"weapon"`, `"armor"`, `"consumable"`. If `slot` is not set, `weapon` → `main_hand`, `armor` → `torso` for equip. |
|
||||
| `slot` | string | No | — | Equipment slot name (e.g. `"main_hand"`, `"off_hand"`, `"torso"`, `"head"`). Must be a slot the equipper’s race has. If set, overrides `kind` for slot choice. |
|
||||
| `takeable` | boolean | No | `false` | If `true`, players can take the object and put it in inventory. |
|
||||
| `stats` | table | No | — | See `[stats]` below. |
|
||||
|
||||
## `[stats]`
|
||||
|
||||
| Field | Type | Required | Default | Description |
|
||||
|-------|------|----------|---------|-------------|
|
||||
| `damage` | integer | No | — | Weapon damage bonus when equipped in a weapon slot. |
|
||||
| `armor` | integer | No | — | Armor bonus when equipped in an armor slot. |
|
||||
| `heal_amount` | integer | No | — | HP restored when the object is **used** (consumable). The object is consumed on use. |
|
||||
|
||||
## Examples
|
||||
|
||||
**Weapon (explicit slot):**
|
||||
|
||||
```toml
|
||||
name = "Rusty Sword"
|
||||
description = "A battered iron blade with a cracked leather grip."
|
||||
room = "town:cellar"
|
||||
kind = "weapon"
|
||||
slot = "main_hand"
|
||||
takeable = true
|
||||
|
||||
[stats]
|
||||
damage = 6
|
||||
```
|
||||
|
||||
**Shield:**
|
||||
|
||||
```toml
|
||||
name = "Iron Shield"
|
||||
description = "A dented but serviceable round shield."
|
||||
room = "town:forge"
|
||||
slot = "off_hand"
|
||||
takeable = true
|
||||
|
||||
[stats]
|
||||
armor = 4
|
||||
```
|
||||
|
||||
**Consumable:**
|
||||
|
||||
```toml
|
||||
name = "Healing Potion"
|
||||
description = "A small glass vial filled with a shimmering red liquid."
|
||||
room = "town:temple"
|
||||
kind = "consumable"
|
||||
takeable = true
|
||||
|
||||
[stats]
|
||||
heal_amount = 30
|
||||
```
|
||||
|
||||
**Non-takeable (e.g. scenery):**
|
||||
|
||||
```toml
|
||||
name = "Stone Fountain"
|
||||
description = "A worn fountain, water trickling quietly."
|
||||
room = "town:town_square"
|
||||
takeable = false
|
||||
```
|
||||
|
||||
## Equipment and races
|
||||
|
||||
- A race defines which slots it has (see `world/races/RACES.md`). Equipping fails if the race does not have the object’s `slot`.
|
||||
- If `slot` is omitted, `kind = "weapon"` defaults to `main_hand`, `kind = "armor"` to `torso`; other kinds have no default slot.
|
||||
- Items are treated as fitting any race that has the slot (no size restriction).
|
||||
33
world/town/rooms/ROOMS.md
Normal file
33
world/town/rooms/ROOMS.md
Normal file
@@ -0,0 +1,33 @@
|
||||
# Room TOML Reference
|
||||
|
||||
Each file in a region’s `rooms/` folder (e.g. `world/town/rooms/`) defines one room. The room ID is `"<region>:<filename_stem>"` (e.g. `town_square.toml` in region `town` → `town:town_square`). Exits reference these full IDs.
|
||||
|
||||
## Top-level fields
|
||||
|
||||
| Field | Type | Required | Default | Description |
|
||||
|-------|------|----------|---------|-------------|
|
||||
| `name` | string | Yes | — | Room title shown to players. |
|
||||
| `description` | string | Yes | — | Room description. Can be a multi-line string (`"""..."""`). |
|
||||
| `exits` | table | No | `{}` | Map of direction → room ID. Direction keys are lowercase (e.g. `north`, `south`, `east`, `west`, `up`, `down`). Values are full room IDs (e.g. `"town:tavern"`). |
|
||||
|
||||
## Example
|
||||
|
||||
```toml
|
||||
name = "Town Square"
|
||||
description = """\
|
||||
You stand in the heart of Thornwall. A worn stone fountain sits at the \
|
||||
center, water trickling quietly. Cobblestone paths branch in every \
|
||||
direction."""
|
||||
|
||||
[exits]
|
||||
north = "town:tavern"
|
||||
east = "town:market"
|
||||
west = "town:temple"
|
||||
south = "town:dark_alley"
|
||||
```
|
||||
|
||||
## Notes
|
||||
|
||||
- NPCs and objects are placed in rooms via their own TOML: NPCs have a `room` field, objects have a `room` field. The server builds room contents from those references.
|
||||
- Exits can point to rooms in other regions; use the full ID (e.g. `"dungeon:entrance"`).
|
||||
- The world `manifest.toml` must list a valid `spawn_room` ID that exists.
|
||||
Reference in New Issue
Block a user