Aller au contenu

Photo

Help understanding a script.


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

#1
Fester Pot

Fester Pot
  • Members
  • 1 391 messages
The below script is from Witches Wake, used in conversations to cast spells.

Two test characters are used and are generating different results and I don't understand why or where the difference in value is coming from.

Character 1

Level 6 Dwarf Pure Wizard with 16 Intelligence

Character 2

Level 6 Dwarf Pure Wizard with 19 Intelligence

When casting the same spell, Acid Splash - or any spell for that matter using these scripts - the value that is added to the d20 roll is different, which I expect based on the +3 difference in the intelligence between the two characters.

The problem, or perhaps it's not a problem, I just can't figure out how the value is being determined, is that Character 1 has a higher value added to the d20 roll vs. Character 2, even though the latter has the higher intelligence.

Character 1 always receives a 9 (sSkill) bonus when casting spells, added to the d20 roll.

Character 2 always receives a 5 (sSkill) bonus when casting spells, added to the d20 roll.

I can't figure out why.

All test characters were naked when casting these spells and all intelligence stats posted above are their stock INT scores with no modifiers.

Here's the script.

//::///////////////////////////////////////////////
//:: Witchwork Conversation System: Cast Acid Splash Check
//:: WW_Abil_AcidSp.nss
//:: Copyright © 2001 Bioware Corp.
//:://////////////////////////////////////////////
/*
     Does a Cast Acid Splash check and broadcasts a
     feedback string.
*/
//:://////////////////////////////////////////////
//:: Created By: Rob Bartel
//:: Created On: August 30, 2002
//:://////////////////////////////////////////////

void main()
{
    object oPC = GetPCSpeaker();
    int bHasSpell1 = GetHasSpell(SPELL_ACID_SPLASH, oPC);

    //If PC is unable to cast Acid Splash, do nothing...
    if (bHasSpell1 == FALSE)
    {
        return;
    }

    object oNPC = OBJECT_SELF;
    int iAbilityType;
    int iSpell;

    //Get the PC's individual class levels for calculating their total
    //character level.
    int iclass1Level = GetLevelByPosition(1, oPC);
    int iclass2Level = GetLevelByPosition(2, oPC);
    int iclass3Level = GetLevelByPosition(3, oPC);

    //Determine what those three classes are.
    int iclass1 = GetclassByPosition(1, oPC);
    int iclass2 = GetclassByPosition(2, oPC);
    int iclass3 = GetclassByPosition(3, oPC);

    //Make an educated guess as to whether they used Acid Splash
    if (GetHasSpell(SPELL_ACID_SPLASH, oPC))
        iSpell = SPELL_ACID_SPLASH;

    //Otherwise start doing some educated guessing as to what class they might
    //be casting from so you can use the appropriate ability score modifier.
    //class 1:
    else if (iclass1 == class_TYPE_WIZARD)
        iAbilityType = ABILITY_INTELLIGENCE;
    else if (iclass1 == class_TYPE_SORCERER ||
             (iclass1 == class_TYPE_BARD &&
              iclass1Level >= 2))
        iAbilityType = ABILITY_CHARISMA;
    //class 2:
    else if (iclass2 == class_TYPE_WIZARD)
        iAbilityType = ABILITY_INTELLIGENCE;
    else if (iclass2 == class_TYPE_SORCERER ||
             (iclass2 == class_TYPE_BARD &&
              iclass1Level >= 2))
        iAbilityType = ABILITY_CHARISMA;
    //class 3:
    else if (iclass3 == class_TYPE_WIZARD)
        iAbilityType = ABILITY_INTELLIGENCE;
    else if (iclass3 == class_TYPE_SORCERER ||
             (iclass3 == class_TYPE_BARD &&
              iclass1Level >= 2))
        iAbilityType = ABILITY_CHARISMA;
    //For Special Abilities, use intelligence:
    else
        iAbilityType = ABILITY_INTELLIGENCE;

    //Decrement the spell & cast a fake one
    AssignCommand(oPC, ActionPauseConversation());
    DecrementRemainingSpellUses(oPC, iSpell);
    AssignCommand(oPC, ActionCastFakeSpellAtObject(iSpell, oNPC));
    AssignCommand(oPC, ActionResumeConversation());

    //Declare the values used in the Ability Check
    int iDC = GetLocalInt(OBJECT_SELF, "iWW_AbilityDC");
    int iD20 = Random(20)+1;
    int iAbilMod = GetAbilityModifier(iAbilityType, oPC);
    int iCharLevel = iclass1Level + iclass2Level + iclass3Level;

    //Create the final Check calculation.
    int iCheck = iD20 + iAbilMod + iCharLevel;
    int iSkill = iAbilMod + iCharLevel;

    //Convert the above Ints to Strings in preparation for broadcast.
    // DEBUG
    string sDC = IntToString(iDC); // DONE
    string sRoll = IntToString(iD20); // DONE
    string sSkill = IntToString(iSkill); // DONE
    string sCheck = IntToString(iCheck);  // DONE
    // DEBUG

    //If the PC's Check >= DC, they succeed.
    if (iCheck >= iDC)
    {
        SetLocalString(OBJECT_SELF, "sWW_AbilityResult", "Success");
        // PASS ROLL
        string sBroadcast = "<c þþ>Acid Splash</c> <cþþ >:</c> <cþþþ>"+sRoll+"</c> <cþþ >+</c> <cþþþ>"+sSkill+"</c> <cþþ >=</c> <c þ >"+sCheck+"</c> <cþþ >vs.</c> <cþþþ>DC</c> <c þþ>"+sDC+".</c>";
    SendMessageToPC(oPC, sBroadcast);
    }
    //If not, they fail.
    else
    {
        SetLocalString(OBJECT_SELF, "sWW_AbilityResult", "Failure");
        // FAIL ROLL
    string sBroadcast = "<c þþ>Acid Splash</c> <cþþ >:</c> <cþþþ>"+sRoll+"</c> <cþþ >+</c> <cþþþ>"+sSkill+"</c> <cþþ >=</c> <cþ  >"+sCheck+"</c> <cþþ >vs.</c> <cþþþ>DC</c> <c þþ>"+sDC+".</c>";
    SendMessageToPC(oPC, sBroadcast);
    }
}


