Aller au contenu

Photo

Effects


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

#1
Shadooow

Shadooow
  • Members
  • 4 468 messages
I am a little confused with effects and their usage.

While lexicons says:

A common mistake with this function is to use the following approach to remove, say, a sleep effect:





effect eSleep=EffectSleep();


RemoveEffect(oPC, eSleep);

Some time ago, Whizard showed an example script that is removing the effect via this method and it works. However I was trying to use effect on PC as track for my new poison system I am working on and it didn't worked how I supposed it will.

When I passed the effect eTrack = EffectVisualEffect(666); into my delay function, the effect was never valid in the time of function executed (although the type/subtype was correct but even when the effect was removed from PC). Then I tried
to pass into the function last effect from GetFirst/Next, this time the effect was always valid even when the effect was removed from PC before function executed.

Why it doesn't work? I thought that the effect declared in spellscript is reference same as object. If this is not true why the Whizard's sample code works?

EDIT: finally seems I found out way how to use effect to track something, but that doesnt answer my questions

Modifié par ShaDoOoW, 31 janvier 2012 - 12:04 .


#2
wyldhunt1

wyldhunt1
  • Members
  • 246 messages
Without seeing exactly how you set up your code, it's hard to guess.
But, here is why that trick tends to fail:

object oPC = OBJECT_SELF;
//We are creating a NEW EffectSleep object
effect eSleep=EffectSleep();
//Applying the EffectSleep object
ApplyEffectToObject(DURATION_TYPE_PERMANENT, eSleep, oPC);

Then, later:

object oPC = OBJECT_SELF;
//Creating a NEW EffectSleep. This is not the same effect as above.
//Similar to spawning a new goblin and expecting it to be the old goblin.
effect eSleep=EffectSleep();
RemoveEffect(oPC, eSleep); //This effect was never applied to oPC



#3
Lightfoot8

Lightfoot8
  • Members
  • 2 535 messages

ShaDoOoW wrote...

I am a little confused with effects and their usage.

While lexicons says:

A common mistake with this function is to use the following approach to remove, say, a sleep effect:





effect eSleep=EffectSleep();


RemoveEffect(oPC, eSleep);

Some time ago, Whizard showed an example script that is removing the effect via this method and it works. However I was trying to use effect on PC as track for my new poison system I am working on and it didn't worked how I supposed it will.

When I passed the effect eTrack = EffectVisualEffect(666); into my delay function, the effect was never valid in the time of function executed (although the type/subtype was correct but even when the effect was removed from PC). Then I tried
to pass into the function last effect from GetFirst/Next, this time the effect was always valid even when the effect was removed from PC before function executed.

Why it doesn't work? I thought that the effect declared in spellscript is reference same as object. If this is not true why the Whizard's sample code works?

EDIT: finally seems I found out way how to use effect to track something, but that doesnt answer my questions


Yes, This confused me also at the time.  In fact the standard boiware scripts does it the same way.  You just got two thing wrong in your post.  First it was not Whizard that posted the example, though he did confirm the script that AD posted.   Second and more inportant it was not effects that where being dealt with, It was Item Props.

I do not think the method will ever work with effects.
I was suprised however that it worked with iProps.

Here is the thread for refreance.

Stuck on conversation conditional check - help!

#4
Shadooow

Shadooow
  • Members
  • 4 468 messages
what I did was this

effect eTrack = EffectVisualEffect(666);
eTrack = ExtraordinaryEffect(eTrack);
ApplyEffectToObject(PERMANENT,eTrack,oTarget);
DelayCommand(60.0,CheckEffect(oTarget,eTrack));


and

void CheckEffect(object oTarget, effect eTrack)
{
 if(!GetIsEffectValid(eTrack))
 {
 return;
}
//DO something
}

but effect wasn't valid in CheckEffect, if I pushed the last effect found by GetFirst/NextEffect then I get opposite results, effect was always valid

I just found out a way that works when I edited first post:

void CheckEffect(object oTarget, effect eTrack)
{
int bValid = FALSE;
 effect e = GetFirstEffect(oTarget);
  while(GetIsEffectValid(e))
  {
   if(e == eTrack)
   {
   bValid = TRUE;
   break;
   }
  e = GetNextEffect(oTarget);
  }
 if(!bValid) return;
//DO something
}

just doesn't undetstand why

Modifié par ShaDoOoW, 31 janvier 2012 - 12:27 .


#5
Shadooow

Shadooow
  • Members
  • 4 468 messages

Lightfoot8 wrote...

Yes, This confused me also at the time.  In fact the standard boiware scripts does it the same way.  You just got two thing wrong in your post.  First it was not Whizard that posted the example, though he did confirm the script that AD posted.   Second and more inportant it was not effects that where being dealt with, It was Item Props.

I do not think the method will ever work with effects.
I was suprised however that it worked with iProps.

Here is the thread for refreance.

Stuck on conversation conditional check - help!

It works. Try this function that I created to handle AB bonuses: And it was really Whizard fe months back who came with similar code sample.

//nDurationType - only permanent and temporary, its logical
//may not work properly with linked effect, proper testing is recommended
void ApplyEffectToPCAndHideIcon(int nDurationType, effect eEffect, object oPC, float fDuration=0.0);
void ApplyEffectToPCAndHideIcon(int nDurationType, effect eEffect, object oPC, float fDuration=0.0)
{
ApplyEffectToObject(nDurationType,eEffect,oPC,fDuration);
eEffect = EffectLinkEffects(eEffect,EffectTurnResistanceIncrease(1));
ApplyEffectToObject(nDurationType,eEffect,oPC,fDuration);
RemoveEffect(oPC,eEffect);
}


Modifié par ShaDoOoW, 31 janvier 2012 - 12:25 .


#6
Rolo Kipp

Rolo Kipp
  • Members
  • 2 791 messages
<painting...>

*Big* difference between effects and visual effects...
As I found out in My very surprised thread

Basically, you can *not* retrieve a visual effect with GetIsEffectValid
(See note in function GetEffectType RemoveEffect). You have to use the *effect creator* to retrieve the effect.

<...outside the lines>

Modifié par Rolo Kipp, 31 janvier 2012 - 12:41 .


#7
wyldhunt1

wyldhunt1
  • Members
  • 246 messages
My guess is that it has something to do with the
DelayCommand();
part.

I'd be curious to see if this would still work:

effect eTrack = EffectVisualEffect(666);
eTrack = ExtraordinaryEffect(eTrack);
ApplyEffectToObject(PERMANENT,eTrack,oTarget);
if(!GetIsEffectValid(eTrack))
{
return;
}
//DO something


My guess is that something concerning the effect changes after the script ends.

EDIT: Rolo seems to have figured it out while I was posting.

Modifié par wyldhunt1, 31 janvier 2012 - 12:41 .


#8
Rolo Kipp

Rolo Kipp
  • Members
  • 2 791 messages
<grinning...>

wyldhunt1 wrote...
...
EDIT: Rolo seems to have figured it out while I was posting.

*Maybe*...
Don't actually know if GetIsEffectValid has the same limitations as GetEffectType :-P

<...ruefully>

#9
Shadooow

Shadooow
  • Members
  • 4 468 messages

Rolo Kipp wrote...

<painting...>

*Big* difference between effects and visual effects...
As I found out in My very surprised thread

Basically, you can *not* retrieve a visual effect with GetIsEffectValid
(See note in function GetEffectType RemoveEffect). You have to use the *effect creator* to retrieve the effect.

<...outside the lines>

I don't think so. The first link shows that GetIsEffectValid normally returns TRUE for visual effects, GetEffectType also works correctly (even in my sample code unlike GetIsEffectValid).

Effect creator is when you want to know where is this visual effect from. I know that in my scenario as I used special effect creator.

