Пример #1
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);
            }
        }
Пример #2
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);
        }
Пример #3
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);
            }
        }
Пример #4
0
        private static string GetMutationScript_ArmorLevel(WorldObject wo, TreasureRoll roll)
        {
            switch (roll.ArmorType)
            {
            case TreasureArmorType.Covenant:

                if (wo.IsShield)
                {
                    return("ArmorLevel.covenant_shield.txt");
                }
                else
                {
                    return("ArmorLevel.covenant_armor.txt");
                }

            case TreasureArmorType.Olthoi:

                if (wo.IsShield)
                {
                    return("ArmorLevel.olthoi_shield.txt");
                }
                else
                {
                    return("ArmorLevel.olthoi_armor.txt");
                }
            }

            if (wo.IsShield)
            {
                return("ArmorLevel.shield_level.txt");
            }

            var coverage = wo.ClothingPriority ?? 0;

            if ((coverage & (CoverageMask)CoverageMaskHelper.Extremities) != 0)
            {
                return("ArmorLevel.armor_level_extremity.txt");
            }
            else if ((coverage & (CoverageMask)CoverageMaskHelper.Outerwear) != 0)
            {
                return("ArmorLevel.armor_level_non_extremity.txt");
            }
            else
            {
                return(null);
            }
        }
Пример #5
0
        private static WorldObject CreateRandomScroll(TreasureDeath profile, TreasureRoll roll = null)
        {
            // level 8 spell components shouldn't be in here,
            // they should be associated with TreasureItemType.SpellComponent (peas)
            if (roll == null && profile.Tier >= 7)
            {
                // According to wiki, Tier 7 has a chance for level 8 spell components or level 7 spell scrolls (as does Tier 8)
                // No indication of weighting in either direction, so assuming a 50/50 split
                var rng = ThreadSafeRandom.Next(0.0f, 1.0f);

                if (rng < 0.5f)
                {
                    var wcid = RollLevel8SpellComp();

                    return(WorldObjectFactory.CreateNewWorldObject((uint)wcid));
                }
            }
            var spellLevel = ScrollLevelChance.Roll(profile);

            // todo: switch to SpellLevelProgression
            var spellId = SpellId.Undef;

            do
            {
                var spellIdx = ThreadSafeRandom.Next(0, ScrollSpells.Table.Length - 1);

                spellId = ScrollSpells.Table[spellIdx][spellLevel - 1];
            }while (spellId == SpellId.Undef);   // simple way of handling spells that start at level 3 (blasts, volleys)

            var weenie = DatabaseManager.World.GetScrollWeenie((uint)spellId);

            if (weenie == null)
            {
                log.DebugFormat("CreateRandomScroll for tier {0} and spellID of {1} returned null from the database.", profile.Tier, spellId);
                return(null);
            }

            return(WorldObjectFactory.CreateNewWorldObject(weenie.WeenieClassId));
        }
Пример #6
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));
        }
Пример #7
0
        /// <summary>
        /// An alternate method to using the SpellSelectionCode from PropertyInt.TSysMutationdata
        /// </summary>
        private static int GetSpellSelectionCode_Dynamic(WorldObject wo, TreasureRoll roll)
        {
            if (wo is Gem)
            {
                return(1);
            }
            else if (roll.ItemType == TreasureItemType_Orig.Jewelry)
            {
                if (!roll.HasArmorLevel(wo))
                {
                    return(2);
                }
                else
                {
                    return(3);
                }
            }
            else if (roll.Wcid == Enum.WeenieClassName.orb)
            {
                return(4);
            }
            else if (roll.IsCaster && wo.W_DamageType != DamageType.Nether)
            {
                return(5);
            }
            else if (roll.IsMeleeWeapon && wo.WeaponSkill != Skill.TwoHandedCombat)
            {
                return(6);
            }
            else if ((roll.IsArmor || roll.IsClothing) && !wo.IsShield)
            {
                return(GetSpellCode_Dynamic_ClothingArmor(wo, roll));
            }
            else if (wo.IsShield)
            {
                return(8);
            }
            else if (roll.IsDinnerware)
            {
                if (roll.Wcid == Enum.WeenieClassName.flasksimple)
                {
                    return(0);
                }
                else
                {
                    return(16);
                }
            }
            else if (roll.IsMissileWeapon || wo.WeaponSkill == Skill.TwoHandedCombat)
            {
                return(17);
            }
            else if (roll.IsCaster && wo.W_DamageType == DamageType.Nether)
            {
                return(19);
            }

            log.Error($"GetSpellCode_Dynamic({wo.Name}) - couldn't determine spell selection code");

            return(0);
        }
