Need help with this script (RESOLVED)

Hello again

I need help with this spell I am working on. I almost have it…I think

The spell is:

Prismatic Sphere

Caster Level(s): Wiz / Sor 9
Innate Level: 9
School: Abjuration
Descriptor(s): None
Component(s): Verbal, Somatic
Range: Personal
Area of Effect / Target: Self (with effects on the first attacker)
Duration: 1 round / level or until discharged
Additional Counter Spells: Dispel Magic
Save: Reflex partial, Fortitude partial, Will partial (varies by effect)
Spell Resistance: Yes

Description:

Prismatic Sphere surrounds the caster with a radiant multicolored sphere of defensive energy, which unleashes devastating effects on the first creature to successfully strike the caster.

These effects occur in the following sequence:

  1. Blinding Light: Creatures with fewer than 8 Hit Dice must succeed on a Reflex save (DC 20) or be blinded for 10 rounds.

  2. Elemental Fury: Creatures that attack you must make a Fortitude save (DC 20) or take 1d10 points of damage from each of the following damage types: acid, fire, cold, electrical, sonic, divine, positive, negative, piercing, slashing, and bludgeoning.

  3. Instant Death: Creatures must succeed on a Will save (DC 20) or die instantly.

  4. Wyvern Poison: On a failed Fortitude save (DC 20), attackers are afflicted with Wyvern Poison, dealing 1d6 Strength damage per round for 6 rounds or until cured.

  5. Confusion: Creatures that fail a Will save (DC 20) become confused for 2d10 rounds.

  6. Petrification: Creatures must succeed on a Reflex save (DC 20) or be permanently turned to stone.

The sphere dissipates after the first attack, releasing its stored energy.

This spell does not block physical attacks or magic, but its retaliatory effects serve as a potent deterrent to those who dare attack the caster.

Script below that won’t compile:

// Prismatic Sphere

#include "nw_i0_spells"

// VFX Constants for Ion Stones and Globe of Invulnerability
const int VFX_ION_STONE_1;
const int VFX_ION_STONE_2;
const int VFX_ION_STONE_3;
const int VFX_ION_STONE_4;
const int VFX_GLOBE_INVULNERABILITY;

// Forward declaration of helper functions
void ApplyPrismaticSphereEffects(object oAttacker);
void RemovePrismaticSphereVFX(object oCaster);

void Main()
{
    object oCaster = OBJECT_SELF;

    // Spell duration: 1 turn per caster level (10 rounds per level)
    float fDuration = 60.0 * GetCasterLevel(oCaster);

    // Apply visual effects to represent the sphere (Ion Stones and Globe of Invulnerability)
    ApplyEffectToObject(DURATION_TYPE_TEMPORARY, EffectVisualEffect(VFX_ION_STONE_1), oCaster, fDuration);
    ApplyEffectToObject(DURATION_TYPE_TEMPORARY, EffectVisualEffect(VFX_ION_STONE_2), oCaster, fDuration);
    ApplyEffectToObject(DURATION_TYPE_TEMPORARY, EffectVisualEffect(VFX_ION_STONE_3), oCaster, fDuration);
    ApplyEffectToObject(DURATION_TYPE_TEMPORARY, EffectVisualEffect(VFX_ION_STONE_4), oCaster, fDuration);
    ApplyEffectToObject(DURATION_TYPE_TEMPORARY, EffectVisualEffect(VFX_GLOBE_INVULNERABILITY), oCaster, fDuration);

    // Apply a damage shield with 0 damage to detect hits
    effect eShield = EffectDamageShield(0, DAMAGE_TYPE_MAGICAL);
    ApplyEffectToObject(DURATION_TYPE_TEMPORARY, eShield, oCaster, fDuration);

    // Set up a signal for active sphere
    SetLocalInt(oCaster, "PRISMATIC_SPHERE_ACTIVE", TRUE);

    // Cleanup the spell effects after the duration
    DelayCommand(fDuration, RemoveEffect(oCaster, EffectVisualEffect(VFX_ION_STONE_1)));
    DelayCommand(fDuration, RemoveEffect(oCaster, EffectVisualEffect(VFX_ION_STONE_2)));
    DelayCommand(fDuration, RemoveEffect(oCaster, EffectVisualEffect(VFX_ION_STONE_3)));
    DelayCommand(fDuration, RemoveEffect(oCaster, EffectVisualEffect(VFX_ION_STONE_4)));
    DelayCommand(fDuration, RemoveEffect(oCaster, EffectVisualEffect(VFX_GLOBE_INVULNERABILITY)));
    DelayCommand(fDuration, RemoveEffect(oCaster, EffectDamageShield(0, DAMAGE_TYPE_MAGICAL)));

    // Set the spell as inactive
    DelayCommand(fDuration, SetLocalInt(oCaster, "PRISMATIC_SPHERE_ACTIVE", FALSE));
}

