Пример #1
0
        public static string TestLootGen(int numItems, int tier, bool logstats, string displaytable)
        {
            string displayHeader = $"\n LootFactory Simulator - Items\n ---------------------\n";

            Console.WriteLine($"Creating {numItems} items, that are in tier {tier}");

            var ls = new LootStats(logstats);

            // Create a dummy treasure profile for passing in tier value
            TreasureDeath profile = new TreasureDeath
            {
                Tier           = tier,
                LootQualityMod = 0
            };

            // Loop depending on how many items you are creating
            for (int i = 0; i < numItems; i++)
            {
                var testItem = LootGenerationFactory.CreateRandomLootObjects(profile, true);
                ls = LootStats(testItem, ls, logstats);
            }
            Console.WriteLine(displayHeader);
            Console.WriteLine(DisplayStats(ls, displaytable));
            displayHeader += $" A total of {ls.TotalItems} items were generated in Tier {tier}. \n";
            if (logstats)
            {
                string myfilename = string.Format("LootSim-{0:hh-mm-ss-tt_MM-dd-yyyy}.csv", DateTime.Now);
                File.WriteAllText(myfilename, displayHeader + DisplayStats(ls, displaytable));
            }

            return(displayHeader);
        }
Пример #2
0
        private static bool AssignArmorLevel_New(WorldObject wo, TreasureDeath profile, TreasureRoll roll)
        {
            // retail was only divied up into a few different mutation scripts here
            // anything with ArmorLevel ran these mutation scripts
            // anything that covered extremities (head / hand / foot wear) started with a slightly higher base AL,
            // but otherwise used the same mutation as anything that covered non-extremities
            // shields also had their own mutation script

            // only exceptions found: covenant armor, olthoi armor, metal cap

            if (!roll.HasArmorLevel(wo))
            {
                return(false);
            }

            var scriptName = GetMutationScript_ArmorLevel(wo, roll);

            if (scriptName == null)
            {
                log.Error($"AssignArmorLevel_New({wo.Name}, {profile.TreasureType}, {roll.ItemType}) - unknown item type");
                return(false);
            }

            //Console.WriteLine($"Mutating {wo.Name} with {scriptName}");

            var mutationFilter = MutationCache.GetMutation(scriptName);

            return(mutationFilter.TryMutate(wo, profile.Tier));
        }
Пример #3
0
        private static void MutateCaster_SpellDID(WorldObject wo, TreasureDeath profile)
        {
            var firstSpell = CasterSlotSpells.Roll(wo);

            var spellLevels = SpellLevelProgression.GetSpellLevels(firstSpell);

            if (spellLevels == null)
            {
                log.Error($"MutateCaster_SpellDID: couldn't find {firstSpell}");
                return;
            }

            if (spellLevels.Count != 8)
            {
                log.Error($"MutateCaster_SpellDID: found {spellLevels.Count} spell levels for {firstSpell}, expected 8");
                return;
            }

            int minSpellLevel = GetLowSpellTier(profile.Tier);
            int maxSpellLevel = GetHighSpellTier(profile.Tier);

            var spellLevel = ThreadSafeRandom.Next(minSpellLevel, maxSpellLevel);

            wo.SpellDID = (uint)spellLevels[spellLevel - 1];

            var spell = new Server.Entity.Spell(wo.SpellDID.Value);

            wo.ItemManaCost = (int)spell.BaseMana * 5;

            wo.ItemUseable = Usable.SourceWieldedTargetRemoteNeverWalk;
        }
Пример #4
0
        private static void MutateCaster_SpellDID(WorldObject wo, TreasureDeath profile)
        {
            var firstSpell = CasterSlotSpells.Roll(wo);

            var spellLevels = SpellLevelProgression.GetSpellLevels(firstSpell);

            if (spellLevels == null)
            {
                log.Error($"MutateCaster_SpellDID: couldn't find {firstSpell}");
                return;
            }

            if (spellLevels.Count != 8)
            {
                log.Error($"MutateCaster_SpellDID: found {spellLevels.Count} spell levels for {firstSpell}, expected 8");
                return;
            }

            var spellLevel = SpellLevelChance.Roll(profile.Tier);

            wo.SpellDID = (uint)spellLevels[spellLevel - 1];

            var spell = new Server.Entity.Spell(wo.SpellDID.Value);

            var castableMod = CasterSlotSpells.IsOrb(wo) ? 5.0f : 2.5f;

            wo.ItemManaCost = (int)(spell.BaseMana * castableMod);

            wo.ItemUseable = Usable.SourceWieldedTargetRemoteNeverWalk;
        }
