Author Topic: Help understanding a script.  (Read 1856 times)

Legacy_Lightfoot8

  • Hero Member
  • *****
  • Posts: 4797
  • Karma: +0/-0
Help understanding a script.
« Reply #15 on: November 07, 2011, 02:38:06 am »


               @Rolo Kipp,
Well you do have a point.  But I do not see it even that cut and dry.   The subject is really a lot more complex,  With the scripting system we have there is really no way to script it.  

Even a compair level falls short, If a PC for some odd reason has both wizard and sorcerer levels there is still no garentee that the spell they are casting is  in both the wizaed and sorcerer books.  So in order to do it right you would have to figure out what book the spell was being cast from.  unfortunatly we just have no way of doing that in  nwscript.  At least not a way that I know of.  

I myself would just use
int ResistSpell(object oCaster, object oTarget);      
and hope that it takes the above into concideration.   But In this case I do not even see a target, so I am not sure if its use is plausable.  

since there are errors either way.  I see no need for the comparisions,  unless you always want to give the benifit of the doubt and advantage to the PC.

I am not much af a mage person my self, but I see a wizard/sorcerer only as an attempt to work the system.  Bad attempt at that.  But then again there are builders out there that like to concider every single caster level as the level a spell is cast at.  In that case it may be a strong working of the system.    

Heck I dont know.   It looks good enough as is to me, but that is just me.
               
               

               
            

Legacy_WhiZard

  • Hero Member
  • *****
  • Posts: 2149
  • Karma: +0/-0
Help understanding a script.
« Reply #16 on: November 07, 2011, 01:14:50 pm »


               

Lightfoot8 wrote...
I myself would just use
int ResistSpell(object oCaster, object oTarget);      
and hope that it takes the above into concideration. 


ResistSpell() only acknowledges last (or current) cast spell, same as GetLastCastSpellclass().  Declaring a spell (e.g. SignalEvent()) has no impact on ReistSpell() as far as spell identification.  (SignalEvent() can fix a bug  in AoE handler scripts (on-enter, on-heartbeat, and on-exit) that by default make ResistSpell() an automatic failure).
               
               

               
            

Legacy_Shadooow

  • Hero Member
  • *****
  • Posts: 7698
  • Karma: +0/-0
Help understanding a script.
« Reply #17 on: November 07, 2011, 02:21:43 pm »


               Or just take the highest casting ability like bioware did with their epic spells.
               
               

               
            

Legacy_Rolo Kipp

  • Hero Member
  • *****
  • Posts: 4349
  • Karma: +0/-0
Help understanding a script.
« Reply #18 on: November 07, 2011, 05:50:48 pm »


               <popping out of the shadow...>

Lightfoot8 wrote...
@Rolo Kipp, Well you do have a point.  But I do not see it even that cut and dry.   The subject is really a lot more complex,  With the scripting system we have there is really no way to script it.  

Even a compair level falls short, If a PC for some odd reason has both wizard and sorcerer levels there is still no garentee that the spell they are casting is  in both the wizaed and sorcerer books.  So in order to do it right you would have to figure out what book the spell was being cast from.  unfortunatly we just have no way of doing that in  nwscript.  At least not a way that I know of.

At least, not without hooking into each and every spell... or perhaps the radial menu? You do pick the spell by spellbook when casting. Pehaps setting a int iSpellBookLastUsed on the PC... Just brainstorming here.

I myself would just use
int ResistSpell(object oCaster, object oTarget);      
and hope that it takes the above into concideration.   But In this case I do not even see a target, so I am not sure if its use is plausable.

I'm a bit lost there. You mean use ResistSpell instead of the whole shebang above?
But, does ResistSpell work with fake spells?
Perhaps I'm missing the whole purpose of Rob's script...?

since there are errors either way.  I see no need for the comparisions,  unless you always want to give the benifit of the doubt and advantage to the PC.

I am not much af a mage person my self, but I see a wizard/sorcerer only as an attempt to work the system.  Bad attempt at that.  But then again there are builders out there that like to concider every single caster level as the level a spell is cast at.  In that case it may be a strong working of the system.    

Heck I dont know.   It looks good enough as is to me, but that is just me.

Ack! You wound me! <heh, he looks fine to me>
Consider that *any* action in game is simply an indirect db query that either retrieves or modifies the world-state db.  Magic is simply an extension of the syntax available to fiesty foo fighters :-P

<...the kitty casts>
               
               

               
            

Legacy_Rolo Kipp

  • Hero Member
  • *****
  • Posts: 4349
  • Karma: +0/-0
Help understanding a script.
« Reply #19 on: November 07, 2011, 05:56:34 pm »


               <tossing an approving...>

