Ok...need a bit of help on my script (RESOLVED)

I want to create the following spell below:

Gaze Reflection

Caster Level(s): Wiz 1
Innate Level: 1
School: Abjuration
Descriptor(s): None
Component(s): V, S
Range: 0
Area of Effect: Caster
Duration: 2 rounds + 1 round/level
Additional Counter Spells: None
Save: None
Spell Resistance: No

Description:

The spell creates a shimmering, mirror-like effect around the caster, offering protection against gaze attacks. While active, the spell grants immunity to charm effects and petrification. Additionally, any gaze-based attack directed at the caster is reflected back to the attacker, forcing them to save against their own effect. The shimmering barrier moves with the caster and lasts for the duration of the spell.

This is the script so far I have smashed together using ChatGPT that is almost there but it keeps giving errors in compiling. I feel like it is close to what needs to be done.

//::///////////////////////////////////////////////
//:: Gaze Reflection Spell
//:: NWN:EE
//::///////////////////////////////////////////////
//:: File Name: sp_gazereflect.nss
//::///////////////////////////////////////////////


#include "nw_i0_spells"

// Reflect a gaze attack back to the attacker
void ReflectGaze(object oCaster, object oAttacker)
{
    // Iterate through effects on the attacker to find gaze-related effects
    object oEffect = GetFirstEffect(oAttacker);

    // Iterate over all effects on the attacker
    while (GetIsEffectValid(oEffect))
    {
        // Check if the effect is a spell effect (e.g., petrification, charm)
        if (GetEffectType(oEffect) == EFFECT_TYPE_SPELL_EFFECT)
        {
            // Apply the effect back to the attacker (reflect it)
            ApplyEffectToObject(DURATION_TYPE_INSTANT, oEffect, oAttacker);
        }
        // Move to the next effect
        oEffect = GetNextEffect(oAttacker);
    }
}

// Apply Gaze Reflection effects to the caster
void ApplyGazeReflection(object oCaster, float fDuration)
{
    // Apply immunity to charm and petrification effects
    object eImmunityCharm = EffectImmunity(IMMUNITY_TYPE_MIND_SPELLS);
    object eImmunityPetrify = EffectImmunity(IMMUNITY_TYPE_PARALYSIS);
    object eCombined = EffectLinkEffects(eImmunityCharm, eImmunityPetrify);

    ApplyEffectToObject(DURATION_TYPE_TEMPORARY, eCombined, oCaster, fDuration);

    // Reflective shimmering mirror-like visual effect
    ApplyEffectToObject(DURATION_TYPE_TEMPORARY, EffectVisualEffect(VFX_DUR_MIRROR), oCaster, fDuration);
}

void main()
{
    object oCaster = OBJECT_SELF;
    float fDuration = RoundsToSeconds(2 + GetCasterLevel(oCaster));

    // Apply the protective effects to the caster
    ApplyGazeReflection(oCaster, fDuration);

    // Set up a loop to check for attackers and reflect their gaze attacks
    object oAttacker = GetNearestCreature(CREATURE_TYPE_IS_ALIVE, TRUE, oCaster, 1, CREATURE_TYPE_REPUTATION, REPUTATION_TYPE_ENEMY);
    while (GetIsObjectValid(oAttacker))
    {
        ReflectGaze(oCaster, oAttacker);
        oAttacker = GetNearestCreature(CREATURE_TYPE_IS_ALIVE, TRUE, oCaster, 1, CREATURE_TYPE_REPUTATION, REPUTATION_TYPE_ENEMY, oAttacker);
    }
}

I found a couple of errors. Change this:

object oEffect = GetFirstEffect(oAttacker);

to this:

effect oEffect = GetFirstEffect(oAttacker);

And then the constant EFFECT_TYPE_SPELL_EFFECT here doesn’t seem to exist according to the NWNEE toolset:

if (GetEffectType(oEffect) == EFFECT_TYPE_SPELL_EFFECT)

Unfortunately there doesn’t seem to be a constant that lets you check for all kinds of spell effects, from what I can gather looking at the constants.

