Implement guild system with multi-guild, spells, and combat casting
- Guild data model: world/guilds/*.toml defines guilds with stat growth, resource type (mana/endurance), spell lists, level caps, and race restrictions. Spells are separate files in world/spells/*.toml. - Player resources: mana and endurance pools added to PlayerStats with DB migration. Passive regen for mana/endurance when out of combat. - Guild commands: guild list/info/join/leave with multi-guild support. spells/skills command shows available spells per guild level. - Spell casting: cast command works in and out of combat. Offensive spells queue as CombatAction::Cast and resolve on tick. Heal/utility spells resolve immediately out of combat. Mana/endurance costs, cooldowns, and damage types all enforced. - Chargen integration: classes reference a guild via TOML field. On character creation, player auto-joins the seeded guild at level 1. Class selection shows "→ joins <Guild>" hint. - Look command: now accepts optional target argument to inspect NPCs (stats/attitude), objects, exits, players, or inventory items. - 4 guilds (warriors/rogues/mages/clerics) and 16 spells created for the existing class archetypes. Made-with: Cursor
This commit is contained in:
24
AGENTS.md
24
AGENTS.md
@@ -15,6 +15,10 @@ This is a Rust MUD server that accepts SSH connections. The architecture separat
|
||||
- **Races are deeply data-driven**: body shape, equipment slots, natural weapons/armor, resistances, traits, regen rates — all defined in TOML. A dragon has different slots than a human.
|
||||
- **Equipment is slot-based**: each race defines available body slots. Items declare their slot. The engine validates compatibility at equip time.
|
||||
- **Items magically resize** — no size restrictions. A dragon can wield a human sword.
|
||||
- **Guilds are data-driven**: defined in `world/guilds/*.toml`. Players can join multiple guilds. Guilds grant spells, stat growth, and resource pools.
|
||||
- **Spells are separate files**: defined in `world/spells/*.toml`, referenced by guild TOML. A spell can be shared across guilds.
|
||||
- **Classes seed initial guild**: each class TOML can reference a `guild` field. On character creation, the player auto-joins that guild at level 1.
|
||||
- **Resources (mana/endurance)**: players have mana and endurance pools, derived from guild base values + racial stat modifiers. Regenerates out of combat.
|
||||
|
||||
## Architecture
|
||||
|
||||
@@ -25,7 +29,7 @@ src/
|
||||
├── ssh.rs russh server/handler: connection lifecycle, chargen flow, command dispatch
|
||||
├── game.rs Core runtime state: Player, GameState, SharedState, XorShift64 RNG
|
||||
├── commands.rs Player command parsing and execution (immediate + queued actions)
|
||||
├── combat.rs Tick-based combat resolution: attack, defend, flee, item use
|
||||
├── combat.rs Tick-based combat resolution: attack, defend, flee, item use, cast
|
||||
├── tick.rs Background tick engine: NPC AI, combat rounds, effects, respawns, regen
|
||||
├── admin.rs Admin command implementations
|
||||
├── chargen.rs Character creation state machine
|
||||
@@ -46,11 +50,12 @@ src/
|
||||
## How Combat Works
|
||||
|
||||
1. Player types `attack <npc>` → enters `CombatState` with `action: Some(Attack)`
|
||||
2. Player can queue a different action before the tick fires (`defend`, `flee`, `use <item>`)
|
||||
2. Player can queue a different action before the tick fires (`defend`, `flee`, `use <item>`, `cast <spell>`)
|
||||
3. Tick engine iterates all players in combat, calls `combat::resolve_combat_tick()`
|
||||
4. Resolution: execute player action → NPC counter-attacks → check death → clear action
|
||||
5. If no action was queued, default is `Attack`
|
||||
6. NPC auto-aggro: hostile NPCs initiate combat with players in their room on each tick
|
||||
7. `cast <spell>` in combat queues `CombatAction::Cast(spell_id)`, resolved on tick: deducts mana/endurance, applies cooldown, deals damage or heals
|
||||
|
||||
## How Status Effects Work
|
||||
|
||||
@@ -90,6 +95,21 @@ src/
|
||||
8. Resistances: damage_type → multiplier (0.0 = immune, 1.0 = normal, 1.5 = vulnerable)
|
||||
9. `xp_rate` modifies XP gain (< 1.0 = slower leveling, for powerful races)
|
||||
|
||||
### New guild
|
||||
1. Create `world/guilds/<name>.toml`
|
||||
2. Required: `name`, `description`
|
||||
3. Key fields: `max_level`, `resource` ("mana" or "endurance"), `base_mana`, `base_endurance`, `spells` (list of spell IDs), `min_player_level`, `race_restricted` (list of race IDs that can't join)
|
||||
4. `[growth]` section: `hp_per_level`, `mana_per_level`, `endurance_per_level`, `attack_per_level`, `defense_per_level`
|
||||
5. **TOML ordering matters**: put `spells`, `min_player_level`, `race_restricted` BEFORE any `[section]` headers
|
||||
6. To link a class to a guild, add `guild = "guild:<filename_stem>"` to the class TOML
|
||||
|
||||
### New spell
|
||||
1. Create `world/spells/<name>.toml`
|
||||
2. Required: `name`, `description`
|
||||
3. Key fields: `spell_type` ("offensive"/"heal"/"utility"), `damage`, `heal`, `damage_type`, `cost_mana`, `cost_endurance`, `cooldown_ticks`, `min_guild_level`
|
||||
4. Optional: `effect` (status effect kind), `effect_duration`, `effect_magnitude`
|
||||
5. Reference the spell ID (`spell:<filename_stem>`) from a guild's `spells` list
|
||||
|
||||
### New equipment slot
|
||||
1. Add the slot name to a race's `[body] slots` array
|
||||
2. Create objects with `slot = "<slot_name>"` in their TOML
|
||||
|
||||
Reference in New Issue
Block a user