void ApplyPrismaticSphereEffects(object oAttacker)
{
    // Effect 1: Blind creatures under 8 HD
    if (GetHitDice(oAttacker) < 8)
    {
        if (!MySavingThrow(SAVING_THROW_FORT, oAttacker, 20))
        {
            ApplyEffectToObject(DURATION_TYPE_TEMPORARY, EffectBlindness(), oAttacker, RoundsToSeconds(10));
        }
    }

    // Effect 2: Take 1d10 of all damage types
    if (!MySavingThrow(SAVING_THROW_FORT, oAttacker, 20))
    {
        ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectDamage(d10(), DAMAGE_TYPE_ACID), oAttacker);
        ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectDamage(d10(), DAMAGE_TYPE_FIRE), oAttacker);
        ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectDamage(d10(), DAMAGE_TYPE_BLUDGEONING), oAttacker);
        ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectDamage(d10(), DAMAGE_TYPE_PIERCING), oAttacker);
        ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectDamage(d10(), DAMAGE_TYPE_SLASHING), oAttacker);
        ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectDamage(d10(), DAMAGE_TYPE_COLD), oAttacker);
        ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectDamage(d10(), DAMAGE_TYPE_ELECTRICAL), oAttacker);
        ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectDamage(d10(), DAMAGE_TYPE_DIVINE), oAttacker);
        ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectDamage(d10(), DAMAGE_TYPE_NEGATIVE), oAttacker);
        ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectDamage(d10(), DAMAGE_TYPE_POSITIVE), oAttacker);
        ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectDamage(d10(), DAMAGE_TYPE_SONIC), oAttacker);
    }

    // Effect 3: Will save or die
    if (!MySavingThrow(SAVING_THROW_WILL, oAttacker, 20))
    {
        ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectDeath(), oAttacker);
    }

    // Effect 4: Fortitude save or be poisoned (Wyvern Poison)
    if (!MySavingThrow(SAVING_THROW_FORT, oAttacker, 20))
    {
        ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectPoison(POISON_WYVERN_POISON), oAttacker);
    }

    // Effect 5: Will save or be confused for 2d10 rounds
    if (!MySavingThrow(SAVING_THROW_WILL, oAttacker, 20))
    {
        ApplyEffectToObject(DURATION_TYPE_TEMPORARY, EffectConfused(), oAttacker, RoundsToSeconds(Random(10) + 2));
    }

    // Effect 6: Reflex save or be petrified
    if (!MySavingThrow(SAVING_THROW_REFLEX, oAttacker, 20))
    {
        ApplyEffectToObject(DURATION_TYPE_PERMANENT, EffectPetrify(), oAttacker);
    }
}

void OnPhysicalAttacked()
{
    object oAttacker = GetLastDamager();
    object oCaster = OBJECT_SELF;

    // Check if the sphere is active
    if (GetLocalInt(oCaster, "PRISMATIC_SPHERE_ACTIVE"))
    {
        // Apply all effects to the attacker
        ApplyPrismaticSphereEffects(oAttacker);

        // Deactivate the sphere
        SetLocalInt(oCaster, "PRISMATIC_SPHERE_ACTIVE", FALSE);
    }
}

I tried to change it just a tiny bit. Now it compiles at least:

// Prismatic Sphere

#include "nw_i0_spells"

// VFX Constants for Ion Stones and Globe of Invulnerability
const int VFX_ION_STONE_1;
const int VFX_ION_STONE_2;
const int VFX_ION_STONE_3;
const int VFX_ION_STONE_4;
const int VFX_GLOBE_INVULNERABILITY;