Пример #5
0
        private static WorldObject CreateJewelry(TreasureDeath profile, bool isMagical, bool mutate = true)
        {
            // 31% chance ring, 31% chance bracelet, 30% chance necklace 8% chance Trinket

            int jewelrySlot = ThreadSafeRandom.Next(1, 100);
            int jewelType;

            // Made this easier to read (switch -> if statement)
            if (jewelrySlot <= 31)
            {
                jewelType = LootTables.ringItems[ThreadSafeRandom.Next(0, LootTables.ringItems.Length - 1)];
            }
            else if (jewelrySlot <= 62)
            {
                jewelType = LootTables.braceletItems[ThreadSafeRandom.Next(0, LootTables.braceletItems.Length - 1)];
            }
            else if (jewelrySlot <= 92)
            {
                jewelType = LootTables.necklaceItems[ThreadSafeRandom.Next(0, LootTables.necklaceItems.Length - 1)];
            }
            else
            {
                jewelType = LootTables.trinketItems[ThreadSafeRandom.Next(0, LootTables.trinketItems.Length - 1)];
            }

            WorldObject wo = WorldObjectFactory.CreateNewWorldObject((uint)jewelType);

            if (wo != null && mutate)
            {
                MutateJewelry(wo, profile, isMagical);
            }

            return(wo);
        }
Пример #6
0
        private static WorldObject TryRollAetheria(TreasureDeath profile)
        {
            var aetheria_drop_rate = (float)PropertyManager.GetDouble("aetheria_drop_rate").Item;

            if (aetheria_drop_rate <= 0.0f)
            {
                return(null);
            }

            var dropRateMod = 1.0f / aetheria_drop_rate;

            // 2% base chance in here, which turns out to be less per corpse w/ MundaneItemChance > 0,
            // when the outer MundaneItemChance roll is factored in

            // loot quality mod?
            var rng = ThreadSafeRandom.Next(0.0f, 1.0f * dropRateMod);

            if (rng < 0.02f)
            {
                return(CreateAetheria_New(profile));
            }
            else
            {
                return(null);
            }
        }
