Ultimate Dice Roll Toolkit

Practical Implementation Examples

Real-world implementation patterns for different game types and scenarios. Each example includes complete code, explanations of design decisions, and variations for different use cases based on the actual Ultimate Dice Roll Toolkit codebase.

Production-Ready Examples: These examples demonstrate actual framework features and are built using the real API methods. Copy-paste ready with comprehensive integration patterns.

Basic Implementation Patterns

Simple Combat System

A straightforward combat implementation using basic dice rolls and modifiers:

Basic Attack Resolution

public class SimpleCombat : MonoBehaviour
{
    [SerializeField] private DiceConfiguration attackDice;  // d20 for attack rolls
    [SerializeField] private DiceConfiguration damageDice;  // Weapon damage dice
    
    public class CombatResult
    {
        public bool hit;
        public int damage;
        public string description;
    }
    
    public CombatResult ExecuteAttack(int attackBonus, int targetAC)
    {
        var result = new CombatResult();
        
        // Simple attack roll using DiceAPI
        int attackRoll = DiceAPI.Roll(20, attackBonus);
        result.hit = attackRoll >= targetAC;
        
        if (result.hit)
        {
            // Roll damage on successful hit
            RollResult damageResult = DiceAPI.RollDetailed(damageDice);
            result.damage = damageResult.totalResult;
            result.description = $"Hit! {attackRoll} vs AC {targetAC}, {result.damage} damage";
        }
        else
        {
            result.damage = 0;
            result.description = $"Miss! {attackRoll} vs AC {targetAC}";
        }
        
        return result;
    }
}

Skill Check Integration

Implementing skill checks with target numbers and degrees of success:

Skill Check System

public class SkillCheckSystem : MonoBehaviour
{
    [System.Serializable]
    public class SkillData
    {
        public string skillName;
        public DiceConfiguration skillDice;
        public int proficiencyBonus;
    }
    
    public SkillData[] characterSkills;
    
    public TargetResult PerformSkillCheck(string skillName, int difficulty)
    {
        var skill = System.Array.Find(characterSkills, s => s.skillName == skillName);
        if (skill == null)
        {
            Debug.LogError($"Skill {skillName} not found");
            return null;
        }
        
        // Create target configuration
        var targetConfig = ScriptableObject.CreateInstance<DiceConfiguration>();
        targetConfig.sides = skill.skillDice.sides;
        targetConfig.modifier = skill.skillDice.modifier + skill.proficiencyBonus;
        targetConfig.targetConfig.enabled = true;
        targetConfig.targetConfig.value = difficulty;
        targetConfig.targetConfig.comparison = ComparisonType.GreaterEqual;
        
        // Perform the skill check
        TargetResult result = DiceAPI.RollTarget(targetConfig);
        
        // Log the result
        string outcome = result.isSuccess ? "SUCCESS" : "FAILURE";
        Debug.Log($"{skillName} check: {result.rollResult.totalResult} vs DC {difficulty} = {outcome}");
        
        return result;
    }
}

Loot Generation System

Using weighted dice to create balanced loot distribution:

Loot Quality System

public class LootGenerator : MonoBehaviour
{
    public enum LootRarity { Common, Uncommon, Rare, Epic, Legendary }
    
    [SerializeField] private DiceConfiguration lootRollConfig;
    
    public class LootDrop
    {
        public string itemName;
        public LootRarity rarity;
        public int quantity;
        public float goldValue;
    }
    
    public LootDrop GenerateLoot(int playerLevel, float luckModifier = 0f)
    {
        var loot = new LootDrop();
        
        // Use weighted dice for rarity distribution
        var rarityConfig = ScriptableObject.CreateInstance<DiceConfiguration>();
        rarityConfig.sides = 100;
        rarityConfig.modifier = Mathf.RoundToInt(luckModifier * 10);
        rarityConfig.weightConfig.enabled = true;
        rarityConfig.weightConfig.algorithm = WeightAlgorithm.BiasLow; // Favor common items
        
        int rarityRoll = DiceAPI.Roll(rarityConfig);
        
        // Determine rarity based on roll
        loot.rarity = rarityRoll switch
        {
            >= 95 => LootRarity.Legendary,
            >= 85 => LootRarity.Epic,
            >= 70 => LootRarity.Rare,
            >= 40 => LootRarity.Uncommon,
            _ => LootRarity.Common
        };
        
        // Generate quantity using drop mechanics for consistent results
        var quantityResult = DiceAPI.RollDrop(6, 4, 1, DropType.Lowest);
        loot.quantity = quantityResult.totalResult;
        
        // Scale value by level and rarity
        int baseValue = playerLevel * (int)loot.rarity;
        loot.goldValue = baseValue * loot.quantity;
        loot.itemName = GenerateItemName(loot.rarity);
        
        return loot;
    }
    
