Download as pdf or txt
Download as pdf or txt
You are on page 1of 54

1 using System;

2 using System.Collections.Generic;
3 using System.Linq;
4 using System.Text;
5 using System.Threading.Tasks;
6 using Kingmaker.Assets.UnitLogic.Mechanics.Actions;
7 using Kingmaker.Blueprints;
8 using Kingmaker.Blueprints.Classes;
9 using Kingmaker.Blueprints.Classes.Prerequisites;
10 using Kingmaker.Blueprints.Classes.Selection;
11 using Kingmaker.Blueprints.Classes.Spells;
12 using Kingmaker.Blueprints.Facts;
13 using Kingmaker.Blueprints.Items;
14 using Kingmaker.Blueprints.Items.Armors;
15 using Kingmaker.Blueprints.Items.Ecnchantments;
16 using Kingmaker.Blueprints.Items.Equipment;
17 using Kingmaker.Blueprints.Items.Weapons;
18 using Kingmaker.Blueprints.Root;
19 using Kingmaker.Designers.Mechanics.Buffs;
20 using Kingmaker.Designers.Mechanics.Facts;
21 using Kingmaker.Designers.Mechanics.Recommendations;
22 using Kingmaker.ElementsSystem;
23 using Kingmaker.EntitySystem.Stats;
24 using Kingmaker.Enums;
25 using Kingmaker.Enums.Damage;
26 using Kingmaker.Localization;
27 using Kingmaker.ResourceLinks;
28 using Kingmaker.RuleSystem;
29 using Kingmaker.UI.Common;
30 using Kingmaker.UnitLogic;
31 using Kingmaker.UnitLogic.Abilities;
32 using Kingmaker.UnitLogic.Abilities.Blueprints;
33 using Kingmaker.UnitLogic.Abilities.Components;
34 using Kingmaker.UnitLogic.Abilities.Components.AreaEffects;
35 using Kingmaker.UnitLogic.Abilities.Components.Base;
36 using Kingmaker.UnitLogic.Abilities.Components.CasterCheckers;
37 using Kingmaker.UnitLogic.Abilities.Components.TargetCheckers;
38 using Kingmaker.UnitLogic.ActivatableAbilities;
39 using Kingmaker.UnitLogic.ActivatableAbilities.Restrictions;
40 using Kingmaker.UnitLogic.Buffs;
41 using Kingmaker.UnitLogic.Buffs.Blueprints;
42 using Kingmaker.UnitLogic.Buffs.Components;
43 using Kingmaker.UnitLogic.Commands.Base;
44 using Kingmaker.UnitLogic.FactLogic;
45 using Kingmaker.UnitLogic.Mechanics;
46 using Kingmaker.UnitLogic.Mechanics.Actions;
47 using Kingmaker.UnitLogic.Mechanics.Components;
48 using Kingmaker.UnitLogic.Mechanics.Conditions;
49 using Kingmaker.UnitLogic.Parts;
50 using Kingmaker.Utility;
51 using static Kingmaker.UnitLogic.ActivatableAbilities.ActivatableAbilityResourceLogic;
52 using static Kingmaker.UnitLogic.Commands.Base.UnitCommand;
53
54
55 namespace CallOfTheWild
56 {
57 class Spiritualist
58 {
59 static LibraryScriptableObject library => Main.library;
60 internal static bool test_mode = false;
61 static public BlueprintCharacterClass spiritualist_class;
62 static public BlueprintProgression spiritualist_progression;
63 static public BlueprintFeature spiritualist_proficiencies;
64 static public BlueprintFeature spiritualist_knacks;
65 static public BlueprintFeatureSelection emotional_focus_selection;
66 static public BlueprintFeature spiritualist_spellcasting;
67 static public BlueprintFeature bonded_manifestation;
68
69 static public BlueprintFeature link;
70 static public BlueprintFeature etheric_tether;
71 static public BlueprintFeature spiritual_bond;
72 static public BlueprintFeature spiritual_inference;
73 static public BlueprintFeature greater_spiritual_inference;
74
75 static public BlueprintAbilityResource phantom_recall_resource;
76 static public BlueprintFeature phantom_recall;
77 static public BlueprintAbility phantom_recall_ability;
78 static public BlueprintFeature fused_consciousness;
79 static public BlueprintFeature dual_bond;
80 static public BlueprintFeatureSelection potent_phantom;
81 static public BlueprintFeature masters_alignment;
82
83 static public BlueprintFeature shared_consciousness;
84 static public BlueprintBuff unsummon_buff;
85 static public BlueprintAbility summon_companion_ability;
86 static public BlueprintAbility summon_call_ability;
87
88 static public BlueprintArchetype hag_haunted;
89 static public BlueprintFeature hag_phantom;
90 static public BlueprintFeature hag_shared_consciousness;
91 static public BlueprintFeature hag_fused_consciousness;
92 static public BlueprintFeature hag_fused_consciousness12;
93 static public BlueprintFeature hag_spell_casting;
94 static public BlueprintFeature hag_curse7;
95 static public BlueprintFeature hag_curse13;
96 static public BlueprintSpellbook hag_haunted_spellbook;
97
98 static public BlueprintArchetype onmyoji;
99 static public BlueprintSpellbook onmyoji_spellbook;
100 static public BlueprintFeature onmyoji_spellcasting;
101 static public BlueprintFeatureSelection divine_teachings;
102
103 static public BlueprintArchetype scourge;
104 static public BlueprintFeature spell_scourge;
105 static public BlueprintFeature ectoplasmic_swarm;
106
107 static public BlueprintFeature charisma_spellcasting;
108 static public BlueprintSpellbook fractured_mind_spellbook;
109 static public BlueprintArchetype fractured_mind;
110
111 static public BlueprintArchetype exciter;
112 static public BlueprintFeatureSelection exciter_phantom_selection;
113 static public BlueprintFeature rapture;
114 static public BlueprintFeatureSelection exciter_potent_phantom;
115 static public BlueprintFeatureSelection rapturous_rage;
116 static public BlueprintFeature greater_rapture;
117 static public BlueprintFeature overwhelming_excitement;
118 static public BlueprintAbilityResource rapture_resource;
119 static public BlueprintFeature perfect_passion;
120 static public BlueprintFeature exciter_shared_consciousness;
121 static public BlueprintBuff rapture_str_con_buff;
122 static public BlueprintBuff rapture_dex_cha_buff;
123 static public BlueprintBuff rapture_share_str_con_buff;
124 static public BlueprintBuff rapture_share_dex_cha_buff;
125 static public BlueprintBuff prevent_shared_conciousness_fact;
126 static public BlueprintFeatureSelection emotional_conduit;
127
128 static public BlueprintArchetype priest_of_the_fallen;
129 static public BlueprintFeature mythmaker;
130 static public BlueprintFeatureSelection channel_energy;
131 static public BlueprintFeature phantom_call;
132 static public BlueprintFeatureSelection emotional_focus_no_unsummon;
133 static public BlueprintFeatureSelection masterful_faith;
134
135 //necrologist, exciter, priest of the fallen
136
137 internal static void createSpiritualistClass()
138 {
139 Main.logger.Log("Spiritualist class test mode: " + test_mode.ToString());
140 var inquisitor_class = library.TryGet<BlueprintCharacterClass>(
"f1a70d9e1b0b41e49874e1fa9052a1ce");
141
142 spiritualist_class = Helpers.Create<BlueprintCharacterClass>();
143 spiritualist_class.name = "SpiritualistClass";
144 library.AddAsset(spiritualist_class, "");
145
146 spiritualist_class.LocalizedName = Helpers.CreateString(
"Spiritualist.Name", "Spiritualist");
147 spiritualist_class.LocalizedDescription = Helpers.CreateString(
"Spiritualsit.Description",
148 "Becoming a
spiritualist is not a calling — it’s a phenomenon.\n"
149 + "When a
creature dies, its spirit flees its body and begins the next stage of its existence.
Debilitating emotional attachments during life and other psychic corruptions cause
some spirits to drift into the Ethereal Plane and descend toward the Negative Energy
Plane. Some of these spirits are able to escape the pull of undeath and make their
way back to the Material Plane, seeking refuge in a psychically attuned mind. Such a
fusing of consciousnesses creates a spiritualist—the master of a single powerful
phantom whom the spiritualist can manifest to do her bidding.\n"
150 + "Role:
The spiritualist seeks the occult and esoteric truth about life, death, and the
passage beyond, using her phantom as a guide and tool. The connection with her
phantom allows her to harness the powers of life and death, thought and nightmare,
shadow and revelation."
151 );
152 spiritualist_class.m_Icon = inquisitor_class.Icon;
153 spiritualist_class.SkillPoints = inquisitor_class.SkillPoints - 1;
154 spiritualist_class.HitDie = DiceType.D8;
155 spiritualist_class.BaseAttackBonus = inquisitor_class.BaseAttackBonus;
156 spiritualist_class.FortitudeSave = inquisitor_class.FortitudeSave;
157 spiritualist_class.ReflexSave = inquisitor_class.ReflexSave;
158 spiritualist_class.WillSave = inquisitor_class.WillSave;
159 spiritualist_class.Spellbook = createSpiritualistSpellbook();
160 spiritualist_class.ClassSkills = new StatType[] { StatType.
SkillPersuasion, StatType.SkillKnowledgeArcana, StatType.SkillKnowledgeWorld,
StatType.SkillLoreNature, StatType.SkillLoreReligion, StatType.SkillPerception,
161 StatType.SkillUseMagicDevice
};
162 spiritualist_class.IsDivineCaster = false;
163 spiritualist_class.IsArcaneCaster = false;
164 spiritualist_class.StartingGold = inquisitor_class.StartingGold;
165 spiritualist_class.PrimaryColor = inquisitor_class.PrimaryColor;
166 spiritualist_class.SecondaryColor = inquisitor_class.SecondaryColor;
167 spiritualist_class.RecommendedAttributes = new StatType[] { StatType.
Wisdom };
168 spiritualist_class.NotRecommendedAttributes = new StatType[0];
169 spiritualist_class.EquipmentEntities = inquisitor_class.EquipmentEntities;
170 spiritualist_class.MaleEquipmentEntities = inquisitor_class.
MaleEquipmentEntities;
171 spiritualist_class.FemaleEquipmentEntities = inquisitor_class.
FemaleEquipmentEntities;
172 spiritualist_class.ComponentsArray = inquisitor_class.ComponentsArray;
173 spiritualist_class.StartingItems = new BlueprintItem[]
174 {
175 library.Get<BlueprintItemArmor>("afbe88d27a0eb544583e00fa78ffb2c7"),
//studded leather
176 library.Get<BlueprintItemWeapon>("1052a1f7128861942aa0c2ee6078531e"),
//scythe
177 library.Get<BlueprintItemWeapon>("511c97c1ea111444aa186b1a58496664"),
//light crossbow
178 library.Get<BlueprintItemEquipmentUsable>(
"807763fd874989e4d96eb2d8e234139e"), //shield scroll
179 library.Get<BlueprintItemEquipmentUsable>(
"fe244c39bdd5cb64eae65af23c6759de"), //cause fear
180 library.Get<BlueprintItemEquipmentUsable>(
"cd635d5720937b044a354dba17abad8d") //cure light wounds
181 };
182
183 createSpiritualistProgression();
184 spiritualist_class.Progression = spiritualist_progression;
185
186 Helpers.RegisterClass(spiritualist_class);
187
188 createHagHaunted();
189 createOnmyoji();
190 createScourge();
191 createFracturedMind();
192 createExciter();
193 createPriestOfTheFallen();
194 spiritualist_class.Archetypes = new BlueprintArchetype[] {hag_haunted,
onmyoji, scourge, fractured_mind, exciter, priest_of_the_fallen};
195 createEmotionalConduit();
196 }
197
198
199 static void createEmotionalConduit()
200 {
201 emotional_conduit = Helpers.CreateFeatureSelection(
"EmotionaConduitFeatureSelection",
202 "Emotional Conduit",
203 "You gain familiarity
with a number of additional spells based on the emotional focus of your phantom.
These spells are added to both your class spell list (if not already on that list)
and your list of spells known; they are in addition to the normal number of spells
known for your level.",
204 "",
205 null,
206 FeatureGroup.Feat,
207 Helpers.
PrerequisiteClassLevel(spiritualist_class, 1)
208 );
209
210 foreach (var kv in Phantom.emotion_conduit_spells_map)
211 {
212 string spell_string = "You gain the following spells:";
213 foreach (var s in kv.Value)
214 {
215 spell_string += " " + s.Name + (s == kv.Value.Last() ? "." : ","
);
216 }
217 var feature = Helpers.CreateFeature(kv.Key + "EmotionaConduitFeature",
218 emotional_conduit.Name + ": " +
Phantom.phantom_name_map[kv.Key],
219 emotional_conduit.Description +
"\n" + spell_string,
220 "",
221 Phantom.phantom_progressions[kv.
Key].Icon,
222 FeatureGroup.Feat);
223
224 for (int i = 0; i < kv.Value.Length; i++)
225 {
226 feature.AddComponent(Helpers.CreateAddKnownSpell(kv.Value[i],
spiritualist_class, i + 1));
227 }
228
229 if (Phantom.exciter_progressions.ContainsKey(kv.Key))
230 {
231 feature.AddComponents(Helpers.PrerequisiteFeaturesFromList(
Phantom.phantom_progressions[kv.Key], Phantom.exciter_progressions[kv.Key]));
232 }
233 else
234 {
235 feature.AddComponent(Helpers.PrerequisiteFeature(Phantom.
phantom_progressions[kv.Key]));
236 }
237 emotional_conduit.AllFeatures = emotional_conduit.AllFeatures.
AddToArray(feature);
238 }
239
240 library.AddFeats(emotional_conduit);
241 }
242
243
244 static void createPriestOfTheFallen()
245 {
246 priest_of_the_fallen = Helpers.Create<BlueprintArchetype>(a =>
247 {
248 a.name = "PriestOfTheFallenArchetype";
249 a.LocalizedName = Helpers.CreateString($"{a.name}.Name", "Priest of
the Fallen");
250 a.LocalizedDescription = Helpers.CreateString($"{a.name}.Description"
, "Countless hero-gods have risen and fallen through Golarion’s long history,
leaving behind mighty spirits. Those attuned to these fallen hero-gods can become
conduits for their restless souls and agents acting out their divine will. The
result is a priest of the fallen, a spiritualist who channels her land’s legends and
provides a vessel for mighty heroes to perform heroic acts once more.");
251 });
252 Helpers.SetField(priest_of_the_fallen, "m_ParentClass",
spiritualist_class);
253 library.AddAsset(priest_of_the_fallen, "");
254
255 createMythmaker();
256 createChannelEnergy();
257 createPhantomCall();
258 createMasterfulFaith();
259
260 var deity_selection = library.Get<BlueprintFeatureSelection>(
"59e7a76987fe3b547b9cce045f4db3e4");
261 emotional_focus_no_unsummon = library.CopyAndAdd(
emotional_focus_selection, "EmotionalFocusNoUnsummonSelection", "");
262 emotional_focus_no_unsummon.RemoveComponents<AddFacts>();
263 priest_of_the_fallen.RemoveFeatures = new LevelEntry[] { Helpers.
LevelEntry(1, emotional_focus_selection, shared_consciousness),
264 Helpers.
LevelEntry(3, bonded_manifestation),
265 Helpers.
LevelEntry(6, phantom_recall),
266 Helpers.
LevelEntry(10, fused_consciousness),
267 Helpers.
LevelEntry(17, dual_bond)};
268 priest_of_the_fallen.AddFeatures = new LevelEntry[] { Helpers.LevelEntry(
1, deity_selection, emotional_focus_no_unsummon, mythmaker),
269 Helpers.LevelEntry(3,
channel_energy),
270 Helpers.LevelEntry(6,
phantom_call),
271 Helpers.LevelEntry(17,
masterful_faith)
272 };
273
274 spiritualist_progression.UIGroups = spiritualist_progression.UIGroups.
AddToArray(Helpers.CreateUIGroup(mythmaker, channel_energy, phantom_call,
masterful_faith));
275 spiritualist_progression.UIDeterminatorsGroup = spiritualist_progression.
UIDeterminatorsGroup.AddToArray(emotional_focus_no_unsummon, deity_selection);
276 }
277
278 static void createMasterfulFaith()
279 {
280 masterful_faith = library.CopyAndAdd<BlueprintFeatureSelection>(
"48525e5da45c9c243a343fc6545dbdb9", "MasterfulFaithFeatureSelection", "");
281 var animal_domain = library.Get<BlueprintProgression>(
"23d2f87aa54c89f418e68e790dba11e0");
282 animal_domain.AddComponent(Common.prerequisiteNoArchetype(
priest_of_the_fallen));
283 for (int i = 0; i < masterful_faith.AllFeatures.Length; i++)
284 {
285 masterful_faith.AllFeatures[i] = domainToMasterfulFaith(
masterful_faith.AllFeatures[i] as BlueprintProgression, 17);
286 }
287
288 masterful_faith.SetNameDescription("Masterful Faith",
289 "At 17th level, a priest of the
fallen chooses one of cleric domains and receives its full benefits, treating her
spiritualist level as her cleric level. She adds the domain spells to her spells
known.");
290 }
291
292
293 static BlueprintProgression domainToMasterfulFaith(BlueprintProgression
domain, int level)
294 {
295 var new_domain = library.CopyAndAdd(domain, "MasterfulFaith" + domain.
name, "");
296 List<LevelEntry> secondary_level_entries = new List<LevelEntry>();
297 secondary_level_entries.Add(Helpers.LevelEntry(level));
298
299 foreach (var level_entry in domain.LevelEntries)
300 {
301 if (level_entry.Level <= level)
302 {
303 secondary_level_entries[0].Features.AddRange(level_entry.Features
);
304 }
305 else
306 {
307 secondary_level_entries.Add(level_entry);
308 }
309 }
310
311 new_domain.LevelEntries = secondary_level_entries.ToArray();
312 var cleric = library.Get<BlueprintCharacterClass>(
"67819271767a9dd4fbfd4ae700befea0");
313 ClassToProgression.addClassToProgression(spiritualist_class, new
BlueprintArchetype[] { priest_of_the_fallen }, ClassToProgression.DomainSpellsType.
NormalList, new_domain, cleric);
314 return new_domain;
315 }
316
317 static void createMythmaker()
318 {
319 var resource = Helpers.CreateAbilityResource("MythmakerResource", "", "",
"", null);
320 resource.SetFixedResource(1);
321 var buffs_pairs = new BlueprintBuff[][]
322 {
323 createArchmageBuffs(),
324 createChampionBuffs(),
325 createGuardianBuffs(),
326 createHierophantBuffs(),
327 createMarshalBuffs(),
328 createTricksterBuffs()
329 };
330
331 var abilities = new List<BlueprintAbility>();
332 var remove_buffs = Helpers.Create<NewMechanics.ContextActionRemoveBuffs>(
c => c.Buffs = new BlueprintBuff[0]);
333
334 var description = "A priest of the fallen can channel many different
hero-god phantoms, though only one at a time.\n"
335 + "These spirits will not suffer being confined in a mortal’s
consciousness and must be manifested in ectoplasmic form.\n"
336 + "They each have same emotional focus but retain some of their
hero-god powers, determined by their mythic archetype. A priest of the fallen can
channel a hero-god phantom with as full-round action. A priest of the fallen can
channel only one hero-god phantom per 24 hours, but once channeled, a hero-god
phantom remains until a new one is channeled.";
337
338 foreach (var bp in buffs_pairs)
339 {
340 remove_buffs.Buffs = remove_buffs.Buffs.AddToArray(bp[0], bp[1]);
341 var apply_buff1 = Common.createContextActionApplyBuff(bp[0], Helpers.
CreateContextDuration(), dispellable: false, is_permanent: true);
342 var apply_buff12 = Common.createContextActionApplyBuff(bp[1], Helpers
.CreateContextDuration(), dispellable: false, is_permanent: true);
343
344 var ability = Helpers.CreateAbility(bp[0].name.Replace("1Buff",
"Ability"),
345 bp[0].Name,
346 bp[0].Description,
347 "",
348 bp[0].Icon,
349 AbilityType.Supernatural,
350 CommandType.Standard,
351 AbilityRange.Personal,
352 "",
353 "",
354 Helpers.CreateRunActions(
remove_buffs,
355 Common.
createRunActionsDependingOnContextValue(Helpers.CreateContextValue(AbilityRankType.
Default),
356
apply_buff1,
357
apply_buff12
358
)
359 ),
360 Helpers.CreateContextRankConfig(
ContextRankBaseValueType.ClassLevel, classes: getSpiritualistArray(),
361
progression: ContextRankProgression.OnePlusDivStep, stepLevel: 12,
362
max: 2, min: 1),
363 resource.CreateResourceLogic()
364 );
365 ability.setMiscAbilityParametersSelfOnly();
366 Common.setAsFullRoundAction(ability);
367 abilities.Add(ability);
368 description += "\n" + ability.Name + ": " + ability.Description;
369 }
370
371 var wrapper = Common.createVariantWrapper("MythmakerAbilityBase", "",
abilities.ToArray());
372 wrapper.SetNameDescriptionIcon("Mythmaker",
373 description,
374 Helpers.GetIcon(
"be68c660b41bc9247bcab727b10d2cd1")
375 ); //defensive stance
376
377 mythmaker = Common.AbilityToFeature(wrapper, false);
378 mythmaker.AddComponent(resource.CreateAddAbilityResource());
379 }
380
381
382 static public BlueprintBuff[] createMarshalBuffs()
383 {
384 var feature12 = Helpers.CreateFeature("MythmakerMarshallFeature12",
385 "",
386 "",
387 "",
388 null,
389 FeatureGroup.None
390 );
391 feature12.HideInCharacterSheetAndLevelUp = true;
392 feature12.HideInUI = true;
393
394 var buff = Helpers.CreateBuff("MythmakerMarshalEffectBuff",
395 "Inspire",
396 "The phantom can fill its allies with its
triumphant spirit as a standard action, granting them a +1 morale bonus on saving
throws against charm and fear effects and a +1 competence bonus on attack and weapon
damage rolls for a number of rounds per day equal to 2 + its Charisma modifier.
These rounds need not be consecutive. At 12th level, these bonuses increase by 1 and
ability can be activated as a move action.",
397 "",
398 Helpers.GetIcon(
"5250fe10c377fdb49be449dfe050ba70"), //inspire courage
399 null,
400 Helpers.CreateAddContextStatBonus(StatType.
AdditionalAttackBonus, ModifierDescriptor.Competence),
401 Helpers.CreateAddContextStatBonus(StatType.
AdditionalDamage, ModifierDescriptor.Competence),
402 Common.
createContextSavingThrowBonusAgainstDescriptor(Helpers.CreateContextValue(
AbilityRankType.Default), ModifierDescriptor.Morale, SpellDescriptor.Charm |
SpellDescriptor.Fear),
403 Helpers.CreateContextRankConfig(
ContextRankBaseValueType.FeatureList, featureList: new BlueprintFeature[] {feature12,
feature12 },
404 min: 1
405 )
406 );
407
408
409 var resource = Helpers.CreateAbilityResource("MythmakerMarshalResource",
"", "", "", null);
410 resource.SetIncreasedByStat(4, StatType.Charisma);
411
412 var toggle = Common.createToggleAreaEffect(buff,
413 50.Feet(),
414 Helpers.
CreateConditionsCheckerAnd(Helpers.Create<ContextConditionIsAlly>()),
415 AbilityActivationType.
WithUnitCommand,
416 UnitCommand.CommandType.
Standard,
417 Common.createPrefabLink(
"2f93a2909cb766f4d961aee34a3c84c2"),
418 Common.createPrefabLink(
"9353083f430e5a44a8e9d6e26faec248")
419 );
420 toggle.AddComponent(resource.CreateActivatableResourceLogic(
ResourceSpendType.NewRound));
421 toggle.DeactivateIfCombatEnded = true;
422 toggle.DeactivateIfOwnerDisabled = true;
423 toggle.DeactivateImmediately = false;
424 toggle.Group = ActivatableAbilityGroupExtension.MarshalInspire.
ToActivatableAbilityGroup();
425 var feature1 = Common.ActivatableAbilityToFeature(toggle);
426 feature1.AddComponent(resource.CreateAddAbilityResource());
427 feature12.AddComponent(Helpers.Create<
ActivatableAbilityActionTypeModierMechanics.ModifyActivatableAbilityGroupActionType>(
m =>
428 {
429 m.group = ActivatableAbilityGroupExtension.
MarshalInspire.ToActivatableAbilityGroup();
430 m.action = CommandType.Move;
431 })
432 );
433
434
435
436 return createMythmakerBuffs("MythmakerMarshal",
437 "Marshal",
438 buff.Description,
439 buff.Icon,
440 feature1,
441 feature12
442 );
443 }
444
445
446 static public BlueprintBuff[] createTricksterBuffs()
447 {
448 var buff = Helpers.CreateBuff("MythmakerTricksterSneakAttackBuff",
449 "Trickster Sneak Attack",
450 "The phantom gains the sneak attack rogue
class feature as a rogue of a level equal to the phantom’s Hit Dice. It can use the
sneak attack ability a number of rounds equal to its Dexterity modifier (minimum 1).
These rounds do not need to be consecutive.",
451 "",
452 Helpers.GetIcon(
"9b9eac6709e1c084cb18c3a366e0ec87"), //sneak attack
453 null,
454 Helpers.CreateAddContextStatBonus(StatType.
SneakAttack, ModifierDescriptor.UntypedStackable),
455 Helpers.CreateContextRankConfig(
ContextRankBaseValueType.ClassLevel, ContextRankProgression.OnePlusDiv2,
456 classes: Phantom.
getPhantomArray())
457 );
458
459
460 var resource = Helpers.CreateAbilityResource("MythmakerTricksterResource"
, "", "", "", null);
461 resource.SetIncreasedByStat(0, StatType.Dexterity);
462
463 var toggle = Common.buffToToggle(buff, CommandType.Free, false, resource.
CreateActivatableResourceLogic(ResourceSpendType.NewRound));
464 toggle.DeactivateIfCombatEnded = true;
465 toggle.DeactivateImmediately = false;
466 toggle.DeactivateIfOwnerDisabled = true;
467 var feature1 = Common.ActivatableAbilityToFeature(toggle);
468 feature1.AddComponent(resource.CreateAddAbilityResource());
469
470
471 var feature12 = library.Get<BlueprintFeature>(
"97a6aa2b64dd21a4fac67658a91067d7");
472
473 return createMythmakerBuffs("MythmakerTrickster",
474 "Trickster",
475 "The phantom gains the sneak attack rogue
class feature as a rogue of a level equal to the phantom’s Hit Dice. It can use the
sneak attack ability a number of times per day equal to its Dexterity modifier
(minimum 1). At 12th level, phantom receives fast stealth rogue talent.",
476 Helpers.GetIcon(
"9b9eac6709e1c084cb18c3a366e0ec87"), //sneak attack
477 feature1,
478 feature12
479 );
480 }
481
482
483 static public BlueprintBuff[] createGuardianBuffs()
484 {
485 var feature1 = Helpers.CreateFeature("MythmakerGuardianFeature1",
486 "",
487 "",
488 "",
489 null,
490 FeatureGroup.None,
491 Helpers.CreateAddStatBonus(StatType.
AC, 2, ModifierDescriptor.NaturalArmor)
492 );
493 feature1.HideInUI = true;
494 feature1.HideInCharacterSheetAndLevelUp = true;
495
496 var feature12 = Helpers.CreateFeature("MythmakerGuardianFeature12",
497 "",
498 "",
499 "",
500 null,
501 FeatureGroup.None,
502 Helpers.CreateAddContextStatBonus(StatType.
HitPoints, ModifierDescriptor.UntypedStackable),
503 Helpers.CreateContextRankConfig(
ContextRankBaseValueType.ClassLevel, ContextRankProgression.MultiplyByModifier,
504 classes: Phantom.
getPhantomArray(), stepLevel: 2)
505 );
506 feature12.HideInUI = true;
507 feature12.HideInCharacterSheetAndLevelUp = true;
508
509 return createMythmakerBuffs("MythmakerGuardian",
510 "Guardian",
511 "The phantom gains a +2 natural armor bonus.
At 12th level, the phantom increases its maximum hit points by twice its number of
Hit Dice.",
512 Helpers.GetIcon(
"62888999171921e4dafb46de83f4d67d"),
513 feature1,
514 feature12
515 );
516 }
517
518
519 static public BlueprintBuff[] createChampionBuffs()
520 {
521 var weapon_focus = library.Get<BlueprintParametrizedFeature>(
"1e1f627d26ad36f43bbd26cc2bf8ac7e");
522 var weapon_specialzation = library.Get<BlueprintParametrizedFeature>(
"31470b17e8446ae4ea0dacd6c5817d86");
523 var greater_weapon_focus = library.Get<BlueprintParametrizedFeature>(
"09c9e82965fb4334b984a1e9df3bd088");
524 var feature1 = Helpers.CreateFeature("MythmakerChampionFeature1",
525 "",
526 "",
527 "",
528 null,
529 FeatureGroup.None,
530 Common.createAddParametrizedFeatures(
weapon_focus, WeaponCategory.OtherNaturalWeapons)
531 );
532 feature1.HideInUI = true;
533 feature1.HideInCharacterSheetAndLevelUp = true;
534
535 var feature12 = Helpers.CreateFeature("MythmakerChampionFeature12",
536 "",
537 "",
538 "",
539 null,
540 FeatureGroup.None,
541 Common.createAddParametrizedFeatures(
weapon_specialzation, WeaponCategory.OtherNaturalWeapons),
542 Common.createAddParametrizedFeatures(
greater_weapon_focus, WeaponCategory.OtherNaturalWeapons)
543 );
544 feature12.HideInUI = true;
545 feature12.HideInCharacterSheetAndLevelUp = true;
546
547 return createMythmakerBuffs("MythmakerChampion",
548 "Champion",
549 "The phantom gains Weapon Focus (slam) as a
bonus feat. At 12th level, it gains Greater Weapon Focus (slam) and Weapon
Specialization (slam) as bonus feats.",
550 Helpers.GetIcon(
"247a4068296e8be42890143f451b4b45"),
551 feature1,
552 feature12
553 );
554 }
555
556
557 static public BlueprintBuff[] createHierophantBuffs()
558 {
559 var resource_bless = Helpers.CreateAbilityResource(
"MythmakerHierophantBlessResource", "", "", "", null);
560 resource_bless.SetIncreasedByLevel(0, 1, Phantom.getPhantomArray());
561
562 var resource_bane = Helpers.CreateAbilityResource(
"MythmakerHierophantBaneResource", "", "", "", null);
563 resource_bane.SetIncreasedByLevel(0, 1, Phantom.getPhantomArray());
564
565 var resource_prayer = Helpers.CreateAbilityResource(
"MythmakerHierophantPrayerResource", "", "", "", null);
566 resource_prayer.SetFixedResource(1);
567
568 var resource_searing_light = Helpers.CreateAbilityResource(
"MythmakerHierophantSearingLightResource", "", "", "", null);
569 resource_searing_light.SetFixedResource(1);
570
571 var bless = Common.convertToSpellLike(library.Get<BlueprintAbility>(
"90e59f4a4ada87243b7b3535a06d0638"), "MythmakerHierophant", Phantom.getPhantomArray
(), StatType.Charisma, resource_bless);
572 var bane = Common.convertToSpellLike(library.Get<BlueprintAbility>(
"8bc64d869456b004b9db255cdd1ea734"), "MythmakerHierophant", Phantom.getPhantomArray
(), StatType.Charisma, resource_bane);
573 var prayer = Common.convertToSpellLike(library.Get<BlueprintAbility>(
"faabd2cc67efa4646ac58c7bb3e40fcc"), "MythmakerHierophant", Phantom.getPhantomArray
(), StatType.Charisma, resource_prayer);
574 var searing_light = Common.convertToSpellLike(library.Get<
BlueprintAbility>("bf0accce250381a44b857d4af6c8e10d"), "MythmakerHierophant", Phantom
.getPhantomArray(), StatType.Charisma, resource_searing_light);
575
576 var feature1 = Common.AbilityToFeature(bless);
577 feature1.AddComponents(Helpers.CreateAddFact(bane),
578 resource_bless.CreateAddAbilityResource(),
579 resource_bane.CreateAddAbilityResource()
580 );
581
582 var feature12 = Common.AbilityToFeature(prayer);
583 feature12.AddComponents(Helpers.CreateAddFact(searing_light),
584 resource_prayer.CreateAddAbilityResource(),
585 resource_searing_light.CreateAddAbilityResource()
586 );
587
588 return createMythmakerBuffs("MythmakerHierophant",
589 "Hierophant",
590 "The phantom gains bane and bless as
spell-like abilities. It can use each spell-like ability a number of times per day
equal to its Hit Dice, which it uses in place of a caster level. At 12th level, it
can also cast prayer and searing light each once per day.",
591 bless.Icon,
592 feature1,
593 feature12
594 );
595 }
596
597
598 static public BlueprintBuff[] createArchmageBuffs()
599 {
600 var resource_mm = Helpers.CreateAbilityResource(
"MythmakerArchmageMagicMissileResource", "", "", "", null);
601 resource_mm.SetIncreasedByLevel(0, 1, Phantom.getPhantomArray());
602
603 var resource_sleep = Helpers.CreateAbilityResource(
"MythmakerArchmageSleepResource", "", "", "", null);
604 resource_sleep.SetIncreasedByLevel(0, 1, Phantom.getPhantomArray());
605
606 var resource_fireball = Helpers.CreateAbilityResource(
"MythmakerArchmageFireballResource", "", "", "", null);
607 resource_fireball.SetFixedResource(1);
608
609 var resource_hold_person = Helpers.CreateAbilityResource(
"MythmakerArchmageHoldPersonResource", "", "", "", null);
610 resource_hold_person.SetFixedResource(1);
611
612 var magic_missile = Common.convertToSpellLike(library.Get<
BlueprintAbility>("4ac47ddb9fa1eaf43a1b6809980cfbd2"), "MythmakerArchmage", Phantom.
getPhantomArray(), StatType.Charisma, resource_mm);
613 var sleep = Common.convertToSpellLike(library.Get<BlueprintAbility>(
"bb7ecad2d3d2c8247a38f44855c99061"), "MythmakerArchmage", Phantom.getPhantomArray(),
StatType.Charisma, resource_sleep);
614 var fireball = Common.convertToSpellLike(library.Get<BlueprintAbility>(
"2d81362af43aeac4387a3d4fced489c3"), "MythmakerArchmage", Phantom.getPhantomArray(),
StatType.Charisma, resource_fireball);
615 var hold_person = Common.convertToSpellLike(library.Get<BlueprintAbility
>("c7104f7526c4c524f91474614054547e"), "MythmakerArchmage", Phantom.getPhantomArray
(), StatType.Charisma, resource_hold_person);
616
617 var feature1 = Common.AbilityToFeature(magic_missile);
618 feature1.AddComponents(Helpers.CreateAddFact(sleep),
619 resource_mm.CreateAddAbilityResource(),
620 resource_sleep.CreateAddAbilityResource()
621 );
622
623 var feature12 = Common.AbilityToFeature(fireball);
624 feature12.AddComponents(Helpers.CreateAddFact(hold_person),
625 resource_fireball.CreateAddAbilityResource(),
626 resource_hold_person.CreateAddAbilityResource()
627 );
628
629 return createMythmakerBuffs("MythmakerArchmage",
630 "Archmage",
631 "The phantom gains magic missile and sleep
as spell-like abilities. It can use each spell-like ability a number of times per
day equal to its Hit Dice, which it uses in place of a caster level. At 12th level,
it can also cast fireball and hold person each once per day.",
632 Helpers.GetIcon(
"55edf82380a1c8540af6c6037d34f322"),
633 feature1,
634 feature12
635 );
636 }
637
638
639 static void createPhantomCall()
640 {
641 var raise_companion_resource = Helpers.CreateAbilityResource(
"PriestOfTheFallenRaisePhantomResource", "", "", "", null);
642 raise_companion_resource.SetFixedResource(1);
643 var spell = library.CopyAndAdd<BlueprintAbility>(
"9288a1e0a4704b54984fd8155de38d4f", "PriestOfTheFallenRaisePhantomAbility", "");
644 spell.RemoveComponents<AbilityTargetIsDeadCompanion>();
645 spell.AddComponent(Helpers.Create<NewMechanics.AbilityCasterCompanionDead
>());
646 spell.AddComponent(Helpers.Create<CompanionMechanics.
AbilityCasterCompanionUnsummoned>(a => a.not = true));
647 spell.ReplaceComponent<AbilityEffectRunAction>(Helpers.CreateRunActions(
Helpers.Create<ContextActionsOnPet>(a => a.Actions = Helpers.CreateActionList(Helpers
.Create<ContextActionResurrect>(c => c.FullRestore = true)))));
648 spell.ReplaceComponent<AbilityTargetIsDeadCompanion>(Helpers.Create<
NewMechanics.AbilityTargetIsDead>());
649 spell.Range = AbilityRange.Personal;
650 spell.setMiscAbilityParametersSelfOnly();
651 spell.Type = AbilityType.Supernatural;
652 spell.AddComponent(raise_companion_resource.CreateResourceLogic());
653 spell.SetNameDescriptionIcon("Phantom Call",
654 "At 6th level, once per day, a priest of
the fallen can summon a fully manifested hero-god phantom back from the Ethereal
Plane as a standard action.",
655 Helpers.GetIcon(
"a0fc99f0933d01643b2b8fe570caa4c5")
656 );
657
658 phantom_call = Helpers.CreateFeature(
"PhantomCallPreisetFoTheFallenFeature",
659 spell.Name,
660 spell.Description,
661 "",
662 spell.Icon,
663 FeatureGroup.None,
664 Helpers.CreateAddFact(
spell),
665 raise_companion_resource.
CreateAddAbilityResource()
666 );
667 }
668
669
670 static BlueprintBuff[] createMythmakerBuffs(string prefix, string
display_name, string description, UnityEngine.Sprite icon, BlueprintFeature feature1,
BlueprintFeature feature12)
671 {
672 var buff1 = Helpers.CreateBuff(prefix + "1Buff",
673 display_name,
674 description,
675 "",
676 icon,
677 null,
678 Common.createAddFeatToAnimalCompanion(
feature1)
679 );
680 buff1.SetBuffFlags(BuffFlags.StayOnDeath);
681
682 var buff12 = library.CopyAndAdd(buff1, prefix + "12Buff", "");
683 buff12.AddComponent(Common.createAddFeatToAnimalCompanion(feature12));
684
685 return new BlueprintBuff[] { buff1, buff12 };
686 }
687
688
689 static void createChannelEnergy()
690 {
691 var channel_positive_allowed = library.Get<BlueprintFeature>(
"8c769102f3996684fb6e09a2c4e7e5b9");
692 var channel_negative_allowed = library.Get<BlueprintFeature>(
"dab5255d809f77c4395afc2b713e9cd6");
693
694 var select_positive = library.Get<BlueprintFeature>(
"a79013ff4bcd4864cb669622a29ddafb");
695 var select_negative = library.Get<BlueprintFeature>(
"3adb2c906e031ee41a01bfc1d5fb7eea");
696
697 channel_energy = Helpers.CreateFeatureSelection(
"PriestOfTheFallenChannelEnergySelection",
698 "Channel
Energy",
699 $"At 3rd
level, a priest of the fallen can channel her phantom’s divine energy. This
functions as the cleric’s channel energy class feature, except that the amount of
damage dealt or hit points restored is equal to
1d{BalanceFixes.getDamageDieString(DiceType.D6)} points plus an additional
1d{BalanceFixes.getDamageDieString(DiceType.D6)} points for every 2 spiritualist
levels beyond 3rd. She can use this ability a number of times per day equal to her
Charisma modifier (minimum 1).",
700 "",
701
select_positive.Icon,
702 FeatureGroup.
None);
703
704 var channel_positive = Helpers.CreateFeature(
"PriestOfTheFallenChannelPositive",
705 select_positive.Name,
706 channel_energy.
Description,
707 "",
708 select_positive.Icon,
709 FeatureGroup.
ChannelEnergy,
710 Helpers.
PrerequisiteFeature(channel_positive_allowed)
711 );
712
713 var channel_negative = Helpers.CreateFeature(
"PriestOfTheFallenChannelNegative",
714 select_negative.Name,
715 channel_energy.
Description,
716 "",
717 select_negative.Icon,
718 FeatureGroup.
ChannelEnergy,
719 Helpers.
PrerequisiteFeature(channel_negative_allowed)
720 );
721
722 var channel_energy_resource = Helpers.CreateAbilityResource(
"PriestOfTheFallenChannelEnergyResource", "", "", "", null);
723 channel_energy_resource.SetIncreasedByStat(0, StatType.Charisma);
724 channel_energy_resource.AddComponent(Helpers.Create<ResourceMechanics.
MinResourceAmount>(m => m.value = 1));
725 var resource_logic = Helpers.CreateResourceLogic(channel_energy_resource);
726
727
728 var context_rank_config = Helpers.CreateContextRankConfig(baseValueType:
ContextRankBaseValueType.ClassLevel, progression: ContextRankProgression.
StartPlusDivStep,
729 classes: new
BlueprintCharacterClass[] { spiritualist_class },
730 startLevel: 3,
stepLevel: 2);
731
732 var dc_scaling = Common.createContextCalculateAbilityParamsBasedOnClasses
(getSpiritualistArray(), StatType.Charisma);
733 var positive_heal = ChannelEnergyEngine.createChannelEnergy(
ChannelEnergyEngine.ChannelType.PositiveHeal, "PriestOfTheFallenPostiveHeal", "",
734 $"Channeling
positive energy causes a burst that heals all living creatures in a 30 - foot radius
centered on the spiritualist. The amount of damage healed is equal to
1d{BalanceFixes.getDamageDieString(DiceType.D6)} points plus an additional
1d{BalanceFixes.getDamageDieString(DiceType.D6)} points for every 2 spiritualist
levels beyond 3rd.",
735 "",
736
context_rank_config, dc_scaling, resource_logic);
737 var positive_harm = ChannelEnergyEngine.createChannelEnergy(
ChannelEnergyEngine.ChannelType.PositiveHarm, "PriestOfTheFallenPostiveHarm", "",
738 $"Channeling
energy causes a burst that damages all undead creatures in a 30 - foot radius
centered on the spiritualist. The amount of damage dealt is equal to
1d{BalanceFixes.getDamageDieString(DiceType.D6)} points plus an additional
1d{BalanceFixes.getDamageDieString(DiceType.D6)} points for every 2 spiritualist
levels beyond 3rd. Creatures that take damage from channeled energy receive a Will
save to halve the damage. The DC of this save is equal to 10 + 1/2 the
spiritualist's level + the spiritualist's Charisma modifier.",
739 "",
740
context_rank_config, dc_scaling, resource_logic);
741 var negative_heal = ChannelEnergyEngine.createChannelEnergy(
ChannelEnergyEngine.ChannelType.NegativeHeal, "PriestOfTheFallenNegativeHeal", "",
742 $"Channeling
negative energy causes a burst that heals all undead creatures in a 30 - foot radius
centered on the spiritualist. The amount of damage healed is equal to
1d{BalanceFixes.getDamageDieString(DiceType.D6)} points plus an additional
1d{BalanceFixes.getDamageDieString(DiceType.D6)} points for every 2 spiritualist
levels beyond 3rd.",
743 "",
744
context_rank_config, dc_scaling, resource_logic);
745 var negative_harm = ChannelEnergyEngine.createChannelEnergy(
ChannelEnergyEngine.ChannelType.NegativeHarm, "PriestOfTheFallenNegativeHarm", "",
746 $"Channeling
energy causes a burst that damages all living creatures in a 30 - foot radius
centered on the spiritualist. The amount of damage dealt is equal to
1d{BalanceFixes.getDamageDieString(DiceType.D6)} points plus an additional
1d{BalanceFixes.getDamageDieString(DiceType.D6)} points for every 2 spiritualist
levels beyond 3rd. Creatures that take damage from channeled energy receive a Will
save to halve the damage. The DC of this save is equal to 10 + 1/2 the
spiritualist's level + the spiritualist's Charisma modifier.",
747 "",
748
context_rank_config, dc_scaling, resource_logic);
749
750 var positive_heal_base = Common.createVariantWrapper(
"PriestOfTheFallenPositiveHealBase", "", positive_heal);
751 var positive_harm_base = Common.createVariantWrapper(
"PriestOfTheFallenPositiveHarmBase", "", positive_harm);
752 var negative_heal_base = Common.createVariantWrapper(
"PriestOfTheFallenNegativeHealBase", "", negative_heal);
753 var negative_harm_base = Common.createVariantWrapper(
"PriestOfTheFallenNegativeHarmBase", "", negative_harm);
754
755 ChannelEnergyEngine.storeChannel(positive_heal, channel_positive,
ChannelEnergyEngine.ChannelType.PositiveHeal);
756 ChannelEnergyEngine.storeChannel(positive_harm, channel_positive,
ChannelEnergyEngine.ChannelType.PositiveHarm);
757 ChannelEnergyEngine.storeChannel(negative_heal, channel_negative,
ChannelEnergyEngine.ChannelType.NegativeHeal);
758 ChannelEnergyEngine.storeChannel(negative_harm, channel_negative,
ChannelEnergyEngine.ChannelType.NegativeHarm);
759
760 channel_positive.AddComponent(Helpers.CreateAddAbilityResource(
channel_energy_resource));
761 channel_positive.AddComponent(Helpers.CreateAddFacts(positive_heal_base,
positive_harm_base));
762
763 channel_negative.AddComponent(Helpers.CreateAddAbilityResource(
channel_energy_resource));
764 channel_negative.AddComponent(Helpers.CreateAddFacts(negative_heal_base,
negative_harm_base));
765
766
767 channel_energy.Features = new BlueprintFeature[] { channel_positive,
channel_negative };
768 channel_energy.AllFeatures = channel_energy.Features;
769
770
771 ChannelEnergyEngine.createExtraChannelFeat(positive_heal, channel_energy,
"ExtraChannelPriestOfTheFallen", "Extra Channel (Priest of the Fallen)",
772 "");
773 }
774
775
776
777 static void createExciter()
778 {
779 exciter = Helpers.Create<BlueprintArchetype>(a =>
780 {
781 a.name = "ExciterArchetype";
782 a.LocalizedName = Helpers.CreateString($"{a.name}.Name", "Exciter");
783 a.LocalizedDescription = Helpers.CreateString($"{a.name}.Description"
, "Psychic magic draws upon the twin and sometimes opposed powers of thought and
emotion, but an exciter cares little for rationality. The phantom that accompanies
him fills him with unbridled exultation, as he lets feeling and passion rule and
sharpen his mind and body into a glorious fusion.");
784 });
785 Helpers.SetField(exciter, "m_ParentClass", spiritualist_class);
786 library.AddAsset(exciter, "");
787
788 createMergedPhantom();
789 createExciterSharedConciousness();
790 createRapture();
791 createOverwhelmingExcitement();
792
793
794 var fast_movement = library.Get<BlueprintFeature>(
"d294a5dddd0120046aae7d4eb6cbc4fc");
795
796
797 exciter.RemoveFeatures = new LevelEntry[] { Helpers.LevelEntry(1,
emotional_focus_selection, shared_consciousness, etheric_tether, masters_alignment),
798 Helpers.LevelEntry(4,
spiritual_inference),
799 Helpers.LevelEntry(6,
phantom_recall),
800 Helpers.LevelEntry(10,
fused_consciousness),
801 Helpers.LevelEntry(12,
greater_spiritual_inference),
802 Helpers.LevelEntry(14,
spiritual_bond),
803 Helpers.LevelEntry(20,
potent_phantom)};
804 exciter.AddFeatures = new LevelEntry[] { Helpers.LevelEntry(1,
exciter_phantom_selection, rapture, fast_movement, exciter_shared_consciousness),
805 Helpers.LevelEntry(4,
perfect_passion),
806 Helpers.LevelEntry(10,
overwhelming_excitement, rapturous_rage),
807 Helpers.LevelEntry(12,
greater_rapture),
808 Helpers.LevelEntry(14,
rapturous_rage),
809 Helpers.LevelEntry(18,
rapturous_rage),
810 Helpers.LevelEntry(20,
exciter_potent_phantom),
811 };
812
813 spiritualist_progression.UIGroups = spiritualist_progression.UIGroups.
AddToArray(Helpers.CreateUIGroup(rapture, rapturous_rage, greater_rapture,
rapturous_rage, rapturous_rage));
814 spiritualist_progression.UIGroups = spiritualist_progression.UIGroups.
AddToArray(Helpers.CreateUIGroup(fast_movement, perfect_passion,
overwhelming_excitement));
815 spiritualist_progression.UIGroups[1].Features.Add(
exciter_shared_consciousness);
816 spiritualist_progression.UIGroups[1].Features.Add(exciter_potent_phantom);
817 spiritualist_progression.UIDeterminatorsGroup = spiritualist_progression.
UIDeterminatorsGroup.AddToArray(exciter_phantom_selection);
818 }
819
820
821 static void createExciterSharedConciousness()
822 {
823 prevent_shared_conciousness_fact = Helpers.CreateBuff(
"PreventExciterSharedConciousnessFeature",
824 "",
825 "",
826 "",
827 null,
828 null
829 );
830 prevent_shared_conciousness_fact.SetBuffFlags(BuffFlags.HiddenInUi);
831
832
833 exciter_shared_consciousness = Helpers.CreateFeature(
"ExciterSharedConsciousnessFeature",
834 shared_consciousness.Name,
835 shared_consciousness.Description,
836 "",
837 shared_consciousness.Icon,
838 FeatureGroup.None,
839 Helpers.Create<RecalculateOnFactsChange
>(a => a.CheckedFacts = new BlueprintUnitFact[] {prevent_shared_conciousness_fact} )
840 );
841
842 foreach (var kv in Phantom.exciter_progressions)
843 {
844 var exciter_skill_foci_feature = Helpers.CreateFeature("Exciter" + kv
.Key + "SharedConsciousnessFeature",
845
shared_consciousness.Name + " (" + Phantom.exciter_progressions[kv.Key].Name + ")",
846
shared_consciousness.Description,
847 "",
848
shared_consciousness.Icon,
849 FeatureGroup.
None,
850 Common.
createContextSavingThrowBonusAgainstDescriptor(Helpers.CreateContextValue(
AbilityRankType.Default), ModifierDescriptor.UntypedStackable, SpellDescriptor.
MindAffecting),
851 Helpers.
CreateContextRankConfig(ContextRankBaseValueType.ClassLevel, classes:
getSpiritualistArray(),
852
progression: ContextRankProgression.Custom,
853
customProgression: new (int, int)[] { (11, 4), (20, 8) })
854 );
855 exciter_skill_foci_feature.HideInCharacterSheetAndLevelUp = true;
856 foreach (var sf in Phantom.phantom_skill_foci[kv.Key])
857 {
858 exciter_skill_foci_feature.AddComponents(Common.
createAddFeatureIfHasFactAndNotHasFact(Phantom.exciter_progressions[kv.Key], sf, sf));
859 }
860
861 exciter_shared_consciousness.AddComponent(Common.
createAddFeatureIfHasFactAndNotHasFactDynamic(Phantom.exciter_progressions[kv.Key],
prevent_shared_conciousness_fact, exciter_skill_foci_feature));
862 }
863 }
864
865
866 static void createOverwhelmingExcitement()
867 {
868 var fatigued = library.Get<BlueprintBuff>(
"e6f2fc5d73d88064583cb828801212f4");
869 var exhausted = library.Get<BlueprintBuff>(
"46d1b9cc3d0fd36469a471b047d773a2");
870 var str_con_effect_buff = Helpers.CreateBuff(
"OverwhelmingExcitementStrConEffectBuff",
871 "Overwhelming Excitement",
872 "At 10th level, an exciter can
share the effects of his rapture with willing allies within 10 feet. He must expend
1 additional round of his rapture each round. The exciter’s allies share all effects
of the rapture except the rage powers; each ally must end its turn within 10 feet of
the exciter, or the effects of the rapture end for that ally and it becomes
fatigued.",
873 "",
874 Helpers.GetIcon(
"1bc83efec9f8c4b42a46162d72cbf494"), //burst of glory
875 Common.createPrefabLink(
"53c86872d2be80b48afc218af1b204d7"), //from rage
876 Helpers.CreateAddContextStatBonus(
StatType.Constitution, ModifierDescriptor.Morale, rankType: AbilityRankType.StatBonus
, multiplier: 2),
877 Helpers.CreateAddContextStatBonus(
StatType.Strength, ModifierDescriptor.Morale, rankType: AbilityRankType.StatBonus,
multiplier: 2),
878 Helpers.CreateAddContextStatBonus(
StatType.SaveWill, ModifierDescriptor.Morale, rankType: AbilityRankType.StatBonus),
879 Helpers.CreateAddStatBonus(StatType.
AC, -2, ModifierDescriptor.UntypedStackable),
880 Helpers.CreateContextRankConfig(
ContextRankBaseValueType.FeatureList, ContextRankProgression.BonusValue, stepLevel: 2
, type: AbilityRankType.StatBonus,
881
featureList: new BlueprintFeature[] { greater_rapture }),
882 Helpers.Create<ForbidSpellCasting>(a
=> a.ForbidMagicItems = true)
883 );
884
885 var dex_cha_effect_buff = library.CopyAndAdd(str_con_effect_buff,
"OverwhelmingExcitementDexChaEffectBuff", "");
886 dex_cha_effect_buff.RemoveComponents<AddContextStatBonus>();
887 dex_cha_effect_buff.AddComponents(Helpers.CreateAddContextStatBonus(
StatType.Dexterity, ModifierDescriptor.Morale, rankType: AbilityRankType.StatBonus,
multiplier: 2),
888 Helpers.CreateAddContextStatBonus(
StatType.Charisma, ModifierDescriptor.Morale, rankType: AbilityRankType.StatBonus,
multiplier: 2),
889 Helpers.CreateAddContextStatBonus(
StatType.SaveWill, ModifierDescriptor.Morale, rankType: AbilityRankType.StatBonus)
890 );
891
892 var area = library.CopyAndAdd<BlueprintAbilityAreaEffect>(
"7ced0efa297bd5142ab749f6e33b112b", "OverwhelmingExcitementAura", "");
893 area.Fx = Common.createPrefabLink("cda35ba5c34a61b499f5858eabcedec7");
//abjuration aoe
894
895 var in_area_effect = Helpers.CreateConditional(Helpers.
CreateConditionsCheckerOr(Helpers.Create<ContextConditionIsCaster>(),
896
Helpers.CreateConditionHasFact(fatigued),
897
Helpers.CreateConditionHasFact(exhausted),
898
Helpers.Create<ContextConditionIsEnemy>()
899
),
900 null,
901 Helpers.CreateConditional(
Common.createContextConditionCasterHasFact(rapture_str_con_buff),
902
Common.createContextActionApplyBuff(str_con_effect_buff, Helpers.
CreateContextDuration(), is_permanent: true, dispellable: false),
903
Helpers.CreateConditional(Common.createContextConditionCasterHasFact(
rapture_dex_cha_buff),
904
Common.createContextActionApplyBuff(dex_cha_effect_buff,
Helpers.CreateContextDuration(), is_permanent: true, dispellable: false)
905
)
906 )
907 );
908 area.ComponentsArray = new BlueprintComponent[]
909 {
910 Helpers.CreateAreaEffectRunAction(unitEnter: new GameAction[]{
in_area_effect },
911 round: new GameAction[]{
in_area_effect },
912 unitExit: new GameAction[]{Helpers.
CreateConditional(new Condition[]{Common.createContextConditionHasBuffFromCaster(
str_con_effect_buff) },
913
new GameAction[]{ Common.createContextActionApplyBuff(fatigued,
Helpers.CreateContextDuration(1, DurationRate.Minutes), dispellable: false),
914
Common.createContextActionRemoveBuffFromCaster(
str_con_effect_buff)
915
}
916
),
917 Helpers.
CreateConditional(new Condition[]{Common.createContextConditionHasBuffFromCaster(
dex_cha_effect_buff) },
918
new GameAction[]{ Common.createContextActionApplyBuff(fatigued,
Helpers.CreateContextDuration(1, DurationRate.Minutes), dispellable: false),
919
Common.createContextActionRemoveBuffFromCaster(
dex_cha_effect_buff)
920
}
921
),

922 }
923 )
924 };
925
926 var overwhelming_excitement_buff = Helpers.CreateBuff(
"OverwhelmingExcitementBuff",
927
str_con_effect_buff.Name,
928
str_con_effect_buff.Description,
929 "",
930
str_con_effect_buff.Icon,
931 null,
932 Common.
createAddAreaEffect(area),
933 Helpers.
CreateAddFactContextActions(activated: Common.createContextActionApplyBuff(
prevent_shared_conciousness_fact, Helpers.CreateContextDuration(), is_child: true,
dispellable: false, is_permanent: true))
934 );
935
936 var toggle = Common.buffToToggle(overwhelming_excitement_buff,
CommandType.Free, false,
937 rapture_resource.
CreateActivatableResourceLogic(ResourceSpendType.NewRound),
938 Helpers.Create<NewMechanics.
RestrictionHasFacts>(r => r.features = new BlueprintUnitFact[] {
rapture_str_con_buff, rapture_dex_cha_buff })
939 );
940
941 overwhelming_excitement = Common.ActivatableAbilityToFeature(toggle,
false);
942
943 Common.addContextActionApplyBuffOnConditionToActivatedAbilityBuffNoRemove
(rapture_str_con_buff,
944 Helpers.
CreateConditional(Common.createContextConditionHasFact(overwhelming_excitement),
945
null,
946
Common.createContextActionApplyBuff(prevent_shared_conciousness_fact,
Helpers.CreateContextDuration(), is_child: true, dispellable: false, is_permanent:
true)
947
)
948 );
949 rapture_share_str_con_buff = str_con_effect_buff;
950 rapture_share_dex_cha_buff = dex_cha_effect_buff;
951 }
952
953 static void createRapture()
954 {
955 rapture_resource = Helpers.CreateAbilityResource("RaptureResource", "",
"", "", null);
956 rapture_resource.SetIncreasedByLevel(0, 2, getSpiritualistArray());
957 rapture_resource.SetIncreasedByStat(2, StatType.Constitution);
958
959 perfect_passion = Helpers.CreateFeature("PerfectPassionFeature",
960 "Perfect Passion",
961 "At 4th level, an exciter can
cast psychic spells even while in his rapture. He can cast these spells defensively
and attempt concentration checks for these spells without impairment, despite being
in a rapture.",
962 "",
963 Helpers.GetIcon(
"ce7dad2b25acf85429b6c9550787b2d9"),
964 FeatureGroup.None
965 );
966
967
968 var rapture_casting_allowed_buff = Helpers.CreateBuff(
"RaptureCastingAllowedBuff",
969 "",
970 "",
971 "",
972 null,
973 null);
974 rapture_casting_allowed_buff.SetBuffFlags(BuffFlags.HiddenInUi);
975
976 var apply_allow_blood_casting = Common.createContextActionApplyBuff(
rapture_casting_allowed_buff, Helpers.CreateContextDuration(1), is_child: true,
dispellable: false);
977
978 var cast_only_on_self = Common.createContextActionApplyBuff(SharedSpells.
can_only_target_self_buff, Helpers.CreateContextDuration(), is_child: true,
dispellable: false, is_permanent: true);
979 var rapture_casting_buff = Helpers.CreateBuff("RaptureCastingBuff",
980 "Rapture Casting",
981 "Uupon entering a rapture,
exiter can apply the effects of a single spiritualist spell he knows to himself. The
spell must have a range of touch or personal, and it must be a 1st- or 2nd-level
spell. For every 3 spiritualist levels he has beyond 12th, the maximum spell level
of this spell increases by 1.",
982 "",
983 library.Get<BlueprintAbility
>("92681f181b507b34ea87018e8f7a528a").Icon,
984 null,
985 Helpers.Create<
TurnActionMechanics.FreeTouchOrPersonalSpellUseFromSpellbook>(f =>
986 {
987 f.allowed_spellbook =
spiritualist_class.Spellbook;
988 f.max_spell_level =
Helpers.CreateContextValue(AbilityRankType.Default);
989 f.control_buff =
rapture_casting_allowed_buff;
990 }
991 ),
992 Helpers.Create<
TurnActionMechanics.FreeTouchOrPersonalSpellUseFromSpellbook>(f =>
993 {
994 f.allowed_spellbook =
fractured_mind_spellbook;
995 f.max_spell_level =
Helpers.CreateContextValue(AbilityRankType.Default);
996 f.control_buff =
rapture_casting_allowed_buff;
997 }

998 ),
999 Helpers.
CreateContextRankConfig(baseValueType: ContextRankBaseValueType.ClassLevel,
1000
classes: getSpiritualistArray(),
1001
progression: ContextRankProgression.Custom,
1002
customProgression: new (int, int)[] { (14, 2), (17, 3), (20, 4) }
1003
),
1004 Helpers.
CreateAddFactContextActions(cast_only_on_self)
1005 );
1006
1007 var rapture_casting_ability = Helpers.CreateActivatableAbility(
"RaptureCastingToggleAbility",
1008
rapture_casting_buff.Name,
1009
rapture_casting_buff.Description,
1010 "",
1011
rapture_casting_buff.Icon,
1012
rapture_casting_buff,
1013
AbilityActivationType.Immediately,
1014 CommandType.
Free,
1015 null,
1016 Helpers.
Create<RestrictionHasFact>(r => r.Feature = rapture_casting_allowed_buff));
1017 rapture_casting_ability.DeactivateImmediately = true;
1018
1019 greater_rapture = Helpers.CreateFeature("GreaterRaptureFeature",
1020 "Greater Rapture",
1021 "At 12th level, an exciter increases the
morale bonus his rapture grants to each applicable ability score by 2 and the morale
bonus he gains on Will saves by 1.\n"
1022 + "In addition, upon entering a rapture, he
can apply the effects of a single spiritualist spell he knows to himself. The spell
must have a range of touch or personal, and it must be a 1st- or 2nd-level spell.
For every 3 spiritualist levels he has beyond 12th, the maximum spell level of this
spell increases by 1.",
1023 "",
1024 Helpers.GetIcon(
"df6a2cce8e3a9bd4592fb1968b83f730"), //rage
1025 FeatureGroup.None,
1026 Helpers.CreateAddFact(rapture_casting_ability)
1027 );
1028
1029
1030 var rapture_str_con_ability = library.CopyAndAdd<
BlueprintActivatableAbility>("df6a2cce8e3a9bd4592fb1968b83f730",
"RaptureStrConToggleAbility", "");
1031 rapture_str_con_ability.SetNameDescription("Rapture (Strength and
Constitution)",
1032 "An exciter gains the ability to
enter an ecstatic state in which he’s consumed and overwhelmed by his passions and
driven into a fighting fury. This functions similarly to a barbarian’s rage,
treating his spiritualist level as his barbarian level, though he doesn’t qualify
for feats or other elements that require rage or bloodrage. When entering a rapture,
the exciter loses all other benefits from having his phantom confined in his
consciousness (such as the Skill Focus feats and bonus against mind-affecting
effects). While in rapture Exciter receives +4 morale bonus to Strength,
Constitution and +2 morale bonus on Will saves instead of usual barbarian rage
bonuses, but he can choose to exchange the normal +4 morale bonus to his Strength
and Constitution scores for a +4 morale bonus to his Dexterity and Charisma."
1033 );
1034 rapture_str_con_ability.Group = ActivatableAbilityGroupExtension.Rage.
ToActivatableAbilityGroup();
1035 rapture_str_con_buff = library.CopyAndAdd<BlueprintBuff>(
"da8ce41ac3cd74742b80984ccc3c9613", "RaptureStrConBuff", "");
1036 rapture_str_con_buff.RemoveComponent(rapture_str_con_buff.GetComponent<
Kingmaker.UnitLogic.FactLogic.ForbidSpellCasting>());
1037 rapture_str_con_buff.AddComponent(Helpers.Create<NewMechanics.
ForbidSpellCastingUnlessHasFacts>(f => { f.ForbidMagicItems = true; f.allowed_facts =
new BlueprintUnitFact[] {perfect_passion}; }));
1038 rapture_str_con_buff.SetNameDescription(rapture_str_con_ability);
1039 rapture_str_con_ability.Buff.RemoveComponents<NewMechanics.
FeatureReplacement>();
1040 rapture_str_con_ability.Buff = rapture_str_con_buff;
1041 rapture_str_con_ability.ReplaceComponent<ActivatableAbilityResourceLogic
>(a => a.RequiredResource = rapture_resource);
1042 rapture_str_con_buff.ReplaceComponent<AddFactContextActions>(a =>
1043 {
1044 a.Activated = Helpers.CreateActionList(a.Activated.Actions.ToList().
ToArray().AddToArray(apply_allow_blood_casting));
1045 a.NewRound = Helpers.CreateActionList(a.NewRound.Actions.ToList().
ToArray());
1046 a.Deactivated = Helpers.CreateActionList(a.Deactivated.Actions.ToList
().ToArray());
1047 });
1048 rapture_str_con_buff.RemoveComponents<TemporaryHitPointsPerLevel>();
1049 rapture_str_con_buff.RemoveComponents<ContextRankConfig>();
1050 rapture_str_con_buff.RemoveComponents<AddContextStatBonus>();
1051 rapture_str_con_buff.RemoveComponents<WeaponAttackTypeDamageBonus>();
1052 rapture_str_con_buff.RemoveComponents<SpellDescriptorComponent>();
1053 rapture_str_con_buff.RemoveComponents<WeaponGroupDamageBonus>();
1054 rapture_str_con_buff.RemoveComponents<AttackTypeAttackBonus>();
1055 rapture_str_con_buff.AddComponents(Helpers.CreateAddContextStatBonus(
StatType.Constitution, ModifierDescriptor.Morale, rankType: AbilityRankType.StatBonus
, multiplier: 2),
1056 Helpers.CreateAddContextStatBonus(
StatType.Strength, ModifierDescriptor.Morale, rankType: AbilityRankType.StatBonus,
multiplier: 2),
1057 Helpers.CreateAddContextStatBonus(
StatType.SaveWill, ModifierDescriptor.Morale, rankType: AbilityRankType.StatBonus),
1058 Helpers.CreateAddStatBonus(StatType.AC
, -2, ModifierDescriptor.UntypedStackable),
1059 Helpers.CreateContextRankConfig(
ContextRankBaseValueType.FeatureList, ContextRankProgression.BonusValue, stepLevel: 2
, type: AbilityRankType.StatBonus,
1060
featureList: new BlueprintFeature[] { greater_rapture })
1061 );
1062
1063 var barbarian = library.Get<BlueprintCharacterClass>(
"f7d7eb166b3dd594fb330d085df41853");
1064 rapturous_rage = library.CopyAndAdd<BlueprintFeatureSelection>(
"28710502f46848d48b3f0d6132817c4e", "RapturousRageFeatureSelection", "");
1065 rapturous_rage.SetNameDescription("Rapturous Rage",
1066 "At 10th level and every 4
spiritualist levels thereafter, an exciter can select one rage power for which he
qualifies, treating his spiritualist level as his barbarian level for all purposes
relating to that particular rage power (he still doesn’t qualify for the Extra Rage
Power feat or any similar abilities).");
1067
1068 ClassToProgression.addClassToBuff(spiritualist_class, new
BlueprintArchetype[] {exciter }, rapture_str_con_buff, barbarian);
1069 foreach (var f in rapturous_rage.AllFeatures)
1070 {
1071 ClassToProgression.addClassToFeat(spiritualist_class, new
BlueprintArchetype[] {exciter}, ClassToProgression.DomainSpellsType.NoSpells, f,
barbarian);
1072 }
1073
1074 if (test_mode)
1075 {
1076 // allow to use rage out of combat for debug purposes
1077 rapture_str_con_ability.IsOnByDefault = false;
1078 rapture_str_con_ability.DeactivateIfCombatEnded = false;
1079 rapture_str_con_ability.IsOnByDefault = false;
1080 rapture_str_con_ability.DeactivateIfCombatEnded = false;
1081 }
1082
1083 rapture_dex_cha_buff = library.CopyAndAdd(rapture_str_con_buff,
"RaptureDexChaBuff", "");
1084 rapture_dex_cha_buff.SetIcon(Helpers.GetIcon(
"3553bda4d6dfe6344ad89b25f7be939a")); //transmutation physical ench dex
1085 rapture_dex_cha_buff.SetName("Rapture (Dexterity and Charisma)");
1086 rapture_dex_cha_buff.RemoveComponents<AddContextStatBonus>();
1087 rapture_dex_cha_buff.AddComponents(Helpers.CreateAddContextStatBonus(
StatType.Charisma, ModifierDescriptor.Morale, rankType: AbilityRankType.StatBonus,
multiplier: 2),
1088 Helpers.CreateAddContextStatBonus(StatType.
Dexterity, ModifierDescriptor.Morale, rankType: AbilityRankType.StatBonus, multiplier
: 2),
1089 Helpers.CreateAddContextStatBonus(StatType.
SaveWill, ModifierDescriptor.Morale, rankType: AbilityRankType.StatBonus, multiplier:
2)
1090 );
1091 var rapture_dex_cha_ability = library.CopyAndAdd(rapture_str_con_ability,
"RaptureDexChaAbility", "");
1092 rapture_dex_cha_ability.SetName(rapture_dex_cha_buff.Name);
1093 rapture_dex_cha_ability.SetIcon(rapture_dex_cha_buff.Icon);
1094 rapture_dex_cha_ability.Buff = rapture_dex_cha_buff;
1095
1096 rapture = Helpers.CreateFeature("RaptureFeature",
1097 "Rapture",
1098 rapture_str_con_ability.Description,
1099 "",
1100 rapture_str_con_ability.Icon,
1101 FeatureGroup.None,
1102 rapture_resource.CreateAddAbilityResource
(),
1103 Helpers.CreateAddFacts(
rapture_str_con_ability, rapture_dex_cha_ability),
1104 Common.createClassLevelsForPrerequisites(
barbarian, spiritualist_class)
1105 );
1106 }
1107
1108
1109 static void createMergedPhantom()
1110 {
1111 exciter_phantom_selection = Helpers.CreateFeatureSelection(
"ExciterPhantomFeatureSelection",
1112 "Merged Phantom",
1113 "An exciter internalizes his
phantom and merges it completely within his mind. He cannot fully manifest his
phantom outside of his own body in incorporeal or ectoplasmic form. Emotional focus
abilities that affect or require a manifested phantom are lost, except for phantom
ability gained at first level and aura gained by the phantom at 7th level; if the
phantom gains an aura at 7th level, this aura functions despite the phantom not
being manifested, and is centered on the exciter. If phantom ability augments only a
phantom's slam attack it augments all exiter's melee attacks instead.",
1114 "",
1115 null,
1116 FeatureGroup.AnimalCompanion
1117 );
1118
1119 foreach (var kv in Phantom.exciter_progressions)
1120 {
1121 exciter_phantom_selection.AllFeatures = exciter_phantom_selection.
AllFeatures.AddToArray(kv.Value);
1122 }
1123
1124
1125 exciter_potent_phantom = Helpers.CreateFeatureSelection(
"ExciterPotentPhantomFeatureSelection",
1126 "Potent Phantom",
1127 "At 20th level, the spiritualist’s
phantom grows ever more complex and sophisticated in its manifestation. The phantom
gains a second emotional focus. This does not change the phantom’s saving throws,
but the phantom otherwise grants all the skills and powers of the focus.",
1128 "",
1129 Helpers.GetIcon(
"c60969e7f264e6d4b84a1499fdcf9039"),
1130 FeatureGroup.None);
1131
1132 foreach (var kv in Phantom.potent_exciter_progressions)
1133 {
1134 exciter_potent_phantom.AllFeatures = exciter_potent_phantom.
AllFeatures.AddToArray(kv.Value);
1135 }
1136 }
1137
1138
1139 static void createOnmyoji()
1140 {
1141 onmyoji = Helpers.Create<BlueprintArchetype>(a =>
1142 {
1143 a.name = "OnmyojiArchetype";
1144 a.LocalizedName = Helpers.CreateString($"{a.name}.Name", "Onmyoji");
1145 a.LocalizedDescription = Helpers.CreateString($"{a.name}.Description"
, "Though most spiritualists are chosen by their phantoms, others deliberately call
phantoms to them through years of careful preparation and study in obscure divine
traditions.\n"
1146
+ "These spiritualists, known as onmyoji, form close bonds with their phantoms, as
any other spiritualist does, but see the phantoms as partners and tools in their
work. Onmyoji serve as emissaries between the mundane world and the spiritual one,
either working to ensure that troubles in the spiritual world do not spill over into
the world of mortals, or stirring up spiritual trouble in order to achieve their
ends among the living.");
1147 });
1148 Helpers.SetField(onmyoji, "m_ParentClass", spiritualist_class);
1149 library.AddAsset(onmyoji, "");
1150
1151 createOnmyojiSpellcasting();
1152 createDivineTeachings();
1153
1154
1155 onmyoji.RemoveFeatures = new LevelEntry[] { Helpers.LevelEntry(1,
spiritualist_spellcasting, shared_consciousness),
1156 Helpers.LevelEntry(4,
spiritual_inference),
1157 Helpers.LevelEntry(10,
fused_consciousness),
1158 Helpers.LevelEntry(12,
greater_spiritual_inference),};
1159 onmyoji.AddFeatures = new LevelEntry[] { Helpers.LevelEntry(1,
onmyoji_spellcasting),
1160 Helpers.LevelEntry(4,
divine_teachings),
1161 Helpers.LevelEntry(7,
divine_teachings),
1162 Helpers.LevelEntry(10,
divine_teachings),
1163 Helpers.LevelEntry(13,
divine_teachings),
1164 Helpers.LevelEntry(16,
divine_teachings),
1165 Helpers.LevelEntry(19,
divine_teachings),
1166 };
1167
1168 onmyoji.ReplaceSpellbook = onmyoji_spellbook;
1169 onmyoji.ChangeCasterType = true;
1170 onmyoji.IsDivineCaster = true;
1171 spiritualist_progression.UIDeterminatorsGroup = spiritualist_progression.
UIDeterminatorsGroup.AddToArray(onmyoji_spellcasting);
1172 Common.addMTDivineSpellbookProgression(spiritualist_class,
onmyoji_spellbook, "MysticTheurgeOnmyojiProgression",
1173 Common.
createPrerequisiteArchetypeLevel(onmyoji, 1),
1174 Common.
createPrerequisiteClassSpellLevel(spiritualist_class, 2)
1175 );
1176 }
1177
1178
1179 static void createScourge()
1180 {
1181 scourge = Helpers.Create<BlueprintArchetype>(a =>
1182 {
1183 a.name = "ScourgeArchetype";
1184 a.LocalizedName = Helpers.CreateString($"{a.name}.Name", "Scourge");
1185 a.LocalizedDescription = Helpers.CreateString($"{a.name}.Description"
, "Scourges are students of pain and have a rare connection to tormented and wracked
spirits. Scourges seek to share their phantoms’ miseries with all around them, using
the spirit’s pain as a weapon. A scourge’s phantom is a broken and wretched
creature, and the torments it suffered in life are reflected in its ghostly or
ectoplasmic appearance as wounds, scars, grotesque malformations, and tattered
garments.");
1186 });
1187 Helpers.SetField(scourge, "m_ParentClass", spiritualist_class);
1188 library.AddAsset(scourge, "");
1189
1190 createSpellScourge();
1191 createEctoplasmicSwarm();
1192
1193
1194 scourge.RemoveFeatures = new LevelEntry[] {Helpers.LevelEntry(4,
spiritual_inference),
1195 Helpers.LevelEntry(12,
greater_spiritual_inference),};
1196 scourge.AddFeatures = new LevelEntry[] {
1197 Helpers.LevelEntry(4,
spell_scourge),
1198 Helpers.LevelEntry(12,
ectoplasmic_swarm),
1199 };
1200
1201 spiritualist_progression.UIGroups = spiritualist_progression.UIGroups.
AddToArray(Helpers.CreateUIGroup(spell_scourge, ectoplasmic_swarm));
1202
1203 //fix phantoms
1204 foreach (var f in emotional_focus_selection.AllFeatures)
1205 {
1206 f.AddComponent(Common.prerequisiteNoArchetype(scourge));
1207 }
1208
1209 foreach (var kv in Phantom.pain_phantom_progressions)
1210 {
1211 kv.Value.AddComponent(Common.createPrerequisiteArchetypeLevel(scourge
, 1));
1212 kv.Value.SetDescription(kv.Value.Description + "\n" + Phantom.
endure_torment.Name + ": " + Phantom.endure_torment.Description + " This ability
replaces devotion.");
1213 emotional_focus_selection.AllFeatures = emotional_focus_selection.
AllFeatures.AddToArray(kv.Value);
1214 }
1215 }
1216
1217
1218 static void createEctoplasmicSwarm()
1219 {
1220 var spider_swarm_damage_effect_immunity = library.Get<BlueprintBuff>(
"1c63c2b0ea1f44940a63211fef462b98");
1221 var nauseted = library.Get<BlueprintBuff>(
"956331dba5125ef48afe41875a00ca0e");
1222 var apply_nauseted = Common.createContextActionApplyBuff(nauseted,
Helpers.CreateContextDuration(1));
1223 var dmg_phantom = Common.createRunActionsDependingOnContextValue(Helpers.
CreateContextValue(AbilityRankType.Default),
1224 Helpers.
CreateActionDealDirectDamage(Helpers.CreateContextDiceValue(DiceType.D6, 1, 0)),
1225 Helpers.
CreateActionDealDirectDamage(Helpers.CreateContextDiceValue(DiceType.D8, 1, 0)),
1226 Helpers.
CreateActionDealDirectDamage(Helpers.CreateContextDiceValue(DiceType.D10, 1, 0)),
1227 Helpers.
CreateActionDealDirectDamage(Helpers.CreateContextDiceValue(DiceType.D6, 2, 0)),
1228 Helpers.
CreateActionDealDirectDamage(Helpers.CreateContextDiceValue(DiceType.D8, 2, 0))
1229 );
1230
1231 var dmg_phantom_large = Common.createRunActionsDependingOnContextValue(
Helpers.CreateContextValue(AbilityRankType.Default),
1232 Helpers.
CreateActionDealDirectDamage(Helpers.CreateContextDiceValue(DiceType.D8, 1, 0)),
1233 Helpers.
CreateActionDealDirectDamage(Helpers.CreateContextDiceValue(DiceType.D6, 2, 0)),
1234 Helpers.
CreateActionDealDirectDamage(Helpers.CreateContextDiceValue(DiceType.D8, 2, 0)),
1235 Helpers.
CreateActionDealDirectDamage(Helpers.CreateContextDiceValue(DiceType.D6, 3, 0)),
1236 Helpers.
CreateActionDealDirectDamage(Helpers.CreateContextDiceValue(DiceType.D8, 3, 0))
1237 );
1238
1239 var dmg = Helpers.CreateConditional(Common.
createContextConditionCasterHasFact(Phantom.slam_damage_large),
1240 dmg_phantom_large,
1241 dmg_phantom);
1242
1243 var context_rank_config = Helpers.CreateContextRankConfig(baseValueType:
ContextRankBaseValueType.ClassLevel,
1244 type:
AbilityRankType.Default,
1245
progression: ContextRankProgression.StartPlusDivStep,
1246
startLevel: 1,
1247
stepLevel: 3,
1248
classes: Phantom.getPhantomArray());
1249
1250 var activated_actions = Helpers.CreateActionList(Helpers.Create<
ContextActionSwarmTarget>(),
1251 Common.
createContextActionApplyBuff(spider_swarm_damage_effect_immunity, Helpers.
CreateContextDuration(1)),
1252 dmg,
1253 Helpers.
CreateActionSavingThrow(SavingThrowType.Fortitude, Helpers.CreateConditionalSaved(
null, apply_nauseted))
1254 );
1255
1256
1257 var in_swarm_buff = Helpers.CreateBuff("EctoplasmicSwarmDamageEffectBuff",
1258 "",
1259 "",
1260 "",
1261 null,
1262 Common.createPrefabLink(
"4b31ab00d34d50845aa087a2a8bed63d"),
1263 Helpers.
CreateAddFactContextActions(activated: activated_actions.Actions,
1264
deactivated: new GameAction[] { Helpers.Create<ContextActionSwarmTarget>(c => c.
Remove = true) }
1265
),
1266 context_rank_config
1267 );
1268 in_swarm_buff.SetBuffFlags(BuffFlags.HiddenInUi);
1269 var swarm_buff = Common.createBuffAreaEffect(in_swarm_buff, 5.Feet(),
Helpers.CreateConditionsCheckerAnd(Helpers.Create<ContextConditionIsEnemy>()));
1270 swarm_buff.SetBuffFlags(BuffFlags.HiddenInUi);
1271
1272
1273 var swarm_attack = Helpers.CreateConditional(new Condition[] { Common.
createContextConditionHasBuffFromCaster(spider_swarm_damage_effect_immunity) },
1274 null,
1275 new GameAction
[]{dmg,
1276
Helpers.CreateActionSavingThrow(SavingThrowType.Fortitude, Helpers.
CreateConditionalSaved(null, apply_nauseted))
1277 }
1278 );
1279
1280 var attack_in_swarm = Helpers.Create<ContextActionSwarmAttack>(c => c.
AttackActions = Helpers.CreateActionList(Helpers.Create<ContextActionOnSwarmTargets>(
a => a.Actions = Helpers.CreateActionList(swarm_attack))));
1281 var swarm_attack_conditional = Helpers.CreateConditional(new Condition[]
{ Helpers.Create<ContextSwarmHasEnemiesInInnerCircle>() },
1282 new GameAction[]
{ attack_in_swarm,
1283
Helpers.Create<ContextActionPlaySound>(c => c.SoundName =
"SwarmMandragora_Attack_Voice")
1284
}
1285 );
1286
1287 swarm_buff.AddComponents(Helpers.CreateAddFactContextActions(newRound:
swarm_attack_conditional),
1288 context_rank_config);
1289
1290 var swarm_feature = Helpers.CreateFeature("EctoplasmicSwarmDamageFeature",
1291 "",
1292 "",
1293 "",
1294 null,
1295 FeatureGroup.None,
1296 Common.
createAuraFeatureComponent(swarm_buff),
1297 Common.
createContextCalculateAbilityParamsBasedOnClass(Phantom.phantom_class, StatType.
Constitution)
1298 );
1299 swarm_feature.HideInUI = true;
1300 swarm_feature.HideInCharacterSheetAndLevelUp = true;
1301
1302 var polymorph_component = library.Get<BlueprintBuff>(
"6ba1229b016317041b17f75e7b0fc686").GetComponent<Polymorph>().CreateCopy();
1303 polymorph_component.DexterityBonus = 8;
1304 polymorph_component.StrengthBonus = -10;
1305 polymorph_component.ConstitutionBonus = -2;
1306 polymorph_component.Size = Size.Diminutive;
1307 polymorph_component.Prefab = Common.createUnitViewLink(
"99a0fbddd76b4b147b1831d315a581cb");//mandragora swarm
1308 polymorph_component.MainHand = null;
1309 polymorph_component.OffHand = null;
1310 polymorph_component.NaturalArmor = 0;
1311 polymorph_component.AdditionalLimbs = new BlueprintItemWeapon[0];
1312 polymorph_component.SecondaryAdditionalLimbs = new BlueprintItemWeapon[0];
1313 polymorph_component.Facts = new BlueprintUnitFact[]
1314 {
1315 swarm_feature,
1316 library.Get<BlueprintFeature>("2e3e840ab458ce04c92064489f87ecc2")
//diminutive swarm
1317 };
1318
1319 var ectoplasmic_swarm_buff = Helpers.CreateBuff("EctoplasmicSwarmBuff",
1320 "Ectoplasmic Swarm",
1321 "At 12th level, as a
standard action, a scourge with a phantom manifested in ectoplasmic form can command
it to break apart in a gruesome display of gore and agony, transforming it into a
swarm of Diminutive ectoplasmic organs and viscera. The phantom gains the swarm
subtype, dealing its unmodified slam damage die as damage for its swarm attack. Its
distraction DC is equal to 10 + 1/2 the phantom’s Hit Dice + its Constitution
modifier. In this form, the phantom is too diffuse to use any of its abilities from
emotional focus (even passive abilities).",
1322 "",
1323 LoadIcons.Image2Sprite.
Create(@"AbilityIcons/EctoplasmicSwarm.png"),
1324 null,
1325 polymorph_component,
1326 Helpers.
CreateSpellDescriptor(SpellDescriptor.Polymorph),
1327 Helpers.Create<
AddCondition>(a => a.Condition = UnitCondition.CanNotAttack),
1328 Helpers.Create<
SpellFailureMechanics.UnableToUseAbilities>()
1329 );
1330 ectoplasmic_swarm_buff.SetBuffFlags(BuffFlags.RemoveOnRest);
1331
1332 var apply_polymorph = Common.createContextActionApplyBuff(
ectoplasmic_swarm_buff, Helpers.CreateContextDuration(), is_permanent: true,
dispellable: false);
1333 var precast_action = Helpers.Create<ContextActionsOnPet>(c => c.Actions =
Helpers.CreateActionList(Common.createContextActionRemoveBuffsByDescriptor(
SpellDescriptor.Polymorph)));
1334 var ectoplasmic_swarm_ability = Helpers.CreateAbility(
"EctoplasmicSwarmAbility",
1335
ectoplasmic_swarm_buff.Name,
1336
ectoplasmic_swarm_buff.Description,
1337 "",
1338
ectoplasmic_swarm_buff.Icon,
1339 AbilityType.
Supernatural,
1340 CommandType.
Standard,
1341 AbilityRange.
Personal,
1342 "",
1343 "",
1344 Helpers.
CreateRunActions(Helpers.Create<ContextActionsOnPet>(c => c.Actions = Helpers.
CreateActionList(apply_polymorph))),
1345 Common.
createAbilityExecuteActionOnCast(Helpers.CreateActionList(precast_action)),
1346 Helpers.Create<
NewMechanics.AbilityCasterCompanionDead>(a => a.not = true),
1347 Helpers.Create<
CompanionMechanics.AbilityCasterCompanionHasFact>(a => { a.fact =
ectoplasmic_swarm_buff; a.not = true; })
1348 );
1349 ectoplasmic_swarm_ability.setMiscAbilityParametersSelfOnly();
1350
1351 var ectoplasmic_swarm_ability_remove = Helpers.CreateAbility(
"EctoplasmicSwarmRemoveAbility",
1352 "Deactivate " +
ectoplasmic_swarm_buff.Name,
1353 ectoplasmic_swarm_buff.
Description,
1354 "",
1355 ectoplasmic_swarm_buff.Icon,
1356 AbilityType.Supernatural,
1357 CommandType.Standard,
1358 AbilityRange.Personal,
1359 "",
1360 "",
1361 Helpers.CreateRunActions(
Helpers.Create<ContextActionsOnPet>(c => c.Actions = Helpers.CreateActionList(Common.
createContextActionRemoveBuff(ectoplasmic_swarm_buff)))),
1362 Helpers.Create<
CompanionMechanics.AbilityCasterCompanionHasFact>(a => a.fact =
ectoplasmic_swarm_buff)
1363 );
1364
1365 var wrapper = Common.createVariantWrapper("EctoplasmicswarmAbilityBase",
"", ectoplasmic_swarm_ability, ectoplasmic_swarm_ability_remove);
1366 ectoplasmic_swarm = Common.AbilityToFeature(wrapper, false);
1367 }
1368
1369
1370 static void createSpellScourge()
1371 {
1372 var spell_scourge_attack_buff = Helpers.CreateBuff(
"SpellScourgePhantomAttackBuff",
1373 "Spell Scourge",
1374 "At 4th level, when a
scourge’s phantom damages a creature, it causes severe pain, requiring that creature
to succeed at a concentration check (DC = 15 + spell level) to use spells,
spell-like abilities, and other abilities that require concentration for 1 round.\n"
1375 + "The phantom gains a
+2 bonus on attack and damage rolls when making attacks of opportunity. Any creature
threatened by the scourge’s phantom takes a –5 penalty on concentration checks.",
1376 "",
1377 NewSpells.
fleshworm_infestation.Icon,
1378 null,
1379 Helpers.Create<
AddCondition>(a => a.Condition = UnitCondition.SpellCastingIsDifficult),
1380 Helpers.
CreateSpellDescriptor((SpellDescriptor)AdditionalSpellDescriptors.
ExtraSpellDescriptor.Pain)
1381 );
1382
1383 var spell_scourge_aura_buff = Helpers.CreateBuff(
"SpellScourgeAuraEffectBuff",
1384 "Spell Scourge Concentration
Penalty",
1385 spell_scourge_attack_buff.
Description,
1386 "",
1387 spell_scourge_attack_buff.Icon,
1388 null,
1389 Helpers.Create<ConcentrationBonus>(
c => c.Value = -5)
1390 );
1391
1392 var spell_scourge_phantom = Common.createAuraEffectFeature(
spell_scourge_attack_buff.Name, spell_scourge_attack_buff.Description,
spell_scourge_attack_buff.Icon,
1393
spell_scourge_aura_buff, 10.Feet(), Helpers.CreateConditionsCheckerAnd(Helpers.Create
<ContextConditionIsEnemy>())
1394 );
1395 spell_scourge_phantom.AddComponents(Common.
createAttackBonusOnAttacksOfOpportunity(2, ModifierDescriptor.UntypedStackable),
1396 Helpers.Create<NewMechanics.
AttackOfOpportunityDamgeBonus>(a => { a.value = 2; a.descriptor = ModifierDescriptor.
UntypedStackable; }),
1397 Helpers.Create<
AddOutgoingDamageTrigger>(a =>
1398 {
1399 a.NotZeroDamage = true;
1400 a.ApplyToAreaEffectDamage = true;
1401 a.Actions = Helpers.
CreateActionList(Common.createContextActionApplyBuff(spell_scourge_attack_buff,
Helpers.CreateContextDuration(1), dispellable: false));
1402 }
1403 )
1404 );
1405 spell_scourge = Common.createAddFeatToAnimalCompanion(
spell_scourge_phantom, "");
1406 }
1407
1408
1409 static void createFracturedMind()
1410 {
1411 fractured_mind = Helpers.Create<BlueprintArchetype>(a =>
1412 {
1413 a.name = "FracturedMindArchetype";
1414 a.LocalizedName = Helpers.CreateString($"{a.name}.Name", "Fractured
Mind");
1415 a.LocalizedDescription = Helpers.CreateString($"{a.name}.Description"
, "Most spiritualists harbor the spirits of the deceased in their psyches, but a
small number of them—known as fractured minds—draw their powers instead from a
fraction of their own souls that resonates with extremely powerful emotions. These
spiritualists’ phantoms are not spiritual allies, but rather extensions of the
fractured minds’ own inner thoughts and emotions.");
1416 });
1417 Helpers.SetField(fractured_mind, "m_ParentClass", spiritualist_class);
1418 library.AddAsset(fractured_mind, "");
1419
1420 createFracturedMindSpellcasting();
1421
1422
1423 fractured_mind.RemoveFeatures = new LevelEntry[] {Helpers.LevelEntry(1,
spiritualist_spellcasting)};
1424 fractured_mind.AddFeatures = new LevelEntry[] {Helpers.LevelEntry(1,
charisma_spellcasting) };
1425 fractured_mind.ReplaceSpellbook = fractured_mind_spellbook;
1426
1427 spiritualist_progression.UIDeterminatorsGroup = spiritualist_progression.
UIDeterminatorsGroup.AddToArray(charisma_spellcasting);
1428 }
1429
1430 static void createOnmyojiSpellcasting()
1431 {
1432 onmyoji_spellbook = library.CopyAndAdd(spiritualist_class.Spellbook,
"OnmyojiSpellbook", "");
1433 onmyoji_spellbook.IsArcane = false;
1434 onmyoji_spellbook.Name = onmyoji.LocalizedName;
1435 onmyoji_spellbook.CantripsType = CantripsType.Orisions;
1436 onmyoji_spellbook.RemoveComponents<SpellbookMechanics.PsychicSpellbook>();
1437
1438 onmyoji_spellcasting = Helpers.CreateFeature("OnmyojiSpellcastingFeature",
1439 "Divine Spellcasting",
1440 "An onmyoji’s spellcasting
ability comes from divine rather than psychic power. As a divine caster, the
onmyoji’s spells use verbal components instead of thought components, and somatic
components instead of emotional components, and she uses an ofuda as a divine focus.
Ofudas are scrolls with holy writings written on parchment, cloth, or wood (having
the same cost as a wooden holy symbol) or metal (having the same cost as a silver
holy symbol).",
1441 "",
1442 Helpers.GetIcon(
"90e59f4a4ada87243b7b3535a06d0638"), //bless
1443 FeatureGroup.None,
1444 Helpers.Create<
SpellbookMechanics.AddUndercastSpells>(p => p.spellbook = onmyoji_spellbook)
1445 );
1446
1447 onmyoji_spellcasting.AddComponents(Common.createCantrips(
spiritualist_class, StatType.Wisdom, onmyoji_spellbook.SpellList.SpellsByLevel[0].
Spells.ToArray()));
1448 onmyoji_spellcasting.AddComponent(Helpers.CreateAddFacts(
onmyoji_spellbook.SpellList.SpellsByLevel[0].Spells.ToArray()));
1449 }
1450
1451
1452 static void createFracturedMindSpellcasting()
1453 {
1454 fractured_mind_spellbook = library.CopyAndAdd(spiritualist_class.
Spellbook, "FracturedMindSpellbook", "");
1455 fractured_mind_spellbook.CastingAttribute = StatType.Charisma;
1456 fractured_mind_spellbook.Name = fractured_mind.LocalizedName;
1457
1458 charisma_spellcasting.AddComponent(Helpers.Create<SpellbookMechanics.
AddUndercastSpells>(p => p.spellbook = fractured_mind_spellbook));
1459
1460 charisma_spellcasting.AddComponents(Common.createCantrips(
spiritualist_class, StatType.Charisma, fractured_mind_spellbook.SpellList.
SpellsByLevel[0].Spells.ToArray()));
1461 charisma_spellcasting.AddComponent(Helpers.CreateAddFacts(
fractured_mind_spellbook.SpellList.SpellsByLevel[0].Spells.ToArray()));
1462 }
1463
1464
1465
1466
1467
1468 static void createDivineTeachings()
1469 {
1470 var icon = library.Get<BlueprintAbility>(
"f2115ac1148256b4ba20788f7e966830").Icon; //restoration
1471 divine_teachings = Helpers.CreateFeatureSelection(
"DivineTeachingsFeatureSelection",
1472 "Divine Teachings",
1473 "An onmyoji gains the
ability to call upon her phantom to help her cast spells she normally couldn’t. At
4th level and every 3 levels thereafter, an onmyoji can choose a single spell from
the cleric spell list with a spell level she is currently able to cast, and add that
spell to her list of spells known, at the same spell level as it appears on the
cleric spell list.",
1474 "",
1475 icon,
1476 FeatureGroup.None);
1477
1478 var cleric_spell_list = Common.combineSpellLists(
"DivineTeachingsSpellList", library.Get<BlueprintSpellList>(
"8443ce803d2d31347897a3d85cc32f53"));
1479 Common.excludeSpellsFromList(cleric_spell_list, spiritualist_class.
Spellbook.SpellList);
1480 for (int i = 1; i <= 6; i++)
1481 {
1482 var learn_spell = library.CopyAndAdd<BlueprintParametrizedFeature>(
"bcd757ac2aeef3c49b77e5af4e510956", $"DivineTeachings{i}ParametrizedFeature", "");
1483 learn_spell.SpellLevel = i;
1484 learn_spell.SpecificSpellLevel = true;
1485 learn_spell.SpellLevelPenalty = 0;
1486 learn_spell.SpellcasterClass = spiritualist_class;
1487 learn_spell.SpellList = cleric_spell_list;
1488 learn_spell.ReplaceComponent<LearnSpellParametrized>(l => { l.
SpellList = cleric_spell_list; l.SpecificSpellLevel = true; l.SpellLevel = i; l.
SpellcasterClass = spiritualist_class; });
1489 learn_spell.AddComponent(Common.createPrerequisiteClassSpellLevel(
spiritualist_class, i));
1490 learn_spell.SetName(Helpers.CreateString( $
"DivineTeachingsParametrizedFeature{i}.Name", "Divine Teachings " + $"(Level {i})"));
1491 learn_spell.SetDescription(divine_teachings.Description);
1492 learn_spell.SetIcon(divine_teachings.Icon);
1493
1494 divine_teachings.AllFeatures = divine_teachings.AllFeatures.
AddToArray(learn_spell);
1495 }
1496 }
1497
1498
1499
1500 static void createHagHaunted()
1501 {
1502 hag_haunted = Helpers.Create<BlueprintArchetype>(a =>
1503 {
1504 a.name = "HagHauntedArchetype";
1505 a.LocalizedName = Helpers.CreateString($"{a.name}.Name",
"Hag-Haunted");
1506 a.LocalizedDescription = Helpers.CreateString($"{a.name}.Description"
, "Hags—those of flesh and blood, at any rate—die like any other mortals, and their
souls normally depart to the Outer Planes for judgment. A hag who dies with a curse
on her breath is often anchored to the Ethereal Plane by the power of her hatred
—similar to vile and angry mortal souls—and some even claw their way back to the
living world through the souls of those they despised or ruined… or those
unfortunate souls they birthed. Hag-haunted spiritualists are tethered to these
spiteful spirits, anchoring them once again in the world of the living. While this
partnership imparts powerful magic, they run the constant risk of serving as little
more than mounts for their overwhelming phantoms.\n"
1507
+ "Hag-haunted spiritualists are rarely the masters in their relationship with
their phantoms, and the only tool at their disposal to control their wicked minion
is to dismiss them back to the Ethereal Plane. In the best scenarios, the
relationship is one of mutual competition and constant bargaining, but just as often
the hag phantom dominates and abuses her spiritualist.");
1508 });
1509 Helpers.SetField(hag_haunted, "m_ParentClass", spiritualist_class);
1510 library.AddAsset(hag_haunted, "");
1511
1512 createHagSpellcasting();
1513 createHagPhantom();
1514 createHagSharedConsciousnessAndFusedConsciousness();
1515 createHagDeathCurse();
1516
1517 hag_haunted.RemoveFeatures = new LevelEntry[] { Helpers.LevelEntry(1,
spiritualist_spellcasting, shared_consciousness, masters_alignment),
1518 Helpers.LevelEntry(4,
spiritual_inference),
1519 Helpers.LevelEntry(10,
fused_consciousness),
1520 Helpers.LevelEntry(12,
greater_spiritual_inference),};
1521 hag_haunted.AddFeatures = new LevelEntry[] { Helpers.LevelEntry(1,
hag_spell_casting, hag_phantom, hag_shared_consciousness),
1522 Helpers.LevelEntry(7,
hag_curse7),
1523 Helpers.LevelEntry(10,
hag_fused_consciousness),
1524 Helpers.LevelEntry(12,
hag_fused_consciousness12),
1525 Helpers.LevelEntry(13,
hag_curse13),
1526 };
1527
1528 hag_haunted.ReplaceSpellbook = hag_haunted_spellbook;
1529 hag_haunted.ChangeCasterType = true;
1530 hag_haunted.IsArcaneCaster = true;
1531 spiritualist_progression.UIDeterminatorsGroup = spiritualist_progression.
UIDeterminatorsGroup.AddToArray(hag_spell_casting, hag_phantom);
1532 spiritualist_progression.UIGroups = spiritualist_progression.UIGroups.
AddToArray(Helpers.CreateUIGroup(hag_shared_consciousness, hag_curse7,
hag_fused_consciousness, hag_curse13));
1533
1534 //add to prestige classes
1535 Common.addReplaceSpellbook(Common.EldritchKnightSpellbookSelection,
hag_haunted_spellbook, "EldritchKnightHagHaunted",
1536 Common.createPrerequisiteArchetypeLevel(hag_haunted, 1),
1537 Common.createPrerequisiteClassSpellLevel(spiritualist_class
, 3));
1538 Common.addReplaceSpellbook(Common.ArcaneTricksterSelection,
hag_haunted_spellbook, "ArcaneTricksterHagHaunted",
1539 Common.createPrerequisiteArchetypeLevel(
hag_haunted, 1),
1540 Common.createPrerequisiteClassSpellLevel(
spiritualist_class, 2));
1541 Common.addReplaceSpellbook(Common.MysticTheurgeArcaneSpellbookSelection,
hag_haunted_spellbook, "MysticTheurgeHagHaunted",
1542 Common.createPrerequisiteArchetypeLevel(
hag_haunted, 1),
1543 Common.createPrerequisiteClassSpellLevel(
spiritualist_class, 2));
1544 Common.addReplaceSpellbook(Common.DragonDiscipleSpellbookSelection,
hag_haunted_spellbook, "DragonDiscipleHagHaunted",
1545 Common.createPrerequisiteArchetypeLevel(
hag_haunted, 1),
1546 Common.createPrerequisiteClassSpellLevel(
spiritualist_class, 1));
1547 }
1548
1549
1550 static void createHagDeathCurse()
1551 {
1552 var bestow_curse = library.Get<BlueprintAbility>(
"989ab5c44240907489aba0a8568d0603");
1553 hag_curse7 = Helpers.CreateFeature("HagDeathCurse7Feature",
1554 "Death Curse",
1555 "At 7th level, the spiritualist gains
bestow curse as an extra 3rd-level spell known.",
1556 "",
1557 bestow_curse.Icon,
1558 FeatureGroup.None,
1559 Helpers.CreateAddKnownSpell(
bestow_curse, spiritualist_class, 3)
1560 );
1561
1562 hag_curse13 = Helpers.CreateFeature("HagDeathCurse16Feature",
1563 "Death Curse II",
1564 "At 13th level, the spiritualist gains major
curse as an additional 5th-level spell known.",
1565 "",
1566 bestow_curse.Icon,
1567 FeatureGroup.None,
1568 Helpers.CreateAddKnownSpell(NewSpells.curse_major,
spiritualist_class, 5)
1569 );
1570
1571 }
1572
1573
1574 static void createHagSpellcasting()
1575 {
1576 hag_haunted_spellbook = library.CopyAndAdd(spiritualist_class.Spellbook,
"HagHauntedSpellbook", "");
1577 hag_haunted_spellbook.IsArcane = true;
1578 hag_haunted_spellbook.Name = hag_haunted.LocalizedName;
1579 hag_haunted_spellbook.CantripsType = CantripsType.Cantrips;
1580 hag_haunted_spellbook.RemoveComponents<SpellbookMechanics.
PsychicSpellbook>();
1581
1582 hag_spell_casting = Helpers.CreateFeature("HagSpellcastingFeature",
1583 "Hag Spellcasting",
1584 "A hag-haunted spiritualist’s
spells come from her connection to her hag phantom. Her spells are considered arcane
rather than psychic, and they use verbal and somatic components instead of thought
and emotion components. She still selects her spells known from the spiritualist
class list.\n"
1585 + "A hag-haunted can cast
spiritualist spells while wearing light armor without incurring the normal arcane
spell failure chance. Like any other arcane spellcaster, a hag-haunted wearing
medium or heavy armor incurs a chance of arcane spell failure.",
1586 "",
1587 Helpers.GetIcon(
"55edf82380a1c8540af6c6037d34f322"),
1588 FeatureGroup.None,
1589 Common.
createArcaneArmorProficiency(ArmorProficiencyGroup.Light),
1590 Helpers.Create<
SpellbookMechanics.AddUndercastSpells>(p => p.spellbook = hag_haunted_spellbook)
1591 );
1592 hag_spell_casting.AddComponents(Common.createCantrips(spiritualist_class,
StatType.Wisdom, hag_haunted_spellbook.SpellList.SpellsByLevel[0].Spells.ToArray()));
1593 hag_spell_casting.AddComponent(Helpers.CreateAddFacts(
hag_haunted_spellbook.SpellList.SpellsByLevel[0].Spells.ToArray()));
1594 }
1595
1596
1597 static void createHagSharedConsciousnessAndFusedConsciousness()
1598 {
1599 var spell_focus = library.Get<BlueprintParametrizedFeature>(
"16fa59cc9a72a6043b566b49184f53fe");
1600 var spell_focus_greater = library.Get<BlueprintParametrizedFeature>(
"5b04b45b228461c43bad768eb0f7c7bf");
1601 var skill_focus_persuasion = library.Get<BlueprintFeature>(
"1621be43793c5bb43be55493e9c45924");
1602 hag_shared_consciousness = Helpers.CreateFeature(
"HagSharedConsciousnessFeature",
1603 "Shared Consciousness",
1604 "When in the spiritualist’s
consciousness, the hag phantom can grant the hag-haunted Spell Focus (necromancy)
and Skill Focus (persuasion), but she often revokes them if the spiritualist
banishes her there as a punishment, and she might use them as leverage to get what
she wants.",
1605 "",
1606 Helpers.GetIcon(
"b48674cef2bff5e478a007cf57d8345b"),
1607 FeatureGroup.None);
1608
1609 hag_fused_consciousness = Helpers.CreateFeature(
"HagFusedConsciousnessFeature",
1610 "Fused Consciousness",
1611 "When the spiritualist reaches 10th
level, the hag can also grant Spell Focus (necromancy) and Skill Focus (persuasion)
while manifested, and when the spiritualist reaches 12th level, she can also grant
Greater Spell Focus (necromancy).",
1612 "",
1613 Helpers.GetIcon(
"b48674cef2bff5e478a007cf57d8345b"),
1614 FeatureGroup.None,
1615 Common.createAddParametrizedFeatures(
spell_focus, SpellSchool.Necromancy),
1616 Common.createAddFeatureIfHasFact(
skill_focus_persuasion, skill_focus_persuasion, not: true),
1617 Common.
createContextSavingThrowBonusAgainstDescriptor(Helpers.CreateContextValue(
AbilityRankType.Default), ModifierDescriptor.UntypedStackable, SpellDescriptor.
MindAffecting),
1618 Helpers.CreateContextRankConfig
(ContextRankBaseValueType.ClassLevel, classes: getSpiritualistArray(),
1619
progression: ContextRankProgression.Custom,
1620
customProgression: new (int, int)[] { (11, 4), (20, 8) })
1621
1622 );
1623
1624 var shared_consciousness_buff = Helpers.CreateBuff(
"HagSharedConsciousnessBuff",
1625 hag_shared_consciousness.Name,
1626 hag_shared_consciousness.
Description,
1627 "",
1628 hag_shared_consciousness.Icon,
1629 null,
1630 hag_fused_consciousness.
ComponentsArray
1631 );
1632
1633 hag_fused_consciousness12 = Helpers.CreateFeature(
"HagFusedConsciousness12Feature",
1634 "",
1635 "",
1636 "",
1637 null,
1638 FeatureGroup.None,
1639 Common.
createAddParametrizedFeatures(spell_focus_greater, SpellSchool.Necromancy)
1640 );
1641 hag_fused_consciousness12.HideInCharacterSheetAndLevelUp = true;
1642 hag_fused_consciousness12.HideInUI = true;
1643 Common.addContextActionApplyBuffOnConditionToActivatedAbilityBuffNoRemove
(unsummon_buff,
1644
Helpers.CreateConditional(Common.createContextConditionHasFact(
hag_fused_consciousness, has: false),
1645
Helpers.CreateConditional(Common.
createContextConditionHasFact(hag_shared_consciousness, has: true),
1646
Common.createContextActionApplyBuff(
shared_consciousness_buff, Helpers.CreateContextDuration(), is_child: true,
is_permanent: true, dispellable: false)
1647
)
1648
)
1649
);
1650 }
1651
1652
1653 static void createHagPhantom()
1654 {
1655 var hag_phantom_feature = Helpers.CreateFeature("HagPhantomFeature",
1656 "Hag Phantom",
1657 "A hag phantom forms
from the soul of a deceased hag. She always has an evil alignment, rather than
matching the spiritualist’s alignment, and must select one of the following
emotional focuses: anger, hatred, or zeal. The hag phantom starts with a +2 bonus to
Strength and Intelligence and has her own agenda—usually contrary to the
spiritualist’s—though she recognizes that the spiritualist can unmanifest her, and
therefore she typically hides suspicious actions from her spiritualist.",
1658 "",
1659 NewSpells.howling_agony.
Icon,
1660 FeatureGroup.None,
1661 Helpers.
CreateAddStatBonus(StatType.Strength, 2, ModifierDescriptor.Racial),
1662 Helpers.
CreateAddStatBonus(StatType.Intelligence, 2, ModifierDescriptor.Racial)
1663 );
1664
1665 hag_phantom = Common.createAddFeatToAnimalCompanion("Spiritualist",
hag_phantom_feature, "");
1666 hag_phantom.AddComponent(Helpers.Create<CompanionMechanics.
ChangeCompanionAlignment>(c => c.alignment = Alignment.NeutralEvil));
1667
1668 var allowed_foci = new string[] { "Anger", "Hatred", "Zeal" };
1669
1670 foreach (var kv in Phantom.phantom_progressions)
1671 {
1672 if (!allowed_foci.Contains(kv.Key))
1673 {
1674 kv.Value.AddComponent(Common.prerequisiteNoArchetype(hag_haunted
));
1675 Phantom.potent_phantom[kv.Key].AddComponent(Common.
prerequisiteNoArchetype(hag_haunted));
1676 }
1677 }
1678
1679 }
1680
1681
1682
1683 public static BlueprintCharacterClass[] getSpiritualistArray()
1684 {
1685 return new BlueprintCharacterClass[] { spiritualist_class };
1686 }
1687
1688
1689 static void createSpiritualistProgression()
1690 {
1691 charisma_spellcasting = Helpers.CreateFeature(
"SpiritualistCharismaSpellcasting",
1692 "Emotional Spellcasting",
1693 "A fractured mind’s
ability to cast spells is tied to the force of her own spirit rather than her
connection to the spirit world. As a result, she uses her Charisma score rather than
her Wisdom score to determine the highest spell level she can cast, the saving throw
DCs of spells and spell-like abilities she casts, and her bonus spells per day.",
1694 "",
1695 null,
1696 FeatureGroup.None
1697 );
1698
1699
1700
1701 createSpiritualistProficiencies();
1702 createSpiritualistKnacks();
1703 createPhantom(); //add fractured mind emotional power instead of spell
like abilities
1704 createSummonUnsummonPhantom();
1705 //createLink(); //not sure if this one is needed since phantom are
already weeker than
1706 createEthericTether();
1707 createSpiritualBond();
1708 createSharedAndFusedConsciousness();
1709 createBondedManifestationAndDualBond();
1710 createSpiritualInferenceAndGreaterSpiritualInference();
1711 createPhantomRecall();
1712 createPotentPhantom();
1713
1714 var detect_magic = library.Get<BlueprintFeature>(
"ee0b69e90bac14446a4cf9a050f87f2e");
1715
1716 spiritualist_progression = Helpers.CreateProgression(
"SpiritualistProgression",
1717 spiritualist_class.Name,
1718 spiritualist_class.
Description,
1719 "",
1720 spiritualist_class.Icon,
1721 FeatureGroup.None);
1722 spiritualist_progression.Classes = getSpiritualistArray();
1723
1724 spiritualist_progression.LevelEntries = new LevelEntry[] {Helpers.
LevelEntry(1, spiritualist_proficiencies, spiritualist_spellcasting, detect_magic,
1725
spiritualist_knacks, emotional_focus_selection, etheric_tether,
shared_consciousness, /*link,*/
1726
masters_alignment,
1727
library.Get<BlueprintFeature>("d3e6275cfa6e7a04b9213b7b292a011c"), // ray
calculate feature
1728
library.Get<BlueprintFeature>("62ef1cdb90f1d654d996556669caf7fa")), // touch
calculate
feature

1729 Helpers.
LevelEntry(2),
1730 Helpers.
LevelEntry(3, bonded_manifestation),
1731 Helpers.
LevelEntry(4, spiritual_inference),
1732 Helpers.
LevelEntry(5),
1733 Helpers.
LevelEntry(6, phantom_recall),
1734 Helpers.
LevelEntry(7),
1735 Helpers.
LevelEntry(8),
1736 Helpers.
LevelEntry(9),
1737 Helpers.
LevelEntry(10, fused_consciousness),
1738 Helpers.
LevelEntry(11),
1739 Helpers.
LevelEntry(12, greater_spiritual_inference),
1740 Helpers.
LevelEntry(13),
1741 Helpers.
LevelEntry(14, spiritual_bond),
1742 Helpers.
LevelEntry(15),
1743 Helpers.
LevelEntry(16),
1744 Helpers.
LevelEntry(17, dual_bond),
1745 Helpers.
LevelEntry(18),
1746 Helpers.
LevelEntry(19),
1747 Helpers.
LevelEntry(20, potent_phantom)
1748 };
1749
1750 spiritualist_progression.UIDeterminatorsGroup = new BlueprintFeatureBase
[] { spiritualist_proficiencies, spiritualist_spellcasting, detect_magic,
1751
spiritualist_knacks, emotional_focus_selection };
1752 spiritualist_progression.UIGroups = new UIGroup[] {Helpers.CreateUIGroup
(etheric_tether, spiritual_inference, phantom_recall, spiritual_bond,
greater_spiritual_inference, potent_phantom),
1753 Helpers.CreateUIGroup(
shared_consciousness, bonded_manifestation, fused_consciousness, dual_bond)
1754 };
1755 }
1756
1757
1758 static void createBondedManifestationAndDualBond()
1759 {
1760 var bonded_manifestation_ac_fcb = Helpers.CreateFeature(
"BondedManifestationShiledAcFavoredClassBonusFeature",
1761 "Bonded Manifestation Shield AC
Bonus",
1762 "Add 1/6 to the shield bonus granted
by the 3rd-level bonded manifestation ability.",
1763 "9aaf6f154e3e4022884715cce4e665f7",
1764 NewSpells.barrow_haze.Icon,
1765 FeatureGroup.None);
1766 bonded_manifestation_ac_fcb.Ranks = 3;
1767
1768
1769 var bonded_manifestation_buff = Helpers.CreateBuff(
"BondedManifestationBuff",
1770 "Bonded Manifestation",
1771 "At 3rd level, as a
swift action, a spiritualist can pull on the consciousness of her phantom and the
substance of the Ethereal Plane to partially manifest aspects of both in her own
body. When she does, she uses this bonded manifestation to enhance her own abilities
while the phantom is still bound to her consciousness.\n"
1772 + "For the
spiritualist to use this ability, the phantom must be confined in the spiritualist’s
consciousness; it can’t be manifested in any other way.\n"
1773 + "During a bonded
manifestation, the phantom can’t be damaged, dismissed, or banished. A spiritualist
can use bonded manifestation a number of rounds per day equal to 3 + her
spiritualist level. The rounds need not be consecutive. She can dismiss the effects
of a bonded manifestation as a free action, but even if she dismisses a bonded
manifestation on the same round that she used it, it counts as 1 round of use.\n"
1774 + "Spiritualist gains
an ectoplasmic shield that protects her without restricting her movement or actions.
She gains a +4 shield bonus to Armor Class; this bonus applies to incorporeal touch
attacks.\n"
1775 + "The ectoplasmic
shield has no armor check penalty or arcane spell failure chance. At 8th level, the
spiritualist also sprouts a pair of ectoplasmic tendrils from her body. As a swift
action, the spiritualist can use these tendrils to attack creatures within her melee
reach (using the damage dice of her manifested phantom).\n"
1776 + "At 13th level, the
bonus from ectoplasmic shield increases to +6. At 18th level, the spiritualist can
take a full-round action to attack all creatures within her melee reach with her
tendrils (using the damage dice of her manifested phantom). When she does, she rolls
the attack roll twice and takes the better of the two results.",
1777 "",
1778 NewSpells.barrow_haze.
Icon,
1779 Common.
createPrefabLink("e9a8af06810719e4d9885c10c827b131"), //from ghost form
1780 Helpers.Create<
AddContextStatBonus>(a =>
1781 {
1782 a.Descriptor =
ModifierDescriptor.Shield;
1783 a.Stat = StatType.
AC;
1784 a.Value = Helpers.
CreateContextValue(AbilitySharedValue.StatBonus);
1785 a.Multiplier = 1;
1786 }
1787 ),
1788 Helpers.
CreateCalculateSharedValue(Helpers.CreateContextDiceValue(DiceType.One, Helpers.
CreateContextValue(AbilityRankType.StatBonus), Helpers.CreateContextValue(
AbilityRankType.Default)), AbilitySharedValue.StatBonus),
1789 Helpers.
CreateContextRankConfig(ContextRankBaseValueType.ClassLevel, classes:
getSpiritualistArray(),
1790
progression: ContextRankProgression.Custom,
1791
customProgression: new (int, int)[] { (12, 4), (20, 6) }
1792
),
1793 Helpers.
CreateContextRankConfig(ContextRankBaseValueType.FeatureRank, type: AbilityRankType.
StatBonus,
1794
feature: bonded_manifestation_ac_fcb
1795
),
1796 Helpers.Create<
NewMechanics.TransferDescriptorBonusToTouchAC>(t =>
1797 {
1798 t.value = Helpers.
CreateContextValue(AbilitySharedValue.StatBonus);
1799 t.Descriptor =
ModifierDescriptor.Sacred;
1800 t.
required_target_fact = library.Get<BlueprintFeature>(
"c4a7f98d743bc784c9d4cf2105852c39");
1801 }
1802 )
1803 );
1804
1805 DiceFormula[] diceFormulas = new DiceFormula[] {new DiceFormula(1,
DiceType.D6),
1806 new DiceFormula(1,
DiceType.D8),
1807 new DiceFormula(1,
DiceType.D10),
1808 new DiceFormula(2,
DiceType.D6),
1809 new DiceFormula(2,
DiceType.D8)};
1810
1811 var slam = library.CopyAndAdd<BlueprintItemWeapon>(
"767e6932882a99c4b8ca95c88d823137", "BondedManifestationSlam",
"b115f320141a43e4b3ac9b076e7bc49b");
1812 slam.AddComponent(Helpers.Create<ItemMechanics.ForcePrimary>());
1813 var bonded_manifestation_buff8_1 = Helpers.CreateBuff(
"BondedManifestation81Buff",
1814 "",
1815 "",
1816 "",
1817 null,
1818 null,
1819 Common.createAddAdditionalLimb(
slam),
1820 Helpers.Create<NewMechanics.
ContextWeaponDamageDiceReplacementForSpecificCategory>(c =>
1821
{
1822
c.category = WeaponCategory.OtherNaturalWeapons;
1823
c.value = Helpers.CreateContextValue(AbilityRankType.Default);
1824
c.dice_formulas = diceFormulas;
1825
}),
1826 Helpers.CreateContextRankConfig(
baseValueType: ContextRankBaseValueType.ClassLevel,
1827 type:
AbilityRankType.Default,
1828
progression: ContextRankProgression.DelayedStartPlusDivStep,
1829
startLevel: 5,
1830
stepLevel: 4,
1831
classes: getSpiritualistArray())
1832 );
1833 bonded_manifestation_buff8_1.SetBuffFlags(BuffFlags.HiddenInUi);
1834
1835 DiceFormula[] diceFormulas2 = new DiceFormula[] {new DiceFormula(1,
DiceType.D8),
1836 new DiceFormula(2,
DiceType.D6),
1837 new DiceFormula(2,
DiceType.D8),
1838 new DiceFormula(3,
DiceType.D6),
1839 new DiceFormula(3,
DiceType.D8)};
1840
1841 var bonded_manifestation_buff8_2 = Helpers.CreateBuff(
"BondedManifestation82Buff",
1842 "",
1843 "",
1844 "",
1845 null,
1846 null,
1847 Common.createAddAdditionalLimb(slam),
1848 Helpers.Create<NewMechanics.
ContextWeaponDamageDiceReplacementForSpecificCategory>(c =>
1849 {
1850 c.category = WeaponCategory.
OtherNaturalWeapons;
1851 c.value = Helpers.CreateContextValue(
AbilityRankType.Default);
1852 c.dice_formulas = diceFormulas2;
1853 }),
1854 Helpers.CreateContextRankConfig(baseValueType
: ContextRankBaseValueType.ClassLevel,
1855 type:
AbilityRankType.Default,
1856 progression:
ContextRankProgression.DelayedStartPlusDivStep,
1857 startLevel: 5,
1858 stepLevel: 4,
1859 classes:
getSpiritualistArray())
1860 );
1861 bonded_manifestation_buff8_2.SetBuffFlags(BuffFlags.HiddenInUi);
1862
1863 var apply_slams = Common.createContextActionOnContextCaster(Helpers.
CreateConditional(Common.createContextConditionCasterHasFact(Phantom.
phantom_progressions["Anger"]),
1864
Common.createContextActionApplyBuff(bonded_manifestation_buff8_2, Helpers.
CreateContextDuration(1)),
1865
Common.createContextActionApplyBuff(bonded_manifestation_buff8_1, Helpers.
CreateContextDuration(1))
1866
));
1867 var remove_slams = Common.createContextActionOnContextCaster(Helpers.
Create<NewMechanics.ContextActionRemoveBuffs>(r => r.Buffs = new BlueprintBuff[] {
bonded_manifestation_buff8_2, bonded_manifestation_buff8_1 }));
1868 var attack8 = Common.createContextActionAttackWithSpecificWeapon(slam,
1869 Helpers.
CreateActionList(apply_slams),
1870 Helpers.
CreateActionList(remove_slams),
1871 Helpers.
CreateActionList(remove_slams));
1872 var bonded_manifesation8_ability = Helpers.CreateAbility(
"BondedManifestation8Ability",
1873 "Tendrils
Attack",
1874 "At 8th level,
the spiritualist also sprouts a pair of ectoplasmic tendrils from her body. As a
swift action, the spiritualist can use these tendrils to attack creatures within her
melee reach (using the damage dice of her manifested phantom).",
1875 "",
1876 Helpers.GetIcon(
"4ac47ddb9fa1eaf43a1b6809980cfbd2"),
1877 AbilityType.
Special,
1878 CommandType.
Swift,
1879 AbilityRange.
Touch,
1880 "",
1881 "",
1882 Helpers.Create<
AbilityDeliverProjectile>(a =>
1883 {
1884 a.LineWidth
= 5.Feet();
1885 a.
Projectiles = new BlueprintProjectile[]
1886 {
1887 library.
Get<BlueprintProjectile>("2e3992d1695960347a7f9bdf8122966f"),
1888 library.
Get<BlueprintProjectile>("741743ccd287a854fbb68ce70f75fa05"),
1889 };
1890 }
1891 ),
1892 Helpers.
CreateRunActions(attack8),
1893 Common.
createAbilityCasterHasFacts(bonded_manifestation_buff)
1894 );
1895 bonded_manifesation8_ability.setMiscAbilityParametersTouchHarmful(true);
1896
1897
1898
1899 var bonded_manifestaion8_feature = Common.AbilityToFeature(
bonded_manifesation8_ability);
1900
1901 var buff_reroll_attacks = Helpers.CreateBuff(
"BondedManifestation13RerollAttacksBuff",
1902 "",
1903 "",
1904 "",
1905 null,
1906 null,
1907 Helpers.Create<ModifyD20>(m
=>
1908 {
1909 m.Rule = RuleType.
AttackRoll;
1910 m.RollsAmount = 1;
1911 m.TakeBest = true;
1912 })
1913 );
1914 buff_reroll_attacks.SetBuffFlags(BuffFlags.HiddenInUi);
1915 var apply_slams18 = Common.createContextActionOnContextCaster(Common.
createContextActionApplyBuff(buff_reroll_attacks, Helpers.CreateContextDuration(1)),
1916 Helpers.
CreateConditional(Common.createContextConditionCasterHasFact(Phantom.
phantom_progressions["Anger"]),
1917 Common.
createContextActionApplyBuff(bonded_manifestation_buff8_2, Helpers.
CreateContextDuration(1)),
1918 Common.
createContextActionApplyBuff(bonded_manifestation_buff8_1, Helpers.
CreateContextDuration(1))
1919 ));
1920 var remove_slams18 = Common.createContextActionOnContextCaster(Helpers.
Create<NewMechanics.ContextActionRemoveBuffs>(r => r.Buffs = new BlueprintBuff[] {
buff_reroll_attacks, bonded_manifestation_buff8_2, bonded_manifestation_buff8_1 }));
1921
1922 var attack18 = Common.createContextActionAttackWithSpecificWeapon(slam,
1923 Helpers.
CreateActionList(apply_slams18),
1924 Helpers.
CreateActionList(remove_slams18),
1925 Helpers.
CreateActionList(remove_slams18));
1926 var attack = Helpers.CreateAbility("BondedManifestationCleaveAbility",
1927 "Bonded Manifestation Attack II",
1928 "At 18th level, while using bonded
manifestation, the spiritualist can take a full-round action to attack all creatures
within her melee reach with her tendrils (using the damage dice of her manifested
phantom). When she does, she rolls the attack roll twice, takes the better of the
two results, and uses that as her attack roll result against all creatures within
her melee reach.",
1929 "",
1930 LoadIcons.Image2Sprite.Create(
@"AbilityIcons/StormOfSouls.png"),
1931 AbilityType.Supernatural,
1932 CommandType.Standard,
1933 AbilityRange.Personal,
1934 "",
1935 "",
1936 Helpers.CreateRunActions(attack18),
1937 Common.createAbilityCasterHasFacts(
bonded_manifestation_buff),
1938 Helpers.CreateAbilityTargetsAround(
7.Feet(), TargetType.Enemy),
1939 Common.
createAbilitySpawnFxDestroyOnCast("859a6d74aedf5f349a470ab14afb47d3", anchor:
AbilitySpawnFxAnchor.SelectedTarget, position_anchor: AbilitySpawnFxAnchor.
SelectedTarget)
1940 );
1941 attack.setMiscAbilityParametersSelfOnly();
1942 Common.setAsFullRoundAction(attack);
1943 var bonded_manifestaion18_feature = Common.AbilityToFeature(attack);
1944
1945 var bonded_manifestation_resource = Helpers.CreateAbilityResource(
"BondedManigfestationResource", "", "", "", null);
1946 bonded_manifestation_resource.SetIncreasedByLevel(3, 1,
getSpiritualistArray());
1947 var toggle = Common.buffToToggle(bonded_manifestation_buff, CommandType.
Swift, false,
1948 bonded_manifestation_resource.
CreateActivatableResourceLogic(ResourceSpendType.NewRound),
1949 Helpers.Create<CompanionMechanics.
ActivatableAbilityCompanionUnsummonedOrNoFeature>(a => a.feature =
emotional_focus_selection)
1950 );
1951
1952 bonded_manifestation = Common.ActivatableAbilityToFeature(toggle, false);
1953 bonded_manifestation.AddComponents(bonded_manifestation_resource.
CreateAddAbilityResource(),
1954 Helpers.CreateAddFeatureOnClassLevel(
bonded_manifestaion8_feature, 8, getSpiritualistArray()),
1955 Helpers.CreateAddFeatureOnClassLevel(
bonded_manifestaion18_feature, 18, getSpiritualistArray())
1956 );
1957
1958 dual_bond = Helpers.CreateFeature("DualBondSpiritualistFeature",
1959 "Dual Bond",
1960 "At 17th level, the spiritualist can
use her bonded manifestation ability a number of rounds per day equal to 3 + twice
her spiritualist level.",
1961 "",
1962 bonded_manifestation.Icon,
1963 FeatureGroup.None,
1964 Helpers.Create<
IncreaseResourceAmountBySharedValue>(i => { i.Resource =
bonded_manifestation_resource; i.Value = Helpers.CreateContextValue(AbilityRankType.
Default);}),
1965 Helpers.CreateContextRankConfig(
ContextRankBaseValueType.ClassLevel, classes: getSpiritualistArray())
1966 );
1967 dual_bond.ReapplyOnLevelUp = true;
1968 }
1969
1970
1971 static void createPhantom()
1972 {
1973 var phantom_rank_progression = library.CopyAndAdd<BlueprintProgression>(
"125af359f8bc9a145968b5d8fd8159b8", "SpiritualistPhantomProgression", "");
1974 phantom_rank_progression.Classes = getSpiritualistArray();
1975 emotional_focus_selection = Helpers.CreateFeatureSelection(
"PhantomFeatureSelection",
1976 "Phantom",
1977 "A spiritualist
begins play with the aid of a powerful and versatile spirit entity called a phantom.
The phantom forms a link with the spiritualist, who forever after can either harbor
the creature within her consciousness or manifest it as an ectoplasmic entity. A
phantom has the same alignment as the spiritualist, and it can speak all the
languages its master can. A spiritualist can harbor her phantom in her consciousness
(see the shared consciousness class feature), manifest it partially (see the bonded
manifestation class feature), or fully manifest it. A fully manifested phantom is
treated as a summoned creature from the Ethereal Plane, except it is not sent back
to the Ethereal Plane until it is reduced to a negative amount of hit points equal
to or greater than its Constitution score.\n"
1978 + "The phantom
does not heal naturally, and can be healed only with magic or by being tended to
with the Heal skill while fully manifested in ectoplasmic form. The phantom stays
fully manifested until it is either returned to the spiritualist’s consciousness (a
standard action) or banished to the Ethereal Plane. If the phantom is banished to
the Ethereal Plane, it can’t return to the spiritualist’s consciousness or manifest
again for 24 hours.\n"
1979 + "Fully
manifested phantoms can use magic items (though not wield weapons) appropriate to
their forms.\n"
1980 + "A fully
manifested phantom’s abilities, feats, Hit Dice, saving throws, and skills are tied
to the spiritualist’s class level and increase as the spiritualist gains levels.\n"
1981 + "Each phantom
has an emotional focus—a powerful emotion based on some experience in life that
keeps it tethered to the Material and Ethereal planes. This emotional focus also
grants the phantom abilities that it can use while manifested. The type of each
ability and its power are determined by the spiritualist’s level.\n"
1982 + "The emotional
focus determines which bonus skill ranks the phantom gains, as well as the skills in
which its spiritualist master gains Skill Focus. It also determines the good saving
throws of the manifested phantom and the special abilities the phantom gains as it
increases in level.\n"
1983 + "While phantoms
tend to appear much as they did in life—at least as they did at the time of death—
each emotional focus twists a phantom’s visage, mannerisms, and even personality in
its own way. Unlike with most creatures, a phantom’s emotion aura often manifests
for all to see, even those without the benefit of spells or abilities.\n"
1984 + "Often phantoms
manifest these emotion auras in unique ways, some of which are described in
individual emotional focus descriptions.",
1985 "",
1986 null,
1987 FeatureGroup.
AnimalCompanion,
1988 Helpers.Create<
AddFeatureOnApply>(a => a.Feature = phantom_rank_progression),
1989 Helpers.Create<
AddFeatureOnApply>(a => a.Feature = library.Get<BlueprintFeature>(
"1670990255e4fe948a863bafd5dbda5d"))

1990 );
1991
1992 masters_alignment = Helpers.CreateFeature("PhantomMastersAlignment",
1993 "",
1994 "",
1995
"5b6cb21f9bd34e2c90a2ef72a70dce8e",
1996 null,
1997 FeatureGroup.None,
1998 Helpers.Create<
CompanionMechanics.ChangeCompanionAlignmentToMasters>()
1999 );
2000 masters_alignment.HideInCharacterSheetAndLevelUp = true;
2001 masters_alignment.HideInUI = true;
2002
2003 Phantom.create();
2004 emotional_focus_selection.AllFeatures = new BlueprintFeature[0]; //no
animal companions allowed since only spiritualist can select phantom
2005 // new BlueprintFeature[] {
library.Get<BlueprintFeature>("472091361cf118049a2b4339c4ea836a") }; //empty companion
2006 foreach (var kv in Phantom.phantom_progressions)
2007 {
2008 emotional_focus_selection.AllFeatures = emotional_focus_selection.
AllFeatures.AddToArray(kv.Value);
2009 }
2010 }
2011
2012 static void createPhantomRecall()
2013 {
2014 phantom_recall_resource = Helpers.CreateAbilityResource(
"PhantomRecallResource", "", "", "", null);
2015 phantom_recall_resource.SetIncreasedByLevelStartPlusDivStep(0, 6, 1, 4, 1
, 0, 0.0f, getSpiritualistArray());
2016
2017
2018 var ability = library.CopyAndAdd<BlueprintAbility>(
"5bdc37e4acfa209408334326076a43bc", "PhantomRecallAbility", "");
2019
2020 ability.Type = AbilityType.Supernatural;
2021 ability.Parent = null;
2022 ability.Range = AbilityRange.Personal;
2023 ability.RemoveComponents<SpellComponent>();
2024 ability.RemoveComponents<SpellListComponent>();
2025 ability.RemoveComponents<RecommendationNoFeatFromGroup>();
2026 ability.SetNameDescriptionIcon("Phantom Recall",
2027 "At 6th level, as a swift action, a
spiritualist can call her manifested phantom to her side. This functions as
dimension door, using the spiritualist’s caster level. When this ability is used,
the phantom appears adjacent to the spiritualist (or as close as possible if all
adjacent spaces are occupied). The spiritualist can use this ability once per day at
6th level, plus one additional time per day for every four levels beyond 6th.",
2028 Helpers.GetIcon(
"a5ec7892fb1c2f74598b3a82f3fd679f")); //stunning barrier
2029
2030 var dimension_door_component = ability.GetComponent<
AbilityCustomDimensionDoor>();
2031
2032 var dimension_door_call = Helpers.Create<NewMechanics.CustomAbilities.
AbilityCustomMoveCompanionToTarget>(a =>
2033 {
2034 a.CasterAppearFx = dimension_door_component.CasterAppearFx;
2035 a.CasterAppearProjectile = dimension_door_component.
CasterAppearProjectile;
2036 a.CasterDisappearFx = dimension_door_component.CasterDisappearFx;
2037 a.CasterDisappearProjectile = dimension_door_component.
CasterDisappearProjectile;
2038 a.PortalBone = dimension_door_component.PortalBone;
2039 a.PortalFromPrefab = dimension_door_component.PortalFromPrefab;
2040 a.Radius = 10.Feet();
2041 a.SideAppearFx = dimension_door_component.SideAppearFx;
2042 a.SideAppearProjectile = dimension_door_component.
SideAppearProjectile;
2043 a.SideDisappearFx = dimension_door_component.SideDisappearFx;
2044 a.SideDisappearProjectile = dimension_door_component.
SideDisappearProjectile;
2045 }
2046 );
2047 ability.ReplaceComponent(dimension_door_component, dimension_door_call);
2048 ability.AddComponent(phantom_recall_resource.CreateResourceLogic());
2049 ability.setMiscAbilityParametersSelfOnly();
2050 ability.AddComponent(Helpers.Create<NewMechanics.
AbilityCasterCompanionDead>(a => a.not = true));
2051
2052 phantom_recall = Common.AbilityToFeature(ability, false);
2053 phantom_recall.AddComponent(Helpers.CreateAddAbilityResource(
phantom_recall_resource));
2054 phantom_recall_ability = ability;
2055
2056 summon_call_ability = library.CopyAndAdd(ability,
"PhantomSummonCallAbility", "");
2057 summon_call_ability.SetNameDescriptionIcon("Call Phantom", "", null);
2058 summon_call_ability.RemoveComponents<AbilityResourceLogic>();
2059 summon_call_ability.Parent = null;
2060 summon_companion_ability.ReplaceComponent<AbilityEffectRunAction>(a => a.
Actions = Helpers.CreateActionList(a.Actions.Actions.AddToArray(Helpers.Create<
ContextActionCastSpell>(c => c.Spell = summon_call_ability))));
2061 }
2062
2063
2064 static void createPotentPhantom()
2065 {
2066 potent_phantom = Helpers.CreateFeatureSelection(
"PotentPhantomFeatureSelection",
2067 "Potent Phantom",
2068 "At 20th level, the
spiritualist’s phantom grows ever more complex and sophisticated in its
manifestation. The phantom gains a second emotional focus. This does not change the
phantom’s saving throws, but the phantom otherwise grants all the skills and powers
of the focus.",
2069 "",
2070 Helpers.GetIcon(
"c60969e7f264e6d4b84a1499fdcf9039"),
2071 FeatureGroup.None);
2072
2073 foreach (var kv in Phantom.potent_phantom)
2074 {
2075 potent_phantom.AllFeatures = potent_phantom.AllFeatures.AddToArray(kv
.Value);
2076 }
2077 }
2078
2079
2080 static void createSharedAndFusedConsciousness()
2081 {
2082 shared_consciousness = Helpers.CreateFeature("SharedConsciousnessFeature",
2083 "Shared Consciousness",
2084 "At 1st level, while a
phantom is confined in a spiritualist’s consciousness (but not while it’s fully
manifested or banished to the Ethereal Plane), it grants the spiritualist the Skill
Focus feat in two skills determined by the phantom’s emotional focus, unless the
spiritualist already has Skill Focus in those skills. It also grants a +4 bonus on
saving throws against all mind - affecting effects; at 12th level, this bonus
increases to + 8.",
2085 "",
2086 Helpers.GetIcon(
"b48674cef2bff5e478a007cf57d8345b"),
2087 FeatureGroup.None);
2088
2089 fused_consciousness = Helpers.CreateFeature("FusedConsciousnessFeature",
2090 "Fused Consciousness",
2091 "At 10th level, a spiritualist always
gains the benefits of Shared Consciousness, even when her phantom is manifested.",
2092 "",
2093 Helpers.GetIcon(
"b48674cef2bff5e478a007cf57d8345b"),
2094 FeatureGroup.None,
2095 Common.
createContextSavingThrowBonusAgainstDescriptor(Helpers.CreateContextValue(
AbilityRankType.Default), ModifierDescriptor.UntypedStackable, SpellDescriptor.
MindAffecting),
2096 Helpers.CreateContextRankConfig
(ContextRankBaseValueType.ClassLevel, classes: getSpiritualistArray(),
2097
progression: ContextRankProgression.Custom,
2098
customProgression: new (int, int)[] { (11, 4), (20, 8) })
2099
2100 );
2101
2102 foreach (var kv in Phantom.phantom_skill_foci)
2103 {
2104 foreach (var sf in kv.Value)
2105 {
2106 fused_consciousness.AddComponents(Common.
createAddFeatureIfHasFactAndNotHasFact(Phantom.phantom_progressions[kv.Key], sf, sf
));
2107 }
2108 }
2109
2110 var shared_consciousness_buff = Helpers.CreateBuff(
"SharedConsciousnessBuff",
2111 shared_consciousness.Name,
2112 shared_consciousness.Description,
2113 "",
2114 shared_consciousness.Icon,
2115 null,
2116 fused_consciousness.ComponentsArray
2117 );
2118
2119 Common.addContextActionApplyBuffOnConditionToActivatedAbilityBuffNoRemove
(unsummon_buff,
2120
Helpers.CreateConditional(Common.createContextConditionHasFact(fused_consciousness,
has: false),
2121
Helpers.CreateConditional(Common.
createContextConditionHasFact(shared_consciousness, has: true),
2122
Common.createContextActionApplyBuff(
shared_consciousness_buff, Helpers.CreateContextDuration(), is_child: true,
is_permanent: true, dispellable: false)
2123
)
2124
)
2125
);
2126 }
2127
2128 static void createSummonUnsummonPhantom()
2129 {
2130 unsummon_buff = Helpers.CreateBuff("PhantomUnsummonedBuff",
2131 "Phantom Confined",
2132 "Your phantom is confined in your
conciousness.",
2133 "",
2134 Helpers.GetIcon(
"4aa7942c3e62a164387a73184bca3fc1"), //disintegrate
2135 null,
2136 Helpers.CreateAddFactContextActions(activated:
new GameAction[] { Helpers.Create<CompanionMechanics.ContextActionUnsummonCompanion
>() },
2137
deactivated: new GameAction[] { Helpers.Create<CompanionMechanics.
ContextActionSummonCompanion>()
2138 }
2139 )
2140 );
2141 unsummon_buff.SetBuffFlags(BuffFlags.RemoveOnRest);
2142
2143 var unsummon_companion = Helpers.CreateAbility("SpiritUnsummonAbility",
2144 "Confine Phantom",
2145 "Confine your phantom in
your consciousness.",
2146 "",
2147 unsummon_buff.Icon,
2148 AbilityType.Supernatural,
2149 CommandType.Standard,
2150 AbilityRange.Personal,
2151 "",
2152 "",
2153 Helpers.CreateRunActions(
Common.createContextActionApplyBuff(unsummon_buff, Helpers.CreateContextDuration(),
is_permanent: true, dispellable: false)),
2154 Helpers.Create<
NewMechanics.AbilityCasterCompanionDead>(a => a.not = true),
2155 Helpers.Create<
CompanionMechanics.AbilityCasterCompanionCanBeUnsummoned>()
2156 );
2157
2158 unsummon_companion.setMiscAbilityParametersSelfOnly();
2159 var summon_companion = Helpers.CreateAbility("ManifestSpiritAbility",
2160 "Manifest Phantom",
2161 "Fully manifest your
phantom.",
2162 "",
2163 unsummon_companion.Icon,
2164 AbilityType.Supernatural,
2165 CommandType.Standard,
2166 AbilityRange.Personal,
2167 "",
2168 "",
2169 Helpers.CreateRunActions(
Helpers.Create<ContextActionRemoveBuff>(c => c.Buff = unsummon_buff)),
2170 Helpers.Create<
CompanionMechanics.AbilityCasterCompanionUnsummoned>());
2171 Common.setAsFullRoundAction(summon_companion);
2172 summon_companion.setMiscAbilityParametersSelfOnly();
2173 emotional_focus_selection.AddComponent(Helpers.CreateAddFacts(
summon_companion, unsummon_companion));
2174 summon_companion_ability = summon_companion;
2175 }
2176
2177
2178 static void createSpiritualInferenceAndGreaterSpiritualInference()
2179 {
2180 var spiritual_inference_ac_fcb = Helpers.CreateFeature(
"SpiritualInferenceShiledAcFavoredClassBonusFeature",
2181 "Spiritual
Inference Shield AC Bonus",
2182 "Add 1/6 to the
shield bonus granted to the spiritualist while under the effects of either spiritual
interference or greater spiritual interference.",
2183
"ce01ec2935e24fcca153863c98295d67",
2184 Helpers.GetIcon(
"ef768022b0785eb43a18969903c537c4"),//shield
2185 FeatureGroup.
None);
2186 spiritual_inference_ac_fcb.Ranks = 3;
2187
2188 var buff1 = Helpers.CreateBuff("SpiritualInferenceBuff",
2189 "",
2190 "",
2191 "",
2192 null,
2193 null,
2194 Helpers.CreateAddStatBonus(StatType.
SaveFortitude, 2, ModifierDescriptor.Circumstance),
2195 Helpers.CreateAddStatBonus(StatType.
SaveReflex, 2, ModifierDescriptor.Circumstance),
2196 Helpers.CreateAddStatBonus(StatType.
SaveWill, 2, ModifierDescriptor.Circumstance)
2197 );
2198 var buff11 = library.CopyAndAdd<BlueprintBuff>(buff1,
"GreaterSpiritualInferenceAllyBuff", "");
2199 buff1.AddComponents(Helpers.CreateAddContextStatBonus(StatType.AC,
ModifierDescriptor.Shield),
2200 Helpers.CreateContextRankConfig(
ContextRankBaseValueTypeExtender.MasterFeatureRank.ToContextRankBaseValueType(),
progression: ContextRankProgression.BonusValue,
2201 stepLevel: 2,
2202 feature:
spiritual_inference_ac_fcb
2203 ));
2204 buff11.AddComponent(Helpers.CreateAddStatBonus(StatType.AC, 2,
ModifierDescriptor.Shield));
2205 var buff2 = Helpers.CreateBuff("GreaterSpiritualInferenceBuff",
2206 "",
2207 "",
2208 "",
2209 null,
2210 null, //shield spell
2211 Helpers.CreateAddContextStatBonus(StatType.AC,
ModifierDescriptor.Shield),
2212 Helpers.CreateContextRankConfig(
ContextRankBaseValueTypeExtender.MasterFeatureRank.ToContextRankBaseValueType(),
progression: ContextRankProgression.BonusValue,
2213 stepLevel: 4,
2214 feature:
spiritual_inference_ac_fcb
2215 ),
2216 Helpers.CreateAddStatBonus(StatType.SaveFortitude,
4, ModifierDescriptor.Circumstance),
2217 Helpers.CreateAddStatBonus(StatType.SaveReflex, 4,
ModifierDescriptor.Circumstance),
2218 Helpers.CreateAddStatBonus(StatType.SaveWill, 4,
ModifierDescriptor.Circumstance)
2219 );
2220
2221 var shield_ally_eidolon = Common.createAuraEffectFeature("Spiritual
Inference",
2222 "At 4th level,
whenever a spiritualist is within the reach of her ectoplasmic manifested phantom,
she gains a +2 shield bonus to her Armor Class and a +2 circumstance bonus on her
saving throws. She doesn’t gain these bonuses when the ectoplasmic manifested
phantom is grappled, helpless, or unconscious.",
2223 Helpers.GetIcon(
"ef768022b0785eb43a18969903c537c4"),
2224 buff1,
2225 10.Feet(),
2226 Helpers.
CreateConditionsCheckerOr(Helpers.Create<NewMechanics.ContextConditionIsMaster>())
2227 );
2228
2229 var add_shield_ally = Common.createAddFeatToAnimalCompanion(
shield_ally_eidolon, "");
2230 add_shield_ally.HideInCharacterSheetAndLevelUp = true;
2231
2232 spiritual_inference = Helpers.CreateFeature("SpiirtualInferenceFeature",
2233 shield_ally_eidolon.Name,
2234 shield_ally_eidolon.Description,
2235 "",
2236 shield_ally_eidolon.Icon,
2237 FeatureGroup.None,
2238 Helpers.CreateAddFeatureOnClassLevel(
add_shield_ally, 12, getSpiritualistArray(), before: true)
2239 );
2240
2241 var greater_shield_ally_eidolon = Common.createAuraEffectFeature(
"Greater Spiritual Inference",
2242 "At 12th level, Whenever
allies are within the phantom’s reach, as long as the manifested phantom is in
ectoplasmic form, each ally gains a +2 shield bonus to its Armor Class and a +2
circumstance bonus on its saving throws. For the spiritualist, these bonuses
increase to +4. The spiritualist and allies within range don’t gain this bonus if
the manifested phantom is grappled, helpless, or unconscious. For the spiritualist,
this bonus increases to +4. This bonus doesn’t apply if the phantom is unconscious.",
2243 Helpers.GetIcon(
"ef768022b0785eb43a18969903c537c4"),
2244 buff11,
2245 10.Feet(),
2246 Helpers.
CreateConditionsCheckerAnd(Helpers.Create<ContextConditionIsAlly>(), Helpers.Create<
NewMechanics.ContextConditionIsMaster>(c => c.Not = true), Helpers.Create<
ContextConditionIsCaster>(c => c.Not = true))
2247 );
2248 greater_shield_ally_eidolon.AddComponent(Common.
createAuraEffectFeatureComponentCustom(buff2,
2249
10.Feet(),
2250
Helpers.CreateConditionsCheckerOr(Helpers.Create<NewMechanics.
ContextConditionIsMaster>())));
2251
2252 greater_spiritual_inference = Helpers.CreateFeature(
"GreaterSpiritualInferenceFeature",
2253 greater_shield_ally_eidolon.
Name,
2254 greater_shield_ally_eidolon.
Description,
2255 "",
2256 greater_shield_ally_eidolon.
Icon,
2257 FeatureGroup.None,
2258 Helpers.Create<
AddFeatureToCompanion>(a => a.Feature = greater_shield_ally_eidolon)
2259 );
2260 }
2261
2262
2263 static void createEthericTether()
2264 {
2265 var etheric_tether_feature = Helpers.CreateFeature(
"SpiritualistEthericTetherFeature",
2266 "Etheric Tether",
2267 "Whenever her
manifested phantom takes enough damage to send it back to the Ethereal Plane, as a
reaction to the damage, the spiritualist can sacrifice any number of her hit points
without using an action. Each hit point sacrificed in this way prevents 1 point of
damage dealt to the phantom. This can prevent the phantom from being sent back to
the Ethereal Plane.",
2268 "",
2269 Helpers.GetIcon(
"d5847cad0b0e54c4d82d6c59a3cda6b0"), //breath of life
2270 FeatureGroup.None,
2271 Helpers.Create<
CompanionMechanics.TransferDamageToMaster>()
2272 );
2273
2274
2275 var buff = Helpers.CreateBuff("EthericTetherBuff",
2276 etheric_tether_feature.Name,
2277 etheric_tether_feature.Description,
2278 "",
2279 etheric_tether_feature.Icon,
2280 null,
2281 Helpers.Create<AddFeatureToCompanion>(a =>
a.Feature = etheric_tether_feature)
2282 );
2283
2284 var toggle = Helpers.CreateActivatableAbility(
"SpiritualistEthericTetherAbility",
2285 etheric_tether_feature.Name,
2286 etheric_tether_feature.
Description,
2287 "",
2288 etheric_tether_feature.Icon,
2289 buff,
2290 AbilityActivationType.
Immediately,
2291 CommandType.Free,
2292 null);
2293 toggle.DeactivateImmediately = true;
2294 toggle.Group = ActivatableAbilityGroupExtension.EidolonLifeLink.
ToActivatableAbilityGroup();
2295 etheric_tether = Common.ActivatableAbilityToFeature(toggle, false);
2296 }
2297
2298
2299 static void createSpiritualBond()
2300 {
2301 var buff = Helpers.CreateBuff("SpiritualBondBuff",
2302 "Spiritual Bond",
2303 "At 14th level, a spiritualist’s life
force becomes intrinsically linked with the phantom’s spiritual essence. As long as
the phantom has 1 or more hit points, when the spiritualist takes damage that would
reduce her to fewer than 0 hit points, those points of damage are transferred to the
phantom instead. This transfer stops after the phantom takes all the points of
damage or the phantom is reduced to a negative amount of hit points equal to its
Constitution score. In the latter case, points of damage dealt in excess of this
limit are dealt to the spiritualist. This ability affects only effects that deal hit
point damage.",
2304 "",
2305 Helpers.GetIcon(
"7792da00c85b9e042a0fdfc2b66ec9a8"), //break enchantment
2306 null,
2307 Helpers.Create<CompanionMechanics.
TransferDamageAfterThresholdToPet>(a => a.threshold = 1)
2308 );
2309
2310 var toggle = Helpers.CreateActivatableAbility(
"SpiritualBondToggleAbility",
2311 buff.Name,
2312 buff.Description,
2313 "",
2314 buff.Icon,
2315 buff,
2316 AbilityActivationType.
Immediately,
2317 CommandType.Free,
2318 null);
2319 toggle.DeactivateImmediately = true;
2320 toggle.Group = ActivatableAbilityGroupExtension.EidolonLifeLink.
ToActivatableAbilityGroup();
2321 spiritual_bond = Common.ActivatableAbilityToFeature(toggle, false);
2322 }
2323
2324
2325 static void createSpiritualistProficiencies()
2326 {
2327 spiritualist_proficiencies = library.CopyAndAdd<BlueprintFeature>(
"25c97697236ccf2479d0c6a4185eae7f", //sorcerer proficiencies
2328
"SpiritualistProficiencies",
2329 "");
2330 spiritualist_proficiencies.SetName("Spiritualist Proficiencies");
2331 spiritualist_proficiencies.SetDescription("A spiritualist is proficient
with all simple weapons, kukris and scythes, as well as with light armor.");
2332 spiritualist_proficiencies.ReplaceComponent<AddFacts>(a => a.Facts = new
BlueprintUnitFact[] { a.Facts[0],
2333
library.Get<BlueprintFeature>("6d3728d4e9c9898458fe5e9532951132"
),//light
2334
library.Get<BlueprintFeature>("96c174b0ebca7b246b82d4bc4aac4574"
),//scythe
2335
Deities.kukri_proficiency});
2336 }
2337
2338
2339 static void createSpiritualistKnacks()
2340 {
2341 var daze = library.Get<BlueprintAbility>(
"55f14bc84d7c85446b07a1b5dd6b2b4c");
2342 spiritualist_knacks = Common.createCantrips("SpiritualistKnacksFeature",
2343 "Knacks",
2344 "A spiritualist learns a number
of knacks, or 0-level psychic spells. These spells are cast like any other spell,
but they are not expended when cast and may be used again.",
2345 daze.Icon,
2346 "",
2347 spiritualist_class,
2348 StatType.Wisdom,
2349 spiritualist_class.Spellbook.
SpellList.SpellsByLevel[0].Spells.ToArray());
2350
2351 spiritualist_knacks.ComponentsArray = new BlueprintComponent[0];
2352 }
2353
2354
2355 static BlueprintSpellbook createSpiritualistSpellbook()
2356 {
2357 var inquisitor_class = ResourcesLibrary.TryGetBlueprint<
BlueprintCharacterClass>("f1a70d9e1b0b41e49874e1fa9052a1ce");
2358 var spiritualist_spellbook = Helpers.Create<BlueprintSpellbook>();
2359 spiritualist_spellbook.name = "SpiritualistSpellbook";
2360 library.AddAsset(spiritualist_spellbook, "");
2361 spiritualist_spellbook.Name = spiritualist_class.LocalizedName;
2362 spiritualist_spellbook.SpellsPerDay = inquisitor_class.Spellbook.
SpellsPerDay;
2363 spiritualist_spellbook.SpellsKnown = inquisitor_class.Spellbook.
SpellsKnown;
2364 spiritualist_spellbook.Spontaneous = true;
2365 spiritualist_spellbook.IsArcane = false;
2366 spiritualist_spellbook.AllSpellsKnown = false;
2367 spiritualist_spellbook.CanCopyScrolls = false;
2368 spiritualist_spellbook.CastingAttribute = StatType.Wisdom;
2369 spiritualist_spellbook.CharacterClass = spiritualist_class;
2370 spiritualist_spellbook.CasterLevelModifier = 0;
2371 spiritualist_spellbook.CantripsType = CantripsType.Cantrips;
2372 spiritualist_spellbook.SpellsPerLevel = inquisitor_class.Spellbook.
SpellsPerLevel;
2373
2374 spiritualist_spellbook.SpellList = Helpers.Create<BlueprintSpellList>();
2375 spiritualist_spellbook.SpellList.name = "SpiritualistSpellList";
2376 library.AddAsset(spiritualist_spellbook.SpellList, "");
2377 spiritualist_spellbook.SpellList.SpellsByLevel = new SpellLevelList[10];
2378 for (int i = 0; i < spiritualist_spellbook.SpellList.SpellsByLevel.Length
; i++)
2379 {
2380 spiritualist_spellbook.SpellList.SpellsByLevel[i] = new
SpellLevelList(i);
2381
2382 }
2383
2384 Common.SpellId[] spells = new Common.SpellId[]
2385 {
2386 new Common.SpellId( "55f14bc84d7c85446b07a1b5dd6b2b4c", 0), //daze
2387 new Common.SpellId( "c3a8f31778c3980498d8f00c980be5f5", 0), //guidance
2388 new Common.SpellId( "95f206566c5261c42aa5b3e7e0d1e36c", 0), //mage
light
2389 new Common.SpellId( "7bc8e27cba24f0e43ae64ed201ad5785", 0),
//resistance
2390 new Common.SpellId( "5bf3315ce1ed4d94e8805706820ef64d", 0), //touch
of fatigue
2391 new Common.SpellId( "d3a852385ba4cd740992d1970170301a", 0), //virtue
2392
2393 new Common.SpellId( NewSpells.burst_of_adrenaline.AssetGuid, 1),
2394 new Common.SpellId( NewSpells.burst_of_insight.AssetGuid, 1),
2395 new Common.SpellId( "bd81a3931aa285a4f9844585b5d97e51", 1), //cause
fear
2396 new Common.SpellId( NewSpells.chill_touch.AssetGuid, 1),
2397 new Common.SpellId( "5590652e1c2225c4ca30c4a699ab3649", 1), //cure
light wounds
2398 new Common.SpellId( "fbdd8c455ac4cde4a9a3e18c84af9485", 1), //doom
2399 new Common.SpellId( "4f8181e7a7f1d904fbaea64220e83379", 1),
//expeditious retreat
2400 new Common.SpellId( "e5af3674bb241f14b9a9f6b0c7dc3d27", 1),
//inflict light wounds
2401 new Common.SpellId( "9e1ad5d6f87d19e4d8883d63a6e35568", 1), //mage
armor
2402 new Common.SpellId( "403cf599412299a4f9d5d925c7b9fb33", 1), //magic
fang
2403 new Common.SpellId( NewSpells.obscuring_mist.AssetGuid, 1),
2404 new Common.SpellId( "433b1faf4d02cc34abb0ade5ceda47c4", 1),
//protection from alignment
2405 new Common.SpellId( "55a037e514c0ee14a8e3ed14b47061de", 1), //remove
fear
2406 new Common.SpellId( NewSpells.sanctuary.AssetGuid, 1),
2407 new Common.SpellId( "ef768022b0785eb43a18969903c537c4", 1), //shield
2408 new Common.SpellId( "8fd74eddd9b6c224693d9ab241f25e84", 1), //summon
monster 1
2409 new Common.SpellId( "ad10bfec6d7ae8b47870e3a545cc8900", 1), //touch
of gracelessness
2410
2411 new Common.SpellId( "03a9630394d10164a9410882d31572f0", 2), //aid
2412 new Common.SpellId( NewSpells.animate_dead_lesser.AssetGuid, 2),
2413 new Common.SpellId( NewSpells.blade_tutor.AssetGuid, 2),
2414 new Common.SpellId( "14ec7a4e52e90fa47a4c8d63c69fd5c1", 2), //blur
2415 new Common.SpellId( "b7731c2b4fa1c9844a092329177be4c3", 2),
//boneshaker
2416 new Common.SpellId( "6b90c773a6543dc49b2505858ce33db5", 2), //cure
moderate wounds
2417 new Common.SpellId( "446f7bf201dc1934f96ac0a26e324803", 2),
//eagle's splendor
2418 new Common.SpellId( "e1291272c8f48c14ab212a599ad17aac", 2),
//effortless armor
2419 new Common.SpellId( "7a5b5bf845779a941a67251539545762", 2), //false
life
2420 new Common.SpellId( NewSpells.force_sword.AssetGuid, 2),
2421 new Common.SpellId( NewSpells.ghoul_touch.AssetGuid, 2),
2422 new Common.SpellId( "65f0b63c45ea82a4f8b8325768a3832d", 2),
//inflict moderate wounds
2423 new Common.SpellId( NewSpells.inflict_pain.AssetGuid, 2),
2424 new Common.SpellId( "89940cde01689fb46946b2f8cd7b66b7", 2),
//invisibility
2425 new Common.SpellId( "c28de1f98a3f432448e52e5d47c73208", 2),
//protection from arrows
2426 new Common.SpellId( "e84fc922ccf952943b5240293669b171", 2),
//restoration, lesser
2427 new Common.SpellId( "21ffef7791ce73f468b6fca4d9371e8b", 2), //resist
energy
2428 new Common.SpellId( "08cb5f4c3b2695e44971bf5c45205df0", 2), //scare
2429 new Common.SpellId( "30e5dc243f937fc4b95d2f8f4e1b7ff3", 2), //see
invisibility
2430 new Common.SpellId( NewSpells.shadow_claws.AssetGuid, 2),
2431 new Common.SpellId( SpiritualWeapons.spiritual_weapon.AssetGuid, 2),
2432 new Common.SpellId( NewSpells.stricken_heart.AssetGuid, 2),
2433 new Common.SpellId( "970c6db48ff0c6f43afc9dbb48780d03", 2), //summon
small elemental
2434 new Common.SpellId( "1724061e89c667045a6891179ee2e8e7", 2), //summon
monster 2
2435
2436 new Common.SpellId( "4b76d32feb089ad4499c3a1ce8e1ac27", 3),
//animate dead
2437 new Common.SpellId( "989ab5c44240907489aba0a8568d0603", 3), //bestow
curse
2438 new Common.SpellId( "46fd02ad56c35224c9c91c88cd457791", 3),
//blindness
2439 new Common.SpellId( NewSpells.cloak_of_winds.AssetGuid, 3),
2440 new Common.SpellId( NewSpells.condensed_ether.AssetGuid, 3),
2441 new Common.SpellId( "3361c5df793b4c8448756146a88026ad", 3), //cure
serious wounds
2442 new Common.SpellId( "92681f181b507b34ea87018e8f7a528a", 3), //dispel
magic
2443 new Common.SpellId( "903092f6488f9ce45a80943923576ab3", 3),
//displacement
2444 new Common.SpellId( NewSpells.fly.AssetGuid, 3),
2445 new Common.SpellId( "486eaff58293f6441a5c2759c4872f98", 3), //haste
2446 new Common.SpellId( "5ab0d42fb68c9e34abae4921822b9d63", 3), //heroism
2447 new Common.SpellId( NewSpells.howling_agony.AssetGuid, 3),
2448 new Common.SpellId( "bd5da98859cf2b3418f6d68ea66cabbe", 3),
//inflict serious wounds
2449 new Common.SpellId( NewSpells.invisibility_purge.AssetGuid, 3),
2450 new Common.SpellId( "f1100650705a69c4384d3edd88ba0f52", 3), //magic
fang, greater
2451 new Common.SpellId( NewSpells.pain_strike.AssetGuid, 3),
2452 new Common.SpellId( "d2f116cfe05fcdd4a94e80143b67046f", 3),
//protection from energy
2453 new Common.SpellId( "c927a8b0cd3f5174f8c0b67cdbfde539", 3), //remove
blindness
2454 new Common.SpellId( "4093d5a0eb5cae94e909eb1e0e1a6b36", 3), //remove
disiese
2455 new Common.SpellId( NewSpells.ray_of_exhaustion.AssetGuid, 3),
2456 new Common.SpellId( NewSpells.rigor_mortis.AssetGuid, 3),
2457 new Common.SpellId( NewSpells.sands_of_time.AssetGuid, 3),
2458 new Common.SpellId( "f492622e473d34747806bdb39356eb89", 3), //slow
2459 new Common.SpellId( NewSpells.spirit_bound_blade.AssetGuid, 3),
2460 new Common.SpellId( SpiritualWeapons.twilight_knife.AssetGuid, 3),
2461 new Common.SpellId( Wildshape.undead_anatomyI.AssetGuid, 3),
2462 new Common.SpellId( "8a28a811ca5d20d49a863e832c31cce1", 3),
//vampyric touch
2463 new Common.SpellId( "5d61dde0020bbf54ba1521f7ca0229dc", 3), //summon
monster 3
2464
2465 new Common.SpellId( NewSpells.aura_of_doom.AssetGuid, 4),
2466 new Common.SpellId( "cf6c901fb7acc904e85c63b342e9c949", 4),
//confusion
2467 new Common.SpellId( "4baf4109145de4345861fe0f2209d903", 4),
//crushing despair
2468 new Common.SpellId( "41c9016596fe1de4faf67425ed691203", 4), //cure
critical wounds
2469 new Common.SpellId( "e9cc9378fd6841f48ad59384e79e9953", 4), //death
ward
2470 new Common.SpellId( NewSpells.debilitating_portent.AssetGuid, 4),
2471 new Common.SpellId( "4a648b57935a59547b7a2ee86fb4f26a", 4),
//dimensions door
2472 new Common.SpellId( "f34fb78eaaec141469079af124bcfa0f", 4),
//enervation
2473 new Common.SpellId( "dc6af3b4fd149f841912d8a3ce0983de", 4), //false
life, greater
2474 new Common.SpellId( "d2aeac47450c76347aebbc02e4f463e0", 4), //fear
2475 new Common.SpellId( "0087fc2d64b6095478bc7b8d7d512caf", 4),
//freedom of movement
2476 new Common.SpellId( "651110ed4f117a948b41c05c5c7624c0", 4),
//inflict critical wounds
2477 new Common.SpellId( "ecaa0def35b38f949bd1976a6c9539e0", 4),
//invisibility greater
2478 new Common.SpellId( "e7240516af4241b42b2cd819929ea9da", 4),
//neutralize poison
2479 new Common.SpellId( "6717dbaef00c0eb4897a1c908a75dfe5", 4),
//phantasmal killer
2480 new Common.SpellId( "b48674cef2bff5e478a007cf57d8345b", 4), //remove
curse
2481 new Common.SpellId( "f2115ac1148256b4ba20788f7e966830", 4),
//restoration
2482 new Common.SpellId( NewSpells.shadow_conjuration.AssetGuid, 4),
2483 new Common.SpellId( NewSpells.solid_fog.AssetGuid, 4),
2484 new Common.SpellId( SpiritualWeapons.spiritual_ally.AssetGuid, 4),
2485 new Common.SpellId( "e42b1dbff4262c6469a9ff0a6ce730e3", 4), //summon
medium elemental
2486 new Common.SpellId( "7ed74a3ec8c458d4fb50b192fd7be6ef", 4), //summon
monster 4
2487
2488 new Common.SpellId( "7792da00c85b9e042a0fdfc2b66ec9a8", 5), //break
enchantment
2489 new Common.SpellId( "d5847cad0b0e54c4d82d6c59a3cda6b0", 5), //breath
of life
2490 new Common.SpellId( "548d339ba87ee56459c98e80167bdf10", 5),
//cloudkill
2491 new Common.SpellId( NewSpells.curse_major.AssetGuid, 5),
2492 new Common.SpellId( "95f7cdcec94e293489a85afdf5af1fd7", 5),
//dismissal
2493 new Common.SpellId( "d7cbd2004ce66a042aeab2e95a3c5c61", 5),
//dominate person
2494 new Common.SpellId( "444eed6e26f773a40ab6e4d160c67faa", 5),
//feeblemind
2495 new Common.SpellId( NewSpells.fickle_winds.AssetGuid, 5),
2496 new Common.SpellId( NewSpells.inflict_pain_mass.AssetGuid, 5),
2497 new Common.SpellId( "eabf94e4edc6e714cabd96aa69f8b207", 5), //mind fog
2498 new Common.SpellId( NewSpells.overland_flight.AssetGuid, 5),
2499 new Common.SpellId( NewSpells.pain_strike_mass.AssetGuid, 5),
2500 new Common.SpellId( "12fb4a4c22549c74d949e2916a2f0b6a", 5),
//phantasmal web
2501 new Common.SpellId( NewSpells.phantom_limbs.AssetGuid, 5),
2502 new Common.SpellId( "a0fc99f0933d01643b2b8fe570caa4c5", 5), //raise
dead
2503 new Common.SpellId( "237427308e48c3341b3d532b9d3a001f", 5), //shadow
evocation
2504 new Common.SpellId( "4fbd47525382517419c66fb548fe9a67", 5), //slay
living
2505 new Common.SpellId( "0a5ddfbcfb3989543ac7c936fc256889", 5), //spell
resistance
2506 new Common.SpellId( NewSpells.suffocation.AssetGuid, 5),
2507 new Common.SpellId( "89404dd71edc1aa42962824b44156fe5", 5), //summon
large elemental
2508 new Common.SpellId( "630c8b85d9f07a64f917d79cb5905741", 5), //summon
monster 5
2509 new Common.SpellId( Wildshape.undead_anatomyII.AssetGuid, 5),
2510 new Common.SpellId( "a34921035f2a6714e9be5ca76c5e34b5", 5),
//vampiric shadow shield
2511 new Common.SpellId( "8878d0c46dfbd564e9d5756349d5e439", 5), //waves
of fatigue
2512
2513 new Common.SpellId( "d361391f645db984bbf58907711a146a", 6),
//banishment
2514 new Common.SpellId( "d42c6d3f29e07b6409d670792d72bc82", 6),
//banshee blast
2515 new Common.SpellId( "a89dcbbab8f40e44e920cc60636097cf", 6), //circle
of death
2516 new Common.SpellId( "76a11b460be25e44ca85904d6806e5a3", 6), //create
undead
2517 new Common.SpellId( "f0f761b808dc4b149b08eaf44b99f633", 6), //dispel
magic, greater
2518 new Common.SpellId( "4aa7942c3e62a164387a73184bca3fc1", 6),
//disintegrate
2519 new Common.SpellId( "3167d30dd3c622c46b0c0cb242061642", 6), //eyebite
2520 new Common.SpellId( "cc09224ecc9af79449816c45bc5be218", 6), //harm
2521 new Common.SpellId( "5da172c4c89f9eb4cbb614f3a67357d3", 6), //heal
2522 new Common.SpellId( "e15e5e7045fda2244b98c8f010adfe31", 6),
//heroism greater
2523 new Common.SpellId( "766ec978fa993034f86a372c8eb1fc10", 6), //summon
huge elemental
2524 new Common.SpellId( "e740afbab0147944dab35d83faa0ae1c", 6), //summon
monster 6
2525 new Common.SpellId( "27203d62eb3d4184c9aced94f22e1806", 6),
//transformation
2526 new Common.SpellId( "4cf3d0fae3239ec478f51e86f49161cb", 6), //true
seeing
2527 new Common.SpellId( "474ed0aa656cc38499cc9a073d113716", 6), //umbral
strike
2528 new Common.SpellId( Wildshape.undead_anatomyIII.AssetGuid, 6),
2529 };
2530
2531 foreach (var spell_id in spells)
2532 {
2533 var spell = library.Get<BlueprintAbility>(spell_id.guid);
2534 spell.AddToSpellList(spiritualist_spellbook.SpellList, spell_id.level
);
2535 }
2536
2537 spiritualist_spellbook.AddComponent(Helpers.Create<SpellbookMechanics.
PsychicSpellbook>());
2538
2539 spiritualist_spellcasting = Helpers.CreateFeature(
"SpiritualistSpellCasting",
2540 "Psychic Magic",
2541 "A spiritualist casts psychic spells
drawn from the spiritualist spell list. She can cast any spell she knows without
preparing it ahead of time, assuming she has not yet used up her allotment of spells
per day for the spell’s level. To learn or cast a spell, a spiritualist must have a
Wisdom score equal to at least 10 + the spell level. The Difficulty Class for a
saving throw against a spiritualist’s spell equals 10 + the spell level + the
spiritualist’s Wisdom modifier.\n"
2542 + "A spiritualist can cast only a
certain number of spells of each spell level per day.",
2543 "",
2544 null,
2545 FeatureGroup.None);
2546
2547 spiritualist_spellcasting.AddComponents(Helpers.Create<
SpellFailureMechanics.PsychicSpellbook>(p => p.spellbook = spiritualist_spellbook),
2548 Helpers.CreateAddMechanics(
AddMechanicsFeature.MechanicsFeatureType.NaturalSpell));
2549 spiritualist_spellcasting.AddComponent(Helpers.Create<SpellbookMechanics.
AddUndercastSpells>(p => p.spellbook = spiritualist_spellbook));
2550 spiritualist_spellcasting.AddComponent(Helpers.CreateAddFact(Investigator
.center_self));
2551 spiritualist_spellcasting.AddComponents(Common.createCantrips(
spiritualist_class, StatType.Wisdom, spiritualist_spellbook.SpellList.SpellsByLevel[0
].Spells.ToArray()));
2552 spiritualist_spellcasting.AddComponents(Helpers.CreateAddFacts(
spiritualist_spellbook.SpellList.SpellsByLevel[0].Spells.ToArray()));
2553
2554 return spiritualist_spellbook;
2555 }
2556
2557 }
2558 }
2559

You might also like