Just a clean crop of the colour codes regarding the broadcast message of the variables.

Acid Splash : "+sRoll+" + "+sSkill+" = "+sCheck+" vs. DC "+sDC+".

FP!

Modifié par Fester Pot, 05 novembre 2011 - 10:22 .


#2
Shadooow

Shadooow
  • Members
  • 4 465 messages
That probably because the second char has Acid splash spell memorised and thus the ability part is errorneusly skipped and ability remains at value of 0 which is strenght. If your strenght is 8-9 it will match then.

#3
Fester Pot

Fester Pot
  • Members
  • 1 391 messages
They both have it memorized, otherwise the option to cast it via a conversation is not available.

The script does not check strength at all.

FP!

#4
Lightfoot8

Lightfoot8
  • Members
  • 2 535 messages
lol, Shadow nailed it. Where it is true that the script as written will only work if they have Acid Splash. The ability being checked is Strength.

else
iAbilityType = ABILITY_INTELLIGENCE;

is never excuted being in an else clause theat can never fire. Since iAbilityType is never set it is 0. hence the strenght is being checked.

#5
WhiZard

WhiZard
  • Members
  • 1 204 messages

Fester Pot wrote...

They both have it memorized, otherwise the option to cast it via a conversation is not available.

The script does not check strength at all.

FP!


Are the two builds of the same character level?  It seems iCheck adds in the character level + ability modifier + d20. However, I am not seeing which value you are broadcasting that you are trying to refer to as the "before the d20". iDC uses a local variable and is possibly isolated from this system.

Modifié par WhiZard, 06 novembre 2011 - 12:17 .


#6
WhiZard

WhiZard
  • Members
  • 1 204 messages

Lightfoot8 wrote...

lol, Shadow nailed it. Where it is true that the script as written will only work if they have Acid Splash. The ability being checked is Strength.

else
iAbilityType = ABILITY_INTELLIGENCE;

is never excuted being in an else clause theat can never fire. Since iAbilityType is never set it is 0. hence the strenght is being checked.


Yep, looks right.  You might wish to get rid of the GetHasSpell() check, and instead work by GetLastSpellCastclass(), instead.

EDIT: Doesn't look like this forum likes the multiple capitalizations in GetLastSpellCastclass().

Modifié par WhiZard, 06 novembre 2011 - 12:37 .


#7
Lightfoot8

Lightfoot8
  • Members
  • 2 535 messages
The local Look to be the DC of casting.  It is never modified or used in calculations, just checked against for the pass/ fail. 

As far as fixing it goes just remove the else in red below.  

