static BlueprintFeature CreateFirestorm()
        {
            // This is a cross between Fire Storm and Incendiary Cloud.
            // Like Fire Storm, it does 1d6 per caster level.
            // Like Incendiary Cloud, it's a persistent AOE (shorter duration though).

            var name      = "MysteryFlameFirestorm";
            var cloudArea = library.CopyAndAdd <BlueprintAbilityAreaEffect>(
                "a892a67daaa08514cb62ad8dcab7bd90",             // IncendiaryCloudArea, used by brass golem breath
                $"{name}Area", "3311da25c50643d0b7ba61da6d953cad");

            // TODO: offer the option to place more, using an activatable ability?
            cloudArea.Size = 15.Feet();
            cloudArea.SetComponents(
                Helpers.CreateContextRankConfig(ContextRankBaseValueType.ClassLevel, ContextRankProgression.AsIs, AbilityRankType.DamageDice, classes: oracleArray),
                Helpers.CreateAreaEffectRunAction(round:
                                                  Helpers.CreateActionSavingThrow(SavingThrowType.Reflex,
                                                                                  Helpers.CreateActionDealDamage(DamageEnergyType.Fire,
                                                                                                                 DiceType.D6.CreateContextDiceValue(AbilityRankType.DamageDice.CreateContextValue()),
                                                                                                                 halfIfSaved: true))));

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

            resource.SetFixedResource(1);

            var ability = Helpers.CreateAbility($"{name}Ability", RES.MysteryFlameFirestormName_info,
                                                RES.MysteryFlameFirestormDescription_info,
                                                "4bddc1868e8b49ed8d27a67ee2085da3",
                                                Helpers.GetIcon("e3d0dfe1c8527934294f241e0ae96a8d"), // fire storm
                                                AbilityType.Supernatural, CommandType.Standard, AbilityRange.Close,
                                                "1 round/Charisma modifier", Helpers.reflexHalfDamage,
                                                resource.CreateResourceLogic(),
                                                FakeTargetsAround.Create(cloudArea.Size),
                                                Helpers.CreateSpellDescriptor(SpellDescriptor.Fire),
                                                Helpers.CreateContextRankConfig(ContextRankBaseValueType.StatBonus, ContextRankProgression.AsIs, stat: StatType.Charisma),
                                                Helpers.CreateRunActions(Helpers.Create <ContextActionSpawnAreaEffect>(c =>
            {
                c.DurationValue = Helpers.CreateContextDuration();
                c.AreaEffect    = cloudArea;
            })));

            ability.CanTargetEnemies = true;
            ability.CanTargetFriends = true;
            ability.CanTargetPoint   = true;
            ability.CanTargetSelf    = true;
            ability.EffectOnAlly     = AbilityEffectOnUnit.Harmful;
            ability.EffectOnEnemy    = AbilityEffectOnUnit.Harmful;

            var feat = Helpers.CreateFeature(name, ability.Name, ability.Description,
                                             "b27101ce8b794188b246c4f2be1bd142",
                                             ability.Icon, FeatureGroup.None,
                                             Helpers.PrerequisiteClassLevel(oracle, 11),
                                             resource.CreateAddAbilityResource(),
                                             ability.CreateAddFact());

            return(feat);
        }
        static void LoadIncendiaryCloud()
        {
            var cloudArea = library.CopyAndAdd <BlueprintAbilityAreaEffect>(
                "a892a67daaa08514cb62ad8dcab7bd90", // IncendiaryCloudArea, used by brass golem breath
                "IncendiaryCloudSpellArea",
                incendiaryCloudAreaId);

            // TODO: should be 20ft.
            // Visual effects can probably be scaled by hooking IAreaEffectHandler,
            // and getting AreaEffectView.m_SpawnedFx, then .GetComponentsInChildren<ParticleSystem>(),
            // then .transform.localScale or something like that.
            cloudArea.Size = 15.Feet();
            cloudArea.SetComponents(Helpers.CreateAreaEffectRunAction(round:
                                                                      Helpers.CreateActionSavingThrow(SavingThrowType.Reflex,
                                                                                                      Helpers.CreateActionDealDamage(DamageEnergyType.Fire,
                                                                                                                                     DiceType.D6.CreateContextDiceValue(6), halfIfSaved: true))));

            var spell = Helpers.CreateAbility("IncendiaryCloud", "Incendiary Cloud",
                                              "An incendiary cloud spell creates a cloud of roiling smoke shot through with white-hot embers. The smoke obscures all sight as a fog cloud does. In addition, the white-hot embers within the cloud deal 6d6 points of fire damage to everything within the cloud on your turn each round. All targets can make Reflex saves each round to take half damage.\n" +
                                              "As with a cloudkill spell, the smoke moves away from you at 10 feet per round. Figure out the smoke’s new spread each round based on its new point of origin, which is 10 feet farther away from where you were when you cast the spell. By concentrating, you can make the cloud move as much as 60 feet each round.Any portion of the cloud that would extend beyond your maximum range dissipates harmlessly, reducing the remainder’s spread thereafter.\n" +
                                              "As with fog cloud, wind disperses the smoke, and the spell can’t be cast underwater.",
                                              "85923af68485439dac5c3e9ddd2dd66c",
                                              Helpers.GetIcon("e3d0dfe1c8527934294f241e0ae96a8d"), // fire storm
                                              AbilityType.Spell, CommandType.Standard, AbilityRange.Medium,
                                              Helpers.roundsPerLevelDuration, Helpers.reflexHalfDamage,
                                              Helpers.CreateSpellComponent(SpellSchool.Conjuration),
                                              Helpers.CreateSpellDescriptor(SpellDescriptor.Fire),
                                              FakeTargetsAround.Create(cloudArea.Size),
                                              Helpers.CreateContextRankConfig(),
                                              Helpers.CreateRunActions(Helpers.Create <ContextActionSpawnAreaEffect>(c =>
            {
                c.DurationValue = Helpers.CreateContextDuration();
                c.AreaEffect    = cloudArea;
            })));

            spell.SpellResistance    = false;
            spell.CanTargetEnemies   = true;
            spell.CanTargetPoint     = true;
            spell.CanTargetFriends   = true;
            spell.CanTargetPoint     = true;
            spell.EffectOnAlly       = AbilityEffectOnUnit.Harmful;
            spell.EffectOnEnemy      = AbilityEffectOnUnit.Harmful;
            spell.AvailableMetamagic = Metamagic.Empower | Metamagic.Extend | Metamagic.Maximize | Metamagic.Quicken | Metamagic.Heighten | Metamagic.Reach;
            incendiaryCloud          = spell;
            spell.AddToSpellList(Helpers.wizardSpellList, 8);
            Helpers.AddSpellAndScroll(spell, "1cbb88fbf2a6bb74aa437fadf6946d22"); // scroll fire storm
            spell.FixDomainSpell(8, "d8f30625d1b1f9d41a24446cbf7ac52e");          // fire domain
        }
        static void LoadIncendiaryCloud()
        {
            var cloudArea = library.CopyAndAdd <BlueprintAbilityAreaEffect>(
                "a892a67daaa08514cb62ad8dcab7bd90", // IncendiaryCloudArea, used by brass golem breath
                "IncendiaryCloudSpellArea",
                incendiaryCloudAreaId);

            // TODO: should be 20ft.
            // Visual effects can probably be scaled by hooking IAreaEffectHandler,
            // and getting AreaEffectView.m_SpawnedFx, then .GetComponentsInChildren<ParticleSystem>(),
            // then .transform.localScale or something like that.
            cloudArea.Size = 15.Feet();
            cloudArea.SetComponents(Helpers.CreateAreaEffectRunAction(round:
                                                                      Helpers.CreateActionSavingThrow(SavingThrowType.Reflex,
                                                                                                      Helpers.CreateActionDealDamage(DamageEnergyType.Fire,
                                                                                                                                     DiceType.D6.CreateContextDiceValue(6), halfIfSaved: true))));

            var spell = Helpers.CreateAbility("IncendiaryCloud", RES.IncendiaryCloudAbilityName_info,
                                              RES.IncendiaryCloudAbilityDescription_info,
                                              "85923af68485439dac5c3e9ddd2dd66c",
                                              Helpers.GetIcon("e3d0dfe1c8527934294f241e0ae96a8d"), // fire storm
                                              AbilityType.Spell, CommandType.Standard, AbilityRange.Medium,
                                              Helpers.roundsPerLevelDuration, Helpers.reflexHalfDamage,
                                              Helpers.CreateSpellComponent(SpellSchool.Conjuration),
                                              Helpers.CreateSpellDescriptor(SpellDescriptor.Fire),
                                              FakeTargetsAround.Create(cloudArea.Size),
                                              Helpers.CreateContextRankConfig(),
                                              Helpers.CreateRunActions(Helpers.Create <ContextActionSpawnAreaEffect>(c =>
            {
                c.DurationValue = Helpers.CreateContextDuration();
                c.AreaEffect    = cloudArea;
            })));

            spell.SpellResistance    = false;
            spell.CanTargetEnemies   = true;
            spell.CanTargetPoint     = true;
            spell.CanTargetFriends   = true;
            spell.CanTargetPoint     = true;
            spell.EffectOnAlly       = AbilityEffectOnUnit.Harmful;
            spell.EffectOnEnemy      = AbilityEffectOnUnit.Harmful;
            spell.AvailableMetamagic = Metamagic.Empower | Metamagic.Extend | Metamagic.Maximize | Metamagic.Quicken | Metamagic.Heighten | Metamagic.Reach;
            incendiaryCloud          = spell;
            spell.AddToSpellList(Helpers.wizardSpellList, 8);
            Helpers.AddSpellAndScroll(spell, "1cbb88fbf2a6bb74aa437fadf6946d22"); // scroll fire storm
            spell.FixDomainSpell(8, "d8f30625d1b1f9d41a24446cbf7ac52e");          // fire domain
        }