Modifié par ShaDoOoW, 31 janvier 2012 - 12:48 .


#10
WhiZard

WhiZard
  • Members
  • 1 204 messages
I'm not sure on this one, but you might want to check which object was used in the last calling of GetFirstEffect() and GetNextEffect(), these functions may set an object to which GetIsEffectValid() refers.

#11
Rolo Kipp

Rolo Kipp
  • Members
  • 2 791 messages
<lighting a...>

Ahh, you are asking why the warning on RemoveEffect?

Your function CheckEffect works because you are passing in the original effect handle eTrack and then comparing it one by one to the list of all effects on the object.

The caution was aimed (if I understand it) at preventing people from creating *new* effect handles and expecting those to equate with a previously applied equivalent effect (i.e. creating a SleepEffect to check if SleepEffect is already on the object.
But each effect object is unique, so it doesn't work.

If that wasn't your question, could you clarify it for me?

And, yes. Visual effects do return as valid effects. That was a silly slip on my part. :-P

<...small taper in his mind>

Modifié par Rolo Kipp, 31 janvier 2012 - 01:10 .


#12
Shadooow

Shadooow
  • Members
  • 4 468 messages
Whizard: GetFirst/NextEffect doesnt ran on anyone else in my testing mod, so this won't be probably it.

Rolo Kipp: I think I know the answer. It seems that both itemproperties and effects are indeed "object constructors". But there is some bug in engine that makes them invalid when passed into delayed function. I just wasn't sure if they ARE constructors because of this bug, but since the workaround check against all effects on PC works, I guess they really ARE. Problem solved.

Modifié par ShaDoOoW, 31 janvier 2012 - 01:11 .


#13
WhiZard

WhiZard
  • Members
  • 1 204 messages
Try adding the bolded line into your previous attempt


void CheckEffect(object oTarget, effect eTrack)
{
effect eWhatever = GetFirstEffect(oTarget);
if(!GetIsEffectValid(eTrack))
 {
 return;
}
//DO something
}



#14
Rolo Kipp

Rolo Kipp
  • Members
  • 2 791 messages
<the taper glows...>

Odd.
Wonder what DelayCommand *does* pass and how it differs.
And what else is affected by this besides effects and itemprops.

Thanks for clarifying :-)

<...a little brighter>

#15
Lightfoot8

Lightfoot8
  • Members
  • 2 535 messages
Ok, Without tracing it out in the VM,  something I just do not have time to do right now. 

So here are My guess.  

First an effect is nothing more then a structure.  
The Lable for the Effect is nothing more then a pointer that holds the location in memory fo where the first data field is in the Effect Structure.   All other Field entrys will be found from an offset from the begining of the effect structure.
When the Effect is first created several of the Fields are blank.  And do not get filed in untill it is applyed.  i.e. Duration, ExpireDay, ExpireTime.

When you first create the Effect it is located on the stack.

When you Apply the Effect it gets added to the structure of the object you are applying it to. (most likely indirectly)

At this point the Effect is valid. It has not yet expired and is on an object.

Now the Compairison operator does not care where the effects are located and most likely only checks a sub set of the structures fields to see if they match. I dout for one that it checks the lists in the structure to see if the are the same.

Now the GetIsEffectValid would for sure check if the Effect has expired yet of not. I dout the compairson (==) would.

Also the newly created effect is on the stack where the applyed effect is on an object.

For you function passing the effect, well, NWScript only passes Argument by value. so even if you effect is on an object you have just pusjed it right back to the stack with the function call.


Now to you code snipit.

ApplyEffectToObject(nDurationType,eEffect,oPC,fDuration);
eEffect = EffectLinkEffects(eEffect,EffectTurnResistanceIncrease(1));
ApplyEffectToObject(nDurationType,eEffect,oPC,fDuration);
RemoveEffect(oPC,eEffect);


Not suprision that it works you are removing the same effect that you applyed.

Question is would

