Author Topic: Metamagic vs. Spellcasting Items (Potions, Wands, etc.)  (Read 389 times)

Legacy_Codex85

  • Newbie
  • *
  • Posts: 9
  • Karma: +0/-0
Metamagic vs. Spellcasting Items (Potions, Wands, etc.)
« on: July 05, 2011, 04:20:23 pm »


               Apparently GetMetaMagicFeat() doesn't function as it should when spells are cast from items (e.g. potions, wands, and the like).  Instead, it returns the value for the last spell that was cast by the PC.  Meaning, for example, that if someone casts an extended spell, potions and wands used afterwards which use the default bioware spell scripts will also have the extend effect attached until a non-metamagic spell is cast.

Is there an easier way to fix this than going through every spell script and adding a check?
               
               

               


                     Modifié par Codex85, 05 juillet 2011 - 03:21 .
                     
                  


            

Legacy_FunkySwerve

  • Hero Member
  • *****
  • Posts: 2325
  • Karma: +0/-0
Metamagic vs. Spellcasting Items (Potions, Wands, etc.)
« Reply #1 on: July 05, 2011, 04:52:06 pm »


               No, and yes. No, because you do have to edit every spell script. Yes, because if you decide to, you should put a central spells include in, to make future mass edits to spells easier.

All of our spells start with this:


#include "hg_inc"
#include "ac_spell_inc"


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

GetSpellInfo collects all pertinent spell info like caster, whether an item was used, what metamagic was used, casterlevel, and so on, for easy, uniform access to it in the spellscripts (which all had to be rewritten to use it). Here's the function itself - you can see where the bug you're concerned with is dealt with a short ways in, where metamagic's value is set to 0 if cast from an item.

[code=auto:0]
struct SpellInfo GetSpellInfo (object oCaster=OBJECT_SELF, int nSpellId=-1, int nSpellclass=-1) {
    struct SpellInfo si;

    if (nSpellId >= 0) {
        si.id   = nSpellId;
        si.item = OBJECT_INVALID;
    } else {
        si.id   = GetSpellId();
        si.item = GetSpellCastItem();
    }

    if (GetLocalInt(oCaster, "DebugSpells")) {
        if (GetIsPC(oCaster))
            SendMessageToPC(oCaster, C_WHITE + SFGetSpellInfo(si.id) + C_END);
        else
            WriteTimestampedLogEntry("SPELLDEBUG: " + SFGetSpellInfo(si.id));
    }


    string sScript = GetLocalString(oCaster, "SpellScript");
    if (sScript != "") {
        DeleteLocalString(oCaster, "SpellScript");

        if (StringToInt(sScript) == si.id && !GetIsObjectValid(si.item)) {
            int nPos = FindSubString(sScript, " ");

            sScript = GetStringRight(sScript, GetStringLength(sScript) - (nPos + 1));
            ExecuteScript(sScript, oCaster);

            si.id = -1;
            return si;
        }
    }


    if (nSpellclass >= 0)
        si.class = nSpellclass;
    else if (GetIsObjectValid(si.item))
        si.class = class_TYPE_INVALID;
    else
        si.class = GetLastSpellCastclass();


    si.school = SFGetSpellSchool(si.id);
    si.clevel = GetCasterLevel(oCaster);
    si.meta   = (si.class == class_TYPE_INVALID ? 0 : GetMetaMagicFeat());
    si.sp     = si.clevel;

    si.caster = oCaster;
    si.area   = GetArea(oCaster);

    si.target = GetSpellTargetObject();
    si.loc    = GetSpellTargetLocation();


    if (!X2PreSpellCastCode()) {
        si.id = -1;
        return si;
    }