// Forward declaration of helper functions
void ApplyPrismaticSphereEffects(object oAttacker);
void RemovePrismaticSphereVFX(object oCaster);

void main()
{
    object oCaster = OBJECT_SELF;

    // Spell duration: 1 turn per caster level (10 rounds per level)
    float fDuration = 60.0 * GetCasterLevel(oCaster);

    // Apply visual effects to represent the sphere (Ion Stones and Globe of Invulnerability)
    ApplyEffectToObject(DURATION_TYPE_TEMPORARY, EffectVisualEffect(VFX_ION_STONE_1), oCaster, fDuration);
    ApplyEffectToObject(DURATION_TYPE_TEMPORARY, EffectVisualEffect(VFX_ION_STONE_2), oCaster, fDuration);
    ApplyEffectToObject(DURATION_TYPE_TEMPORARY, EffectVisualEffect(VFX_ION_STONE_3), oCaster, fDuration);
    ApplyEffectToObject(DURATION_TYPE_TEMPORARY, EffectVisualEffect(VFX_ION_STONE_4), oCaster, fDuration);
    ApplyEffectToObject(DURATION_TYPE_TEMPORARY, EffectVisualEffect(VFX_GLOBE_INVULNERABILITY), oCaster, fDuration);

    // Apply a damage shield with 0 damage to detect hits
    effect eShield = EffectDamageShield(0,0,DAMAGE_TYPE_MAGICAL);
    ApplyEffectToObject(DURATION_TYPE_TEMPORARY, eShield, oCaster, fDuration);

    // Set up a signal for active sphere
    SetLocalInt(oCaster, "PRISMATIC_SPHERE_ACTIVE", TRUE);

    // Cleanup the spell effects after the duration
    DelayCommand(fDuration, RemoveEffect(oCaster, EffectVisualEffect(VFX_ION_STONE_1)));
    DelayCommand(fDuration, RemoveEffect(oCaster, EffectVisualEffect(VFX_ION_STONE_2)));
    DelayCommand(fDuration, RemoveEffect(oCaster, EffectVisualEffect(VFX_ION_STONE_3)));
    DelayCommand(fDuration, RemoveEffect(oCaster, EffectVisualEffect(VFX_ION_STONE_4)));
    DelayCommand(fDuration, RemoveEffect(oCaster, EffectVisualEffect(VFX_GLOBE_INVULNERABILITY)));
    DelayCommand(fDuration, RemoveEffect(oCaster, EffectDamageShield(0,0,DAMAGE_TYPE_MAGICAL)));

    // Set the spell as inactive
    DelayCommand(fDuration, SetLocalInt(oCaster, "PRISMATIC_SPHERE_ACTIVE", FALSE));
}

void ApplyPrismaticSphereEffects(object oAttacker)
{
    // Effect 1: Blind creatures under 8 HD
    if (GetHitDice(oAttacker) < 8)
    {
        if (!MySavingThrow(SAVING_THROW_FORT, oAttacker, 20))
        {
            ApplyEffectToObject(DURATION_TYPE_TEMPORARY, EffectBlindness(), oAttacker, RoundsToSeconds(10));
        }
    }

    // Effect 2: Take 1d10 of all damage types
    if (!MySavingThrow(SAVING_THROW_FORT, oAttacker, 20))
    {
        ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectDamage(d10(), DAMAGE_TYPE_ACID), oAttacker);
        ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectDamage(d10(), DAMAGE_TYPE_FIRE), oAttacker);
        ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectDamage(d10(), DAMAGE_TYPE_BLUDGEONING), oAttacker);
        ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectDamage(d10(), DAMAGE_TYPE_PIERCING), oAttacker);
        ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectDamage(d10(), DAMAGE_TYPE_SLASHING), oAttacker);
        ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectDamage(d10(), DAMAGE_TYPE_COLD), oAttacker);
        ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectDamage(d10(), DAMAGE_TYPE_ELECTRICAL), oAttacker);
        ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectDamage(d10(), DAMAGE_TYPE_DIVINE), oAttacker);
        ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectDamage(d10(), DAMAGE_TYPE_NEGATIVE), oAttacker);
        ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectDamage(d10(), DAMAGE_TYPE_POSITIVE), oAttacker);
        ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectDamage(d10(), DAMAGE_TYPE_SONIC), oAttacker);
    }

    // Effect 3: Will save or die
    if (!MySavingThrow(SAVING_THROW_WILL, oAttacker, 20))
    {
        ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectDeath(), oAttacker);
    }

    // Effect 4: Fortitude save or be poisoned (Wyvern Poison)
    if (!MySavingThrow(SAVING_THROW_FORT, oAttacker, 20))
    {
        ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectPoison(POISON_WYVERN_POISON), oAttacker);
    }

    // Effect 5: Will save or be confused for 2d10 rounds
    if (!MySavingThrow(SAVING_THROW_WILL, oAttacker, 20))
    {
        ApplyEffectToObject(DURATION_TYPE_TEMPORARY, EffectConfused(), oAttacker, RoundsToSeconds(Random(10) + 2));
    }

    // Effect 6: Reflex save or be petrified
    if (!MySavingThrow(SAVING_THROW_REFLEX, oAttacker, 20))
    {
        ApplyEffectToObject(DURATION_TYPE_PERMANENT, EffectPetrify(), oAttacker);
    }
}

