Author Topic: Dispel Non-hostile Effects on Self  (Read 612 times)

Legacy_The Mad Poet

  • Hero Member
  • *****
  • Posts: 715
  • Karma: +0/-0
Dispel Non-hostile Effects on Self
« on: August 04, 2015, 09:41:39 pm »


               

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.



               
               

               
            

Legacy_JediMindTrix

  • Sr. Member
  • ****
  • Posts: 383
  • Karma: +0/-0
Dispel Non-hostile Effects on Self
« Reply #1 on: August 05, 2015, 07:45:05 am »


               

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);
   }
}


               
               

               
            

Legacy_The Mad Poet

  • Hero Member
  • *****
  • Posts: 715
  • Karma: +0/-0
Dispel Non-hostile Effects on Self
« Reply #2 on: August 06, 2015, 01:02:03 pm »


               

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



               
               

               
            

Legacy_JediMindTrix

  • Sr. Member
  • ****
  • Posts: 383
  • Karma: +0/-0
Dispel Non-hostile Effects on Self
« Reply #3 on: August 06, 2015, 01:35:09 pm »


               

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.



               
               

               
            

Legacy_meaglyn

  • Hero Member
  • *****
  • Posts: 1451
  • Karma: +0/-0
Dispel Non-hostile Effects on Self
« Reply #4 on: August 06, 2015, 01:38:55 pm »


               

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.



               
               

               
            

Legacy_JediMindTrix

  • Sr. Member
  • ****
  • Posts: 383
  • Karma: +0/-0
Dispel Non-hostile Effects on Self
« Reply #5 on: August 06, 2015, 02:55:23 pm »


               

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."



               
               

               
            

Legacy_meaglyn

  • Hero Member
  • *****
  • Posts: 1451
  • Karma: +0/-0
Dispel Non-hostile Effects on Self
« Reply #6 on: August 06, 2015, 03:16:54 pm »


               

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.



               
               

               
            

Legacy_The Mad Poet

  • Hero Member
  • *****
  • Posts: 715
  • Karma: +0/-0
Dispel Non-hostile Effects on Self
« Reply #7 on: August 06, 2015, 05:26:01 pm »


               

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);
    }
}

               
               

               
            

Legacy_meaglyn

  • Hero Member
  • *****
  • Posts: 1451
  • Karma: +0/-0
Dispel Non-hostile Effects on Self
« Reply #8 on: August 06, 2015, 06:32:36 pm »


               

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. 



               
               

               
            

Legacy_The Mad Poet

  • Hero Member
  • *****
  • Posts: 715
  • Karma: +0/-0
Dispel Non-hostile Effects on Self
« Reply #9 on: August 06, 2015, 06:45:49 pm »


               

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



               
               

               
            

Legacy_JediMindTrix

  • Sr. Member
  • ****
  • Posts: 383
  • Karma: +0/-0
Dispel Non-hostile Effects on Self
« Reply #10 on: August 06, 2015, 06:48:07 pm »


               

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.



               
               

               
            

Legacy_meaglyn

  • Hero Member
  • *****
  • Posts: 1451
  • Karma: +0/-0
Dispel Non-hostile Effects on Self
« Reply #11 on: August 06, 2015, 07:37:58 pm »


               

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.



               
               

               
            

Legacy_JediMindTrix

  • Sr. Member
  • ****
  • Posts: 383
  • Karma: +0/-0
Dispel Non-hostile Effects on Self
« Reply #12 on: August 06, 2015, 08:11:40 pm »


               

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!



               
               

               
            

Legacy_meaglyn

  • Hero Member
  • *****
  • Posts: 1451
  • Karma: +0/-0
Dispel Non-hostile Effects on Self
« Reply #13 on: August 06, 2015, 09:02:37 pm »


               

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.



               
               

               
            

Legacy_Squatting Monk

  • Hero Member
  • *****
  • Posts: 776
  • Karma: +0/-0
Dispel Non-hostile Effects on Self
« Reply #14 on: August 07, 2015, 12:07:46 am »


               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.