    if (GetIsObjectValid(si.item)) {
        int nItemType = GetBaseItemType(si.item);

        if (nItemType == BASE_ITEM_POTIONS          ||
            nItemType == BASE_ITEM_MAGICROD         ||
            nItemType == BASE_ITEM_MAGICWAND        ||
            nItemType == BASE_ITEM_ENCHANTED_POTION ||
            nItemType == BASE_ITEM_ENCHANTED_WAND) {

            if (!GetItemIsUsable(si.item, oCaster)) {
                si.id = -1;
                return si;
            }
        }

        if (CheckRestWearRestricted(si.item, oCaster)) {
            si.id = -1;
            return si;
        }

        CheckMarketDupe(si.item, oCaster);

        int nSpellSub = GetLocalInt(si.item, "CastSubstitute_" + IntToString(si.id));
        if (nSpellSub > 0) {
            si.id     = nSpellSub;
            si.school = SFGetSpellSchool(si.id);
        }
    }


    string sPack = GetLocalString(oCaster, "SpellPack");
    if (sPack != "") {
        struct IntList il = GetIntList(sPack);

        if (GetLocalInt(oCaster, "DebugSpells"))
            SendMessageToPC(oCaster, C_WHITE + "Spell Pack: " + sPack + C_END);

        if (il.i0 == si.id && si.class == class_TYPE_INVALID && !GetIsObjectValid(si.item)) {
            si.id     = il.i1;
            si.meta   = il.i2;
            si.class  = il.i3;
            si.school = SFGetSpellSchool(si.id);

            int nPseudo = FindSubString(sPack, "TAG");
            object oPseudo = GetItemPossessedBy(si.caster, GetStringRight(sPack, GetStringLength(sPack) - (nPseudo + 4)));

            if (GetIsObjectValid(oPseudo)) {
                int nUses, nLimit = GetLocalInt(oPseudo, "RadialLimit");
                int nReqLevel = (StringToInt(GetStringRight(GetTag(oPseudo), 1)) * 2) - 1;

                if (nReqLevel < 1)
                    nReqLevel = 1;

                if (GetLevelByclass(si.class, si.caster) < nReqLevel) {
                    nUses = -1;
                } else if (nLimit > 0) {
                    int nUsed = GetLocalInt(oPseudo, "RadialUsed") + 1;
                    SetLocalInt(oPseudo, "RadialUsed", nUsed);

                    nUses = nLimit - nUsed;

                    if (nUses >= 50)
                        SetItemCharges(oPseudo, 50);
                    else if (nUses < 1)
                        SetItemSpellUses(oPseudo, 0);
                    else
                        SetItemCharges(oPseudo, nUses);
                } else {
                    AddLocalInt(oPseudo, "Radial_" + IntToString(il.i4) + "_Used", 1);
                    SetItemSpellUses(oPseudo, -1);
                    SetItemCharges(oPseudo, 1);

                    nUses = GetLocalInt(oPseudo, "Radial_" + IntToString(il.i4) + "_Limit") -
                            GetLocalInt(oPseudo, "Radial_" + IntToString(il.i4) + "_Used");
                }

                if (nUses < 0) {
                    SendMessageToPCByStrRef(oCaster, 7956);
                    si.id = -1;
                    return si;
                }
            } else {
                SendMessageToPCByStrRef(oCaster, 7956);
                si.id = -1;
                return si;
            }
        }

        DeleteLocalString(oCaster, "SpellPack");
    } else {
        /* XXX: make sure this validation works for pseudospells */

        /* ensure personal-range spells are always centered on the caster */
        if (GetObjectType(si.target) == OBJECT_TYPE_CREATURE) {
            if (SFGetSpellRange(si.id) == SPELLFUNC_RANGE_PERSONAL) {
                if (GetLocalInt(oCaster, "DebugSpells"))
                    SendMessageToPC(oCaster, C_WHITE + "Spell target overridden due to personal range" + C_END);

                si.target = oCaster;
                si.loc    = GetLocation(oCaster);
            } else if (!(SFGetSpellTarget(si.id) & SPELLFUNC_TARGET_CREATURE)) {
                if (GetLocalInt(oCaster, "DebugSpells"))
                    SendMessageToPC(oCaster, C_WHITE + "Spell target overridden due to not allowing creature targets" + C_END);

                si.target = oCaster;
                si.loc    = GetLocation(oCaster);
            }
        }
    }

