示例#1
0
        private static void addSteelHeadbutt()
        {
            foreach (ArmorProficiencyGroup ArmorProficiency in new ArmorProficiencyGroup[] { ArmorProficiencyGroup.Heavy, ArmorProficiencyGroup.Medium })
            {
                string              newAssetID = Helpers.getGuid("SteelHeadbuttType" + ArmorProficiency);
                DiceType            diceType   = ArmorProficiency == ArmorProficiencyGroup.Heavy ? DiceType.D4 : DiceType.D3;
                BlueprintWeaponType BlueprintWeaponTypeBite     = library.Get <BlueprintWeaponType>("952e30e6cb40b454789a9db6e5f6dd09");
                BlueprintWeaponType BlueprintWeaponTypeHeadbutt = library.CopyAndAdd(BlueprintWeaponTypeBite, "SteelHeadbuttType" + ArmorProficiency, newAssetID);

                Traverse traverse = Traverse.Create(BlueprintWeaponTypeHeadbutt);
                traverse.Field("m_AssetGuid").SetValue(newAssetID);
                traverse.Field("m_IsNatural").SetValue(false);
                traverse.Field("m_DefaultNameText").SetValue(new FakeLocalizedString("Steel Headbutt"));
                traverse.Field("m_DescriptionText").SetValue(new FakeLocalizedString("While wearing medium or heavy armor, a fighter can deliver a headbutt with his helm as part of a full attack action. This headbutt is in addition to his normal attacks, and is made using the fighter’s base attack bonus – 5. A helmet headbutt deals 1d3 points of damage if the fighter is wearing medium armor, or 1d4 points of damage if he is wearing heavy armor (1d2 and 1d3, respectively, for Small creatures), plus an amount of damage equal to 1/2 the fighter’s Strength modifier. Treat this attack as a weapon attack made using the same special material (if any) as the armor. The armor’s enhancement bonus does modify the headbutt attack."));
                traverse.Field("m_BaseDamage").SetValue(new DiceFormula(1, diceType));


                for (int i = 0; i <= 5; ++i)
                {
                    newAssetID = Helpers.getGuid("SteelHeadbuttType" + ArmorProficiency + "Enhancement" + i);
                    BlueprintItemWeapon BlueprintItemWeaponBite     = library.Get <BlueprintItemWeapon>("35dfad6517f401145af54111be04d6cf");
                    BlueprintItemWeapon BlueprintItemWeaponHeadbutt = library.CopyAndAdd(BlueprintItemWeaponBite, "SteelHeadbuttType" + ArmorProficiency + "Enhancement" + i, newAssetID);

                    traverse = Traverse.Create(BlueprintItemWeaponHeadbutt);
                    traverse.Field("m_AssetGuid").SetValue(newAssetID);
                    traverse.Field("m_Type").SetValue(BlueprintWeaponTypeBite);
                    traverse.Field("SpendCharges").SetValue(false);
                    BlueprintItemWeaponBite.DamageType.Physical.Enhancement      = i;
                    BlueprintItemWeaponBite.DamageType.Physical.EnhancementTotal = i;
                }
            }
        }
示例#2
0
 private static void Postfix(BlueprintItemWeapon __instance, ref string __result)
 {
     foreach (var enchantment in __instance.Enchantments)
     {
         var component = enchantment.GetComponent <WeaponBaseSizeChange>();
         if (component != null)
         {
             if (__instance.Type.IsLight && component.SizeCategoryChange == -1)
             {
                 __result = $"{new L10NString("1b8e1ff2-d137-402b-83d0-60c82c79fe67")} { __result}"; // tiny
             }
             else if (!__instance.IsTwoHanded && component.SizeCategoryChange == -1)
             {
                 __result = $"{new L10NString("7266d912-6bab-4a1d-afab-e218f231429a")} { __result}"; // small
             }
             else if ((__instance.Type.IsLight && component.SizeCategoryChange == 1) ||
                      (__instance.Type.IsTwoHanded && component.SizeCategoryChange == -1))
             {
                 __result = $"{new L10NString("485ccfc5-1107-480a-9614-63692e2d9b28")} {__result}"; // medium
             }
             else if (!__instance.Type.IsTwoHanded)
             {
                 __result = $"{new L10NString("8da7c769-c04f-4b16-92bb-f65f05e7f1a3")} {__result}"; // large
             }
             else
             {
                 __result = $"{new L10NString("c6e8323e-68cf-4ffb-a095-fcaf2f257c48")} {__result}"; // huge
             }
             break;
         }
     }
 }
 private static void Postfix(BlueprintItemWeapon __instance, ref bool __result)
 {
     if (__instance.Type.AttackType == AttackType.Melee && !__instance.Type.IsNatural && !__instance.Type.IsUnarmed)
     {
         foreach (var enchantment in __instance.Enchantments)
         {
             var component = enchantment.GetComponent <WeaponBaseSizeChange>();
             if (component != null)
             {
                 if (component.SizeCategoryChange == 1 && __instance.Type.IsLight)
                 {
                     __result = true;
                 }
                 else if ((component.SizeCategoryChange == -1 && __instance.Type.IsTwoHanded))
                 {
                     __result = true;
                 }
                 else
                 {
                     __result = false;
                 }
                 break;
             }
         }
     }
 }
示例#4
0
 public static bool isSwashbucklerWeapon(BlueprintItemWeapon weapon, UnitDescriptor wielder)
 {
     // Identical check for Duelist weapons
     if (weapon.IsMelee && (weapon.Category.HasSubCategory(WeaponSubCategory.Light) || weapon.Category.HasSubCategory(WeaponSubCategory.OneHandedPiercing) || (wielder.State.Features.DuelingMastery && weapon.Category == WeaponCategory.DuelingSword) || wielder.Ensure <DamageGracePart>().HasEntry(weapon.Category)))
     {
         return(true);
     }
     return(false);
 }
        static internal void createGreaterSpiritTotem()
        {
            var area_effect = Helpers.Create <Kingmaker.UnitLogic.Abilities.Blueprints.BlueprintAbilityAreaEffect>();

            area_effect.name          = "GreaterSpiritTotemAura";
            area_effect.AffectEnemies = true;
            area_effect.AggroEnemies  = true;
            area_effect.Size          = 5.Feet();
            area_effect.Shape         = AreaEffectShape.Cylinder;
            var damage             = Helpers.CreateContextDiceValue(DiceType.D8, Common.createSimpleContextValue(1));
            var damage_action      = Helpers.CreateActionDealDamage(DamageEnergyType.NegativeEnergy, damage, isAoE: true);
            var conditional_damage = Helpers.CreateConditional(new Condition[] { Helpers.Create <ContextConditionIsEnemy>() },
                                                               damage_action);

            area_effect.AddComponent(Helpers.CreateAreaEffectRunAction(round: conditional_damage));
            area_effect.Fx = new Kingmaker.ResourceLinks.PrefabLink();
            library.AddAsset(area_effect, "");

            greater_spirit_totem_slam_attack = library.CopyAndAdd <BlueprintItemWeapon>(lesser_spirit_totem_slam_attack.AssetGuid, "GreaterSpiritTotemSlam", "");
            Helpers.SetField(greater_spirit_totem_slam_attack, "m_DamageDice", new DiceFormula(1, DiceType.D6));
            var buff = Helpers.CreateBuff("GreaterSpiritTotemBuff",
                                          "",
                                          "",
                                          "",
                                          null,
                                          null,
                                          Common.createAddSecondaryAttacks(greater_spirit_totem_slam_attack),
                                          Common.createAddAreaEffect(area_effect)
                                          );

            buff.SetBuffFlags(BuffFlags.HiddenInUi);


            greater_spirit_totem = Helpers.CreateFeature("GreaterSpiritTotemFeature",
                                                         "Sprit Totem, Greater",
                                                         "While raging, the spirits that surround the barbarian become dangerous to any enemy adjacent to the barbarian. Living enemies adjacent to the barbarian at the start of her turn take 1d8 points of negative energy damage. In addition slam attack deals 1d6 points of negative energy damage.",
                                                         "",
                                                         lesser_spirit_totem.Icon,
                                                         FeatureGroup.RagePower,
                                                         Helpers.PrerequisiteClassLevel(barbarian_class, 10),
                                                         Helpers.PrerequisiteFeature(spirit_totem)
                                                         );

            Common.addContextActionApplyBuffOnFactsToActivatedAbilityBuffNoRemove(rage_buff, buff, greater_spirit_totem);

            var conditional_lesser = Helpers.CreateConditional(new Condition[] { Common.createContextConditionHasFact(greater_spirit_totem, false),
                                                                                 Common.createContextConditionHasFact(lesser_spirit_totem) },
                                                               Common.createContextActionApplyBuff(lesser_spirit_totem_buff, Helpers.CreateContextDuration(),
                                                                                                   is_child: true, is_permanent: true, dispellable: false)
                                                               );

            Common.addContextActionApplyBuffOnConditionToActivatedAbilityBuff(rage_buff, conditional_lesser);
            Common.addContextActionApplyBuffOnFactsToActivatedAbilityBuffNoRemove(rage_buff, buff, greater_spirit_totem);
            addToSelection(greater_spirit_totem);
        }
        public void ActivateModifier()
        {
            if (headbuttSlot == null)
            {
                headbuttSlot = -1;
                int    armorEnhancement = GameHelper.GetItemEnhancementBonus(base.Owner.Body.Armor.Armor);
                string assetID          = Helpers.getGuid("SteelHeadbuttType" + base.Owner.Body.Armor.Armor.Blueprint.ProficiencyGroup + "Enhancement" + armorEnhancement);

                BlueprintItemWeapon headbutt = Main.library.Get <BlueprintItemWeapon>(assetID);
                headbuttSlot = base.Owner.Body.AddAdditionalLimb(headbutt, true);
            }
        }
 private static void Postfix(BlueprintItemWeapon __instance, ref DiceFormula __result)
 {
     foreach (var enchantment in __instance.Enchantments)
     {
         var component = enchantment.GetComponent <WeaponSizeChange>();
         if (component != null)
         {
             __result = WeaponDamageScaleTable.Scale(__result, __instance.Size + component.SizeCategoryChange, __instance.Size, __instance);
             break;
         }
     }
 }