void OnPhysicalAttacked()
{
    object oAttacker = GetLastDamager();
    object oCaster = OBJECT_SELF;

    // Check if the sphere is active
    if (GetLocalInt(oCaster, "PRISMATIC_SPHERE_ACTIVE"))
    {
        // Apply all effects to the attacker
        ApplyPrismaticSphereEffects(oAttacker);

        // Deactivate the sphere
        SetLocalInt(oCaster, "PRISMATIC_SPHERE_ACTIVE", FALSE);
    }
}

The stuff that game complained about was the function
effect eShield = EffectDamageShield(0, DAMAGE_TYPE_MAGICAL);
which needs two integers if you look at the description:

// Create a Damage Shield effect which does (nDamageAmount + nRandomAmount)
// damage to any melee attacker on a successful attack of damage type nDamageType.
// - nDamageAmount: an integer value
// - nRandomAmount: DAMAGE_BONUS_*
// - nDamageType: DAMAGE_TYPE_*
// NOTE! You *must* use the DAMAGE_BONUS_* constants! Using other values may
//       result in odd behaviour.
effect EffectDamageShield(int nDamageAmount, int nRandomAmount, int nDamageType)

So I just added the nRandomAmount which I set to 0. I don’t know if that was what you wanted, but anyway.
You had also a written void Main() when it should be void main()

I’m not an expert in writing spell scripts but I think

a) every spell script should start with

void main()
{
    if (!X2PreSpellCastCode())
    {
    // If code within the PreSpellCastHook (i.e. UMD) reports FALSE, do not run this spell
        return;
    }
    ...

b) effects should be linked together so in case the spell gets dispelled all effects are removed or none.

c) it’s not required to call

DelayCommand(fDuration, RemoveEffect(...))

as the effects are applied with a duration and are removed automatically.

d) it’s not a good idea to set locals to indicate a spell is active and delete that local after a fixed time as the spell might be dispelled earlier and then the local is not deleted. If it’s really required to use a local one could use the effect EffectRunScript() (see lexicon) to run a script to cleanup once the duration expires or the spell is dispelled.

2 Likes

But the spell should vanish upon the first hit on the caster according to this spell. How do I do that?

Thanks andgalf,

But with your changes and Kamiryn’s below…and my comments to him …not sure what the final script should look like. To be honest I cheated…lol…I got chatgpt to help me with this. Could you or Kamiryn repost the script with the changes you both made with my comments to him.

Well, currently you only delete the local when the caster is hit. The visual effects remain until the duration wears off.

@Imtherealthing - I think @Kamiryn better handle this as it was a lot of suggestions and quite involved. I’m not that used to writing spell scripts either, but…here’s a start. I have removed all the

