示例#1
0
        static BlueprintFeature CreateFrail()
        {
            var frailsprite = Image2Sprite.Create("Mods/EldritchArcana/sprites/frail.png");
            var fraily      = new BlueprintComponent[64];

            fraily[0] = Helpers.CreateAddStatBonus(StatType.HitPoints, -3, ModifierDescriptor.Crippled);
            for (int i = 2; i < 65; i++)
            {
                fraily[i - 1] = Helpers.CreateAddStatBonusOnLevel(StatType.HitPoints, i * -1, ModifierDescriptor.Penalty, i, i);
            }
            ;

            var feat = Helpers.CreateFeature("Frail", "Frail",
                                             "You have A frail body and you break bones easily also your health is not great so you have -1 vs disease saves.\n" +
                                             "if you pick a Drawback at level one you can choose an extra feat on top\n" +
                                             "Drawback: -3 hp at level 1 and You lose 1 additional hit points.For every Hit Die you possess.",
                                             "0639446638b04ecc85e069e050751bfb",
                                             frailsprite,//Helpers.NiceIcons(9),
                                             FeatureGroup.Feat,
                                             Helpers.Create <SavingThrowBonusAgainstDescriptor>(s => { s.SpellDescriptor = SpellDescriptor.Disease; s.Bonus = -1; s.ModifierDescriptor = ModifierDescriptor.Crippled; })
                                             //,
                                             //Helpers.Create<FeyFoundlingLogic>(s => { s.dieModefier = 2;}),
                                             //Helpers.CreateAddStatBonusOnLevel(StatType.HitPoints,-3,ModifierDescriptor.Penalty,1),
                                             //PrerequisiteCharacterLevelExact.Create(1)
                                             );

            feat.AddComponents(fraily);
            return(feat);
        }
        static BlueprintFeature CreateFrail()
        {
            var frailsprite = Image2Sprite.Create("Mods/EldritchArcana/sprites/frail.png");
            var fraily      = new BlueprintComponent[64];

            fraily[0] = Helpers.CreateAddStatBonus(StatType.HitPoints, -3, ModifierDescriptor.Crippled);
            for (int i = 2; i < 65; i++)
            {
                fraily[i - 1] = Helpers.CreateAddStatBonusOnLevel(StatType.HitPoints, i * -1, ModifierDescriptor.Penalty, i, i);
            }
            ;

            var feat = Helpers.CreateFeature("Frail", RES.DrawbackFrailFeatureName_info,
                                             RES.DrawbackFrailFeatureDescription_info,
                                             "0639446638b04ecc85e069e050751bfb",
                                             frailsprite,//Helpers.NiceIcons(9),
                                             FeatureGroup.Feat,
                                             Helpers.Create <SavingThrowBonusAgainstDescriptor>(s => { s.SpellDescriptor = SpellDescriptor.Disease; s.Bonus = -1; s.ModifierDescriptor = ModifierDescriptor.Crippled; })
                                             //,
                                             //Helpers.Create<FeyFoundlingLogic>(s => { s.dieModefier = 2;}),
                                             //Helpers.CreateAddStatBonusOnLevel(StatType.HitPoints,-3,ModifierDescriptor.Penalty,1),
                                             //PrerequisiteCharacterLevelExact.Create(1)
                                             );

            feat.AddComponents(fraily);
            return(feat);
        }
        public static void CheckComponent(BlueprintScriptableObject obj, BlueprintComponent c)
        {
#if DEBUG
            var type = c.GetType();
            if (IsStatefulComponent(type))
            {
                statefulComponentMessage.AppendLine($"Warning: in object {obj.name}, stateful {type.Name} should be named.");
            }
#endif
        }
示例#4
0
        /// <summary>Clones ComponentsArray and overrides reference.
        /// This makes it so replacing components on a copy does not mutate the original.</summary>
        /// <returns>Reference to new array.</returns>
        public static BlueprintComponent[] DetachComponents(this BlueprintScriptableObject obj)
        {
            var result = new BlueprintComponent[obj.ComponentsArray.Length];

            for (int i = 0; i < result.Length; i++)
            {
                result[i] = obj.ComponentsArray[i];
            }
            obj.ComponentsArray = result;
            return(result);
        }
示例#5
0
 internal static void Validate(BlueprintComponent c, BlueprintScriptableObject parent)
 {
     c.Validate(validation);
     if (validation.HasErrors)
     {
         Append($"Error: component `{c.name}` of `{parent.name}` failed validation:");
         foreach (var e in validation.Errors)
         {
             Append($"  {e}");
         }
         ((List <ValidationContext.Error>)validation.ErrorsAdvanced).Clear();
         Flush();
     }
 }
        static void AmuletofDyingWisdomChange()
        {
            var immortality        = library.Get <BlueprintFeature>(Helpers.getGuid("ImmortalityArcaneDiscovery"));
            var middleage          = library.Get <BlueprintFeature>(Helpers.getGuid("MiddleAgeFeature"));
            var oldage             = library.Get <BlueprintFeature>(Helpers.getGuid("OldAgeFeature"));
            var venerableage       = library.Get <BlueprintFeature>(Helpers.getGuid("VenerableAgeFeature"));
            var DyingWisdomEnchant = library.Get <BlueprintEquipmentEnchantment>("84b63c1516d208247bceec28d6b6b38d");

            DyingWisdomEnchant.ComponentsArray = Array.Empty <BlueprintComponent>();
            var newcomponents = new BlueprintComponent[] { Helpers.Create <HandleImmortality>(p => p.Stat = StatType.Strength),
                                                           Helpers.Create <HandleImmortality>(p => p.Stat = StatType.Dexterity),
                                                           Helpers.Create <HandleImmortality>(p => p.Stat = StatType.Constitution),
                                                           Helpers.Create <HandleImmortality>(p => p.Stat = StatType.Intelligence),
                                                           Helpers.Create <HandleImmortality>(p => p.Stat = StatType.Wisdom),
                                                           Helpers.Create <HandleImmortality>(p => p.Stat = StatType.Charisma) };

            DyingWisdomEnchant.AddComponents(newcomponents);
        }
示例#7
0
        static BlueprintUnitLoot ConvertItemsToLoot <T>(List <T> items, int amountToAdd = 99)
        {
            var result     = ScriptableObject.CreateInstance <BlueprintUnitLoot>();
            var components = new BlueprintComponent[items.Count()];
            var itemsAdded = 0;

            foreach (var item in items)
            {
                var lootComponent = ScriptableObject.CreateInstance <LootItemsPackFixed>();
                var lootItem      = new LootItem();
                Helpers.SetField(lootItem, "m_Item", item);
                Helpers.SetField(lootItem, "m_Type", LootItemType.Item);
                Helpers.SetField(lootComponent, "m_Item", lootItem);
                Helpers.SetField(lootComponent, "m_Count", amountToAdd);
                components[itemsAdded] = lootComponent;
                itemsAdded++;
            }

            result.ComponentsArray = components;
            return(result);
        }