//Make an educated guess as to whether they used Acid Splash
    if (GetHasSpell(SPELL_ACID_SPLASH, oPC))
        iSpell = SPELL_ACID_SPLASH;


    //Otherwise start doing some educated guessing as to what class they might
    //be casting from so you can use the appropriate ability score modifier.
    //class 1:
    else if (iclass1 == class_TYPE_WIZARD)
        iAbilityType = ABILITY_INTELLIGENCE;
    else if (iclass1 == class_TYPE_SORCERER ||......

#8
Lightfoot8

Lightfoot8
  • Members
  • 2 535 messages

WhiZard wrote...

EDIT: Doesn't look like this forum likes the multiple capitalizations in GetLastSpellCastclass().


It is the word 'class'  that it does not like.   This forum will always change it to lower case reguardless of where it is found.  

#9
Fester Pot

Fester Pot
  • Members
  • 1 391 messages
Got it now. In the end, I removed the entire iclass checks as it's a base Wizard/Sorcerer module anyhow and added in an additional check for SpellCraft to the roll to add to the iAbilityType. It's working fine now for both test characters but wow, that strength comment really confused me at first. :)

Thanks all for the direction.

Final and modified script below for reference,

//::///////////////////////////////////////////////
//:: Witchwork Conversation System: Cast Acid Splash Check
//:: WW_Abil_AcidSp.nss
//:: Copyright © 2001 Bioware Corp.
//:://////////////////////////////////////////////
/*
     Does a Cast Acid Splash check and broadcasts a
     feedback string.
*/
//:://////////////////////////////////////////////
//:: Created By: Rob Bartel
//:: Created On: August 30, 2002
//:://////////////////////////////////////////////

void main()
{
    object oPC = GetPCSpeaker();
    int bHasSpell1 = GetHasSpell(SPELL_ACID_SPLASH, oPC);


    //If PC is unable to cast Acid Splash, do nothing...
    if (bHasSpell1 == FALSE)
    {
        return;
    }

    object oNPC = OBJECT_SELF;
    int iAbilityType;
    int iSpell;
    int iSpellCraft;


   if (GetHasSpell(SPELL_ACID_SPLASH, oPC))

        iSpell = SPELL_ACID_SPLASH;
        iSpellCraft = GetSkillRank(SKILL_SPELLCRAFT, oPC, FALSE);

    if (GetLevelByclass(class_TYPE_WIZARD, oPC) == TRUE)

    {
     iAbilityType = ABILITY_INTELLIGENCE;
    }

    if (GetLevelByclass(class_TYPE_SORCERER, oPC) == TRUE)

    {
     iAbilityType = ABILITY_CHARISMA;
    }

    //Decrement the spell & cast a fake one
    AssignCommand(oPC, ActionPauseConversation());
    DecrementRemainingSpellUses(oPC, iSpell);
    AssignCommand(oPC, ActionCastFakeSpellAtObject(iSpell, oNPC));
    AssignCommand(oPC, ActionResumeConversation());

    //Declare the values used in the Ability Check
    int iDC = GetLocalInt(OBJECT_SELF, "iWW_AbilityDC");
    int iD20 = Random(20)+1;
    int iAbilMod = GetAbilityModifier(iAbilityType, oPC);

    //Create the final Check calculation.
    int iCheck = iD20 + iAbilMod + iSpellCraft;
    int iSkill = iAbilMod + iSpellCraft;

    //Convert the above Ints to Strings in preparation for broadcast.
    string sDC = IntToString(iDC); // DONE
    string sRoll = IntToString(iD20); // DONE
    string sSkill = IntToString(iSkill); // DONE
    string sCheck = IntToString(iCheck);  // DONE

    //If the PC's Check >= DC, they succeed.
    if (iCheck >= iDC)
    {
        SetLocalString(OBJECT_SELF, "sWW_AbilityResult", "Success");
        // PASS ROLL
        string sBroadcast = "<c þþ>Acid Splash</c> <cþþ >:</c> <cþþþ>"+sRoll+"</c> <cþþ >+</c> <cþþþ>"+sSkill+"</c> <cþþ >=</c> <c þ >"+sCheck+"</c> <cþþ >vs.</c> <cþþþ>DC</c> <c þþ>"+sDC+".</c>";
    SendMessageToPC(oPC, sBroadcast);
    }
    //If not, they fail.
    else
    {
        SetLocalString(OBJECT_SELF, "sWW_AbilityResult", "Failure");
        // FAIL ROLL
    string sBroadcast = "<c þþ>Acid Splash</c> <cþþ >:</c> <cþþþ>"+sRoll+"</c> <cþþ >+</c> <cþþþ>"+sSkill+"</c> <cþþ >=</c> <cþ  >"+sCheck+"</c> <cþþ >vs.</c> <cþþþ>DC</c> <c þþ>"+sDC+".</c>";
    SendMessageToPC(oPC, sBroadcast);
    }
}