If you know exactly what effects in the list here from the lexicon that the script should look for, I guess I could help you out. Otherwise, this is all I can do for now.

1 Like

It’s prismatic sphere all over again, but worse. Don’t most version 3.x monsters have immune to their own gaze attacks in their description anyway?

The practical way is to rewrite all the gaze attack spell scripts to support this (GetHasSpellEffect on the target for this spell), but there’s a lot of things to think of there too.

For simpler but way hackier: maybe replace the spell cast at script, there’s a lot of copy/paste in spell scripts so the gaze attacks might have a SignalEvent line that triggers those. Don’t recall the state of that event though, how much useful can be done there (it might be there since that’s one way to remove invisible/etc but other hostile calls do that too). We do stuff like this in a prespell call for all spells…

Is there some way to cancel the resistance of the target creature if they are immune to those attacks when the spell is reflected back?

I made your changes…still not compiling…also had chatgpt try to help…no luck.


//::///////////////////////////////////////////////
//:: Gaze Reflection Spell
//:: NWN:EE
//::///////////////////////////////////////////////
//:: File Name: sp_gazereflect.nss
//::///////////////////////////////////////////////

#include "nw_i0_spells"

// Reflect a gaze attack back to the attacker, overriding specific immunities
void ReflectGaze(object oCaster, object oAttacker)
{
    // Iterate through effects on the attacker to find gaze-related effects
    effect eEffect = GetFirstEffect(oAttacker);

    // Iterate over all effects on the attacker
    while (GetIsEffectValid(eEffect))
    {
        // Check for specific effect types to reflect
        int nEffectType = GetEffectType(eEffect);

        if (nEffectType == EFFECT_TYPE_CHARMED ||
            nEffectType == EFFECT_TYPE_PARALYZE ||
            nEffectType == EFFECT_TYPE_PETRIFY)
        {
            // Remove specific immunities to allow reflection
            effect eRemoveParalysisImmunity = EffectImmunity(IMMUNITY_TYPE_PARALYSIS);
            effect eRemoveMindSpellImmunity = EffectImmunity(IMMUNITY_TYPE_MIND_SPELLS);

            // Apply the immunity removal to the attacker
            ApplyEffectToObject(DURATION_TYPE_INSTANT, eRemoveParalysisImmunity, oAttacker);
            ApplyEffectToObject(DURATION_TYPE_INSTANT, eRemoveMindSpellImmunity, oAttacker);

            // Apply the effect back to the attacker (reflect it)
            ApplyEffectToObject(DURATION_TYPE_INSTANT, eEffect, oAttacker);
        }

        // Move to the next effect
        eEffect = GetNextEffect(oAttacker);
    }
}

// Apply Gaze Reflection effects to the caster
void ApplyGazeReflection(object oCaster, float fDuration)
{
    // Apply immunity to charm and petrification effects
    effect eImmunityCharm = EffectImmunity(IMMUNITY_TYPE_MIND_SPELLS);
    effect eImmunityPetrify = EffectImmunity(IMMUNITY_TYPE_PARALYSIS);
    effect eCombined = EffectLinkEffects(eImmunityCharm, eImmunityPetrify);

    ApplyEffectToObject(DURATION_TYPE_TEMPORARY, eCombined, oCaster, fDuration);

    // Reflective shimmering mirror-like visual effect
    ApplyEffectToObject(DURATION_TYPE_TEMPORARY, EffectVisualEffect(295), oCaster, fDuration);
}

void main()
{
    object oCaster = OBJECT_SELF;
    float fDuration = RoundsToSeconds(2 + GetCasterLevel(oCaster));

    // Apply the protective effects to the caster
    ApplyGazeReflection(oCaster, fDuration);

    // Reflect gaze attacks from all nearby enemies
    object oAttacker = GetNearestCreature(CREATURE_TYPE_IS_ALIVE, TRUE, oCaster, 1, CREATURE_TYPE_REPUTATION, REPUTATION_TYPE_ENEMY);
    while (GetIsObjectValid(oAttacker))
    {
        ReflectGaze(oCaster, oAttacker);

        // Find the next nearest enemy (avoiding infinite loops)
        oAttacker = GetNearestCreature(CREATURE_TYPE_IS_ALIVE, TRUE, oCaster, 1, CREATURE_TYPE_REPUTATION, REPUTATION_TYPE_ENEMY, oAttacker);
    }
}