Пример #8
0
        private static List <SpellId> RollSpells(WorldObject wo, TreasureDeath profile, TreasureRoll roll)
        {
            var spells = new List <SpellId>();

            // crowns, which are classified as TreasureItemType.Jewelry, should also be getting item spells
            // perhaps replace this with wo.ArmorLevel check?
            //if (roll.IsArmor || roll.IsArmorClothing(wo) || roll.IsWeapon)
            if (roll.HasArmorLevel(wo) || roll.IsWeapon)
            {
                var itemSpells = RollItemSpells(wo, profile, roll);

                if (itemSpells != null)
                {
                    spells.AddRange(itemSpells);
                }
            }

            var enchantments = RollEnchantments(wo, profile, roll);

            if (enchantments != null)
            {
                spells.AddRange(enchantments);

                roll.ItemDifficulty += RollEnchantmentDifficulty(enchantments);
            }

            var cantrips = RollCantrips(wo, profile, roll);

            if (cantrips != null)
            {
                spells.AddRange(cantrips);

                roll.ItemDifficulty += RollCantripDifficulty(cantrips);
            }

            return(spells);
        }
Пример #9
0
        private static int RollNumEnchantments_Clothing_Jewelry_Dinnerware(WorldObject wo, TreasureDeath profile, TreasureRoll roll)
        {
            var chance = 0.1f;

            var rng = ThreadSafeRandom.NextInterval(profile.LootQualityMod);

            if (rng >= chance)
            {
                return(1);
            }
            else if (profile.Tier < 6)
            {
                return(2);
            }

            // tier 6+ has a chance for 3 enchantments
            rng = ThreadSafeRandom.NextInterval(profile.LootQualityMod * 0.1f);

            if (rng >= chance * 0.5f)
            {
                return(2);
            }
            else
            {
                return(3);
            }
        }
Пример #10
0
        private static void MutateGem(WorldObject wo, TreasureDeath profile, bool isMagical, TreasureRoll roll = null)
        {
            // workmanship
            wo.ItemWorkmanship = WorkmanshipChance.Roll(profile.Tier);

            // item color
            MutateColor(wo);

            if (!isMagical)
            {
                // TODO: verify if this is needed
                wo.ItemUseable         = Usable.No;
                wo.SpellDID            = null;
                wo.ItemManaCost        = null;
                wo.ItemMaxMana         = null;
                wo.ItemCurMana         = null;
                wo.ItemSpellcraft      = null;
                wo.ItemDifficulty      = null;
                wo.ItemSkillLevelLimit = null;
                wo.ManaRate            = null;
            }
            else
            {
                if (roll == null)
                {
                    AssignMagic_Gem(wo, profile);
                }
                else
                {
                    AssignMagic_Gem_New(wo, profile, roll);
                }

                wo.UiEffects   = UiEffects.Magical;
                wo.ItemUseable = Usable.Contained;

                wo.LongDesc = GetLongDesc(wo);
            }

            // item value, review
            var gemValue = LootTables.gemValues[(int)wo.MaterialType];

            wo.Value = gemValue + ThreadSafeRandom.Next(1, gemValue);
        }
Пример #11
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);
        }
Пример #12
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);

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

            var finalCantrips = new List <SpellId>();

            var hasLegendary = false;

            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]);

                if (cantripLevel == 4)
                {
                    hasLegendary = true;
                }
            }

            // if a legendary cantrip dropped on this item
            if (hasLegendary)
            {
                // and if the item has a level requirement, ensure the level requirement is at least 180
                // if the item does not already contain a level requirement, don't add one?

                if (wo.WieldRequirements == WieldRequirement.Level && wo.WieldDifficulty < 180)
                {
                    wo.WieldDifficulty = 180;
                }

                if (wo.WieldRequirements2 == WieldRequirement.Level && wo.WieldDifficulty2 < 180)
                {
                    wo.WieldDifficulty2 = 180;
                }
            }

            return(finalCantrips);
        }