示例#8
0
        public static void ReplaceComponent(this BlueprintScriptableObject obj, BlueprintComponent original, BlueprintComponent replacement)
        {
            // Note: make a copy so we don't mutate the original component
            // (in case it's a clone of a game one).
            var components    = obj.ComponentsArray;
            var newComponents = new BlueprintComponent[components.Length];

            for (int i = 0; i < components.Length; i++)
            {
                var c = components[i];
                if (c == original)
                {
                    newComponents[i] = replacement;
                }
                else
                {
                    newComponents[i] = c;
                }
                //newComponents[i] = c == original ? replacement : c;
            }
            obj.SetComponents(newComponents); // fix up names if needed
        }
示例#9
0
        static void CreateMetamagicRods(BlueprintFeature feature, ModMetamagic modMetamagic, String friendlyName, BlueprintComponent logic)
        {
            // Create a metamagic rod by cloning an existing one.
            var rodIds   = existingRodIds[Metamagic.Empower];
            var rodCosts = metamagicRodCosts[modMetamagic.OriginalCost() - 1];

            var library       = Main.library;
            var names         = new string[] { "Lesser", "Normal", "Greater" };
            var displayPrefix = new string[] { "Lesser ", "", "Greater " };
            var maxLevel      = new string[] { "3rd", "6th", "9th " };

            for (int i = 0; i < 3; i++)
            {
                var displayName = displayPrefix[i] + friendlyName.Replace(" Spell", " Metamagic Rod");
                var description = $"The wielder can cast up to three spells per day that are affected as though the spells were augmented with the {friendlyName} feat.\n" +
                                  $"{displayPrefix[i]} rods can be used with spells of {maxLevel[i]} level or lower.\n" +
                                  $"{friendlyName}: {feature.Description}";

                // We need to clone 3 things:
                // - the item
                // - the activatable ability
                // - the buff
                var existingRod     = library.Get <BlueprintItemEquipmentUsable>(rodIds[i]);
                var existingAbility = existingRod.ActivatableAbility;
                var existingBuff    = existingAbility.Buff;

                var newRod     = library.CopyAndAdd(existingRod, $"MetamagicRod{names[i]}{modMetamagic}", feature.AssetGuid, existingRod.AssetGuid);
                var newAbility = library.CopyAndAdd(existingAbility, $"{newRod.name}ToggleAbility", feature.AssetGuid, existingAbility.AssetGuid);
                var newBuff    = library.CopyAndAdd(existingBuff, $"{newRod.name}Buff", feature.AssetGuid, existingBuff.AssetGuid);
                newRod.ActivatableAbility = newAbility;
                newAbility.Buff           = newBuff;
                if (logic != null)
                {
                    newAbility.AddComponent(logic);
                }

                Helpers.SetField(newRod, "m_Cost", rodCosts[i]);
                Helpers.SetField(newRod, "m_DisplayNameText", Helpers.CreateString(newRod.name + ".Name", displayName));
                Helpers.SetField(newRod, "m_DescriptionText", Helpers.CreateString(newRod.name + ".Description", description));

                newAbility.SetNameDescriptionIcon(displayName, description, newAbility.Icon);

                newBuff.SetNameDescriptionIcon(displayName, description, newBuff.Icon);
                newBuff.SetComponents(newBuff.ComponentsArray.Select(c =>
                {
                    var mechanics = c as MetamagicRodMechanics;
                    if (mechanics == null)
                    {
                        return(c);
                    }
                    var newMechanics        = UnityEngine.Object.Instantiate(mechanics);
                    newMechanics.Metamagic  = (Metamagic)modMetamagic;
                    newMechanics.RodAbility = newAbility;
                    return(newMechanics);
                }));

                newRods.PutIfAbsent(GetMetamagicRodKey(i, modMetamagic.OriginalCost()),
                                    () => new List <BlueprintItemEquipmentUsable>()).Add(newRod);
            }
        }