Пример #7
0
        /// <summary>
        /// Returns a quality level between 0-12
        /// </summary>
        public static int Roll(TreasureDeath treasureDeath, bool isArmorModVsType = false)
        {
            // roll for the initial chance for any quality modification -- based on tier
            if (!RollTierChance(treasureDeath, isArmorModVsType))
            {
                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.Next(treasureDeath.LootQualityMod, 1.0f);

            for (var i = 0; i < chances.Count; i++)
            {
                var curChance = chances[i];

                if (rng < curChance)
                {
                    return(i + 1);
                }
            }
            log.Error($"QualityTables.Roll({treasureDeath.Tier}, {treasureDeath.LootQualityMod}, {isArmorModVsType}) - this shouldn't happen");
            return(0);
        }
Пример #8
0
        private static bool AssignMagic_Gem_New(WorldObject wo, TreasureDeath profile, TreasureRoll roll)
        {
            // TODO: move to standard AssignMagic() pipeline

            var spell = SpellSelectionTable.Roll(1);

            var spellLevel = SpellLevelChance.Roll(profile.Tier);

            var spellLevels = SpellLevelProgression.GetSpellLevels(spell);

            if (spellLevels == null || spellLevels.Count != 8)
            {
                log.Error($"AssignMagic_Gem_New({wo.Name}, {profile.TreasureType}, {roll.ItemType}) - unknown spell {spell}");
                return(false);
            }

            var finalSpellId = spellLevels[spellLevel - 1];

            wo.SpellDID = (uint)finalSpellId;

            var _spell = new Server.Entity.Spell(finalSpellId);

            // retail spellcraft was capped at 370
            wo.ItemSpellcraft = Math.Min((int)_spell.Power, 370);

            var castableMana = (int)_spell.BaseMana * 5;

            wo.ItemMaxMana = RollItemMaxMana_New(wo, roll, castableMana);
            wo.ItemCurMana = wo.ItemMaxMana;

            // verified
            wo.ItemManaCost = castableMana;

            return(true);
        }
Пример #9
0
        /// <summary>
        /// Creates and optionally mutates a new MissileWeapon
        /// </summary>
        public static WorldObject CreateMissileWeapon(TreasureDeath profile, bool isMagical, bool mutate = true)
        {
            int weaponWeenie;

            int wieldDifficulty = RollWieldDifficulty(profile.Tier, TreasureWeaponType.MissileWeapon);

            // Changing based on wield, not tier. Refactored, less code, best results.  HarliQ 11/18/19
            if (wieldDifficulty < 315)
            {
                weaponWeenie = GetNonElementalMissileWeapon();
            }
            else
            {
                weaponWeenie = GetElementalMissileWeapon();
            }

            WorldObject wo = WorldObjectFactory.CreateNewWorldObject((uint)weaponWeenie);

            if (wo != null && mutate)
            {
                MutateMissileWeapon(wo, profile, isMagical, wieldDifficulty);
            }

            return(wo);
        }
Пример #10
0
        /// <summary>
        /// Performs a weighted RNG roll
        /// linearly interpolates between discrete values
        /// </summary>
        /// <returns>A quality level between 0.0f - 1.0f, higher values = better</returns>
        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.Next(treasureDeath.LootQualityMod, 1.0f);

            for (var i = 0; i < chances.Count; i++)
            {
                var curChance = chances[i];

                if (rng < curChance)
                {
                    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);
        }
Пример #11
0
        private static List <SpellId> RollItemSpells(WorldObject wo, TreasureDeath profile, TreasureRoll roll)
        {
            List <SpellId> spells = null;

            //if (roll.IsArmor || roll.IsArmorClothing(wo))
            if (roll.HasArmorLevel(wo))
            {
                spells = ArmorSpells.Roll(profile);
            }
            else if (roll.IsMeleeWeapon)
            {
                spells = MeleeSpells.Roll(profile);
            }
            else if (roll.IsMissileWeapon)
            {
                spells = MissileSpells.Roll(profile);
            }
            else if (roll.IsCaster)
            {
                spells = WandSpells.Roll(wo, profile);
            }
            else
            {
                log.Error($"RollItemSpells({wo.Name}) - item is not clothing / armor / weapon");
                return(null);
            }

            return(RollSpellLevels(wo, profile, spells));
        }
Пример #12
0
        public void CreateSQLINSERTStatement(TreasureDeath input, StreamWriter writer)
        {
            writer.WriteLine("INSERT INTO `treasure_death` (`treasure_Type`, `tier`, `loot_Quality_Mod`, `unknown_Chances`, `item_Chance`, `item_Min_Amount`, `item_Max_Amount`, `item_Treasure_Type_Selection_Chances`, `magic_Item_Chance`, `magic_Item_Min_Amount`, `magic_Item_Max_Amount`, `magic_Item_Treasure_Type_Selection_Chances`, `mundane_Item_Chance`, `mundane_Item_Min_Amount`, `mundane_Item_Max_Amount`, `mundane_Item_Type_Selection_Chances`)");

            var output = "VALUES (" +
                         $"{input.TreasureType}, " +
                         $"{input.Tier}, " +
                         $"{input.LootQualityMod}, " +
                         $"{input.UnknownChances}, " +
                         $"{input.ItemChance}, " +
                         $"{input.ItemMinAmount}, " +
                         $"{input.ItemMaxAmount}, " +
                         $"{input.ItemTreasureTypeSelectionChances}, " +
                         $"{input.MagicItemChance}, " +
                         $"{input.MagicItemMinAmount}, " +
                         $"{input.MagicItemMaxAmount}, " +
                         $"{input.MagicItemTreasureTypeSelectionChances}, " +
                         $"{input.MundaneItemChance}, " +
                         $"{input.MundaneItemMinAmount}, " +
                         $"{input.MundaneItemMaxAmount}, " +
                         $"{input.MundaneItemTypeSelectionChances}" +
                         ");";

            output = FixNullFields(output);

            writer.WriteLine(output);
        }
Пример #13
0
        private static void AssignMagic(WorldObject wo, TreasureDeath profile, TreasureRoll roll, bool isArmor = false)
        {
            int numSpells = 0;

            if (roll == null)
            {
                // previous method
                if (!AssignMagic_Spells(wo, profile, isArmor, out numSpells))
                {
                    return;
                }
            }
            else
            {
                // new method
                if (!AssignMagic_New(wo, profile, roll, out numSpells))
                {
                    return;
                }
            }

            wo.UiEffects = UiEffects.Magical;

            var maxBaseMana = GetMaxBaseMana(wo);

            wo.ManaRate = CalculateManaRate(maxBaseMana);

            if (roll == null)
            {
                wo.ItemMaxMana = RollItemMaxMana(numSpells, profile.Tier);
                wo.ItemCurMana = wo.ItemMaxMana;

                wo.ItemSpellcraft = RollSpellcraft(wo);
                wo.ItemDifficulty = RollItemDifficulty(wo);
            }
            else
            {
                var maxSpellMana = maxBaseMana;

                if (wo.SpellDID != null)
                {
                    var spell = new Server.Entity.Spell(wo.SpellDID.Value);

                    var castableMana = (int)spell.BaseMana * 5;

                    if (castableMana > maxSpellMana)
                    {
                        maxSpellMana = castableMana;
                    }
                }

                wo.ItemMaxMana = RollItemMaxMana_New(wo, roll, maxSpellMana);
                wo.ItemCurMana = wo.ItemMaxMana;

                wo.ItemSpellcraft = RollSpellcraft(wo, roll);

                AddActivationRequirements(wo, roll);
            }
        }
Пример #14
0
        /// <summary>
        /// Rolls for the initial chance of getting a quality bonus for an item
        /// </summary>
        /// <param name="treasureDeath">The chances are based on treasureDeath.Tier, and can be increased with treasureDeath.LootQualityMod</param>
        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);
        }