Пример #13
0
        private static void MutateGem(WorldObject wo, TreasureDeath profile, bool isMagical, TreasureRoll roll = null)
        {
            // workmanship
            wo.ItemWorkmanship = WorkmanshipChance.Roll(profile.Tier);

            // item color
            MutateColor(wo);

            if (!isMagical)
            {
                // TODO: verify if this is needed
                wo.ItemUseable         = Usable.No;
                wo.SpellDID            = null;
                wo.ItemManaCost        = null;
                wo.ItemMaxMana         = null;
                wo.ItemCurMana         = null;
                wo.ItemSpellcraft      = null;
                wo.ItemDifficulty      = null;
                wo.ItemSkillLevelLimit = null;
                wo.ManaRate            = null;
            }
            else
            {
                if (roll == null)
                {
                    AssignMagic_Gem(wo, profile);
                }
                else
                {
                    AssignMagic_Gem_New(wo, profile, roll);
                }

                wo.UiEffects   = UiEffects.Magical;
                wo.ItemUseable = Usable.Contained;
            }

            // item value
            if (wo.HasMutateFilter(MutateFilter.Value))
            {
                MutateValue(wo, profile.Tier, roll);
            }

            // long desc
            wo.LongDesc = GetLongDesc(wo);
        }
Пример #14
0
        private static bool AssignArmorLevel_New(WorldObject wo, TreasureDeath profile, TreasureRoll roll, LootTables.ArmorType armorType)
        {
            // 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);
            }

            // persist original values for society armor
            var wieldRequirements = wo.WieldRequirements;
            var wieldSkillType    = wo.WieldSkillType;
            var wieldDifficulty   = wo.WieldDifficulty;

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

            var mutationFilter = MutationCache.GetMutation(scriptName);

            var success = mutationFilter.TryMutate(wo, profile.Tier);

            if (armorType == LootTables.ArmorType.SocietyArmor)
            {
                wo.WieldRequirements = wieldRequirements;
                wo.WieldSkillType    = wieldSkillType;
                wo.WieldDifficulty   = wieldDifficulty;
            }

            return(success);
        }
Пример #15
0
        private static List <SpellId> RollEnchantments(WorldObject wo, TreasureDeath profile, TreasureRoll roll)
        {
            /*if (wo.SpellSelectionCode == null)
             * {
             *  log.Warn($"RollEnchantments({wo.Name}) - missing spell selection code / PropertyInt.TsysMutationData");
             *  return null;
             * }*/

            // test method: determine spell selection code dynamically
            var spellSelectionCode = GetSpellSelectionCode_Dynamic(wo, roll);

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

            //Console.WriteLine($"Using spell selection code {spellSelectionCode} for {wo.Name}");

            var numEnchantments = RollNumEnchantments(wo, profile, roll);

            if (numEnchantments <= 0)
            {
                return(null);
            }

            var numAttempts = numEnchantments * 3;

            var spells = new HashSet <SpellId>();

            for (var i = 0; i < numAttempts && spells.Count < numEnchantments; i++)
            {
                var spell = SpellSelectionTable.Roll(spellSelectionCode);

                if (spell != SpellId.Undef)
                {
                    spells.Add(spell);
                }
            }

            return(RollSpellLevels(wo, profile, spells));
        }
Пример #16
0
 private static int RollNumEnchantments(WorldObject wo, TreasureDeath profile, TreasureRoll roll)
 {
     if (roll.IsArmor || roll.IsWeapon)
     {
         return(RollNumEnchantments_Armor_Weapon(wo, profile, roll));
     }
     // confirmed:
     // - crowns (classified as TreasureItemType.Jewelry) used this table
     // - clothing w/ al also used this table
     else if (roll.IsClothing || roll.IsJewelry || roll.IsDinnerware)
     {
         return(RollNumEnchantments_Clothing_Jewelry_Dinnerware(wo, profile, roll));
     }
     else
     {
         log.Warn($"RollNumEnchantments({wo.Name}, {profile.TreasureType}, {roll.ItemType}) - unknown item type");
         return(1);   // gems?
     }
 }
        private static void MutateJewelry(WorldObject wo, TreasureDeath profile, bool isMagical, TreasureRoll roll = null)
        {
            // material type
            int materialType = GetMaterialType(wo, profile.Tier);

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

            // item color
            MutateColor(wo);

            // gem count / gem material
            if (wo.GemCode != null)
            {
                wo.GemCount = GemCountChance.Roll(wo.GemCode.Value, profile.Tier);
            }
            else
            {
                wo.GemCount = ThreadSafeRandom.Next(1, 5);
            }

            wo.GemType = RollGemType(profile.Tier);

            // workmanship
            wo.ItemWorkmanship = WorkmanshipChance.Roll(profile.Tier);

            // wield requirements (verify)
            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;
            }

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

            // gear rating (t8)
            if (roll != null && profile.Tier == 8)
            {
                TryMutateGearRating(wo, profile, roll);
            }

            // item value
            wo.Value = Roll_ItemValue(wo, profile.Tier);

            wo.LongDesc = GetLongDesc(wo);
        }