    /* validate metamagic */
    if (si.meta == METAMAGIC_ANY || si.meta < 0)
        si.meta = METAMAGIC_NONE;

    /* allow creatures to cast spells as a specific class by local */
    if (!GetIsPC(oCaster) && si.class == class_TYPE_INVALID) {
        int nCastAs = GetLocalInt(oCaster, "CastAsclass_" + IntToString(si.id));

        if (nCastAs == 0)
            nCastAs = GetLocalInt(oCaster, "CastAsclass_*");

        if (nCastAs > 0)
            si.class = nCastAs;
    }

    /* adjust for shifter-cast spells */
    if (GetIsPC(oCaster)                                   &&
        !GetIsObjectValid(si.item)                         &&
        GetHasEffectOfType(EFFECT_TYPE_POLYMORPH, oCaster)) {

        if (GetLevelByclass(class_TYPE_SHIFTER, oCaster) > 0 &&
            (si.id == SPELL_BESTOW_CURSE                  ||
             si.id == SPELL_BURNING_HANDS                 ||
             si.id == SPELL_DARKNESS                      ||
             si.id == SPELL_DISPEL_MAGIC                  ||
             si.id == SPELL_DOMINATE_MONSTER              ||
             si.id == SPELL_FINGER_OF_DEATH               ||
             si.id == SPELL_GREATER_SPELL_BREACH          ||
             si.id == SPELL_GREAT_THUNDERCLAP             ||
             si.id == SPELL_ICE_STORM                     ||
             si.id == SPELL_ISAACS_GREATER_MISSILE_STORM  ||
             si.id == SPELL_ISAACS_LESSER_MISSILE_STORM   ||
             si.id == SPELL_MAGIC_MISSILE                 ||
             si.id == SPELL_MESTILS_ACID_BREATH           ||
             si.id == SPELL_PRISMATIC_SPRAY               ||
             si.id == SPELL_SUNBURST                      ||
             si.id == SPELL_VAMPIRIC_TOUCH                ||
             si.id == SPELL_WEB                           ||
             si.id == SPELL_WALL_OF_FIRE)) {

            int nEssence = 1;

            if (si.id == SPELL_FINGER_OF_DEATH      ||
                si.id == SPELL_GREATER_SPELL_BREACH ||
                si.id == SPELL_PRISMATIC_SPRAY      ||
                si.id == SPELL_WEB)
                nEssence = 2;
            else if (si.id == SPELL_GREAT_THUNDERCLAP            ||
                     si.id == SPELL_MAGIC_MISSILE                ||
                     si.id == SPELL_ISAACS_LESSER_MISSILE_STORM  ||
                     si.id == SPELL_ISAACS_GREATER_MISSILE_STORM ||
                     si.id == SPELL_SUNBURST)
                nEssence = 3;
            else if (si.id == SPELL_BESTOW_CURSE                ||
                     si.id == SPELL_WALL_OF_FIRE)
                nEssence = 4;
            else if (si.id == SPELL_DOMINATE_MONSTER)
                nEssence = 40;

            if (!ConsumeShifterEssence(oCaster, nEssence)) {
                si.id = -1;
                return si;
            }

            si.class  = class_TYPE_SHIFTER;
            si.slevel = SFGetInnateSpellLevel(si.id);
            si.meta   = METAMAGIC_NONE;
        } else {
            FloatingTextStringOnCreature("You cannot cast spells while polymorphed!", oCaster, FALSE);

            si.id = -1;
            return si;
        }
    }