    private string GenerateItemName(LootRarity rarity)
    {
        string[] prefixes = { "Worn", "Simple", "Fine", "Masterwork", "Legendary" };
        string[] items = { "Sword", "Shield", "Potion", "Ring", "Amulet" };
        
        string prefix = prefixes[(int)rarity];
        int itemIndex = DiceAPI.Roll(items.Length) - 1;
        return $"{prefix} {items[itemIndex]}";
    }
}

Advanced Game Systems

RPG Combat Engine

Complex combat system with advantage/disadvantage and conditional rules:

Advanced Combat with Rules

public class AdvancedCombat : MonoBehaviour
{
    [SerializeField] private ConditionalRule criticalHitRule;
    [SerializeField] private ConditionalRule fumbleRule;
    
    public class CombatAction
    {
        public string attackerName;
        public string weaponName;
        public bool hasAdvantage;
        public bool hasDisadvantage;
        public int attackBonus;
        public DiceConfiguration weaponDamage;
    }
    
    public class DetailedCombatResult
    {
        public bool hit;
        public bool critical;
        public bool fumble;
        public int attackRoll;
        public int damage;
        public string[] triggeredRules;
        public string fullDescription;
    }
    
    public DetailedCombatResult ExecuteAdvancedAttack(CombatAction action, int targetAC)
    {
        var result = new DetailedCombatResult();
        
        // Create attack configuration
        var attackConfig = ScriptableObject.CreateInstance<DiceConfiguration>();
        attackConfig.sides = 20;
        attackConfig.modifier = action.attackBonus;
        
        // Apply advantage/disadvantage
        if (action.hasAdvantage && !action.hasDisadvantage)
        {
            attackConfig.rollType = RollType.Advantage;
        }
        else if (action.hasDisadvantage && !action.hasAdvantage)
        {
            attackConfig.rollType = RollType.Disadvantage;
        }
        
        // Execute attack with conditional rules
        var rules = new ConditionalRule[] { criticalHitRule, fumbleRule };
        var (attackResult, nextModifier) = DiceAPI.RollWithRules(attackConfig, rules);
        
        result.attackRoll = attackResult.totalResult;
        result.hit = result.attackRoll >= targetAC;
        result.critical = attackResult.naturalResult == 20;
        result.fumble = attackResult.naturalResult == 1;
        
        if (result.hit)
        {
            // Base damage
            var damageResult = DiceAPI.RollDetailed(action.weaponDamage);
            result.damage = damageResult.totalResult;
            
            // Critical hit doubles damage
            if (result.critical)
            {
                var critDamage = DiceAPI.RollDetailed(action.weaponDamage);
                result.damage += critDamage.totalResult;
            }
        }
        
        // Build description
        string advantageText = action.hasAdvantage ? " (Advantage)" : 
                              action.hasDisadvantage ? " (Disadvantage)" : "";
        string hitText = result.hit ? "HIT" : "MISS";
        string specialText = result.critical ? " CRITICAL!" : result.fumble ? " FUMBLE!" : "";
        
        result.fullDescription = $"{action.attackerName} attacks with {action.weaponName}{advantageText}: " +
                               $"{result.attackRoll} vs AC {targetAC} = {hitText}{specialText}";
        
        if (result.hit)
        {
            result.fullDescription += $" for {result.damage} damage";
        }
        
        return result;
    }
}

Crafting and Quality

Sophisticated crafting system using multiple roll types and quality determination:

Quality-Based Crafting

public class CraftingSystem : MonoBehaviour
{
    public enum ItemQuality { Poor, Common, Good, Excellent, Masterwork }
    