Пример #18
0
        private static int RollNumEnchantments_Armor_Weapon(WorldObject wo, TreasureDeath profile, TreasureRoll roll)
        {
            var tierChances = roll.IsCaster ? EnchantmentChances_Caster : EnchantmentChances_Armor_MeleeMissileWeapon;

            var chance = tierChances[profile.Tier - 1];

            var rng = ThreadSafeRandom.NextInterval(profile.LootQualityMod);

            if (rng < chance)
            {
                return(1);
            }
            else
            {
                return(0);
            }
        }
Пример #19
0
        private static bool MutateMeleeWeapon(WorldObject wo, TreasureDeath profile, bool isMagical, TreasureRoll roll = null)
        {
            if (!(wo is MeleeWeapon))
            {
                return(false);
            }

            if (roll == null)
            {
                // previous method
                var wieldDifficulty = RollWieldDifficulty(profile.Tier, TreasureWeaponType.MeleeWeapon);

                if (!MutateStats_OldMethod(wo, profile, wieldDifficulty))
                {
                    return(false);
                }
            }
            else
            {
                // thanks to 4eyebiped for helping with the data analysis of magloot retail logs
                // that went into reversing these mutation scripts

                var weaponSkill = wo.WeaponSkill.ToMeleeWeaponSkill();

                // mutate Damage / WieldDifficulty / Variance
                var scriptName = GetDamageScript(weaponSkill, roll.WeaponType);

                var mutationFilter = MutationCache.GetMutation(scriptName);

                mutationFilter.TryMutate(wo, profile.Tier);

                // mutate WeaponOffense / WeaponDefense
                scriptName = GetOffenseDefenseScript(weaponSkill, roll.WeaponType);

                mutationFilter = MutationCache.GetMutation(scriptName);

                mutationFilter.TryMutate(wo, profile.Tier);
            }

            // weapon speed
            if (wo.WeaponTime != null)
            {
                var weaponSpeedMod = RollWeaponSpeedMod(profile);
                wo.WeaponTime = (int)(wo.WeaponTime * weaponSpeedMod);
            }

            // material type
            var materialType = GetMaterialType(wo, profile.Tier);

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

            // item color
            MutateColor(wo);

            // gem count / gem material
            if (wo.GemCode != null)
            {
                wo.GemCount = GemCountChance.Roll(wo.GemCode.Value, profile.Tier);
            }
            else
            {
                wo.GemCount = ThreadSafeRandom.Next(1, 5);
            }

            wo.GemType = RollGemType(profile.Tier);

            // workmanship
            wo.ItemWorkmanship = WorkmanshipChance.Roll(profile.Tier);

            // burden
            MutateBurden(wo, profile, true);

            // missile / magic defense
            wo.WeaponMissileDefense = MissileMagicDefense.Roll(profile.Tier);
            wo.WeaponMagicDefense   = MissileMagicDefense.Roll(profile.Tier);

            // spells
            if (!isMagical)
            {
                // clear base
                wo.ItemManaCost   = null;
                wo.ItemMaxMana    = null;
                wo.ItemCurMana    = null;
                wo.ItemSpellcraft = null;
                wo.ItemDifficulty = null;
            }
            else
            {
                AssignMagic(wo, profile, roll);
            }

            // item value
            //if (wo.HasMutateFilter(MutateFilter.Value))   // fixme: data
            MutateValue(wo, profile.Tier, roll);

            // long description
            wo.LongDesc = GetLongDesc(wo);

            return(true);
        }
Пример #20
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);

                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);
        }
