Aller au contenu

Photo

Dispel Non-hostile Effects on Self


  • Veuillez vous connecter pour répondre
23 réponses à ce sujet

#1
The Mad Poet

The Mad Poet
  • Members
  • 425 messages

After a pair of failed attempts I figure I'll ask. Does anyone have a script that would dispel non-hostile spell effects on self? I plan to add it to a conversation to let players remove lingering spells they or their party have cast on them so they don't walk around being forced to look like sparkly rocks.



#2
JediMindTrix

JediMindTrix
  • Members
  • 283 messages

Try this:

 

//Adapted from Lexicon example
void main()
{
object oPC = GetPCSpeaker();
effect eLoop=GetFirstEffect(oPC);
while (GetIsEffectValid(eLoop))
   {
   if (GetEffectType(eLoop)!=EFFECT_TYPE_BLINDNESS| EFFECT_TYPE_ABILITY_DECREASE | EFFECT_TYPE_AC_DECREASE | EFFECT_TYPE_ARCANE_SPELL_FAILURE
   | EFFECT_TYPE_ATTACK_DECREASE | EFFECT_TYPE_CHARMED | EFFECT_TYPE_CONFUSED | EFFECT_TYPE_CURSE | EFFECT_TYPE_DAMAGE_DECREASE | EFFECT_TYPE_DAMAGE_IMMUNITY_DECREASE
   | EFFECT_TYPE_DAZED | EFFECT_TYPE_DEAF | EFFECT_TYPE_DISEASE | EFFECT_TYPE_DOMINATED | EFFECT_TYPE_ENTANGLE | EFFECT_TYPE_FRIGHTENED | EFFECT_TYPE_MISS_CHANCE |
   EFFECT_TYPE_MOVEMENT_SPEED_DECREASE | EFFECT_TYPE_NEGATIVELEVEL | EFFECT_TYPE_PARALYZE | EFFECT_TYPE_PETRIFY | EFFECT_TYPE_POISON | EFFECT_TYPE_SAVING_THROW_DECREASE |
   EFFECT_TYPE_SILENCE | EFFECT_TYPE_SKILL_DECREASE | EFFECT_TYPE_SLOW | EFFECT_TYPE_SPELL_FAILURE | EFFECT_TYPE_SPELL_RESISTANCE_DECREASE | EFFECT_TYPE_STUNNED | EFFECT_TYPE_TURN_RESISTANCE_DECREASE
   | EFFECT_TYPE_TURNED)
   RemoveEffect(oPC, eLoop);
   eLoop=GetNextEffect(oPC);
   }
}

  • Squatting Monk et The Mad Poet aiment ceci

#3
The Mad Poet

The Mad Poet
  • Members
  • 425 messages

This has worked like a charm. Thank you very much.



#4
JediMindTrix

JediMindTrix
  • Members
  • 283 messages

You're welcome! If you ever need to change or add effects, you can find their constants here. That's what I used to build that current posted list.



#5
meaglyn

meaglyn
  • Members
  • 808 messages

You might look at that code more closely. I don't think it is doing what you think it is.  It's made with bitwise or. So you are removing the effect if the effect type is not equal to a bitwise or of all those listed effect values. That's pretty much certain to be the case so it will very likely remove any and all effects.


  • Zwerkules aime ceci

#6
JediMindTrix

JediMindTrix
  • Members
  • 283 messages

Because I wasn't 100% sure, I tested this, and it does work as intended.

 

Basically, the script is saying: "Get the first effect, and if it is not equal to one of these (!=) negative effects, then I will strip it. Then, go to the next effect and repeat."



#7
meaglyn

meaglyn
  • Members
  • 808 messages

No, that's not what it's doing.

 

The code

if ( type != 1 | 2 | 3) 

Is not the same as

 if (type != 1 && type != 2 && type != 3) 

The first one, because it is using a bitwise or operation (|) , is actually saying

if (type != 3) 

because   1 (binary 1)  | 2 (binary 10) | 3 (binary 11)  = 3 (binary 11).

 