Beispiel #4
0
        static void LoadKnock()
        {
            var spell = Helpers.CreateAbility("KnockSpell", Main.lc.GetTranslate("Knock.spKnockName"),
                                              Main.lc.GetTranslate("Knock.spKnockDesc"),
                                              "1dc0c67a10a54387b2679712969cab27",
                                              Helpers.GetIcon("26a668c5a8c22354bac67bcd42e09a3f"), // adaptability
                                              AbilityType.Spell, CommandType.Standard, AbilityRange.Medium, "", "",
                                              SpellSchool.Transmutation.CreateSpellComponent(),
                                              FakeTargetsAround.Create(10.Feet()),
                                              Helpers.CreateRunActions(KnockAction.Create(1, 10.Feet())));

            spell.CanTargetPoint     = true;
            spell.AvailableMetamagic = Metamagic.Quicken | Metamagic.Heighten | Metamagic.Reach;

            spell.AddToSpellList(Helpers.inquisitorSpellList, 2);
            spell.AddToSpellList(Helpers.wizardSpellList, 2);
            Helpers.AddSpellAndScroll(spell, "5e9bd8e141c622a4a8f4e4654d022f40"); // find traps scroll

            var massSpell = Helpers.CreateAbility("KnockMass", Main.lc.GetTranslate("Knock.spKnockMassName"),
                                                  Main.lc.GetTranslate("Knock.spKnockMassDescHalf") + $"{ spell.Description}",
                                                  "551f0b78de034fe88b4391293ff20e1b",
                                                  spell.Icon, // adaptability
                                                  AbilityType.Spell, CommandType.Standard, AbilityRange.Close, "", "",
                                                  SpellSchool.Transmutation.CreateSpellComponent(),
                                                  Helpers.CreateContextRankConfig(),
                                                  FakeTargetsAround.Create(30.Feet()),
                                                  Helpers.CreateRunActions(KnockAction.Create(Helpers.CreateContextValueRank(), 30.Feet())));

            massSpell.CanTargetPoint     = true;
            massSpell.AvailableMetamagic = Metamagic.Quicken | Metamagic.Heighten | Metamagic.Reach;

            massSpell.AddToSpellList(Helpers.clericSpellList, 6);
            massSpell.AddToSpellList(Helpers.inquisitorSpellList, 6);
            massSpell.AddToSpellList(Helpers.wizardSpellList, 6);
            Helpers.AddSpellAndScroll(massSpell, "5e9bd8e141c622a4a8f4e4654d022f40"); // find traps scroll
        }