Пример #21
0
        private static void MutateCaster(WorldObject wo, TreasureDeath profile, bool isMagical, int?wieldDifficulty = null, TreasureRoll roll = null)
        {
            if (wieldDifficulty != null)
            {
                // previous method

                var wieldRequirement = WieldRequirement.RawSkill;
                var wieldSkillType   = Skill.None;

                double elementalDamageMod = 0;

                if (wieldDifficulty == 0)
                {
                    if (profile.Tier > 6)
                    {
                        wieldRequirement = WieldRequirement.Level;
                        wieldSkillType   = Skill.Axe; // Set by examples from PCAP data

                        wieldDifficulty = 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
                        };
                    }
                }
                else
                {
                    elementalDamageMod = RollElementalDamageMod(wieldDifficulty.Value);

                    if (wo.W_DamageType == DamageType.Nether)
                    {
                        wieldSkillType = Skill.VoidMagic;
                    }
                    else
                    {
                        wieldSkillType = Skill.WarMagic;
                    }
                }

                // ManaConversionMod
                var manaConversionMod = RollManaConversionMod(profile.Tier);
                if (manaConversionMod > 0.0f)
                {
                    wo.ManaConversionMod = manaConversionMod;
                }

                // ElementalDamageMod
                if (elementalDamageMod > 1.0f)
                {
                    wo.ElementalDamageMod = elementalDamageMod;
                }

                // WieldRequirements
                if (wieldDifficulty > 0 || wieldRequirement == WieldRequirement.Level)
                {
                    wo.WieldRequirements = wieldRequirement;
                    wo.WieldSkillType    = (int)wieldSkillType;
                    wo.WieldDifficulty   = wieldDifficulty;
                }
                else
                {
                    wo.WieldRequirements = WieldRequirement.Invalid;
                    wo.WieldSkillType    = null;
                    wo.WieldDifficulty   = null;
                }

                // WeaponDefense
                wo.WeaponDefense = RollWeaponDefense(wieldDifficulty.Value, profile);
            }
            else
            {
                // new method - mutation scripts

                // mutate ManaConversionMod
                var mutationFilter = MutationCache.GetMutation("Casters.caster.txt");
                mutationFilter.TryMutate(wo, profile.Tier);

                // mutate ElementalDamageMod / WieldRequirements
                var isElemental = wo.W_DamageType != DamageType.Undef;
                var scriptName  = GetCasterScript(isElemental);

                mutationFilter = MutationCache.GetMutation(scriptName);
                mutationFilter.TryMutate(wo, profile.Tier);

                // this part was not handled by mutation filter
                if (wo.WieldRequirements == WieldRequirement.RawSkill)
                {
                    if (wo.W_DamageType == DamageType.Nether)
                    {
                        wo.WieldSkillType = (int)Skill.VoidMagic;
                    }
                    else
                    {
                        wo.WieldSkillType = (int)Skill.WarMagic;
                    }
                }

                // mutate WeaponDefense
                mutationFilter = MutationCache.GetMutation("Casters.weapon_defense.txt");
                mutationFilter.TryMutate(wo, profile.Tier);
            }

            // material type
            var materialType = GetMaterialType(wo, profile.Tier);

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

            // item color
            MutateColor(wo);

            // gem count / gem material
            if (wo.GemCode != null)
            {
                wo.GemCount = GemCountChance.Roll(wo.GemCode.Value, profile.Tier);
            }
            else
            {
                wo.GemCount = ThreadSafeRandom.Next(1, 5);
            }

            wo.GemType = RollGemType(profile.Tier);

            // workmanship
            wo.ItemWorkmanship = WorkmanshipChance.Roll(profile.Tier);

            // burden?

            // missile defense / magic defense
            wo.WeaponMissileDefense = MissileMagicDefense.Roll(profile.Tier);
            wo.WeaponMagicDefense   = MissileMagicDefense.Roll(profile.Tier);

            // spells
            if (!isMagical)
            {
                wo.ItemManaCost   = null;
                wo.ItemMaxMana    = null;
                wo.ItemCurMana    = null;
                wo.ItemSpellcraft = null;
                wo.ItemDifficulty = null;
            }
            else
            {
                // if a caster was from a MagicItem profile, it always had a SpellDID
                MutateCaster_SpellDID(wo, profile);

                AssignMagic(wo, profile, roll);
            }

            // item value
            //if (wo.HasMutateFilter(MutateFilter.Value))   // fixme: data
            MutateValue(wo, profile.Tier, roll);

            // long description
            wo.LongDesc = GetLongDesc(wo);
        }
