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

Legacy_WhiZard

  • Hero Member
  • *****
  • Posts: 2149
  • Karma: +0/-0
Help understanding a script.
« Reply #30 on: November 10, 2011, 02:54:34 am »


               

ShaDoOoW wrote...

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.

I have gone through all four user types and user type 2 and 4 have the -1 return value.  This value only pertains to its associated script when the "caster" is the caster of the spell.  If you enter an AoE after using a user type 2 or 4 the -1 value will not be reflected.  This looks like another peculiarity like AoEs using the "dispel caster level" for their caster level.

its not about InnateLevel which is for other special abilities lesser than 10 and the ResistSpell still returns -1.

the innate level does have significance in other circumstances.


EDIT: User type 4, now has significance but only for the caster being the "caster" same constraint applies to user type 2.
               
               

               


                     Modifié par WhiZard, 10 novembre 2011 - 03:16 .
                     
                  


            

Legacy_Shadooow

  • Hero Member
  • *****
  • Posts: 7698
  • Karma: +0/-0
Help understanding a script.
« Reply #31 on: November 10, 2011, 03:04:11 am »


               fine, thats something what I havent tested this time '<img'> good job
               
               

               
            

Legacy_henesua

  • Hero Member
  • *****
  • Posts: 6519
  • Karma: +0/-0
Help understanding a script.
« Reply #32 on: November 10, 2011, 03:03:33 pm »


               

Lightfoot8 wrote...
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 believe this is the function that you are looking for:


// Returns the class that the spellcaster cast the
// spell as.
// - Returns class_TYPE_INVALID if the caster has
// no valid class (placeables, etc...)
int GetLastSpellCastclass()

This function will return a class value when the character casts a spell. If the spell is activated by a feat, it will return class_TYPE_INVALID.

-edit-
just noticed that the forum does not like the word class in all caps, and puts it in all lower case. weird.
               
               

               


                     Modifié par henesua, 10 novembre 2011 - 03:06 .
                     
                  


            

Legacy_Shadooow

  • Hero Member
  • *****
  • Posts: 7698
  • Karma: +0/-0
Help understanding a script.
« Reply #33 on: November 10, 2011, 03:33:42 pm »


               henesua: Problem is that this function, same as all other spell related function doesn't work properly outside of spellscript which is this case. The script cast fake Acid Splash spell. But the actual damage and DC is computed before this action is done. Thats the reason to do such workaround in the first place.

BUT, is a question why it is done this way, the OP didnt provided enough inromations as whats the purpose etc. but I guess it could be done via simply ActionCastSpell with bCheat = TRUE. It has one downside and that is the metamagic doesnt work and the caster level in such case is (InnateLevel*2)-1 min 10 (or something like that, WhiZard will correct me if Im wrong). But in this case of Acid Splash or low lvl environment in general, it shouldn't matter (unless the acid splash was only an example). If it would matter, then thats where my patch comes handy - it allows to override caster level, DC and metamagic used (provided the spell in question uses script with new spell engine, if there is modified script in module/hak it wont work ).

Also I noticed that even fake spell (once is cast) setup some spell informations. So i the worst case the actual spell script could be fires after the fakespell action is done using actiondocommand. However I dont know for sure which spell informations are set this way, but definitely not all of them.
               
               

               
            

Legacy_henesua

  • Hero Member
  • *****
  • Posts: 6519
  • Karma: +0/-0
Help understanding a script.
« Reply #34 on: November 10, 2011, 03:54:03 pm »


               Hmmm... I'm not fully conversant in how these things work. I've been using that function in a custom spellhook. I guess that counts as a spell script because it is called by the spell script?

Anyway, thanks. Good information as usual.
               
               

               
            

Legacy_WhiZard

  • Hero Member
  • *****
  • Posts: 2149
  • Karma: +0/-0
Help understanding a script.
« Reply #35 on: November 10, 2011, 06:22:16 pm »


               

ShaDoOoW wrote...
 and the caster level in such case is (InnateLevel*2)-1 min 10 (or something like that, WhiZard will correct me if Im wrong).

You are right on.

However I dont know for sure which spell informations are set this way, but definitely not all of them.

