Help with script - spell affecting a door


#21

It’s not ideal because you can’t target the door, but if you feel it’s clear to the player that they need to ‘encompass’ the door with the Sound Burst effect, you can achieve this through a Spell Hook. Have a look in the Lexicon for more info, but you can set a variable in Module properties

X2_S_UD_SPELLSCRIPT string my_spellhook

Then create a script called my_spellhook and put the following code in

#include "x2_inc_switches"

void main()
{
    int nSpell=GetSpellId();
    object oTarget = GetSpellTargetObject();
    location lLoc = GetSpellTargetLocation();
    switch (nSpell)
    {
        case 167:
        FloatingTextStringOnCreature("Sound Burst", GetFirstPC());
        oTarget = GetFirstObjectInShape(SHAPE_SPHERE, RADIUS_SIZE_MEDIUM, lLoc, FALSE, OBJECT_TYPE_DOOR);
        while (GetIsObjectValid(oTarget))
        {
            if(GetTag(oTarget)== "MetalDoor")
            {
                FloatingTextStringOnCreature("SoundBurst hits door", GetFirstPC());
                SetModuleOverrideSpellScriptFinished();
            }
            oTarget = GetNextObjectInShape(SHAPE_SPHERE, RADIUS_SIZE_MEDIUM, lLoc, FALSE, OBJECT_TYPE_DOOR);
        }

        break;
    }
}

Change the "MetalDoor’ to the tag of your door(or placeable) - if you are going with the placeable approach, replace OBJECT_TYPE_DOOR with OBJECT_TYPE_PLACEABLE


#22
#include "x2_inc_switches"

void main()
{
	int       iSpell       = GetSpellId();
	object    oTarget      = GetSpellTargetObject();
	location  lLoc         = GetSpellTargetLocation();
	float     fRadius;
	string    sName;

	if (iSpell == SPELL_SOUND_BURST)
	{
		fRadius = RADIUS_SIZE_MEDIUM;
	}
	else
	if (iSpell == SPELL_DISPEL_MAGIC && !GetIsObjectValid(oTarget))
	{
		fRadius = RADIUS_SIZE_LARGE;
	}
	else
		return;

	sName = GetStringByStrRef(StringToInt(Get2DAString("Spells", "Name", iSpell)));
	oTarget = GetFirstObjectInShape(SHAPE_SPHERE, fRadius, lLoc, FALSE, OBJECT_TYPE_DOOR);
	while (GetIsObjectValid(oTarget))
	{
		if (GetTag(oTarget)== "door_out")
		{
			FloatingTextStringOnCreature(sName + " hits the door", OBJECT_SELF);
			SetLocalInt(oTarget, IntToString(iSpell) + "_triggered", TRUE);
			if (GetLocalInt(oTarget, IntToString(SPELL_SOUND_BURST) + "_triggered") &&
				GetLocalInt(oTarget, IntToString(SPELL_DISPEL_MAGIC) + "_triggered"))
			{
				DestroyObject(oTarget, 0.5);
			}
            return;
		}
		oTarget = GetNextObjectInShape(SHAPE_SPHERE, fRadius, lLoc, FALSE, OBJECT_TYPE_DOOR);
	}

}

Just rewrote a bit the script above.


#23

Upd. Found a typo: RADIUS_SIZE_* constants should be float. Fixed.


#24

Sigh. None of this worked strangely enough, but I’m probably doing it the wrong way as usual…

I first tried with creating a script hidden creature where I took away everyting on the “Scripts” slots accept I put my script at the OnSpellCastAt slot. As before, weirdly enough, the game only recognizes when Dispel Magic is cast. I disabled the Disable AI While Hidden, and tested with that. When that didn’t work I tested with that enabled. I then tested using the default scripts at the Scripts slots on the creature except for the OnSpellCastAt slot, where I put my script, and enabled Disable AI While Hidden…

Since all that didn’t work I tried with your my_spellhook script but that didn’t do anything, so there I think I didn’t understand fully what to do. I went to Module Properties Scripts/Variables where I put X2_S_UD_SPELLSCRIPT and then used the my_spellhook script as string. Like this:

variables2

Was that the wrong thing to do? (Of course I also first created a script called my_spellhook where I put Aqvilinus version of Phantasma’s script)


#25

re. scripthidden creature vs SoundBurst

