Author Topic: Any way to cap the number of spell slots a PC has?  (Read 1327 times)

Legacy_Lazarus Magni

  • Hero Member
  • *****
  • Posts: 1837
  • Karma: +0/-0
Any way to cap the number of spell slots a PC has?
« on: December 29, 2014, 12:06:23 am »


               

Looking for a solution to this issue. Would appreciate any help/ideas in this regard.



               
               

               
            

Legacy_Squatting Monk

  • Hero Member
  • *****
  • Posts: 776
  • Karma: +0/-0
Any way to cap the number of spell slots a PC has?
« Reply #1 on: December 29, 2014, 12:43:54 am »


               You can get the number of uses the PC has with GetHasSpell() and then call DecrementRemainingSpellUses() in a loop for the necessary number of times:
 
void CapSpellUses(object oPC, int nSpell, int nCap)
{
    int i = GetHasSpell(nSpell, oPC);
    for (i; i > nCap; i--)
    {
        DecrementRemainingSpellUses(oPC, nSpell);
    }
}
This is a simple use case, as GetHasSpell() will report a higher number of uses if the spell has been enhanced by meta-magic. You will need to do some additional math to catch this if it matters to you.

Alternatively, you can use nwnx_func's SetRemainingSpellSlots().
               
               

               
            

Legacy_Lazarus Magni

  • Hero Member
  • *****
  • Posts: 1837
  • Karma: +0/-0
Any way to cap the number of spell slots a PC has?
« Reply #2 on: December 29, 2014, 04:52:58 pm »


               

Thanks for the response SM. We do use nwnx_funcs (for windows.)


 


Would either of these solutions be best as part of the onequip event?


 


I would imagine there would have to be some sort of check for how many spell slots the player has similar to the code posted above?


 


Also does anyone know what the actual limit is? I think it is in the 200-250 range...



               
               

               
            

Legacy_Lazarus Magni

  • Hero Member
  • *****
  • Posts: 1837
  • Karma: +0/-0
Any way to cap the number of spell slots a PC has?
« Reply #3 on: December 29, 2014, 06:41:41 pm »


               

I am wondering if something like this will work as part of the on enter script?


 


void CapSpellUses(object oPC, int iClass, int iSpellLevel, int nSlots)

{


    NWNXFuncs_GetRemainingSpellSlots(oPC, iClass, iSpellLevel);

    if (nSlots>240)

    {

    NWNXFuncs_SetRemainingSpellSlots(oPC, iClass, iSpellLevel, 240);

    }


}


 


And then:


 


CapSpellUses(oPC, iClass, iSpellLevel, nSlots);


 


in the void main?



               
               

               
            

Legacy_Squatting Monk

  • Hero Member
  • *****
  • Posts: 776
  • Karma: +0/-0
Any way to cap the number of spell slots a PC has?
« Reply #4 on: December 29, 2014, 08:11:13 pm »


               

I think that'd work. One thing to remember is GetRemainingSpellSlots() is for spontaneous casters (bards and sorcs) only. You can do something similar with GetMaxSpellSlots()/ClearMemorizedSpell() for prepared spell-casters.


Question: are you just trying to overcome exploits whereby players manage to get more spells than they should? Because if not and you just don't like the number of spells classes get at certain levels you could just edit the cls_spgn_*.2das and set these manually.



               
               

               
            

Legacy_Lazarus Magni

  • Hero Member
  • *****
  • Posts: 1837
  • Karma: +0/-0
Any way to cap the number of spell slots a PC has?
« Reply #5 on: December 29, 2014, 08:25:37 pm »


               