as Kamiryn suggested. I also added the

    if (!X2PreSpellCastCode())
    {
    // If code within the PreSpellCastHook (i.e. UMD) reports FALSE, do not run this spell
        return;

to the script (also by Kamiryn’s suggestion) and commented out all the setlocal ints. I’m afraid I don’t know where and how to apply the EffectRunScript() as I’ve never used that function before. It’s probably because it’s made for NWNEE. I read in the lexicon what it does, and it does sound neat, I just don’t quite know how to apply it and where. As I stated before, this is quite complicated stuff. It’s just not a simple script that does things. Those kind of scripts I can handle pretty well by now. Anyway, I’ll let @Kamiryn refine this for you. I tried my best:

// Prismatic Sphere

#include "nw_i0_spells"
#include "x2_inc_spellhook"

// VFX Constants for Ion Stones and Globe of Invulnerability
const int VFX_ION_STONE_1;
const int VFX_ION_STONE_2;
const int VFX_ION_STONE_3;
const int VFX_ION_STONE_4;
const int VFX_GLOBE_INVULNERABILITY;

// Forward declaration of helper functions
void ApplyPrismaticSphereEffects(object oAttacker);
void RemovePrismaticSphereVFX(object oCaster);

void main()
{

    if (!X2PreSpellCastCode())
    {
    // If code within the PreSpellCastHook (i.e. UMD) reports FALSE, do not run this spell
        return;
    }

    object oCaster = OBJECT_SELF;

    // Spell duration: 1 turn per caster level (10 rounds per level)
    float fDuration = 60.0 * GetCasterLevel(oCaster);

    // Apply visual effects to represent the sphere (Ion Stones and Globe of Invulnerability)
    ApplyEffectToObject(DURATION_TYPE_TEMPORARY, EffectVisualEffect(VFX_ION_STONE_1), oCaster, fDuration);
    ApplyEffectToObject(DURATION_TYPE_TEMPORARY, EffectVisualEffect(VFX_ION_STONE_2), oCaster, fDuration);
    ApplyEffectToObject(DURATION_TYPE_TEMPORARY, EffectVisualEffect(VFX_ION_STONE_3), oCaster, fDuration);
    ApplyEffectToObject(DURATION_TYPE_TEMPORARY, EffectVisualEffect(VFX_ION_STONE_4), oCaster, fDuration);
    ApplyEffectToObject(DURATION_TYPE_TEMPORARY, EffectVisualEffect(VFX_GLOBE_INVULNERABILITY), oCaster, fDuration);

    // Apply a damage shield with 0 damage to detect hits
    effect eShield = EffectDamageShield(0,0,DAMAGE_TYPE_MAGICAL);
    ApplyEffectToObject(DURATION_TYPE_TEMPORARY, eShield, oCaster, fDuration);

    // Set up a signal for active sphere
    //SetLocalInt(oCaster, "PRISMATIC_SPHERE_ACTIVE", TRUE);

    // Cleanup the spell effects after the duration

    // Set the spell as inactive
    //DelayCommand(fDuration, SetLocalInt(oCaster, "PRISMATIC_SPHERE_ACTIVE", FALSE));
}

void ApplyPrismaticSphereEffects(object oAttacker)
{
    // Effect 1: Blind creatures under 8 HD
    if (GetHitDice(oAttacker) < 8)
    {
        if (!MySavingThrow(SAVING_THROW_FORT, oAttacker, 20))
        {
            ApplyEffectToObject(DURATION_TYPE_TEMPORARY, EffectBlindness(), oAttacker, RoundsToSeconds(10));
        }
    }

    // Effect 2: Take 1d10 of all damage types
    if (!MySavingThrow(SAVING_THROW_FORT, oAttacker, 20))
    {
        ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectDamage(d10(), DAMAGE_TYPE_ACID), oAttacker);
        ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectDamage(d10(), DAMAGE_TYPE_FIRE), oAttacker);
        ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectDamage(d10(), DAMAGE_TYPE_BLUDGEONING), oAttacker);
        ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectDamage(d10(), DAMAGE_TYPE_PIERCING), oAttacker);
        ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectDamage(d10(), DAMAGE_TYPE_SLASHING), oAttacker);
        ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectDamage(d10(), DAMAGE_TYPE_COLD), oAttacker);
        ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectDamage(d10(), DAMAGE_TYPE_ELECTRICAL), oAttacker);
        ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectDamage(d10(), DAMAGE_TYPE_DIVINE), oAttacker);
        ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectDamage(d10(), DAMAGE_TYPE_NEGATIVE), oAttacker);
        ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectDamage(d10(), DAMAGE_TYPE_POSITIVE), oAttacker);
        ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectDamage(d10(), DAMAGE_TYPE_SONIC), oAttacker);
    }

    // Effect 3: Will save or die
    if (!MySavingThrow(SAVING_THROW_WILL, oAttacker, 20))
    {
        ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectDeath(), oAttacker);
    }

    // Effect 4: Fortitude save or be poisoned (Wyvern Poison)
    if (!MySavingThrow(SAVING_THROW_FORT, oAttacker, 20))
    {
        ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectPoison(POISON_WYVERN_POISON), oAttacker);
    }

    // Effect 5: Will save or be confused for 2d10 rounds
    if (!MySavingThrow(SAVING_THROW_WILL, oAttacker, 20))
    {
        ApplyEffectToObject(DURATION_TYPE_TEMPORARY, EffectConfused(), oAttacker, RoundsToSeconds(Random(10) + 2));
    }

    // Effect 6: Reflex save or be petrified
    if (!MySavingThrow(SAVING_THROW_REFLEX, oAttacker, 20))
    {
        ApplyEffectToObject(DURATION_TYPE_PERMANENT, EffectPetrify(), oAttacker);
    }
}