FP!

Modifié par Fester Pot, 06 novembre 2011 - 01:45 .


#10
Lightfoot8

Lightfoot8
  • Members
  • 2 535 messages

Fester wrote....

... object oNPC = OBJECT_SELF;
    int iAbilityType;
    int iSpell;
    int iSpellCraft;


   if (GetHasSpell(SPELL_ACID_SPLASH, oPC))

        iSpell = SPELL_ACID_SPLASH;
        iSpellCraft = GetSkillRank(SKILL_SPELLCRAFT, oPC, FALSE);

    if (GetLevelByclass(class_TYPE_WIZARD, oPC) == TRUE)

    {
     iAbilityType = ABILITY_INTELLIGENCE;
    }

    if (GetLevelByclass(class_TYPE_SORCERER, oPC) == TRUE)

    {
     iAbilityType = ABILITY_CHARISMA;
    }...

 


Note; with the way it is written, If the PC is nither a Wizard or a Sorcerer you will still end up checking strength.  Also if the PC has one level of bard and 20 levels of wizard you wuold end up using Charaisma not intelegence.  

#11
Fester Pot

Fester Pot
  • Members
  • 1 391 messages
If the player is not a Wizard or a Sorcerer, then they should not be playing any of my modules, which are Wizard and Sorcerer only. I will not cater to players who can't read module requirements. ;)

FP!

Modifié par Fester Pot, 06 novembre 2011 - 03:59 .


#12
WhiZard

WhiZard
  • Members
  • 1 204 messages

Fester Pot wrote...

    if (GetLevelByclass(class_TYPE_SORCERER, oPC) == TRUE)


No, this will only work if the player has exactly one level in sorcerer (same can be said for the wizard class check).
TRUE == 1.  "==" in this case would be returning FALSE if GetLevelByclass != 1 (1 being the value of TRUE).

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.

#13
Lightfoot8

Lightfoot8
  • Members
  • 2 535 messages
Good catch WhiZard.

So,
...
iAbilityType = ABILITY_INTELLIGENCE;
if (GetLevelByclass(class_TYPE_SORCERER, oPC)) iAbilityType = ABILITY_CHARISMA;
...

would cover all of your bases.

#14
Fester Pot

Fester Pot
  • Members
  • 1 391 messages
Great! Thanks for catching that! Will modify and go with that then.

FP!

#15
Rolo Kipp

Rolo Kipp
  • Members
  • 2 788 messages
<holding a large lens...>

Lightfoot8 wrote...
...
iAbilityType = ABILITY_INTELLIGENCE;
if (GetLevelByclass(class_TYPE_SORCERER, oPC)) iAbilityType = ABILITY_CHARISMA;
...
would cover all of your bases.

Unless the PC had 1 level in sorcerer and 19 levels in wizard? *Any* level in Sorc will change iAbilityType to CHA, regardless of major class.

Wouldn't a compare levels check be good in there so the weak ability isn't chosen over the strong? Is that what you were getting at with:

Note; with the way it is written, If the PC is nither a Wizard or a Sorcerer you will still end up checking strength.  Also if the PC has one level of bard and 20 levels of wizard you wuold end up using Charaisma not intelegence.  

<...to his eye>

Modifié par Rolo Kipp, 07 novembre 2011 - 01:33 .


#16
Lightfoot8

Lightfoot8
  • Members
  • 2 535 messages
@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.

#17
WhiZard

WhiZard
  • Members
  • 1 204 messages

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

#18
Shadooow

Shadooow
  • Members
  • 4 465 messages
Or just take the highest casting ability like bioware did with their epic spells.

#19
Rolo Kipp

Rolo Kipp
  • Members
  • 2 788 messages
<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>

#20
Rolo Kipp

Rolo Kipp
  • Members
  • 2 788 messages
<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>

#21
Rolo Kipp

Rolo Kipp
  • Members
  • 2 788 messages
<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>

#22
WhiZard

WhiZard
  • Members
  • 1 204 messages

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.

#23
Shadooow

Shadooow
  • Members
  • 4 465 messages

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.

#24
WhiZard

WhiZard
  • Members
  • 1 204 messages

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 .


#25
WhiZard

WhiZard
  • Members
  • 1 204 messages
Double post

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