Aller au contenu

Photo

Contents of the effect struct?


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

#1
ColorsFade

ColorsFade
  • Members
  • 1 267 messages
Does anyone know where the effect struct is defined in the script code? Is it defined in an accessible script or is it part of the compiled program and therefore inaccessible? 

Is there any way to figure out what properties it contains?

#2
kevL

kevL
  • Members
  • 4 056 messages
i'm sure its hardcoded. But when needed i use this to investigate:

void main()
{
  object oPC = OBJECT_SELF;

  effect eEffect = GetFirstEffect(oPC);
  while (GetIsEffectValid(eEffect))
  {
    if (GetEffectType(eEffect) == EFFECT_TYPE_DAMAGE_RESISTANCE)
    {
      SendMessageToPC(oPC, "Found Damage Resistance Effect Type : "
          + IntToString(GetEffectType(eEffect)));
      SendMessageToPC(oPC, "Found Damage Resistance Effect Sub Type : "
          + IntToString(GetEffectSubType(eEffect)));
      SendMessageToPC(oPC, "Found Damage Resistance Effect SpellID : "
          + IntToString(GetEffectSpellId(eEffect)));
      SendMessageToPC(oPC, "Found Damage Resistance Effect Integer 0 : "
          + IntToString(GetEffectInteger(eEffect, 0)));
      SendMessageToPC(oPC, "Found Damage Resistance Effect Integer 1 : "
          + IntToString(GetEffectInteger(eEffect, 1)));
      SendMessageToPC(oPC, "Found Damage Resistance Effect Integer 2 : "
          + IntToString(GetEffectInteger(eEffect, 2)));
      SendMessageToPC(oPC, "Found Damage Resistance Effect Integer 3 : "
          + IntToString(GetEffectInteger(eEffect, 3)));
      SendMessageToPC(oPC, "Found Damage Resistance Effect Integer 4 : "
          + IntToString(GetEffectInteger(eEffect, 4)));
      SendMessageToPC(oPC, "Found Damage Resistance Effect Integer 5 : "
          + IntToString(GetEffectInteger(eEffect, 5)));
      SendMessageToPC(oPC, "Found Damage Resistance Effect Integer 6 : "
          + IntToString(GetEffectInteger(eEffect, 6)));
      SendMessageToPC(oPC, "Found Damage Resistance Effect Integer 7 : "
          + IntToString(GetEffectInteger(eEffect, 7)) + "\\n");
    }
    else
    {
      SendMessageToPC(GetFirstPC(FALSE), "Found Other Effect : "
          + IntToString(GetEffectType(eEffect)));
    }

    eEffect = GetNextEffect(oPC);
  }
}


G'luck :)


ps. add these and i Think that's pretty much all of it (it might hold a DC also..)

int GetEffectDurationType(effect eEffect);
object GetEffectCreator(effect eEffect);

Modifié par kevL, 09 juin 2013 - 03:55 .


#3
ColorsFade

ColorsFade
  • Members
  • 1 267 messages
Thanks KevL. Not quite what I was looking for, but it might turn out to be useful anyway.

The effect struct is... well, a struct. And what I am wondering is if it is like all the other structs in the scripting library or if it is actually something wholly unique (like a special object with no public properties)

You can create your own structs in the script language and access their properties via "dot notation". And if I knew what the properties were I could just access them via dot notation.

Obviously the effect struct is compiled into the actual app, because there's no definition anywhere for it in the scripts (grepped it, no joy). So it makes sense that there are several Get() methods that reveal properties of the struct, because there is no other way to discover what the properties of the struct really are.

What I am curious about is whether the properties are logically named or whether they are obfuscated in some way. If the properties are logically named then the dot notation should still work. But if the properties are named with some sort of non public, non-obvious naming convention then it might be impossible to ever get at them without some decompiler magic...

I'll just have to try a few tests and see if I can get at a property. If I can narrow down the naming convention it should be possible.

#4
kevL

kevL
  • Members
  • 4 056 messages
good luck

#5
ColorsFade

ColorsFade
  • Members
  • 1 267 messages
KevL - what are all the various Integer calls for? (GetEffectInteger) How many are there?

It's like a bunch of values stored in some array.. .

#6
kevL

kevL
  • Members
  • 4 056 messages
they're for parameters that go beyond "subtype" and "durationtype"