Пример #15
0
        private static int GetSpellDistribution(TreasureDeath profile, out int numMinors, out int numMajors, out int numEpics, out int numLegendaries)
        {
            int numNonCantrips = 0;

            numMinors      = 0;
            numMajors      = 0;
            numEpics       = 0;
            numLegendaries = 0;

            int nonCantripChance = ThreadSafeRandom.Next(1, 100000);

            numMinors      = GetNumMinorCantrips(profile); // All tiers have a chance for at least one minor cantrip
            numMajors      = GetNumMajorCantrips(profile);
            numEpics       = GetNumEpicCantrips(profile);
            numLegendaries = GetNumLegendaryCantrips(profile);

            //  Fixing the absurd amount of spells on items - HQ 6/21/2020
            //  From Mags Data all tiers have about the same chance for a given number of spells on items.  This is the ratio for magical items.
            //  1 Spell(s) - 46.410 %
            //  2 Spell(s) - 27.040 %
            //  3 Spell(s) - 17.850 %
            //  4 Spell(s) - 6.875 %
            //  5 Spell(s) - 1.525 %
            //  6 Spell(s) - 0.235 %
            //  7 Spell(s) - 0.065 %

            if (nonCantripChance <= 46410)
            {
                numNonCantrips = 1;
            }
            else if (nonCantripChance <= 73450)
            {
                numNonCantrips = 2;
            }
            else if (nonCantripChance <= 91300)
            {
                numNonCantrips = 3;
            }
            else if (nonCantripChance <= 98175)
            {
                numNonCantrips = 4;
            }
            else if (nonCantripChance <= 99700)
            {
                numNonCantrips = 5;
            }
            else if (nonCantripChance <= 99935)
            {
                numNonCantrips = 6;
            }
            else
            {
                numNonCantrips = 7;
            }

            return(numNonCantrips + numMinors + numMajors + numEpics + numLegendaries);
        }
Пример #16
0
        /// <summary>
        /// Default is formed from: input.TreasureType.ToString("00000")
        /// </summary>
        public string GetDefaultFileName(TreasureDeath input)
        {
            string fileName = input.TreasureType.ToString("00000");

            fileName  = IllegalInFileName.Replace(fileName, "_");
            fileName += ".sql";

            return(fileName);
        }