    [System.Serializable]
    public class Recipe
    {
        public string itemName;
        public int difficultyClass;
        public DiceConfiguration skillRequired;
        public int materialQuality; // 1-5 scale
    }
    
    public class CraftingResult
    {
        public bool success;
        public ItemQuality quality;
        public int skillRoll;
        public int qualityRoll;
        public string resultDescription;
    }
    
    public CraftingResult AttemptCrafting(Recipe recipe, int crafterSkillLevel)
    {
        var result = new CraftingResult();
        
        // Main skill check
        var skillConfig = recipe.skillRequired;
        var skillCheck = DiceAPI.RollTarget(skillConfig, recipe.difficultyClass, 
                                          ComparisonType.GreaterEqual);
        
        result.success = skillCheck.isSuccess;
        result.skillRoll = skillCheck.rollResult.totalResult;
        
        if (result.success)
        {
            // Quality determination using drop mechanics (4d6 drop lowest for consistency)
            var qualityResult = DiceAPI.RollDrop(6, 4, 1, DropType.Lowest, 
                                               recipe.materialQuality);
            result.qualityRoll = qualityResult.totalResult;
            
            // Determine quality tier
            result.quality = result.qualityRoll switch
            {
                >= 20 => ItemQuality.Masterwork,
                >= 17 => ItemQuality.Excellent,
                >= 14 => ItemQuality.Good,
                >= 11 => ItemQuality.Common,
                _ => ItemQuality.Poor
            };
            
            result.resultDescription = $"Successfully crafted {result.quality} {recipe.itemName}! " +
                                     $"(Skill: {result.skillRoll} vs DC {recipe.difficultyClass}, " +
                                     $"Quality: {result.qualityRoll})";
        }
        else
        {
            result.quality = ItemQuality.Poor;
            result.resultDescription = $"Failed to craft {recipe.itemName}. " +
                                     $"(Skill: {result.skillRoll} vs DC {recipe.difficultyClass})";
        }
        
        return result;
    }
}

Procedural Content

Seeded procedural generation for consistent world creation:

Seeded World Generation

public class ProceduralGenerator : MonoBehaviour
{
    [System.Serializable]
    public class WorldSeed
    {
        public string seedString;
        public int dungeonSize;
        public int treasureCount;
        public float dangerLevel;
    }
    
    public class GeneratedRoom
    {
        public Vector2Int position;
        public string roomType;
        public int monsterCount;
        public bool hasTreasure;
        public string description;
    }
    
    public GeneratedRoom[] GenerateWorld(WorldSeed worldSeed)
    {
        // Initialize seeded generation for consistent results
        DiceAPI.InitializeSeed(worldSeed.seedString);
        
        var rooms = new List<GeneratedRoom>();
        
        // Generate room layout
        for (int i = 0; i < worldSeed.dungeonSize; i++)
        {
            var room = new GeneratedRoom();
            room.position = new Vector2Int(i % 5, i / 5);
            
            // Room type determination using weighted distribution
            var roomTypeConfig = ScriptableObject.CreateInstance<DiceConfiguration>();
            roomTypeConfig.sides = 100;
            roomTypeConfig.weightConfig.enabled = true;
            roomTypeConfig.weightConfig.algorithm = WeightAlgorithm.BiasLow; // More common rooms
            
            int roomTypeRoll = DiceAPI.Roll(roomTypeConfig);
            
            room.roomType = roomTypeRoll switch
            {
                >= 90 => "Boss Chamber",
                >= 75 => "Treasure Room",
                >= 60 => "Trap Room",
                >= 30 => "Monster Den",
                _ => "Empty Chamber"
            };
            
            // Monster population using dice pools
            if (room.roomType == "Monster Den" || room.roomType == "Boss Chamber")
            {
                int poolSize = room.roomType == "Boss Chamber" ? 8 : 5;
                var monsterPool = DiceAPI.RollPool(6, poolSize, 4); // Count 4+ as monsters
                room.monsterCount = monsterPool.totalResult;
            }
            
            // Treasure placement using exploding dice for rare valuable finds
            if (room.roomType == "Treasure Room")
            {
                var treasureRoll = DiceAPI.RollExploding(10, 3); // Exploding d10, max 3 explosions
                room.hasTreasure = treasureRoll.totalResult >= 15; // High-value threshold
            }
            
            room.description = GenerateRoomDescription(room);
            rooms.Add(room);
        }
        
        return rooms.ToArray();
    }
    