If you take all the values of all those bad effect constants and or them together you will end up with a value of 127. So your code is  saying :

if (type != 127)   RemoveEffect();

which is why I said it will be removing all effects. I'm guessing you did not test it with a negative effect applied.


  • Squatting Monk aime ceci

#8
The Mad Poet

The Mad Poet
  • Members
  • 425 messages

Alright, so after thoroughly testing instead of just throwing some spells on the character and winging it I decided to go back and revisit my script. Ended up working out for the best. Thanks for pointing out the error meaglyn, and thanks there Jedi for stepping up!

/////////////////////////////////////////////////
//TMP - Remove Effects                         //
//      For Avernostra                         //
/////////////////////////////////////////////////
void RemoveMyEffects(object oTarget, object oPC);

void main()
{
    object oPC = GetPCSpeaker();
    location lPC = GetLocation(oPC);
    RemoveMyEffects(oPC, oPC);

    //Best to do a shape. Maybe get rid of wall spells too? (hopefully... maybe... HA doubtful!)
    object oTarget = GetFirstObjectInShape(SHAPE_SPHERE, RADIUS_SIZE_COLOSSAL, lPC, TRUE, OBJECT_TYPE_ALL);
    
    //Don't screw up the loop there Poet, you know you do that all the time.
    while (GetIsObjectValid(oTarget))
    {
        RemoveMyEffects(oTarget, oPC);
        oTarget = GetNextObjectInShape(SHAPE_SPHERE, RADIUS_SIZE_COLOSSAL, lPC, TRUE, OBJECT_TYPE_ALL);
    }
}

//Get rid of effects made by the pc, on the pc. I know, novel idea, right! I don't think you can
//even cast spells on yourself that are negative. Should though... Masochism FTW!
//P.S. Don't screw up this loop either!
void RemoveMyEffects(object oTarget, object oPC)
{
    effect eEff = GetFirstEffect(oTarget);
    while (GetIsEffectValid(eEff))
    {
        if (GetEffectCreator(eEff) == oPC)
            DelayCommand(0.1, RemoveEffect(oTarget, eEff));
        eEff = GetNextEffect(oTarget);
    }
}

  • Squatting Monk et meaglyn aiment ceci

#9
meaglyn

meaglyn
  • Members
  • 808 messages

One thing about using the PC is that it won't remove beneficial effects cast by others. Buffs from a party member or henchperson for example.  Explicitly listing the effects to remove or not remove can handle that (the direction jedi's code was taking). If you are not concerned about effects from others then this should work nicely. 


  • The Mad Poet aime ceci

#10
The Mad Poet

The Mad Poet
  • Members
  • 425 messages

I'm not terribly miffed about it, no. Casters are rare on my server anyway.



#11
JediMindTrix

JediMindTrix
  • Members
  • 283 messages

I tested it with a daze effect and fireshield applied to the character. The Fireshield was dispelled, while the Daze effect remained. The code works as intended.

 

I used this:

void main()
{
object oPC = GetPCSpeaker();
effect eEffect = EffectDazed();
ApplyEffectToObject(DURATION_TYPE_INSTANT, eEffect, oPC, 0.0);
}

On a conversation node to apply the daze effect after having cast a fireshield with a wizard. The following conversation option then dispelled the fireshield while leaving the daze effect untouched.

 

EDIT: I just tested it with a ton of spells and the daze effect on. Still works as intended. My interpretation of why the code worked might be wrong, but I am inclined to believe that meaglyn's interpretation of why it wouldn't is as well.



#12
meaglyn

meaglyn
  • Members
  • 808 messages

