User Guide: Comprehensive Framework Usage
This guide covers everything you need to effectively use the Ultimate Dice Roll Toolkit in your Unity projects. From basic dice rolls to complex conditional rule systems, this guide provides step-by-step instructions for all major features.
Basic Usage Patterns
Simple Dice Rolls
The simplest way to use the framework is through the static DiceAPI class methods:
Basic Roll Methods
// Roll a single die with modifier
int result = DiceAPI.Roll(20, 5); // 1d20+5 (6-25)
// Roll multiple dice with modifier
int total = DiceAPI.Roll(6, 3, 2); // 3d6+2 (5-20)
// Get detailed result information
RollResult detailed = DiceAPI.RollDetailed(20, 3);
Debug.Log($"Roll: {detailed.totalResult}, Raw: {detailed.naturalResult}");
Working with Roll Results
The framework provides different result types depending on the operation complexity:
Result Types
// RollResult - Basic roll information
RollResult basic = DiceAPI.RollDetailed(20, 5);
Debug.Log($"Total: {basic.totalResult}");
Debug.Log($"Natural: {basic.naturalResult}");
Debug.Log($"Modifier: {basic.appliedModifier}");
// TargetResult - Success/failure against targets
TargetResult target = DiceAPI.RollTarget(diceConfig, 15, ComparisonType.GreaterEqual);
Debug.Log($"Success: {target.isSuccess}");
Debug.Log($"Margin: {target.margin}");
// OpposedResult - Contest results
OpposedResult contest = DiceAPI.RollOpposed(opposedConfig);
Debug.Log($"Winner: {contest.winner}");
Debug.Log($"Attacker: {contest.attackerResult}, Defender: {contest.defenderResult}");
Understanding Modifiers
The framework handles modifiers at multiple levels:
Modifier Sources
// Direct modifiers (applied immediately)
int result = DiceAPI.Roll(20, 5); // +5 modifier
// Configuration modifiers (stored in ScriptableObject)
var config = CreateDiceConfiguration();
config.modifier = 3; // Built into configuration
// Session modifiers (persistent across rolls)
ModifierSession.AddModifier(2, "Blessing");
int roll = DiceAPI.Roll(20); // Includes session modifiers automatically
// Combined result includes all modifier sources
RollResult detailed = DiceAPI.RollDetailed(config);
Debug.Log($"Total modifiers: {detailed.appliedModifier}");
Roll Types Usage
Advantage and Disadvantage
Advantage and disadvantage rolls use D&D 5e mechanics:
Advantage/Disadvantage Implementation
// Advantage: Roll twice, take higher
int advantage = DiceAPI.RollAdvantage(20, 3);
// Disadvantage: Roll twice, take lower
int disadvantage = DiceAPI.RollDisadvantage(20, 3);
// Using configurations
var advantageConfig = CreateDiceConfiguration();
advantageConfig.rollType = RollType.Advantage;
RollResult result = DiceAPI.RollDetailed(advantageConfig);
// Check which die was used in advantage/disadvantage
Debug.Log($"Selected die: {result.selectedDie}");
Exploding Dice
Exploding dice continue rolling when maximum values are rolled:
Exploding Dice Configuration
// Simple exploding roll with explosion limit
RollResult exploding = DiceAPI.RollExploding(6, 3); // Explode up to 3 times
// Configuration-based exploding dice
var config = CreateDiceConfiguration();
config.rollType = RollType.Exploding;
config.maxExplosions = 5; // Maximum explosion limit
RollResult result = DiceAPI.RollDetailed(config);
Debug.Log($"Explosions: {result.explosionCount}");
Dice Pool Systems
Pool systems count successes rather than summing dice:
Pool System Usage
// Roll 5d10, count 8+ as successes
RollResult pool = DiceAPI.RollPool(10, 5, 8);
Debug.Log($"Successes: {pool.totalResult}");
// Configuration-based pools
var poolConfig = CreateDiceConfiguration();
poolConfig.rollType = RollType.Pool;
poolConfig.poolSize = 7; // Roll 7 dice
// Success threshold auto-calculated based on die size
RollResult result = DiceAPI.RollDetailed(poolConfig);
Debug.Log($"Success threshold: {result.successThreshold}");
Drop Mechanics
Drop mechanics remove highest or lowest dice before summing:
Drop Configuration
// Roll 4d6, drop lowest 1 (classic D&D ability scores)
var config = CreateDiceConfiguration();
config.rollType = RollType.Drop;
config.dropConfig.type = DropType.Lowest;
config.dropConfig.diceCount = 4;
config.dropConfig.count = 1;
RollResult result = DiceAPI.RollDetailed(config);
Debug.Log($"Kept dice: {string.Join(", ", result.keptDice)}");
ScriptableObject Configurations
Creating Dice Configurations
DiceConfiguration ScriptableObjects provide reusable dice setups:
Configuration Creation
// Create configuration asset in editor
[MenuItem("Tools/Create D20 Configuration")]
public static void CreateD20Config()
{
var config = ScriptableObject.CreateInstance<DiceConfiguration>();
config.displayName = "Standard d20";
config.sides = 20;
config.modifier = 0;
config.rollType = RollType.Normal;
AssetDatabase.CreateAsset(config, "Assets/DiceConfigs/D20.asset");
}
// Use configuration at runtime
public DiceConfiguration d20Config;
void Start()
{
RollResult result = DiceAPI.RollDetailed(d20Config);
}
Target Number Systems
Target configurations enable success/failure mechanics:
Target Configuration
var config = CreateDiceConfiguration();
config.targetConfig.enabled = true;
config.targetConfig.value = 15; // Target number
config.targetConfig.comparison = ComparisonType.GreaterEqual;
config.targetConfig.showDegrees = true; // Show degrees of success
TargetResult result = DiceAPI.RollTarget(config);
Debug.Log($"Success: {result.isSuccess}, Margin: {result.margin}");
Reroll Configurations
Reroll systems allow re-rolling specific dice values:
Reroll Setup
var config = CreateDiceConfiguration();
config.rerollConfig.enabled = true;
config.rerollConfig.type = RerollType.Values;
config.rerollConfig.values = new int[] { 1, 2 }; // Reroll 1s and 2s
config.rerollConfig.maxRerolls = 3; // Maximum reroll attempts
config.rerollConfig.rerollOnce = false; // Can reroll multiple times
RollResult result = DiceAPI.RollDetailed(config);
Debug.Log($"Rerolls used: {result.rerollCount}");
Weight Systems
Weight configurations bias dice toward certain results:
Weight Configuration
var config = CreateDiceConfiguration();
config.weightConfig.enabled = true;
config.weightConfig.algorithm = WeightAlgorithm.BiasHigh; // Favor higher results
// Custom weights for each face
config.weightConfig.algorithm = WeightAlgorithm.Custom;
config.weightConfig.customWeights = new float[] { 0.5f, 0.5f, 1f, 1f, 2f, 3f }; // d6 favoring 5-6
RollResult result = DiceAPI.RollDetailed(config);
Conditional Rule System
Creating Conditional Rules
Conditional rules create dynamic effects based on roll results:
Rule Creation
// Create critical hit rule
var critRule = ScriptableObject.CreateInstance<ConditionalRule>();
critRule.ruleName = "Critical Hit";
critRule.enabled = true;
critRule.priority = 10; // Lower executes first
// Configure trigger: Natural 20
critRule.trigger.type = TriggerType.OnMax;
// Configure action: Double damage
critRule.action.type = ActionType.MultiplyResult;
critRule.action.multiplier = 2.0f;
Setting Up Triggers
Triggers define when rules activate:
Trigger Types
// Trigger on specific value
rule.trigger.type = TriggerType.OnValue;
rule.trigger.value = 7; // Triggers on lucky 7s
// Trigger on range
rule.trigger.type = TriggerType.OnRange;
rule.trigger.min = 18;
rule.trigger.max = 20; // Triggers on 18-20
// Trigger on success margin
rule.trigger.type = TriggerType.OnMargin;
rule.trigger.targetNumber = 15;
rule.trigger.margin = 5; // Succeed by 5+ vs DC 15
Configuring Actions
Actions define what happens when triggers activate:
Action Types
// Roll bonus dice
rule.action.type = ActionType.RollBonus;
rule.action.diceConfig = new BonusDiceConfiguration
{
count = 2,
sides = 6,
modifier = 1,
rollType = RollType.Normal
};
// Add fixed value
rule.action.type = ActionType.AddValue;
rule.action.value = 10;
// Set status flag
rule.action.type = ActionType.SetFlag;
rule.action.flagName = "Critical";
Rule Priority and Execution
Rules execute in priority order with proper chaining:
Priority Management
// Priority 0: First to execute
var firstRule = CreateRule();
firstRule.priority = 0;
firstRule.chainable = true; // Allow other rules to trigger
// Priority 10: Executes after priority 0
var secondRule = CreateRule();
secondRule.priority = 10;
// Priority 100: Cleanup/final effects
var finalRule = CreateRule();
finalRule.priority = 100;
finalRule.maxTriggers = 1; // Only trigger once per roll
Multi-Dice Sessions
Creating Sessions
Sessions manage multiple dice configurations together:
Session Creation
// Create session programmatically
var session = DiceAPI.CreateSession("Combat Round");
session.Description = "Attack and damage rolls";
session.RollMode = RollMode.Simultaneous;
session.UseSessionModifiers = true;
// Add dice to session
session.AddDice(attackDice, "Attack Roll");
session.AddDice(damageDice, "Damage Roll");
// Create as asset
var sessionAsset = DiceAPI.CreateSessionAsset("Combat", "Assets/Sessions/");
sessionAsset.AddDice(weaponConfig, "Weapon Attack");
Managing Dice in Sessions
Sessions provide comprehensive dice management:
Session Management
// Enable/disable specific dice
session.SetDiceEnabled(0, false); // Disable first die
session.SetDiceEnabled("Attack Roll", true); // Enable by label
// Remove dice
session.RemoveDice(1); // Remove by index
session.RemoveDice("Damage Roll"); // Remove by label
// Get session information
Debug.Log($"Enabled dice: {session.GetEnabledDiceCount()}");
Debug.Log($"Session valid: {session.IsValid(out string error)}");
Rolling Sessions
Sessions can be rolled as complete units:
Session Rolling
// Roll entire session
SessionResult result = DiceAPI.RollSession(session);
// Access individual results by label
Debug.Log($"Attack: {result.GetResult(\"Attack Roll\").totalResult}");
Debug.Log($"Damage: {result.GetResult(\"Damage Roll\").totalResult}");
// Get aggregate statistics
Debug.Log($"Total: {result.grandTotal}");
Debug.Log($"Average: {result.averageResult:F1}");
Opposed Roll System
Setting Up Opposed Rolls
Opposed rolls handle contests between two sides:
Opposed Configuration
var opposedConfig = ScriptableObject.CreateInstance<OpposedRollConfig>();
opposedConfig.contestName = "Strength Contest";
opposedConfig.resolutionMode = ResolutionMode.Simple;
// Configure attacker side
opposedConfig.attacker.sideName = "Player";
opposedConfig.attacker.modifier = 3;
opposedConfig.attacker.diceConfigurations = new DiceConfiguration[] { playerDice };
// Configure defender side
opposedConfig.defender.sideName = "Monster";
opposedConfig.defender.modifier = 5;
opposedConfig.defender.diceConfigurations = new DiceConfiguration[] { monsterDice };
Resolution Modes
Four resolution modes handle different contest types:
Resolution Mode Setup
// Simple: Highest total wins
config.resolutionMode = ResolutionMode.Simple;
// Margin: Must win by minimum amount
config.resolutionMode = ResolutionMode.Margin;
config.marginRequired = 5; // Must win by 5+
// Contested: Degrees of success (margin / 5)
config.resolutionMode = ResolutionMode.Contested;
// Blackjack: Closest to 21 without going over
config.resolutionMode = ResolutionMode.Blackjack;
Understanding Results
Opposed results provide detailed contest information:
Result Analysis
OpposedResult result = DiceAPI.RollOpposed(opposedConfig);
Debug.Log($"Winner: {result.winner}"); // Attacker, Defender, or Tie
Debug.Log($"Attacker total: {result.attackerResult}");
Debug.Log($"Defender total: {result.defenderResult}");
Debug.Log($"Margin: {result.margin}");
// Check for specific outcomes
if (result.winner == ContestResult.Attacker)
{
Debug.Log($"Player wins by {result.margin}!");
}
Advanced Topics
Seeded Random Generation
Seeded random enables reproducible results:
Seeded Rolling
// Initialize with string seed
DiceAPI.InitializeSeed("Tournament_Game_1");
// All subsequent rolls are deterministic
int roll1 = DiceAPI.Roll(20); // Always same result for this seed
int roll2 = DiceAPI.Roll(20); // Next in deterministic sequence
// Reset to system random
DiceAPI.InitializeSystemRandom();
// Get current random state for saving
int currentSeed = RandomProvider.GetCurrentSeed();
Probability Analysis
Built-in statistical analysis for game balance:
Statistical Analysis
// Calculate probability of meeting target
ProbabilityResult stats = DiceAPI.CalculateProbability(
diceConfig,
15, // Target number
ComparisonType.GreaterEqual,
50000 // Simulation iterations
);
Debug.Log($"Success rate: {stats.percentage:F2}%");
Debug.Log($"Average result: {stats.average:F2}");
Debug.Log($"Range: {stats.minimum}-{stats.maximum}");
Performance Optimization
Best practices for optimal performance:
Performance Guidelines
// Cache configurations instead of creating new ones
public DiceConfiguration cachedConfig;
void Start()
{
// Good: Reuse configurations
cachedConfig = LoadDiceConfiguration();
}
void Update()
{
// Good: Use cached configuration
int result = DiceAPI.Roll(cachedConfig);
// Avoid: Creating new configurations in hot paths
// var newConfig = ScriptableObject.CreateInstance<DiceConfiguration>();
}
// Limit explosion counts for performance
config.maxExplosions = 10; // Reasonable limit
// Use appropriate iteration counts for probability analysis
// 10K iterations for quick estimates, 50K+ for final validation
Common Issues
Solutions to frequently encountered problems:
Issue: Rolls always return same value
Cause: Seeded random is active
Solution: Call DiceAPI.InitializeSystemRandom() to use system random
Issue: Conditional rules not triggering
Cause: Rule validation failed or priority conflicts
Solution: Check rule.IsValid(out string error) and ensure proper priority ordering
Issue: Session modifiers not applying
Cause: Session configuration disabled modifiers
Solution: Ensure session.UseSessionModifiers = true
Issue: Poor performance with exploding dice
Cause: Unlimited explosions on high-explosion dice
Solution: Set reasonable maxExplosions limit (5-10)