Ok, I’ll try and look into it. By the way:

Unfortunately I don’t have a clue how to do a thing like this.

The problem is this here:

// Find the next nearest enemy (avoiding infinite loops)
        oAttacker = GetNearestCreature(CREATURE_TYPE_IS_ALIVE, TRUE, oCaster, 1, CREATURE_TYPE_REPUTATION, REPUTATION_TYPE_ENEMY, oAttacker);

ChatGPT wrongly tries to find the next nearest enemy by just using GetNearestCreature that you already used before going in to the “while loop”, and it added oAttacker at the end of the function which is totally wrong, causing it not to compile. As you need to find the “next enemy” that function doesn’t do that, and there is no function to my knowledge that does that. I’ll try something out, but this is a bit above my skill level.

I have no idea if this will work. It’s untested:

//::///////////////////////////////////////////////
//:: Gaze Reflection Spell
//:: NWN:EE
//::///////////////////////////////////////////////
//:: File Name: sp_gazereflect.nss
//::///////////////////////////////////////////////

#include "nw_i0_spells"

// Reflect a gaze attack back to the attacker, overriding specific immunities
void ReflectGaze(object oCaster, object oAttacker)
{
    // Iterate through effects on the attacker to find gaze-related effects
    effect eEffect = GetFirstEffect(oAttacker);

    // Iterate over all effects on the attacker
    while (GetIsEffectValid(eEffect))
    {
        // Check for specific effect types to reflect
        int nEffectType = GetEffectType(eEffect);

        if (nEffectType == EFFECT_TYPE_CHARMED ||
            nEffectType == EFFECT_TYPE_PARALYZE ||
            nEffectType == EFFECT_TYPE_PETRIFY)
        {
            // Remove specific immunities to allow reflection
            effect eRemoveParalysisImmunity = EffectImmunity(IMMUNITY_TYPE_PARALYSIS);
            effect eRemoveMindSpellImmunity = EffectImmunity(IMMUNITY_TYPE_MIND_SPELLS);

            // Apply the immunity removal to the attacker
            ApplyEffectToObject(DURATION_TYPE_INSTANT, eRemoveParalysisImmunity, oAttacker);
            ApplyEffectToObject(DURATION_TYPE_INSTANT, eRemoveMindSpellImmunity, oAttacker);

            // Apply the effect back to the attacker (reflect it)
            ApplyEffectToObject(DURATION_TYPE_INSTANT, eEffect, oAttacker);
        }

        // Move to the next effect
        eEffect = GetNextEffect(oAttacker);
    }
}

// Apply Gaze Reflection effects to the caster
void ApplyGazeReflection(object oCaster, float fDuration)
{
    // Apply immunity to charm and petrification effects
    effect eImmunityCharm = EffectImmunity(IMMUNITY_TYPE_MIND_SPELLS);
    effect eImmunityPetrify = EffectImmunity(IMMUNITY_TYPE_PARALYSIS);
    effect eCombined = EffectLinkEffects(eImmunityCharm, eImmunityPetrify);

    ApplyEffectToObject(DURATION_TYPE_TEMPORARY, eCombined, oCaster, fDuration);

    // Reflective shimmering mirror-like visual effect
    ApplyEffectToObject(DURATION_TYPE_TEMPORARY, EffectVisualEffect(295), oCaster, fDuration);
}