Пример #17
0
        /// <summary>
        /// Creates a Melee weapon object.
        /// </summary>
        /// <param name="profile"></param><param name="isMagical"></param>
        /// <returns>Returns Melee Weapon WO</returns>
        public static WorldObject CreateMeleeWeapon(TreasureDeath profile, bool isMagical, int weaponType = -1, bool mutate = true)
        {
            int weaponWeenie = 0;
            int subtype      = 0;

            int eleType = ThreadSafeRandom.Next(0, 4);

            if (weaponType == -1)
            {
                weaponType = ThreadSafeRandom.Next(0, 3);
            }

            // Weapon Types
            // 0 = Heavy
            // 1 = Light
            // 2 = Finesse
            // default = Two Handed
            switch (weaponType)
            {
            case 0:
                // Heavy Weapons
                subtype      = ThreadSafeRandom.Next(0, LootTables.HeavyWeaponsMatrix.Length - 1);
                weaponWeenie = LootTables.HeavyWeaponsMatrix[subtype][eleType];
                break;

            case 1:
                // Light Weapons
                subtype      = ThreadSafeRandom.Next(0, LootTables.LightWeaponsMatrix.Length - 1);
                weaponWeenie = LootTables.LightWeaponsMatrix[subtype][eleType];
                break;

            case 2:
                // Finesse Weapons;
                subtype      = ThreadSafeRandom.Next(0, LootTables.FinesseWeaponsMatrix.Length - 1);
                weaponWeenie = LootTables.FinesseWeaponsMatrix[subtype][eleType];
                break;

            default:
                // Two handed
                subtype      = ThreadSafeRandom.Next(0, LootTables.TwoHandedWeaponsMatrix.Length - 1);
                weaponWeenie = LootTables.TwoHandedWeaponsMatrix[subtype][eleType];
                break;
            }

            var wo = WorldObjectFactory.CreateNewWorldObject((uint)weaponWeenie);

            if (wo != null && mutate)
            {
                if (!MutateMeleeWeapon(wo, profile, isMagical))
                {
                    log.Warn($"[LOOT] Missing needed melee weapon properties on loot item {wo.WeenieClassId} - {wo.Name} for mutations");
                    return(null);
                }
            }

            return(wo);
        }
Пример #18
0
        /// <summary>
        /// Rolls for the initial chance of getting a quality bonus for an item
        /// </summary>
        /// <param name="treasureDeath">The chances are based on treasureDeath.Tier, and can be increased with treasureDeath.LootQualityMod</param>
        /// <param name="isArmorModVsType">ArmorModVsType has a separate chance table</param>
        private static bool RollTierChance(TreasureDeath treasureDeath, bool isArmorModVsType = false)
        {
            var tierChance = isArmorModVsType ? QualityChancePerTier_ArmorModVsType[treasureDeath.Tier - 1] : QualityChancePerTier[treasureDeath.Tier - 1];

            // use for initial roll? logic seems backwards here...
            var rng = ThreadSafeRandom.Next(0.0f, 1.0f) - treasureDeath.LootQualityMod;

            return(rng < tierChance);
        }
Пример #19
0
        private static void MutateSocietyArmor(WorldObject wo, TreasureDeath profile, bool isMagical)
        {
            int materialType = GetMaterialType(wo, profile.Tier);

            if (materialType > 0)
            {
                wo.MaterialType = (MaterialType)materialType;
            }

            if (wo.GemCode != null)
            {
                wo.GemCount = GemCountChance.Roll(wo.GemCode.Value, profile.Tier);
            }
            else
            {
                wo.GemCount = ThreadSafeRandom.Next(1, 6);
            }

            wo.GemType = RollGemType(profile.Tier);

            int workmanship = GetWorkmanship(profile.Tier);

            wo.ItemWorkmanship = workmanship;

            double materialMod    = LootTables.getMaterialValueModifier(wo);
            double gemMaterialMod = LootTables.getGemMaterialValueModifier(wo);
            var    value          = GetValue(profile.Tier, workmanship, gemMaterialMod, materialMod);

            wo.Value = value;

            // wo.WieldSkillType = (int)Skill.Axe;  // Set by examples from PCAP data

            if (isMagical)
            {
                // looks like society armor always had impen on it
                AssignMagic(wo, profile, true);
            }
            else
            {
                wo.ItemManaCost   = null;
                wo.ItemMaxMana    = null;
                wo.ItemCurMana    = null;
                wo.ItemSpellcraft = null;
                wo.ItemDifficulty = null;
            }
            wo = AssignArmorLevel(wo, profile.Tier, LootTables.ArmorType.SocietyArmor);

            wo.LongDesc = GetLongDesc(wo);

            // try mutate burden, if MutateFilter exists
            if (wo.HasMutateFilter(MutateFilter.EncumbranceVal))
            {
                MutateBurden(wo, profile, false);
            }
        }
        private static void MutateJewelry(WorldObject wo, TreasureDeath profile, bool isMagical)
        {
            wo.AppraisalLongDescDecoration = AppraisalLongDescDecorations.PrependWorkmanship;
            wo.LongDesc = wo.Name;
            int materialType = GetMaterialType(wo, profile.Tier);

            if (materialType > 0)
            {
                wo.MaterialType = (MaterialType)materialType;
            }
            int gemCount = ThreadSafeRandom.Next(1, 5);
            int gemType  = ThreadSafeRandom.Next(10, 50);

            wo.GemCount = gemCount;
            wo.GemType  = (MaterialType)gemType;
            int workmanship = GetWorkmanship(profile.Tier);

            double materialMod    = LootTables.getMaterialValueModifier(wo);
            double gemMaterialMod = LootTables.getGemMaterialValueModifier(wo);
            var    value          = GetValue(profile.Tier, workmanship, gemMaterialMod, materialMod);

            wo.Value           = value;
            wo.ItemWorkmanship = workmanship;

            wo.ItemSkillLevelLimit = null;

            if (profile.Tier > 6)
            {
                wo.WieldRequirements = WieldRequirement.Level;
                wo.WieldSkillType    = (int)Skill.Axe; // Set by examples from PCAP data

                var wield = profile.Tier switch
                {
                    7 => 150, // In this instance, used for indicating player level, rather than skill level
                    _ => 180, // In this instance, used for indicating player level, rather than skill level
                };
                wo.WieldDifficulty = wield;
            }

            if (isMagical)
            {
                wo = AssignMagic(wo, profile);
            }
            else
            {
                wo.ItemManaCost   = null;
                wo.ItemMaxMana    = null;
                wo.ItemCurMana    = null;
                wo.ItemSpellcraft = null;
                wo.ItemDifficulty = null;
                wo.ManaRate       = null;
            }

            RandomizeColor(wo);
        }