示例#8
0
 private static void Postfix(BlueprintItemWeapon __instance, ref StatType __result)
 {
     foreach (var enchantment in __instance.Enchantments)
     {
         var component = enchantment.GetComponent <WeaponBaseSizeChange>();
         if (component != null)
         {
             if (component.SizeCategoryChange != 0)
             {
                 __result = StatType.Strength;
             }
             break;
         }
     }
 }
        static internal void createLesserSpiritTotem()
        {
            var blur = library.Get <BlueprintAbility>("14ec7a4e52e90fa47a4c8d63c69fd5c1");

            lesser_spirit_totem_slam_attack = library.CopyAndAdd <BlueprintItemWeapon>("7445b0b255796d34495a8bca81b2e2d4", "LesserSpiritTotemSlam", "");
            Helpers.SetField(lesser_spirit_totem_slam_attack, "m_OverrideDamageDice", true);
            Helpers.SetField(lesser_spirit_totem_slam_attack, "m_DamageDice", new DiceFormula(1, DiceType.D4));
            Helpers.SetField(lesser_spirit_totem_slam_attack, "m_OverrideDamageType", true);
            Helpers.SetField(lesser_spirit_totem_slam_attack, "m_DamageType", Common.createEnergyDamageDescription(Kingmaker.Enums.Damage.DamageEnergyType.NegativeEnergy));

            var enchant = Common.createWeaponEnchantment("LesserSpiritTotemSlamEnchantment",
                                                         "Spirit",
                                                         "Spirit weapon uses wielders Charisma modifier for attack and damage bonus.",
                                                         "Spirit", "",
                                                         "",
                                                         0,
                                                         null,
                                                         Common.createWeaponAttackStatReplacementEnchantment(StatType.Charisma),
                                                         Common.createWeaponDamageStatReplacementEnchantment(StatType.Charisma)
                                                         );

            Common.addEnchantment(lesser_spirit_totem_slam_attack, enchant);

            lesser_spirit_totem_buff = Helpers.CreateBuff("LesserSpiritTotemBuff",
                                                          "",
                                                          "",
                                                          "",
                                                          null,
                                                          null,
                                                          Common.createAddSecondaryAttacks(lesser_spirit_totem_slam_attack)
                                                          );
            lesser_spirit_totem_buff.SetBuffFlags(BuffFlags.HiddenInUi);

            lesser_spirit_totem = Helpers.CreateFeature("LesserSpiritTotemFeature",
                                                        "Sprit Totem, Lesser",
                                                        "While raging, the barbarian is surrounded by spirit wisps that harass her foes. These spirits make one slam attack each round against a living foe that is adjacent to the barbarian. This slam attack is made using the barbarian’s full base attack bonus, plus the barbarian’s Charisma modifier. The slam deals 1d4 points of negative energy damage, plus the barbarian’s Charisma modifier.\n"
                                                        + "Note: Totem rage powers grant powers related to a theme.A barbarian cannot select from more than one group of totem rage powers; for example, a barbarian who selects a beast totem rage power cannot later choose to gain any of the dragon totem rage powers(any rage power with “dragon totem” in its title).",
                                                        "",
                                                        blur.Icon,
                                                        FeatureGroup.RagePower
                                                        );

            addToSelection(lesser_spirit_totem, is_totem: true);
        }
示例#10
0
 private static void Postfix(BlueprintItemWeapon __instance, ref bool __result)
 {
     foreach (var enchantment in __instance.Enchantments)
     {
         var component = enchantment.GetComponent <WeaponBaseSizeChange>();
         if (component != null)
         {
             if (component.SizeCategoryChange == 1)
             {
                 __result = false;
             }
             else if ((component.SizeCategoryChange == -1 && !__instance.Type.IsTwoHanded) || (component.SizeCategoryChange == -2))
             {
                 __result = true;
             }
             break;
         }
     }
 }
        /*static IEnumerable<Harmony12.CodeInstruction> Transpiler(IEnumerable<Harmony12.CodeInstruction> instructions)
         * {
         *  var codes = instructions.ToList();
         *  var check_is_unarmed = codes.FindIndex(x => x.opcode == System.Reflection.Emit.OpCodes.Callvirt && x.operand.ToString().Contains("IsUnarmed")); //checking is unarmed on weapon on primary hand
         *
         *  codes[check_is_unarmed] = new Harmony12.CodeInstruction(System.Reflection.Emit.OpCodes.Ldarg_0);
         *  codes.Insert(check_is_unarmed + 1, new Harmony12.CodeInstruction(System.Reflection.Emit.OpCodes.Call, new Func<BlueprintItemWeapon, RuleCalculateAttacksCount, bool>(considerUnarmedAndIgnore).Method));
         *
         *  check_is_unarmed = codes.IndexOf(codes.FindAll(x => x.opcode == System.Reflection.Emit.OpCodes.Callvirt && x.operand.ToString().Contains("IsUnarmed"))[2]);
         *  codes[check_is_unarmed] = new Harmony12.CodeInstruction(System.Reflection.Emit.OpCodes.Ldarg_0);
         *  codes.Insert(check_is_unarmed + 1, new Harmony12.CodeInstruction(System.Reflection.Emit.OpCodes.Call, new Func<BlueprintItemWeapon, RuleCalculateAttacksCount, bool>(considerUnarmedAndIgnoreOffHand).Method));
         *  return codes.AsEnumerable();
         * }*/

        static bool Prefix(RuleCalculateAttacksCount __instance, RulebookEventContext context)
        {
            int                 bab = (int)__instance.Initiator.Stats.BaseAttackBonus;
            int                 num_penalized_attacks = Math.Min(Math.Max(0, bab / 5 - (bab % 5 == 0 ? 1 : 0)), 3);
            HandSlot            primary_hand          = __instance.Initiator.Body.PrimaryHand;
            HandSlot            secondary_hand        = __instance.Initiator.Body.SecondaryHand;
            BlueprintItemWeapon blueprint1            = primary_hand.MaybeWeapon?.Blueprint;
            BlueprintItemWeapon blueprint2            = secondary_hand.MaybeShield != null ? ((bool)__instance.Initiator.Descriptor.State.Features.ShieldBash ? secondary_hand.MaybeShield.WeaponComponent?.Blueprint : null) : secondary_hand.MaybeWeapon?.Blueprint;
            int                 num = primary_hand.MaybeWeapon == null ? 0 : (primary_hand.MaybeWeapon.HoldInTwoHands ? 1 : 0);

            if ((secondary_hand.MaybeWeapon?.HoldInTwoHands).GetValueOrDefault() == false &&
                (blueprint1 != null) &&
                (!considerUnarmedAndIgnore(blueprint1, __instance) || blueprint2 == null || blueprint2.IsUnarmed)
                )
            {
                ++__instance.PrimaryHand.MainAttacks;
                if (!blueprint1.IsNatural || (bool)__instance.Initiator.Descriptor.State.Features.IterativeNaturalAttacks || __instance.ForceIterativeNaturealAttacks || blueprint1.IsUnarmed)
                {
                    __instance.PrimaryHand.PenalizedAttacks += Math.Max(0, num_penalized_attacks);
                }
            }
            if ((secondary_hand.MaybeWeapon?.HoldInTwoHands).GetValueOrDefault() == true ||
                (blueprint2 == null) ||
                considerUnarmedAndIgnoreOffHand(blueprint2, __instance) && (blueprint1 != null) ||
                (primary_hand.MaybeWeapon?.HoldInTwoHands).GetValueOrDefault() == true
                )
            {
                return(false);
            }
            ++__instance.SecondaryHand.MainAttacks;
            if (blueprint1 == null || !considerUnarmedAndIgnore(blueprint1, __instance) &&
                (blueprint1 == null || !blueprint1.IsNatural || !(bool)__instance.Initiator.Descriptor.State.Features.IterativeNaturalAttacks && !__instance.ForceIterativeNaturealAttacks) ||
                (blueprint2.IsUnarmed)
                )
            {
                return(false);
            }
            __instance.SecondaryHand.PenalizedAttacks += Math.Max(0, num_penalized_attacks);
            return(false);
        }
示例#12
0
 //signal weapon set change to notify that weapons could have been changed
 static void Postfix(UnitBody __instance, BlueprintItemWeapon weapon)
 {
     UnitBody__SetEmptyHandWeapon__Patch.no_animation_action = true;
     EventBus.RaiseEvent <IUnitActiveEquipmentSetHandler>((Action <IUnitActiveEquipmentSetHandler>)(h => h.HandleUnitChangeActiveEquipmentSet(__instance.Owner)));
     UnitBody__SetEmptyHandWeapon__Patch.no_animation_action = false;
 }
 private static bool considerUnarmedAndIgnoreOffHand(BlueprintItemWeapon weapon, UnitDescriptor unit)
 {
     return(Aux.isOffHandUnarmedAndCanBeIgnored(weapon, unit));
 }
 public static bool isOffHandUnarmedAndCanBeIgnored(BlueprintItemWeapon weapon, UnitDescriptor unit)
 {
     return(weapon.IsUnarmed && !((bool)unit.State.Features.ImprovedUnarmedStrike && (unit.Get <UnitPartUnarmedTwf>()?.active()).GetValueOrDefault()));
 }
 public static bool isMainHandUnarmedAndCanBeIgnored(BlueprintItemWeapon weapon, UnitDescriptor unit)
 {
     return(weapon.IsUnarmed && !(bool)unit.State.Features.ImprovedUnarmedStrike);
 }
 private static bool considerUnarmedAndIgnoreOffHand(BlueprintItemWeapon weapon, RuleCalculateAttacksCount evt)
 {
     return(Aux.isOffHandUnarmedAndCanBeIgnored(weapon, evt.Initiator.Descriptor));
 }
