Spell System Architecture¶
This document outlines the architecture for the spell system in Stingbatbot, which provides a centralized source of spell data for the Shadowdark RPG.
Overview¶
The Spell System follows a centralized architecture pattern:
- Data Layer: Spell definitions stored in
spells.json
- Service Layer:
SpellList
GenServer providing access to spell data - Domain Layer:
Spell
struct representing individual spells - Integration Layer: Character system and spell casting mechanics using the SpellList
This architecture ensures a single source of truth for all spell data while providing efficient access patterns.
Core Components¶
SpellList GenServer¶
Responsibility: Central registry and lookup service for all spells
- Loads all spells from
spells.json
at startup - Provides lookup functions for finding spells by name, class, and tier
- Acts as the single source of truth for all spell data
- Maintains a map of spells indexed by name for efficient lookup
- Used during character parsing to associate spells with characters
Key Functions:
- get_all/0
: Returns all available spells
- get_spell/1
: Retrieves a spell by name (case-insensitive, supports partial matches)
- get_spells_for_class/1
: Returns all spells available to a specific class
- get_spells_for_class_and_tier/2
: Returns all spells for a class at a specific tier
- get_spell_for_class/2
: Retrieves a specific spell for a specific class
- reload/0
: Reloads the spell list from the JSON file (for development/admin use)
Spell Struct¶
Responsibility: Represents individual spell data
- Defines the structure of a spell with all properties from
spells.json
- Provides helper functions for checking class availability and tier information
- Used throughout the application to represent spell data consistently
Key Fields:
- name
: The name of the spell
- classes
: List of class names that can use this spell
- tierByClass
: List of tier/level numbers corresponding to classes
- duration
: Duration of the spell
- range
: Range of the spell
- desc
: Description of the spell
- castWithAdv
: Whether the spell is cast with advantage
- popularityWithClass
: List of popularity scores corresponding to classes
- sourceId
: Optional - source of the spell
- alignmentRestriction
: Optional - alignment restrictions
- class
: Backward compatibility - first class in classes
- tier
: Backward compatibility - first tier in tierByClass
Key Functions:
- get_tier_for_class/2
: Gets the tier for a specific class
- available_to_class?/2
: Checks if a spell is available to a specific class
Integration with Character System¶
The spell system integrates with the character system during character parsing:
- When parsing character data, any spells referenced in the character's abilities are looked up in the SpellList
- Class-specific default spells (like Turn Undead for Priests) are also retrieved from the SpellList
- Spell references are resolved to complete spell objects with all properties from
spells.json
- This ensures all characters have complete and consistent spell data
Character.Parse Integration¶
During character parsing, spells are looked up from the SpellList rather than being constructed directly:
# From a character ability/bonus to a proper Spell object
def ability_to_spell(ability) do
SpellList.get_spell_for_class(ability.bonus_name, ability.source_name)
end
For class-specific default spells, the same pattern is used:
# In Priest class module
def apply_parsing_modification(%{class: "Priest"} = character) do
# Add Turn Undead if not already present
if not has_turn_undead?(character) do
turn_undead = SpellList.get_spell_for_class("Turn Undead", "Priest")
%{character | spells: [turn_undead | character.spells]}
else
character
end
end
Testing Strategy¶
The testing strategy for the spell system focuses on verifying:
- Accuracy: SpellList correctly loads and represents spells from JSON
- Completeness: All expected spells are available
- Integration: Character parsing correctly associates spells with characters
- Performance: Lookups are efficient even with many spells
Tests use the actual SpellList service (no mocking) to ensure end-to-end validation of the system.
Benefits of Centralized Spell Data¶
This centralized architecture provides several key benefits:
- Single Source of Truth: All spell data comes from
spells.json
, ensuring consistency - Complete Information: All spells have complete information (duration, range, etc.)
- Maintainability: Updating spell data only requires changing the JSON file
- Consistency: All spell references use the same data structure
- Efficiency: Fast lookups via indexed map structure
Implementation Requirements¶
To implement this architecture:
- Ensure all spells are properly defined in
spells.json
- Implement
get_spell_for_class/2
in SpellList - Update character parsing to use SpellList lookups
- Update class modules to retrieve default spells from SpellList
- Verify that all spells are properly loaded at application startup
Migration Path¶
The migration path from direct Spell construction to SpellList lookups:
- Add backward compatibility fields (
class
,tier
) to the Spell struct - Implement SpellList with efficient lookup functions
- Replace direct Spell construction with SpellList lookups
- Update tests to verify SpellList integration
- (Future) Consider removing backward compatibility fields once all code is updated