    private string GenerateRoomDescription(GeneratedRoom room)
    {
        var description = $"{room.roomType} at {room.position}";
        
        if (room.monsterCount > 0)
        {
            description += $" with {room.monsterCount} monsters";
        }
        
        if (room.hasTreasure)
        {
            description += " containing valuable treasure";
        }
        
        return description;
    }
}

Specialized Use Cases

Opposed Roll Contests

Implementing competitive rolls using the OpposedRollConfig system:

Contest Resolution System

public class ContestSystem : MonoBehaviour
{
    [SerializeField] private OpposedRollConfig armWrestlingConfig;
    [SerializeField] private OpposedRollConfig ridingContestConfig;
    
    public OpposedResult ExecuteContest(string contestType, int player1Bonus, int player2Bonus)
    {
        OpposedRollConfig config = contestType switch
        {
            "Arm Wrestling" => armWrestlingConfig,
            "Horse Racing" => ridingContestConfig,
            _ => armWrestlingConfig // Default
        };
        
        // Configure bonuses for this specific contest
        config.attacker.modifier = player1Bonus;
        config.defender.modifier = player2Bonus;
        
        // Execute the opposed roll
        OpposedResult result = DiceAPI.RollOpposed(config);
        
        // Detailed logging
        string winnerName = result.winner switch
        {
            ContestResult.Attacker => config.attacker.sideName,
            ContestResult.Defender => config.defender.sideName,
            _ => "Nobody (Tie)"
        };
        
        Debug.Log($"{contestType} Contest Result:");
        Debug.Log($"{config.attacker.sideName}: {result.attackerResult}");
        Debug.Log($"{config.defender.sideName}: {result.defenderResult}");
        Debug.Log($"Winner: {winnerName} (Margin: {result.margin})");
        
        return result;
    }
}

Multi-Dice Sessions

Complex scenarios requiring multiple dice rolled simultaneously:

Combat Session Management

public class CombatSessionManager : MonoBehaviour
{
    [SerializeField] private DiceConfiguration attackDice;
    [SerializeField] private DiceConfiguration mainDamage;
    [SerializeField] private DiceConfiguration bonusDamage;
    
    public SessionResult ExecuteFullAttack(string attackerName)
    {
        // Create a session for complete attack resolution
        var combatSession = DiceAPI.CreateSession($"{attackerName} Full Attack");
        combatSession.Description = "Complete attack with main and bonus damage";
        combatSession.UseSessionModifiers = true;
        
        // Add all dice to the session
        combatSession.AddDice(attackDice, "Attack Roll");
        combatSession.AddDice(mainDamage, "Main Damage");
        combatSession.AddDice(bonusDamage, "Bonus Damage");
        
        // Execute entire session at once
        SessionResult result = DiceAPI.RollSession(combatSession);
        
        // Process results
        var attackResult = result.GetResult("Attack Roll");
        var mainDamageResult = result.GetResult("Main Damage");
        var bonusDamageResult = result.GetResult("Bonus Damage");
        
        Debug.Log($"{attackerName} Full Attack Results:");
        Debug.Log($"Attack: {attackResult.totalResult}");
        Debug.Log($"Main Damage: {mainDamageResult.totalResult}");
        Debug.Log($"Bonus Damage: {bonusDamageResult.totalResult}");
        Debug.Log($"Total Damage: {mainDamageResult.totalResult + bonusDamageResult.totalResult}");
        
        return result;
    }
}

Dynamic Rule Systems

Advanced conditional rules that modify gameplay dynamically:

Dynamic Combat Rules

public class DynamicRuleSystem : MonoBehaviour
{
    [SerializeField] private ConditionalRule criticalRule;
    [SerializeField] private ConditionalRule heroicMomentRule;
    [SerializeField] private ConditionalRule comboRule;
    
