Major script update for 8 class support. prc_wipeNSB.nss PRC_S_spellb.nss prc_amagsys_gain.nss - AMSCompatibilityCheck() prc_prereq.nss - Dragonheart(), KnightWeave() prc_onenter.nss - OnEnter_AMSCompatibilityCheck() prc_metamagic.nss - GetHasSpontaneousNSBClass() prc_feats.nss prc_dracactive.nss prc_debug_hfeatm.nss prc_cbtmed_spnhl.nss psi_powconv.nss psi_pow_bstpwr.nss x2_pc_umdcheck.nss
368 lines
12 KiB
Plaintext
368 lines
12 KiB
Plaintext
//:://////////////////////////////////////////////
|
|
//:: Name: new spellbook spellgain / spell memorization include
|
|
//:: File: inc_sp_gain_mem.nss
|
|
//:://////////////////////////////////////////////
|
|
/**
|
|
contains helper functions for the two dynamic conversation scripts
|
|
- prc_s_spellb.nss
|
|
- prc_s_spellgain.nss
|
|
that handle learning / gaining new spells at level up (prc_s_spellgain)
|
|
or preparing what spells to learn at next rest (prc_s_spellb)
|
|
|
|
Author: motu99
|
|
Created: May 1, 2008
|
|
*/
|
|
|
|
//#include "prc_inc_core" //granted access via parent (inc_newspellbook)
|
|
|
|
//:: Updated for .35 by Jaysyn 2023/03/11
|
|
|
|
#include "inc_newspellbook.nss"
|
|
|
|
//:: Test Void
|
|
//void main (){}
|
|
|
|
//:://////////////////////////////////////////////
|
|
//:: Constants
|
|
//:://////////////////////////////////////////////
|
|
|
|
// max. number of classes a PC (or creature) can take (8 for NWN, 4 for NWN2)
|
|
const int MAX_CLASSES = 8;
|
|
|
|
//////////////////////////////////////////////////
|
|
/* Aid functions */
|
|
//////////////////////////////////////////////////
|
|
|
|
string GetNSBDefinitionFileName(int nClass);
|
|
int GetCasterLevelByClass(int nClass, object oPC);
|
|
|
|
int GetSpellsKnown_MaxCount(int nCasterLevel, int nClass, int nSpellLevel, object oPC);
|
|
int GetSpellsInClassSpellbook_Count(int nClass, int nSpellLevel);
|
|
string GetClassString(int nClass);
|
|
int GetMaxSpellLevelForCasterLevel(int nClass, int nCasterLevel);
|
|
int GetMinSpellLevelForCasterLevel(int nClass, int nCasterLevel);
|
|
|
|
void WipeSpellFromHide(int nIPFeatID, object oPC);
|
|
|
|
string GetSpellsKnown_Array(int nClass, int nSpellLevel = -1);
|
|
object GetSpellsOfClass_Token(int nClass, int nSpellLevel);
|
|
string GetSpellsOfClass_Array();
|
|
string GetSpellsMemorized_Array(int nClass);
|
|
string GetSpellsToBeMemorized_Array(int nClass, int nSpellSlotLevel);
|
|
|
|
void array_set_size(object oPC, string sArrayName, int nSize);
|
|
int array_has_string(object oPC, string sArrayName, string sValue, int nFirst = 0, int nSize = 0);
|
|
int array_has_int(object oPC, string sArrayName, int nValue, int nFirst = 0, int nSize = 0);
|
|
int persistant_array_has_string(object oPC, string sArrayName, string sValue, int nFirst = 0, int nSize = 0);
|
|
int persistant_array_has_int(object oPC, string sArrayName, int nValue, int nFirst = 0, int nSize = 0);
|
|
int array_extract_string(object oPC, string sArrayName, string sValue, int nFirst = 0);
|
|
int array_extract_int(object oPC, string sArrayName, int nValue, int nFirst = 0);
|
|
int persistant_array_extract_string(object oPC, string sArrayName, string sValue, int nFirst = 0);
|
|
int persistant_array_extract_int(object oPC, string sArrayName, int nValue, int nFirst = 0);
|
|
|
|
string GetMetaMagicString_Short(int nMetaMagic);
|
|
string GetMetaMagicString(int nMetaMagic);
|
|
int GetMetaMagicFromFeat(int nFeat);
|
|
int GetMetaMagicOfCaster(object oPC = OBJECT_SELF);
|
|
|
|
// name of the new spellbook file (cls_spell_*)
|
|
string GetNSBDefinitionFileName(int nClass)
|
|
{
|
|
return GetFileForClass(nClass);
|
|
}
|
|
|
|
// gets the caster level (without special modifications due to feats), by which the max spell slot level is determined
|
|
int GetCasterLevelByClass(int nClass, object oPC)
|
|
{
|
|
return GetSpellslotLevel(nClass, oPC);
|
|
// return GetPrCAdjustedCasterLevel(nClass, oPC, TRUE);
|
|
}
|
|
|
|
// gets the maximum nr of spells that oPC can know with a given nCasterLevel, nClass and nSpellLevel
|
|
int GetSpellsKnown_MaxCount(int nCasterLevel, int nClass, int nSpellLevel, object oPC)
|
|
{
|
|
return GetSpellKnownMaxCount(nCasterLevel, nSpellLevel, nClass, oPC);
|
|
}
|
|
|
|
|
|
// gets the total nr of spells available at nSpellLevel for nClass
|
|
int GetSpellsInClassSpellbook_Count(int nClass, int nSpellLevel)
|
|
{
|
|
return persistant_array_get_size(GetSpellsOfClass_Token(nClass, nSpellLevel), GetSpellsOfClass_Array());
|
|
}
|
|
|
|
string GetClassString(int nClass)
|
|
{
|
|
// get the name of the feats table 2da
|
|
string sClass = Get2DACache("classes", "FeatsTable", nClass);
|
|
// truncate the first 8 characters (the "cls_feat" part), leaving the "_<class>" part
|
|
sClass = GetStringRight(sClass, GetStringLength(sClass) - 8);
|
|
return sClass;
|
|
}
|
|
|
|
// gets the maximum spell level that nClass can cast at nCasterLevel
|
|
int GetMaxSpellLevelForCasterLevel(int nClass, int nCasterLevel)
|
|
{
|
|
string sFile;
|
|
// Bioware casters use their classes.2da-specified tables
|
|
//if(GetIsBioSpellCastClass(nClass))
|
|
//{
|
|
sFile = Get2DACache("classes", "SpellGainTable", nClass);
|
|
//}
|
|
//else
|
|
//{
|
|
// sFile = "cls_spbk" + GetClassString(nClass);
|
|
//}
|
|
|
|
// row nr in the files is nCasterLevel minus 1
|
|
nCasterLevel--;
|
|
int nSpellLevel;
|
|
|
|
if (Get2DACache(sFile, "NumSpellLevels", 9) != "")
|
|
{
|
|
string sTemp = Get2DACache(sFile, "NumSpellLevels", nCasterLevel);
|
|
if (sTemp != "")
|
|
{
|
|
nSpellLevel = StringToInt(sTemp)-1;
|
|
if (nSpellLevel <= 0) nSpellLevel = 0;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
for (nSpellLevel=9; nSpellLevel >= 0; nSpellLevel--)
|
|
{
|
|
string sTemp = Get2DACache(sFile, "SpellLevel" + IntToString(nSpellLevel), nCasterLevel);
|
|
if (sTemp != "")
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
return nSpellLevel;
|
|
}
|
|
|
|
// gets the minimum spell level that nClass can cast at nCasterLevel
|
|
int GetMinSpellLevelForCasterLevel(int nClass, int nCasterLevel)
|
|
{
|
|
string sFile;
|
|
// Bioware casters use their classes.2da-specified tables
|
|
//if(GetIsBioSpellCastClass(nClass))
|
|
//{
|
|
sFile = Get2DACache("classes", "SpellGainTable", nClass);
|
|
//}
|
|
//else
|
|
//{
|
|
// sFile = "cls_spbk" + GetClassString(nClass);
|
|
//}
|
|
|
|
// row nr in the files is nCasterLevel minus 1
|
|
nCasterLevel--;
|
|
|
|
int bFound = 0;
|
|
|
|
int nSpellLevel;
|
|
for (nSpellLevel=0; nSpellLevel <= 9; nSpellLevel++)
|
|
{
|
|
string sTemp = Get2DACache(sFile, "SpellLevel" + IntToString(nSpellLevel), nCasterLevel);
|
|
if (sTemp != "")
|
|
{
|
|
bFound = TRUE;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (!bFound) nSpellLevel = -1;
|
|
return nSpellLevel;
|
|
}
|
|
|
|
// wipes the IPbonusfeat from the hide
|
|
void WipeSpellFromHide(int nIPFeatID, object oPC)
|
|
{
|
|
// go through all item properties on the hide
|
|
object oHide = GetPCSkin(oPC);
|
|
itemproperty ipTest = GetFirstItemProperty(oHide);
|
|
while(GetIsItemPropertyValid(ipTest))
|
|
{
|
|
// is it a bonus feat?
|
|
if(GetItemPropertyType(ipTest) == ITEM_PROPERTY_BONUS_FEAT)
|
|
{
|
|
// get the row nr of the bonus feat in iprp_feat.2da
|
|
// is it the ipfeat to delete?
|
|
if (GetItemPropertySubType(ipTest) == nIPFeatID)
|
|
{
|
|
RemoveItemProperty(oHide, ipTest);
|
|
if(DEBUG) DoDebug("WipeSpellFromHide: Removing item property " + DebugIProp2Str(ipTest));
|
|
}
|
|
}
|
|
ipTest = GetNextItemProperty(oHide);
|
|
}
|
|
}
|
|
|
|
// one array for each class (array holds all spell levels, but only non-metamagicked masterspells)
|
|
string GetSpellsKnown_Array(int nClass, int nSpellLevel = -1)
|
|
{
|
|
int nSpellbookType = GetSpellbookTypeForClass(nClass);
|
|
if(nSpellbookType == SPELLBOOK_TYPE_PREPARED)
|
|
return "Spellbook_Known_" + IntToString(nClass) + "_" + IntToString(nSpellLevel);
|
|
return "Spellbook" + IntToString(nClass);
|
|
}
|
|
|
|
// class spellbook (one storage token for each spell level and class)
|
|
object GetSpellsOfClass_Token(int nClass, int nSpellLevel)
|
|
{
|
|
return GetObjectByTag("SpellLvl_" + IntToString(nClass) + "_Level_" + IntToString(nSpellLevel));
|
|
}
|
|
|
|
string GetSpellsOfClass_Array()
|
|
{
|
|
return "Lkup";
|
|
}
|
|
|
|
string GetSpellsMemorized_Array(int nClass)
|
|
{
|
|
return "NewSpellbookMem_" + IntToString(nClass);
|
|
}
|
|
|
|
string GetSpellsToBeMemorized_Array(int nClass, int nSpellSlotLevel)
|
|
{
|
|
return "Spellbook" + IntToString(nSpellSlotLevel) + "_" + IntToString(nClass);
|
|
}
|
|
|
|
|
|
void array_set_size(object oPC, string sArrayName, int nSize)
|
|
{
|
|
SetPersistantLocalInt(oPC, sArrayName, nSize+1);
|
|
}
|
|
|
|
int array_has_string(object oPC, string sArrayName, string sValue, int nFirst = 0, int nSize = 0)
|
|
{
|
|
// get array size, if size not already supplied
|
|
if (nSize == 0) nSize = GetPersistantLocalInt(oPC, sArrayName) -1;
|
|
int i;
|
|
|
|
for (i = nFirst; i < nSize; i++)
|
|
{
|
|
if (sValue == GetPersistantLocalString(oPC, sArrayName + "_" + IntToString(i)))
|
|
return i;
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
int array_has_int(object oPC, string sArrayName, int nValue, int nFirst = 0, int nSize = 0)
|
|
{
|
|
// array values are stored as strings, so convert nValue to a string
|
|
return array_has_string(oPC, sArrayName, IntToString(nValue), nFirst, nSize);
|
|
}
|
|
|
|
int persistant_array_has_string(object oPC, string sArrayName, string sValue, int nFirst = 0, int nSize = 0)
|
|
{
|
|
return array_has_string(oPC, sArrayName, sValue, nFirst, nSize);
|
|
}
|
|
|
|
int persistant_array_has_int(object oPC, string sArrayName, int nValue, int nFirst = 0, int nSize = 0)
|
|
{
|
|
return array_has_string(oPC, sArrayName, IntToString(nValue), nFirst, nSize);
|
|
}
|
|
|
|
int array_extract_string(object oPC, string sArrayName, string sValue, int nFirst = 0)
|
|
{
|
|
// get array size
|
|
int nSize = GetPersistantLocalInt(oPC, sArrayName)-1;
|
|
if (nSize <= nFirst) return -1;
|
|
|
|
// position of the first found; -1 if not found
|
|
int nPos = array_has_string(oPC, sArrayName, sValue, nFirst, nSize);
|
|
if (nPos < 0) return -1;
|
|
|
|
// Is is not the last element?
|
|
if (nPos < nSize-1)
|
|
{
|
|
// then swap nPos (or rather nPos-1) with the last element (nSize-1)
|
|
string sTemp = GetPersistantLocalString(oPC, sArrayName + "_" + IntToString(nSize-1));
|
|
SetPersistantLocalString(oPC, sArrayName + "_" + IntToString(nPos), sTemp);
|
|
}
|
|
|
|
// now decrement the array size (note that we already subtracted one in the beginning)
|
|
SetPersistantLocalInt(oPC, sArrayName, nSize);
|
|
|
|
return nPos;
|
|
}
|
|
|
|
// extracts the integer value nValue from a persistant sArray on oPC
|
|
// extracts the first instance of nValue that it finds
|
|
// extracts it by swapping the last array element to the position of the extracted element and reducing the array size by one
|
|
// returns the position where the extracted element was found
|
|
int array_extract_int(object oPC, string sArrayName, int nValue, int nFirst = 0)
|
|
{
|
|
// array values are stored as strings, so convert nValue to a string
|
|
return array_extract_string(oPC, sArrayName, IntToString(nValue), nFirst);
|
|
}
|
|
|
|
int persistant_array_extract_string(object oPC, string sArrayName, string sValue, int nFirst = 0)
|
|
{
|
|
return array_extract_string(oPC, sArrayName, sValue, nFirst);
|
|
}
|
|
|
|
int persistant_array_extract_int(object oPC, string sArrayName, int nValue, int nFirst = 0)
|
|
{
|
|
// array values are stored as strings, so convert nValue to a string
|
|
return array_extract_string(oPC, sArrayName, IntToString(nValue), nFirst);
|
|
}
|
|
|
|
string GetMetaMagicString_Short(int nMetaMagic)
|
|
{
|
|
string s;
|
|
if (nMetaMagic == 0) return s;
|
|
|
|
if (nMetaMagic & METAMAGIC_EXTEND) s += "ext ";
|
|
if (nMetaMagic & METAMAGIC_SILENT) s += "sil ";
|
|
if (nMetaMagic & METAMAGIC_STILL) s += "sti ";
|
|
if (nMetaMagic & METAMAGIC_EMPOWER) s += "emp ";
|
|
if (nMetaMagic & METAMAGIC_MAXIMIZE) s += "max ";
|
|
if (nMetaMagic & METAMAGIC_QUICKEN) s += "qui ";
|
|
|
|
return GetStringLeft(s, GetStringLength(s)-1);
|
|
}
|
|
|
|
string GetMetaMagicString(int nMetaMagic)
|
|
{
|
|
string s;
|
|
if (nMetaMagic == 0) return s;
|
|
|
|
if (nMetaMagic & METAMAGIC_EXTEND) s += "extend ";
|
|
if (nMetaMagic & METAMAGIC_SILENT) s += "silent ";
|
|
if (nMetaMagic & METAMAGIC_STILL) s += "still ";
|
|
if (nMetaMagic & METAMAGIC_EMPOWER) s += "empower ";
|
|
if (nMetaMagic & METAMAGIC_MAXIMIZE) s += "maximize ";
|
|
if (nMetaMagic & METAMAGIC_QUICKEN) s += "quicken ";
|
|
|
|
return GetStringLeft(s, GetStringLength(s)-1);
|
|
}
|
|
|
|
int GetMetaMagicFromFeat(int nFeat)
|
|
{
|
|
switch(nFeat)
|
|
{
|
|
case FEAT_EMPOWER_SPELL: return METAMAGIC_EMPOWER;
|
|
case FEAT_EXTEND_SPELL: return METAMAGIC_EXTEND;
|
|
case FEAT_MAXIMIZE_SPELL: return METAMAGIC_MAXIMIZE;
|
|
case FEAT_QUICKEN_SPELL: return METAMAGIC_QUICKEN;
|
|
case FEAT_SILENCE_SPELL: return METAMAGIC_SILENT;
|
|
case FEAT_STILL_SPELL: return METAMAGIC_STILL;
|
|
}
|
|
return METAMAGIC_NONE;
|
|
}
|
|
|
|
int GetMetaMagicOfCaster(object oPC = OBJECT_SELF)
|
|
{
|
|
int nMetaMagic;
|
|
|
|
if (GetHasFeat(FEAT_EMPOWER_SPELL, oPC)) nMetaMagic |= METAMAGIC_EMPOWER;
|
|
if (GetHasFeat(FEAT_EXTEND_SPELL, oPC)) nMetaMagic |= METAMAGIC_EXTEND;
|
|
if (GetHasFeat(FEAT_MAXIMIZE_SPELL, oPC)) nMetaMagic |= METAMAGIC_MAXIMIZE;
|
|
if (GetHasFeat(FEAT_QUICKEN_SPELL, oPC)) nMetaMagic |= METAMAGIC_QUICKEN;
|
|
if (GetHasFeat(FEAT_SILENCE_SPELL, oPC)) nMetaMagic |= METAMAGIC_SILENT;
|
|
if (GetHasFeat(FEAT_STILL_SPELL, oPC)) nMetaMagic |= METAMAGIC_STILL;
|
|
|
|
return nMetaMagic;
|
|
} |