Beispiel #5
0
        static void LoadKnock()
        {
            var spell = Helpers.CreateAbility("KnockSpell", "Knock",
                                              "Knock opens stuck, barred, or locked doors, as well as those subject to hold portal or arcane lock. When you complete the casting of this spell, make a caster level check against the DC of the lock with a +10 bonus. If successful, knock opens up to two means of closure. This spell opens secret doors, as well as locked or trick-opening boxes or chests. It also loosens welds, shackles, or chains (provided they serve to hold something shut). If used to open an arcane locked door, the spell does not remove the arcane lock but simply suspends its functioning for 10 minutes. In all other cases, the door does not relock itself or become stuck again on its own. Knock does not raise barred gates or similar impediments (such as a portcullis), nor does it affect ropes, vines, and the like. The effect is limited by the area. Each casting can undo as many as two means of preventing access.",
                                              "1dc0c67a10a54387b2679712969cab27",
                                              Helpers.GetIcon("26a668c5a8c22354bac67bcd42e09a3f"), // adaptability
                                              AbilityType.Spell, CommandType.Standard, AbilityRange.Medium, "", "",
                                              SpellSchool.Transmutation.CreateSpellComponent(),
                                              FakeTargetsAround.Create(10.Feet()),
                                              Helpers.CreateRunActions(KnockAction.Create(1, 10.Feet())));

            spell.CanTargetPoint     = true;
            spell.AvailableMetamagic = Metamagic.Quicken | Metamagic.Heighten | Metamagic.Reach;

            spell.AddToSpellList(Helpers.inquisitorSpellList, 2);
            spell.AddToSpellList(Helpers.wizardSpellList, 2);
            Helpers.AddSpellAndScroll(spell, "5e9bd8e141c622a4a8f4e4654d022f40"); // find traps scroll

            var massSpell = Helpers.CreateAbility("KnockMass", "Knock, Mass",
                                                  $"This spell functions as knock, but works on multiple means of closure at once (up to 1/caster level).\n{spell.Description}",
                                                  "551f0b78de034fe88b4391293ff20e1b",
                                                  spell.Icon, // adaptability
                                                  AbilityType.Spell, CommandType.Standard, AbilityRange.Close, "", "",
                                                  SpellSchool.Transmutation.CreateSpellComponent(),
                                                  Helpers.CreateContextRankConfig(),
                                                  FakeTargetsAround.Create(30.Feet()),
                                                  Helpers.CreateRunActions(KnockAction.Create(Helpers.CreateContextValueRank(), 30.Feet())));

            massSpell.CanTargetPoint     = true;
            massSpell.AvailableMetamagic = Metamagic.Quicken | Metamagic.Heighten | Metamagic.Reach;

            massSpell.AddToSpellList(Helpers.clericSpellList, 6);
            massSpell.AddToSpellList(Helpers.inquisitorSpellList, 6);
            massSpell.AddToSpellList(Helpers.wizardSpellList, 6);
            Helpers.AddSpellAndScroll(massSpell, "5e9bd8e141c622a4a8f4e4654d022f40"); // find traps scroll
        }
        static void LoadDelayedBlastFireball()
        {
            // Note: this was reworked a bit. It does not spawn an item.
            // The original version did use an item, and it worked (the code is still in ExperimentalSpells).
            //
            // But this version has nicer UX, IMO: you get the AOE targeting circle, and you can see the
            // buff tick down, and the projectile is fired later from the caster's position, which looks neat.
            // And it doesn't spawn the loot bag. I'm more confident it'll work correctly with saves and such.
            var fireball = library.Get <BlueprintAbility>("2d81362af43aeac4387a3d4fced489c3");
            var spell    = Helpers.CreateAbility("DelayedBlastFireball", "Delayed Blast Fireball",
                                                 "This spell functions like fireball, except that it is more powerful and can detonate up to 5 rounds after the spell is cast. The burst of flame deals 1d6 points of fire damage per caster level (maximum 20d6). " +
                                                 "The glowing bead created by delayed blast fireball can detonate immediately if you desire, or you can choose to delay the burst for as many as 5 rounds. " +
                                                 "You select the amount of delay upon completing the spell.", //", and that time cannot change once it has been set unless someone touches the bead. If you choose a delay, the glowing bead sits at its destination until it detonates. " +
                                                                                                              //"A creature can pick up and hurl the bead as a thrown weapon (range increment 10 feet). If a creature handles and moves the bead within 1 round of its detonation, there is a 25% chance that the bead detonates while being handled.",
                                                 "dfe891561c4d48ed8235268b0e7692e7",
                                                 fireball.Icon, AbilityType.Spell, CommandType.Standard, fireball.Range,
                                                 "5 rounds or less; see text", fireball.LocalizedSavingThrow);

            spell.SpellResistance    = true;
            spell.EffectOnAlly       = AbilityEffectOnUnit.Harmful;
            spell.EffectOnEnemy      = AbilityEffectOnUnit.Harmful;
            spell.AvailableMetamagic = Metamagic.Empower | Metamagic.Heighten | Metamagic.Maximize | Metamagic.Quicken | Metamagic.Reach;

            var delayIds = new String[] {
                "1e403a3188214a5c94ad63ede5928f81",
                "2b6efa3759d842f7a549b85712784ee2",
                "d762acc02c71446b834723ac20eb722a",
                "2ca70c4525574cba8661beaef0a6b35f",
                "45f6b2f4c3ce424d98d269548691d6bc",
                "c1b683e809c348428011f0ed2e9da67b",
            };

            var spell0 = library.CopyAndAdd(fireball, $"{spell.name}Delay0", delayIds[0]);

            spell0.SetNameDescriptionIcon(spell);

            spell0.ReplaceContextRankConfig(c =>
            {
                Helpers.SetField(c, "m_UseMax", false);
                Helpers.SetField(c, "m_Max", 20);
            });
            spell0.SpellResistance = true;

            var buff = Helpers.CreateBuff($"{spell.name}Buff", spell.Name, spell.Description, "fc9490e3a7d24723a017609397521ea1",
                                          spell.Icon, null,
                                          Helpers.CreateAddFactContextActions(
                                              deactivated: ActionCastSpellWithOriginalParams.Create(spell0)));

            buff.Stacking            = StackingType.Stack;
            delayedBlastFireballBuff = buff;

            var variants = new List <BlueprintAbility> {
                spell0
            };

            for (int delay = 1; delay <= 5; delay++)
            {
                var delaySpell = library.CopyAndAdd(spell0, $"{spell.name}Delay{delay}", delayIds[delay]);
                delaySpell.SetName($"{spell.Name} ({delay} rounds)");
                delaySpell.SetComponents(
                    spell0.GetComponent <SpellComponent>(),
                    FakeTargetsAround.Create(20.Feet(), toCaster: true),
                    Helpers.CreateRunActions(
                        Helpers.CreateApplyBuff(buff, Helpers.CreateContextDuration(delay),
                                                fromSpell: true, dispellable: false, toCaster: true)));
                variants.Add(delaySpell);
            }

            spell.SetComponents(
                Helpers.CreateSpellComponent(fireball.School),
                Helpers.CreateSpellDescriptor(fireball.SpellDescriptor),
                spell.CreateAbilityVariants(variants));

            spell.AddToSpellList(Helpers.wizardSpellList, 7);
            Helpers.AddSpellAndScroll(spell, "5b172c2c3e356eb43ba5a8f8008a8a5a", 1); // scroll of fireball
            delayedBlastFireball = spell;
        }