void OnPhysicalAttacked()
{
    object oAttacker = GetLastDamager();
    object oCaster = OBJECT_SELF;

    // Check if the sphere is active
    if (GetLocalInt(oCaster, "PRISMATIC_SPHERE_ACTIVE"))
    {
        // Apply all effects to the attacker
        //ApplyPrismaticSphereEffects(oAttacker);

        // Deactivate the sphere
        //SetLocalInt(oCaster, "PRISMATIC_SPHERE_ACTIVE", FALSE);
    }
}

Maybe you can test it as it is at the moment and see what happens at least, and then maybe add the other stuff that needs to be added.

Another thing I don’t know how to do is the:

I’ve never written a spell script, all I do is looking at existing spell script to see how they work.

Effects can be linked by using EffectLinkEffect().

Another thing that spell scripts should probably have is a line (replace hostile? with TRUE or FALSE depending on the spell)

    //Fire cast spell at event for the specified target
    SignalEvent(oTarget, EventSpellCastAt(OBJECT_SELF, GetSpellId(), hostile?));

to let the target know about the spell.

Removing spell effects can be done by calling

RemoveEffectsFromSpell(oTarget, GetSpellId());

The big problem however is that as far as I can tell OnPhysicalAttacked() is never called and I don’t know how this is properly done. Do you have to overwrite the target’s / caster’s OnPhysicalAttacked event script? Seems not a good idea to me (but I don’t really know).

I think if the spell script is done properly the local is not required (and so is EffectRunScript()) to check whether the spell is active or not.

I see a lot of work that has to be done but I do not know how to do this. At least not without further investigating spell scripts of similar spells (at the moment I do not even know a similar spell) and asking a lot of questions myself. But I do not have the time to do this, sorry.

Ok thanks for looking at it though bud.

Thanks andgalf…could you try to put together whatever you have here so far? I’m lost…lol

I’m not sure how that compiles, surely those constants are defined in nwscript?

Pris wall/sphere break a lot of the usual combat rules. Most of the consequences can be done individually, but the pile of things gets pretty ugly and needs a lot of help in a lot of other areas. It’s the type of things that’d make a cool boss battle where each effect is handled separately but as a single spell, it’s going to take a lot.

Maybe something along the lines of cast spell, get a visual and some pretty beefy buffs + a cast spell on creature hide to cast pris spell which does damage, poison, etc? Check for effects of the spell on the caster when the item triggers to do the things (remember seteffectcasterlevel exists base game now) or clean up and so on. It’ll be complex and definitely not worth the effort, but it’s pretty doable.

I already did. Check my latest post.

Ah…that there is where my problem lays…lol…“too complex”…lol…ChatGPT did most of this then andgalf and Kamiryn put in their ideas too…

Yep, you often try pretty complex stuff, and oftentimes for that to work you need to be a master scripter (not just a basic scripter like me) and a master when it comes to a deep knowledge of how the game works and functions (again, not like me).

The only time I tried something really complicated was when adapting 4760’s horse riding into my own jousting system for my upcoming campaign for NWN2 (will be released in a month). It’s still a bit buggy though (according to one of my three beta testers) but it will have to do. It took a lot of time and effort when putting that together and was super frustrating. I think I must have tested that system 50 or more times myself.