I'm hazy and haven't worked with this for a while ( ie. it's a headache ) but let's see:

if investigating DAMAGE_RESISTANCE, it's applied w/


EffectDamageResistance(int nDamageType, int nAmount, int nLimit=0

the Type is EFFECT_TYPE_DAMAGE_RESISTANCE
the subType is magical/extraordinary/supernatural
the duration is whatever (permanent/temporary)

then the array (for Damage_Resistance) should hold DAMAGE_TYPE_*, nAmount, nLimit

The headache happens if/when you find yerself hunting through a score of .2da's trying to figure out which one holds the right value ... ( i don't think any of this is documented, but if you come across something for NwN1 it probably holds true for 2 by and large though there are one or two differences )

#7
ColorsFade

ColorsFade
  • Members
  • 1 267 messages
It's cool. I realize that I'm going about this the wrong way. Even if I knew what ever integer value corresponded to, I still couldn't change the value.

This is all in regards to trying to refresh spell buffs after a long conversation - something I really want to do in my campaign. I decided to try a different tact and I think it's going to work. It's a bit complicated and requires some array data structures to store information, but so far so good.

#8
kevL

kevL
  • Members
  • 4 056 messages
oh yeah.

The NWNx runtime ( for 1 or 2 ) might have something to say.. doubt it but maybe. My intuition tells me it's not so much the Effect that needs manipulation, as whatever it is in the game-engine that actually does the countdown


idk, g'Luck

#9
ColorsFade

ColorsFade
  • Members
  • 1 267 messages
Yeah. But somewhere, some piece of data has to store the countdown after every turn, and I'd bet that's on the effect, although it could be stored on the creature in some other weird way we don't know about.

But like I said, I think there is a better way to go about it. It's clear to me now that manipulating the countdown isn't going to happen. The properties and methods necessary to properly extend a spell's duration simply aren't exposed through the scripting interface. They are buried too far in the code.

But as Pain mentioned in one of my first threads about this months ago, the way to do it is store the pertinent information about the spell so you can essentially re-cast it on the target. Done right, this works.

This is the route I'm taking now. Being able to use the spell hook is helping a lot to capture the data when the spell is actually cast (who cast it and did they use any metamagic? - those are the two big things). I have a way to store all the data and I have a way to recast the spell. I'm in the middle of testing that aspect of it now to make sure the re-casting is accurate. So far, so good.

The final trick in all of this is determining how you go about re-casting the spells and when. I only want it to happen during conversations - essentially those conversation cut scenes that happen before a boss mob fight. This makes it easier, because it means I only want to re-cast buffs in a specific situation.

So my first choice is an area heartbeat that checks if the PC is in a conversation. If it is, the script cycles through the party members and their effects and rebuffs them every heartbeat tick. This gets a little involved with the logic because a single spell can provide several enhancements, so you don't want to overbuff. I'm working that logic out now.

So far it seems to work. By the time the conversation is over, the characters are still buffed and ready to go.

What I am doing is not a true "refresh" however - because the buffs have been recast like new, the duration for each is going to be the max, as if you'd just cast it. But I'm okay with that, because the boss mobs are going to be instantly casting numerous buffs via my AI as if they had a sequencer at work.

So far, testing is working it out... seems like it's going to work. If it does... it solves a huge issue for me.

#10
kevL

kevL
  • Members
  • 4 056 messages
If you need a function that filters buffs by SpellID, see kL_GetIsBuff() at the bottom of 'mrop_spellhook' in the MetaPrepa. It very likely includes all stock and kPrC buffs

but yeah, eventually i intend to get to the sort of things CSL does as part'n'parcel of my stock game .... And, for me, that means dealing with the scripts directly,


( link to previous thread )

#11
ColorsFade

ColorsFade
  • Members
  • 1 267 messages
Well, my plan, once again, didn't work. My rebuffing code works - but it causes the conversation to exit because it's actually casting the spell again - not just applying the spell to the character. Not what I wanted... And I can't find a "silent", non-intrusive way to get a spell back onto a character.

I'm giving up on this. I've invested way too much time in something that clearly the game designers just didn't account for.

It irks the heck out of me that they didn't build this into the game by default. Conversations shouldn't cause time to pass and buffs to fade. It's just too annoying for actual gameplay.

#12
kevL

kevL
  • Members
  • 4 056 messages
heck you've come this far...

Can it run from the EndConversation slot (dialog properties)? Even trigger it from the BossAI....


sure it's colorful (sic) but that can be kinda cool and give the player a needed shot of adreneline.

Modifié par kevL, 10 juin 2013 - 07:12 .


#13
ColorsFade

ColorsFade
  • Members
  • 1 267 messages
 I'd have to rework the code some. '

The way I'm doing it now, I'm looping through the effects on the character and getting the Spell ID, then checking to see if the spell has any meta data stored on the creature (it does - because that gets stored from the spell hook code when the spell is actually cast) and then recasting the spell. Problem is - if the spell wears off during the conversation.. the effect is gone. Which is why I was doing it on heartbeat. 

What I'd have to do is perform the loop at the start of the conversation and store the Spell ID's then , and then at the end of the conversation do the rebuff. 

It's doable. I'm already using an array to store the Spell ID's when I do the looping. I'd only have to do it one time now and it wouldn't require a heartbeat... It would just be tied to the actual conversation, which I kind of like.

Okay. I'll give it a shot. 

There's one more issue though: I can't get the companions to fire the spell hook script in the area. I have the X2_L_WILD_MAGIC =1 on the area per the Lilac Soul Tutorial, but so far the script doesn't fire for them. Do you know of anything else I could be missing? The spell hook script fires for the PC. 

Modifié par ColorsFade, 10 juin 2013 - 01:25 .


#14
kevL

kevL
  • Members
  • 4 056 messages
X2_L_WILD_MAGIC = 1 on the area,

should fire up the spellhook for companions likety split.


..typo?

#15
ColorsFade

ColorsFade
  • Members
  • 1 267 messages

kevL wrote...

X2_L_WILD_MAGIC = 1 on the area,

should fire up the spellhook for companions likety split.


..typo?


I wish, but I copied and pasted it and checked again. 

I know when a paste a variable name in the variable section that sometimes I accidentally end up with a whitespace character on the very end, which makes it not work. But I checked... seems correct. 

I'll have to verify this afternoon. Morning real job work has me swamped. 

#16
rjshae

rjshae
  • Members
  • 4 485 messages

ColorsFade wrote...
The way I'm doing it now, I'm looping through the effects on the character and getting the Spell ID, then checking to see if the spell has any meta data stored on the creature (it does - because that gets stored from the spell hook code when the spell is actually cast) and then recasting the spell. Problem is - if the spell wears off during the conversation.. the effect is gone. Which is why I was doing it on heartbeat.


Don't the ga_clock_off & ga_clock_on scripts work?

#17
ColorsFade

ColorsFade
  • Members
  • 1 267 messages

rjshae wrote...

Don't the ga_clock_off & ga_clock_on scripts work?


From looking at the code, it looks like all those methods do is turn on/off the GUI - they don't actually affect the internal clock of the game. I'd have to test to verify it. 

#18
ColorsFade

ColorsFade
  • Members
  • 1 267 messages

kevL wrote...

X2_L_WILD_MAGIC = 1 on the area,

should fire up the spellhook for companions likety split.

..typo?


Got it working. I think it was just a quirk of the Toolset - sometimes CTRL-S just doesn't seem to "save" everything. 


I just tried the whole thing and it worked. It's not perfect - but really close. 

I have two scripts: ga_save_buffs and ga_restore_buffs. I call those at the start and end of the conversation. I use a low level caster to make sure the buffs wear off. And at the end of the conversation it rebuffs my characters completely. 

I thought it might bug me having the buffs re-cast like that at the end of the conversation, but it's actually pretty cool. And if you're doing a NWN2 cut-scene conversation (which is when I would use these little scripts) then it's not really noticable anyway. 

It's kind of neat. The NPC's are going to insta-buff themsevles anyway. And PC and party are insta-buffed and ready for battle. It's showtime. 

Thanks for the assist KevL. This fixes a huge issue. 

Oh, but like I said, it's not perfect. The one issue is summons. It doesn't work on summoned creatures - it won't re-cast them. And I think that's because the summoned creature isn't an effect, so when the conversation starts and I cycle through effects on the creature to figure out what spells were cast, there is no effect for the summoned creature, hence it can't be tracked to be re-cast. 

But I'm okay with that. 

This makes me much happier. And it's pretty easy to manage. A spellhook script and to action scripts for conversations. That's not much maintenance effort at all. 

#19
kevL

kevL
  • Members
  • 4 056 messages
great :) Am sure you'll add in some niceties ( like checks for summons ) as time goes by,


