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.
Dispel Non-hostile Effects on Self
#1
Posté 04 août 2015 - 08:41
#2
Posté 05 août 2015 - 06:45
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
Posté 06 août 2015 - 12:02
This has worked like a charm. Thank you very much.
#5
Posté 06 août 2015 - 12:38
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
Posté 06 août 2015 - 01:55
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
Posté 06 août 2015 - 02:16
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
Posté 06 août 2015 - 04:26
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
Posté 06 août 2015 - 05:32
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
Posté 06 août 2015 - 05:45
I'm not terribly miffed about it, no. Casters are rare on my server anyway.
#11
Posté 06 août 2015 - 05:48
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
Posté 06 août 2015 - 06:37
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
Posté 06 août 2015 - 07:11
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
Posté 06 août 2015 - 08:02
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
Posté 06 août 2015 - 11:07
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
- Zwerkules, Thayan, henesua et 2 autres aiment ceci
#16
Posté 07 août 2015 - 12:09
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
Posté 07 août 2015 - 12:41
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
Posté 07 août 2015 - 01:11
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
Posté 07 août 2015 - 01:54
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
Posté 07 août 2015 - 02:10
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
Posté 07 août 2015 - 02:18
True. I'll update the language for those pages and see about adding a caveat somewhere about using instant duration.
- meaglyn aime ceci
#22
Posté 07 août 2015 - 08:14
Sweet, mystery solved and I learned a bunch along the way. Thanks guys ![]()
- Squatting Monk et meaglyn aiment ceci
#23
Posté 09 août 2015 - 05:27
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
Posté 09 août 2015 - 07:07
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





Retour en haut