void main()
{
    object oCaster = OBJECT_SELF;
    float fDuration = RoundsToSeconds(2 + GetCasterLevel(oCaster));

    // Apply the protective effects to the caster
    ApplyGazeReflection(oCaster, fDuration);
    // Please change to the tag of the area here
    object oArea = GetObjectByTag("areatag");
    // Reflect gaze attacks from all nearby enemies
    //object oAttacker = GetNearestCreature(CREATURE_TYPE_IS_ALIVE, TRUE, oCaster, 1, CREATURE_TYPE_REPUTATION, REPUTATION_TYPE_ENEMY);
    object oAttacker = GetFirstObjectInArea(oArea,OBJECT_TYPE_CREATURE);
    while (GetIsObjectValid(oAttacker))
    {

        if(GetIsEnemy(oCaster,oAttacker))
        {
            ReflectGaze(oCaster, oAttacker);
        }
        // Find the next nearest enemy (avoiding infinite loops)
        //oAttacker = GetNearestCreature(CREATURE_TYPE_IS_ALIVE, TRUE, oCaster, 1, CREATURE_TYPE_REPUTATION, REPUTATION_TYPE_ENEMY, oAttacker);
        oAttacker = GetNextObjectInArea(oArea,OBJECT_TYPE_CREATURE);
    }
}

Be aware: You need to change the tag of the area the caster and the enemies are in, in the script, before you test it:

// Please change to the tag of the area here
    object oArea = GetObjectByTag("areatag");

Thanks andgalf

I gave chatgpt your script and your comments to help it learn too. This is what it said:

Thank you for bringing this to my attention. The issues and the subsequent adjustments pointed out by the fellow scripter highlight an important concept: understanding the limitations of available functions in NWN’s scripting language and appropriately adapting to them.

Key Observations

  1. The Original Problem:
  • My original approach misused GetNearestCreature to iteratively fetch “next enemies,” which was incorrect as the function doesn’t support this type of iteration.
  • Adding oAttacker as the LastObject parameter does not create a functional loop for subsequent creatures.
  1. The Corrected Script:
  • The corrected script resolves this by using GetFirstObjectInArea and GetNextObjectInArea to iterate through all creatures in the specified area.
  • The adjustment introduces a conditional check (GetIsEnemy) to ensure that only valid enemies are processed.
  1. Area Tag:
  • The script assumes a specific area tag is set manually. This requires the user to edit the script and replace "areatag" with the actual tag of the area in question.

Recommendations for Improvement

To avoid the manual tag replacement (which can lead to errors if the wrong tag is used), the script could automatically determine the area of the caster. This makes the script more versatile and less prone to user error.

Here’s an adjusted version:

//::///////////////////////////////////////////////
//:: Gaze Reflection Spell
//:: NWN:EE
//::///////////////////////////////////////////////
//:: File Name: sp_gazereflect.nss
//::///////////////////////////////////////////////

#include "nw_i0_spells"

// Reflect a gaze attack back to the attacker, overriding specific immunities
void ReflectGaze(object oCaster, object oAttacker)
{
    // Iterate through effects on the attacker to find gaze-related effects
    effect eEffect = GetFirstEffect(oAttacker);

    // Iterate over all effects on the attacker
    while (GetIsEffectValid(eEffect))
    {
        // Check for specific effect types to reflect
        int nEffectType = GetEffectType(eEffect);

        if (nEffectType == EFFECT_TYPE_CHARMED ||
            nEffectType == EFFECT_TYPE_PARALYZE ||
            nEffectType == EFFECT_TYPE_PETRIFY)
        {
            // Remove specific immunities to allow reflection
            effect eRemoveParalysisImmunity = EffectImmunity(IMMUNITY_TYPE_PARALYSIS);
            effect eRemoveMindSpellImmunity = EffectImmunity(IMMUNITY_TYPE_MIND_SPELLS);

            // Apply the immunity removal to the attacker
            ApplyEffectToObject(DURATION_TYPE_INSTANT, eRemoveParalysisImmunity, oAttacker);
            ApplyEffectToObject(DURATION_TYPE_INSTANT, eRemoveMindSpellImmunity, oAttacker);

            // Apply the effect back to the attacker (reflect it)
            ApplyEffectToObject(DURATION_TYPE_INSTANT, eEffect, oAttacker);
        }

        // Move to the next effect
        eEffect = GetNextEffect(oAttacker);
    }
}