示例#17
0
        public static BlueprintFeatureSelection CreateRaceTraits(BlueprintFeatureSelection adopted)
        {
            var noFeature  = Helpers.PrerequisiteNoFeature(null);
            var raceTraits = Helpers.CreateFeatureSelection("RaceTrait", RES.RaceTraitName_info,
                                                            RES.RaceTraitDescription_info,
                                                            "6264aa9515be40cda55892da93685764", null, FeatureGroup.None,
                                                            Helpers.PrerequisiteNoFeature(adopted), noFeature);

            noFeature.Feature = raceTraits;

            var humanReq = Helpers.PrerequisiteFeaturesFromList(Helpers.human, Helpers.halfElf, Helpers.halfOrc,
                                                                // Note: Aasimar/Tiefling included under the assumption they have "Scion of Humanity"/"Pass for Human"
                                                                Helpers.aasimar, Helpers.tiefling);

            var halfElfReq  = Helpers.PrerequisiteFeature(Helpers.halfElf);
            var halfOrcReq  = Helpers.PrerequisiteFeature(Helpers.halfOrc);
            var elfReq      = Helpers.PrerequisiteFeaturesFromList(Helpers.elf, Helpers.halfElf);
            var dwarfReq    = Helpers.PrerequisiteFeature(Helpers.dwarf);
            var halflingReq = Helpers.PrerequisiteFeature(Helpers.halfling);
            var gnomeReq    = Helpers.PrerequisiteFeature(Helpers.gnome);
            var aasimarReq  = Helpers.PrerequisiteFeature(Helpers.aasimar);
            var tieflingReq = Helpers.PrerequisiteFeature(Helpers.tiefling);

            // TODO: how do we code prerequisites so they aren't ignored by "Adopted"?
            // (only race prereq should be ignored, not others)
            //
            // Note: half-elf, half-orc can take traits from either race.
            // Also Aasimar/Tiefling are treated as having Scion of Humanity/Pass for Human in the game.
            var choices = new List <BlueprintFeature>();

            // Human:
            // - Carefully Hidden (+1 will save, +2 vs divination)
            // - Fanatic (Arcana)
            // - Historian (World and +1 bardic knowledge if Bard)
            // - Shield Bearer (+1 dmg shield bash)
            // - Superstitious (+1 save arcane spells)
            // - World Traveler (choose: persuasion, perception, or world)

            var components = new List <BlueprintComponent> {
                humanReq
            };

            components.Add(Helpers.CreateAddStatBonus(StatType.SaveWill, 1, ModifierDescriptor.Trait));
            components.Add(Helpers.Create <SavingThrowBonusAgainstSchool>(a =>
            {
                a.School             = SpellSchool.Divination;
                a.Value              = 2;
                a.ModifierDescriptor = ModifierDescriptor.Trait;
            }));
            choices.Add(Helpers.CreateFeature("CarefullyHiddenTrait", RES.RaceCarefullyHiddenTraitName_info,
                                              RES.RaceCarefullyHiddenTraitDescription_info,
                                              "38b92d2ebb4c4cdb8e946e29f5b2f178",
                                              Helpers.GetIcon("175d1577bb6c9a04baf88eec99c66334"), // Iron Will
                                              FeatureGroup.None,
                                              components.ToArray()));

            choices.Add(Traits.CreateAddStatBonus("FanaticTrait", RES.RaceFanaticTraitName_info,
                                                  RES.RaceFanaticTraitDescription_info,
                                                  "6427e81ba399406c93b463c284a42055",
                                                  StatType.SkillKnowledgeArcana,
                                                  humanReq));

            var bardicKnowledge = Traits.library.Get <BlueprintFeature>("65cff8410a336654486c98fd3bacd8c5");

            components.Clear();
            components.Add(humanReq);
            components.AddRange((new StatType[] {
                StatType.SkillKnowledgeArcana,
                StatType.SkillKnowledgeWorld,
                StatType.SkillLoreNature,
                StatType.SkillLoreReligion,
            }).Select((skill) => Helpers.Create <AddStatBonusIfHasFact>(a =>
            {
                a.Stat        = skill;
                a.Value       = 1;
                a.CheckedFact = bardicKnowledge;
                a.Descriptor  = ModifierDescriptor.UntypedStackable;
            })));

            var historian = Traits.CreateAddStatBonus("HistorianTrait", RES.RaceHistorianTraitName_info,
                                                      RES.RaceHistorianTraitDescription_info,
                                                      "4af3871899e4440bae03d4c33d4b52fd",
                                                      StatType.SkillKnowledgeWorld,
                                                      components.ToArray());

            choices.Add(historian);

            components.Clear();
            components.Add(humanReq);
            components.AddRange(new String[] {
                "98a0dc03586a6d04791901c41700e516", // SpikedLightShield
                "1fd965e522502fe479fdd423cca07684", // WeaponLightShield
                "a1b85d048fb5003438f34356df938a9f", // SpikedHeavyShield
                "be9b6408e6101cb4997a8996484baf19"  // WeaponHeavyShield
            }.Select(id => Helpers.Create <WeaponTypeDamageBonus>(w => { w.DamageBonus = 1; w.WeaponType = Traits.library.Get <BlueprintWeaponType>(id); })));

            choices.Add(Helpers.CreateFeature("ShieldBearerTrait", RES.RaceShieldBearerTraitName_info,
                                              RES.RaceShieldBearerTraitDescription_info,
                                              "044ebbbadfba4d58afa11bfbf38df199",
                                              Helpers.GetIcon("121811173a614534e8720d7550aae253"), // Shield Bash
                                              FeatureGroup.None,
                                              components.ToArray()));

            choices.Add(Helpers.CreateFeature("SuperstitiousTrait", RES.RaceSuperstitiousTraitName_info,
                                              RES.RaceSuperstitiousTraitDescription_info,
                                              "f5d79e5fbb87473ca0b13ed15b742079",
                                              Helpers.GetIcon("2483a523984f44944a7cf157b21bf79c"), // Elven Immunities
                                              FeatureGroup.None,
                                              humanReq,
                                              Helpers.Create <SavingThrowBonusAgainstSpellSource>()));

            //var travelerDescription = "Your family has taken the love of travel to an extreme, roaming the world extensively. You've seen dozens of cultures and have learned to appreciate the diversity of what the world has to offer.";
            var worldTraveler = Helpers.CreateFeatureSelection("WorldTravelerTrait", RES.RaceWorldTravelerTraitName_info,
                                                               RES.RaceWorldTravelerTraitDescription_info + RES.RaceWorldTravelerTraitBenefit_info,
                                                               "ecacfcbeddfe453cafc8d60fc1db7d34",
                                                               Helpers.GetIcon("3adf9274a210b164cb68f472dc1e4544"), // Human Skilled
                                                               FeatureGroup.None,
                                                               humanReq);

            var travelerFeats = new StatType[] {
                StatType.SkillPersuasion,
                StatType.SkillKnowledgeWorld,
                StatType.SkillPerception
            }.Select(skill => Traits.CreateAddStatBonus(
                         $"WorldTraveler{skill}Trait",
                         String.Format(RES.TypeHyphenSubtype_info,
                                       RES.RaceWorldTravelerTraitName_info.Substring(0, RES.RaceWorldTravelerTraitName_info.IndexOf("(") >= 0 ?
                                                                                     RES.RaceWorldTravelerTraitName_info.IndexOf("(") : RES.RaceWorldTravelerTraitName_info.IndexOf("(")),
                                       UIUtility.GetStatText(skill)),
                         RES.RaceWorldTravelerTraitDescription_info,
                         Helpers.MergeIds(Helpers.GetSkillFocus(skill).AssetGuid, "9b03b7ff17394007a3fbec18aa42604b"),
                         skill)).ToArray();

            worldTraveler.SetFeatures(travelerFeats);
            choices.Add(worldTraveler);

            // Elf:
            // - Dilettante Artist (persuasion)
            // - Forlorn (+1 fort save)
            // - Warrior of the Old (+2 init)
            // - Youthful Mischief (+1 ref)
            choices.Add(Traits.CreateAddStatBonus("DilettanteArtistTrait", RES.DilettanteArtistTraitName_info,
                                                  RES.DilettanteArtistTraitDescription_info,
                                                  "ac5a16e72ef74b4884c674dcbb61692c",
                                                  StatType.SkillPersuasion, elfReq));

            choices.Add(Helpers.CreateFeature("ForlornTrait", RES.ForlornTraitName_info,
                                              RES.ForlornTraitDescription_info,
                                              "1511289c92ea4233b14c4f51072ea10f",
                                              Helpers.GetIcon("79042cb55f030614ea29956177977c52"), // Great Fortitude
                                              FeatureGroup.None,
                                              elfReq,
                                              Helpers.CreateAddStatBonus(StatType.SaveFortitude, 1, ModifierDescriptor.Trait)
                                              ));

            choices.Add(Helpers.CreateFeature("WarriorOfOldTrait", RES.WarriorOfOldTraitName_info,
                                              RES.WarriorOfOldTraitDescription_info,
                                              "dc36a2c52abb4e6dbff549ac65a5a171",
                                              Helpers.GetIcon("797f25d709f559546b29e7bcb181cc74"), // Improved Initiative
                                              FeatureGroup.None,
                                              elfReq,
                                              Helpers.CreateAddStatBonus(StatType.Initiative, 2, ModifierDescriptor.Trait)));

            choices.Add(Helpers.CreateFeature("YouthfulMischiefTrait", RES.YouthfulMischiefTraitName_info,
                                              RES.YouthfulMischiefTraitDescription_info,
                                              "bfcc574d1f214455ac369fa46e07200e",
                                              Helpers.GetIcon("15e7da6645a7f3d41bdad7c8c4b9de1e"), // Lightning Reflexes
                                              FeatureGroup.None,
                                              elfReq,
                                              Helpers.CreateAddStatBonus(StatType.SaveReflex, 1, ModifierDescriptor.Trait)));

            // Half-orc:
            // - Brute (persuasion)
            // - Legacy of Sand (+1 will save)
            var brute = Traits.CreateAddStatBonus("BruteTrait", RES.BruteTraitName_info,
                                                  RES.BruteTraitDescription_info,
                                                  "1ee0ce55ace74ccbb798e2fdc13181f6", StatType.SkillPersuasion, halfOrcReq);

            brute.SetIcon(Helpers.GetIcon("885f478dff2e39442a0f64ceea6339c9")); // Intimidating
            choices.Add(brute);

            BlueprintItemWeapon bite = Traits.library.CopyAndAdd <BlueprintItemWeapon>("35dfad6517f401145af54111be04d6cf", "Tusked",
                                                                                       "44dfad6517f401145af54111be04d644");

            choices.Add(Helpers.CreateFeature("TuskedTrait", RES.TuskedTraitName_info,
                                              RES.TuskedTraitDescription_info,
                                              "1511289c92ea4233b14c4f51072ea09g",
                                              Image2Sprite.Create("Mods/EldritchArcana/sprites/halforc_tusked.png"), // Great Fortitude
                                              FeatureGroup.None,
                                              halfOrcReq,
                                              Helpers.Create <AddAdditionalLimb>(x => x.Weapon = bite)
                                              ));

            choices.Add(Helpers.CreateFeature("LegacyOfSandTrait", RES.LegacyOfSandTraitName_info,
                                              RES.LegacyOfSandTraitDescription_info,
                                              "e5fb1675eb6e4ef9accef7eb3a10862a",
                                              Image2Sprite.Create("Mods/EldritchArcana/sprites/halforc_legacy_of_sand.png"),
                                              FeatureGroup.None,
                                              halfOrcReq,
                                              Helpers.CreateAddStatBonus(StatType.SaveWill, 1, ModifierDescriptor.Trait)));

            // Half-elf:
            // - Elven Relexes (+2 initiative)
            // - Failed Apprentice (+1 save arcane spells)
            choices.Add(Helpers.CreateFeature("ElvenReflexsTrait", RES.ElvenReflexsTraitName_info,
                                              RES.ElvenReflexsTraitDescription_info,
                                              "9975678ce2fc420da9cd6ec4fe8c8b9b",
                                              Helpers.GetIcon("797f25d709f559546b29e7bcb181cc74"), // Improved Initiative
                                              FeatureGroup.None,
                                              halfElfReq,
                                              Helpers.CreateAddStatBonus(StatType.Initiative, 2, ModifierDescriptor.Trait)));

            choices.Add(Helpers.CreateFeature("FailedAprenticeTrait", RES.FailedAprenticeTraitName_info,
                                              RES.FailedAprenticeTraitDescription_info,
                                              "8ed66066751f43c2920055dd6358adc8",
                                              Helpers.GetIcon("2483a523984f44944a7cf157b21bf79c"), // Elven Immunities
                                              FeatureGroup.None,
                                              halfElfReq,
                                              Helpers.Create <SavingThrowBonusAgainstSpellSource>()));

            // Halfling:
            // - Freed Slave (world)
            // - Freedom Fighter (mobility)
            // - Well-Informed (persuasion)
            choices.Add(Traits.CreateAddStatBonus("FreedSlaveTrait", RES.FreedSlaveTraitName_info,
                                                  RES.FreedSlaveTraitDescription_info,
                                                  "d2fc5fe0c64142a79e0ebee18f14b0be", StatType.SkillKnowledgeWorld, halflingReq));
            choices.Add(Traits.CreateAddStatBonus("FreedomFighterTrait", RES.FreedomFighterTraitName_info,
                                                  RES.FreedomFighterTraitDescription_info,
                                                  "3a4d2cd14dc446319085c865570ccc3d", StatType.SkillMobility, halflingReq));
            choices.Add(Traits.CreateAddStatBonus("WellInformedTrait", RES.WellInformedTraitName_info,
                                                  RES.WellInformedTraitDescription_info,
                                                  "940ced5d41594b9aa22ee22217fbd46f", StatType.SkillPersuasion, halflingReq));

            // Dwarf:
            // - Grounded (+2 mobility, +1 reflex)
            // - Militant Merchant (perception)Owner.HPLeft
            // - Ruthless (+1 confirm crits)
            // - Zest for Battle (+1 trait dmg if has morale attack bonus)

            var GloryOfOld = Helpers.CreateFeature("GloryOfOldTrait", RES.GloryOfOldTraitName_info,
                                                   RES.GloryOfOldTraitDescription_info,
                                                   "4283a523984f44944a7cf157b21bf7c9",
                                                   Image2Sprite.Create("Mods/EldritchArcana/sprites/spell_perfection.png"),
                                                   FeatureGroup.None,
                                                   dwarfReq,
                                                   Helpers.Create <SavingThrowBonusAgainstDescriptor>(s => { s.SpellDescriptor = SpellDescriptor.Poison; s.Value = 1; s.ModifierDescriptor = ModifierDescriptor.Racial; }),
                                                   Helpers.Create <SavingThrowBonusAgainstDescriptor>(s => { s.SpellDescriptor = SpellDescriptor.BreathWeapon; s.Value = 1; s.ModifierDescriptor = ModifierDescriptor.Trait; }));

            components.Clear();
            components.AddRange((new SpellSchool[]
            {
                SpellSchool.Abjuration,
                SpellSchool.Conjuration,
                SpellSchool.Divination,
                SpellSchool.Enchantment,
                SpellSchool.Evocation,
                SpellSchool.Illusion,
                SpellSchool.Necromancy,
                SpellSchool.Transmutation,
                SpellSchool.Universalist
            }).Select((school) => Helpers.Create <SavingThrowBonusAgainstSchool>(a =>
            {
                a.School             = school;
                a.Value              = 1;
                a.ModifierDescriptor = ModifierDescriptor.Racial;
            })));

            GloryOfOld.AddComponents(components);

            choices.Add(GloryOfOld);

            choices.Add(Helpers.CreateFeature("GroundedTrait", RES.GroundedTraitName_info,
                                              RES.GroundedTraitDescription_info,
                                              "9b13923527a64c3bbf8de904c5a9ef8b",
                                              Helpers.GetIcon("3a8d34905eae4a74892aae37df3352b9"), // Skill Focus Stealth (mobility)
                                              FeatureGroup.None,
                                              dwarfReq,
                                              Helpers.CreateAddStatBonus(StatType.SkillMobility, 2, ModifierDescriptor.Racial),
                                              Helpers.CreateAddStatBonus(StatType.SaveReflex, 1, ModifierDescriptor.Racial)));

            choices.Add(Traits.CreateAddStatBonus("MilitantMerchantTrait", RES.MilitantMerchantTraitName_info,
                                                  RES.MilitantMerchantTraitDescription_info,
                                                  "38226f4ad9ed4211878ef95497d01857", StatType.SkillPerception, dwarfReq));

            choices.Add(Helpers.CreateFeature("RuthlessTrait", RES.RuthlessTraitName_info,
                                              RES.RuthlessTraitDescription_info,
                                              "58d18289cb7f4ad4a690d9502d397a3a",
                                              Helpers.GetIcon("f4201c85a991369408740c6888362e20"), // Improved Critical
                                              FeatureGroup.None,
                                              dwarfReq,
                                              Helpers.Create <CriticalConfirmationBonus>(a => { a.Bonus = 1; a.Value = 0; })));


            var Frostborn = Helpers.CreateFeature("FrostbornTrait", RES.FrostbornTraitName_info,
                                                  RES.FrostbornTraitDescription_info,
                                                  "f987f5e69db44cdd99983985e37a6c3c",
                                                  Helpers.GetIcon("121811173a614534e8720d7550aae253"), // Weapon Specialization
                                                  FeatureGroup.None,
                                                  dwarfReq);

            Frostborn.AddComponent(Helpers.Create <AddDamageResistanceEnergy>(r => { r.Type = Kingmaker.Enums.Damage.DamageEnergyType.Cold; r.Value = 4; }));
            Frostborn.AddComponent(Helpers.Create <SavingThrowBonusAgainstDescriptor>(s => { s.SpellDescriptor = SpellDescriptor.Cold; s.ModifierDescriptor = ModifierDescriptor.Racial; s.Bonus = 1; }));
            choices.Add(Frostborn);

            choices.Add(Helpers.CreateFeature("ZestForBattleTrait", RES.ZestForBattleTraitName_info,
                                              RES.ZestForBattleTraitDescription_info,
                                              "a987f5e69db44cdd98983985e37a6c2a",
                                              Helpers.GetIcon("31470b17e8446ae4ea0dacd6c5817d86"), // Weapon Specialization
                                              FeatureGroup.None,
                                              dwarfReq,
                                              Helpers.Create <DamageBonusIfMoraleBonus>()));

            // Gnome:
            // - Animal Friend (+1 will save and lore nature class skill, must have familar or animal companion)
            // - Rapscallion (+1 init, +1 thievery)
            components.Clear();
            components.Add(gnomeReq);
            components.Add(Helpers.Create <AddClassSkill>(a => a.Skill = StatType.SkillLoreNature));
            // TODO: is there a cleaner way to implement this rather than a hard coded list?
            // (Ideally: it should work if a party NPC has a familiar/animal companion too.)
            // See also: PrerequisitePet.
            components.AddRange((new String[] {
                // Animal companions
                "f6f1cdcc404f10c4493dc1e51208fd6f",
                "afb817d80b843cc4fa7b12289e6ebe3d",
                "f9ef7717531f5914a9b6ecacfad63f46",
                "f894e003d31461f48a02f5caec4e3359",
                "e992949eba096644784592dc7f51a5c7",
                "aa92fea676be33d4dafd176d699d7996",
                "2ee2ba60850dd064e8b98bf5c2c946ba",
                "6adc3aab7cde56b40aa189a797254271",
                "ece6bde3dfc76ba4791376428e70621a",
                "126712ef923ab204983d6f107629c895",
                "67a9dc42b15d0954ca4689b13e8dedea",
                // Familiars
                "1cb0b559ca2e31e4d9dc65de012fa82f",
                "791d888c3f87da042a0a4d0f5c43641c",
                "1bbca102706408b4cb97281c984be5d5",
                "f111037444d5b6243bbbeb7fc9056ed3",
                "7ba93e2b888a3bd4ba5795ae001049f8",
                "97dff21a036e80948b07097ad3df2b30",
                "952f342f26e2a27468a7826da426f3e7",
                "61aeb92c176193e48b0c9c50294ab290",
                "5551dd90b1480e84a9caf4c5fd5adf65",
                "adf124729a6e01f4aaf746abbed9901d",
                "4d48365690ea9a746a74d19c31562788",
                "689b16790354c4c4c9b0f671f68d85fc",
                "3c0b706c526e0654b8af90ded235a089",
            }).Select(id => Helpers.Create <AddStatBonusIfHasFact>(a =>
            {
                a.Stat        = StatType.SaveWill;
                a.Value       = 1;
                a.Descriptor  = ModifierDescriptor.Trait;
                a.CheckedFact = Traits.library.Get <BlueprintFeature>(id);
            })));

            choices.Add(Helpers.CreateFeature("AnimalFriendTrait", RES.AnimalFriendTraitName_info,
                                              RES.AnimalFriendTraitDescription_info,
                                              "91c612b225d54adaa4ce4c633501b58e",
                                              Image2Sprite.Create("Mods/EldritchArcana/sprites/gnome_animal_friend.png"),//Helpers.GetIcon("1670990255e4fe948a863bafd5dbda5d"), // Boon Companion
                                              FeatureGroup.None,
                                              components.ToArray()));

            choices.Add(Helpers.CreateFeature("RapscallionTrait", RES.RapscallionTraitName_info,
                                              RES.RapscallionTraitDescription_info,
                                              "4f95abdcc70e4bda818be5b8860585c5",
                                              Helpers.GetSkillFocus(StatType.SkillMobility).Icon,
                                              FeatureGroup.None,
                                              gnomeReq,
                                              Helpers.CreateAddStatBonus(StatType.SkillMobility, 1, ModifierDescriptor.Trait),
                                              Helpers.CreateAddStatBonus(StatType.Initiative, 1, ModifierDescriptor.Trait)));

            // Aasimar:
            // - Martyr's Blood (+1 attack if HP below half).
            // - Toxophilite (+2 crit confirm with bows)
            // - Wary (+1 perception/persuasion)

            // TODO: Enlightened Warrior

            choices.Add(Helpers.CreateFeature("MartyrsBloodTrait", RES.MartyrsBloodTraitName_info,
                                              RES.MartyrsBloodTraitDescription_info,
                                              "729d27ad020d485f843264844f0f2155",
                                              Helpers.GetIcon("3ea2215150a1c8a4a9bfed9d9023903e"), // Iron Will Improved
                                              FeatureGroup.None,
                                              aasimarReq,
                                              Helpers.Create <AttackBonusIfAlignmentAndHealth>(a =>
            {
                a.TargetAlignment = AlignmentComponent.Evil;
                a.Descriptor      = ModifierDescriptor.Trait;
                a.Value           = 1;
                a.HitPointPercent = 0.5f;
            })));

            choices.Add(Helpers.CreateFeature("ToxophiliteTrait", RES.ToxophiliteTraitName_info,
                                              RES.ToxophiliteTraitDescription_info,
                                              "6c434f07c8984971b1d842cecdf144c6",
                                              Helpers.GetIcon("f4201c85a991369408740c6888362e20"), // Improved Critical
                                              FeatureGroup.None,
                                              aasimarReq,
                                              Helpers.Create <CriticalConfirmationBonus>(a =>
            {
                a.Bonus = 2;
                a.Value = 0;
                a.CheckWeaponRangeType = true;
                a.Type = AttackTypeAttackBonus.WeaponRangeType.RangedNormal;
            })));

            choices.Add(Helpers.CreateFeature("WaryTrait", RES.WaryTraitName_info,
                                              RES.WaryTraitDescription_info,
                                              "7a72a0e956784cc38ea049e503189810",
                                              Helpers.GetIcon("86d93a5891d299d4983bdc6ef3987afd"), // Persuasive
                                              FeatureGroup.None,
                                              aasimarReq,
                                              Helpers.CreateAddStatBonus(StatType.SkillPerception, 1, ModifierDescriptor.Trait),
                                              Helpers.CreateAddStatBonus(StatType.SkillPerception, 1, ModifierDescriptor.Trait)));

            // Tiefling:
            // - Ever Wary (retain half dex bonus AC during surpise round)
            // - Prolong Magic (racial spell-like abilities get free extend spell)
            // - God Scorn (Demodand heritage; +1 saves vs divine spells)
            // - Shadow Stabber (+2 damage if opponent can't see you)

            choices.Add(Helpers.CreateFeature("EverWaryTrait", RES.EverWaryTraitName_info,
                                              RES.EverWaryTraitDescripton_info,
                                              "0400c9c99e704a1f81a769aa88044a03",
                                              Helpers.GetIcon("3c08d842e802c3e4eb19d15496145709"), // uncanny dodge
                                              FeatureGroup.None,
                                              tieflingReq,
                                              Helpers.Create <ACBonusDuringSurpriseRound>()));

            var tieflingHeritageDemodand = Traits.library.Get <BlueprintFeature>("a53d760a364cd90429e16aa1e7048d0a");

            choices.Add(Helpers.CreateFeature("GodScornTrait", RES.GodScornTraitName_info,
                                              RES.GodScornTraitDescription_info,
                                              "db41263f6fd3450ea0a3bc45c98330f7",
                                              Helpers.GetIcon("2483a523984f44944a7cf157b21bf79c"), // Elven Immunities
                                              FeatureGroup.None,
                                              Helpers.PrerequisiteFeature(tieflingHeritageDemodand),
                                              Helpers.Create <SavingThrowBonusAgainstSpellSource>(s => s.Source = SpellSource.Divine)));

            var tieflingHeritageSelection = Traits.library.Get <BlueprintFeatureSelection>("c862fd0e4046d2d4d9702dd60474a181");

            choices.Add(Helpers.CreateFeature("ProlongMagicTrait", RES.ProlongMagicTraitName_info,
                                              RES.ProlongMagicTraitDescription_info,
                                              "820f697f59114993a55c46044c98bf9c",
                                              tieflingHeritageSelection.Icon,
                                              FeatureGroup.None,
                                              tieflingReq,
                                              // TODO: double check that this actually works for SLAs.
                                              Helpers.Create <AutoMetamagic>(a => { a.Metamagic = Metamagic.Extend; a.Abilities = Traits.CollectTieflingAbilities(tieflingHeritageSelection); })));

            choices.Add(Helpers.CreateFeature("ShadowStabberTrait", RES.ShadowStabberTraitName_info,
                                              RES.ShadowStabberTraitDescription_info,
                                              "b67d04e21a9147e3b8f9bd81ba36f409",
                                              Helpers.GetIcon("9f0187869dc23744292c0e5bb364464e"), // accomplished sneak attacker
                                              FeatureGroup.None,
                                              tieflingReq,
                                              Helpers.Create <DamageBonusIfInvisibleToTarget>(d => d.Bonus = 2)));

            choices.Add(UndoSelection.Feature.Value);
            raceTraits.SetFeatures(choices);
            adopted.SetFeatures(raceTraits.Features);
            adopted.AddComponent(Helpers.PrerequisiteNoFeature(raceTraits));

            return(raceTraits);
        }