@Imtherealthing - Did you try my rendition of the script? It might not be perfect by any means, but maybe it’ll be ok enough…?

1 Like

You can try with this combination of two scripts.
The first one is the actual spell script, the second one is a script that will be set as the “on damaged” event handler on the caster. The name of this script must be “dmg_prism_custom” or it won’t work.
Unlike the first script, the second one does not have to “slotted” anywhere, it just needs to be present in the module folder (or whatever folder the game retrieves the scripts from)

Spell Script

// Prismatic Sphere
#include "nw_i0_spells"
#include "x2_inc_spellhook"

void ApplySphereEffect(object oPC, int nSPELL, int nSTACK)
{
    // Apply visual effects to represent the sphere (Ion Stones and Globe of Invulnerability)
    float fDUR = 60.0 * GetCasterLevel(oPC);
    effect eFX = EffectVisualEffect(VFX_DUR_GLOBE_INVULNERABILITY);
    eFX = EffectLinkEffects(eFX, EffectVisualEffect(VFX_DUR_IOUNSTONE_BLUE));
    eFX = EffectLinkEffects(eFX, EffectVisualEffect(VFX_DUR_IOUNSTONE_GREEN));
    eFX = EffectLinkEffects(eFX, EffectVisualEffect(VFX_DUR_IOUNSTONE_RED));
    eFX = EffectLinkEffects(eFX, EffectVisualEffect(VFX_DUR_IOUNSTONE_YELLOW));
    eFX = SetEffectSpellId(eFX, nSPELL);
    ApplyEffectToObject(DURATION_TYPE_TEMPORARY, eFX, oPC, fDUR);

    //Set the script handlers if not cast already to avoid loss of the original script
    if (nSTACK == TRUE) return;
    string sSCRIPT = GetEventScript(oPC, EVENT_SCRIPT_CREATURE_ON_DAMAGED);
    SetLocalString(oPC, "ORG_DMG_SCRIPT", sSCRIPT);
    SetEventScript(oPC, EVENT_SCRIPT_CREATURE_ON_DAMAGED, "dmg_prism_custom");
}

void main()
{
    if (!X2PreSpellCastCode())
    {
    // If code within the PreSpellCastHook (i.e. UMD) reports FALSE, do not run this spell
        return;
    }

    object oPC = OBJECT_SELF;
    int nSTACK = FALSE;
    int nSPELL = GetSpellId();
    SetLocalInt(oPC, "PRISM_SPHERE_ID", nSPELL);

    if (GetHasSpellEffect(nSPELL, oPC) == TRUE)
    {
        nSTACK = TRUE;
        RemoveSpellEffects(nSPELL, oPC, oPC);
    }

    DelayCommand(0.01,ApplySphereEffect(oPC, nSPELL, nSTACK));
}

“dmg_prism_custom” Script

#include "nw_i0_spells"