Things like a recently quaffed Haste potion might be nigh impossible; but then, AutomaticFailure on a natural 1 for Will & Reflex saves don't actually fail either.

tallyho! ( I just got a message that 'they' turned off PM's -- then they wished me a nice day, Lol )

#20
ColorsFade

ColorsFade
  • Members
  • 1 267 messages
Potions work. I just checked. I checked Bless and Speed... rebuffed at the end of the conversation (Speed wore off before the conversation finished - but you get it back!)

What I don't know for certain is the level of the potion before it gets re-cast.

When I "re-buff" the characters, I keep track of whoever initially cast the spell (or in the case of a potion, it tracks whoever used it). The game engine needs that information in the function call and internally it uses the creature to determine spell level.

So, for instance, with the Bless potion, my main PC was the character that used the potion. Thus, my main PC is the object that gets passed when the call is made to ActionCastSpellAtObject() by my rebuff script. When each of the members of my party get rebuffed for Bless, my PC is the object being passed to the function and used as the source of the spell/potion (it seems the scripts don't differentiate).

I'd have to sit down with a timer and watch the potion wear off to be sure. But judging from the scripting, they should be the same thing...

I think I remember reading something about effects from wands/items are set at level 10 though. I'll have to check into it.

Right now this works. I'll probably allow for some kind of global flag to be set if people don't like it and want to turn this behavior off. But for me - this is nice. I really enjoy the cut scenes right before a big boss battle, but I hate having my buffs go away. And this solves it.

A bit more testing and I might have to post the scripts.

#21
kevL

kevL
  • Members
  • 4 056 messages
It struck me as odd because, i thought, potions (& items) don't have valid SpellID's ( or valid Creator-objects ). Am pretty sure 10 is default for potions/wands, although casts from special items have pre-defined Level ( in Iprp_Spells.2da, fwiw )

anyway, your scripts, you pick the nits ;)


edit: knits

Modifié par kevL, 10 juin 2013 - 10:26 .


#22
ColorsFade

ColorsFade
  • Members
  • 1 267 messages

kevL wrote...

It struck me as odd because, i thought, potions (& items) don't have valid SpellID's ( or valid Creator-objects ). Am pretty sure 10 is default for potions/wands, although casts from special items have pre-defined Level ( in Iprp_Spells.2da, fwiw )

anyway, your scripts, you pick the nits ;)