示例#18
0
 static bool IsValidWeapon(BlueprintItemWeapon weapon)
 {
     return((Mod.Enabled && FixSpellstrikeWithNaturalWeapon) ? weapon.IsMelee && !weapon.IsNatural : weapon.IsMelee);
 }
示例#19
0
 public RuleCheckCombatManeuverReplaceAttack(UnitEntityData initiator, UnitEntityData target, BlueprintItemWeapon weapon) : base(initiator, target)
 {
     Result = CombatManeuver.None;
     Weapon = weapon;
 }
        private static BlueprintFeature AddSpiderCompanion()
        {
            PortraitData portraitData = new PortraitData("AdvancedMartialArtsSpider");

            BlueprintPortrait portrait = Helpers.Create <BlueprintPortrait>();

            portrait.Data = portraitData;
            Main.library.AddAsset(portrait, Helpers.getGuid("GiantSpiderPortrait"));

            BlueprintUnitFact reducedReachFact = Main.library.Get <BlueprintUnitFact>("c33f2d68d93ceee488aa4004347dffca");
            BlueprintFeature  weaponFinesse    = Main.library.Get <BlueprintFeature>("90e54424d682d104ab36436bd527af09");

            BlueprintFeature animalCompanionUpgradeCentipede = Main.library.Get <BlueprintFeature>("c938099ca0438b242b3edecfa9083e9f");
            BlueprintUnit    animalCompanionUnitCentipede    = Main.library.Get <BlueprintUnit>("f9df16ffd0c8cec4d99a0ae6f025a3f8");

            BlueprintUnit giantSpider = Main.library.CopyAndAdd <BlueprintUnit>("c4b33e5fd3d3a6f46b2aade647b0bf25", "GiantSpiderCompanion", Helpers.getGuid("GiantSpiderCompanion"));

            BlueprintItemWeapon Bite1d6         = Main.library.Get <BlueprintItemWeapon>("a000716f88c969c499a535dadcf09286");
            BlueprintItemWeapon EmptyHandWeapon = Main.library.Get <BlueprintItemWeapon>("20375b5a0c9243d45966bd72c690ab74");

            giantSpider.Brain           = animalCompanionUnitCentipede.Brain;
            giantSpider.ComponentsArray = animalCompanionUnitCentipede.ComponentsArray;
            giantSpider.Body            = animalCompanionUnitCentipede.Body;
            giantSpider.AddFacts        = giantSpider.AddFacts.AddToArray(weaponFinesse);
            giantSpider.Faction         = Main.library.Get <BlueprintFaction>("d8de50cc80eb4dc409a983991e0b77ad"); // Neutral faction

            Helpers.SetField(giantSpider, "m_Portrait", portrait);

            BlueprintUnitAsksList giantSpiderBarks = Main.library.CopyAndAdd <BlueprintUnitAsksList>("7d340f75a57c47d45b0e79200a6b5eac", "SpiderAnimalCompanionBarks", Helpers.getGuid("SpiderAnimalCompanionBarks"));
            UnitAsksComponent     component        = giantSpiderBarks.GetComponent <UnitAsksComponent>();

            foreach (var componentAnimationBark in component.AnimationBarks)
            {
                if (componentAnimationBark.AnimationEvent == MappedAnimationEventType.AlertSound1 || componentAnimationBark.AnimationEvent == MappedAnimationEventType.AlertSound2)
                {
                    componentAnimationBark.Cooldown = 10f;
                    componentAnimationBark.DelayMin = 5f;
                }
            }

            ChangeUnitSize unitSize = Helpers.Create <ChangeUnitSize>(x => x.SizeDelta = 1);

            FieldInfo typeField = unitSize.GetType().GetField("m_Type", BindingFlags.NonPublic | BindingFlags.Instance);
            object    delta     = unitSize.GetType().GetNestedType("ChangeType", BindingFlags.NonPublic).GetField("Delta").GetValue(unitSize);

            typeField.SetValue(unitSize, delta);

            AddMechanicsFeature addMechanicsFeature = Helpers.Create <AddMechanicsFeature>();

            Traverse traverse = Traverse.Create(addMechanicsFeature);

            traverse.Field("m_Feature").SetValue(AddMechanicsFeature.MechanicsFeatureType.IterativeNaturalAttacks);


            typeField.SetValue(unitSize, delta);

            BlueprintFeature animalCompanionFeatureSpider = Main.library.CopyAndAdd <BlueprintFeature>("f9ef7717531f5914a9b6ecacfad63f46", "AnimalCompanionFeatureGiantSpider", Helpers.getGuid("AnimalCompanionFeatureGiantSpider"));

            animalCompanionFeatureSpider.SetNameDescription("Animal Companion — Giant Spider", "Size Medium\nSpeed 30 ft.\nAC +1 natural armor\nAttack bite (1d6 plus poison)\nAbility Scores Str 11, Dex 17, Con 12, Int 1, Wis 10, Cha 2\nSpecial Attacks poison (frequency 1 round (4); effect 1d2 Str damage; cure 1 save; Con-based DC)\nCMD +8 vs. trip.\nAt 7th level size becomes Large, Str +2, Dex +8, Con +4, +2 natural armor.");

            AddPet addPetFact = animalCompanionFeatureSpider.ComponentsArray.OfType <AddPet>().First();

            animalCompanionFeatureSpider.RemoveComponent(addPetFact);
            addPetFact = UnityEngine.Object.Instantiate(addPetFact);
            animalCompanionFeatureSpider.AddComponent(addPetFact);

            addPetFact.Pet            = giantSpider;
            addPetFact.UpgradeFeature = Helpers.CreateFeature(
                "AnimalCompanionUpgradeGiantSpider",
                "",
                "",
                Helpers.getGuid("AnimalCompanionUpgradeGiantSpider"),
                animalCompanionUpgradeCentipede.Icon,
                FeatureGroup.None,
                unitSize,
                Helpers.Create <AddStatBonus>(x =>
            {
                x.Stat       = StatType.AC;
                x.Value      = 2;
                x.Descriptor = ModifierDescriptor.NaturalArmor;
            }),
                Helpers.Create <AddStatBonus>(x =>
            {
                x.Stat  = StatType.Strength;
                x.Value = 2;
            }),
                Helpers.Create <AddStatBonus>(x =>
            {
                x.Stat  = StatType.Dexterity;
                x.Value = 8;
            }),
                Helpers.Create <AddStatBonus>(x =>
            {
                x.Stat  = StatType.Constitution;
                x.Value = 4;
            }),
                addMechanicsFeature,
                Helpers.CreateAddFacts(reducedReachFact)
                );
            addPetFact.UpgradeLevel = 7;
            return(animalCompanionFeatureSpider);
        }