示例#10
0
        internal static void Append(BlueprintComponent c, String indent = "")
        {
            var spellComp = c as SpellComponent;

            if (spellComp != null)
            {
                Append($"{indent}SpellComponent school {spellComp.School.ToString()}");
                return;
            }
            var spellList = c as SpellListComponent;

            if (spellList != null)
            {
                Append($"{indent}SpellListComponent {spellList.SpellList.name} level {spellList.SpellLevel}");
                return;
            }
            var spellDesc = c as SpellDescriptorComponent;

            if (spellDesc != null)
            {
                Append($"{indent}SpellDescriptorComponent " + spellDesc.Descriptor.Value.ToString("x"));
                return;
            }
            var execOnCast = c as AbilityExecuteActionOnCast;

            if (execOnCast != null)
            {
                Append($"{indent}AbilityExecuteActionOnCast:");
                var conditions = execOnCast.Conditions;
                if (conditions != null)
                {
                    Append($"{indent}  conditions op {conditions.Operation}:");
                    foreach (var cond in conditions.Conditions)
                    {
                        Append($"{indent}  " + (cond.Not ? "not " : " ") + c.GetType().Name + $" {cond.GetCaption()}");
                    }
                }
                Append($"{indent}  actions:");
                foreach (var action in execOnCast.Actions.Actions)
                {
                    Append(action, $"{indent}    ");
                }
            }
            var runActions = c as AbilityEffectRunAction;

            if (runActions != null)
            {
                Append($"{indent}AbilityEffectRunAction saving throw {runActions.SavingThrowType}");
                foreach (var action in runActions.Actions.Actions)
                {
                    Append(action, $"{indent}  ");
                }
                return;
            }
            var config = c as ContextRankConfig;

            if (config != null)
            {
                Func <String, object> field = (name) => Helpers.GetField(config, name);

                var progression = (ContextRankProgression)field("m_Progression");
                Append($"{indent}ContextRankConfig type {config.Type} value type " +
                       ((ContextRankBaseValueType)field("m_BaseValueType")) + $" progression {progression}");

                if (config.IsBasedOnClassLevel)
                {
                    Append($"{indent}  class level " + ((BlueprintCharacterClass[])field("m_Class"))?.StringJoin(b => b.name));
                    Append($"{indent}  except classes? " + (bool)field("m_ExceptClasses"));
                }
                if (config.RequiresArchetype)
                {
                    Append($"{indent}  archetype " + ((BlueprintArchetype)field("Archetype")).name);
                }
                if (config.IsBasedOnFeatureRank)
                {
                    Append($"{indent}  feature rank " + ((BlueprintFeature)field("m_Feature")).name);
                }
                if (config.IsFeatureList)
                {
                    Append($"{indent}  feature list " + ((BlueprintFeature[])field("m_FeatureList"))?.StringJoin(f => f.name));
                }
                if (config.IsBasedOnStatBonus)
                {
                    Append($"{indent}  stat bonus " + ((StatType)field("m_Stat")));
                }
                if ((bool)field("m_UseMax"))
                {
                    Append($"{indent}  max " + ((int)field("m_Max")));
                }
                if ((bool)field("m_UseMin"))
                {
                    Append($"{indent}  min " + ((int)field("m_Min")));
                }
                if (config.IsDivisionProgression)
                {
                    Append($"{indent}  start level " + ((int)field("m_StartLevel")));
                }
                if (config.IsDivisionProgressionStart)
                {
                    Append($"{indent}  step level " + ((int)field("m_StepLevel")));
                }
                if (progression == ContextRankProgression.Custom)
                {
                    Append($"{indent}  custom progression:");
                    foreach (var p in (IEnumerable <object>)field("m_CustomProgression"))
                    {
                        Func <String, int> field2 = (name) => (int)Helpers.GetField(p, name);
                        Append($"{indent}    base value {field2("BaseValue")} progression {field2("ProgressionValue")}");
                    }
                }
                return;
            }

            Append($"{indent}component {c.name}, type {c.GetType().Name}");

            var abilityVariants = c as AbilityVariants;

            if (abilityVariants != null)
            {
                foreach (var v in abilityVariants.Variants)
                {
                    Append(v, $"{indent}    ");
                }
            }
            var polymorph = c as Polymorph;

            if (polymorph != null)
            {
                foreach (var f in polymorph.Facts)
                {
                    Append(f, $"{indent}    ");
                }
            }
            var stickyTouch = c as AbilityEffectStickyTouch;

            if (stickyTouch != null)
            {
                Append(stickyTouch.TouchDeliveryAbility, $"{indent}  ");
            }
            var addIf = c as AddFeatureIfHasFact;

            if (addIf != null)
            {
                Append($"{indent}  if {(addIf.Not ? "!" : "")}{addIf.CheckedFact.name} then add {addIf.Feature.name}");
                Append(addIf.Feature, $"{indent}    ");
            }
            var addOnLevel = c as AddFeatureOnClassLevel;

            if (addOnLevel != null)
            {
                Append($"{indent}  if level {(addOnLevel.BeforeThisLevel ? "before " : "")}{addOnLevel.Level} then add {addOnLevel.Feature.name}");
                Append(addOnLevel.Feature, $"{indent}    ");
            }
            var addFacts = c as AddFacts;

            if (addFacts != null)
            {
                Append($"{indent}  add facts");
                foreach (var f in addFacts.Facts)
                {
                    Append(f, $"{indent}    ");
                }
            }
            var prereq = c as Prerequisite;

            if (prereq != null)
            {
                Append($"{indent}  prerequisite group {prereq.Group}");

                var log = new StringBuilder();
                Action <String, object> logIf = (desc, name) =>
                {
                    if (name != null)
                    {
                        log.Append(desc + name);
                    }
                };
                logIf(" class ", (prereq as PrerequisiteClassLevel)?.CharacterClass.name);
                logIf(" level ", (prereq as PrerequisiteClassLevel)?.Level);
                logIf(" feature ", (prereq as PrerequisiteFeature)?.Feature.name);
                logIf(" no feature ", (prereq as PrerequisiteNoFeature)?.Feature.name);
                logIf(" stat ", (prereq as PrerequisiteStatValue)?.Stat.ToString());
                logIf(" value ", (prereq as PrerequisiteStatValue)?.Value);
                Append($"{indent}   {log.ToString()}");
            }
        }
        internal static (BlueprintFeature, BlueprintFeature) Create(String mysteryDescription, BlueprintFeature classSkillFeat)
        {
            var skill1  = StatType.SkillPerception;
            var skill2  = StatType.SkillKnowledgeArcana;
            var mystery = Helpers.CreateFeatureSelection("MysteryDragonSelection", "Dragon Mystery", $"{mysteryDescription}\n" +
                                                         "Oracles who draw their power from the mysterious and primal might of dragons are usually solitary folk. They are deep thinkers and often quick of wit, but prideful and equally quick-tempered.\n" +
                                                         "Upon selecting this mystery, the oracle must select an energy type (acid, cold, electricity, or fire) to be her associated element, which impacts several revelations.\n" +
                                                         $"Class skills: {UIUtility.GetStatText(skill1)}, {UIUtility.GetStatText(skill2)}",
                                                         "aec53bfbee334a0e93b90a283d4e308d",
                                                         Helpers.GetIcon("da48f9d7f697ae44ca891bfc50727988"), // Blood of Dragons selection
                                                         UpdateLevelUpDeterminatorText.Group);

            var classSkills = new BlueprintComponent[] {
                AddClassSkillIfHasFeature.Create(skill1, classSkillFeat),
                AddClassSkillIfHasFeature.Create(skill2, classSkillFeat)
            };

            BlueprintProgression acid, cold, electric, fire;

            mystery.SetFeatures(
                acid     = CreateMysteryForEnergy(mystery, classSkills, DamageEnergyType.Acid, SpellDescriptor.Acid, "8e339ab3898fdd14b879753eaaae933d", "3d77ee3fc4913c44b9df7c5bbcdc4906"),               // copper dragon acid breath, protection from acid
                cold     = CreateMysteryForEnergy(mystery, classSkills, DamageEnergyType.Cold, SpellDescriptor.Cold, "cd36514cf1f38f84a977a265cec113ae", "021d39c8e0eec384ba69140f4875e166"),               // silver dragon cold breath, protection from cold
                electric = CreateMysteryForEnergy(mystery, classSkills, DamageEnergyType.Electricity, SpellDescriptor.Electricity, "f97e345b9f474764fae2b7eff1c1a1c7", "e24ce0c3e8eaaaf498d3656b534093df"), // bronze dragon elecric breath, protection from electric
                fire     = CreateMysteryForEnergy(mystery, classSkills, DamageEnergyType.Fire, SpellDescriptor.Fire, "2a711cd134b91d34ab027b50d721778b", "3f9605134d34e1243b096e1f6cb4c148"));              // gold dragon fire breath, protection from fire

            var energyFeats = mystery.Features;
            var revelations = new List <BlueprintFeature> {
                CreateBreathWeapon(energyFeats),
                CreateDragonMagic(),
                CreateDragonSenses(),
                CreateFormOfTheDragon(),
                CreatePresenceOfDragons(),
                CreateScaledToughness(),
                CreateTailSwipe(),
                CreateWingsOfTheDragon(),
            };
            var description = new StringBuilder(mystery.Description).AppendLine();

            description.AppendLine("An oracle with the dragon mystery can choose from any of the following revelations:");
            foreach (var r in revelations)
            {
                description.AppendLine($"• {r.Name}");
            }
            revelations.AddRange(new BlueprintFeature[] {
                CreateDragonResistanceToEnergy(acid, DamageEnergyType.Acid, "fedc77de9b7aad54ebcc43b4daf8decd"),            // resist acid
                CreateDragonResistanceToEnergy(cold, DamageEnergyType.Cold, "5368cecec375e1845ae07f48cdc09dd1"),            // resist cold
                CreateDragonResistanceToEnergy(electric, DamageEnergyType.Electricity, "90987584f54ab7a459c56c2d2f22cee2"), // resist electric
                CreateDragonResistanceToEnergy(fire, DamageEnergyType.Fire, "ddfb4ac970225f34dbff98a10a4a8844"),            // resist fire
                CreateTalonsOfTheDragon(acid, DamageEnergyType.Acid, "b522759a265897b4f8f7a1a180a692e4"),                   // acid (copper)
                CreateTalonsOfTheDragon(cold, DamageEnergyType.Cold, "c7d2f393e6574874bb3fc728a69cc73a"),                   // cold (silver)
                CreateTalonsOfTheDragon(electric, DamageEnergyType.Electricity, "7e0f57d8d00464441974e303b84238ac"),        // electricity (bronze)
                CreateTalonsOfTheDragon(fire, DamageEnergyType.Fire, "6c67ef823db8d7d45bb0ef82f959743d"),                   // fire (gold)
            });
            description.AppendLine($"• Draconic Resistances");
            description.AppendLine($"• Talons of the Dragon");
            var descriptionStr = description.ToString();

            mystery.SetDescription(descriptionStr);
            foreach (var choice in mystery.Features)
            {
                choice.SetDescription(descriptionStr);
            }
            var revelation = Helpers.CreateFeatureSelection("MysteryDragonRevelation", "Dragon Revelation",
                                                            mystery.Description, "b5bff56fe6cc4ca192df65f5ced050c9", null, FeatureGroup.None,
                                                            mystery.PrerequisiteFeature());

            revelation.Mode = SelectionMode.OnlyNew;
            revelations.Add(UndoSelection.Feature.Value);
            revelation.SetFeatures(revelations);
            return(mystery, revelation);
        }