It's interesting to dig into this stuff. 

I took the Bull's Strength spell script and put it into my Module folder and edited it. All I did was add a SendMessageToPC() call so I could see my local version fire. 

Guess what? 

Doesn't matter if you cast from a spell or a potion - the same script fires. I got the message both ways. 

And hence, the SpellHookScript also fires...

So that got me curious. There's a call in nearly every spell script to GetCasterLevel, which is an internal (blue) function. I decided to check caster levels. 

I had my party of me, Elanee, and Z, all at level 5. Elanee casts Bull's Strength and it correctly reports the CasterLevel as lEvel 5. 

I then went to use a potion of Bull's Strength. Same script fired, but it reported the CasterLevel as 3. Yet, it considered Elanee (the creature using the spell) as the caster... 

So something fishy is happening inside GetCasterLevel. And of course, we'll never be privvy to it. 

But that's cool. I now know that buffs from potions, items or spells are going to work with this. They will all be re-cast at the end of the conversation. 

#23
Dann-J

Dann-J
  • Members
  • 3 161 messages
I'm pretty sure there is a column in spells.2DA that indicates a default casting level, for when a spell script is being executed by an item rather than a creature (so there is no valid caster level).

[Edit: I think it's the 'Innate' column: http://nwn2.wikia.com/wiki/Spells.2da ]

Modifié par DannJ, 11 juin 2013 - 01:22 .


#24
I_Raps

I_Raps
  • Members
  • 1 262 messages
The Caster Level for spells cast by items (including scrolls) is set in one of the IPRPs 2das.

(edit)  It's iprp_spells.2da

Some spells are already in there at different CLs.  Greater Heroism, for example, can be set for CL 13, 17, or 20.

Modifié par I_Raps, 11 juin 2013 - 01:24 .


#25
Dann-J

Dann-J
  • Members
  • 3 161 messages
Yes - I've just checked a copy of spells.2DA I have here at work, and the 'innate' level for Bull's Strength is set to level 2. So obviously the item property 2DAs override that (if indeed the 'innate' column does anything at all in NWN2).