示例#21
0
        public static BlueprintFeatureSelection CreateRaceTraits(BlueprintFeatureSelection adopted)
        {
            var noFeature  = Helpers.PrerequisiteNoFeature(null);
            var raceTraits = Helpers.CreateFeatureSelection("RaceTrait", "Race Trait",
                                                            "Race traits are keyed to specific races or ethnicities, which your character must belong to in order to select the trait.",
                                                            "6264aa9515be40cda55892da93685764", null, FeatureGroup.None,
                                                            Helpers.PrerequisiteNoFeature(adopted), noFeature);

            noFeature.Feature = raceTraits;

            var humanReq = Helpers.PrerequisiteFeaturesFromList(Helpers.human, Helpers.halfElf, Helpers.halfOrc,
                                                                // Note: Aasimar/Tiefling included under the assumption they have "Scion of Humanity"/"Pass for Human"
                                                                Helpers.aasimar, Helpers.tiefling);

            var halfElfReq  = Helpers.PrerequisiteFeature(Helpers.halfElf);
            var halfOrcReq  = Helpers.PrerequisiteFeature(Helpers.halfOrc);
            var elfReq      = Helpers.PrerequisiteFeaturesFromList(Helpers.elf, Helpers.halfElf);
            var dwarfReq    = Helpers.PrerequisiteFeature(Helpers.dwarf);
            var halflingReq = Helpers.PrerequisiteFeature(Helpers.halfling);
            var gnomeReq    = Helpers.PrerequisiteFeature(Helpers.gnome);
            var aasimarReq  = Helpers.PrerequisiteFeature(Helpers.aasimar);
            var tieflingReq = Helpers.PrerequisiteFeature(Helpers.tiefling);

            // TODO: how do we code prerequisites so they aren't ignored by "Adopted"?
            // (only race prereq should be ignored, not others)
            //
            // Note: half-elf, half-orc can take traits from either race.
            // Also Aasimar/Tiefling are treated as having Scion of Humanity/Pass for Human in the game.
            var choices = new List <BlueprintFeature>();

            // Human:
            // - Carefully Hidden (+1 will save, +2 vs divination)
            // - Fanatic (Arcana)
            // - Historian (World and +1 bardic knowledge if Bard)
            // - Shield Bearer (+1 dmg shield bash)
            // - Superstitious (+1 save arcane spells)
            // - World Traveler (choose: persuasion, perception, or world)
            //e62f392949c24eb4b8fb2bc9db4345e3 // cleric orisons
            // IllusionMirrorImageAbility.62a04a20dcd3067468565f89e3d7c687/
            //TrickeryDomainBaseFeature.cd1f4a784e0820647a34fe9bd5ffa770  /// copycat
            //TrickeryDomainBaseResource.148c9ad7e47f4284b9c3686bb440c08c
            //ring of radiant arrows 3 arcane missles
            //blessed signet ring 3 times bless
            //MesmerizingNecklaceFeature.6fbea605b47e3354481683233511051b 3 times color spray
            //var copycatresource = Traits.library.Get<BlueprintAbilityResource>("148c9ad7e47f4284b9c3686bb440c08c");

            //var triflerDescription = "A childhood spent at your mystically gifted grandmother’s side has taught you the basics of real magic.";
            //var trifler = Helpers.CreateFeatureSelection("TriflerTrait", "Trifler (grandma)",
            //    triflerDescription + "\nBenefits: You may choose one of the level 1 spells and that spell you can cast 3 times per day as a spell-like ability.",
            //    "ecacfccfddfe456cafc8d60fc1db7d34",
            //    Helpers.GetIcon("3adf9274a210b164cb68f472dc1e4544"), // Human Skilled
            //    FeatureGroup.None);

            //var colorspray = Traits.library.CopyAndAdd<BlueprintFeature>(
            //    "6fbea605b47e3354481683233511051b",
            //    "TriflerTraitColorspray",
            //    "cd1f4a784e0b20647a34fe9bd5ffa7a0");
            //colorspray.SetDescription(triflerDescription + "\n Benefit: You may cast color spray 3 times per day as a spell-like ability.");
            //colorspray.SetName("Trifler color spray");

            //var colorspray = Traits.library.CopyAndAdd<BlueprintFeature>(
            //    "cd1f4a784e0820647a34fe9bd5ffa770",
            //    "TriflerTraitColorspray",
            //    "6fbea605b47e3354481683233511051b");
            //colorspray.SetDescription(triflerDescription + "\n Benefit: You may cast color spray 3 times per day as a spell-like ability.");
            //colorspray.SetName("Trifler color spray");

            //var TriflerFeatures = new List<BlueprintFeature>()
            //{
            //    colorspray
            //};

            //choices.Add(trifler);
            //choices.Add(colorspray);


            var components = new List <BlueprintComponent> {
                humanReq
            };

            components.Add(Helpers.CreateAddStatBonus(StatType.SaveWill, 1, ModifierDescriptor.Trait));
            components.Add(Helpers.Create <SavingThrowBonusAgainstSchool>(a =>
            {
                a.School             = SpellSchool.Divination;
                a.Value              = 2;
                a.ModifierDescriptor = ModifierDescriptor.Trait;
            }));
            choices.Add(Helpers.CreateFeature("CarefullyHiddenTrait", "Carefully Hidden (Human)",
                                              "Your life as a member of an unpopular ethnic group has given you an uncanny knack for avoiding detection.\nBenefit: You gain a +1 trait bonus to Will saves and a +2 trait bonus to saving throws versus divination effects.",
                                              "38b92d2ebb4c4cdb8e946e29f5b2f178",
                                              Helpers.GetIcon("175d1577bb6c9a04baf88eec99c66334"), // Iron Will
                                              FeatureGroup.None,
                                              components.ToArray()));
            choices.Add(Traits.CreateAddStatBonus("FanaticTrait", "Fanatic (Human)",
                                                  "Your years spent in libraries reading every musty tome you could find about ancient lost civilizations has given you insight into the subjects of history and the arcane.",
                                                  "6427e81ba399406c93b463c284a42055",
                                                  StatType.SkillKnowledgeArcana,
                                                  humanReq));

            var bardicKnowledge = Traits.library.Get <BlueprintFeature>("65cff8410a336654486c98fd3bacd8c5");

            components.Clear();
            components.Add(humanReq);
            components.AddRange((new StatType[] {
                StatType.SkillKnowledgeArcana,
                StatType.SkillKnowledgeWorld,
                StatType.SkillLoreNature,
                StatType.SkillLoreReligion,
            }).Select((skill) => Helpers.Create <AddStatBonusIfHasFact>(a =>
            {
                a.Stat        = skill;
                a.Value       = 1;
                a.CheckedFact = bardicKnowledge;
                a.Descriptor  = ModifierDescriptor.UntypedStackable;
            })));

            var historian = Traits.CreateAddStatBonus("HistorianTrait", "Historian (Human)",
                                                      "Your parents were scholars of history, whether genealogists of your own family tree, sages on the subject of ancient empires, or simply hobbyists with a deep and abiding love for the past.\nBenefits: You gain a +1 trait bonus on Knowledge (history) checks and bardic knowledge checks, and Knowledge (history) is always a class skill for you.",
                                                      "4af3871899e4440bae03d4c33d4b52fd",
                                                      StatType.SkillKnowledgeWorld,
                                                      components.ToArray());

            choices.Add(historian);

            components.Clear();
            components.Add(humanReq);
            components.AddRange(new String[] {
                "98a0dc03586a6d04791901c41700e516", // SpikedLightShield
                "1fd965e522502fe479fdd423cca07684", // WeaponLightShield
                "a1b85d048fb5003438f34356df938a9f", // SpikedHeavyShield
                "be9b6408e6101cb4997a8996484baf19"  // WeaponHeavyShield
            }.Select(id => Helpers.Create <WeaponTypeDamageBonus>(w => { w.DamageBonus = 1; w.WeaponType = Traits.library.Get <BlueprintWeaponType>(id); })));

            choices.Add(Helpers.CreateFeature("ShieldBearerTrait", "Shield Bearer (Human)",
                                              "You have survived many battles thanks to your skill with your shield.\nBenefit: When performing a shield bash, you deal 1 additional point of damage.",
                                              "044ebbbadfba4d58afa11bfbf38df199",
                                              Helpers.GetIcon("121811173a614534e8720d7550aae253"), // Shield Bash
                                              FeatureGroup.None,
                                              components.ToArray()));

            choices.Add(Helpers.CreateFeature("SuperstitiousTrait", "Superstitious (Human)",
                                              "You have a healthy fear of sorcerers’ speech and wizards’ words that has helped you to survive their charms.\nBenefit: You gain a +1 trait bonus on saving throws against arcane spells.",
                                              "f5d79e5fbb87473ca0b13ed15b742079",
                                              Helpers.GetIcon("2483a523984f44944a7cf157b21bf79c"), // Elven Immunities
                                              FeatureGroup.None,
                                              humanReq,
                                              Helpers.Create <SavingThrowBonusAgainstSpellSource>()));

            var travelerDescription = "Your family has taken the love of travel to an extreme, roaming the world extensively. You’ve seen dozens of cultures and have learned to appreciate the diversity of what the world has to offer.";
            var worldTraveler       = Helpers.CreateFeatureSelection("WorldTravelerTrait", "World Traveler (Human)",
                                                                     travelerDescription + "\nBenefits: Select one of the following skills: Persuasion, Knowledge (world), or Perception. You gain a +1 trait bonus on checks with that skill, and it is always a class skill for you.",
                                                                     "ecacfcbeddfe453cafc8d60fc1db7d34",
                                                                     Helpers.GetIcon("3adf9274a210b164cb68f472dc1e4544"), // Human Skilled
                                                                     FeatureGroup.None,
                                                                     humanReq);

            var travelerFeats = new StatType[] {
                StatType.SkillPersuasion,
                StatType.SkillKnowledgeWorld,
                StatType.SkillPerception
            }.Select(skill => Traits.CreateAddStatBonus(
                         $"WorldTraveler{skill}Trait",
                         $"World Traveler — {UIUtility.GetStatText(skill)}",
                         travelerDescription,
                         Helpers.MergeIds(Helpers.GetSkillFocus(skill).AssetGuid, "9b03b7ff17394007a3fbec18aa42604b"),
                         skill)).ToArray();

            worldTraveler.SetFeatures(travelerFeats);
            choices.Add(worldTraveler);

            // Elf:
            // - Dilettante Artist (persuasion)
            // - Forlorn (+1 fort save)
            // - Warrior of the Old (+2 init)
            // - Youthful Mischief (+1 ref)
            choices.Add(Traits.CreateAddStatBonus("DilettanteArtistTrait", "Dilettante Artist (Elf)",
                                                  "Art for you is a social gateway and you use it to influence and penetrate high society.",
                                                  "ac5a16e72ef74b4884c674dcbb61692c", StatType.SkillPersuasion, elfReq));

            BlueprintItemWeapon bite = Traits.library.CopyAndAdd <BlueprintItemWeapon>("35dfad6517f401145af54111be04d6cf", "Tusked",
                                                                                       "44dfad6517f401145af54111be04d644");



            choices.Add(Helpers.CreateFeature("ForlornTrait", "Forlorn (Elf)",
                                              "Having lived outside of traditional elf society for much or all of your life, you know the world can be cruel, dangerous, and unforgiving of the weak.\nBenefit: You gain a +1 trait bonus on Fortitude saving throws.",
                                              "1511289c92ea4233b14c4f51072ea10f",
                                              Helpers.GetIcon("79042cb55f030614ea29956177977c52"), // Great Fortitude
                                              FeatureGroup.None,
                                              elfReq,
                                              Helpers.CreateAddStatBonus(StatType.SaveFortitude, 1, ModifierDescriptor.Trait)
                                              ));

            choices.Add(Helpers.CreateFeature("TuskedTrait", "Tusked (Half-orc)",
                                              "Benefit: Huge, sharp tusks bulge from your mouth, and you receive a bite attack (1d4 damage for Medium characters). If used as part of a full attack action, the bite attack is made at your full base attack bonus –5.",
                                              "1511289c92ea4233b14c4f51072ea09g",
                                              Image2Sprite.Create("Mods/EldritchArcana/sprites/halforc_tusked.png"), // Great Fortitude
                                              FeatureGroup.None,
                                              halfOrcReq,
                                              Helpers.Create <AddAdditionalLimb>(x => x.Weapon = bite)
                                              ));

            choices.Add(Helpers.CreateFeature("WarriorOfOldTrait", "Warrior of Old (Elf)",
                                              "As a child, you put in long hours on combat drills, and though time has made this training a dim memory, you still have a knack for quickly responding to trouble.\nBenefit: You gain a +2 trait bonus on initiative checks.",
                                              "dc36a2c52abb4e6dbff549ac65a5a171",
                                              Helpers.GetIcon("797f25d709f559546b29e7bcb181cc74"), // Improved Initiative
                                              FeatureGroup.None,
                                              elfReq,
                                              Helpers.CreateAddStatBonus(StatType.Initiative, 2, ModifierDescriptor.Trait)));

            choices.Add(Helpers.CreateFeature("YouthfulMischiefTrait", "Youthful Mischeif (Elf)",
                                              "Though you gave up the life of a padfoot, scout, or minstrel decades before, you still know how to roll with the punches when things turn sour.\nBenefit: You gain a +1 trait bonus on Reflex saves.",
                                              "bfcc574d1f214455ac369fa46e07200e",
                                              Helpers.GetIcon("15e7da6645a7f3d41bdad7c8c4b9de1e"), // Lightning Reflexes
                                              FeatureGroup.None,
                                              elfReq,
                                              Helpers.CreateAddStatBonus(StatType.SaveReflex, 1, ModifierDescriptor.Trait)));

            // Half-orc:
            // - Brute (persuasion)
            // - Legacy of Sand (+1 will save)
            var brute = Traits.CreateAddStatBonus("BruteTrait", "Brute (Half-Orc)",
                                                  "You have worked for a crime lord, either as a low-level enforcer or as a guard, and are adept at frightening away people.",
                                                  "1ee0ce55ace74ccbb798e2fdc13181f6", StatType.SkillPersuasion, halfOrcReq);

            brute.SetIcon(Helpers.GetIcon("885f478dff2e39442a0f64ceea6339c9")); // Intimidating
            choices.Add(brute);

            var GloryOfOld = Helpers.CreateFeature("GloryOfOldTrait", "Glory of old",
                                                   "You are part of the old Guard" +
                                                   "\nYou belong to the elite veteran regiments of The old king and his army and are intensely loyal to him. It was you who made the last charge at the dwarven kingdom." +
                                                   "Benefit: You receive a +1 trait bonus on saving throws against spells, spell-like abilities, and poison",
                                                   "4283a523984f44944a7cf157b21bf7c9",
                                                   Image2Sprite.Create("Mods/EldritchArcana/sprites/spell_perfection.png"),
                                                   FeatureGroup.None,
                                                   dwarfReq,
                                                   Helpers.Create <SavingThrowBonusAgainstDescriptor>(s => { s.SpellDescriptor = SpellDescriptor.Poison; s.Value = 1; s.ModifierDescriptor = ModifierDescriptor.Racial; }),
                                                   Helpers.Create <SavingThrowBonusAgainstDescriptor>(s => { s.SpellDescriptor = SpellDescriptor.BreathWeapon; s.Value = 1; s.ModifierDescriptor = ModifierDescriptor.Trait; }));

            components.Clear();
            components.AddRange((new SpellSchool[]
            {
                SpellSchool.Abjuration,
                SpellSchool.Conjuration,
                SpellSchool.Divination,
                SpellSchool.Enchantment,
                SpellSchool.Evocation,
                SpellSchool.Illusion,
                SpellSchool.Necromancy,
                SpellSchool.Transmutation,
                SpellSchool.Universalist
            }).Select((school) => Helpers.Create <SavingThrowBonusAgainstSchool>(a =>
            {
                a.School             = school;
                a.Value              = 1;
                a.ModifierDescriptor = ModifierDescriptor.Racial;
            })));

            GloryOfOld.AddComponents(components);

            choices.Add(GloryOfOld);



            choices.Add(Helpers.CreateFeature("LegacyOfSandTrait", "Legacy of Sand (Half-Orc)",
                                              "A large tribe of orcs adapted to life in the desert once dwelt in southeastern Katapesh. Although this tribe is long extinct, some half-orcs of Katapesh carry the traits of this tribe in their particularly large jaws, broad shoulders, and shockingly pale eyes. You often have dreams of hunts and strange ceremonies held under moonlight in the desert sands. Some ascribe these dreams to racial memory, others to visions or prophecies. These dreams have instilled in you a fierce sense of tradition.\nBenefit: You gain a +1 trait bonus on all Will saving throws.",
                                              "e5fb1675eb6e4ef9accef7eb3a10862a",
                                              Image2Sprite.Create("Mods/EldritchArcana/sprites/halforc_legacy_of_sand.png"),
                                              FeatureGroup.None,
                                              halfOrcReq,
                                              Helpers.CreateAddStatBonus(StatType.SaveWill, 1, ModifierDescriptor.Trait)));

            // Half-elf:
            // - Elven Relexes (+2 initiative)
            // - Failed Apprentice (+1 save arcane spells)
            choices.Add(Helpers.CreateFeature("ElvenReflexsTrait", "Elven Reflexes (Half-Elf)",
                                              "One of your parents was a member of a wild elven tribe, and you’ve inherited a portion of your elven parent’s quick reflexes.\nBenefit: You gain a +2 trait bonus on initiative checks.",
                                              "9975678ce2fc420da9cd6ec4fe8c8b9b",
                                              Helpers.GetIcon("797f25d709f559546b29e7bcb181cc74"), // Improved Initiative
                                              FeatureGroup.None,
                                              halfElfReq,
                                              Helpers.CreateAddStatBonus(StatType.Initiative, 2, ModifierDescriptor.Trait)));

            choices.Add(Helpers.CreateFeature("FailedAprenticeTrait", "Failed Apprentice (Half-Elf)",
                                              "You have a healthy fear of sorcerers’ speech and wizards’ words that has helped you to survivAs a child, your parents sent you to a distant wizard’s tower as an apprentice so that you could learn the arcane arts. Unfortunately, you had no arcane talent whatsoever, though you did learn a great deal about the workings of spells and how to resist them.\nBenefit: You gain a +1 trait bonus on saves against arcane spells.",
                                              "8ed66066751f43c2920055dd6358adc8",
                                              Helpers.GetIcon("2483a523984f44944a7cf157b21bf79c"), // Elven Immunities
                                              FeatureGroup.None,
                                              halfElfReq,
                                              Helpers.Create <SavingThrowBonusAgainstSpellSource>()));

            // Halfling:
            // - Freed Slave (world)
            // - Freedom Fighter (mobility)
            // - Well-Informed (persuasion)
            choices.Add(Traits.CreateAddStatBonus("FreedSlaveTrait", "Freed Slave (Halfling)",
                                                  "You grew up as a slave and know the ins and outs of nobility better than most.",
                                                  "d2fc5fe0c64142a79e0ebee18f14b0be", StatType.SkillKnowledgeWorld, halflingReq));
            choices.Add(Traits.CreateAddStatBonus("FreedomFighterTrait", "Freedom Fighter (Halfling)",
                                                  "Your parents allowed escaping slaves to hide in your home, and the stories you’ve heard from them instilled into you a deep loathing of slavery, and a desire to help slaves evade capture and escape.",
                                                  "3a4d2cd14dc446319085c865570ccc3d", StatType.SkillMobility, halflingReq));
            choices.Add(Traits.CreateAddStatBonus("WellInformedTrait", "Well-Informed (Halfling)",
                                                  "You make it a point to know everyone and to be connected to everything around you. You frequent the best taverns, attend all of the right events, and graciously help anyone who needs it.",
                                                  "940ced5d41594b9aa22ee22217fbd46f", StatType.SkillPersuasion, halflingReq));

            // Dwarf:
            // - Grounded (+2 mobility, +1 reflex)
            // - Militant Merchant (perception)Owner.HPLeft
            // - Ruthless (+1 confirm crits)
            // - Zest for Battle (+1 trait dmg if has morale attack bonus)
            choices.Add(Helpers.CreateFeature("GroundedTrait", "Grounded (Dwarf)",
                                              "You are well balanced, both physically and mentally.\nBenefit: You gain a +2 trait bonus on Mobility checks, and a +1 trait bonus on Reflex saves.",
                                              "9b13923527a64c3bbf8de904c5a9ef8b",
                                              Helpers.GetIcon("3a8d34905eae4a74892aae37df3352b9"), // Skill Focus Stealth (mobility)
                                              FeatureGroup.None,
                                              dwarfReq,
                                              Helpers.CreateAddStatBonus(StatType.SkillMobility, 2, ModifierDescriptor.Racial),
                                              Helpers.CreateAddStatBonus(StatType.SaveReflex, 1, ModifierDescriptor.Racial)));

            choices.Add(Traits.CreateAddStatBonus("MilitantMerchantTrait", "Militant Merchant (Dwarf)",
                                                  "You know what it takes to get your goods to market and will stop at nothing to protect your products. Years of fending off thieves, cutthroats, and brigands have given you a sixth sense when it comes to danger.",
                                                  "38226f4ad9ed4211878ef95497d01857", StatType.SkillPerception, dwarfReq));

            choices.Add(Helpers.CreateFeature("RuthlessTrait", "Ruthless (Dwarf)",
                                              "You never hesitate to strike a killing blow.\nBenefit: You gain a +1 trait bonus on attack rolls to confirm critical hits.",
                                              "58d18289cb7f4ad4a690d9502d397a3a",
                                              Helpers.GetIcon("f4201c85a991369408740c6888362e20"), // Improved Critical
                                              FeatureGroup.None,
                                              dwarfReq,
                                              Helpers.Create <CriticalConfirmationBonus>(a => { a.Bonus = 1; a.Value = 0; })));


            var Frostborn = Helpers.CreateFeature("FrostbornTrait", "Frostborn (Dwarf)",
                                                  "You were raised in the icy tundra\nBenefit:Benefit: You gain a +4 trait bonus to resist the effects of cold environments, as well as a +1 trait bonus on all saving throws against cold effects.",
                                                  "f987f5e69db44cdd99983985e37a6c3c",
                                                  Helpers.GetIcon("121811173a614534e8720d7550aae253"), // Weapon Specialization
                                                  FeatureGroup.None,
                                                  dwarfReq);

            Frostborn.AddComponent(Helpers.Create <AddDamageResistanceEnergy>(r => { r.Type = Kingmaker.Enums.Damage.DamageEnergyType.Cold; r.Value = 4; }));
            Frostborn.AddComponent(Helpers.Create <SavingThrowBonusAgainstDescriptor>(s => { s.SpellDescriptor = SpellDescriptor.Cold; s.ModifierDescriptor = ModifierDescriptor.Racial; s.Bonus = 1; }));
            choices.Add(Frostborn);

            choices.Add(Helpers.CreateFeature("ZestForBattleTrait", "Zest for Battle (Dwarf)",
                                              "Your greatest joy is being in the thick of battle, and smiting your enemies for a righteous or even dastardly cause.\nBenefit: Whenever you have a morale bonus to weapon attack rolls, you also receive a +1 trait bonus on weapon damage rolls.",
                                              "a987f5e69db44cdd98983985e37a6c2a",
                                              Helpers.GetIcon("31470b17e8446ae4ea0dacd6c5817d86"), // Weapon Specialization
                                              FeatureGroup.None,
                                              dwarfReq,
                                              Helpers.Create <DamageBonusIfMoraleBonus>()));

            // Gnome:
            // - Animal Friend (+1 will save and lore nature class skill, must have familar or animal companion)
            // - Rapscallion (+1 init, +1 thievery)
            components.Clear();
            components.Add(gnomeReq);
            components.Add(Helpers.Create <AddClassSkill>(a => a.Skill = StatType.SkillLoreNature));
            // TODO: is there a cleaner way to implement this rather than a hard coded list?
            // (Ideally: it should work if a party NPC has a familiar/animal companion too.)
            // See also: PrerequisitePet.
            components.AddRange((new String[] {
                // Animal companions
                "f6f1cdcc404f10c4493dc1e51208fd6f",
                "afb817d80b843cc4fa7b12289e6ebe3d",
                "f9ef7717531f5914a9b6ecacfad63f46",
                "f894e003d31461f48a02f5caec4e3359",
                "e992949eba096644784592dc7f51a5c7",
                "aa92fea676be33d4dafd176d699d7996",
                "2ee2ba60850dd064e8b98bf5c2c946ba",
                "6adc3aab7cde56b40aa189a797254271",
                "ece6bde3dfc76ba4791376428e70621a",
                "126712ef923ab204983d6f107629c895",
                "67a9dc42b15d0954ca4689b13e8dedea",
                // Familiars
                "1cb0b559ca2e31e4d9dc65de012fa82f",
                "791d888c3f87da042a0a4d0f5c43641c",
                "1bbca102706408b4cb97281c984be5d5",
                "f111037444d5b6243bbbeb7fc9056ed3",
                "7ba93e2b888a3bd4ba5795ae001049f8",
                "97dff21a036e80948b07097ad3df2b30",
                "952f342f26e2a27468a7826da426f3e7",
                "61aeb92c176193e48b0c9c50294ab290",
                "5551dd90b1480e84a9caf4c5fd5adf65",
                "adf124729a6e01f4aaf746abbed9901d",
                "4d48365690ea9a746a74d19c31562788",
                "689b16790354c4c4c9b0f671f68d85fc",
                "3c0b706c526e0654b8af90ded235a089",
            }).Select(id => Helpers.Create <AddStatBonusIfHasFact>(a =>
            {
                a.Stat        = StatType.SaveWill;
                a.Value       = 1;
                a.Descriptor  = ModifierDescriptor.Trait;
                a.CheckedFact = Traits.library.Get <BlueprintFeature>(id);
            })));

            choices.Add(Helpers.CreateFeature("AnimalFriendTrait", "Animal Friend (Gnome)",
                                              "You’ve long been a friend to animals, and feel safer when animals are nearby.\nBenefits: You gain a +1 trait bonus on Will saving throws as long as you have an animal companion or familiar, and Lore (Nature) is always a class skill for you.",
                                              "91c612b225d54adaa4ce4c633501b58e",
                                              Image2Sprite.Create("Mods/EldritchArcana/sprites/gnome_animal_friend.png"),//Helpers.GetIcon("1670990255e4fe948a863bafd5dbda5d"), // Boon Companion
                                              FeatureGroup.None,
                                              components.ToArray()));

            choices.Add(Helpers.CreateFeature("Rapscallion", "Rapscallion (Gnome)",
                                              "You’ve spent your entire life thumbing your nose at the establishment and take pride in your run-ins with the law. Somehow, despite all your mischievous behavior, you’ve never been caught.\nBenefits: You gain a +1 trait bonus on Mobility checks and a +1 trait bonus on initiative checks.",
                                              "4f95abdcc70e4bda818be5b8860585c5",
                                              Helpers.GetSkillFocus(StatType.SkillMobility).Icon,
                                              FeatureGroup.None,
                                              gnomeReq,
                                              Helpers.CreateAddStatBonus(StatType.SkillMobility, 1, ModifierDescriptor.Trait),
                                              Helpers.CreateAddStatBonus(StatType.Initiative, 1, ModifierDescriptor.Trait)));

            // Aasimar:
            // - Martyr’s Blood (+1 attack if HP below half).
            // - Toxophilite (+2 crit confirm with bows)
            // - Wary (+1 perception/persuasion)

            // TODO: Enlightened Warrior

            choices.Add(Helpers.CreateFeature("MartyrsBloodTrait", "Martyr’s Blood (Aasimar)",
                                              "You carry the blood of a self-sacrificing celestial, and strive to live up to your potential for heroism.\nBenefit(s): As long as your current hit point total is less than half of your maximum hit points possible, you gain a +1 trait bonus on attack rolls against evil foes.",
                                              "729d27ad020d485f843264844f0f2155",
                                              Helpers.GetIcon("3ea2215150a1c8a4a9bfed9d9023903e"), // Iron Will Improved
                                              FeatureGroup.None,
                                              aasimarReq,
                                              Helpers.Create <AttackBonusIfAlignmentAndHealth>(a =>
            {
                a.TargetAlignment = AlignmentComponent.Evil;
                a.Descriptor      = ModifierDescriptor.Trait;
                a.Value           = 1;
                a.HitPointPercent = 0.5f;
            })));

            choices.Add(Helpers.CreateFeature("ToxophiliteTrait", "Toxophilite (Aasimar)",
                                              "You’ve inherited some of your celestial ancestor’s prowess with the bow.\nBenefit: You gain a +2 trait bonus on attack rolls made to confirm critical hits with bows.",
                                              "6c434f07c8984971b1d842cecdf144c6",
                                              Helpers.GetIcon("f4201c85a991369408740c6888362e20"), // Improved Critical
                                              FeatureGroup.None,
                                              aasimarReq,
                                              Helpers.Create <CriticalConfirmationBonus>(a =>
            {
                a.Bonus = 2;
                a.Value = 0;
                a.CheckWeaponRangeType = true;
                a.Type = AttackTypeAttackBonus.WeaponRangeType.RangedNormal;
            })));

            choices.Add(Helpers.CreateFeature("WaryTrait", "Wary (Aasimar)",
                                              "You grew up around people who were jealous of and hostile toward you. Perhaps your parents were not pleased to have a child touched by the divine—they may have berated or beaten you, or even sold you into slavery for an exorbitant price. You grew up mistrustful of others and believing your unique appearance to be a curse.\nBenefit: You gain a +1 trait bonus on Persuasion and Perception checks.",
                                              "7a72a0e956784cc38ea049e503189810",
                                              Helpers.GetIcon("86d93a5891d299d4983bdc6ef3987afd"), // Persuasive
                                              FeatureGroup.None,
                                              aasimarReq,
                                              Helpers.CreateAddStatBonus(StatType.SkillPersuasion, 1, ModifierDescriptor.Trait),
                                              Helpers.CreateAddStatBonus(StatType.SkillPerception, 1, ModifierDescriptor.Trait)));

            // Tiefling:
            // - Ever Wary (retain half dex bonus AC during surpise round)
            // - Prolong Magic (racial spell-like abilities get free extend spell)
            // - God Scorn (Demodand heritage; +1 saves vs divine spells)
            // - Shadow Stabber (+2 damage if opponent can't see you)

            choices.Add(Helpers.CreateFeature("EverWaryTrait", "Ever wary (Tiefling)",
                                              "Constant fear that your fiendish nature might provoke a sudden attack ensures that you never completely let down your guard.\nBenefit During the surprise round and before your first action in combat, you can apply half your Dexterity bonus (if any) to your AC. You still count as flat-footed for the purposes of attacks and effects.",
                                              "0400c9c99e704a1f81a769aa88044a03",
                                              Helpers.GetIcon("3c08d842e802c3e4eb19d15496145709"), // uncanny dodge
                                              FeatureGroup.None,
                                              tieflingReq,
                                              Helpers.Create <ACBonusDuringSurpriseRound>()));

            var tieflingHeritageDemodand = Traits.library.Get <BlueprintFeature>("a53d760a364cd90429e16aa1e7048d0a");

            choices.Add(Helpers.CreateFeature("GodScornTrait", "God Scorn (Demodand Tiefling)",
                                              "Your contempt for the gods and their sad little priests makes it easier to shake off the effects of their prayers.\nBenefit You gain a +1 trait bonus on saving throws against divine spells.",
                                              "db41263f6fd3450ea0a3bc45c98330f7",
                                              Helpers.GetIcon("2483a523984f44944a7cf157b21bf79c"), // Elven Immunities
                                              FeatureGroup.None,
                                              Helpers.PrerequisiteFeature(tieflingHeritageDemodand),
                                              Helpers.Create <SavingThrowBonusAgainstSpellSource>(s => s.Source = SpellSource.Divine)));

            var tieflingHeritageSelection = Traits.library.Get <BlueprintFeatureSelection>("c862fd0e4046d2d4d9702dd60474a181");

            choices.Add(Helpers.CreateFeature("ProlongMagicTrait", "Prolong Magic (Tiefling)",
                                              "Constant drills and preparation allow you to get more out of your innate magic.\nBenefit Whenever you use a spell - like ability gained through your tiefling heritage, it automatically acts as if affected by the Extend Spell metamagic feat.",
                                              "820f697f59114993a55c46044c98bf9c",
                                              tieflingHeritageSelection.Icon,
                                              FeatureGroup.None,
                                              tieflingReq,
                                              // TODO: double check that this actually works for SLAs.
                                              Helpers.Create <AutoMetamagic>(a => { a.Metamagic = Metamagic.Extend; a.Abilities = Traits.CollectTieflingAbilities(tieflingHeritageSelection); })));

            choices.Add(Helpers.CreateFeature("ShadowStabberTrait", "Shadow Stabber (Tiefling)",
                                              "An instinct for dishonorable conduct serves you well when fighting opponents who are blind, oblivious, or blundering around in the dark.\nBenefit You gain a +2 trait bonus on melee weapon damage rolls made against foes that cannot see you.",
                                              "b67d04e21a9147e3b8f9bd81ba36f409",
                                              Helpers.GetIcon("9f0187869dc23744292c0e5bb364464e"), // accomplished sneak attacker
                                              FeatureGroup.None,
                                              tieflingReq,
                                              Helpers.Create <DamageBonusIfInvisibleToTarget>(d => d.Bonus = 2)));

            choices.Add(UndoSelection.Feature.Value);
            raceTraits.SetFeatures(choices);
            adopted.SetFeatures(raceTraits.Features);
            adopted.AddComponent(Helpers.PrerequisiteNoFeature(raceTraits));

            return(raceTraits);
        }