Пример #21
0
        private static bool AssignMagic_New(WorldObject wo, TreasureDeath profile, TreasureRoll roll, out int numSpells)
        {
            var spells = RollSpells(wo, profile, roll);

            foreach (var spell in spells)
            {
                wo.Biota.GetOrAddKnownSpell((int)spell, wo.BiotaDatabaseLock, out _);
            }
            numSpells = spells.Count;
            return(true);
        }
Пример #22
0
        /// <summary>
        /// Creates a Melee weapon object.
        /// </summary>
        /// <param name="profile"></param><param name="isMagical"></param>
        /// <returns>Returns Melee Weapon WO</returns>
        public static WorldObject CreateMeleeWeapon(TreasureDeath profile, bool isMagical, int weaponType = -1, bool mutate = true)
        {
            int weaponWeenie = 0;
            int subtype      = 0;

            int eleType = ThreadSafeRandom.Next(0, 4);

            if (weaponType == -1)
            {
                weaponType = ThreadSafeRandom.Next(0, 3);
            }

            // Weapon Types
            // 0 = Heavy
            // 1 = Light
            // 2 = Finesse
            // default = Two Handed
            switch (weaponType)
            {
            case 0:
                // Heavy Weapons
                subtype      = ThreadSafeRandom.Next(0, 22);
                weaponWeenie = LootTables.HeavyWeaponsMatrix[subtype][eleType];
                break;

            case 1:
                // Light Weapons
                subtype      = ThreadSafeRandom.Next(0, 19);
                weaponWeenie = LootTables.LightWeaponsMatrix[subtype][eleType];
                break;

            case 2:
                // Finesse Weapons;
                subtype      = ThreadSafeRandom.Next(0, 22);
                weaponWeenie = LootTables.FinesseWeaponsMatrix[subtype][eleType];
                break;

            default:
                // Two handed
                subtype      = ThreadSafeRandom.Next(0, 11);
                weaponWeenie = LootTables.TwoHandedWeaponsMatrix[subtype][eleType];
                break;
            }

            var wo = WorldObjectFactory.CreateNewWorldObject((uint)weaponWeenie);

            if (wo != null && mutate)
            {
                MutateMeleeWeapon(wo, profile, isMagical, weaponType, subtype);
            }

            return(wo);
        }
        private static WorldObject CreateAetheria_New(TreasureDeath profile, bool mutate = true)
        {
            var wcid = AetheriaWcids.Roll(profile.Tier);

            var wo = WorldObjectFactory.CreateNewWorldObject((uint)wcid);

            if (mutate)
            {
                MutateAetheria_New(wo, profile);
            }

            return(wo);
        }