void main()
{
    // Does not trigger against allies that accidentally hit you
    object oPC = OBJECT_SELF;
    object oAttacker = GetLastDamager(oPC);
    if (GetIsEnemy(oAttacker, oPC) == FALSE) return;

    // Reset the script handler if the spell ran out before an enemy actually hit you
    int nSPELL = GetLocalInt(oPC, "PRISM_SPHERE_ID");
    string sSCRIPT = GetLocalString(oPC, "ORG_DMG_SCRIPT");

    if (GetHasSpellEffect(nSPELL, oPC) == FALSE)
    {
        SetEventScript(oPC, EVENT_SCRIPT_CREATURE_ON_DAMAGED, sSCRIPT);
        return;
    }

    // Effect 1: Blind creatures under 8 HD
    if (GetHitDice(oAttacker) < 8)
    {
        if (!MySavingThrow(SAVING_THROW_FORT, oAttacker, 20, SAVING_THROW_TYPE_SPELL, oPC))
        {
            ApplyEffectToObject(DURATION_TYPE_TEMPORARY, EffectBlindness(), oAttacker, RoundsToSeconds(10));
        }
    }

    // Effect 2: Take 1d10 of all damage types
    if (!MySavingThrow(SAVING_THROW_FORT, oAttacker, 20, SAVING_THROW_TYPE_SPELL, oPC))
    {
        ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectDamage(d10(), DAMAGE_TYPE_ACID), oAttacker);
        ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectDamage(d10(), DAMAGE_TYPE_FIRE), oAttacker);
        ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectDamage(d10(), DAMAGE_TYPE_BLUDGEONING), oAttacker);
        ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectDamage(d10(), DAMAGE_TYPE_PIERCING), oAttacker);
        ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectDamage(d10(), DAMAGE_TYPE_SLASHING), oAttacker);
        ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectDamage(d10(), DAMAGE_TYPE_COLD), oAttacker);
        ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectDamage(d10(), DAMAGE_TYPE_ELECTRICAL), oAttacker);
        ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectDamage(d10(), DAMAGE_TYPE_DIVINE), oAttacker);
        ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectDamage(d10(), DAMAGE_TYPE_NEGATIVE), oAttacker);
        ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectDamage(d10(), DAMAGE_TYPE_POSITIVE), oAttacker);
        ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectDamage(d10(), DAMAGE_TYPE_SONIC), oAttacker);
    }

    // Effect 3: Will save or die
    if (!MySavingThrow(SAVING_THROW_WILL, oAttacker, 20, SAVING_THROW_TYPE_DEATH, oPC))
    {
        ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectDeath(), oAttacker);
    }

    // Effect 4: Fortitude save or be poisoned (Wyvern Poison)
    if (!MySavingThrow(SAVING_THROW_FORT, oAttacker, 20, SAVING_THROW_TYPE_POISON, oPC))
    {
        ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectPoison(POISON_WYVERN_POISON), oAttacker);
    }

    // Effect 5: Will save or be confused for 2d10 rounds
    if (!MySavingThrow(SAVING_THROW_WILL, oAttacker, 20, SAVING_THROW_TYPE_MIND_SPELLS, oPC))
    {
        ApplyEffectToObject(DURATION_TYPE_TEMPORARY, EffectConfused(), oAttacker, RoundsToSeconds(Random(19) + 2));
    }

    // Effect 6: Reflex save or be petrified
    if (!MySavingThrow(SAVING_THROW_REFLEX, oAttacker, 20, SAVING_THROW_TYPE_SPELL, oPC))
    {
        ApplyEffectToObject(DURATION_TYPE_PERMANENT, EffectPetrify(), oAttacker);
    }

    //The sphere dissipates. Remove effect and reset the script handler
    RemoveSpellEffects(nSPELL, oPC, oPC);
    SetEventScript(oPC, EVENT_SCRIPT_CREATURE_ON_DAMAGED, sSCRIPT);
}

Let me know if it works out for you.

2 Likes

I haven’t tried it yet, but will. I will also try Clangeddin’s script too. :slight_smile:

Thanks bud

Hi Clangeddin,

Hey thanks for doing this. Not sure if one is dependant on the other? Or is one of the scripts suppose to be on a Module script?

Hi Clagenddin,

I tried your script but it did not work. I attach the module, hak, and tlk for you to test it. Perhaps I did not put the scripts in the right place? Everything is set up for testing. Just need the script to work.

andgalf or anyone else…you can download the zipped file too to test. It does have Clangenddin’s scripts currently in this zipped folder.
Prismatic_Sphere_Spell.zip (150.9 KB)

On your script andgalf I can at least see the vfx effects work on the caster and when the enemies hit I see the vfx effects on them.

But no damage is done as per the spell description I gave above.

Maybe both your and Clangeddin’s scripts can be combined…it’s closer.

As far as I know @Clangeddin works mainly with NWN2, just as I do.

@Clangeddin - I have a hard time comprehending your post where you say:

and then later:

So where do we put the first script exactly? It seems to me that you in your second paragraph talks about the first script and not the second. I almost never dabble with spell scripts myself. The few times I have done it I have had help and in NWN2 there’s something called a spellhook that is used that I’ve never quite got the hang of.

@Imtherealthing Again you try and get me to help with stuff I have no experience with and which @Lokey already told you are quite involved and complicated stuff for a game I don’t even work with. I’ll try but with these things it’s a bit too much work. I don’t have the time or knowledge to deep dive into something like this. In NWN2 there’s something called a spellhook that is used that I’ve never quite got the hang of. Do you use that kind of stuff in NWNEE?