Пример #22
0
        private static void MutateJewelry(WorldObject wo, TreasureDeath profile, bool isMagical, TreasureRoll roll = null)
        {
            // material type
            var materialType = GetMaterialType(wo, profile.Tier);

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

            // item color
            MutateColor(wo);

            // gem count / gem material
            if (wo.GemCode != null)
            {
                wo.GemCount = GemCountChance.Roll(wo.GemCode.Value, profile.Tier);
            }
            else
            {
                wo.GemCount = ThreadSafeRandom.Next(1, 5);
            }

            wo.GemType = RollGemType(profile.Tier);

            // workmanship
            wo.ItemWorkmanship = WorkmanshipChance.Roll(profile.Tier);

            // wield level requirement for t7+
            if (profile.Tier > 6)
            {
                RollWieldLevelReq_T7_T8(wo, profile);
            }

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

            // gear rating (t8)
            if (roll != null && profile.Tier == 8)
            {
                TryMutateGearRating(wo, profile, roll);
            }

            // item value
            //  if (wo.HasMutateFilter(MutateFilter.Value))     // fixme: data
            MutateValue(wo, profile.Tier, roll);

            wo.LongDesc = GetLongDesc(wo);
        }
        private static void MutateArmor(WorldObject wo, TreasureDeath profile, bool isMagical, LootTables.ArmorType armorType, TreasureRoll roll = null)
        {
            // material type
            int materialType = GetMaterialType(wo, profile.Tier);

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

            // item color
            MutateColor(wo);

            // gem count / gem material
            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);

            // workmanship
            wo.ItemWorkmanship = WorkmanshipChance.Roll(profile.Tier);

            // try mutate burden, if MutateFilter exists
            if (wo.HasMutateFilter(MutateFilter.EncumbranceVal))
            {
                MutateBurden(wo, profile, false);
            }

            if (profile.Tier > 6 && armorType != LootTables.ArmorType.CovenantArmor && armorType != LootTables.ArmorType.OlthoiArmor)
            {
                wo.WieldRequirements = WieldRequirement.Level;
                wo.WieldSkillType    = (int)Skill.Axe; // Set by examples from PCAP data

                wo.WieldDifficulty = 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
                };
            }

            if (armorType == LootTables.ArmorType.CovenantArmor || armorType == LootTables.ArmorType.OlthoiArmor)
            {
                int chance     = ThreadSafeRandom.Next(1, 3);
                var wieldSkill = chance switch
                {
                    1 => Skill.MagicDefense,
                    2 => Skill.MissileDefense,
                    _ => Skill.MeleeDefense,
                };

                wo.WieldRequirements = WieldRequirement.RawSkill;
                wo.WieldSkillType    = (int)wieldSkill;
                wo.WieldDifficulty   = GetCovenantWieldReq(profile.Tier, wieldSkill);

                // used by tinkering requirements for copper/silver
                wo.ItemSkillLimit = wieldSkill;
            }

            wo = AssignArmorLevel(wo, profile.Tier, armorType);

            wo = AssignEquipmentSetId(wo, profile);

            if (isMagical)
            {
                //bool covenantArmor = false || (armorType == LootTables.ArmorType.CovenantArmor || armorType == LootTables.ArmorType.OlthoiArmor);
                AssignMagic(wo, profile, roll, true);
            }
            else
            {
                wo.ItemManaCost   = null;
                wo.ItemMaxMana    = null;
                wo.ItemCurMana    = null;
                wo.ItemSpellcraft = null;
                wo.ItemDifficulty = null;
            }

            if (wo.HasMutateFilter(MutateFilter.ArmorModVsType) && wo.ArmorLevel > 0)
            {
                // covenant armor and olthoi armor appear to have different mutation methods possibly
                if (armorType != LootTables.ArmorType.CovenantArmor && armorType != LootTables.ArmorType.OlthoiArmor)
                {
                    MutateArmorModVsType(wo, profile);
                }
            }

            if (roll != null && profile.Tier == 8)
            {
                TryMutateGearRating(wo, profile, roll);
            }

            // item value
            wo.Value = Roll_ItemValue(wo, profile.Tier);

            wo.LongDesc = GetLongDesc(wo);
        }