示例#12
0
        static BlueprintFeatureSelection CreateCustomTraits(Boolean optedin)
        {
            var noFeature    = Helpers.PrerequisiteNoFeature(null);
            var customTraits = Helpers.CreateFeatureSelection("CustomTrait", "Custom Trait{cheat}",
                                                              "These traits are a little overpowered and are here just for fun, if you want to play fair don't pick em.",
                                                              "9e41e60c929e46bc84ded046148d08ec", null, FeatureGroup.None, noFeature);

            noFeature.Feature = customTraits;
            var choices = new List <BlueprintFeature>();

            /*
             * foreach (StatType stat in (StatType[])Enum.GetValues(typeof(StatType)))
             * {
             *  Log.Write(stat.ToString());
             * }
             */

            var metamagicMaster = Helpers.CreateFeatureSelection("MetamagicMasterTrait", "Metamagic expert([cheat])",
                                                                 "Your ability to alter your spell of choice is greater than expected.\nBenefit: Select one spell of 3rd level or below; when you use the chosen spell with a metamagic feat, it uses up three spell slots one level lower than it normally would.\nstarting level is still minimun",
                                                                 "00844f940e434033ab826e5ff5929011",
                                                                 Helpers.GetIcon("ee7dc126939e4d9438357fbd5980d459"), // Spell Penetration
                                                                 FeatureGroup.None);

            FillSpellSelection(metamagicMaster, 1, 3, Helpers.Create <ReduceMetamagicCostForSpell>(r => { r.Reduction = 3; r.MaxSpellLevel = 3; }));
            choices.Add(metamagicMaster);


            choices.Add(Helpers.CreateFeature("MysticTrait", "Mystic Prophecy",
                                              "no one knows where You were born. its a Mistery you where given a the divine blessing to complete a prophecy\nBenefit: At level 10 your prophecy will come true +2 wis,int +10 arcana",
                                              "e50acadda65b4028884dd4a74f14e228",
                                              Helpers.NiceIcons(19), // Iron Will
                                              FeatureGroup.None,
                                              Helpers.CreateAddStatBonusOnLevel(StatType.SkillKnowledgeArcana, 10, ModifierDescriptor.Trait, 10),
                                              Helpers.CreateAddStatBonusOnLevel(StatType.SkillKnowledgeWorld, 10, ModifierDescriptor.Trait, 10),
                                              Helpers.CreateAddStatBonusOnLevel(StatType.Intelligence, 2, ModifierDescriptor.Trait, 10),
                                              Helpers.CreateAddStatBonusOnLevel(StatType.Wisdom, 2, ModifierDescriptor.Trait, 10),
                                              Helpers.CreateAddStatBonusOnLevel(StatType.Charisma, 2, ModifierDescriptor.Trait, 10), PrerequisiteCharacterLevelExact.Create(1)
                                              ));


            var magicalStrongLineage = Helpers.CreateFeatureSelection("MagicalStrongLineageTrait", "Magical Strong Lineage({cheat})",
                                                                      "One of your parents was a gifted spellcaster who not only used metamagic often, but also developed many magical items and perhaps even a new spell or two—and you have inherited a fragment of this greatness.\nBenefit: Pick one spell when you choose this trait. When you apply metamagic feats to this spell that add at least 1 level to the spell, treat its actual level as 1 lower up to 2 for determining the spell’s final adjusted level.",
                                                                      "1785787fb62a4c529104ba53d0de99ae",
                                                                      Helpers.GetIcon("ee7dc126939e4d9438357fbd5980d459"), // Spell Penetration
                                                                      FeatureGroup.None);

            FillSpellSelection(magicalStrongLineage, 1, 9, Helpers.Create <ReduceMetamagicCostForSpell>(r => r.Reduction = 2));
            choices.Add(magicalStrongLineage);



            choices.Add(Helpers.CreateFeature("CustomMagicalKnackTrait", "Magical flat Knack",
                                              "You were raised, either wholly or in part, by a magical creature, either after it found you abandoned in the woods or because your parents often left you in the care of a magical minion. This constant exposure to magic has made its mysteries easy for you to understand, even when you turn your mind to other devotions and tasks.\nBenefit: Pick a class when you gain this trait—your caster level in that class gains a +2flat level added.",
                                              "8fd15d5aa003498ba7f976530d21e433",
                                              Helpers.GetIcon("16fa59cc9a72a6043b566b49184f53fe"), // Spell Focus
                                              FeatureGroup.None,
                                                                                                   //Helpers.Create<IncreaseCasterLevelUpToCharacterLevel>()
                                              Helpers.Create <IncreaseCasterLevelCharacterLevel>()
                                              ));

            choices.Add(Helpers.CreateFeature("BloodHavocTrait", "Blood havoc Damage Bonus",
                                              "Whenever you cast a bloodrager or sorcerer spell that deals damage, add 1 point of damage per die rolled.",
                                              "2dd15d5aa003498ba7f945530d22e444",
                                              Helpers.NiceIcons(28), // M
                                              FeatureGroup.None,
                                                                     //Helpers.Create<IncreaseCasterLevelUpToCharacterLevel>()
                                              Helpers.Create <OrcBloodlineArcana>()
                                              ));


            var dwarfy = new BlueprintComponent[64];

            for (int i = 1; i < 65; i++)
            {
                dwarfy[i - 1] = Helpers.CreateAddStatBonusOnLevel(StatType.HitPoints, i * 2, ModifierDescriptor.Trait, i);
            }
            ;
            var dwarfReq        = Helpers.PrerequisiteFeature(Helpers.dwarf);
            var bulkybattleborn = Helpers.CreateFeature("BulkyAfTrait", "Bulky Battleborn (Dwarf)",
                                                        "Your greatest joy is being in the thick of battle and taking hits for the team,\nNote: this trait is not realy a cheat but it's homebrew so that's why its here. \nBenefit:you gain 2 extra hitpoints per level",
                                                        "a987f5e69db44cdd99983985e37a6c3b",
                                                        Helpers.GetIcon("121811173a614534e8720d7550aae253"), // Weapon Specialization
                                                        FeatureGroup.None,
                                                        dwarfReq);

            bulkybattleborn.AddComponents(dwarfy);
            choices.Add(bulkybattleborn);


            if (optedin)
            {
                customTraits.SetFeatures(choices);
            }
            return(customTraits);
        }
