static void Postfix(CharBSelectorLayer __instance, BlueprintCharacterClass charClass, BlueprintArchetype[] archetypesList)
        {
            try
            {
                var self  = __instance;
                var items = self.SelectorItems;
                if (items == null || archetypesList == null || items.Count == 0 || Main.settings?.RelaxAncientLorekeeper == true)
                {
                    return;
                }

                // Note: conceptually this is the same as `CharBSelectorLayer.FillDataLightClass()`,
                // but for archetypes.

                // TODO: changing race won't refresh the prereq, although it does update if you change class.
                var state = Game.Instance.UI.CharacterBuildController.LevelUpController.State;
                foreach (var item in items)
                {
                    var archetype = item?.Archetype;
                    if (archetype == null || !archetypesList.Contains(archetype))
                    {
                        continue;
                    }

                    item.Show(state: true);
                    item.Toggle.interactable = item.enabled = OracleArchetypes.MeetsPrerequisites(archetype, state.Unit, state);
                    var classData = state.Unit.Progression.GetClassData(state.SelectedClass);
                    self.SilentSwitch(classData.Archetypes.Contains(archetype), item);
                }
            }
            catch (Exception e)
            {
                Log.Error(e);
            }
        }
 public override void OnEventAboutToTrigger(RuleCalculateAbilityParams evt)
 {
     if (evt.Spellbook != Owner.GetSpellbook(Class))
     {
         return;
     }
     if (OracleArchetypes.IsGrantedSpell(Owner, evt.Spell))
     {
         evt.AddBonusConcentration(Bonus);
     }
 }
 public override void OnEventAboutToTrigger(RuleApplyMetamagic evt)
 {
     if (evt.Spellbook != Owner.GetSpellbook(Class))
     {
         return;
     }
     if (OracleArchetypes.IsGrantedSpell(Owner, evt.Spell))
     {
         Log.Write($"Reduce cost of spell: {evt.Spell.name} by {Reduction}");
         evt.ReduceCost(Reduction);
     }
 }
        public override void OnEventAboutToTrigger(RuleSpellResistanceCheck evt)
        {
            if (evt.Ability.Type != AbilityType.Spell)
            {
                return;
            }
            // TODO: ideally we could check the spellbook used to cast the spell.
            var spellbook = Owner.GetSpellbook(Class);

            if (spellbook == null || !spellbook.IsKnown(evt.Ability))
            {
                return;
            }
            if (OracleArchetypes.IsGrantedSpell(Owner, evt.Ability))
            {
                evt.AdditionalSpellPenetration += Bonus;
            }
        }