WhiZard wrote...
What this should be is:

if(GetLevelByclass(class_TYPE_SORCERER, oPC))  as the if clause will report any non-zero value as satisfying the "if" requirements.

Elegant :-) I like. (subject to the above comments ;-P )

ResistSpell() only acknowledges last (or current) cast spell, same as GetLastCastSpellclass().  Declaring a spell (e.g. SignalEvent()) has no impact on ReistSpell() as far as spell identification.  (SignalEvent() can fix a bug  in AoE handler scripts (on-enter, on-heartbeat, and on-exit) that by default make ResistSpell() an automatic failure).

Didn't know that about SignalEvent, Thanks, WiZard. 

<...nod to his brother in spells>
               
               

               
            

Legacy_Rolo Kipp

  • Hero Member
  • *****
  • Posts: 4349
  • Karma: +0/-0
Help understanding a script.
« Reply #20 on: November 07, 2011, 05:59:52 pm »


               <carefully *not*...>

ShaDoOoW wrote...
Or just take the highest casting ability like bioware did with their epic spells.

Which is the direction *I* was leaning (i.e. give the PC the benefit of the extra hard work it would be to figger out the *accurate* modifier ;-)

<...mucking with *this* shadow>
               
               

               
            

Legacy_WhiZard

  • Hero Member
  • *****
  • Posts: 2149
  • Karma: +0/-0
Help understanding a script.
« Reply #21 on: November 07, 2011, 07:42:36 pm »


               

Rolo Kipp wrote...

ResistSpell() only acknowledges last (or current) cast spell, same as GetLastCastSpellclass().  Declaring a spell (e.g. SignalEvent()) has no impact on ReistSpell() as far as spell identification.  (SignalEvent() can fix a bug  in AoE handler scripts (on-enter, on-heartbeat, and on-exit) that by default make ResistSpell() an automatic failure).

Didn't know that about SignalEvent, Thanks, WiZard. 

<...nod to his brother in spells>

The full description of the bug is in the wiki SR article.  It is one of the bugs which I have no idea why it exists and why it is limited to AoEs.  Its only in-game appearance is for the darkness area of effect which prevents ResistSpell() from getting spell immunity from the caster or those that are not standard hostile.  Unlike feats, which will always show nothing to the player and report ResistSpell() as failure to the script (regardless of the correct SignalEvent()), the AoE bug actually displays to the player an SR roll that has nothing to do with what is reported to the script.
               
               

               
            

Legacy_Shadooow

  • Hero Member
  • *****
  • Posts: 7698
  • Karma: +0/-0
Help understanding a script.
« Reply #22 on: November 08, 2011, 08:46:18 am »


               

WhiZard wrote...

Lightfoot8 wrote...
I myself would just use
int ResistSpell(object oCaster, object oTarget);      
and hope that it takes the above into concideration. 


ResistSpell() only acknowledges last (or current) cast spell, same as GetLastCastSpellclass().  Declaring a spell (e.g. SignalEvent()) has no impact on ReistSpell() as far as spell identification.  (SignalEvent() can fix a bug  in AoE handler scripts (on-enter, on-heartbeat, and on-exit) that by default make ResistSpell() an automatic failure).

can anyone comfirm this? I tried it and it did work without SignalEvent correctly.
               
               

               
            

Legacy_WhiZard

  • Hero Member
  • *****
  • Posts: 2149
  • Karma: +0/-0
Help understanding a script.
« Reply #23 on: November 09, 2011, 04:39:22 am »


               

ShaDoOoW wrote...

WhiZard wrote...
(SignalEvent() can fix a bug  in AoE handler scripts (on-enter, on-heartbeat, and on-exit) that by default make ResistSpell() an automatic failure).

can anyone comfirm this? I tried it and it did work without SignalEvent correctly.


I am cutting the amount you quoted me down to the parenthetical that is being challenged.  I apologize for the slow response (ShaDoOoW had PMed me on this before),  but quirky behavior often causes a lot of test cases before I am willing to respond, especially when the quirkiness had previously been misidentified.

This discussion may probably warrant its own thread, so if there is discussion possibility start a new thread quoting this post.

