Plugin NetBots Buff Stacking is Broken

rlane187

Member
Joined
Dec 14, 2010
Messages
30
Reaction score
0
Points
6
NetBots thinks that Hand of Conviction or Conviction blocks any spells from the shileding line (Wunshi's Focusing, Armor of the Pious, all int caster shielding spells, etc.). Consequently, the buffs on my team all depend on who cast first, the cleric or the the shielding caster.

Can we fix stacking issues in NetBots please? If you do not have the time or inclination and you wanted to PM me the portion of the source that covers spell stacking, I would be glad to unwind the issue myself and send it back to you.
 
This is the relative code. If you don't have time, I can sometime Monday or Tuesday at best.


htw


Code:
// ***************************************************************************
// Function:    LargerEffectTest
// Description: Return boolean true if the spell effect is to be ignored
//              for stacking purposes
// ***************************************************************************
BOOL NBLargerEffectTest(PSPELL aSpell, PSPELL bSpell, int i)
{
    LONG aAttrib = GetSpellNumEffects(aSpell) > i ? GetSpellAttrib(aSpell, i) : 254;
    LONG bAttrib = GetSpellNumEffects(bSpell) > i ? GetSpellAttrib(bSpell, i) : 254;
    if (aAttrib == bAttrib
        && (aAttrib == 0        // HP +/-: heals/regen/dd
            || aAttrib == 1        // Ac Mod
            || aAttrib == 55    // Add Effect: Absorb Damage
            || aAttrib == 69    // Max HP Mod
            || aAttrib == 79    // HP Mod
            || aAttrib == 114    // Aggro Multiplier
            || aAttrib == 127))    // Spell Haste
        return abs(GetSpellBase(aSpell, i)) >= abs(GetSpellBase(bSpell, i));
    return false;
}

// ***************************************************************************
// Function:    TriggeringEffectSpell
// Description: Return boolean true if the spell effect is to be ignored
//              for stacking purposes
// ***************************************************************************
BOOL NBTriggeringEffectSpell(PSPELL aSpell, int i)
{
    LONG aAttrib = GetSpellNumEffects(aSpell) > i ? GetSpellAttrib(aSpell, i) : 254;
    return (aAttrib == 85        // Add Proc
        || aAttrib == 374     // Trigger Spell
        || aAttrib == 419     // Add Proc
        || aAttrib == 442     // Trigger Effect
        || aAttrib == 443     // Trigger Effect
        || aAttrib == 453     // Trigger Effect
        || aAttrib == 454     // Trigger Effect
        || aAttrib == 475     // Trigger Spell Non-Item
        || aAttrib == 481);     // Trigger Spell
}

// ***************************************************************************
// Function:    DurationWindowTest
// Description: Return boolean true if the spell effect is to be ignored
//              for stacking purposes
// ***************************************************************************
BOOL NBDurationWindowTest(PSPELL aSpell, PSPELL bSpell, int i)
{
    LONG aAttrib = GetSpellNumEffects(aSpell) > i ? GetSpellAttrib(aSpell, i) : 254;
    LONG bAttrib = GetSpellNumEffects(bSpell) > i ? GetSpellAttrib(bSpell, i) : 254;
    if ((aSpell->SpellType != 1 && aSpell->SpellType != 2) || (bSpell->SpellType != 1 && bSpell->SpellType != 2) || (aSpell->DurationWindow == bSpell->DurationWindow))
        return false;
    return (!(aAttrib == bAttrib &&
        (aAttrib == 2        // Attack Mod
            || aAttrib == 162)));     // Mitigate Melee Damage
}

// ***************************************************************************
// Function:    SpellEffectTest
// Description: Return boolean true if the spell effect is to be ignored
//              for stacking purposes
// ***************************************************************************
BOOL NBSpellEffectTest(PSPELL aSpell, PSPELL bSpell, int i, BOOL bIgnoreTriggeringEffects, BOOL bIgnoreCrossDuration)
{
    LONG aAttrib = GetSpellNumEffects(aSpell) > i ? GetSpellAttrib(aSpell, i) : 254;
    LONG bAttrib = GetSpellNumEffects(bSpell) > i ? GetSpellAttrib(bSpell, i) : 254;
    return ((aAttrib == 57 || bAttrib == 57)        // Levitate
        || (aAttrib == 134 || bAttrib == 134)        // Limit: Max Level
        || (aAttrib == 135 || bAttrib == 135)        // Limit: Resist
        || (aAttrib == 136 || bAttrib == 136)        // Limit: Target
        || (aAttrib == 137 || bAttrib == 137)        // Limit: Effect
        || (aAttrib == 138 || bAttrib == 138)        // Limit: SpellType
        || (aAttrib == 139 || bAttrib == 139)        // Limit: Spell
        || (aAttrib == 140 || bAttrib == 140)        // Limit: Min Duraction
        || (aAttrib == 141 || bAttrib == 141)        // Limit: Instant
        || (aAttrib == 142 || bAttrib == 142)        // Limit: Min Level
        || (aAttrib == 143 || bAttrib == 143)        // Limit: Min Cast Time
        || (aAttrib == 144 || bAttrib == 144)        // Limit: Max Cast Time
        || (aAttrib == 254 || bAttrib == 254)        // Placeholder
        || (aAttrib == 311 || bAttrib == 311)        // Limit: Combat Skills not Allowed
        || (aAttrib == 339 || bAttrib == 339)        // Trigger DoT on cast
        || (aAttrib == 340 || bAttrib == 340)        // Trigger DD on cast
        || (aAttrib == 348 || bAttrib == 348)        // Limit: Min Mana
        || (aAttrib == 385 || bAttrib == 385)        // Limit: SpellGroup
        || (aAttrib == 391 || bAttrib == 391)        // Limit: Max Mana
        || (aAttrib == 403 || bAttrib == 403)        // Limit: SpellClass
        || (aAttrib == 404 || bAttrib == 404)        // Limit: SpellSubclass
        || (aAttrib == 411 || bAttrib == 411)        // Limit: PlayerClass
        || (aAttrib == 412 || bAttrib == 412)        // Limit: Race
        || (aAttrib == 414 || bAttrib == 414)        // Limit: CastingSkill
        || (aAttrib == 415 || bAttrib == 415)        // Limit: Item Class
        || (aAttrib == 420 || bAttrib == 420)        // Limit: Use
        || (aAttrib == 421 || bAttrib == 421)        // Limit: Use Amt
        || (aAttrib == 422 || bAttrib == 422)        // Limit: Use Min
        || (aAttrib == 423 || bAttrib == 423)        // Limit: Use Type
        || (aAttrib == 428 || bAttrib == 428)        // Limit: Skill
        || (aAttrib == 442 || bAttrib == 442)        // Trigger Effect
        || (aAttrib == 443 || bAttrib == 443)        // Trigger Effect
        || (aAttrib == 453 || bAttrib == 453)        // Trigger Effect
        || (aAttrib == 454 || bAttrib == 454)        // Trigger Effect
        || (aAttrib == 460 || bAttrib == 460)        // Limit: Include Non-Focusable
        || (aAttrib == 475 || bAttrib == 475)        // Trigger Spell Non-Item
        || (aAttrib == 479 || bAttrib == 479)        // Limit: Value
        || (aAttrib == 480 || bAttrib == 480)        // Limit: Value
        || (aAttrib == 481 || bAttrib == 481)        // Trigger Spell
        || (aAttrib == 485 || bAttrib == 485)        // Limit: Caster Class
        || (aAttrib == 486 || bAttrib == 486)        // Limit: Caster
        || (NBLargerEffectTest(aSpell, bSpell, i))    // Ignore if the new effect is greater than the old effect
        || (bIgnoreTriggeringEffects && (NBTriggeringEffectSpell(aSpell, i) || NBTriggeringEffectSpell(bSpell, i)))        // Ignore triggering effects validation
        || (bIgnoreCrossDuration && NBDurationWindowTest(aSpell, bSpell, i)));    // Ignore if the effects cross Long/Short Buff windows (with exceptions)
}

// ***************************************************************************
// Function:    BuffStackTest
// Description: Return boolean true if the two spells will stack
// ***************************************************************************
BOOL NBBuffStackTest(PSPELL aSpell, PSPELL bSpell, BOOL bIgnoreTriggeringEffects, BOOL bIgnoreCrossDuration)
{
    if (aSpell->ID == bSpell->ID)
        return true;

    // We need to loop over the largest of the two, this may seem silly but one could have stacking command blocks
    // which we will always need to check.
    LONG effects = max(GetSpellNumEffects(aSpell), GetSpellNumEffects(bSpell));
    for (int i = 0; i < effects; i++) {
        //Compare 1st Buff to 2nd. If Attrib[i]==254 its a place holder. If it is 10 it
        //can be 1 of 3 things: PH(Base=0), CHA(Base>0), Lure(Base=-6). If it is Lure or
        //Placeholder, exclude it so slots don't match up. Now Check to see if the slots
        //have equal attribute values. If the do, they don't stack.
        LONG aAttrib = 254, bAttrib = 254; // Default to placeholder ...
        LONG aBase = 0, bBase = 0, aBase2 = 0, bBase2 = 0;
        if (GetSpellNumEffects(aSpell) > i) {
            aAttrib = GetSpellAttrib(aSpell, i);
            aBase = GetSpellBase(aSpell, i);
            aBase2 = GetSpellBase2(aSpell, i);
        }
        if (GetSpellNumEffects(bSpell) > i) {
            bAttrib = GetSpellAttrib(bSpell, i);
            bBase = GetSpellBase(bSpell, i);
            bBase2 = GetSpellBase2(bSpell, i);
        }
//        if (TriggeringEffectSpell(aSpell, i) || TriggeringEffectSpell(bSpell, i)) {
//            if (!BuffStackTest(GetSpellByID(TriggeringEffectSpell(aSpell, i) ? aBase2 : aSpell->ID), GetSpellByID(TriggeringEffectSpell(bSpell, i) ? bBase2 : bSpell->ID), bIgnoreTriggeringEffects))
//                return false;
//        }
        if (bAttrib == aAttrib && !NBSpellEffectTest(aSpell, bSpell, i, bIgnoreTriggeringEffects, bIgnoreCrossDuration)) {
            if (aAttrib == 55 && bAttrib == 55) {
                //WriteChatf("Increase Absorb Damage by %d over %d", aBase, bBase);
                return (aBase >= bBase);
            }
            else if (!((bAttrib == 10 && (bBase == -6 || bBase == 0)) ||
                (aAttrib == 10 && (aBase == -6 || aBase == 0)) ||
                (bAttrib == 79 && bBase > 0 && bSpell->TargetType == 6) ||
                (aAttrib == 79 && aBase > 0 && aSpell->TargetType == 6) ||
                (bAttrib == 0 && bBase < 0) ||
                (aAttrib == 0 && aBase < 0) ||
                (bAttrib == 148 || bAttrib == 149) ||
                (aAttrib == 148 || aAttrib == 149))) {
                return false;
            }
        }
        //Check to see if second buffs blocks first buff:
        //148: Stacking: Block new spell if slot %d is effect
        //149: Stacking: Overwrite existing spell if slot %d is effect
        if (bAttrib == 148 || bAttrib == 149) {
            // in this branch we know bSpell has enough slots
            int tmpSlot = GetSpellCalc(bSpell, i) - 200 - 1;
            int tmpAttrib = bBase;
            if (GetSpellNumEffects(aSpell) > tmpSlot) { // verify aSpell has that slot
                if (GetSpellMax(bSpell, i) > 0) {
                    int tmpVal = abs(GetSpellMax(bSpell, i));
                    if (GetSpellAttrib(aSpell, tmpSlot) == tmpAttrib && GetSpellBase(aSpell, tmpSlot) < tmpVal) {
                        return false;
                    }
                }
                else if (GetSpellAttrib(aSpell, tmpSlot) == tmpAttrib) {
                    return false;
                }
            }
        }
        //Now Check to see if the first buff blocks second buff. This is necessary 
        //because only some spells carry the Block Slot. Ex. Brells and Spiritual 
        //Vigor don't stack Brells has 1 slot total, for HP. Vigor has 4 slots, 2 
        //of which block Brells.
        if (aAttrib == 148 || aAttrib == 149) {
            // in this branch we know aSpell has enough slots
            int tmpSlot = GetSpellCalc(aSpell, i) - 200 - 1;
            int tmpAttrib = aBase;
            if (GetSpellNumEffects(bSpell) > tmpSlot) { // verify bSpell has that slot
                if (GetSpellMax(aSpell, i) > 0) {
                    int tmpVal = abs(GetSpellMax(aSpell, i));
                    if (GetSpellAttrib(bSpell, tmpSlot) == tmpAttrib && GetSpellBase(bSpell, tmpSlot) < tmpVal) {
                        return false;
                    }
                }
                else if (GetSpellAttrib(bSpell, tmpSlot) == tmpAttrib) {
                    return false;
                }
            }
        }
    }
    return true;
}
 
It looks like they changed something with how Attrib 148 works. I do not know if you talk to folks on "that other site," but they are aware of the need to address the issue as well.
 
Does anyone have any information on what Attrib 148 looked like on spells before they changed it to what it is now? I am trying to understand the conditionals and how they may have changed.