    /* if the spell was cast as a particular class, get the DC for it */
    if (si.class != class_TYPE_INVALID) {
        if ((si.slevel = SFGetInnateSpellLevelByclass(si.class, si.id)) < 0)
            si.slevel = SFGetInnateSpellLevel(si.id);

        if (si.class == class_TYPE_CLERIC  ||
            si.class == class_TYPE_DRUID   ||
            si.class == class_TYPE_PALADIN ||
            si.class == class_TYPE_RANGER) {

            if (GetLevelByclass(si.class, oCaster) < (si.slevel * 2) - 1) {
                FloatingTextStringOnCreature("You do not have enough class levels to cast that spell!", oCaster, FALSE);

                si.id = -1;
                return si;
            }
        }

        if (GetLevelByclass(class_TYPE_PALEMASTER, oCaster) > 10 &&
            si.id == SPELL_BESTOW_CURSE)
            si.school = SPELL_SCHOOL_NECROMANCY;

        if (GetIsQuasiclass(QUASIclass_BLOODFIRE_MAGE, oCaster) &&
            SFGetIsQuasiSpell(QUASIclass_BLOODFIRE_MAGE, si.id))
            si.school = SPELL_SCHOOL_EVOCATION;

        if (GetIsQuasiclass(QUASIclass_DRAGONSTORM_MAGE, oCaster) &&
            SFGetIsQuasiSpell(QUASIclass_DRAGONSTORM_MAGE, si.id))
            si.school = SPELL_SCHOOL_EVOCATION;

        if (GetIsQuasiclass(QUASIclass_DWARVEN_WARCHANTER, oCaster) &&
            si.id == SPELL_HOLD_MONSTER)
            si.school = SPELL_SCHOOL_TRANSMUTATION;

        if (GetIsQuasiclass(QUASIclass_HERALD_OF_STORMS, oCaster)) {
            if (si.id == SPELL_HORRID_WILTING)
                si.school = SPELL_SCHOOL_CONJURATION;
            else if (si.id == HGSPELL_FREEZING_FOG)
                si.school = SPELL_SCHOOL_CONJURATION;
            else if (si.id == HGSPELL_STATIC_FIELD)
                si.school = SPELL_SCHOOL_CONJURATION;
        }
        si.dc = GetCasterSpellSaveDC(si.id, si.class, si.slevel, si.school, oCaster);
    } else {
        /* Base DC is 10 + spell level + minimum ability modifier to cast */

        si.slevel = SFGetInnateSpellLevel(si.id);
        si.dc     = 10 + si.slevel + (si.slevel / 2);
    }


    /* If the spell was item-cast, check for item spell modifiers */
    if (GetIsObjectValid(si.item)) {
        int nItemCL = GetLocalInt(si.item, "CasterLevel_" + IntToString(si.id));

        if (nItemCL == 0)
            nItemCL = GetLocalInt(si.item, "CasterLevel_*");

        if (nItemCL > 0) {
            si.clevel = nItemCL;
            si.dc    += nItemCL / 2;
            si.meta   = GetLocalInt(si.item, "Metamagic_" + IntToString(si.id));

            if ((si.sp == GetLocalInt(si.item, "SpellPenetration_" + IntToString(si.id))) == 0)
                si.sp = si.clevel + (si.clevel / 10);

            int nItemclass = GetLocalInt(si.item, "CastAsclass_" + IntToString(si.id));
            if (nItemclass == 0)
                nItemclass = GetLocalInt(si.item, "CastAsclass_*");

            if (nItemclass > 0)
                si.class = nItemclass;

            SendSpellDebug(oCaster, si);
            return si;
        } else if (nItemCL < 0) {
            int nItemclass = GetLocalInt(si.item, "CastAsclass_" + IntToString(si.id));

            if (nItemclass == 0)
                nItemclass = GetLocalInt(si.item, "CastAsclass_*");

            if (GetLevelIncludingLLs(nItemclass, oCaster) < 1) {
                si.clevel = 1;
                si.sp     = 1;

                SendSpellDebug(oCaster, si);
                return si;
            }

            si.class = nItemclass;
            if ((si.slevel = SFGetInnateSpellLevelByclass(si.class, si.id)) < 0)
                si.slevel = SFGetInnateSpellLevel(si.id);

            si.dc = GetCasterSpellSaveDC(si.id, si.class, si.slevel, si.school, oCaster);

            if (si.class == class_TYPE_BARD || si.class == class_TYPE_SORCERER) {
                int nItemSlots = GetLocalInt(si.item, "CastWithSlots_" + IntToString(si.id));
                if (nItemSlots == 0)
                    nItemSlots = GetLocalInt(si.item, "CastWithSlots_*");

                int nRemaining = GetRemainingSpellSlots(si.caster, si.class, si.slevel);

                if (nItemSlots > nRemaining) {
                    FloatingTextStringOnCreature("You do not have enough spell slots remaining to use that item!", si.caster, FALSE);

                    si.id = -1;
                    return si;
                }

                SetRemainingSpellSlots(si.caster, si.class, si.slevel, nRemaining - nItemSlots);
            }
        } else {
            SendSpellDebug(oCaster, si);
            return si;
        }
    }