The big one not included is the Spell ID link for the script.  Thus the effects it creates are not labeled as Spell effects (GetHasSpellEffect() and GetEffectSpellID() won't work properly)  and these effects can often stack from recasting.
               
               

               
            

Legacy_Shadooow

  • Hero Member
  • *****
  • Posts: 7698
  • Karma: +0/-0
Help understanding a script.
« Reply #36 on: November 19, 2011, 05:59:25 am »


               

WhiZard wrote...

ShaDoOoW wrote...

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.

I have gone through all four user types and user type 2 and 4 have the -1 return value.  This value only pertains to its associated script when the "caster" is the caster of the spell.  If you enter an AoE after using a user type 2 or 4 the -1 value will not be reflected.  This looks like another peculiarity like AoEs using the "dispel caster level" for their caster level.

its not about InnateLevel which is for other special abilities lesser than 10 and the ResistSpell still returns -1.

the innate level does have significance in other circumstances.


EDIT: User type 4, now has significance but only for the caster being the "caster" same constraint applies to user type 2.


Did you run any more tests? I found out that the spell immunity is still checked even if the UserType is 2. But only spell immunity part of ResistSpell check. Didnt tried higher values yet.
               
               

               
            

Legacy_WhiZard

  • Hero Member
  • *****
  • Posts: 2149
  • Karma: +0/-0
Help understanding a script.
« Reply #37 on: November 19, 2011, 07:22:00 am »


               

ShaDoOoW wrote...
Did you run any more tests? I found out that the spell immunity is still checked even if the UserType is 2. But only spell immunity part of ResistSpell check. Didnt tried higher values yet.


Can't quite tell the context.

On  -1 spells then, no I haven't pursued beyond verifying the -1s exist only on user type 2 and 4 and do not carry over to AoEs.

For AoEs in general, the user type doesn't matter. Only the last cast spell feat flag (not user type 3, but whether or not it was used as a feat), the last cast spell properties (Spell ID and school) and the "dispelability caster level" seem to have significance.
               
               

               
            

Legacy_Shadooow

  • Hero Member
  • *****
  • Posts: 7698
  • Karma: +0/-0
Help understanding a script.
« Reply #38 on: November 19, 2011, 07:34:33 am »


               Yea, right about AOEs, I tried the same solution for "immunity feedback workaroud" for BBoD as I did for petrification and ResistSpell returned 0, although I granted the immunity to the last spell cast.
               
               

               


                     Modifié par ShaDoOoW, 19 novembre 2011 - 07:34 .
                     
                  


            

Legacy_FunkySwerve

  • Hero Member
  • *****
  • Posts: 2325
  • Karma: +0/-0
Help understanding a script.
« Reply #39 on: November 19, 2011, 07:01:28 pm »


               Our custom AOE scripts have workarounds for those issues - you set the needed info on the aoe at time of casting, and check it instead of calling on the buggy functions. Code is acaos'. You'll have to disregard references to Herald of Storms - it's one of our quasis. Likewise, the #pragma stuff is for Skywing's compiler, which won't allow includes to contain void mains otherwise. I'll post the include first, then the acid fog spell:

ac_aoeper_inc

#include "hg_inc"
#include "ac_spell_inc"

int GetIsHeraldAoE(object oAoE) {
    string sTag = GetTag(oAoE);
    if (sTag == "VFX_PER_FOGFREEZE"     ||
        sTag == "VFX_AOE_CONSECRATE_20" ||
        sTag == "VFX_PER_FOGACID"       ||
        sTag == "VFX_PER_FOGKILL"       ||
        sTag == "VFX_PER_FOGMIND"       ||
        sTag == "VFX_PER_FOGSTINK")
        return TRUE;

    return FALSE;
}

struct SpellInfo GetPersistentAoESpellInfo ();
#pragma default_function(GetPersistentAoESpellInfo)
int GetPersistentAoELimit (struct SpellInfo si);
#pragma default_function(GetPersistentAoELimit)
int GetPersistentAoEEffect (struct SpellInfo si);
#pragma default_function(GetPersistentAoEEffect)
string GetPersistentAoETag (struct SpellInfo si);
#pragma default_function(GetPersistentAoETag)
string GetPersistentAoEName (struct SpellInfo si);
#pragma default_function(GetPersistentAoEName)
int GetPersistentAoETargetMask (struct SpellInfo si);
#pragma default_function(GetPersistentAoETargetMask)
int GetPersistentAoETargetType (struct SpellInfo si);
#pragma default_function(GetPersistentAoETargetType)

float GetPersistentAoEDuration (struct SpellInfo si);
#pragma default_function(GetPersistentAoEDuration)

effect GetPersistentAoEImpactEffect (struct SpellInfo si);
#pragma default_function(GetPersistentAoEImpactEffect)
effect GetPersistentAoEDurationEffect (struct SpellInfo si);
#pragma default_function(GetPersistentAoEDurationEffect)
effect GetPersistentAoEVisualEffect (struct SpellInfo si);
#pragma default_function(GetPersistentAoEVisualEffect)

void ApplyAoEEffect (struct SpellInfo si, object oAoE, object oTarget, effect eEff, effect eDur, effect eVis);
#pragma default_function(ApplyAoEEffect)

float GetPersistentAoERemaining (object oAoE) {
    int nRemaining = GetLocalInt(oAoE, "AoEExpires") - GetLocalInt(GetModule(), "uptime");

    return IntToFloat(nRemaining < 1 ? 1 : nRemaining);
}


void DoAoEHeartbeat (struct SpellInfo si, object oAoE, effect eEff, effect eDur, effect eVis) {
    int bDestroy = FALSE, bAllPCs = FALSE;

    if (!GetIsObjectValid(oAoE))
        return;


    /* Storm of Vengeance doesn't destroy properly sometimes */
    if (GetPersistentAoEEffect(si) == AOE_PER_STORM) {
        if (si.id == SPELL_STORM_OF_VENGEANCE && GetLocalInt(GetArea(oAoE), "Area_Underwater"))
            bAllPCs = TRUE;

        if (GetLocalInt(GetModule(), "uptime") > GetLocalInt(oAoE, "AoEExpires"))
            bDestroy = TRUE;
    }

    if (bDestroy                     ||
        !GetIsObjectValid(si.caster) ||
        GetIsDead(si.caster)         ||
        GetArea(si.caster) != si.area) {

        SetPlotFlag(oAoE, FALSE);
        DestroyObject(oAoE);
        return;
    }

    DelayCommand(6.0, DoAoEHeartbeat(si, oAoE, eEff, eDur, eVis));
    AddLocalInt(oAoE, "AoERounds", 1);

    if (!LineOfSightObject(oAoE, si.caster))//PAoEs have no effect when caster out of LoS
        return;


    si.target = oAoE;
    int nMask = GetPersistentAoETargetMask(si);
    int nType = GetPersistentAoETargetType(si);

    for (si.target = GetFirstInPersistentObject(oAoE, nMask);
         GetIsObjectValid(si.target);
         si.target = GetNextInPersistentObject(oAoE, nMask)) {

        if (GetIsSpellTarget(si, si.target, nType) || (bAllPCs && GetIsPC(si.target))) {
            SignalEvent(si.target, EventSpellCastAt(si.caster, si.id));

            AssignCommand(si.caster, DelayCommand(GetRandomDelay(0.5, 4.5), ApplyAoEEffect(si, oAoE, si.target, eEff, eDur, eVis)));
        }
    }
}

void StartAoEHeartbeat (struct SpellInfo si, string sTag, effect eEff, effect eDur, effect eVis, int nUntil) {
    int nCount = 1;
    object oLoc, oAoE;

    do {
        oLoc = GetNearestObjectToLocation(OBJECT_TYPE_ALL, si.loc, nCount++);
    } while (GetTag(oLoc) == sTag);

    nCount = 1;
    oAoE = GetNearestObjectByTag(sTag, oLoc);

    while (GetIsObjectValid(oAoE)) {
        if (GetAreaOfEffectCreator(oAoE) == si.caster && !GetLocalInt(oAoE, "AoEHeartbeat")) {

            SetLocalInt(oAoE, "AoEHeartbeat", 1);
            SetLocalInt(oAoE, "AoEExpires", nUntil);
            SetLocalInt(oAoE, "AoESP", si.sp);

            DelayCommand(0.0, DoAoEHeartbeat(si, oAoE, eEff, eDur, eVis));
            return;
        }

        oAoE = GetNearestObjectByTag(sTag, oLoc, ++nCount);
    }
}

void main () {
    struct SpellInfo si = GetPersistentAoESpellInfo();
    if (si.id < 0)
        return;

    float fDur  = GetPersistentAoEDuration(si);
    string sTag = GetPersistentAoETag(si);
    effect eAoE = EffectAreaOfEffect(GetPersistentAoEEffect(si),
        (si.id == SPELL_GREASE ? "nw_s0_greasea" : "****"), "****", "****");


    int nLimit = GetPersistentAoELimit(si);

    if (nLimit > 0) {
        int nFound = 0, nCount = 1;
        object oOther, oCreator, oArea = GetArea(si.caster);

        while (GetIsObjectValid(oOther = GetNearestObjectByTag(sTag, si.caster, nCount++))) {
            oCreator = GetAreaOfEffectCreator(oOther);
            if (oCreator == oArea                                       ||
                GetLocalInt(oOther, "NoAoEDispel"))
                continue;

            if (GetIsPC(si.caster) && GetIsPC(oCreator)) {
                if (GetIsHeraldAoE(oOther)) {
                    if (!GetIsQuasiclass(QUASIclass_HERALD_OF_STORMS, oCreator))
                        nFound++;
                } else
                    nFound++;
            } else if (GetFactionEqual(si.caster, oCreator)) {
                nFound++;
            }

            if (nFound >= nLimit) {
                SetPlotFlag(oOther, FALSE);
                DestroyObject(oOther);

                if (nFound == nLimit)
                    FloatingTextStringOnCreature("To prevent lag, only " +
                        IntToString(nLimit) + " " + GetPersistentAoEName(si) +
                        " spell" + (nLimit == 1 ? "" : "s") + " may exist in an area at the same time.", si.caster);
            }
        }
    } else if (nLimit == -1) {
        object oAoE, oCreator, oArea = GetArea(si.caster);

        for (oAoE = GetFirstObjectInArea(oArea); GetIsObjectValid(oAoE); oAoE = GetNextObjectInArea(oArea)) {

            oCreator = GetAreaOfEffectCreator(oAoE);
            if (GetObjectType(oAoE) != OBJECT_TYPE_AREA_OF_EFFECT ||
                oCreator != si.caster)
                continue;

            if (GetIsQuasiclass(QUASIclass_HERALD_OF_STORMS, oCreator) && //heralds ignore herald spells in this check - that limit handled in -2
                GetIsHeraldAoE(oAoE))
                continue;

            if (FindSubString(" VFX_PER_FOGACID VFX_PER_FOGFIRE VFX_PER_FOGFREEZE VFX_PER_STORM VFX_PER_RAINFIRE VFX_PER_RAINFREEZE VFX_AOE_CONSECRATE_20 ",
                              " " + GetTag(oAoE) + " ") >= 0) {
                SetPlotFlag(oAoE, FALSE);
                DestroyObject(oAoE);

                FloatingTextStringOnCreature("Only one area of effect damage field may exist per caster in an area at the same time.", si.caster);
            }
        }
    } else if (nLimit == -2) {
        object oAoE, oArea = GetArea(si.caster);
        int nFound;
        for (oAoE = GetFirstObjectInArea(oArea); GetIsObjectValid(oAoE); oAoE = GetNextObjectInArea(oArea)) {
            if (GetObjectType(oAoE) != OBJECT_TYPE_AREA_OF_EFFECT ||
                !GetIsQuasiclass(QUASIclass_HERALD_OF_STORMS, GetAreaOfEffectCreator(oAoE)))
                continue;

            if (FindSubString(" VFX_PER_FOGACID VFX_PER_FOGSTINK VFX_PER_FOGKILL VFX_AOE_CONSECRATE_20 VFX_PER_FOGFREEZE VFX_PER_FOGMIND ",
                              " " + GetTag(oAoE) + " ") >= 0) {
                nFound++;
                if (nFound >= 2) {
                    SetPlotFlag(oAoE, FALSE);
                    DestroyObject(oAoE);

                    if (nFound == 2)
                        FloatingTextStringOnCreature("Only two herald of storms clouds may exist in an area at the same time.", si.caster);
                }
            }
        }
    }


    effect eEff = GetPersistentAoEImpactEffect(si);
    effect eDur = GetPersistentAoEDurationEffect(si);
    effect eVis = GetPersistentAoEVisualEffect(si);


    AssignCommand(si.area, DelayCommand(2.0, StartAoEHeartbeat(si, sTag, eEff, eDur, eVis,
        GetLocalInt(GetModule(), "uptime") + FloatToInt(fDur))));

    ApplyEffectAtLocation(DURATION_TYPE_TEMPORARY, eAoE, si.loc, fDur);
}




nw_s0_acidfog

#include "ac_aoeper_inc"


struct SpellInfo GetPersistentAoESpellInfo ()        { return GetSpellInfo(); }

int GetPersistentAoELimit (struct SpellInfo si)      {
    if (GetIsQuasiSpell(si, QUASIclass_HERALD_OF_STORMS))
        return -2;
    return -1;
}
int GetPersistentAoEEffect (struct SpellInfo si)     { return AOE_PER_FOGACID; }
string GetPersistentAoETag (struct SpellInfo si)     { return "VFX_PER_FOGACID"; }
string GetPersistentAoEName (struct SpellInfo si)    { return "Acid Fog"; }
int GetPersistentAoETargetMask (struct SpellInfo si) { return OBJECT_TYPE_CREATURE; }
int GetPersistentAoETargetType (struct SpellInfo si) { return TARGET_TYPE_DEFAULT; }


float GetPersistentAoEDuration (struct SpellInfo si) {
    return MetaDuration(si, si.clevel / 2, DURATION_IN_ROUNDS);
}

effect GetPersistentAoEImpactEffect (struct SpellInfo si) {
    effect eEff;
    return eEff;
}

effect GetPersistentAoEDurationEffect (struct SpellInfo si) {
    effect eDur;

    if (GetIsQuasiSpell(si, QUASIclass_HERALD_OF_STORMS))
        eDur = EffectDamageIncrease(1);
    return eDur;
}

effect GetPersistentAoEVisualEffect (struct SpellInfo si) {
    ApplyVisualAtLocation(VFX_FNF_GAS_EXPLOSION_ACID, si.loc);

    return EffectVisualEffect(VFX_FNF_GAS_EXPLOSION_ACID);
}


void ApplyAoEEffect (struct SpellInfo si, object oAoE, object oTarget, effect eEff, effect eDur, effect eVis) {
    if (!GetSpellResisted(si, oTarget, 0.0, 2)) {
        int nDamage, nDice = si.clevel, nEffType = GetEffectType(eDur);
        int nDamType = DAMAGE_TYPE_ACID, nSaveType = SAVING_THROW_TYPE_ACID;

        if (nDice < 1)
            nDice = 1;

        nDamage = MetaPower(si, nDice, 6);
        nDamage = GetEvasionAdjustedDamage(nDamage, oTarget, si.dc, nSaveType|SAVING_THROW_FLAG_SPELL, si.caster);

        if (nDamage > 0) {
            if (nEffType == EFFECT_TYPE_DAMAGE_IMMUNITY_DECREASE) {
                if (!GetHasSpecificEffect(eDur, oTarget))
                    ApplyEffectToObject(DURATION_TYPE_PERMANENT, eDur, oTarget);

                eEff = EffectDamage(nDamage / 2, nDamType);
                DelayCommand(0.1, ApplyEffectToObject(DURATION_TYPE_INSTANT, eEff, oTarget));

                eEff = EffectDamage(nDamage / 2, DAMAGE_TYPE_MAGICAL);
                DelayCommand(0.1, ApplyEffectToObject(DURATION_TYPE_INSTANT, eEff, oTarget));
            } else if (nEffType == EFFECT_TYPE_DAMAGE_INCREASE) {
                if (GetTrueDamageImmunity(oTarget, nDamType) < 100) {
                    int nDecrease = 25 - GetTotalDamageImmunityDecrease(oTarget, nDamType);

                    if (nDecrease > 5)
                        nDecrease = 5;

                    if (nDecrease > 0) {
                        eEff = EffectDamageImmunityDecrease(nDamType, nDecrease);
                        ApplyEffectToObject(DURATION_TYPE_PERMANENT, eEff, oTarget);
                    }
                }

                eEff = EffectDamage(nDamage, nDamType);
                ApplyEffectToObject(DURATION_TYPE_INSTANT, eEff, oTarget);
            } else {
                eEff = EffectDamage(nDamage, nDamType);
                ApplyEffectToObject(DURATION_TYPE_INSTANT, eEff, oTarget);
            }

            ApplyEffectToObject(DURATION_TYPE_INSTANT, eVis, oTarget);
        }
    }
}


Funky
               
               

               
            

Legacy_Shadooow

  • Hero Member
  • *****
  • Posts: 7698
  • Karma: +0/-0
Help understanding a script.
« Reply #40 on: November 21, 2011, 03:32:59 am »


               I can't see how you solved the main issue we are talking about, ResistSpell? I do use similar workaround like you and I have correct values stored as local int on AOE, but since ResistSpell is hardcoded there is no way to pass them inside this function. I tried to make a fake ResistSpell function that would behave like the default one, but I dropped that approach due to the technical limitations.
               
               

               
            

Legacy_FunkySwerve

  • Hero Member
  • *****
  • Posts: 2325
  • Karma: +0/-0
Help understanding a script.
« Reply #41 on: November 23, 2011, 04:36:28 am »


               Sorry, it's in GetSpellResisted, in our spells include - should've pasted it as well. We bypass the issue by passing the the original sp value in the si struct. Here's the function:


int GetSpellResisted (struct SpellInfo si, object oTarget=OBJECT_INVALID, float fDelay=0.0, int bSROnly=FALSE) {
    int nSR = 0, nResisted = 0, nRoll = 0;

    if (!GetIsObjectValid(oTarget))
        oTarget = si.target;
    if (!GetIsObjectValid(oTarget))
        return 0;

    if (GetObjectType(oTarget) == OBJECT_TYPE_CREATURE)
        nSR = GetSpellResistance(oTarget);
    else
        nSR = GetLocalInt(oTarget, "SR");


    if (nSR > 0 && GetHasSpellImmunity(SPELL_SPELL_RESISTANCE, oTarget)) {
        nSR -= GetLocalInt(oTarget, "TauntResult");
        if (nSR < 1)
            nSR = 1;
    }


    if (nSR > 0 && si.sp >= 0 && !GetFactionEqual(si.caster, oTarget)) {
        nRoll = d20(1);

        if (si.sp + nRoll < nSR)
            nResisted = 1;
    }

    if (nResisted == 0) {
        if (bSROnly) {
            if (bSROnly == 2 && GetHasSpellImmunity(si.id, oTarget))
                nResisted = 2;
        } else {
            switch (ResistSpell(si.caster, oTarget)) {
                case 2:  /* globe or spell immunity */
                    nResisted = 2;
                    break;
                case 3:  /* spell mantle */
                    if (si.sp >= 0)
                        nResisted = 3;
                    break;
            }
        }
    }

    if (!nResisted) {
        if (nRoll > 0)
            SendSpellResistanceMessage(si.caster, oTarget, nRoll, si.sp, nSR, fDelay);

        return 0;
    }

    if (GetObjectType(oTarget) == OBJECT_TYPE_CREATURE) {
        effect eVis;

        switch (nResisted) {
            case 2:
                nSR  = -2;
                eVis = EffectVisualEffect(VFX_IMP_GLOBE_USE);
                break;
            case 3:
                nSR  = -3;
                eVis = EffectVisualEffect(VFX_IMP_SPELL_MANTLE_USE);
                break;
            default:
                eVis = EffectVisualEffect(VFX_IMP_MAGIC_RESISTANCE_USE);
                break;
        }

        DelayCommand(fDelay, ApplyEffectToObject(DURATION_TYPE_INSTANT, eVis, oTarget));
    }

    if (nRoll > 0 || nSR < -1)
        SendSpellResistanceMessage(si.caster, oTarget, nRoll, si.sp, nSR, fDelay);

    return nResisted;
}

Funky
               
               

               
            

Legacy_Shadooow

  • Hero Member
  • *****
  • Posts: 7698
  • Karma: +0/-0
Help understanding a script.
« Reply #42 on: November 23, 2011, 06:38:43 am »


               

[code=auto:0]if (nResisted == 0) {
        if (bSROnly) {
            if (bSROnly == 2 && GetHasSpellImmunity(si.id, oTarget))
                nResisted = 2;
        } else {
            switch (ResistSpell(si.caster, oTarget)) {
                case 2:  /* globe or spell immunity */
                    nResisted = 2;
                    break;
                case 3:  /* spell mantle */
                    if (si.sp >= 0)
                        nResisted = 3;
                    break;
            }
        }
    }

See this is it. I ended up with the same issue so I abadoned that aproach for now. If the target fail in fake spell resistance roll and neither is immune to the correct AOE spell, then you call the ResistSpell function which is hardcoded and which uses the wrong spell id of something that target could be immune of.

Also the ResistSpell does SR check again, so in case that the fake SR check failed due to the fact that you have changed the caster level downstairs, second SR check will be probably successful.

True, your solution handles the main issue which is fact that AOE spell can bypass target immunities. But caster still can make the AOE spell to get immunity himself.
               
               

               


                     Modifié par ShaDoOoW, 23 novembre 2011 - 01:07 .
                     
                  


            

Legacy_FunkySwerve

  • Hero Member
  • *****
  • Posts: 2325
  • Karma: +0/-0
Help understanding a script.
« Reply #43 on: November 23, 2011, 08:05:48 am »


               

ShaDoOoW wrote...

See this is it. I ended up with the same issue so I abadoned that aproach for now. If the target fail in fake spell resistance roll and neither is immune to the correct AOE spell, then you call the ResistSpell function which is hardcoded and which uses the wrong spell id of something that target could be immune of.

Wrong. Read it again. ResistSpell is only called to drain mantles.

Also the ResistSpell does SR check again, so in case that the fake SR check failed due to the fact that you have changed the caster level downstairs, second SR check will be probably successful.

You need to check the returns on the ResistSpell function and then read the script again.

Funky
               
               

               
            

Legacy_Shadooow

  • Hero Member
  • *****
  • Posts: 7698
  • Karma: +0/-0
Help understanding a script.
« Reply #44 on: November 23, 2011, 08:35:00 am »


               I assumed this function is called from AOE spell like incendiary cloud with oTarget == si.Caster and bSROnly = FALSE

Lets say that last spell cast was finger of death.

si.id = incendiary cloud
si.sp = caster level of lets say 20

real id = FoD
real caster level = 20



int GetSpellResisted (struct SpellInfo si, object oTarget=OBJECT_INVALID, float fDelay=0.0, int bSROnly=FALSE) {
    int nSR = 0, nResisted = 0, nRoll = 0;

    if (!GetIsObjectValid(oTarget))
        oTarget = si.target;
    if (!GetIsObjectValid(oTarget))
        return 0;

    if (GetObjectType(oTarget) == OBJECT_TYPE_CREATURE)
        nSR = GetSpellResistance(oTarget); <<nSR = lets say 30
    else
        nSR = GetLocalInt(oTarget, "SR");


    if (nSR > 0 && GetHasSpellImmunity(SPELL_SPELL_RESISTANCE, oTarget)) {
        nSR -= GetLocalInt(oTarget, "TauntResult");
        if (nSR < 1)
            nSR = 1;
    }


    if (nSR > 0 && si.sp >= 0 && !GetFactionEqual(si.caster, oTarget)) { <<FALSE
        nRoll = d20(1);

        if (si.sp + nRoll < nSR)
            nResisted = 1;
    }

    if (nResisted == 0) { << TRUE
        if (bSROnly) { << FALSE
            if (bSROnly == 2 && GetHasSpellImmunity(si.id, oTarget))
                nResisted = 2;
        } else { << TRUE
            switch (ResistSpell(si.caster, oTarget)) { << ResistSpell with real id and caster level
                case 2:  /* globe or spell immunity */ << TRUE caster doesnt have mantle but have shadow shield
                    nResisted = 2;
                    break;
                case 3:  /* spell mantle */
                    if (si.sp >= 0)
                        nResisted = 3;
                    break;
            }
        }
    }

    if (!nResisted) {
        if (nRoll > 0)
            SendSpellResistanceMessage(si.caster, oTarget, nRoll, si.sp, nSR, fDelay);

        return 0;
    }

    if (GetObjectType(oTarget) == OBJECT_TYPE_CREATURE) {
        effect eVis;

        switch (nResisted) {
            case 2:
                nSR  = -2;
                eVis = EffectVisualEffect(VFX_IMP_GLOBE_USE);
                break;
            case 3:
                nSR  = -3;
                eVis = EffectVisualEffect(VFX_IMP_SPELL_MANTLE_USE);
                break;
            default:
                eVis = EffectVisualEffect(VFX_IMP_MAGIC_RESISTANCE_USE);
                break;
        }

        DelayCommand(fDelay, ApplyEffectToObject(DURATION_TYPE_INSTANT, eVis, oTarget));
    }

    if (nRoll > 0 || nSR < -1)
        SendSpellResistanceMessage(si.caster, oTarget, nRoll, si.sp, nSR, fDelay);

    return nResisted;
}
               
               

               


                     Modifié par ShaDoOoW, 23 novembre 2011 - 09:19 .