// Apply Gaze Reflection effects to the caster
void ApplyGazeReflection(object oCaster, float fDuration)
{
    // Apply immunity to charm and petrification effects
    effect eImmunityCharm = EffectImmunity(IMMUNITY_TYPE_MIND_SPELLS);
    effect eImmunityPetrify = EffectImmunity(IMMUNITY_TYPE_PARALYSIS);
    effect eCombined = EffectLinkEffects(eImmunityCharm, eImmunityPetrify);

    ApplyEffectToObject(DURATION_TYPE_TEMPORARY, eCombined, oCaster, fDuration);

    // Reflective shimmering mirror-like visual effect
    ApplyEffectToObject(DURATION_TYPE_TEMPORARY, EffectVisualEffect(295), oCaster, fDuration);
}

void main()
{
    object oCaster = OBJECT_SELF;
    float fDuration = RoundsToSeconds(2 + GetCasterLevel(oCaster));

    // Apply the protective effects to the caster
    ApplyGazeReflection(oCaster, fDuration);

    // Automatically detect the area of the caster
    object oArea = GetArea(oCaster);

    // Reflect gaze attacks from all nearby enemies
    object oAttacker = GetFirstObjectInArea(oArea, OBJECT_TYPE_CREATURE);
    while (GetIsObjectValid(oAttacker))
    {
        // Process only enemies of the caster
        if (GetIsEnemy(oCaster, oAttacker))
        {
            ReflectGaze(oCaster, oAttacker);
        }
        // Move to the next object in the area
        oAttacker = GetNextObjectInArea(oArea, OBJECT_TYPE_CREATURE);
    }
}

Changes Made:

  1. Dynamic Area Detection:
  • Replaced GetObjectByTag("areatag") with GetArea(oCaster) to dynamically determine the area where the caster is located.
  1. Improved Comments:
  • Added clear documentation to guide users on the functionality of each block.
  1. General Robustness:
  • By eliminating the need for manual tag entry, the script is less error-prone.

This version eliminates the need for user intervention while maintaining the core functionality. Let me know if you’d like to test or further refine it!

Ok…I have made further fixes. Spell still does not work as the spell description below:

Gaze Reflection

Caster Level(s): Bard 2, Wiz/Sorc 1
Innate Level: 2
School: Transmutation
Descriptor(s): None
Component(s): V, S
Range: 0
Area of Effect: Caster
Duration: 2 rounds + 1 round/level
Additional Counter Spells: None
Save: None
Spell Resistance: No

Description:

The spell creates a shimmering, mirror-like effect around the caster, offering protection against gaze attacks. While active, the spell grants immunity to charm effects and petrification. Additionally, any gaze-based attack directed at the caster is reflected back to the attacker, forcing them to save against their own effect. The shimmering barrier moves with the caster and lasts for the duration of the spell.

So I attached a DEMO module zipped.

Just need the script in the module to work. I have everything in the module. I will of course fine tune stuff (i.e. the final VFX for the spell)
Gaze_Reflection_Spell_ DEMO.zip (90.0 KB)

If anyone can help I’d give credit and appreciate it. It’s close.

Ok, ChatGPT may say all this, but the reality is always a bit more complicated. I agree with it with using GetArea(oCaster) though. It should work, I believe. But you have to try it out. I wouldn’t assume anything before testing if I were you.

Tested it…try it the demo module I attached. Still not working.

LOL…I love how you totally did something chatgpt could not figure out…you taught it something…good on you. :slight_smile:

What doesn’t work then? I don’t have time to go into testing your module at the moment, so if you could just describe what works and what doesn’t then maybe I could help further.

Or maybe you could just say to ChatGPT that it doesn’t work and it will give you another long answer, like it always does (I’ve used ChatGPT somewhat myself lately too). :wink:

I have redone the script with comments to see where it runs or doesn’t run. Please check and see which of the following messages you receive while testing it:

“oAttacker object is valid!”
“oAttacker is enemy!”
“ReflectGaze function is running”
“EffectType is either charmed,paralyze or petrify”

Here’s the revised script:

//::///////////////////////////////////////////////
//:: Gaze Reflection Spell
//:: NWN:EE
//::///////////////////////////////////////////////
//:: File Name: sp_gazereflect.nss
//::///////////////////////////////////////////////

#include "nw_i0_spells"