    si.dc -= GetSpellAreaDCPenalty(si.caster, si.area);


    string sOnce = GetLocalString(oCaster, "CasterLevelOnce");

    if (sOnce != "") {
        DeleteLocalString(oCaster, "CasterLevelOnce");

        int nOnceID = StringToInt(GetStringSubString(sOnce, 0));
        int nOnceLevel = StringToInt(GetStringSubString(sOnce, 1));

        if (nOnceID == si.id && nOnceLevel > 0)
            si.clevel = nOnceLevel;
        else
            si.clevel = 0;
    } else
        si.clevel = GetLocalInt(oCaster, "CasterLevelOnce_" + IntToString(si.id));

    if (si.clevel > 0)
        DeleteLocalInt(oCaster, "CasterLevelOnce_" + IntToString(si.id));

    if (!GetIsPC(oCaster)) {
        if (si.clevel == 0)
            si.clevel = GetLocalInt(oCaster, "CasterLevel_" + IntToString(si.class) + "_" + IntToString(si.id));

        if (si.clevel == 0)
            si.clevel = GetLocalInt(oCaster, "CasterLevel_" + IntToString(si.id));

        if (si.clevel == 0)
            si.clevel = GetLocalInt(oCaster, "CasterLevel_" + IntToString(si.class) + "_*");

        if (si.clevel == 0)
            si.clevel = GetLocalInt(oCaster, "CasterLevel_*");
    }

    if (si.clevel == 0) {
        if (GetIsDM(oCaster)) {
            si.clevel = GetLocalInt(oCaster, "CasterLevel_*");

            if (si.clevel == 0)
                si.clevel = 60;
        } else if (si.class == class_TYPE_INVALID)
            si.clevel = GetCasterLevel(oCaster);
        else if (si.class == class_TYPE_SHIFTER)
            si.clevel = GetLevelIncludingLLs(class_TYPE_DRUID, oCaster) +
                        GetLevelIncludingLLs(class_TYPE_SHIFTER, oCaster);
        else
            si.clevel = GetLevelIncludingLLs(si.class, oCaster);
    }


    int nLevel;

    /* Blackguards and Paladins must be aligned to cast spells */
    if (si.class == class_TYPE_BLACKGUARD) {
        if (GetAlignmentGoodEvil(si.caster) != ALIGNMENT_EVIL) {
            FloatingTextStringOnCreature("You must be evil to cast Blackguard spells!", si.caster, FALSE);
            si.id = -1;
            return si;
        }

        /* Non-quasi blackguards add their paladin level to caster level for their spells. */
        if (!GetQuasiclass(si.caster))
            si.clevel += GetLevelByclass(class_TYPE_PALADIN, si.caster);
    } else if (si.class == class_TYPE_PALADIN && GetAlignmentGoodEvil(si.caster) != ALIGNMENT_GOOD) {
        FloatingTextStringOnCreature("You must be good to cast Paladin spells!", si.caster, FALSE);
        si.id = -1;
        return si;
    } else if (si.class == class_TYPE_ASSASSIN && GetAlignmentGoodEvil(si.caster) == ALIGNMENT_GOOD) {
        FloatingTextStringOnCreature("You must not be good to cast Assassin spells!", si.caster, FALSE);
        si.id = -1;
        return si;
    }