示例#13
0
        public BlueprintFeature createSacredCouncil(string name_prefix, string display_name, string description)
        {
            //+2 bonus for 6 seconds on attack rolls, skill checks, spell penetration, CombatManeuver
            var icon = Helpers.GetIcon("1bb08308c9f6a5e4697887cd438b7221"); //judgement protection

            var resource = Helpers.CreateAbilityResource($"{name_prefix}Resource", "", "", "", null);

            resource.SetIncreasedByStat(0, StatType.Wisdom);

            var components = new BlueprintComponent[]
            {
                Helpers.CreateAddStatBonus(StatType.AdditionalAttackBonus, 2, ModifierDescriptor.UntypedStackable),
                Helpers.Create <BuffAllSavesBonus>(b => b.Value = 2),
                Helpers.Create <BuffAllSkillsBonusAbilityValue>(b => b.Value     = 2),
                Helpers.Create <NewMechanics.CasterLevelCheckBonus>(b => b.Value = 2),
                Helpers.CreateAddStatBonus(StatType.AdditionalCMB, 2, ModifierDescriptor.UntypedStackable),
            };

            var names = new string[] { "Attack Rolls", "Saving throws", "Skills", "Caster Level Checks", "Combat Maneuvers" };

            BlueprintAbility[] abilities = new BlueprintAbility[components.Length];

            for (int i = 0; i < abilities.Length; i++)
            {
                var ext  = names[i].Replace(" ", "");
                var buff = Helpers.CreateBuff(name_prefix + ext + "Buff",
                                              display_name + ": " + names[i] + " Bonus",
                                              description,
                                              "",
                                              icon,
                                              null,
                                              components[i]
                                              );
                var apply_buff = Common.createContextActionApplyBuff(buff, Helpers.CreateContextDuration(1), dispellable: false);
                var ability    = Helpers.CreateAbility(name_prefix + ext + "Ability",
                                                       buff.Name,
                                                       description,
                                                       "",
                                                       icon,
                                                       AbilityType.Supernatural,
                                                       CommandType.Move,
                                                       AbilityRange.Personal,
                                                       Helpers.oneRoundDuration,
                                                       "",
                                                       Helpers.CreateRunActions(apply_buff),
                                                       Common.createAbilitySpawnFx("44295e9774b2864488f4a3790b8b0bcf", anchor: AbilitySpawnFxAnchor.SelectedTarget),
                                                       Helpers.CreateResourceLogic(resource)
                                                       );
                ability.setMiscAbilityParametersSelfOnly();
                abilities[i] = ability;
            }

            var wrapper = Common.createVariantWrapper(name_prefix + "Ability", "", abilities);

            wrapper.SetName(display_name);
            wrapper.AddComponent(Helpers.CreateResourceLogic(resource));

            var feature = Helpers.CreateFeature(name_prefix + "Feature",
                                                wrapper.Name,
                                                wrapper.Description,
                                                "",
                                                wrapper.Icon,
                                                FeatureGroup.None,
                                                resource.CreateAddAbilityResource(),
                                                Helpers.CreateAddFact(wrapper)
                                                );

            return(feature);
        }