The reason I am interested in this is because a PC can crash our server (it doesn't actually crash, but hangs the nwnserver process with excessive CPU usage) if they log in with more than 240 (something) spell slots.


 


And so are you saying the function I wrote will work for prepared casters, but not spontaneous ones? Do I need a seprate check and cap for them?



               
               

               
            

Legacy_Squatting Monk

  • Hero Member
  • *****
  • Posts: 776
  • Karma: +0/-0
Any way to cap the number of spell slots a PC has?
« Reply #6 on: December 29, 2014, 08:30:26 pm »


               

Other way around. The function as written will work for spontaneous casters but not prepared ones.


Is this 240 spell slots total, or 240 spells slots of each level? Because as it currently is the function is limiting the PC to 240 of the spell level iSpellLevel. If you want to make it no more than 240 spell slots altogether, you're going to need to total up all the spell slots of each level and figure out if/where you need to delete.



               
               

               
            

Legacy_Lazarus Magni

  • Hero Member
  • *****
  • Posts: 1837
  • Karma: +0/-0
Any way to cap the number of spell slots a PC has?
« Reply #7 on: December 30, 2014, 01:03:30 am »


               

The problem appears to be related to total spell slots.


 


So, I could limit nSlots to 24 then to cap it at 240 total (24 spells per spell level)?  Is that correct?


 


And how would I rewrite it for both spontaneous and prepared casters?



               
               

               
            

Legacy_Lazarus Magni

  • Hero Member
  • *****
  • Posts: 1837
  • Karma: +0/-0
Any way to cap the number of spell slots a PC has?
« Reply #8 on: December 30, 2014, 05:29:15 pm »


               

BTW GetMaxSpellSlots() does not appear to be in the lexicon, or is ClearMemorizedSpell(). So I am not sure how to use those.



               
               

               
            

Legacy_Lazarus Magni

  • Hero Member
  • *****
  • Posts: 1837
  • Karma: +0/-0
Any way to cap the number of spell slots a PC has?
« Reply #9 on: December 30, 2014, 10:42:13 pm »


               

I did find 2 other interesting functions in nwnx_funcs, but I am not sure how to use them. They are:


 


struct MemorizedSpellSlot NWNXFuncs_GetMemorizedSpellSlot(object oCreature, int iClass, int iSpellLevel, int iIndex) {

    SetLocalString(oCreature, "NWNX!FUNCS!GETMEMORIZEDSPELLSLOT", IntToString(iClass)+" "+IntToString(iSpellLevel)+" "+IntToString(iIndex));

    int nSpell = StringToInt(GetLocalString(oCreature, "NWNX!FUNCS!GETMEMORIZEDSPELLSLOT"));

    DeleteLocalString(oCreature, "NWNX!FUNCS!GETMEMORIZEDSPELLSLOT");


    struct MemorizedSpellSlot iRet;


   if (nSpell >= 0) {

        iRet.id    = nSpell & 0xFFFF;

        iRet.meta  = (nSpell >> 16) & 0x7F;

        iRet.ready = (nSpell >> 24) & 1;

    } else

        iRet.id = -1;


    return iRet;

 


 


AND...


 


void NWNXFuncs_SetMemorizedSpellSlot(object oCreature, int iClass, int iSpellLevel, int iIndex, struct MemorizedSpellSlot spell) {

    int P4 = (spell.id & 0xFFFF) | ((spell.meta& 0xFF) << 16) | (spell.ready << 24);

    SetLocalString(oCreature, "NWNX!FUNCS!SETMEMORIZEDSPELLSLOT", IntToString(iClass)+" "+IntToString(iSpellLevel)+" "+IntToString(iIndex)+" "+IntToString(P4));

    DeleteLocalString(oCreature, "NWNX!FUNCS!SETMEMORIZEDSPELLSLOT");

}


 


Unfortunately though, I can not simply add


 


NWNXFuncs_GetMemorizedSpellSlot();


Nor


NWNXFuncs_SetMemorizedSpellSlot();


 


to the on client login script. Even though I have nwnx_funcs as an include. Anybody got any ideas on how I can use these?


               
               

               
            

Legacy_Lazarus Magni

  • Hero Member
  • *****
  • Posts: 1837
  • Karma: +0/-0
Any way to cap the number of spell slots a PC has?
« Reply #10 on: December 30, 2014, 10:44:10 pm »


               

P.S. This is what I currently have:


 


    {


    NWNXFuncs_GetRemainingSpellSlots(oPC, iClass, iSpellLevel);

    if (nSlots>24)

    {

    NWNXFuncs_SetRemainingSpellSlots(oPC, iClass, iSpellLevel, 24);

    }

    }


 


Which compiles fine (although remains to be seen if it works for spontaneous casters.) But that still leaves the prepared casters as a problem.



               
               

               
            

Legacy_Lazarus Magni

  • Hero Member
  • *****
  • Posts: 1837
  • Karma: +0/-0
Any way to cap the number of spell slots a PC has?
« Reply #11 on: December 31, 2014, 01:33:31 am »


               

P.P.S. I am not publishing this server crashing phenomenon to try to black mail the community into helping me fix it. I know one concrete way I can fix it for the world I am involved with. We have a script to nerf on login any item we choose, and if push comes to shove, I will simply add all the items with more than one spell slot per level to that list to update. It will take some work, but I have some time presently...


 


No, I am publishing this because it is a flaw in the game, and one I hoped the NWN community could help me solve, and post for all interested in fixing it on their worlds. The capacity to do so seems to be there, but the knowledge is lacking or not forthcoming. I guess I have burned too many bridges here eh? Well that's sad... in many respects, and especially for what it says about the NWN community.



               
               

               
            

Legacy_Lazarus Magni

  • Hero Member
  • *****
  • Posts: 1837
  • Karma: +0/-0
Any way to cap the number of spell slots a PC has?
« Reply #12 on: December 31, 2014, 03:56:54 pm »


               

BTW for any PW owners out there who are worried about this, here is the item update code that can nerf specific items and update them (used here to remove gear with too many spell slots which can parcipitate this problem.) This is in our on client login event.


 


void UpdateItems(object oPC)

{

   object oItem = GetFirstItemInInventory(oPC);

   while(oItem != OBJECT_INVALID)

   {

      string sTag = GetTag(oItem);

      string sRef = GetResRef(oItem); // Either the tag or the ref can be used


      // Destroy illegal items. Add or remove checks as needed.

      // if(sTag == "any_tag" || sTag == "any_other_tag") DestroyObject(oItem);     tbz_tmpl_magelec

      if(sTag == "skip_divideritem" || sTag == "skip_xpsignet" || sTag == "laz_aventianid1" || sTag == "laz_aventianid2" || sTag == "laz_aventianid3" || sTag == "laz_aventianid4" || sTag == "tbz_tmpl_magelec") DestroyObject(oItem);

      // Replace items in inventories

      if(sRef == "ice_glaciercape" || sRef == "grtringanimempth" || sRef == "ice_vx4druidstaf" || sRef == "midnightplate" || sRef == "piratesarmor" || sRef == "armorofsin") // Items with same ref

      {

         AddStringElement(sRef, "ToReplace", oPC); // Store the ref in a list for later creation

         DestroyObject(oItem);

      }

      else if(sRef == "x2_it_mring019" || sRef == "laz_mring019") // Items with different ref or tag

      {

         AddStringElement("laz_30ring1", "ToReplace", oPC);

         DestroyObject(oItem);

      }


 


oItem = GetNextItemInInventory(oPC);

   }


   int nSlot = 0;

   for(nSlot = 0; nSlot < NUM_INVENTORY_SLOTS; nSlot++)

   {

      object oWorn = GetItemInSlot(nSlot, oPC);

      string sTag = GetTag(oWorn);

      string sRef = GetResRef(oWorn); // Either the tag or the ref can be used


      // Destroy illegal items. Add or remove checks as needed.

      // if(sTag == "any_tag" || sTag == "any_other_tag") DestroyObject(oItem);


      // Replace equiped items

      if(sRef == "tov_vissii_boots" || sRef == "ice_glaciercape" || sRef == "grtringanimempth" ||

      sRef == "ice_vx4druidstaf" || sRef == "midnightplate" || sRef == "piratesarmor" || sRef == "armorofsin") // Items with same ref

      {

         AddStringElement(sRef, "ToReplace", oPC); // Store the ref in a list for later creation

         DestroyObject(oWorn);

      }

      else if(sRef == "x2_it_mring019" || sRef == "laz_mring019") // Items with different ref or tag

      {

         AddStringElement("laz_30ring1", "ToReplace", oPC);

         DestroyObject(oWorn);

      }


 


}


   int nNth = 0;

   int nCount = GetElementCount("ToReplace", oPC);

   for(nNth = 0; nNth < nCount; nNth++) // Loop over the list and create items from the refs

   {

      CreateItemOnObject(GetStringElement(nNth, "ToReplace", oPC), oPC);

   }

   DeleteList("ToReplace", oPC); // Delete the list

}


 


 


Then in the void main you have to add this line somewhere:


 


UpdateItems(oPC);



               
               

               
            

Legacy_Squatting Monk

  • Hero Member
  • *****
  • Posts: 776
  • Karma: +0/-0
Any way to cap the number of spell slots a PC has?
« Reply #13 on: December 31, 2014, 11:51:48 pm »


               

BTW GetMaxSpellSlots() does not appear to be in the lexicon, or is ClearMemorizedSpell(). So I am not sure how to use those.


These are also nwnx_funcs functions. Since you have the Windows version, your functions may have slightly different names than mine do.

I'll try to whip up a suitable function for you, but it's likely it will need lots of testing and tweaks. Simply removing or limiting items that add extra spell slots may turn out to be an easier solution.
               
               

               
            

Legacy_Lazarus Magni

  • Hero Member
  • *****
  • Posts: 1837
  • Karma: +0/-0
Any way to cap the number of spell slots a PC has?
« Reply #14 on: January 01, 2015, 12:01:23 am »


               

That is kind of you to offer SM, I think it would be a valuable tool not just to us, but to the NWN community. I am however, resigned to the fact that indeed, I will likely just have to nerf items, but if a scripted solution is possible, that would be a much better alternative.