Beispiel #7
0
        static void LoadDelayedBlastFireball()
        {
            // Note: this was reworked a bit. It does not spawn an item.
            // The original version did use an item, and it worked (the code is still in ExperimentalSpells).
            //
            // But this version has nicer UX, IMO: you get the AOE targeting circle, and you can see the
            // buff tick down, and the projectile is fired later from the caster's position, which looks neat.
            // And it doesn't spawn the loot bag. I'm more confident it'll work correctly with saves and such.
            var fireball = library.Get <BlueprintAbility>("2d81362af43aeac4387a3d4fced489c3");
            var spell    = Helpers.CreateAbility("DelayedBlastFireball", Main.lc.GetTranslate("FireSpells.spDelayedFireballName"),
                                                 Main.lc.GetTranslate("FireSpells.spDelayedFireballDesc"),
                                                 "dfe891561c4d48ed8235268b0e7692e7",
                                                 fireball.Icon, AbilityType.Spell, CommandType.Standard, fireball.Range,
                                                 "5 rounds or less; see text", fireball.LocalizedSavingThrow);

            spell.SpellResistance    = true;
            spell.EffectOnAlly       = AbilityEffectOnUnit.Harmful;
            spell.EffectOnEnemy      = AbilityEffectOnUnit.Harmful;
            spell.AvailableMetamagic = Metamagic.Empower | Metamagic.Heighten | Metamagic.Maximize | Metamagic.Quicken | Metamagic.Reach;
            var delayIds = new String[] {
                "1e403a3188214a5c94ad63ede5928f81",
                "2b6efa3759d842f7a549b85712784ee2",
                "d762acc02c71446b834723ac20eb722a",
                "2ca70c4525574cba8661beaef0a6b35f",
                "45f6b2f4c3ce424d98d269548691d6bc",
                "c1b683e809c348428011f0ed2e9da67b",
            };

            var spell0 = library.CopyAndAdd(fireball, $"{spell.name}Delay0", delayIds[0]);

            spell0.SetNameDescriptionIcon(spell);

            spell0.ReplaceContextRankConfig(c =>
            {
                Helpers.SetField(c, "m_UseMax", false);
                Helpers.SetField(c, "m_Max", 20);
            });
            spell0.SpellResistance = true;

            var buff = Helpers.CreateBuff($"{spell.name}Buff", spell.Name, spell.Description, "fc9490e3a7d24723a017609397521ea1",
                                          spell.Icon, null,
                                          Helpers.CreateAddFactContextActions(
                                              deactivated: ActionCastSpellWithOriginalParams.Create(spell0)));

            buff.Stacking            = StackingType.Stack;
            delayedBlastFireballBuff = buff;

            var variants = new List <BlueprintAbility> {
                spell0
            };

            for (int delay = 1; delay <= 5; delay++)
            {
                var delaySpell = library.CopyAndAdd(spell0, $"{spell.name}Delay{delay}", delayIds[delay]);
                delaySpell.SetName($"{spell.Name} ({delay} rounds)");
                delaySpell.SetComponents(
                    spell0.GetComponent <SpellComponent>(),
                    FakeTargetsAround.Create(20.Feet(), toCaster: true),
                    Helpers.CreateRunActions(
                        Helpers.CreateApplyBuff(buff, Helpers.CreateContextDuration(delay),
                                                fromSpell: true, dispellable: false, toCaster: true)));
                variants.Add(delaySpell);
            }

            spell.SetComponents(
                Helpers.CreateSpellComponent(fireball.School),
                Helpers.CreateSpellDescriptor(fireball.SpellDescriptor),
                spell.CreateAbilityVariants(variants));

            spell.AddToSpellList(Helpers.wizardSpellList, 7);
            Helpers.AddSpellAndScroll(spell, "5b172c2c3e356eb43ba5a8f8008a8a5a", 1); // scroll of fireball
            delayedBlastFireball = spell;
        }