示例#14
0
        static void CreateMetamagicRods(BlueprintFeature feature, ModMetamagic modMetamagic, String friendlyName, BlueprintComponent logic)
        {
            // For loacalization
            var ModMetamagicNames = new Dictionary <ModMetamagic, string> {
                { ModMetamagic.Dazing, RES.NewMetamagicNamesDazing_info },
                // {ModMetamagic.Elemental, RES.NewMetamagicNamesElemental_info.Trim()},
                { ModMetamagic.ElementalAcid, LocalizedTexts.Instance.DamageEnergy.GetText(DamageEnergyType.Acid) + RES.NewMetamagicNamesElemental_info },
                { ModMetamagic.ElementalCold, LocalizedTexts.Instance.DamageEnergy.GetText(DamageEnergyType.Cold) + RES.NewMetamagicNamesElemental_info },
                { ModMetamagic.ElementalElectricity, LocalizedTexts.Instance.DamageEnergy.GetText(DamageEnergyType.Electricity) + RES.NewMetamagicNamesElemental_info },
                { ModMetamagic.ElementalFire, LocalizedTexts.Instance.DamageEnergy.GetText(DamageEnergyType.Fire) + RES.NewMetamagicNamesElemental_info },
                { ModMetamagic.ElementalForce, RES.NewMetamagicNamesElementalForcePrefix_info + RES.NewMetamagicNamesElemental_info },
                { ModMetamagic.Intensified, RES.NewMetamagicNamesIntensified_info },
                { ModMetamagic.Persistent, RES.NewMetamagicNamesPersistent_info },
                { ModMetamagic.Rime, RES.NewMetamagicNamesRime_info },
                { ModMetamagic.Selective, RES.NewMetamagicNamesSelectvie_info },
                { ModMetamagic.Toppling, RES.NewMetamagicNamesToppling_info }
            };

            // Create a metamagic rod by cloning an existing one.
            var rodIds   = existingRodIds[Metamagic.Empower];
            var rodCosts = metamagicRodCosts[modMetamagic.OriginalCost() - 1];

            var library       = Main.library;
            var names         = new string[] { "Lesser", "Normal", "Greater" };
            var displayPrefix = new string[] { RES.MetamagicRodDisplayPrefixString_Lesser, RES.MetamagicRodDisplayPrefixString_Normal, RES.MetamagicRodDisplayPrefixString_Greater };
            var maxLevel      = new string[] { RES.MetamagicRodSpellMaxLevel_3rd, RES.MetamagicRodSpellMaxLevel_6th, RES.MetamagicRodSpellMaxLevel_9th };

            for (int i = 0; i < 3; i++)
            {
                var displayName = i == 1 ? ModMetamagicNames[modMetamagic] + RES.MetamagicRodName_info :
                                  displayPrefix[i] + ModMetamagicNames[modMetamagic] + RES.MetamagicRodName_info;
                var description = string.Format(RES.MetamagicRodDescription_info,
                                                feature.Name, displayPrefix[i], maxLevel[i], friendlyName, feature.Description);

                // We need to clone 3 things:
                // - the item
                // - the activatable ability
                // - the buff
                var existingRod     = library.Get <BlueprintItemEquipmentUsable>(rodIds[i]);
                var existingAbility = existingRod.ActivatableAbility;
                var existingBuff    = existingAbility.Buff;

                var newRod     = library.CopyAndAdd(existingRod, $"MetamagicRod{names[i]}{modMetamagic}", feature.AssetGuid, existingRod.AssetGuid);
                var newAbility = library.CopyAndAdd(existingAbility, $"{newRod.name}ToggleAbility", feature.AssetGuid, existingAbility.AssetGuid);
                var newBuff    = library.CopyAndAdd(existingBuff, $"{newRod.name}Buff", feature.AssetGuid, existingBuff.AssetGuid);
                newRod.ActivatableAbility = newAbility;
                newAbility.Buff           = newBuff;
                if (logic != null)
                {
                    newAbility.AddComponent(logic);
                }

                Helpers.SetField(newRod, "m_Cost", rodCosts[i]);
                Helpers.SetField(newRod, "m_DisplayNameText", Helpers.CreateString(newRod.name + ".Name", displayName));
                Helpers.SetField(newRod, "m_DescriptionText", Helpers.CreateString(newRod.name + ".Description", description));

                newAbility.SetNameDescriptionIcon(displayName, description, newAbility.Icon);

                newBuff.SetNameDescriptionIcon(displayName, description, newBuff.Icon);
                newBuff.SetComponents(newBuff.ComponentsArray.Select(c =>
                {
                    var mechanics = c as MetamagicRodMechanics;
                    if (mechanics == null)
                    {
                        return(c);
                    }
                    var newMechanics        = UnityEngine.Object.Instantiate(mechanics);
                    newMechanics.Metamagic  = (Metamagic)modMetamagic;
                    newMechanics.RodAbility = newAbility;
                    return(newMechanics);
                }));

                newRods.PutIfAbsent(GetMetamagicRodKey(i, modMetamagic.OriginalCost()),
                                    () => new List <BlueprintItemEquipmentUsable>()).Add(newRod);
            }
        }
示例#15
0
 public static void AddComponent(this BlueprintScriptableObject obj, BlueprintComponent component)
 {
     obj.SetComponents(obj.ComponentsArray.AddToArray(component));
 }
示例#16
0
        static void createRerollsAndRerollsBonus()
        {
            var resource = Helpers.CreateAbilityResource("PactWizardRerollResource", "", "", "", null);

            resource.SetIncreasedByStat(0, StatType.Intelligence);


            reroll_feature = Helpers.CreateFeature("PactWizardRerollsFeature",
                                                   "Great Power, Greater Expense",
                                                   "At 10th level, the pact wizard can invoke his patron’s power to roll twice and take the better result when attempting any caster level check, concentration check, initiative check, or saving throw. He can activate this ability as a free action before attempting the check, even if it isn’t his turn. He can use this ability a number of times per day equal to his Intelligence modifier.",
                                                   "",
                                                   Helpers.GetIcon("9af0b584f6f754045a0a79293d100ab3"), //luck
                                                   FeatureGroup.None,
                                                   resource.CreateAddAbilityResource()
                                                   );

            reroll_bonus = Helpers.CreateFeature("PactWizardRerollsBonusFeature",
                                                 "Great Power, Greater Expense",
                                                 "At 20th level, when the pact wizard invokes his patron’s power to roll twice on a check, he adds his Intelligence bonus to the result as an insight bonus.",
                                                 "",
                                                 Helpers.GetIcon("9af0b584f6f754045a0a79293d100ab3"), //luck
                                                 FeatureGroup.None
                                                 );

            var rule_types = new NewMechanics.ModifyD20WithActions.RuleType[] { ModifyD20WithActions.RuleType.Concentration,
                                                                                ModifyD20WithActions.RuleType.Intiative,
                                                                                ModifyD20WithActions.RuleType.SavingThrow,
                                                                                ModifyD20WithActions.RuleType.SpellResistance };
            var names = new string[] { "Concentration", "Initiative", "Saving Throw", "Spell Resistance" };
            var stats = new BlueprintComponent[][] { new BlueprintComponent[] { Helpers.Create <ConcentrationBonus>(c => c.Value = Helpers.CreateContextValue(AbilityRankType.Default)) },
                                                     new BlueprintComponent[] { Helpers.CreateAddContextStatBonus(StatType.Initiative, ModifierDescriptor.Insight) },
                                                     new BlueprintComponent[] { Helpers.CreateAddContextStatBonus(StatType.SaveWill, ModifierDescriptor.Insight),
                                                                                Helpers.CreateAddContextStatBonus(StatType.SaveReflex, ModifierDescriptor.Insight),
                                                                                Helpers.CreateAddContextStatBonus(StatType.SaveFortitude, ModifierDescriptor.Insight), },
                                                     new BlueprintComponent[] { Helpers.Create <SpellPenetrationBonus>(c => c.Value = Helpers.CreateContextValue(AbilityRankType.Default)) } };
            var abilities = new List <BlueprintActivatableAbility>();

            for (int i = 0; i < rule_types.Length; i++)
            {
                var buff2 = library.CopyAndAdd <BlueprintBuff>("3bc40c9cbf9a0db4b8b43d8eedf2e6ec", rule_types[i].ToString() + "PactWizardRerollBuff", "");
                buff2.SetNameDescription(reroll_feature.Name + ": " + names[i], reroll_feature.Description);
                buff2.RemoveComponents <ModifyD20>();
                buff2.AddComponent(Helpers.Create <NewMechanics.ModifyD20WithActions>(m =>
                {
                    m.Rule               = rule_types[i];
                    m.RollsAmount        = 1;
                    m.TakeBest           = true;
                    m.RerollOnlyIfFailed = false; //to avoid applying bonus before roll and also make it work per description
                    m.actions            = Helpers.CreateActionList(Common.createContextActionSpendResource(resource, 1));
                    m.required_resource  = resource;
                })
                                   );
                var ability2 = Helpers.CreateActivatableAbility(rule_types[i].ToString() + "PactWizardReroll" + "ToggleAbility",
                                                                buff2.Name,
                                                                buff2.Description,
                                                                "",
                                                                buff2.Icon,
                                                                buff2,
                                                                AbilityActivationType.Immediately,
                                                                Kingmaker.UnitLogic.Commands.Base.UnitCommand.CommandType.Free,
                                                                null,
                                                                Helpers.CreateActivatableResourceLogic(resource, ActivatableAbilityResourceLogic.ResourceSpendType.Never)
                                                                );

                var buff = Helpers.CreateBuff(rule_types[i].ToString() + "PactWizardRerollBonusBuff",
                                              buff2.Name,
                                              buff2.Description,
                                              "",
                                              buff2.Icon,
                                              null,
                                              stats[i]);
                buff.SetBuffFlags(BuffFlags.HiddenInUi);
                buff.AddComponent(Helpers.CreateContextRankConfig(ContextRankBaseValueType.StatBonus, stat: StatType.Intelligence));
                Common.addContextActionApplyBuffOnCasterFactsToActivatedAbilityBuffNoRemove(buff2, buff, reroll_bonus);
                ability2.DeactivateImmediately = true;
                abilities.Add(ability2);
            }


            reroll_feature.AddComponent(Helpers.CreateAddFacts(abilities.ToArray()));
        }