ApplyEffectToObject(nDurationType,eEffect,oPC,fDuration);
eEffect1 = EffectLinkEffects(eEffect,EffectTurnResistanceIncrease(1));
ApplyEffectToObject(nDurationType,eEffect1,oPC,fDuration);
eEffect2 = EffectLinkEffects(eEffect,EffectTurnResistanceIncrease(1));
RemoveEffect(oPC,eEffect2);

I dout it.
In effect (heh) what you are asking it to do is remove eEffect2 from the stack.

Modifié par Lightfoot8, 31 janvier 2012 - 01:27 .


#16
Shadooow

Shadooow
  • Members
  • 4 468 messages
Thanks for clarification LightFoot8, that makes sense.

WhiZard wrote...

Try adding the bolded line into your previous attempt


void CheckEffect(object oTarget, effect eTrack)
{
effect eWhatever = GetFirstEffect(oTarget);
if(!GetIsEffectValid(eTrack))
 {
 return;
}
//DO something
}


just tried, still invalid

Modifié par ShaDoOoW, 31 janvier 2012 - 01:29 .


#17
FunkySwerve

FunkySwerve
  • Members
  • 1 308 messages

ShaDoOoW wrote...

Whizard: GetFirst/NextEffect doesnt ran on anyone else in my testing mod, so this won't be probably it.

Rolo Kipp: I think I know the answer. It seems that both itemproperties and effects are indeed "object constructors". But there is some bug in engine that makes them invalid when passed into delayed function. I just wasn't sure if they ARE constructors because of this bug, but since the workaround check against all effects on PC works, I guess they really ARE. Problem solved.


They're structs. Take a look at nwnx_structs. DelayCommanding them, among other things, strips their spell ids.

Why are you trying to do what you're doing in the OP, anyway?

Funky

#18
Lightfoot8

Lightfoot8
  • Members
  • 2 535 messages
One clairification on my post above. I should have said that all custom functions pass arguments by value. The internal functions play by there own rules.

#19
Shadooow

Shadooow
  • Members
  • 4 468 messages

FunkySwerve wrote...

ShaDoOoW wrote...

Whizard: GetFirst/NextEffect doesnt ran on anyone else in my testing mod, so this won't be probably it.

Rolo Kipp: I think I know the answer. It seems that both itemproperties and effects are indeed "object constructors". But there is some bug in engine that makes them invalid when passed into delayed function. I just wasn't sure if they ARE constructors because of this bug, but since the workaround check against all effects on PC works, I guess they really ARE. Problem solved.


They're structs. Take a look at nwnx_structs. DelayCommanding them, among other things, strips their spell ids.

Why are you trying to do what you're doing in the OP, anyway?

Funky

This is part of my new poison system to be included with next Patch beta version. This system allows to stack poisons as by default when there is poison effect no other poisons can be applied anymore. I don't think its possible to do without passing the poison effect applied to PC as its possible to heal poison effects.