Looking at the disassembled dump of that function using the nwnnsscomp compiler (I don't have access to the toolset compiler right now), it shows a couple of things. First, the precedence of the "|" operation versus the "!=" is not what I expected so the details of my explanation are not correct (my bad), but the result is the same. 

 

What it is actually doing is the != first which leaves a value of 0 or 1 on the stack depending on whether the effect type is or is not EFFECT_TYPE_BLINDNESS. It then does the bitwise or (INCORII) with each of the following constants, rather than what I said which was doing all the bitwise ors first and then the inequality.

 

After all the ors it then skips the removeeffect if the top of the stack value is zero (JZ). There is no way I can see for that value to ever be zero so I stand by what I said, the code as written should not work. 

 

It will be interesting to see what the toolset compiler produces for this script.

Here is what my compiler produces:

00000008 42 000001A9              T 000001A9
0000000D 1E 00 00000008           JSR fn_00000015
00000013 20 00                    RETN
00000015 02 06                    RSADDO
00000017 05 00 00EE 00            ACTION GetPCSpeaker(00EE), 00
0000001C 01 01 FFFFFFF8 0004      CPDOWNSP FFFFFFF8, 0004
00000024 1B 00 FFFFFFFC           MOVSP FFFFFFFC
0000002A 02 10                    RSADDEFF
0000002C 03 01 FFFFFFF8 0004      CPTOPSP FFFFFFF8, 0004
00000034 05 00 0055 01            ACTION GetFirstEffect(0055), 01
00000039 01 01 FFFFFFF8 0004      CPDOWNSP FFFFFFF8, 0004
00000041 1B 00 FFFFFFFC           MOVSP FFFFFFFC
00000047 03 01 FFFFFFFC 0004      CPTOPSP FFFFFFFC, 0004
0000004F 05 00 0058 01            ACTION GetIsEffectValid(0058), 01
00000054 1F 00 0000014D           JZ off_000001A1
0000005A 03 01 FFFFFFFC 0004      CPTOPSP FFFFFFFC, 0004
00000062 05 00 00AA 01            ACTION GetEffectType(00AA), 01
00000067 04 03 00000043           CONSTI 00000043
0000006D 0C 20                    NEQUALII
0000006F 04 03 00000027           CONSTI 00000027
00000075 08 20                    INCORII
00000077 04 03 0000002F           CONSTI 0000002F
0000007D 08 20                    INCORII
0000007F 04 03 00000012           CONSTI 00000012
00000085 08 20                    INCORII
00000087 04 03 00000029           CONSTI 00000029
0000008D 08 20                    INCORII
0000008F 04 03 00000017           CONSTI 00000017
00000095 08 20                    INCORII
00000097 04 03 00000018           CONSTI 00000018
0000009D 08 20                    INCORII
0000009F 04 03 00000021           CONSTI 00000021
000000A5 08 20                    INCORII
000000A7 04 03 0000002B           CONSTI 0000002B
000000AD 08 20                    INCORII
000000AF 04 03 0000002D           CONSTI 0000002D
000000B5 08 20                    INCORII
000000B7 04 03 0000001C           CONSTI 0000001C
000000BD 08 20                    INCORII
000000BF 04 03 0000000D           CONSTI 0000000D
000000C5 08 20                    INCORII
000000C7 04 03 00000020           CONSTI 00000020
000000CD 08 20                    INCORII
000000CF 04 03 0000001A           CONSTI 0000001A
000000D5 08 20                    INCORII
000000D7 04 03 0000000B           CONSTI 0000000B
000000DD 08 20                    INCORII
000000DF 04 03 00000019           CONSTI 00000019
000000E5 08 20                    INCORII
000000E7 04 03 00000047           CONSTI 00000047
000000ED 08 20                    INCORII
000000EF 04 03 00000031           CONSTI 00000031
000000F5 08 20                    INCORII
000000F7 04 03 0000003D           CONSTI 0000003D
000000FD 08 20                    INCORII
000000FF 04 03 0000001B           CONSTI 0000001B
00000105 08 20                    INCORII
00000107 04 03 0000004F           CONSTI 0000004F
0000010D 08 20                    INCORII
0000010F 04 03 0000001F           CONSTI 0000001F
00000115 08 20                    INCORII
00000117 04 03 00000033           CONSTI 00000033
0000011D 08 20                    INCORII
0000011F 04 03 00000022           CONSTI 00000022
00000125 08 20                    INCORII
00000127 04 03 00000037           CONSTI 00000037
0000012D 08 20                    INCORII
0000012F 04 03 00000025           CONSTI 00000025
00000135 08 20                    INCORII
00000137 04 03 00000052           CONSTI 00000052
0000013D 08 20                    INCORII
0000013F 04 03 00000035           CONSTI 00000035
00000145 08 20                    INCORII
00000147 04 03 0000001D           CONSTI 0000001D
0000014D 08 20                    INCORII
0000014F 04 03 0000004D           CONSTI 0000004D
00000155 08 20                    INCORII
00000157 04 03 00000023           CONSTI 00000023
0000015D 08 20                    INCORII
0000015F 1F 00 00000021           JZ off_00000180
00000165 03 01 FFFFFFFC 0004      CPTOPSP FFFFFFFC, 0004
0000016D 03 01 FFFFFFF4 0004      CPTOPSP FFFFFFF4, 0004
00000175 05 00 0057 02            ACTION RemoveEffect(0057), 02
0000017A 1D 00 00000006           JMP off_00000180
00000180 03 01 FFFFFFF8 0004      CPTOPSP FFFFFFF8, 0004
00000188 05 00 0056 01            ACTION GetNextEffect(0056), 01
0000018D 01 01 FFFFFFF8 0004      CPDOWNSP FFFFFFF8, 0004
00000195 1B 00 FFFFFFFC           MOVSP FFFFFFFC
0000019B 1D 00 FFFFFEAC           JMP off_00000047
000001A1 1B 00 FFFFFFF8           MOVSP FFFFFFF8
000001A7 20 00                    RETN

Edit: The code produced by the toolset compiler is effectively the same as the above.


  • MrZork et Squatting Monk aiment ceci

#13
JediMindTrix

JediMindTrix
  • Members
  • 283 messages

I definitely don't understand any of that. The code works, but I'm no longer convinced that I know why. I thought it would remove every effect on the user, excluding the negative effects listed, but now I'm not so sure. More input from people who know more than I would be helpful to the learning process!


  • Squatting Monk aime ceci

#14
meaglyn

meaglyn
  • Members
  • 808 messages

I'll do it with the toolset when I can and see what it looks like. 

 

What you have is a good start and the concept is spot on. My point was that it really should be written like

int nType;
while (GetIsEffectValid(eLoop))
   {
   nType = GetEffectType(eLoop);
   if (nType != EFFECT_TYPE_BLINDNESS 
        && nType != EFFECT_TYPE_ABILITY_DECREASE 
        && nType != EFFECT_TYPE_AC_DECREASE 
           < etc > 
   )
   RemoveEffect(oPC, eLoop);
   eLoop=GetNextEffect(oPC);
}

because it really should not work right with those "|"s in there.


  • Squatting Monk aime ceci

#15
Squatting Monk

Squatting Monk
  • Members
  • 445 messages
Here's an alternate way of doing this:
void RemoveNonHostileSpellEffects(object oTarget)
{
    int nSpellID;
    effect eEff = GetFirstEffect(oTarget);
    while (GetIsEffectValid(eEff))
    {
        nSpellID = GetEffectSpellId(eEff);
        if (!StringToInt(Get2DAString("spells", "HostileSetting", nSpellID)))
            RemoveEffect(oTarget, eEff);
        
        eEff = GetNextEffect(oTarget);
    }
}
Differences from the other ways in this thread:
  • will remove effects from PC and NPC casters
  • will not remove VFX applied by hostile spells
  • will remove negative effects associated with non-hostile spells
  • will not remove positive effects associated with hostile spells
  • will not remove effects not applied by spell
Whether these points are desirable or not depends on your use case.
  • Zwerkules, Thayan, henesua et 2 autres aiment ceci

#16
meaglyn

meaglyn
  • Members
  • 808 messages

Fwiw, I setup a quick test with the original script and it does as expected remove all the effects when run.


  • Squatting Monk aime ceci

#17
JediMindTrix

JediMindTrix
  • Members
  • 283 messages

Fwiw, I setup a quick test with the original script and it does as expected remove all the effects when run.

 

An ingame test or a test similar to the long transcript you posted? I swear up and down that the code I wrote functions as intended for me and that I have not altered it since posting the original. Also, what does fwiw mean?

 

Squatting Monk's is probably the best to use.

 

EDIT: Here's the module I tested this in if anyone wants to take a peak and see if I'm missing something: https://www.dropbox....relith.mod?dl=0



#18
meaglyn

meaglyn
  • Members
  • 808 messages

I was not doubting that you were seeing what you were seeing, just that the script was not doing that so something else must be happening.

 

I see what's going on. You are applying the EffectDazed with DURATION_TYPE_INSTANT. There seems to be an engine bug when you do that.  The effect it not removable at all.  Resting does not clear it either.

 

You are not supposed to use INSTANT for this type of effect only TEMPORARY or PERMANENT.

 

Others may be able to comment on whether that bug is known or not.  The Lexicon says " This effect cannot be applied instantly, only temporarily or permanently." But that does not seem to be accurate since the effect is clearly applied. Maybe we need different wording there. 

 

Edit : That listing was the actual code the script compiles to... the byte code read by the machine that executes scripts in the engine, not a log or transcipt of a test execution, but it shows the exact steps the execution of the script would entail.

 

fwiw means "for what it's worth" :)


  • Squatting Monk et henesua aiment ceci