示例#17
0
        static BlueprintFeature CreateMetamagicFeat(ModMetamagic metamagic, String assetId, String friendlyName, String description, String iconAssetId, BlueprintComponent logic = null, params BlueprintComponent[] extra)
        {
            var components = new List <BlueprintComponent> {
                Helpers.Create <AddMetamagicFeat>(m => m.Metamagic = (Metamagic)metamagic),
                Helpers.Create <RecommendationRequiresSpellbook>()
            };

            if (logic != null)
            {
                components.Add(logic);
            }
            components.AddRange(extra);
            var feat = Helpers.Create <BlueprintFeature>();

            feat.name   = metamagic.ToString() + "SpellFeat";
            feat.Groups = new FeatureGroup[] { FeatureGroup.WizardFeat, FeatureGroup.Feat };
            feat.SetComponents(components);
            friendlyName = friendlyName ?? (metamagic.ToString() + " Spell");
            feat.SetNameDescriptionIcon($"Metamagic ({friendlyName})", description, Helpers.GetIcon(iconAssetId));
            Main.library.AddAsset(feat, assetId);

            Main.SafeLoad(() => CreateMetamagicRods(feat, metamagic, friendlyName, logic), "Metamagic rods");
            return(feat);
        }
        internal static (BlueprintFeature, BlueprintFeature) Create(String mysteryDescription, BlueprintFeature classSkillFeat)
        {
            var skill1  = StatType.SkillPerception;
            var skill2  = StatType.SkillKnowledgeArcana;
            var mystery = Helpers.CreateFeatureSelection("MysteryDragonSelection", "巨龙秘视域", $"{mysteryDescription}\n" +
                                                         "追寻着巨龙的神秘并从那原始的魔力中汲取力量的先知们常常在这条道路上踽踽独行。他们往往深思熟虑,聪明骄傲。但与此同时,巨龙们的暴躁个性也渗透进了他们的灵魂中。\n" +
                                                         "在选择这个启示时,先知们必须选择一种能量类型 (酸,冷,电或者火) 作为他的专注元素。这会影响几个他所获得的启示。\n" +
                                                         $"本职技能: {UIUtility.GetStatText(skill1)}, {UIUtility.GetStatText(skill2)}",
                                                         "aec53bfbee334a0e93b90a283d4e308d",
                                                         Helpers.GetIcon("da48f9d7f697ae44ca891bfc50727988"), // Blood of Dragons selection
                                                         UpdateLevelUpDeterminatorText.Group);

            var classSkills = new BlueprintComponent[] {
                AddClassSkillIfHasFeature.Create(skill1, classSkillFeat),
                AddClassSkillIfHasFeature.Create(skill2, classSkillFeat)
            };

            BlueprintProgression acid, cold, electric, fire;

            mystery.SetFeatures(
                acid     = CreateMysteryForEnergy(mystery, classSkills, DamageEnergyType.Acid, SpellDescriptor.Acid, "8e339ab3898fdd14b879753eaaae933d", "3d77ee3fc4913c44b9df7c5bbcdc4906"),               // copper dragon acid breath, protection from acid
                cold     = CreateMysteryForEnergy(mystery, classSkills, DamageEnergyType.Cold, SpellDescriptor.Cold, "cd36514cf1f38f84a977a265cec113ae", "021d39c8e0eec384ba69140f4875e166"),               // silver dragon cold breath, protection from cold
                electric = CreateMysteryForEnergy(mystery, classSkills, DamageEnergyType.Electricity, SpellDescriptor.Electricity, "f97e345b9f474764fae2b7eff1c1a1c7", "e24ce0c3e8eaaaf498d3656b534093df"), // bronze dragon elecric breath, protection from electric
                fire     = CreateMysteryForEnergy(mystery, classSkills, DamageEnergyType.Fire, SpellDescriptor.Fire, "2a711cd134b91d34ab027b50d721778b", "3f9605134d34e1243b096e1f6cb4c148"));              // gold dragon fire breath, protection from fire

            var energyFeats = mystery.Features;
            var revelations = new List <BlueprintFeature> {
                CreateBreathWeapon(energyFeats),
                CreateDragonMagic(),
                CreateDragonSenses(),
                CreateFormOfTheDragon(),
                CreatePresenceOfDragons(),
                CreateScaledToughness(),
                CreateTailSwipe(),
                CreateWingsOfTheDragon(),
            };
            var description = new StringBuilder(mystery.Description).AppendLine();

            description.AppendLine("选择了巨龙秘视域的先知可以选择以下启示:");
            foreach (var r in revelations)
            {
                description.AppendLine($"• {r.Name}");
            }
            revelations.AddRange(new BlueprintFeature[] {
                CreateDragonResistanceToEnergy(acid, DamageEnergyType.Acid, "fedc77de9b7aad54ebcc43b4daf8decd"),            // resist acid
                CreateDragonResistanceToEnergy(cold, DamageEnergyType.Cold, "5368cecec375e1845ae07f48cdc09dd1"),            // resist cold
                CreateDragonResistanceToEnergy(electric, DamageEnergyType.Electricity, "90987584f54ab7a459c56c2d2f22cee2"), // resist electric
                CreateDragonResistanceToEnergy(fire, DamageEnergyType.Fire, "ddfb4ac970225f34dbff98a10a4a8844"),            // resist fire
                CreateTalonsOfTheDragon(acid, DamageEnergyType.Acid, "b522759a265897b4f8f7a1a180a692e4"),                   // acid (copper)
                CreateTalonsOfTheDragon(cold, DamageEnergyType.Cold, "c7d2f393e6574874bb3fc728a69cc73a"),                   // cold (silver)
                CreateTalonsOfTheDragon(electric, DamageEnergyType.Electricity, "7e0f57d8d00464441974e303b84238ac"),        // electricity (bronze)
                CreateTalonsOfTheDragon(fire, DamageEnergyType.Fire, "6c67ef823db8d7d45bb0ef82f959743d"),                   // fire (gold)
            });
            description.AppendLine($"• Draconic Resistances");
            description.AppendLine($"• Talons of the Dragon");
            var descriptionStr = description.ToString();

            mystery.SetDescription(descriptionStr);
            foreach (var choice in mystery.Features)
            {
                choice.SetDescription(descriptionStr);
            }
            var revelation = Helpers.CreateFeatureSelection("MysteryDragonRevelation", "巨龙启示",
                                                            mystery.Description, "b5bff56fe6cc4ca192df65f5ced050c9", null, FeatureGroup.None,
                                                            mystery.PrerequisiteFeature());

            revelation.Mode = SelectionMode.OnlyNew;
            revelations.Add(UndoSelection.Feature.Value);
            revelation.SetFeatures(revelations);
            return(mystery, revelation);
        }
