using System.Collections.Generic; using log4net; using ACE.Common; using ACE.Database.Models.World; namespace ACE.Server.Factories.Tables { public static class QualityChance { private static readonly ILog log = LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType); private static readonly List QualityChancePerTier = new List() { 0.5f, 0.6f, 0.7f, 0.8f, 0.9f, 1.0f, 1.0f, 1.0f }; private static readonly List T1_QualityChances = new List() { 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, }; private static readonly List T2_QualityChances = new List() { 0.75f, 1.00f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, }; private static readonly List T3_QualityChances = new List() { 0.20f, 0.50f, 0.80f, 1.00f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, }; private static readonly List T4_QualityChances = new List() { 0.0f, 0.10f, 0.30f, 0.70f, 0.90f, 1.00f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, }; private static readonly List T5_QualityChances = new List() { 0.0f, 0.0f, 0.10f, 0.30f, 0.70f, 0.90f, 1.00f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, }; private static readonly List T6_QualityChances = new List() { 0.0f, 0.0f, 0.0f, 0.10f, 0.25f, 0.50f, 0.75f, 0.90f, 1.00f, 0.0f, 0.0f, 0.0f, }; private static readonly List T7_QualityChances = new List() { 0.0f, 0.0f, 0.0f, 0.0f, 0.10f, 0.25f, 0.50f, 0.75f, 0.90f, 1.00f, 0.0f, 0.0f, }; private static readonly List T8_QualityChances = new List() { 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.10f, 0.25f, 0.50f, 0.75f, 0.90f, 1.00f, }; /// /// Returns the quality chance tables for a tier /// public static List GetQualityChancesForTier(int tier) { switch (tier) { case 1: default: return T1_QualityChances; case 2: return T2_QualityChances; case 3: return T3_QualityChances; case 4: return T4_QualityChances; case 5: return T5_QualityChances; case 6: return T6_QualityChances; case 7: return T7_QualityChances; case 8: return T8_QualityChances; } } /// /// Rolls for the initial chance of getting a quality bonus for an item /// /// The chances are based on treasureDeath.Tier, and can be increased with treasureDeath.LootQualityMod private static bool RollTierChance(TreasureDeath treasureDeath) { var tierChance = QualityChancePerTier[treasureDeath.Tier - 1]; // use for initial roll? logic seems backwards here... var rng = ThreadSafeRandom.NextInterval(treasureDeath.LootQualityMod); return rng < tierChance; } /// /// Returns a quality level between 1 - 12 /// public static int Roll(TreasureDeath treasureDeath) { // roll for the initial chance for any quality modification -- based on tier if (!RollTierChance(treasureDeath)) return 0; // if the initial roll succeeds, roll for the actual quality level -- also based on tier var chances = GetQualityChancesForTier(treasureDeath.Tier); //var rng = ThreadSafeRandom.NextIntervalMax(treasureDeath.LootQualityMod); var rng = ThreadSafeRandom.Next(0.0f, 1.0f); for (var i = 0; i < chances.Count; i++) { var curChance = chances[i]; if (rng < curChance && curChance >= treasureDeath.LootQualityMod) return i + 1; } log.Error($"QualityTables.Roll({treasureDeath.Tier}, {treasureDeath.LootQualityMod}) - this shouldn't happen"); return 0; } /// /// Performs a weighted RNG roll /// linearly interpolates between discrete values /// /// A quality level between 0.0f - 1.0f, higher values = better public static float RollInterval(TreasureDeath treasureDeath) { // roll for the initial chance for any quality modification -- based on tier if (!RollTierChance(treasureDeath)) return 0.0f; // if the initial roll succeeds, roll for the actual quality level -- also based on tier var chances = GetQualityChancesForTier(treasureDeath.Tier); //var rng = ThreadSafeRandom.NextIntervalMax(treasureDeath.LootQualityMod); var rng = ThreadSafeRandom.Next(0.0f, 1.0f); for (var i = 0; i < chances.Count; i++) { var curChance = chances[i]; if (rng < curChance && curChance >= treasureDeath.LootQualityMod) { var prevChance = i > 0 ? chances[i - 1] : 0; var dx = curChance - prevChance; var dy = 1.0f / chances.Count; var interval = (rng - prevChance) / dx; return (float)(dy * (interval + i)); } } log.Error($"QualityTables.RollInterval({treasureDeath.Tier}, {treasureDeath.LootQualityMod}) - this shouldn't happen"); return 0.0f; } } }