#19
Squatting Monk

Squatting Monk
  • Members
  • 445 messages

Ah, this makes more sense now. That same wording is present in the Lexicon pages of most of the other effect constructor functions (all the ones that would be expected to have a duration, however short). I wonder if these other effects show this same behavior when applied with DURATION_TYPE_INSTANT. If so, then it's not a bug, per se, but just unintended results.

 

Edit: looking through the Omnibus, it looks like this was a known bug. Before SupernaturalEffect() was added, people were using it to force effects to stay present through rests.


  • henesua et meaglyn aiment ceci

#20
meaglyn

meaglyn
  • Members
  • 808 messages

Thanks Monk.  I had not gone digging in there yet.  One person's "unintended result" is another person's bug :)


  • Squatting Monk aime ceci

#21
Squatting Monk

Squatting Monk
  • Members
  • 445 messages

True. I'll update the language for those pages and see about adding a caveat somewhere about using instant duration.


  • meaglyn aime ceci

#22
JediMindTrix

JediMindTrix
  • Members
  • 283 messages

Sweet, mystery solved and I learned a bunch along the way. Thanks guys :)


  • Squatting Monk et meaglyn aiment ceci

#23
WhiZard

WhiZard
  • Members
  • 1 204 messages

Here's an alternate way of doing this:

void RemoveNonHostileSpellEffects(object oTarget)
{
    int nSpellID;
    effect eEff = GetFirstEffect(oTarget);
    while (GetIsEffectValid(eEff))
    {
        nSpellID = GetEffectSpellId(eEff);
        if (!StringToInt(Get2DAString("spells", "HostileSetting", nSpellID)))
            RemoveEffect(oTarget, eEff);
        
        eEff = GetNextEffect(oTarget);
    }
}
  • will not remove effects not applied by spell

 

 

Not sure on that point.  Non-spells would not have an ID, and thus their strings from indexing would likely be null and thus be treated the same as a 0 in "HostileSetting"


  • Squatting Monk aime ceci

#24
Squatting Monk

Squatting Monk
  • Members
  • 445 messages

Good catch! I'd originally written this to remove hostile spell effects and just added the ! thinking that would do it. Since Get2daString() returns "" if the lookup fails, we can just check if the string matches "0".

void RemoveNonHostileSpellEffects(object oTarget)
{
    effect eEff = GetFirstEffect(oTarget);
    while (GetIsEffectValid(eEff))
    {
        if (Get2DAString("spells", "HostileSetting", GetEffectSpellId(eEff)) == "0")
            RemoveEffect(oTarget, eEff);
        
        eEff = GetNextEffect(oTarget);
    }
}

  • The Mad Poet aime ceci