void SecondaryDamage(object oTarget, int nPoisonID, effect eTrack)
{
 if(GetIsObjectValid(oTarget))
 {
 int bCured = TRUE;
 effect e = GetFirstEffect(oTarget);
  while(GetIsEffectValid(e))
  {
   if(e == eTrack)
   {
   bCured = FALSE;
   break;
   }
  e = GetNextEffect(oTarget);
  }
  if(bCured)
  {
  return;
  }
 int nDC = StringToInt(Get2DAString("poison","Save_DC",nPoisonID));
  if(!FortitudeSave(oTarget,nDC,SAVING_THROW_TYPE_POISON,OBJECT_INVALID))
  {
  SendMessageToPCByStrRef(oTarget,66947);
  int nVFX = VFX_IMP_POISON_S;
  if(Get2DAString("poison","VFX_Impact",nPoisonID) == "VFX_IMP_POISON_L")
   {
   nVFX = VFX_IMP_POISON_L;
   }
  ApplyEffectToObject(DURATION_TYPE_INSTANT,EffectVisualEffect(nVFX),oTarget);
  string s2DA = Get2DAString("poison","Default2",nPoisonID);
   if(s2DA == "" || s2DA == "****")
   {
   s2DA = Get2DAString("poison","Script_2",nPoisonID);
   ExecuteScript(s2DA,oTarget);
   return;
   }
  int nAbility = ABILITY_CONSTITUTION;
   if(s2DA == "DEX") nAbility = ABILITY_DEXTERITY;
   else if(s2DA == "STR") nAbility = ABILITY_STRENGTH;
   else if(s2DA == "WIS") nAbility = ABILITY_WISDOM;
   else if(s2DA == "INT") nAbility = ABILITY_INTELLIGENCE;
   else if(s2DA == "CHA") nAbility = ABILITY_CHARISMA;
  int nDice = StringToInt(Get2DAString("poison","Dice2",nPoisonID));
  int nDamage, nDam = StringToInt(Get2DAString("poison","Dam2",nPoisonID));
   do
   {
   nDamage+= Random(nDice)+1;
   }while(--nDam > 0);
   if(nDamage < 1) nDamage = 0;//sanity check
  ApplyEffectToObject(DURATION_TYPE_PERMANENT,ExtraordinaryEffect(EffectAbilityDecrease(nAbility,nDamage)),oTarget);
  }
 }
 else
 {
 DelayCommand(60.0,SecondaryDamage(oTarget,nPoisonID,eTrack));
 }
}

void Apply1stPoison(object oTarget, int nPoisonID)
{
effect e = GetFirstEffect(oTarget);
 while(GetIsEffectValid(e))
 {
  if(GetEffectType(e) == EFFECT_TYPE_POISON)
  {
  effect ePoison = EffectVisualEffect(VFX_DUR_CESSATE_NEUTRAL);
//  eTrack = ExtraordinaryEffect(eTrack);
//  ApplyEffectToObject(DURATION_TYPE_PERMANENT,eTrack,oTarget);
  string s2DA = Get2DAString("poison","Default1",nPoisonID);
   if(s2DA != "" && s2DA != "****")
   {
   int nAbility = ABILITY_CONSTITUTION;
    if(s2DA == "DEX") nAbility = ABILITY_DEXTERITY;
    else if(s2DA == "STR") nAbility = ABILITY_STRENGTH;
    else if(s2DA == "WIS") nAbility = ABILITY_WISDOM;
    else if(s2DA == "INT") nAbility = ABILITY_INTELLIGENCE;
    else if(s2DA == "CHA") nAbility = ABILITY_CHARISMA;
   int nDice = StringToInt(Get2DAString("poison","Dice1",nPoisonID));
   int nDamage, nDam = StringToInt(Get2DAString("poison","Dam1",nPoisonID));
    do
    {
    nDamage+= Random(nDice)+1;
    }while(--nDam > 0);
    if(nDamage < 1) nDamage = 0;//sanity check
   ePoison = EffectLinkEffects(ePoison,EffectAbilityDecrease(nAbility,nDamage));
   ePoison = ExtraordinaryEffect(ePoison);
   }
  ApplyEffectToObject(DURATION_TYPE_PERMANENT,ePoison,oTarget);
   if(GetLocalInt(GetModule(),"71_ALLOW_POISON_STACKING") == TRUE || GetGameDifficulty() == GAME_DIFFICULTY_DIFFICULT)
   {
   RemoveEffect(oTarget,e);
   DelayCommand(60.0,SecondaryDamage(oTarget,nPoisonID,ePoison));
   }
   else if(GetEffectSubType(e) == SUBTYPE_MAGICAL)
   {
   effect eCopy = ExtraordinaryEffect(e);
   RemoveEffect(oTarget,e);
   AssignCommand(OBJECT_SELF,ApplyEffectToObject(DURATION_TYPE_PERMANENT,eCopy,oTarget));
   }
  return;
  }
 e = GetNextEffect(oTarget);
 }
}