示例#5
0
        internal static void Load()
        {
            if (OracleClass.oracle != null)
            {
                return;
            }

            var sorcerer = Helpers.GetClass("b3a505fb61437dc4097f43c3f8f9a4cf");
            var cleric   = Helpers.GetClass("67819271767a9dd4fbfd4ae700befea0");

            var oracle = OracleClass.oracle = Helpers.Create <BlueprintCharacterClass>();

            oracleArray = new BlueprintCharacterClass[] { oracle };
            oracle.name = "OracleClass";
            library.AddAsset(oracle, "ec73f4790c1d4554871b81cde0b9399b");
            oracle.LocalizedName        = Helpers.CreateString("Oracle.Name", "Oracle");
            oracle.LocalizedDescription = Helpers.CreateString("Oracle.Description", "Although the gods work through many agents, perhaps none is more mysterious than the oracle. These divine vessels are granted power without their choice, selected by providence to wield powers that even they do not fully understand. Unlike a cleric, who draws her magic through devotion to a deity, oracles garner strength and power from many sources, namely those patron deities who support their ideals. Instead of worshiping a single source, oracles tend to venerate all of the gods that share their beliefs. While some see the powers of the oracle as a gift, others view them as a curse, changing the life of the chosen in unforeseen ways.\n" +
                                                               "Role: Oracles do not usually associate with any one church or temple, instead preferring to strike out on their own, or with a small group of like-minded individuals. Oracles typically use their spells and revelations to further their understanding of their mystery, be it through fighting mighty battles or tending to the poor and sick.");
            oracle.m_Icon          = cleric.Icon;
            oracle.SkillPoints     = 4;
            oracle.HitDie          = DiceType.D8;
            oracle.BaseAttackBonus = cleric.BaseAttackBonus;
            oracle.FortitudeSave   = sorcerer.FortitudeSave;
            oracle.ReflexSave      = sorcerer.ReflexSave;
            oracle.WillSave        = sorcerer.WillSave;

            // TODO: Oracle will not work properly with Mystic Theurge.
            // Not sure it's worth fixing, but if desired the fix would be:
            // - patch spellbook selection feats, similar to what Crossblooded does.
            // - use a similar apporach as Theurge does for Inquisitor, to select new spells via the feat UI.
            var spellbook = Helpers.Create <BlueprintSpellbook>();

            spellbook.name = "OracleSpellbook";
            library.AddAsset(spellbook, "c26cdf7ee670428c96aad20225f3fdca");
            spellbook.Name             = oracle.LocalizedName;
            spellbook.SpellsPerDay     = sorcerer.Spellbook.SpellsPerDay;
            spellbook.SpellsKnown      = sorcerer.Spellbook.SpellsKnown;
            spellbook.SpellList        = cleric.Spellbook.SpellList;
            spellbook.Spontaneous      = true;
            spellbook.IsArcane         = false;
            spellbook.AllSpellsKnown   = false;
            spellbook.CanCopyScrolls   = false;
            spellbook.CastingAttribute = StatType.Charisma;
            spellbook.CharacterClass   = oracle;
            spellbook.CantripsType     = CantripsType.Orisions;
            oracle.Spellbook           = spellbook;

            // Consolidated skills make this a bit of a judgement call. Explanation below.
            // Note that Mysteries add 2 more skills typically.
            oracle.ClassSkills = new StatType[] {
                // Oracles have Diplomacy and Sense Motive. Diplomacy is the main component of
                // Persuasion in PF:K. (Also: while Sense Motives should map to Perception with
                // consolidated skills, in PF:K it seems to be more in line with Persuasion).
                StatType.SkillPersuasion,
                // Oracles have Knowledge (history), which is a main component of (world).
                StatType.SkillKnowledgeWorld,
                // Oracles have Knowledge (planes) and Knowledge (religion) so this is an easy call,
                // because those skills are 100% of consolidated Religion skill.
                StatType.SkillLoreReligion,
            };

            oracle.IsDivineCaster = true;
            oracle.IsArcaneCaster = false;

            oracle.StartingGold   = cleric.StartingGold; // all classes start with 411.
            oracle.PrimaryColor   = cleric.PrimaryColor;
            oracle.SecondaryColor = cleric.SecondaryColor;

            oracle.RecommendedAttributes    = new StatType[] { StatType.Charisma };
            oracle.NotRecommendedAttributes = new StatType[] { StatType.Intelligence };

            oracle.EquipmentEntities       = cleric.EquipmentEntities;
            oracle.MaleEquipmentEntities   = cleric.MaleEquipmentEntities;
            oracle.FemaleEquipmentEntities = cleric.FemaleEquipmentEntities;

            // Both of the restrictions here are relevant (no atheism feature, no animal class).
            oracle.ComponentsArray = cleric.ComponentsArray;
            oracle.StartingItems   = cleric.StartingItems;

            var progression = Helpers.CreateProgression("OracleProgression",
                                                        oracle.Name,
                                                        oracle.Description,
                                                        "317a0f107135425faa7def96cb8ef690",
                                                        oracle.Icon,
                                                        FeatureGroup.None);

            progression.Classes = oracleArray;
            var entries = new List <LevelEntry>();

            var orisons = library.CopyAndAdd <BlueprintFeature>(
                "e62f392949c24eb4b8fb2bc9db4345e3", // cleric orisions
                "OracleOrisonsFeature",
                "926891a8e8a74d9eac63a1e296b1a4f3");

            orisons.SetDescription("Oracles learn a number of orisons, or 0-level spells. These spells are cast like any other spell, but they do not consume any slots and may be used again.");
            orisons.SetComponents(orisons.ComponentsArray.Select(c =>
            {
                var bind = c as BindAbilitiesToClass;
                if (bind == null)
                {
                    return(c);
                }
                bind = UnityEngine.Object.Instantiate(bind);
                bind.CharacterClass = oracle;
                bind.Stat           = StatType.Charisma;
                return(bind);
            }));
            var proficiencies = library.CopyAndAdd <BlueprintFeature>(
                "8c971173613282844888dc20d572cfc9", // cleric proficiencies
                "OracleProficiencies",
                "baee2212dee249cb8136bda72a872ba4");

            proficiencies.SetName("Oracle Proficiencies");
            proficiencies.SetDescription("Oracles are proficient with all simple weapons, light armor, medium armor, and shields (except tower shields). Some oracle revelations grant additional proficiencies.");

            // Note: curses need to be created first, because some revelations use them (e.g. Cinder Dance).
            var curse = OracleCurses.CreateSelection();

            (var mystery, var revelation, var mysteryClassSkills) = CreateMysteryAndRevelationSelection();

            var cureOrInflictSpell = CreateCureOrInflictSpellSelection();

            var detectMagic = library.Get <BlueprintFeature>("ee0b69e90bac14446a4cf9a050f87f2e");

            entries.Add(Helpers.LevelEntry(1,
                                           proficiencies,
                                           mystery,
                                           curse,
                                           cureOrInflictSpell,
                                           revelation,
                                           orisons,
                                           mysteryClassSkills,
                                           library.Get <BlueprintFeature>("d3e6275cfa6e7a04b9213b7b292a011c"), // ray calculate feature
                                           library.Get <BlueprintFeature>("62ef1cdb90f1d654d996556669caf7fa"), // touch calculate feature
                                           library.Get <BlueprintFeature>("9fc9813f569e2e5448ddc435abf774b3"), // full caster
                                           detectMagic
                                           ));
            entries.Add(Helpers.LevelEntry(3, revelation));
            entries.Add(Helpers.LevelEntry(7, revelation));
            entries.Add(Helpers.LevelEntry(11, revelation));
            entries.Add(Helpers.LevelEntry(15, revelation));
            entries.Add(Helpers.LevelEntry(19, revelation));
            progression.UIDeterminatorsGroup = new BlueprintFeatureBase[] {
                mystery, curse, cureOrInflictSpell, proficiencies, orisons, mysteryClassSkills, detectMagic,
            };
            progression.UIGroups = Helpers.CreateUIGroups(
                revelation, revelation, revelation, revelation, revelation, revelation);
            progression.LevelEntries = entries.ToArray();

            oracle.Progression = progression;

            oracle.Archetypes = OracleArchetypes.Create(mystery, revelation, mysteryClassSkills).ToArray();

            oracle.RegisterClass();

            var extraRevelation = Helpers.CreateFeatureSelection("ExtraRevelation",
                                                                 "Extra Revelation", "You gain one additional revelation. You must meet all of the prerequisites for this revelation.\nSpecial: You can gain Extra Revelation multiple times.",
                                                                 "e91bd89bb5534ae2b61a3222a9b7325e",
                                                                 Helpers.GetIcon("fd30c69417b434d47b6b03b9c1f568ff"), // selective channel
                                                                 FeatureGroup.Feat,
                                                                 Helpers.PrerequisiteClassLevel(oracle, 1));
            var extras = revelation.Features.Select(
                // The level-up UI sometimes loses track of two selections at the same level
                // (e.g. taking Extra Revelations at 1st level),  so clone the feature selections.
                f => library.CopyAndAdd(f, $"{f.name}Extra", f.AssetGuid, "afc8ceb5eb2849d5976e07f5f02ab200")).ToList();

            extras.Add(UndoSelection.Feature.Value);
            extraRevelation.SetFeatures(extras);
            var abundantRevelations = Helpers.CreateFeatureSelection("AbundantRevelations",
                                                                     "Abundant Revelations",
                                                                     "Choose one of your revelations that has a number of uses per day. You gain 1 additional use per day of that revelation.\nSpecial: You can gain this feat multiple times. Its effects do not stack. Each time you take the feat, it applies to a new revelation.",
                                                                     "1614c7b40565481fa3728fd7375ddca0",
                                                                     Helpers.GetIcon("a2b2f20dfb4d3ed40b9198e22be82030"), // extra lay on hands
                                                                     FeatureGroup.Feat);
            var resourceChoices   = new List <BlueprintFeature>();
            var prereqRevelations = new List <Prerequisite> {
                Helpers.PrerequisiteClassLevel(oracle, 1)
            };

            CreateAbundantRevelations(revelation, abundantRevelations, resourceChoices, prereqRevelations, new HashSet <BlueprintFeature>());
            abundantRevelations.SetFeatures(resourceChoices);
            abundantRevelations.SetComponents(prereqRevelations);

            library.AddFeats(extraRevelation, abundantRevelations);
        }
        internal static void Load()
        {
            if (OracleClass.oracle != null)
            {
                return;
            }

            var sorcerer = Helpers.GetClass("b3a505fb61437dc4097f43c3f8f9a4cf");
            var cleric   = Helpers.GetClass("67819271767a9dd4fbfd4ae700befea0");

            var oracle = OracleClass.oracle = Helpers.Create <BlueprintCharacterClass>();

            oracleArray = new BlueprintCharacterClass[] { oracle };
            oracle.name = "OracleClass";
            library.AddAsset(oracle, "ec73f4790c1d4554871b81cde0b9399b");
            oracle.LocalizedName        = Helpers.CreateString("Oracle.Name", "先知");
            oracle.LocalizedDescription = Helpers.CreateString("Oracle.Description", "虽然众神有无数代言人为祂们在地上行走,这些人中最为神秘的一群恐怕莫过于先知了。这些获选者在并不知情的状况下成为了神祇伟力的容器,得以操纵他们并不能完全理解的大能。和通过虔诚侍奉以从他们的主宰手中获得神力的牧师不同,先知的力量可能来源于多种多样的途径,换句话说,他们可以从所有与自己分享同一理念的神祇那里获得支持。先知并不依靠敬拜单一神明,而是向所有与自己的信仰融会贯通的神祇表达敬意。当然,有人将先知掌握的力量视为天赋,而另一些人则将之看作是这些人背负的诅咒——它们以种种不可预料的方法影响着这些获选者的命运之路。\n" +
                                                               "角色定位:先知的任务并不一定与某个特定的教会或神殿相关,他们更喜欢独来独往或是和一小群志同道合的先知合作。运用自己的法术和通过启迪自己所身负的秘示之能,一个先知既可以呼啸沙场战无不胜,也可以医疗疾患救死扶伤。");
            oracle.m_Icon          = cleric.Icon;
            oracle.SkillPoints     = 4;
            oracle.HitDie          = DiceType.D8;
            oracle.BaseAttackBonus = cleric.BaseAttackBonus;
            oracle.FortitudeSave   = sorcerer.FortitudeSave;
            oracle.ReflexSave      = sorcerer.ReflexSave;
            oracle.WillSave        = sorcerer.WillSave;

            // TODO: Oracle will not work properly with Mystic Theurge.
            // Not sure it's worth fixing, but if desired the fix would be:
            // - patch spellbook selection feats, similar to what Crossblooded does.
            // - use a similar apporach as Theurge does for Inquisitor, to select new spells via the feat UI.
            var spellbook = Helpers.Create <BlueprintSpellbook>();

            spellbook.name = "OracleSpellbook";
            library.AddAsset(spellbook, "c26cdf7ee670428c96aad20225f3fdca");
            spellbook.Name             = oracle.LocalizedName;
            spellbook.SpellsPerDay     = sorcerer.Spellbook.SpellsPerDay;
            spellbook.SpellsKnown      = sorcerer.Spellbook.SpellsKnown;
            spellbook.SpellList        = cleric.Spellbook.SpellList;
            spellbook.Spontaneous      = true;
            spellbook.IsArcane         = false;
            spellbook.AllSpellsKnown   = false;
            spellbook.CanCopyScrolls   = false;
            spellbook.CastingAttribute = StatType.Charisma;
            spellbook.CharacterClass   = oracle;
            spellbook.CantripsType     = CantripsType.Orisions;
            oracle.Spellbook           = spellbook;

            // Consolidated skills make this a bit of a judgement call. Explanation below.
            // Note that Mysteries add 2 more skills typically.
            oracle.ClassSkills = new StatType[] {
                // Oracles have Diplomacy and Sense Motive. Diplomacy is the main component of
                // Persuasion in PF:K. (Also: while Sense Motives should map to Perception with
                // consolidated skills, in PF:K it seems to be more in line with Persuasion).
                StatType.SkillPersuasion,
                // Oracles have Knowledge (history), which is a main component of (world).
                StatType.SkillKnowledgeWorld,
                // Oracles have Knowledge (planes) and Knowledge (religion) so this is an easy call,
                // because those skills are 100% of consolidated Religion skill.
                StatType.SkillLoreReligion,
            };

            oracle.IsDivineCaster = true;
            oracle.IsArcaneCaster = false;

            oracle.StartingGold   = cleric.StartingGold; // all classes start with 411.
            oracle.PrimaryColor   = cleric.PrimaryColor;
            oracle.SecondaryColor = cleric.SecondaryColor;

            oracle.RecommendedAttributes    = new StatType[] { StatType.Charisma };
            oracle.NotRecommendedAttributes = new StatType[] { StatType.Intelligence };

            oracle.EquipmentEntities       = cleric.EquipmentEntities;
            oracle.MaleEquipmentEntities   = cleric.MaleEquipmentEntities;
            oracle.FemaleEquipmentEntities = cleric.FemaleEquipmentEntities;

            // Both of the restrictions here are relevant (no atheism feature, no animal class).
            oracle.ComponentsArray = cleric.ComponentsArray;
            oracle.StartingItems   = cleric.StartingItems;

            var progression = Helpers.CreateProgression("OracleProgression",
                                                        oracle.Name,
                                                        oracle.Description,
                                                        "317a0f107135425faa7def96cb8ef690",
                                                        oracle.Icon,
                                                        FeatureGroup.None);

            progression.Classes = oracleArray;
            var entries = new List <LevelEntry>();

            var orisons = library.CopyAndAdd <BlueprintFeature>(
                "e62f392949c24eb4b8fb2bc9db4345e3", // cleric orisions
                "OracleOrisonsFeature",
                "926891a8e8a74d9eac63a1e296b1a4f3");

            orisons.SetDescription("先知可以了解一些祷念,或称0环法术。祷念的数量见上表。这些法术的施法方式和正常法术相同,不过它们不会消耗任何法术位且可以重复施放。");
            orisons.SetComponents(orisons.ComponentsArray.Select(c =>
            {
                var bind = c as BindAbilitiesToClass;
                if (bind == null)
                {
                    return(c);
                }
                bind = UnityEngine.Object.Instantiate(bind);
                bind.CharacterClass = oracle;
                bind.Stat           = StatType.Charisma;
                return(bind);
            }));
            var proficiencies = library.CopyAndAdd <BlueprintFeature>(
                "8c971173613282844888dc20d572cfc9", // cleric proficiencies
                "OracleProficiencies",
                "baee2212dee249cb8136bda72a872ba4");

            proficiencies.SetName("先知擅长");
            proficiencies.SetDescription("先知擅长所有的简单武器,轻甲,中甲以及所有盾牌(除了塔盾)。一些秘示域会赋予先知额外的武器和护甲擅长。");

            // Note: curses need to be created first, because some revelations use them (e.g. Cinder Dance).
            var curse = OracleCurses.CreateSelection();

            (var mystery, var revelation, var mysteryClassSkills) = CreateMysteryAndRevelationSelection();

            var cureOrInflictSpell = CreateCureOrInflictSpellSelection();

            var detectMagic = library.Get <BlueprintFeature>("ee0b69e90bac14446a4cf9a050f87f2e");

            entries.Add(Helpers.LevelEntry(1,
                                           proficiencies,
                                           mystery,
                                           curse,
                                           cureOrInflictSpell,
                                           revelation,
                                           orisons,
                                           mysteryClassSkills,
                                           library.Get <BlueprintFeature>("d3e6275cfa6e7a04b9213b7b292a011c"), // ray calculate feature
                                           library.Get <BlueprintFeature>("62ef1cdb90f1d654d996556669caf7fa"), // touch calculate feature
                                           library.Get <BlueprintFeature>("9fc9813f569e2e5448ddc435abf774b3"), // full caster
                                           detectMagic
                                           ));
            entries.Add(Helpers.LevelEntry(3, revelation));
            entries.Add(Helpers.LevelEntry(7, revelation));
            entries.Add(Helpers.LevelEntry(11, revelation));
            entries.Add(Helpers.LevelEntry(15, revelation));
            entries.Add(Helpers.LevelEntry(19, revelation));
            progression.UIDeterminatorsGroup = new BlueprintFeatureBase[] {
                mystery, curse, cureOrInflictSpell, proficiencies, orisons, mysteryClassSkills, detectMagic,
            };
            progression.UIGroups = Helpers.CreateUIGroups(
                revelation, revelation, revelation, revelation, revelation, revelation);
            progression.LevelEntries = entries.ToArray();

            oracle.Progression = progression;

            oracle.Archetypes = OracleArchetypes.Create(mystery, revelation, mysteryClassSkills).ToArray();

            oracle.RegisterClass();

            var extraRevelation = Helpers.CreateFeatureSelection("ExtraRevelation",
                                                                 "额外启示", "你获得了一个额外启示,你必须满足此启示的所有先决条件。.\n特殊:你可以多次选择此专长。",
                                                                 "e91bd89bb5534ae2b61a3222a9b7325e",
                                                                 Helpers.GetIcon("fd30c69417b434d47b6b03b9c1f568ff"), // selective channel
                                                                 FeatureGroup.Feat,
                                                                 Helpers.PrerequisiteClassLevel(oracle, 1));
            var extras = revelation.Features.Select(
                // The level-up UI sometimes loses track of two selections at the same level
                // (e.g. taking Extra Revelations at 1st level),  so clone the feature selections.
                f => library.CopyAndAdd(f, $"{f.name}Extra", f.AssetGuid, "afc8ceb5eb2849d5976e07f5f02ab200")).ToList();

            extras.Add(UndoSelection.Feature.Value);
            extraRevelation.SetFeatures(extras);
            var abundantRevelations = Helpers.CreateFeatureSelection("AbundantRevelations",
                                                                     "额外启示次数",
                                                                     "选择一项你已拥有的有每日使用次数的启示,此启示获得每日一次额外使用次数。\n特殊:你可以多次选择此专长。它的效果不会叠加。你每次选择此专长,它都只适用于新的启示。",
                                                                     "1614c7b40565481fa3728fd7375ddca0",
                                                                     Helpers.GetIcon("a2b2f20dfb4d3ed40b9198e22be82030"), // extra lay on hands
                                                                     FeatureGroup.Feat);
            var resourceChoices   = new List <BlueprintFeature>();
            var prereqRevelations = new List <Prerequisite> {
                Helpers.PrerequisiteClassLevel(oracle, 1)
            };

            CreateAbundantRevelations(revelation, abundantRevelations, resourceChoices, prereqRevelations, new HashSet <BlueprintFeature>());
            abundantRevelations.SetFeatures(resourceChoices);
            abundantRevelations.SetComponents(prereqRevelations);

            library.AddFeats(extraRevelation, abundantRevelations);
        }
        internal static void Load()
        {
            if (OracleClass.oracle != null)
            {
                return;
            }

            var sorcerer = Helpers.GetClass("b3a505fb61437dc4097f43c3f8f9a4cf");
            var cleric   = Helpers.GetClass("67819271767a9dd4fbfd4ae700befea0");

            var oracle = OracleClass.oracle = Helpers.Create <BlueprintCharacterClass>();

            oracleArray = new BlueprintCharacterClass[] { oracle };
            oracle.name = "OracleClass";
            library.AddAsset(oracle, "ec73f4790c1d4554871b81cde0b9399b");
            oracle.LocalizedName        = Helpers.CreateString("Oracle.Name", RES.OracleLocalizedName_info);
            oracle.LocalizedDescription = Helpers.CreateString("Oracle.Description", RES.OracleLocalizedDescription_info);
            oracle.m_Icon          = cleric.Icon;
            oracle.SkillPoints     = Main.settings?.OracleHas3SkillPoints == true ? 3 : 4;
            oracle.HitDie          = DiceType.D8;
            oracle.BaseAttackBonus = cleric.BaseAttackBonus;
            oracle.FortitudeSave   = sorcerer.FortitudeSave;
            oracle.ReflexSave      = sorcerer.ReflexSave;
            oracle.WillSave        = sorcerer.WillSave;

            // TODO: Oracle will not work properly with Mystic Theurge.
            // Not sure it's worth fixing, but if desired the fix would be:
            // - patch spellbook selection feats, similar to what Crossblooded does.
            // - use a similar apporach as Theurge does for Inquisitor, to select new spells via the feat UI.
            var spellbook = Helpers.Create <BlueprintSpellbook>();

            spellbook.name = "OracleSpellbook";
            library.AddAsset(spellbook, "c26cdf7ee670428c96aad20225f3fdca");
            spellbook.Name             = oracle.LocalizedName;
            spellbook.SpellsPerDay     = sorcerer.Spellbook.SpellsPerDay;
            spellbook.SpellsKnown      = sorcerer.Spellbook.SpellsKnown;
            spellbook.SpellList        = cleric.Spellbook.SpellList;
            spellbook.Spontaneous      = true;
            spellbook.IsArcane         = false;
            spellbook.AllSpellsKnown   = false;
            spellbook.CanCopyScrolls   = false;
            spellbook.CastingAttribute = StatType.Charisma;
            spellbook.CharacterClass   = oracle;
            spellbook.CantripsType     = CantripsType.Orisions;
            oracle.Spellbook           = spellbook;

            // Consolidated skills make this a bit of a judgement call. Explanation below.
            // Note that Mysteries add 2 more skills typically.
            oracle.ClassSkills = new StatType[] {
                // Oracles have Diplomacy and Sense Motive. Diplomacy is the main component of
                // Persuasion in PF:K. (Also: while Sense Motives should map to Perception with
                // consolidated skills, in PF:K it seems to be more in line with Persuasion).
                StatType.SkillPersuasion,
                // Oracles have Knowledge (history), which is a main component of (world).
                StatType.SkillKnowledgeWorld,
                // Oracles have Knowledge (planes) and Knowledge (religion) so this is an easy call,
                // because those skills are 100% of consolidated Religion skill.
                StatType.SkillLoreReligion,
            };

            oracle.IsDivineCaster = true;
            oracle.IsArcaneCaster = false;

            oracle.StartingGold   = cleric.StartingGold; // all classes start with 411.
            oracle.PrimaryColor   = cleric.PrimaryColor;
            oracle.SecondaryColor = cleric.SecondaryColor;

            oracle.RecommendedAttributes    = new StatType[] { StatType.Charisma };
            oracle.NotRecommendedAttributes = new StatType[] { StatType.Intelligence };

            oracle.EquipmentEntities       = cleric.EquipmentEntities;
            oracle.MaleEquipmentEntities   = cleric.MaleEquipmentEntities;
            oracle.FemaleEquipmentEntities = cleric.FemaleEquipmentEntities;

            // Both of the restrictions here are relevant (no atheism feature, no animal class).
            oracle.ComponentsArray = sorcerer.ComponentsArray;
            oracle.StartingItems   = cleric.StartingItems;

            var progression = Helpers.CreateProgression("OracleProgression",
                                                        oracle.Name,
                                                        oracle.Description,
                                                        "317a0f107135425faa7def96cb8ef690",
                                                        oracle.Icon,
                                                        FeatureGroup.None);

            progression.Classes = oracleArray;
            var entries = new List <LevelEntry>();

            var orisons = library.CopyAndAdd <BlueprintFeature>(
                "e62f392949c24eb4b8fb2bc9db4345e3", // cleric orisions
                "OracleOrisonsFeature",
                "926891a8e8a74d9eac63a1e296b1a4f3");

            orisons.SetDescription(RES.OracleOrisonsFeatureDescription_info);
            orisons.SetComponents(orisons.ComponentsArray.Select(c =>
            {
                var bind = c as BindAbilitiesToClass;
                if (bind == null)
                {
                    return(c);
                }
                bind = UnityEngine.Object.Instantiate(bind);
                bind.CharacterClass = oracle;
                bind.Stat           = StatType.Charisma;
                return(bind);
            }));
            var proficiencies = library.CopyAndAdd <BlueprintFeature>(
                "8c971173613282844888dc20d572cfc9", // cleric proficiencies
                "OracleProficiencies",
                "baee2212dee249cb8136bda72a872ba4");

            proficiencies.SetName(RES.OracleProficienciesFeatureName_info);
            proficiencies.SetDescription(RES.OracleProficienciesFeatureDescription_info);

            // Note: curses need to be created first, because some revelations use them (e.g. Cinder Dance).
            var curse = OracleCurses.CreateSelection();

            (var mystery, var revelation, var mysteryClassSkills) = CreateMysteryAndRevelationSelection();

            var cureOrInflictSpell = CreateCureOrInflictSpellSelection();

            var detectMagic = library.Get <BlueprintFeature>("ee0b69e90bac14446a4cf9a050f87f2e");

            entries.Add(Helpers.LevelEntry(1,
                                           proficiencies,
                                           mystery,
                                           curse,
                                           cureOrInflictSpell,
                                           revelation,
                                           orisons,
                                           mysteryClassSkills,
                                           library.Get <BlueprintFeature>("d3e6275cfa6e7a04b9213b7b292a011c"), // ray calculate feature
                                           library.Get <BlueprintFeature>("62ef1cdb90f1d654d996556669caf7fa"), // touch calculate feature
                                           library.Get <BlueprintFeature>("9fc9813f569e2e5448ddc435abf774b3"), // full caster
                                           detectMagic
                                           ));
            entries.Add(Helpers.LevelEntry(3, revelation));
            entries.Add(Helpers.LevelEntry(7, revelation));
            entries.Add(Helpers.LevelEntry(11, revelation));
            entries.Add(Helpers.LevelEntry(15, revelation));
            entries.Add(Helpers.LevelEntry(19, revelation));
            progression.UIDeterminatorsGroup = new BlueprintFeatureBase[] {
                mystery, curse, cureOrInflictSpell, proficiencies, orisons, mysteryClassSkills, detectMagic,
            };
            progression.UIGroups = Helpers.CreateUIGroups(
                revelation, revelation, revelation, revelation, revelation, revelation);
            progression.LevelEntries = entries.ToArray();

            oracle.Progression = progression;

            oracle.Archetypes = OracleArchetypes.Create(mystery, revelation, mysteryClassSkills).ToArray();

            oracle.RegisterClass();

            var extraRevelation = Helpers.CreateFeatureSelection("ExtraRevelation",
                                                                 RES.ExtraRevelationFeatureName_info, RES.ExtraRevelationFeatureDescription_info,
                                                                 "e91bd89bb5534ae2b61a3222a9b7325e",
                                                                 Image2Sprite.Create("Mods/EldritchArcana/sprites/revelations_extra.png"),
                                                                 FeatureGroup.Feat,
                                                                 Helpers.PrerequisiteClassLevel(oracle, 1));
            var extras = revelation.Features.Select(
                // The level-up UI sometimes loses track of two selections at the same level
                // (e.g. taking Extra Revelations at 1st level),  so clone the feature selections.
                f => library.CopyAndAdd(f, $"{f.name}Extra", f.AssetGuid, "afc8ceb5eb2849d5976e07f5f02ab200")).ToList();

            extras.Add(UndoSelection.Feature.Value);
            extraRevelation.SetFeatures(extras);
            var abundantRevelations = Helpers.CreateFeatureSelection("AbundantRevelations",
                                                                     RES.AbundantRevelationsFeatureName_info,
                                                                     RES.AbundantRevelationsFeatureDescription_info,
                                                                     "1614c7b40565481fa3728fd7375ddca0",
                                                                     Image2Sprite.Create("Mods/EldritchArcana/sprites/revelations_abundant.png"),
                                                                     FeatureGroup.Feat);
            var resourceChoices   = new List <BlueprintFeature>();
            var prereqRevelations = new List <Prerequisite> {
                Helpers.PrerequisiteClassLevel(oracle, 1)
            };

            CreateAbundantRevelations(revelation, abundantRevelations, resourceChoices, prereqRevelations, new HashSet <BlueprintFeature>());
            abundantRevelations.SetFeatures(resourceChoices);
            abundantRevelations.SetComponents(prereqRevelations);

            library.AddFeats(extraRevelation, abundantRevelations);
        }