bleh, the SignalEvent is hidden inside a check for hostile target …


#26

I’m not sure I get what you mean kevL_s…

Does it mean you can’t affect a scripthidden creature with SoundBurst?

I tried making the scripthidden creature hostile (had him being commoner before) but that didn’t change anything.


#27

if you look in the spellscript it goes something like this

object oTarget = GetFirstObjectInShape(SHAPE_SPHERE, RADIUS_SIZE_MEDIUM, lSpell);
while (GetIsObjectValid(oTarget))
{
    if (spellsIsTarget(oTarget, SPELL_TARGET_STANDARDHOSTILE, OBJECT_SELF))
    {
        SignalEvent(oTarget, EventSpellCastAt(OBJECT_SELF, SPELL_SOUND_BURST));

but when I changed that to

object oTarget = GetFirstObjectInShape(SHAPE_SPHERE, RADIUS_SIZE_MEDIUM, lSpell);
while (GetIsObjectValid(oTarget))
{
        SignalEvent(oTarget, EventSpellCastAt(OBJECT_SELF, SPELL_SOUND_BURST));

    if (spellsIsTarget(oTarget, SPELL_TARGET_STANDARDHOSTILE, OBJECT_SELF))
    {

then the OnSpellCastAt script registered the SoundBurst …

 
I doubt that scripthidden creatures will ever register as hostile (even if their AI-events are kept enabled)

look more closely into using a spellhook i guess,


#28

As a starting point, you can check that your spell hook is set up correctly by putting a line of debug directly before the first ‘if’ statement, e.g.

FloatingTextStringOnCreature("Spell id = " + IntToString(iSpell), GetFirstPC());

That will at least help to start narrowing down where the problem lies, if you don’t get that message when you cast any spell, your spell hook isn’t being invoked.

Also make sure that “door_out” is the tag of your door, or that you change the script to match the actual tag of your door. I’m not sure if the script is correct in using OBJECT_SELF in its message, it may be, but if things seem to be working but you’re not getting the “hits the door” message, change OBJECT_SELF to GetFirstPC() to keep things simple.


#29

My brother helped me and after 1 and a half hours searching we found out what was the problem. My module uses ColorsFade’s Companion System, and in his OnModuleLoad script, that I copied, he had a line that looked like this:

SetLocalString(GetModule(),"X2_S_UD_SPELLSCRIPT", "d_spellhook");

Since I don’t have or use his d_spellhook script I just replaced that with my_spellhook, and now everything works as it should.

Thanks everyone for all the help!


#30

However, one odd thing happens and that is that the text “Sound Burst hits the door” and “Dispel Magic hits the door” appear two times each. I wonder why that is…


#31

The updated script works fine for me (just one message appears) - double-check you haven’t made any copy/paste errors in the amended script, or feel free to post your latest code :slight_smile:


#32

I’m not sure but I don’t think so. Here is the code:

void main()
{
	int       iSpell       = GetSpellId();
	object    oTarget      = GetSpellTargetObject();
	location  lLoc         = GetSpellTargetLocation();
	float     fRadius;
	string    sName;

	if (iSpell == SPELL_SOUND_BURST)
	{
		fRadius = RADIUS_SIZE_MEDIUM;
	}
	else
	if (iSpell == SPELL_DISPEL_MAGIC && !GetIsObjectValid(oTarget))
	{
		fRadius = RADIUS_SIZE_LARGE;
	}
	else
		return;

	sName = GetStringByStrRef(StringToInt(Get2DAString("Spells", "Name", iSpell)));
	oTarget = GetFirstObjectInShape(SHAPE_SPHERE, fRadius, lLoc, FALSE, OBJECT_TYPE_DOOR);
	while (GetIsObjectValid(oTarget))
	{
		if (GetTag(oTarget)== "door_out")
		{
			FloatingTextStringOnCreature(sName + " hits the door", OBJECT_SELF);
			SetLocalInt(oTarget, IntToString(iSpell) + "_triggered", TRUE);
			if (GetLocalInt(oTarget, IntToString(SPELL_SOUND_BURST) + "_triggered") &&
				GetLocalInt(oTarget, IntToString(SPELL_DISPEL_MAGIC) + "_triggered"))
			{
				DestroyObject(oTarget, 0.5);
			}
            return;
		}
		oTarget = GetNextObjectInShape(SHAPE_SPHERE, fRadius, lLoc, FALSE, OBJECT_TYPE_DOOR);
	}

}

#33

If you are controlling a companion, then the floating text will broadcast twice. To prevent that, ensure that the bBroadcastToFaction parameter is set to FALSE. Like this:

FloatingTextStringOnCreature(sName + " hits the door", OBJECT_SELF, FALSE);


#34

Thank you, travus! That solved it.


#35

So, I went back and added to this script in my module. But now I have a problem again.

In my mod I have a rabbit that is really a human that has been transformed and is locked behind a magical barrier. So I thought if the PC casts Dispel Magic and then uses a custom item with Cast Spell:Unique Power the character then disappears (gets destroyed) and then I’ll spawn in a human character. But the script doesn’t really work. I think it has to do with the item and Cast Spell:Unique Power. Here is the whole script with the new stuff (the stuff concering the “esaspia” object) at the end:

#include "x2_inc_switches"

void main()
{
	int       iSpell       = GetSpellId();
	object    oTarget      = GetSpellTargetObject();
	location  lLoc         = GetSpellTargetLocation();
	float     fRadius;
	string    sName;

	object oPC = GetFirstPC();

	if (iSpell == SPELL_SOUND_BURST)
	{
		fRadius = RADIUS_SIZE_MEDIUM;
	}
	else
	if (iSpell == SPELL_DISPEL_MAGIC)
	{
		fRadius = RADIUS_SIZE_LARGE;
	}
	else
	if (iSpell == SPELL_TRUE_SEEING)
	{
		fRadius = RADIUS_SIZE_LARGE;
	}
	
	else
		return;

	sName = GetStringByStrRef(StringToInt(Get2DAString("Spells", "Name", iSpell)));
	oTarget = GetFirstObjectInShape(SHAPE_SPHERE, fRadius, lLoc, FALSE, OBJECT_TYPE_DOOR);
	while (GetIsObjectValid(oTarget))
	{
		if (GetTag(oTarget)== "door_out")
		{
			FloatingTextStringOnCreature(sName + " hits the door", OBJECT_SELF,FALSE);
			SetLocalInt(oTarget, IntToString(iSpell) + "_triggered", TRUE);
			if (GetLocalInt(oTarget, IntToString(SPELL_SOUND_BURST) + "_triggered") &&
				GetLocalInt(oTarget, IntToString(SPELL_DISPEL_MAGIC) + "_triggered"))
			{
				DestroyObject(oTarget, 0.5);
			}
            return;
		}
		oTarget = GetNextObjectInShape(SHAPE_SPHERE, fRadius, lLoc, FALSE, OBJECT_TYPE_DOOR);		
	}
	
	oTarget = GetFirstObjectInShape(SHAPE_SPHERE, fRadius, lLoc, FALSE, OBJECT_TYPE_PLACEABLE);
	while (GetIsObjectValid(oTarget))
	{
		if (GetTag(oTarget)== "PLC_NL_ROCKFCE01")
		{
			FloatingTextStringOnCreature(sName + " hits the rocks", OBJECT_SELF,FALSE);
			SetLocalInt(oTarget, IntToString(iSpell) + "_triggered", TRUE);
			if (GetLocalInt(oTarget, IntToString(SPELL_TRUE_SEEING) + "_triggered"))
			{
				DestroyObject(oTarget, 0.5);
				SetLocalInt(oPC,"rocksdestroyed",1);
			}
            return;
		}
		oTarget = GetNextObjectInShape(SHAPE_SPHERE, fRadius, lLoc, FALSE, OBJECT_TYPE_PLACEABLE);
	}
	
	oTarget = GetFirstObjectInShape(SHAPE_SPHERE, fRadius, lLoc, FALSE, OBJECT_TYPE_CREATURE);
	object spellItem = GetItemActivated();
	object oRabbit = GetObjectByTag("esaspia");
	while (GetIsObjectValid(oTarget))
	{
		if (GetTag(oTarget)== "esaspia")
		{
			if (GetIsObjectValid(spellItem) && GetTag(spellItem) == "ltransmutate")
			{
				FloatingTextStringOnCreature("Transmutate hits the rabbit", oRabbit,FALSE);
				SetLocalInt(oTarget, "transmutate_triggered", TRUE);
			}
			else if (iSpell == SPELL_DISPEL_MAGIC)
			{
				FloatingTextStringOnCreature(sName + " hits the rabbit", OBJECT_SELF,FALSE);
				SetLocalInt(oTarget, IntToString(iSpell) + "_triggered", TRUE);
			}
			else
			{
				FloatingTextStringOnCreature(sName + " hits the rabbit", OBJECT_SELF,FALSE);
			}
			
			if (GetLocalInt(oTarget, IntToString(SPELL_DISPEL_MAGIC) + "_triggered") &&
				GetLocalInt(oTarget, "transmutate_triggered"))
			{
				DestroyObject(oTarget, 0.5);
			}
            return;
		}
		oTarget = GetNextObjectInShape(SHAPE_SPHERE, fRadius, lLoc, FALSE, OBJECT_TYPE_CREATURE);	
	}
}

The thing that doesn’t quite work is this part:

	oTarget = GetFirstObjectInShape(SHAPE_SPHERE, fRadius, lLoc, FALSE, OBJECT_TYPE_CREATURE);
	object spellItem = GetItemActivated();
	object oRabbit = GetObjectByTag("esaspia");
	while (GetIsObjectValid(oTarget))
	{
		if (GetTag(oTarget)== "esaspia")
		{
			if (GetIsObjectValid(spellItem) && GetTag(spellItem) == "ltransmutate")
			{
				FloatingTextStringOnCreature("Transmutate hits the rabbit", oRabbit,FALSE);
				SetLocalInt(oTarget, "transmutate_triggered", TRUE);
			}
			else if (iSpell == SPELL_DISPEL_MAGIC)
			{
				FloatingTextStringOnCreature(sName + " hits the rabbit", OBJECT_SELF,FALSE);
				SetLocalInt(oTarget, IntToString(iSpell) + "_triggered", TRUE);
			}
			else
			{
				FloatingTextStringOnCreature(sName + " hits the rabbit", OBJECT_SELF,FALSE);
			}
			
			if (GetLocalInt(oTarget, IntToString(SPELL_DISPEL_MAGIC) + "_triggered") &&
				GetLocalInt(oTarget, "transmutate_triggered"))
			{
				DestroyObject(oTarget, 0.5);
			}
            return;
		}
		oTarget = GetNextObjectInShape(SHAPE_SPHERE, fRadius, lLoc, FALSE, OBJECT_TYPE_CREATURE);	
	}

Mainly it is the:

FloatingTextStringOnCreature("Transmutate hits the rabbit", oRabbit,FALSE);

that doesn’t work. I’m sure there are things here that I’m doing wrong, and maybe someone could help me perhaps…


#36

Try this:

//spellhook_script

#include "x2_inc_switches"

void main()
{
	int nSpellID = GetSpellId();
	object oTarget = GetSpellTargetObject();
	location lTarget = GetSpellTargetLocation();
	float fRadius;
	int bDoor = FALSE, bRabbit = FALSE, bRock = FALSE;

	switch (nSpellID)
	{
		case SPELL_SOUND_BURST:
			fRadius = RADIUS_SIZE_MEDIUM;
			bDoor = TRUE;
			break;

		case SPELL_DISPEL_MAGIC:
			if (GetIsObjectValid(oTarget)) return; //not AOE
			fRadius = RADIUS_SIZE_LARGE;
			bDoor = TRUE;
			bRabbit = TRUE;
			break;

		case SPELL_TRUE_SEEING:
			fRadius = RADIUS_SIZE_LARGE;
			bRock = TRUE;
			break;

		default: return;
	}

	string sSpellName = GetStringByStrRef(StringToInt(Get2DAString("Spells", "Name", nSpellID)));
	oTarget = GetFirstObjectInShape(SHAPE_SPHERE, fRadius, lTarget, FALSE, OBJECT_TYPE_CREATURE | OBJECT_TYPE_DOOR | OBJECT_TYPE_PLACEABLE);
	while (GetIsObjectValid(oTarget))
	{
		if (bDoor == TRUE && GetObjectType(oTarget) == OBJECT_TYPE_DOOR && GetTag(oTarget) == "door_out")
		{
			FloatingTextStringOnCreature(sSpellName + " hits the door", OBJECT_SELF, FALSE);
			SetLocalInt(oTarget, IntToString(nSpellID) + "_triggered", TRUE);
			if (GetLocalInt(oTarget, IntToString(SPELL_SOUND_BURST) + "_triggered") &&
				GetLocalInt(oTarget, IntToString(SPELL_DISPEL_MAGIC) + "_triggered"))
			{
				DestroyObject(oTarget, 0.5f);
				bDoor = FALSE;
			}
		}

		if (bRock == TRUE && GetObjectType(oTarget) == OBJECT_TYPE_PLACEABLE && GetTag(oTarget) == "PLC_NL_ROCKFCE01")
		{
			FloatingTextStringOnCreature(sSpellName + " hits the rocks", OBJECT_SELF, FALSE);
			SetLocalInt(oTarget, IntToString(nSpellID) + "_triggered", TRUE);
			if (GetLocalInt(oTarget, IntToString(SPELL_TRUE_SEEING) + "_triggered"))
			{
				DestroyObject(oTarget, 0.5f);
				SetLocalInt(GetFirstPC(TRUE), "rocksdestroyed", TRUE);
				bRock = FALSE;
			}
		}

		if (bRabbit == TRUE && GetObjectType(oTarget) == OBJECT_TYPE_CREATURE && GetTag(oTarget) == "esaspia")
		{
			FloatingTextStringOnCreature(sSpellName + " hits the rabbit", OBJECT_SELF,FALSE);
			SetLocalInt(oTarget, IntToString(nSpellID) + "_triggered", TRUE);

			if (GetLocalInt(oTarget, IntToString(SPELL_DISPEL_MAGIC) + "_triggered") &&
				GetLocalInt(oTarget, "transmutate_triggered"))
			{
				DestroyObject(oTarget, 0.5f);
				bRabbit = FALSE;
			}
		}

		if (bDoor + bRock + bRabbit > 0)
			oTarget = GetNextObjectInShape(SHAPE_SPHERE, fRadius, lTarget, FALSE, OBJECT_TYPE_CREATURE | OBJECT_TYPE_DOOR | OBJECT_TYPE_PLACEABLE);
		else
			oTarget = OBJECT_INVALID;
	}
}

#37

Name this script i_ltransmutate_ac and compile. Use in conjunction with the script above.

//i_ltransmutate_ac

void main()
{
	object oPC = GetItemActivator();
	object oTarget  = GetItemActivatedTarget();
	effect eVFX = EffectNWN2SpecialEffectFile("sp_transmutation_conjure.sef");

	if (GetObjectType(oTarget) == OBJECT_TYPE_CREATURE && GetTag(oTarget) == "esaspia")
	{
		FloatingTextStringOnCreature("Transmutate hits the rabbit", oPC, FALSE);
		ApplyEffectToObject(DURATION_TYPE_INSTANT, eVFX, oTarget);
		SetLocalInt(oTarget, "transmutate_triggered", TRUE);

		if (GetLocalInt(oTarget, IntToString(SPELL_DISPEL_MAGIC) + "_triggered"))
		{
			DestroyObject(oTarget, 0.5f);
		}
	}
}

#38

Read this: https://nwnlexicon.com/index.php/FloatingTextStringOnCreature
Text targeted to NPCs with the FloatingTextStringOnCreature function will never be visible to PCs. Since oRabbit belongs to NPCs, it doesn’t work…

You can display the floating text above the head of a NPC with the SpeakString function:

AssignCommand(oTarget, SpeakString("Transmutate hits the rabbit", TALKVOLUME_TALK));

#39

Thanks, Aqvilinus! I’ll try your version of the script.


#40

I got an error compiling your script. It seems you used oTarget two times. I changed line 36 to this:

object oTarget2 = GetFirstObjectInShape(SHAPE_SPHERE, fRadius, lTarget, FALSE, OBJECT_TYPE_CREATURE | OBJECT_TYPE_DOOR | OBJECT_TYPE_PLACEABLE);

and then all the other oTarget following I changed to oTarget2, then it compiled. Hopefully this wont make things not working the way they should.

And looking more closely at your script I don’t want it to say that Dispel Magic hits the creature when it is supposed to be a custom spell in disguise, but I’ll try your AssignCommand variation and see if it works…hmm, seems I have to rework this thing…