// known issues: // - composite blasts consisting of two elements (ice) count as two attacks and will roll concealment/mirror-image individually. also true for crit and crit confirm // - "Miss" text doesn't show, if attack roll on consecutive hits was too high compared to initial roll // - "Miss" text shows up, if attack roll on consecutive hits was too low compared to initial roll // ! found "RuleAttackRoll ruleAttackRoll = Rulebook.CurrentContext.LastEvent<RuleAttackRoll>();" which might be useful for improvement! static public void createImpaleInfusion() { var earth_blast = library.Get <BlueprintFeature>("7f5f82c1108b961459c9884a0fa0f5c4"); //EarthBlastFeature var earth_blast_ab = library.Get <BlueprintAbility>("b28c336c10eb51c4a8ded0258d5742e1"); //EarthBlastAbility var metal_blast = library.Get <BlueprintFeature>("ad20bc4e586278c4996d4a81b2448998"); //MetalBlastFeature var metal_blast_ab = library.Get <BlueprintAbility>("665cfd3718c4f284d80538d85a2791c9"); //MetalBlastAbility var ice_blast = library.Get <BlueprintFeature>("a8cc34ca1a5e55a4e8aa5394efe2678e"); //IceBlastFeature var ice_blast_ab = library.Get <BlueprintAbility>("519e36decde7c964d87c2ffe4d3d8459"); //IceBlastAbility var icon = library.Get <BlueprintFeature>("2aad85320d0751340a0786de073ee3d5").Icon; //TorrentInfusionFeature // create new impale feature // - add to selection of infusions infusion_impale_feature = Helpers.CreateFeature( "InfusionImpaleFeature", "Impale", "Element: earth\nType: form infusion\nLevel: 3\nBurn: 2\nAssociated Blasts: earth, metal, ice\n" + "You extend a long, sharp spike of elemental matter along a line, impaling multiple foes. Make a single attack roll against each creature or object in a 30-foot line.", "f942f82c01c34c7da5f1131f5484e8b4", icon, FeatureGroup.KineticBlastInfusion, Helpers.PrerequisiteFeaturesFromList(new BlueprintFeature[] { earth_blast, metal_blast, ice_blast }, true), Helpers.PrerequisiteClassLevel(kineticist_class, 6), Helpers.PrerequisiteFeature(elemental_focus) ); infusion_impale_feature.IsClassFeature = true; Helper.AppendAndReplace(ref infusion_selection.AllFeatures, infusion_impale_feature); #region create impale ability - earth // - clone from water torrent // - replace EffectRunAction to a custom one: damage as usual for kineticist, only piercing, no saving throw, must roll attack, can crit // - replace projectile to what we want // - replace AbilityKineticist to fix CachedDamageInfo // - replace spawnFx // - replace requirement to need the impale feature // - add as variant to parent blast var earth_impale_ability = library.CopyAndAdd <BlueprintAbility>("93cc42235edc6824fa7d54b83ed4e1fe", "EarthImpaleAbility", "adcf52d3bc874d9a94250053b7ebf6e4"); // TorrentWaterBlastAbility earth_impale_ability.SetNameDescriptionIcon(infusion_impale_feature); earth_impale_ability.LocalizedSavingThrow = Helpers.savingThrowNone; earth_impale_ability.Parent = earth_base; //var damage_roll = Helpers.CreateActionDealDamage(PhysicalDamageForm.Piercing, damage_dice, isAoE: false, halfIfSaved: false, IgnoreCritical: false); var earth_damage_roll = NewComponents.ContextActionDealDamage2.CreateNew(PhysicalDamageForm.Piercing, physical_dice, isAoE: true, halfIfSaved: false, IgnoreCritical: false); earth_damage_roll.Half = false; earth_damage_roll.WeaponOverride = new ItemEntityWeapon(weapon_blast_physical); var earth_actions = Helper.CreateAbilityEffectRunAction(0, earth_damage_roll); earth_impale_ability.ReplaceComponent <AbilityEffectRunAction>(earth_actions); earth_impale_ability.ReplaceComponent <AbilityDeliverProjectile>(a => { a.Type = AbilityProjectileType.Line; a.Length = new Feet(30f); a.LineWidth = new Feet(5f); a.NeedAttackRoll = true; a.Weapon = weapon_blast_physical; a.Projectiles = library.Get <BlueprintProjectile>("5d66a6c3cac5124469b2d0474e53ecab").ToArray(); // Kinetic_EarthBlastLine00: 5d66a6c3cac5124469b2d0474e53ecab }); earth_impale_ability.ReplaceComponent <AbilityKineticist>(a => { a.InfusionBurnCost = 2; a.BlastBurnCost = 0; a.Amount = 1; a.CachedDamageInfo = earth_blast_ab.GetComponent <AbilityKineticist>().CachedDamageInfo; }); //earth_impale_ability.RemoveComponents<SpellDescriptorComponent>(); earth_impale_ability.RemoveComponents <AbilitySpawnFx>(); earth_impale_ability.AddComponents(earth_blast_ab.GetComponents <AbilitySpawnFx>()); earth_impale_ability.ReplaceComponent <AbilityCasterHasFacts>(a => a.Facts = infusion_impale_feature.ToArray()); earth_impale_ability.ReplaceComponent <AbilityShowIfCasterHasFact>(a => a.UnitFact = infusion_impale_feature); #endregion #region create impale ability - metal var metal_impale_ability = library.CopyAndAdd <BlueprintAbility>("82db79a0b4e91dc4ea2938192e6fc7af", "MetalImpaleAbility", "c25c7c8f05284317984ddcbcba69f53c"); //TorrentSandstormBlastAbility metal_impale_ability.SetNameDescriptionIcon(infusion_impale_feature); metal_impale_ability.LocalizedSavingThrow = Helpers.savingThrowNone; metal_impale_ability.Parent = metal_base; metal_impale_ability.ReplaceComponent <AbilityEffectRunAction>(earth_actions); //this can be reused, because both deal full physical damage // AbilityDeliverProjectile can be kept, because the fx and form/range is the same as sandstorm-torrent metal_impale_ability.ReplaceComponent <AbilityKineticist>(a => { a.InfusionBurnCost = 2; a.BlastBurnCost = 2; a.Amount = 1; a.CachedDamageInfo = metal_blast_ab.GetComponent <AbilityKineticist>().CachedDamageInfo; }); // AbilitySpawnFx can be kept metal_impale_ability.ReplaceComponent <AbilityCasterHasFacts>(a => a.Facts = infusion_impale_feature.ToArray()); metal_impale_ability.ReplaceComponent <AbilityShowIfCasterHasFact>(a => a.UnitFact = infusion_impale_feature); #endregion #region create impale ability - ice var ice_impale_ability = library.CopyAndAdd <BlueprintAbility>("d02fba9ae78f12642b4111a4bbbdc023", "IceImpaleAbility", "50486077f898441dba7c2922a3d251ed"); //TorrentBlizzardBlastAbility ice_impale_ability.SetNameDescriptionIcon(infusion_impale_feature); ice_impale_ability.LocalizedSavingThrow = Helpers.savingThrowNone; ice_impale_ability.Parent = ice_base; //var damage_roll = Helpers.CreateActionDealDamage(PhysicalDamageForm.Piercing, damage_dice, isAoE: false, halfIfSaved: false, IgnoreCritical: false); var ice_damage_roll = NewComponents.ContextActionDealDamage2.CreateNew(PhysicalDamageForm.Piercing, physical_dice, isAoE: true, halfIfSaved: false, IgnoreCritical: false); ice_damage_roll.Half = false; ice_damage_roll.WeaponOverride = new ItemEntityWeapon(weapon_blast_physical); var ice_damage_roll2 = NewComponents.ContextActionDealDamage2.CreateNew(DamageEnergyType.Cold, physical_dice, isAoE: true, halfIfSaved: false, IgnoreCritical: false); ice_damage_roll2.Half = false; ice_damage_roll2.WeaponOverride = new ItemEntityWeapon(weapon_blast_physical); //this is correct, because the bonus damage is the same as physical //ice_damage_roll2.ReadPreRolledFromSharedValue = true; //ice_damage_roll2.PreRolledSharedValue = AbilitySharedValue.Duration; ice_impale_ability.ReplaceComponent <AbilityEffectRunAction>(Helper.CreateAbilityEffectRunAction(0, ice_damage_roll, ice_damage_roll2)); // AbilityDeliverProjectile can be kept, because the fx and form/range is the same as blizzard-torrent ice_impale_ability.ReplaceComponent <AbilityKineticist>(a => { a.InfusionBurnCost = 2; a.BlastBurnCost = 2; a.Amount = 1; a.CachedDamageInfo = ice_blast_ab.GetComponent <AbilityKineticist>().CachedDamageInfo; }); // AbilitySpawnFx can be kept ice_impale_ability.ReplaceComponent <AbilityCasterHasFacts>(a => a.Facts = infusion_impale_feature.ToArray()); ice_impale_ability.ReplaceComponent <AbilityShowIfCasterHasFact>(a => a.UnitFact = infusion_impale_feature); #endregion Helper.AppendAndReplace(ref earth_base.GetComponent <AbilityVariants>().Variants, earth_impale_ability); Helper.AppendAndReplace(ref metal_base.GetComponent <AbilityVariants>().Variants, metal_impale_ability); Helper.AppendAndReplace(ref ice_base.GetComponent <AbilityVariants>().Variants, ice_impale_ability); }