    public class RuleProcessingResult
    {
        public RollResult baseRoll;
        public int finalResult;
        public string[] activatedRules;
        public int accumulatedModifier;
        public string description;
    }
    
    public RuleProcessingResult ProcessWithDynamicRules(DiceConfiguration baseDice, 
                                                       string context = "")
    {
        var result = new RuleProcessingResult();
        
        // Determine which rules apply based on context
        var applicableRules = GetApplicableRules(context);
        
        // Process roll with conditional rules
        var (rollResult, nextModifier) = DiceAPI.RollWithRules(baseDice, applicableRules);
        
        result.baseRoll = rollResult;
        result.finalResult = rollResult.totalResult;
        result.accumulatedModifier = nextModifier;
        
        // Track which rules were activated
        var activatedRulesList = new List<string>();
        
        // Check critical hit
        if (rollResult.naturalResult == 20)
        {
            activatedRulesList.Add("Critical Success");
        }
        
        // Check for heroic moments (high roll + good context)
        if (rollResult.totalResult >= 18 && context.Contains("dramatic"))
        {
            activatedRulesList.Add("Heroic Moment");
        }
        
        // Check for combo potential
        if (nextModifier > 0)
        {
            activatedRulesList.Add("Combo Setup");
        }
        
        result.activatedRules = activatedRulesList.ToArray();
        
        // Build comprehensive description
        result.description = $"Roll: {rollResult.totalResult}";
        if (result.activatedRules.Length > 0)
        {
            result.description += $" (Rules: {string.Join(", ", result.activatedRules)})";
        }
        if (result.accumulatedModifier != 0)
        {
            result.description += $" [+{result.accumulatedModifier} next roll]";
        }
        
        return result;
    }
    
    private ConditionalRule[] GetApplicableRules(string context)
    {
        var rules = new List<ConditionalRule>();
        
        // Always include critical rule
        rules.Add(criticalRule);
        
        // Context-specific rules
        if (context.Contains("combat"))
        {
            rules.Add(comboRule);
        }
        
        if (context.Contains("dramatic"))
        {
            rules.Add(heroicMomentRule);
        }
        
        return rules.ToArray();
    }
}

Performance and Optimization

Configuration Management

Efficient configuration caching and reuse patterns:

Configuration Cache System

public class DiceConfigurationManager : MonoBehaviour
{
    private static Dictionary<string, DiceConfiguration> configCache = 
        new Dictionary<string, DiceConfiguration>();
    
    // Common configurations
    public static DiceConfiguration GetD20Config()
    {
        return GetOrCreateConfig("d20", () => {
            var config = ScriptableObject.CreateInstance<DiceConfiguration>();
            config.sides = 20;
            config.modifier = 0;
            config.rollType = RollType.Normal;
            return config;
        });
    }
    
    public static DiceConfiguration GetAdvantageD20Config()
    {
        return GetOrCreateConfig("d20_advantage", () => {
            var config = ScriptableObject.CreateInstance<DiceConfiguration>();
            config.sides = 20;
            config.modifier = 0;
            config.rollType = RollType.Advantage;
            return config;
        });
    }
    
    public static DiceConfiguration GetWeaponDamageConfig(int diceSides, int modifier)
    {
        string key = $"weapon_{diceSides}_{modifier}";
        return GetOrCreateConfig(key, () => {
            var config = ScriptableObject.CreateInstance<DiceConfiguration>();
            config.sides = diceSides;
            config.modifier = modifier;
            config.rollType = RollType.Normal;
            return config;
        });
    }
    
    private static DiceConfiguration GetOrCreateConfig(string key, 
                                                      System.Func<DiceConfiguration> factory)
    {
        if (!configCache.ContainsKey(key))
        {
            configCache[key] = factory();
        }
        return configCache[key];
    }
    
    // Cleanup method for memory management
    public static void ClearCache()
    {
        foreach (var config in configCache.Values)
        {
            if (config != null)
            {
                DestroyImmediate(config);
            }
        }
        configCache.Clear();
    }
}

Statistical Validation

Using the probability engine for game balance validation:

Balance Validation System

public class BalanceValidator : MonoBehaviour
{
    public class BalanceReport
    {
        public string testName;
        public float successRate;
        public float averageResult;
        public bool isBalanced;
        public string recommendation;
    }
    