    /* Pale Masters add 7/6 their PM level to caster level for illusion/necro
     * spells and PWK. They don't get the bonus for EV. They also get +1 DC
     * for every 15 levels of PM. */
    if ((nLevel = GetLevelIncludingLLs(class_TYPE_PALEMASTER, oCaster)) > 0) {
        if (si.class == class_TYPE_SORCERER && GetLocalInt(oCaster, "ForsakenSorcerer")) {
            si.clevel -= 10;
            nLevel    += 10;
        }

        if (si.id != SPELL_ETHEREAL_VISAGE &&
            si.id != SPELL_SHADES_STONESKIN &&
            (si.school == SPELL_SCHOOL_ILLUSION   ||
             si.school == SPELL_SCHOOL_NECROMANCY ||
             si.id == SPELL_BESTOW_CURSE          ||
             si.id == SPELL_POWER_WORD_KILL))
            si.clevel += (nLevel * 7) / 6;
        else
            si.clevel += (nLevel / 3);
    }


    if (si.class != class_TYPE_INVALID && GetIsPC(oCaster)) {
        /* Many quasiclasses add multiple class levels for spell caster levels */
        switch (GetQuasiclass(oCaster)) {
            case QUASIclass_BANE_KNIGHT:
                if (si.class == class_TYPE_SORCERER &&
                    SFGetIsQuasiSpell(QUASIclass_BANE_KNIGHT, si.id))
                    si.clevel += GetLevelIncludingLLs(class_TYPE_BLACKGUARD, oCaster);
                break;

            case QUASIclass_STAFFMASTER:
                if (si.class == class_TYPE_WIZARD &&
                    (nLevel = GetLevelIncludingLLs(class_TYPE_WEAPON_MASTER, oCaster)) > 0) {
                    if (SFGetIsQuasiSpell(QUASIclass_STAFFMASTER, si.id))
                        si.clevel += nLevel;
                    else
                        si.clevel += (nLevel / 3);
                }
                break;

            case QUASIclass_DIVINE_SLINGER:
                if (si.class == class_TYPE_CLERIC &&
                    si.clevel > 16                &&
                    !SFGetIsQuasiSpell(QUASIclass_DIVINE_SLINGER, si.id))
                    si.clevel = 16 + (((si.clevel - 16) * 3) / 5);
                break;

            case QUASIclass_THEURGE:
                if (si.class == class_TYPE_CLERIC)
                    si.clevel += (GetLevelIncludingLLs(class_TYPE_WIZARD, oCaster) - 1);
                else if (si.class == class_TYPE_WIZARD)
                    si.clevel += (GetLevelIncludingLLs(class_TYPE_CLERIC, oCaster) - 1);
                break;

            case QUASIclass_LASH_OF_HATRED:
                if (si.class == class_TYPE_RANGER &&
                    SFGetIsQuasiSpell(QUASIclass_LASH_OF_HATRED, si.id))
                    si.clevel += GetLevelIncludingLLs(class_TYPE_BLACKGUARD, oCaster);
                break;

            case QUASIclass_BLOODFIRE_MAGE:
                if (si.class == class_TYPE_SORCERER &&
                    SFGetIsQuasiSpell(QUASIclass_BLOODFIRE_MAGE, si.id))
                    si.clevel += GetLevelIncludingLLs(class_TYPE_DRAGON_DISCIPLE, oCaster);
                break;

            case QUASIclass_DRAGONSTORM_MAGE:
                if (si.class == class_TYPE_SORCERER &&
                    SFGetIsQuasiSpell(QUASIclass_DRAGONSTORM_MAGE, si.id))
                    si.clevel += GetLevelIncludingLLs(class_TYPE_DRAGON_DISCIPLE, oCaster);
                break;

            case QUASIclass_ACCURSED_PARIAH:
                if (si.class == class_TYPE_SORCERER)
                    si.clevel += GetLevelIncludingLLs(class_TYPE_BARBARIAN, oCaster);
                if (si.clevel > (nLevel = GetAbilityS
               
               

               
            

Legacy_FunkySwerve

  • Hero Member
  • *****
  • Posts: 2325
  • Karma: +0/-0
Metamagic vs. Spellcasting Items (Potions, Wands, etc.)
« Reply #2 on: July 05, 2011, 04:54:39 pm »


               Edit: the function was too long for these forums. Go figure. I'll post the spell info struct as well, in case you're curious:


struct SpellInfo {
    int         id, school, class, clevel, slevel, meta, sp, dc;
    object      caster, target, item, area;
    location    loc;
};

Hope that helps,
Funky
               
               

               
            

Legacy_Shadooow

  • Hero Member
  • *****
  • Posts: 7698
  • Karma: +0/-0
Metamagic vs. Spellcasting Items (Potions, Wands, etc.)
« Reply #3 on: July 05, 2011, 05:19:14 pm »


               

Codex85 wrote...

Apparently GetMetaMagicFeat() doesn't function as it should when spells are cast from items (e.g. potions, wands, and the like).  Instead, it returns the value for the last spell that was cast by the PC.  Meaning, for example, that if someone casts an extended spell, potions and wands used afterwards which use the default bioware spell scripts will also have the extend effect attached until a non-metamagic spell is cast.

Is there an easier way to fix this than going through every spell script and adding a check?

My patch fixes that.
               
               

               
            

Legacy_FunkySwerve

  • Hero Member
  • *****
  • Posts: 2325
  • Karma: +0/-0
Metamagic vs. Spellcasting Items (Potions, Wands, etc.)
« Reply #4 on: July 05, 2011, 05:27:01 pm »


               

ShaDoOoW wrote...

Codex85 wrote...

Apparently GetMetaMagicFeat() doesn't function as it should when spells are cast from items (e.g. potions, wands, and the like).  Instead, it returns the value for the last spell that was cast by the PC.  Meaning, for example, that if someone casts an extended spell, potions and wands used afterwards which use the default bioware spell scripts will also have the extend effect attached until a non-metamagic spell is cast.

Is there an easier way to fix this than going through every spell script and adding a check?

My patch fixes that.


Oh, nice work. Looks like you did the same thing we did. :happy: Drop me a pm if you want to peep the full include for ideas for your patch - ours has seen hundreds of thousands of hours of playtest. I'll definitely recommend that to less-experienced coders in the future - doing a spells system from the ground up is a major undertaking.

Funky
               
               

               
            

Legacy_Codex85

  • Newbie
  • *
  • Posts: 9
  • Karma: +0/-0
Metamagic vs. Spellcasting Items (Potions, Wands, etc.)
« Reply #5 on: August 07, 2011, 11:20:22 am »


               Minor thread necromancy here--does that patch just change all the spell scripts, or is it actually altering how GetMetaMagicFeat() functions?
               
               

               
            

Legacy_Shadooow

  • Hero Member
  • *****
  • Posts: 7698
  • Karma: +0/-0
Metamagic vs. Spellcasting Items (Potions, Wands, etc.)
« Reply #6 on: August 07, 2011, 09:51:19 pm »


               It changes all spell scripts.

I created a new structure that contains all spell informations and this is declared in each script like this:

struct spell spell = spellsDeclareMajorVariables();

and then those spell scripts uses instead declaring

int nMetamagic = GetMetaMagicFeat(); simple int nMetamagic = spell.Meta;

the core function GetMetaMagicFeat(); is used in the new spell engine include where before is set into spell structure is checked many parameters like if the spell comes from item, if that is the case engine save into spell.Meta = METAMAGIC_NONE;


This means that if you have any spell script altered you must rewrite it to the new spell engine otherwise the fix for metamagic wont work there. If you already changed all spellscripts (few PWs out there did it), then its not for much use and using other techniques like core function hook would be better idea.
               
               

               


                     Modifié par ShaDoOoW, 07 août 2011 - 08:53 .