// Reflect a gaze attack back to the attacker, overriding specific immunities
void ReflectGaze(object oCaster, object oAttacker)
{

	object oPC = GetFirstPC();
	
	SendMessageToPC(oPC,"ReflectGaze function is running");

    // Iterate through effects on the attacker to find gaze-related effects
    effect eEffect = GetFirstEffect(oAttacker);

    // Iterate over all effects on the attacker
    while (GetIsEffectValid(eEffect))
    {
        // Check for specific effect types to reflect
        int nEffectType = GetEffectType(eEffect);

        if (nEffectType == EFFECT_TYPE_CHARMED ||
            nEffectType == EFFECT_TYPE_PARALYZE ||
            nEffectType == EFFECT_TYPE_PETRIFY)
        {
            
			SendMessageToPC(oPC,"EffectType is either charmed,paralyze or petrify");
			// Remove specific immunities to allow reflection
            effect eRemoveParalysisImmunity = EffectImmunity(IMMUNITY_TYPE_PARALYSIS);
            effect eRemoveMindSpellImmunity = EffectImmunity(IMMUNITY_TYPE_MIND_SPELLS);

            // Apply the immunity removal to the attacker
            ApplyEffectToObject(DURATION_TYPE_INSTANT, eRemoveParalysisImmunity, oAttacker);
            ApplyEffectToObject(DURATION_TYPE_INSTANT, eRemoveMindSpellImmunity, oAttacker);

            // Apply the effect back to the attacker (reflect it)
            ApplyEffectToObject(DURATION_TYPE_INSTANT, eEffect, oAttacker);
        }

        // Move to the next effect
        eEffect = GetNextEffect(oAttacker);
    }
}

// Apply Gaze Reflection effects to the caster
void ApplyGazeReflection(object oCaster, float fDuration)
{
    // Apply immunity to charm and petrification effects
    effect eImmunityCharm = EffectImmunity(IMMUNITY_TYPE_MIND_SPELLS);
    effect eImmunityPetrify = EffectImmunity(IMMUNITY_TYPE_PARALYSIS);
    effect eCombined = EffectLinkEffects(eImmunityCharm, eImmunityPetrify);

    ApplyEffectToObject(DURATION_TYPE_TEMPORARY, eCombined, oCaster, fDuration);

    // Reflective shimmering mirror-like visual effect
    ApplyEffectToObject(DURATION_TYPE_TEMPORARY, EffectVisualEffect(295), oCaster, fDuration);
}

void main()
{
    object oCaster = OBJECT_SELF;
	object oPC = GetFirstPC();
    float fDuration = RoundsToSeconds(2 + GetCasterLevel(oCaster));

    // Apply the protective effects to the caster
    ApplyGazeReflection(oCaster, fDuration);

    // Automatically detect the area of the caster
    object oArea = GetArea(oCaster);

    // Reflect gaze attacks from all nearby enemies
    object oAttacker = GetFirstObjectInArea(oArea, OBJECT_TYPE_CREATURE);
	
    while (GetIsObjectValid(oAttacker))
    {
		SendMessageToPC(oPC,"oAttacker object is valid!");
	    // Process only enemies of the caster
        if (GetIsEnemy(oCaster, oAttacker))
        {            
			SendMessageToPC(oPC,"oAttacker is enemy!");
			ReflectGaze(oCaster, oAttacker);
        }
        // Move to the next object in the area
        oAttacker = GetNextObjectInArea(oArea, OBJECT_TYPE_CREATURE);
    }
}

There’s ignore immunity for effects in ee now (might be .37 preview).

If there is do you know how to script that into this script?

I will test this…thanks andgalf for all your help and efforts

LOL…trust me…ChatGPT and I are well aquainted…argued many times…it constantly makes mistakes…uses non-NWN scripting even when I tell it to use ONLY NWN:EE functions, variables, and constants found in the game…no creative scripting!!!..yet it does it over and over again…I berate it and all it has to say is…Yes, you’re right, I’m sorry…over and over like it does not read the previous stuff it’s done.

Put your new script in…my PC still gets turned to stone :frowning:

You get none of the messages I asked you about? It’s important that you answer this for me to help you further.