Пример #24
0
        public static WeenieClassName Roll(TreasureDeath treasureDeath, TreasureWeaponType weaponType)
        {
            switch (weaponType)
            {
            /*case TreasureWeaponType.Sword:
             *  return RollSwordWcid(treasureDeath);
             *
             * case TreasureWeaponType.Mace:
             *  return RollMaceWcid(treasureDeath);
             *
             * case TreasureWeaponType.Axe:
             *  return RollAxeWcid(treasureDeath);
             *
             * case TreasureWeaponType.Spear:
             *  return RollSpearWcid(treasureDeath);
             *
             * case TreasureWeaponType.Unarmed:
             *  return RollUnarmedWcid(treasureDeath);
             *
             * case TreasureWeaponType.Staff:
             *  return RollStaffWcid(treasureDeath);
             *
             * case TreasureWeaponType.Dagger:
             *  return RollDaggerWcid(treasureDeath);*/

            case TreasureWeaponType.Sword:
            case TreasureWeaponType.Mace:
            case TreasureWeaponType.Axe:
            case TreasureWeaponType.Spear:
            case TreasureWeaponType.Unarmed:
            case TreasureWeaponType.Staff:
            case TreasureWeaponType.Dagger:
                return(RollMeleeWeapon());

            case TreasureWeaponType.Bow:
                return(RollBowWcid(treasureDeath));

            case TreasureWeaponType.Crossbow:
                return(RollCrossbowWcid(treasureDeath));

            case TreasureWeaponType.Atlatl:
                return(RollAtlatlWcid(treasureDeath));

            case TreasureWeaponType.Caster:
                return(RollCaster(treasureDeath));

            case TreasureWeaponType.TwoHandedWeapon:
                return(RollTwoHandedWeaponWcid());
            }
            return(WeenieClassName.undef);
        }
Пример #25
0
        /// <summary>
        /// Creates and optionally mutates a new MeleeWeapon
        /// </summary>
        public static WorldObject CreateMeleeWeapon(TreasureDeath profile, bool isMagical, MeleeWeaponSkill weaponSkill = MeleeWeaponSkill.Undef, bool mutate = true)
        {
            var wcid       = 0;
            var weaponType = 0;

            var eleType = ThreadSafeRandom.Next(0, 4);

            if (weaponSkill == MeleeWeaponSkill.Undef)
            {
                weaponSkill = (MeleeWeaponSkill)ThreadSafeRandom.Next(1, 4);
            }

            switch (weaponSkill)
            {
            case MeleeWeaponSkill.HeavyWeapons:

                weaponType = ThreadSafeRandom.Next(0, LootTables.HeavyWeaponsMatrix.Length - 1);
                wcid       = LootTables.HeavyWeaponsMatrix[weaponType][eleType];
                break;

            case MeleeWeaponSkill.LightWeapons:

                weaponType = ThreadSafeRandom.Next(0, LootTables.LightWeaponsMatrix.Length - 1);
                wcid       = LootTables.LightWeaponsMatrix[weaponType][eleType];
                break;

            case MeleeWeaponSkill.FinesseWeapons:

                weaponType = ThreadSafeRandom.Next(0, LootTables.FinesseWeaponsMatrix.Length - 1);
                wcid       = LootTables.FinesseWeaponsMatrix[weaponType][eleType];
                break;

            case MeleeWeaponSkill.TwoHandedCombat:

                weaponType = ThreadSafeRandom.Next(0, LootTables.TwoHandedWeaponsMatrix.Length - 1);
                wcid       = LootTables.TwoHandedWeaponsMatrix[weaponType][eleType];
                break;
            }

            var wo = WorldObjectFactory.CreateNewWorldObject((uint)wcid);

            if (wo != null && mutate)
            {
                if (!MutateMeleeWeapon(wo, profile, isMagical))
                {
                    log.Warn($"[LOOT] {wo.WeenieClassId} - {wo.Name} is not a MeleeWeapon");
                    return(null);
                }
            }
            return(wo);
        }
Пример #26
0
        private static int GetNumEpicCantrips(TreasureDeath profile)
        {
            int numEpics = 0;

            if (profile.Tier < 7)
            {
                return(0);
            }

            var dropRate = PropertyManager.GetDouble("epic_cantrip_drop_rate").Item;

            if (dropRate <= 0)
            {
                return(0);
            }

            var dropRateMod = 1.0 / dropRate;

            double lootQualityMod = 1.0f;

            if (PropertyManager.GetBool("loot_quality_mod").Item&& profile.LootQualityMod > 0 && profile.LootQualityMod < 1)
            {
                lootQualityMod = 1.0f - profile.LootQualityMod;
            }

            // 25% base chance for no epics for tier 7
            if (ThreadSafeRandom.Next(1, 4) > 1)
            {
                // 1% chance for 1 Epic, 0.1% chance for 2 Epics,
                // 0.01% chance for 3 Epics, 0.001% chance for 4 Epics
                if (ThreadSafeRandom.Next(1, (int)(100 * dropRateMod * lootQualityMod)) == 1)
                {
                    numEpics = 1;
                }
                if (ThreadSafeRandom.Next(1, (int)(1000 * dropRateMod * lootQualityMod)) == 1)
                {
                    numEpics = 2;
                }
                if (ThreadSafeRandom.Next(1, (int)(10000 * dropRateMod * lootQualityMod)) == 1)
                {
                    numEpics = 3;
                }
                if (ThreadSafeRandom.Next(1, (int)(100000 * dropRateMod * lootQualityMod)) == 1)
                {
                    numEpics = 4;
                }
            }

            return(numEpics);
        }