    public BalanceReport ValidateWeaponBalance(DiceConfiguration weaponConfig, int targetAC)
    {
        var report = new BalanceReport();
        report.testName = $"Weapon vs AC {targetAC}";
        
        // Analyze hit probability
        var hitProbability = DiceAPI.CalculateProbability(
            weaponConfig, targetAC, ComparisonType.GreaterEqual, 50000);
        
        report.successRate = hitProbability.percentage;
        report.averageResult = hitProbability.average;
        
        // Balance evaluation
        if (report.successRate >= 60f && report.successRate <= 80f)
        {
            report.isBalanced = true;
            report.recommendation = "Weapon balance is within acceptable range";
        }
        else if (report.successRate < 60f)
        {
            report.isBalanced = false;
            report.recommendation = "Weapon may be too weak - consider increasing attack bonus";
        }
        else
        {
            report.isBalanced = false;
            report.recommendation = "Weapon may be too strong - consider adjusting modifiers";
        }
        
        Debug.Log($"Balance Report: {report.testName}");
        Debug.Log($"Hit Rate: {report.successRate:F1}%");
        Debug.Log($"Average Roll: {report.averageResult:F1}");
        Debug.Log($"Recommendation: {report.recommendation}");
        
        return report;
    }
    
    public void ValidateMultipleWeapons(DiceConfiguration[] weapons, int[] targetACs)
    {
        foreach (var weapon in weapons)
        {
            foreach (var ac in targetACs)
            {
                var report = ValidateWeaponBalance(weapon, ac);
                // Store or process report as needed
            }
        }
    }
}

Seeded Generation

Ensuring consistent results across game sessions:

Seeded Game Session

public class SeededGameSession : MonoBehaviour
{
    [SerializeField] private string sessionSeed = "GameSession2024";
    [SerializeField] private bool useSeededGeneration = true;
    
    public class SessionState
    {
        public string currentSeed;
        public int rollCount;
        public List<int> rollHistory;
    }
    
    private SessionState currentSession;
    
    void Start()
    {
        InitializeSession();
    }
    
    public void InitializeSession()
    {
        currentSession = new SessionState();
        currentSession.rollHistory = new List<int>();
        
        if (useSeededGeneration)
        {
            // Initialize with deterministic seed
            DiceAPI.InitializeSeed(sessionSeed);
            currentSession.currentSeed = sessionSeed;
            Debug.Log($"Session initialized with seed: {sessionSeed}");
        }
        else
        {
            // Use system random
            DiceAPI.InitializeSystemRandom();
            currentSession.currentSeed = "System Random";
            Debug.Log("Session using system random generation");
        }
    }
    
    public int MakeSeededRoll(int sides, int modifier = 0)
    {
        int result = DiceAPI.Roll(sides, modifier);
        
        // Track roll for session replay
        currentSession.rollHistory.Add(result);
        currentSession.rollCount++;
        
        Debug.Log($"Roll #{currentSession.rollCount}: d{sides}+{modifier} = {result}");
        
        return result;
    }
    
    public bool ValidateSessionReplay()
    {
        if (!useSeededGeneration)
        {
            Debug.LogWarning("Cannot validate replay without seeded generation");
            return false;
        }
        
        // Re-initialize with same seed
        var originalHistory = new List<int>(currentSession.rollHistory);
        DiceAPI.InitializeSeed(sessionSeed);
        
        // Re-execute all rolls
        bool isValid = true;
        for (int i = 0; i < originalHistory.Count; i++)
        {
            int replayResult = DiceAPI.Roll(20); // Example: assuming d20 rolls
            if (replayResult != originalHistory[i])
            {
                Debug.LogError($"Replay validation failed at roll {i + 1}");
                isValid = false;
                break;
            }
        }
        
        Debug.Log($"Session replay validation: {(isValid ? "PASSED" : "FAILED")}");
        return isValid;
    }
}
Implementation Notes: These examples demonstrate real framework features and patterns. Each code sample is based on the actual Ultimate Dice Roll Toolkit API and can be adapted for your specific game requirements. Remember to cache configurations for performance and use seeded generation when consistency is important.

Quick Nav