For simplicity AoE will refer to the AoE effect object (the one with the on-enter, on-heartbeat, and on-exit handler scripts), not scripting on objects within an area.

  First the misidentification: My original testing had begun with darkness, a fluked area of effect from the start, which has signaling for both hostile and non-hostile spells depending on the creature.  I noticed the lack of spell immunity ever having an effect for the caster and set up a response system within the script to report various values being used, especially the value of ResistSpell().  I had also modified the scripts of wall of fire (hostile flag in spells.2da) and a changed version of invisibility sphere (non-hostile flag in spells.2da) as my comparison.  Both wall of fire and invisibility sphere only used a hostile spell signal event followed by the ResistSpell().  I then had the values of darkness compared and flukes were there for the non-hostile spell signal and remained when I commented it out.  What I did not realize is that darkness had a further bug, which in the hostile cases I had unintentionally fixed.  Each ResistSpell() was determined by OBJECT_SELF (that is the area of effect not my character) however the frequency of the spell resistance success and failure rolls matched my character completely, no matter which character or what level, which prevented me from noticing the obvious difference in objects.  The return value of 0 does happen for magic immunity and spell mantles, but when the normal SR roll was tested I was getting the local variable off the wrong object.

  Second the quirkiness:  Area of effects do function slightly differently with ResistSpell().  ResistSpell() has two arguments the "caster" and the "target", as well as three potential checks "spell level absorption" (i.e. mantle), "spell immunity", and "SR roll".   In addition ResistSpell() looks at whether the last cast spell by the "caster" was used from a feat (hereafter described as "feat flag"). 
  Use outside of AoEs (even for planar rift on BBoD which uses the summoner as the "caster" rather than the blade) for ResistSpell() only uses elements of the last cast spell of the "caster."  They are, the caster level (GetCasterLevel()) with penetration feats added, the spell level and school from which the spell was cast, the spell ID, and the "feat flag".  If the last cast spell was cast as a feat ResistSpell() defaults to 0 and sends no message to the PC.  Otherwise, the entire ResistSpell() functions normally.  Thus if I cast BBoD, then cast the assassin ghostly visage, the planar rifts of BBoD would refer to ghostly visage being a feat and thus bypass ResistSpell().  If I cast the spell shield instead of ghostly visage, the spell level would be 1, the school would be abjuration, and my caster level from the spellbook which I cast shield would be used in the "SR roll".
  When used within an AoE script (any script or command initiated by an Area of Effect object including DelayCommand())  both "spell level absorption" and "spell immunity" carry their entire information over from the last cast spell of the "caster" respecting the "feat flag".  The "SR roll" instead of potentially using another spell's caster level or being negated by a "feat flag", instead overrides the normal process using the same value for its "SR roll" as the dispels retrieve for the caster level of the effect.  For normal spells, this means the "SR roll" is not bugged when going from one spellbook to another or using feats.  On the other hand, feats like the assassin's darkness will use the full character level (instead of class level which is retrieved by GetCasterLevel()), as they are not cast from a spellbook.  Given darkness is the only AoE feat, and that it ignores an "SR roll" success, there is no in-game issue arising from feats being treated this way.

  Third the darkness bug:  The darkness AoE uses OBJECT_SELF as the caster and thus since the AoE does not have a last cast spell, all checks for spell immunity or spell level absorption fail.  Changing the "caster" to the AoE creator will allow it to check spell immunity according to the creator's last cast spell (the "SR roll" will be the same as the effect's "dispelability caster level" overrides the normal caster level).

EDIT: cleaning up format and clarifying examples
               
               

               


                     Modifié par WhiZard, 09 novembre 2011 - 05:15 .
                     
                  


            

Legacy_WhiZard

  • Hero Member
  • *****
  • Posts: 2149
  • Karma: +0/-0
Help understanding a script.
« Reply #24 on: November 09, 2011, 04:42:19 am »


               Double post
               
               

               


                     Modifié par WhiZard, 09 novembre 2011 - 04:42 .
                     
                  


            

Legacy_Shadooow

  • Hero Member
  • *****
  • Posts: 7698
  • Karma: +0/-0
Help understanding a script.
« Reply #25 on: November 09, 2011, 12:11:19 pm »


               Yup, this is the real issue. I didnt wanted to mention it anywhere especially on wiki as it allows some really nasty 3xpl01ts, the one with BBoD (where you can use any epic spell to bypass immunity as well) is the reason why my patch adds a new variable-based immunity to BBoD which works in all cases.

I didnt noticed the level would changed (and assassin feats uses
Assassin level not character level) but caster level doesn't have any
effect on AOEs by default anyway as the damage is usualy fixed or it has
different effect though. Even if my patch fixes the incorrect caster
level or DC as it uses not values from functions but values stored on
AOE object which are written from original spell script).