Modifié par ShaDoOoW, 31 janvier 2012 - 01:46 .


#20
WhiZard

WhiZard
  • Members
  • 1 204 messages

Lightfoot8 wrote...
Question is would

ApplyEffectToObject(nDurationType,eEffect,oPC,fDuration);
eEffect1 = EffectLinkEffects(eEffect,EffectTurnResistanceIncrease(1));
ApplyEffectToObject(nDurationType,eEffect1,oPC,fDuration);
eEffect2 = EffectLinkEffects(eEffect,EffectTurnResistanceIncrease(1));
RemoveEffect(oPC,eEffect2);

I dout it.
In effect (heh) what you are asking it to do is remove eEffect2 from the stack.


I tried a stacking effect as shown below

void main()
{
object oPC = OBJECT_SELF;
effect eEffect = EffectRegenerate(5, 1.0);
eEffect = EffectLinkEffects(eEffect,EffectRegenerate(1, 1.0));
ApplyEffectToObject(DURATION_TYPE_PERMANENT,eEffect,OBJECT_SELF);
//RemoveEffect(oPC,eEffect);
effect eEffect1 = EffectLinkEffects(eEffect,EffectRegenerate(2, 1.0));
ApplyEffectToObject(DURATION_TYPE_PERMANENT,eEffect1,OBJECT_SELF);
effect eEffect2 = EffectLinkEffects(eEffect1,EffectRegenerate(3, 1.0));
//RemoveEffect(oPC,eEffect2);
ApplyEffectToObject(DURATION_TYPE_PERMANENT,eEffect2,OBJECT_SELF);
}


This passes three regenerations
1: 5, 1
2: 5, 1, 2
3: 5, 1, 2, 3

When the first remove effect is uncommented the first regeneration only  is stopped.
When the last remove effect is uncommented only the last regeneration is stopped.


EDIT: Last line of code didn't copy
DOUBLE EDIT: The regen icon got lost on the first one, though the regen of 2 and 3 were still in place.

Modifié par WhiZard, 31 janvier 2012 - 02:28 .


#21
Lightfoot8

Lightfoot8
  • Members
  • 2 535 messages
Interesting, Not sure I can explain that one at the moment.

#22
WhiZard

WhiZard
  • Members
  • 1 204 messages
Here is actually a good script that demonstrates that RemoveEffect() actually performs a loop removing all effects that are from the same calling.

void main()
{
object oPC = OBJECT_SELF;
effect eEffect = EffectRegenerate(5, 1.0);
ApplyEffectToObject(DURATION_TYPE_PERMANENT,eEffect,OBJECT_SELF);
ApplyEffectToObject(DURATION_TYPE_PERMANENT,eEffect,OBJECT_SELF);
ApplyEffectToObject(DURATION_TYPE_PERMANENT,eEffect,OBJECT_SELF);
DelayCommand(3.0, RemoveEffect(oPC,eEffect));
}

#23
henesua

henesua
  • Members
  • 3 863 messages
Does it actually apply the effect three times in that case?

[Edit]
The reason I ask is that there is an item property function that will not add similar properties to an item unless you tell it to do so. So I wonder if Apply EffectToObject is similar in that it opts not to add the same effect with same subproperties more than once.

Modifié par henesua, 31 janvier 2012 - 02:40 .


#24
Lightfoot8

Lightfoot8
  • Members
  • 2 535 messages
I have no problem with that one.

#25
WhiZard

WhiZard
  • Members
  • 1 204 messages

henesua wrote...

Does it actually apply the effect three times in that case?

[Edit]
The reason I ask is that there is an item property function that will not add similar properties to an item unless you tell it to do so. So I wonder if Apply EffectToObject is similar in that it opts not to add the same effect with same subproperties more than once.


Regeneration is nice in that it stack in all sorts of ways.  Regeneration is applied multiple times whether effect or item property.  The IPSafe...() commands are BioWare's way of self cleaning which involve first checking whether there is an item property there that shares certain traits.