Пример #24
0
        private static int GetSpellCode_Dynamic_ClothingArmor(WorldObject wo, TreasureRoll roll)
        {
            // special cases
            switch (roll.Wcid)
            {
            case Enum.WeenieClassName.glovescloth:
                return(14);

            case Enum.WeenieClassName.capleather:
                return(20);
            }

            var coverageMask = wo.ClothingPriority ?? 0;
            var isArmor      = roll.IsArmor;

            if ((coverageMask & upperArmor) != 0 && (coverageMask & CoverageMask.OuterwearLowerLegs) == 0)
            {
                return(7);
            }

            if (coverageMask == CoverageMask.Hands && isArmor)
            {
                return(9);
            }

            if (coverageMask == CoverageMask.Head && roll.BaseArmorLevel > 20)
            {
                return(10);
            }

            // base weenie armorLevel > 20
            if ((coverageMask & CoverageMask.Feet) != 0 && roll.BaseArmorLevel > 20)
            {
                return(11);
            }

            if ((coverageMask & clothing) != 0)
            {
                return(12);
            }

            // metal cap?
            if (coverageMask == CoverageMask.Head && !isArmor)
            {
                return(13);
            }

            if (coverageMask == CoverageMask.Hands && !isArmor)
            {
                return(14);
            }

            // leggings
            if ((coverageMask & lowerArmor) != 0)
            {
                return(15);
            }

            if (coverageMask == CoverageMask.Feet)
            {
                return(18);
            }

            log.Error($"GetSpellCode_Dynamic_ClothingArmor({wo.Name}) - couldn't determine spell selection code for {coverageMask}, {isArmor}");
            return(0);
        }
        private static void MutateSocietyArmor(WorldObject wo, TreasureDeath profile, bool isMagical, TreasureRoll roll = null)
        {
            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);

            wo.ItemWorkmanship = WorkmanshipChance.Roll(profile.Tier);

            wo.Value = Roll_ItemValue(wo, profile.Tier);

            // 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, roll, 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);
            }
        }
Пример #26
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));
        }
Пример #27
0
        private static void MutateMissileWeapon(WorldObject wo, TreasureDeath profile, bool isMagical, int?wieldDifficulty = null, TreasureRoll roll = null)
        {
            if (roll == null)
            {
                // previous method

                // DamageMod
                wo.DamageMod = GetMissileDamageMod(wieldDifficulty.Value, wo.W_WeaponType);

                // ElementalDamageBonus
                if (wo.W_DamageType != DamageType.Undef)
                {
                    int elementalBonus = GetElementalDamageBonus(wieldDifficulty.Value);
                    if (elementalBonus > 0)
                    {
                        wo.ElementalDamageBonus = elementalBonus;
                    }
                }

                // Wield Requirements
                if (wieldDifficulty > 0)
                {
                    wo.WieldDifficulty   = wieldDifficulty;
                    wo.WieldRequirements = WieldRequirement.RawSkill;
                    wo.WieldSkillType    = (int)Skill.MissileWeapons;
                }
                else
                {
                    wo.WieldDifficulty   = null;
                    wo.WieldRequirements = WieldRequirement.Invalid;
                    wo.WieldSkillType    = null;
                }

                // WeaponDefense
                var meleeDMod = RollWeaponDefense(wieldDifficulty.Value, profile);
                if (meleeDMod > 0.0f)
                {
                    wo.WeaponDefense = meleeDMod;
                }
            }
            else
            {
                // new method / mutation scripts
                var isElemental = wo.W_DamageType != DamageType.Undef;

                var scriptName = GetMissileScript(roll.WeaponType, isElemental);

                // mutate DamageMod / ElementalDamageBonus / WieldRequirements
                var mutationFilter = MutationCache.GetMutation(scriptName);

                mutationFilter.TryMutate(wo, profile.Tier);

                // mutate WeaponDefense
                mutationFilter = MutationCache.GetMutation("MissileWeapons.weapon_defense.txt");

                mutationFilter.TryMutate(wo, profile.Tier);
            }

            // weapon speed
            if (wo.WeaponTime != null)
            {
                var weaponSpeedMod = RollWeaponSpeedMod(profile);
                wo.WeaponTime = (int)(wo.WeaponTime * weaponSpeedMod);
            }

            // material type
            var materialType = GetMaterialType(wo, profile.Tier);

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

            // item color
            MutateColor(wo);

            // gem count / gem material
            if (wo.GemCode != null)
            {
                wo.GemCount = GemCountChance.Roll(wo.GemCode.Value, profile.Tier);
            }
            else
            {
                wo.GemCount = ThreadSafeRandom.Next(1, 5);
            }

            wo.GemType = RollGemType(profile.Tier);

            // workmanship
            wo.ItemWorkmanship = WorkmanshipChance.Roll(profile.Tier);

            // burden
            MutateBurden(wo, profile, true);

            // missile / magic defense
            wo.WeaponMissileDefense = MissileMagicDefense.Roll(profile.Tier);
            wo.WeaponMagicDefense   = MissileMagicDefense.Roll(profile.Tier);

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

            // item value
            //if (wo.HasMutateFilter(MutateFilter.Value))   // fixme: data
            MutateValue(wo, profile.Tier, roll);

            // long description
            wo.LongDesc = GetLongDesc(wo);
        }