But you are incorrect in the case of AoE and other spells when you claim its not bugged when you cast other spells. There is a big issue with ResistSpell that some players already learn to abuse. Since the ResistSpell uses last spell cast, you can very simpy penetrate eg. demilich immunity to all spells using an epic spell or non-spell-like feat like in the case in BBoD. Or you can make yourself immune. To do it, you need to cast shadow shield/globe of invulnerability/shield spell and then simply after you stack all the aoes you need you cast a necromantic/lvl 1-4/magic missile spell before you enter your AoEs. Then you will be completely immune while enemies won't. Neither my patch fixes this issue as it would mean to rewrite the spell resist function itself as its hardcoded and use a innatelevel to do it. Ugly workaround I mean, it would be easier and maybe would make more sense to remove the spell resist check for AoEs. They are not subject to resistance according to dnd rules anyway.
               
               

               


                     Modifié par ShaDoOoW, 10 novembre 2011 - 02:39 .
                     
                  


            

Legacy_WhiZard

  • Hero Member
  • *****
  • Posts: 2149
  • Karma: +0/-0
Help understanding a script.
« Reply #26 on: November 09, 2011, 07:21:40 pm »


               

ShaDoOoW wrote...
But you are incorrect in the case of AoE and other spells when you claim its not bugged when you cast other spells. .


My claim was that the "SR roll" portion (not spell immunity or spell level absorption) was not bugged for AoEs as it used the "dispelability caster level" (of the effect) instead of the normal caster level (of the last cast spell).  Non-AoEs (like planar rift) will be bugged for all three portions as it takes its caster level from the "last cast spell" of the "caster".
               
               

               


                     Modifié par WhiZard, 09 novembre 2011 - 07:22 .
                     
                  


            

Legacy_Shadooow

  • Hero Member
  • *****
  • Posts: 7698
  • Karma: +0/-0
Help understanding a script.
« Reply #27 on: November 09, 2011, 07:46:22 pm »


               ok

WhiZard wrote...

Non-AoEs (like planar rift) will be bugged for all three portions as it takes its caster level from the "last cast spell" of the "caster".

Hmmm, not neccessarily. It should work fine in a lets say with ordinar special ability provided the ResistSpell function is called in the actual script and that this script only fires after spell is cast, not in onhit or from other place via ExecuteScript.

But I think we both forgot on one important thing - spell resistance comes into play only for normal spell. For a spellscripts called from a spell of UserType > 1 only spell immunity and possibly spell mantle (untested) is checked.
               
               

               
            

Legacy_WhiZard

  • Hero Member
  • *****
  • Posts: 2149
  • Karma: +0/-0
Help understanding a script.
« Reply #28 on: November 09, 2011, 09:38:01 pm »


               

ShaDoOoW wrote...

ok

WhiZard wrote...

Non-AoEs (like planar rift) will be bugged for all three portions as it takes its caster level from the "last cast spell" of the "caster".

Hmmm, not neccessarily. It should work fine in a lets say with ordinar special ability provided the ResistSpell function is called in the actual script and that this script only fires after spell is cast, not in onhit or from other place via ExecuteScript.

"last cast spell" implies (current) in the way I defined it (just like GetLastSpellCastclass() uses current).   ResistSpell() only looks at the last information for the character ("caster") in question for usage of spells.2da (spell-casting feat using, etc.)

But I think we both forgot on one important thing - spell resistance comes into play only for normal spell. For a spellscripts called from a spell of UserType > 1 only spell immunity and possibly spell mantle (untested) is checked.

False.  User type has no significance for ResistSpell() .  Planar Rift has user type 4 and functions as expected.  ResistSpell() uses no information from the actual spell unless it happens to correspond to the last set information of the "caster", (e.g. normal spells).


EDIT:  If the "last cast spell" of the "caster" has a spell level above 9 will skip the "SR roll" automatically.  This may be the "user type" discrepancy you were seeing.
               
               

               


                     Modifié par WhiZard, 09 novembre 2011 - 09:57 .
                     
                  


            

Legacy_Shadooow

  • Hero Member
  • *****
  • Posts: 7698
  • Karma: +0/-0
Help understanding a script.
« Reply #29 on: November 09, 2011, 11:14:14 pm »


               False? Really? You have tested it? I did, long time ago when I encountered the BBoD bug the first time, and now again before few minutes to be extra sure.

ResistSpell return -1 if the UserType is not 1. See epic spells are 2, its not about InnateLevel which is for other special abilities lesser than 10 and the ResistSpell still returns -1. The BBoD is an exception as its triggered from onhit where it does uses the spell informations of the last spell cast so if the last spell cast was of UserType 1 it, the ResistSpell will work as that spell so i will try to remove spell mantle with last spell cast spell level, then it might be stopped by a spell immunity of caster is immune to the school or spell of the last spell cast and then it will try to penetrate SR (with a caster level of last spell cast). Since the last spell cast after casting BBoD is the BBoD spell it will work that way until the caster uses anything with a UserType of 2+, then the ResistSpell simply return -1 like it would normally for such ability.
               
               

               


                     Modifié par ShaDoOoW, 09 novembre 2011 - 11:15 .