Пример #27
0
        public static WeenieClassName Roll(TreasureDeath profile)
        {
            // roll for pet level
            var petLevel = PetDeviceChance.Roll(profile);

            // even chance of rolling each pet device type
            var rng = ThreadSafeRandom.Next(0, petDevices.Count - 1);

            var table = petDevices[rng];

            var petLevelIdx = petLevelIndexes[petLevel];

            return(table[petLevelIdx]);
        }
Пример #28
0
        private static WorldObject TryRollMundaneAddon(TreasureDeath profile)
        {
            // coalesced mana only dropped in tiers 1-4
            if (profile.Tier <= 4)
            {
                return(TryRollCoalescedMana(profile));
            }

            // aetheria dropped in tiers 5+
            else
            {
                return(TryRollAetheria(profile));
            }
        }
Пример #29
0
        private static List <SpellId> RollCantrips(WorldObject wo, TreasureDeath profile, TreasureRoll roll)
        {
            // no cantrips on dinnerware?
            if (roll.ItemType == TreasureItemType_Orig.ArtObject)
            {
                return(null);
            }

            var numCantrips = CantripChance.RollNumCantrips(profile);

            if (numCantrips == 0)
            {
                return(null);
            }

            var numAttempts = numCantrips * 3;

            var cantrips = new HashSet <SpellId>();

            for (var i = 0; i < numAttempts && cantrips.Count < numCantrips; i++)
            {
                var cantrip = RollCantrip(wo, profile, roll);

                cantrip = AdjustForWeaponMastery(wo, cantrip);

                if (cantrip != SpellId.Undef)
                {
                    cantrips.Add(cantrip);
                }
            }

            var finalCantrips = new List <SpellId>();

            foreach (var cantrip in cantrips)
            {
                var cantripLevel = CantripChance.RollCantripLevel(profile);

                var cantripLevels = SpellLevelProgression.GetSpellLevels(cantrip);

                if (cantripLevels.Count != 4)
                {
                    log.Error($"RollCantrips({wo.Name}, {profile.TreasureType}, {roll.ItemType}) - {cantrip} has {cantripLevels.Count} cantrip levels, expected 4");
                    continue;
                }

                finalCantrips.Add(cantripLevels[cantripLevel - 1]);
            }
            return(finalCantrips);
        }
Пример #30
0
        private static SpellId RollCantrip(WorldObject wo, TreasureDeath profile, TreasureRoll roll)
        {
            if (roll.HasArmorLevel(wo) || roll.IsClothing)
            {
                // armor / clothing cantrip
                // this table also applies to crowns (treasureitemtype.jewelry w/ al)
                return(ArmorCantrips.Roll());
            }
            if (roll.IsMeleeWeapon)
            {
                // melee cantrip
                var meleeCantrip = MeleeCantrips.Roll();

                // adjust for weapon skill
                if (meleeCantrip == SpellId.CANTRIPLIGHTWEAPONSAPTITUDE1)
                {
                    meleeCantrip = AdjustForWeaponMastery(wo);
                }

                return(meleeCantrip);
            }
            else if (roll.IsMissileWeapon)
            {
                // missile cantrip
                return(MissileCantrips.Roll());
            }
            else if (roll.IsCaster)
            {
                // caster cantrip
                var casterCantrip = WandCantrips.Roll();

                if (casterCantrip == SpellId.CANTRIPWARMAGICAPTITUDE1)
                {
                    casterCantrip = AdjustForDamageType(wo, casterCantrip);
                }

                return(casterCantrip);
            }
            else if (roll.IsJewelry)
            {
                // jewelry cantrip
                return(JewelryCantrips.Roll());
            }
            else
            {
                log.Error($"RollCantrip({wo.Name}, {profile.TreasureType}, {roll.ItemType}) - unknown item type");
                return(SpellId.Undef);
            }
        }