Пример #28
0
        private static void MutateArmor(WorldObject wo, TreasureDeath profile, bool isMagical, LootTables.ArmorType armorType, TreasureRoll roll = null)
        {
            // material type
            var materialType = GetMaterialType(wo, profile.Tier);

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

            // item color
            MutateColor(wo);

            // gem count / gem material
            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);

            // workmanship
            wo.ItemWorkmanship = WorkmanshipChance.Roll(profile.Tier);

            // burden
            if (wo.HasMutateFilter(MutateFilter.EncumbranceVal))  // fixme: data
            {
                MutateBurden(wo, profile, false);
            }

            if (roll == null)
            {
                if (armorType == LootTables.ArmorType.CovenantArmor || armorType == LootTables.ArmorType.OlthoiArmor)
                {
                    int chance     = ThreadSafeRandom.Next(1, 3);
                    var wieldSkill = chance switch
                    {
                        1 => Skill.MagicDefense,
                        2 => Skill.MissileDefense,
                        _ => Skill.MeleeDefense,
                    };

                    wo.WieldRequirements = WieldRequirement.RawSkill;
                    wo.WieldSkillType    = (int)wieldSkill;
                    wo.WieldDifficulty   = GetCovenantWieldReq(profile.Tier, wieldSkill);
                }
                else if (profile.Tier > 6)
                {
                    wo.WieldRequirements = WieldRequirement.Level;
                    wo.WieldSkillType    = (int)Skill.Axe; // Set by examples from PCAP data

                    wo.WieldDifficulty = 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
                    };
                }
            }
            else if (profile.Tier > 6 && !wo.HasArmorLevel())
            {
                // normally this is handled in the mutation script for armor
                // for clothing, just calling the generic method here
                RollWieldLevelReq_T7_T8(wo, profile);
            }

            if (roll == null)
            {
                AssignArmorLevel(wo, profile.Tier, armorType);
            }
            else
            {
                AssignArmorLevel_New(wo, profile, roll);
            }

            if (wo.HasMutateFilter(MutateFilter.ArmorModVsType))
            {
                MutateArmorModVsType(wo, profile);
            }

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

            if (profile.Tier > 6)
            {
                TryRollEquipmentSet(wo, profile, roll);
            }

            if (roll != null && profile.Tier == 8)
            {
                TryMutateGearRating(wo, profile, roll);
            }

            // item value
            //if (wo.HasMutateFilter(MutateFilter.Value))   // fixme: data
            MutateValue(wo, profile.Tier, roll);

            wo.LongDesc = GetLongDesc(wo);
        }
        private static void MutateDinnerware(WorldObject wo, TreasureDeath profile, bool isMagical, TreasureRoll roll = null)
        {
            // dinnerware did not have its Damage / DamageVariance / WeaponSpeed mutated

            // material type
            wo.MaterialType = (MaterialType)GetMaterialType(wo, profile.Tier);

            // item color
            MutateColor(wo);

            // gem count / gem material
            if (wo.GemCode != null)
            {
                wo.GemCount = GemCountChance.Roll(wo.GemCode.Value, profile.Tier);
            }
            else
            {
                wo.GemCount = ThreadSafeRandom.Next(1, 5);
            }

            wo.GemType = RollGemType(profile.Tier);

            // workmanship
            wo.ItemWorkmanship = WorkmanshipChance.Roll(profile.Tier);

            // "Empty Flask" was the only dinnerware that never received spells
            if (isMagical && wo.WeenieClassId != (uint)WeenieClassName.flasksimple)
            {
                AssignMagic(wo, profile, roll);
            }

            // item value
            MutateDinnerware_ItemValue(wo);

            wo.LongDesc = GetLongDesc(wo);
        }