示例#19
0
        public static void InsertComponent(this BlueprintScriptableObject obj, int index, BlueprintComponent component)
        {
            var components = obj.ComponentsArray.ToList();

            components.Insert(index, component);
            obj.SetComponents(components);
        }
示例#20
0
        /// <summary>Looks for the first component of the replacement type and overrides the reference.
        /// Note that you need to detach the component first, otherwise the original gets mutated.</summary>
        /// <param name="replacement">The new component that should take it's place.</param>
        /// <returns>Itself for chaining.</returns>
        public static BlueprintScriptableObject ReplaceDirty(this BlueprintScriptableObject obj, BlueprintComponent replacement)
        {
            Type replacementType = replacement.GetType();

            for (int i = 0; i < obj.ComponentsArray.Length; i++)
            {
                if (obj.ComponentsArray[i].GetType() == replacementType)
                {
                    obj.ComponentsArray[i] = replacement;
                    return(obj);
                }
            }
            return(null);
        }
示例#21
0
 public static void RemoveComponent(this BlueprintScriptableObject obj, BlueprintComponent component)
 {
     obj.SetComponents(obj.ComponentsArray.RemoveFromArray(component));
 }
        static void CreateMetamagicRods(BlueprintFeature feature, ModMetamagic modMetamagic, String friendlyName, BlueprintComponent logic)
        {
            Dictionary <ModMetamagic, string> AdjMetamagic = new Dictionary <ModMetamagic, string> {
                { ModMetamagic.Dazing, Main.lc.GetTranslate("Metamagic.stAdjDazing") },
                { ModMetamagic.ElementalAcid, Main.lc.GetTranslate("Metamagic.stAdjElementalAcid") },
                { ModMetamagic.ElementalCold, Main.lc.GetTranslate("Metamagic.stAdjElementalCold") },
                { ModMetamagic.ElementalElectricity, Main.lc.GetTranslate("Metamagic.stAdjElementalElectric") },
                { ModMetamagic.ElementalFire, Main.lc.GetTranslate("Metamagic.stAdjElementalFire") },
                { ModMetamagic.Intensified, Main.lc.GetTranslate("Metamagic.stAdjIntensified") },
                { ModMetamagic.Persistent, Main.lc.GetTranslate("Metamagic.stAdjPersistent") },
                { ModMetamagic.Rime, Main.lc.GetTranslate("Metamagic.stAdjRime") },
                { ModMetamagic.Selective, Main.lc.GetTranslate("Metamagic.stAdjSelective") },
                { ModMetamagic.Toppling, Main.lc.GetTranslate("Metamagic.stAdjToppling") }
            };
            // Create a metamagic rod by cloning an existing one.
            var rodIds   = existingRodIds[Metamagic.Empower];
            var rodCosts = metamagicRodCosts[modMetamagic.DefaultCost() - 1];

            var library       = Main.library;
            var names         = new string[] { "Lesser", "Normal", "Greater" };
            var displayPrefix = new string[] { Main.lc.GetTranslate("Metamagic.stLesser") + " ", Main.lc.GetTranslate("Metamagic.stNormal") + " ", Main.lc.GetTranslate("Metamagic.stGreater") + " " };
            var maxLevel      = new string[] { Main.lc.GetTranslate("Metamagic.st3rd"),
                                               Main.lc.GetTranslate("Metamagic.st6th"),
                                               Main.lc.GetTranslate("Metamagic.st9th") };

            for (int i = 0; i < 3; i++)
            {
                var displayName = displayPrefix[i] + AdjMetamagic[modMetamagic] + Main.lc.GetTranslate("Metamagic.stMetamagicRodSuffix");
                var description = string.Format(Main.lc.GetTranslate("Metamagic.ieMetamagicRodDesc"),
                                                friendlyName, displayPrefix[i], maxLevel[i], feature.Description);

                // We need to clone 3 things:
                // - the item
                // - the activatable ability
                // - the buff
                var existingRod     = library.Get <BlueprintItemEquipmentUsable>(rodIds[i]);
                var existingAbility = existingRod.ActivatableAbility;
                var existingBuff    = existingAbility.Buff;

                var newRod     = library.CopyAndAdd(existingRod, $"MetamagicRod{names[i]}{modMetamagic}", feature.AssetGuid, existingRod.AssetGuid);
                var newAbility = library.CopyAndAdd(existingAbility, $"{newRod.name}ToggleAbility", feature.AssetGuid, existingAbility.AssetGuid);
                var newBuff    = library.CopyAndAdd(existingBuff, $"{newRod.name}Buff", feature.AssetGuid, existingBuff.AssetGuid);
                newRod.ActivatableAbility = newAbility;
                newAbility.Buff           = newBuff;
                if (logic != null)
                {
                    newAbility.AddComponent(logic);
                }

                Helpers.SetField(newRod, "m_Cost", rodCosts[i]);
                Helpers.SetField(newRod, "m_DisplayNameText", Helpers.CreateString(newRod.name + ".Name", displayName));
                Helpers.SetField(newRod, "m_DescriptionText", Helpers.CreateString(newRod.name + ".Description", description));

                newAbility.SetNameDescriptionIcon(displayName, description, newAbility.Icon);

                newBuff.SetNameDescriptionIcon(displayName, description, newBuff.Icon);
                newBuff.SetComponents(newBuff.ComponentsArray.Select(c =>
                {
                    var mechanics = c as MetamagicRodMechanics;
                    if (mechanics == null)
                    {
                        return(c);
                    }
                    var newMechanics        = UnityEngine.Object.Instantiate(mechanics);
                    newMechanics.Metamagic  = (Metamagic)modMetamagic;
                    newMechanics.RodAbility = newAbility;
                    return(newMechanics);
                }));

                newRods.PutIfAbsent(GetMetamagicRodKey(i, modMetamagic.DefaultCost()),
                                    () => new List <BlueprintItemEquipmentUsable>()).Add(newRod);
            }
        }