Ability Check System¶
Overview¶
The Ability Check System provides a streamlined way for characters to make ability checks in Shadowdark RPG. It integrates with the character system to automatically calculate and apply appropriate modifiers based on the character's ability scores.
This system follows the same architectural patterns established by the Attack Roll System, leveraging the generic RollResult and RollFormatter modules to maintain a consistent user experience across all roll types.
Command Usage¶
!check <stat> [option1] [option2] ... [descriptive text]
stat
: One of the six core statistics (required)str
- Strengthdex
- Dexteritycon
- Constitutionint
- Intelligencewis
- Wisdom-
cha
- Charisma -
Options (can be provided in any order after the stat):
adv
: Roll the check with advantage (roll twice and take the higher result)dis
: Roll the check with disadvantage (roll twice and take the lower result)-
verb
: Show detailed modifier breakdown -
descriptive text
: Optional text describing what the check is for (e.g., "picking a lock", "climbing a wall")
Examples:
!check str # Basic Strength check
!check dex # Basic Dexterity check
!check wis adv # Wisdom check with advantage
!check int dis # Intelligence check with disadvantage
!check dex picking a lock # Dexterity check for picking a lock
!check str adv climbing a wall # Strength check with advantage for climbing
Note: If both adv
and dis
are specified, they cancel each other out and a normal roll is made.
System Components¶
Core Modules¶
Character Module Extension¶
Responsibility: Provides pre-calculated stat check data
- Already contains character stats, class, ancestry data
- Calculates modifiers based on stats and other factors
- Returns StatCheck structure with pre-calculated modifiers
Key Functions:
- get_stat_check/2
: Returns a pre-calculated StatCheck structure for a specific stat
StatCheck¶
Responsibility: Structured data representation of a stat check with pre-calculated modifiers
- Contains the stat being checked
- Stores the character making the check
- Includes pre-calculated modifiers and bonuses from all sources
- Similar to how Attack structures work for weapons
Key Fields:
- character
: The character making the check
- stat
: The stat being checked (str
, dex
, etc.)
- stat_name
: Full name of the stat (e.g., "Strength")
- stat_score
: Raw stat value (3-18)
- modifier
: The calculated total stat modifier (including all bonuses)
- modifiers
: List of all modifier sources (base stat, class bonuses, etc.)
StatCheckCommand¶
Responsibility: Processes the !check
command from Discord
- Implements the
Stingbatbot.Commands.Command
behavior - Located in the
Stingbatbot.Commands
namespace - Registered in the Command Registry for bot access
- Validates the specified stat
- Extracts options like advantage/disadvantage
- Retrieves the pre-calculated StatCheck structure from the Character
- Passes the StatCheck to StatCheckRoll for dice mechanics
- Uses RollFormatter to format the results
- Sends the formatted message back to Discord via MessageApi
- Follows standard command pattern for error handling and responses
Key Functions:
- name/0
: Returns "check" as the command name
- shortcut/0
: Returns "c" as the command shortcut (optional)
- description/0
: Provides a description of the command
- usage/0
: Provides usage instructions
- execute/2
: Main function that handles command execution, returns {:ok, :sent}
or {:error, reason}
- extract_args/1
: Extracts stat and options from command arguments
StatCheckRoll¶
Responsibility: Handles the dice rolling logic for stat checks
- Takes a pre-calculated StatCheck structure
- Creates a die expression using the pre-calculated modifier
- Uses the Dice module for actual dice rolling
- Creates structured results for formatting
- Supports advantage/disadvantage mechanics
Key Functions:
- roll/2
: Main function that performs the check with the StatCheck and options
- build_check_expression/2
: Creates dice expressions with proper modifiers
RollResult Integration¶
The existing RollResult
struct will be used to store check results, with:
context
: A%StatCheck{}
structure with check detailsroll_expression
: The dice expression (e.g., "1d20+2")roll_result
: The formatted result (e.g., "[15]+2 = 17")roll_total
: The numerical totalcritical
: Status of critical success/failure- No damage-related fields will be used
options
: Map of options used for the roll (e.g.,%{advantage: true}
)
RollFormatter Integration¶
The RollFormatter
module will be extended with pattern matching for StatCheck contexts:
# Format title for stat checks
def format_title_part(%RollResult{context: %StatCheck{}} = result) do
character_name = result.context.character.name
stat_name = result.context.stat_name
title = "🎲 #{character_name}'s #{stat_name} Check"
# Add options if present
option_text = build_option_text(result.options)
if option_text != "", do: "#{title} (#{option_text})", else: title
end
# Format description for stat checks
def format_description_part(%RollResult{context: %StatCheck{}} = result) do
check_part = format_check_part(result)
"#{check_part}"
end
# Helper for formatting stat checks
def format_check_part(%RollResult{} = result) do
# Base check text
check_text = "**Stat Check:** #{result.roll_result}"
# Add critical success/failure indicator
case result.critical do
:crit -> check_text <> "\n**CRITICAL SUCCESS!** 🎯"
:fail -> check_text <> "\n**CRITICAL FAILURE!** 💥"
_ -> check_text
end
end
Data Flow¶
The stat check process follows these steps:
- User invokes
!check <stat>
command - Bot's command processor identifies "check" and routes to StatCheckCommand
- StatCheckCommand validates the stat and extracts options
- Command retrieves the pre-calculated StatCheck structure from Character module
- Command passes StatCheck to StatCheckRoll with options
- StatCheckRoll:
- Uses the pre-calculated modifier from StatCheck
- Generates dice expression based on modifiers and options
- Uses Dice module to execute the roll
- Creates a structured RollResult with the StatCheck as context
- StatCheckCommand passes the RollResult to RollFormatter
- RollFormatter converts the result into a user-friendly message
- Message is sent back to Discord via MessageApi
Implementation Details¶
Stat Score Calculation¶
These calculations are performed once in the Character module when generating the StatCheck structure, rather than calculating them at roll time.
Class and Ancestry Bonuses¶
The StatCheck structures will include any relevant bonuses from: - Character class features affecting stat checks - Ancestry traits affecting stat checks - Magic items or other equipment - Temporary effects or status conditions
This ensures that all modifiers are pre-calculated and available when rolling.
Advantage Implementation¶
Like attack rolls, advantage uses the 2d20kh1
dice notation, which rolls two d20s and keeps the higher result.
Disadvantage Implementation¶
Like attack rolls, disadvantage uses the 2d20kl1
dice notation, which rolls two d20s and keeps the lower result.
When both advantage and disadvantage are specified on the same check, they cancel each other out, resulting in a normal d20 roll.
Critical Success/Failure¶
The system will detect natural 20s as critical successes and natural 1s as critical failures, marking them in the output with special formatting and emoji.
Extension Points¶
Key extension points in the current architecture:
- StatCheckRoll can be extended with additional options
- The RollResult structure already supports different types of contexts
- RollFormatter already has pattern matching for different context types
- Roll modifiers framework can be used for class/ancestry features affecting stat checks
Implementation Plan¶
- Extend the Character module to generate StatCheck structures via get_stat_check/2
- Create the StatCheck struct with relevant fields
- Implement the StatCheckRoll module to handle dice expressions and rolling
- Extend RollFormatter with pattern matching for StatCheck contexts
- Implement the StatCheckCommand to handle the !check command
- Register the command in the command registry
- Add tests to ensure all functionality works as expected
- Update documentation