Stingbatbot Architecture¶
Overview¶
Stingbatbot is designed with a modular, behavior-based architecture that enables flexible extension of game mechanics across a growing number of character types. The system follows these architectural principles:
- Behavior-based interfaces for game mechanics (SpellCasting, Attack, with StatCheck planned)
- Implementation modules that apply modifiers based on character attributes
- Pattern matching for specialized handling of different game scenarios
- Database storage for character data with import validation workflow
- Integration with Pythonx for advanced dice rolling capabilities
The architecture is specifically designed to scale to accommodate all 22+ current classes and ancestries, plus future expansion content, without requiring core code modifications.
Core Modules¶
Character Data Management¶
Database Storage System¶
Responsibility: Persistent storage for character data
- Stores character data in a database
- Provides CRUD operations for character management
- Replaces the older file-based storage system
Key Functions:
- get_all/0
: Returns all characters
- get_character/1
: Gets a character by name
- save_character/1
: Saves a character to the database
- delete_character/1
: Removes a character from the database
Character Import System¶
Responsibility: Validates and imports character data from JSON
- Processes uploaded JSON files
- Validates data structure and required fields
- Presents validation results to users
- Converts valid data for database storage
Key Functions:
- validate_json/1
: Checks if JSON contains required structure
- preview_character/1
: Generates a summary of the character for user confirmation
- import_character/1
: Finalizes import after user confirmation
Character and Character.Parse¶
Responsibility: Domain model for character data and parsing
- Transforms data into structured character representations
- Contains all business logic related to characters
- Provides a comprehensive data model including all character attributes
- Tracks character bonuses, abilities, and talents
- Separates parsing logic into the Character.Parse module
For detailed information on the Character system, see characters.md.
Character Selection System¶
Responsibility: Manages user character selection across different context levels
- Provides a hierarchical selection system (channel > guild > global)
- Allows users to select different characters at different context levels
- Tracks character selections persistently in the database
- Validates character ownership before selection
- Enforces uniqueness of character names per user
For detailed information on the Character selection system, see character_selection.md.
Game Mechanics Systems¶
SpellCasting Behavior¶
Responsibility: Defines the interface for spell casting mechanics
- Maintains a list of implementation modules
- Handles spell casting checks and modifiers
- Combines modifiers from various sources (class, ancestry, etc.)
- Designed to scale to all current and future classes/ancestries
Key Components:
- apply_stat_modifier/1
: Applies the primary spellcasting stat (e.g., INT for Wizards)
- apply_casting_modifiers/1
: Applies additional modifiers from abilities
- Implementation modules for all spellcasting classes and relevant ancestries
SpellCastingRoll¶
Responsibility: Handles dice rolling for spell casting checks
- Takes pre-calculated SpellCasting structures
- Builds appropriate dice expressions with modifiers
- Supports advantage/disadvantage mechanics
- Detects critical success/failure
- Determines success/failure against spell DC
- Produces structured RollResult objects
Key Functions:
- roll/2
: Performs the spell casting roll with options
- build_casting_expression/2
: Creates dice expressions
Attack Behavior¶
Responsibility: Defines the interface for attack mechanics
- Maintains a list of implementation modules
- Handles attack rolls and damage calculations
- Applies modifiers based on weapon types and character abilities
- Designed to scale to all current and future classes/ancestries
Key Components:
- apply_attack_modifiers/1
: Applies modifiers to attack and damage
- Implementation modules for all weapon-using classes and ancestries
- Weapon type handling (melee, ranged, versatile)
StatCheck Behavior (Planned)¶
Responsibility: Defines the interface for stat checks and contested checks
- Will follow the same behavior-based pattern as SpellCasting and Attack
- Will allow classes and ancestries to modify stat checks
- Will support both standard and contested stat checks
- Will integrate with the dice rolling system
Dice Rolling Integration¶
Responsibility: Handles dice rolls with detailed results
- Integrates with Pythonx to use Avrae's d20 dice rolling library
- Provides rich roll results including individual dice values
- Supports complex dice expressions for various game mechanics
Key Components: - Interface for attack rolls - Interface for spell casting rolls - Interface for stat checks (planned) - Interface for contested stat checks (planned) - Detailed display of roll results
Class and Ancestry Implementation Modules¶
Responsibility: Implement behavior-specific modifiers
- Each class (22+ current) implements relevant behaviors
- Each ancestry implements relevant behaviors
- Modules apply specific bonuses based on character abilities
- Designed for easy extension as new content is published
Implementation Pattern: - Pattern matching for character attributes (class, ancestry) - Conditional logic for ability bonuses - Struct updates to apply modifiers
User Interface¶
CharacterFormatter¶
Responsibility: Presentation layer for character data
- Takes structured character data and formats it for display
- Provides different views of character data (summary, details, sheet)
- Contains only presentation logic, no business logic
Key Functions:
- format_summary/1
: Creates a basic character summary
- format_details/1
: Creates a detailed character sheet
- format_ability/2
: Formats a specific ability
Advanced User Interface (Planned)¶
Responsibility: Enhanced interaction with character data
- Provides explanations of modifier calculations
- Allows drilling down into specific character attributes
- Presents contextual information about character abilities
Key Features:
- explain
command to show detailed modifier breakdowns
- Interactive elements for exploring character attributes
- Context-sensitive help for game mechanics
Commands¶
Responsibility: Interface layer for user interaction
- Handles user commands
- Uses core modules to process commands and generate responses
- Maps user input to appropriate actions
Key Commands:
- sheet
: Displays the currently selected character's summary
- detail
: Displays detailed character information
- import
: Initiates character import workflow
- roll
: Handles dice rolling requests
- attack
: Manages attack rolls for characters (planned)
- cast
: Manages spell casting rolls (planned)
- check
: Manages stat checks for characters (planned)
Architectural Patterns¶
Behavior Implementation Pattern¶
The system uses Elixir behaviors to define interfaces that are implemented by various modules:
- Behavior Definition: Core modules define callback functions
- Implementation List: Each behavior maintains a list of modules that implement it
- Module Application: When processing, each implementation module is called in sequence
- Modifier Accumulation: Results accumulate as they pass through each implementation
This pattern enables the system to scale efficiently to the current 22+ classes and ancestries, plus future expansions, without requiring core code changes.
# Example from SpellCasting
def apply_modifiers(spell_casting, implementations) do
Enum.reduce(implementations, spell_casting, fn module, acc ->
module.apply_casting_modifiers(acc)
end)
end
Roll Modifiers Pipeline Pattern¶
The system employs a pipeline-based callback architecture for all dice roll mechanics:
- Roll Components Structure: Core dice components (count, dice, modifier) are encapsulated in a dedicated structure
- Pipeline Transformations: Dice roll logic flows through a series of transformation functions
- Callback Interface: Each character component module can modify roll mechanics through a standardized callback
- Context Preservation: Each transformation maintains and passes along the full context of the roll
- User Modifiers: Custom modifiers provided by users are applied after all other transformations
- Extensibility: The pipeline can be extended with new transformations without modifying existing code
This pattern is applied consistently across all roll-based mechanics (attacks, spell casting, skill checks) and provides several benefits:
- Clear Separation: Distinguishes between static modifiers and dynamic dice mechanics
- Composable Transformations: Multiple modifications can be applied in sequence
- Encapsulation: Implementation details stay within specific modules
- Testability: Each transformation can be tested in isolation
- Maintainability: Common logic is centralized while specific logic is distributed appropriately
# Example pipeline from AttackRoll
def build_damage_modifiers(%Attack{} = attack, opts \\ %{}) do
# Run the pipeline to get modified attack and components
{modified_attack, _roll_type, components, options} = build_damage_roll_components(attack, opts)
|> handle_versatile_weapon()
|> handle_crit_damage()
# Get the expression with any additional modifications from DiceExpression
DiceExpression.build_expression_with_context(modified_attack, :damage, components, options)
end
This architecture creates a unified approach to game mechanics across the entire system, ensuring that features like critical hits, advantage/disadvantage, and class-specific abilities work consistently in all contexts.
Pattern Matching for Game Logic¶
The system uses pattern matching extensively to handle different game scenarios:
# Example from the Elf module
defp apply_farsight_attack_bonus(%{character: %{ancestry: "Elf"}, weapon: weapon} = attack)
when not is_nil(weapon) do
# Process Elf-specific logic
end
# Catch-all for non-matching cases
defp apply_farsight_attack_bonus(attack), do: attack
Testing Architecture¶
The testing architecture follows the same principles as the rest of the system, emphasizing modularity, separation of concerns, and realistic testing:
Dependency Injection Pattern¶
Commands and services accept external dependencies through parameters, enabling easy test substitution:
- Function Parameters: Functions accept optional parameters for dependencies
- Default Production Implementations: Default parameter values use real implementations
- Test Substitution: Tests supply test implementations that maintain the same interface
- Consistent Interfaces: Test modules mirror the interface of real modules
This pattern allows for testing without mocking our own code, focusing mocks only on external services.
Test Helpers¶
The system includes specialized test implementations for external dependencies:
Message API Test Modules¶
- MessageApi: Test implementation that captures sent messages for verification
- ErrorMessageApi: Simulates message creation failures
- MessageApiHelper: Creates customized message API test implementations
HTTP Client Test Modules¶
- JSONHTTPClient: Returns configurable JSON responses
- ErrorHTTPClient: Simulates HTTP request failures
- StatusHTTPClient: Simulates specific HTTP status codes
- HTTPClientHelper: Factory for creating HTTP client test implementations
Testing Approach Benefits¶
This architecture enables:
- Clean Tests: No mocking of our own code
- Realistic Testing: Test implementations mimic real behavior
- Testable Components: Clear separation of external dependencies
- Easy Verification: Captured outputs can be inspected directly
- Consistent Patterns: All commands follow the same testing approach
Data Flow¶
Character Data Flow¶
- User uploads a character JSON file through the import command
- System validates the character data structure
- Preview is shown to the user for confirmation
- Upon acceptance, character is stored in the database
- Character data is retrieved from database when needed
- Character module parses and structures the data
- Game mechanics are applied via behavior implementations
- Results are formatted for display
Game Mechanics Flow¶
- Character module generates game mechanics structures:
get_attacks/1
Implementation Status¶
- ✅ Core character data model
- ✅ Database storage system
- ✅ Character import workflow
- ✅ SpellCasting behavior system
- ✅ Attack behavior system
- ✅ Character.Parse class/ancestry modification system
- ✅ Character class implementations (Wizard, Priest, and others)
- ✅ Ancestry implementations (Elf and others) with appropriate bonuses
Data Types¶
The system uses several standard data types for consistency:
- Discord IDs (guild_id, user_id, channel_id, message_id):
- Stored as
:integer
in schemas - Stored as
:bigint
in the database - This includes all IDs from Discord's API