Initial upload.
Adding base PRC 4.19a files to repository.
This commit is contained in:
622
trunk/users/Stratovarius/NWNEE Updates/PRC_S_spellb.nss
Normal file
622
trunk/users/Stratovarius/NWNEE Updates/PRC_S_spellb.nss
Normal file
@@ -0,0 +1,622 @@
|
||||
//:://////////////////////////////////////////////
|
||||
//:: PRC New Spellbooks use conversation
|
||||
//:: prc_s_spellb
|
||||
//:://////////////////////////////////////////////
|
||||
/** @file
|
||||
@todo Primo: Could you write a blurb on what
|
||||
this does and TLKify it?
|
||||
|
||||
|
||||
@author Primogenitor
|
||||
@date Created - yyyy.mm.dd
|
||||
|
||||
last changed by motu99, April 29, 2008:
|
||||
|
||||
Conversation script for setting up spells to be memorized by prepared casters
|
||||
|
||||
This conversation script sets up a persistent array of the spells to be memorized
|
||||
(at the end of the next rest) for any newspellbook prepared caster class.
|
||||
|
||||
It uses the persistent array name prefix "Spellbook", then appends the spell level
|
||||
(converted to a string) to the prefix and lastly appends the class-nr (converted to a string)
|
||||
|
||||
The thus appended prefix is a persistent array name, in which the nSpellbookIDs of the
|
||||
spells to be memorized at the end of the next rest are stored
|
||||
|
||||
the conversation is called by activating the prc_spellbook feat (#1999 in feats.2da)
|
||||
which fires the spellscript prc_spellbook (#1792 in spells.2da), which then calls this
|
||||
conversation script
|
||||
*/
|
||||
//:://////////////////////////////////////////////
|
||||
//:://////////////////////////////////////////////
|
||||
|
||||
|
||||
// persistant storage format on hide
|
||||
/**
|
||||
MEMORIZED SPELLS FOR PREP CASTERS:
|
||||
All spell levels are all stored in one single array (motu99: very unfortunate, should be changed):
|
||||
sArrayName = "NewSpellbookMem_"+IntToString(nClass)
|
||||
The array is indexed by the spellbookID; the value is the number of spells with that spellbookID still in memory:
|
||||
nNrOfSpellsStillInMemory = sArrayName[nSpellbookID]
|
||||
|
||||
SPELLS TO BE MEMORIZED BY PREP CASTERS
|
||||
They are stored in up to ten arrays, one array for each spell level (or rather spell slot level)
|
||||
sArrayName = "Spellbook"+IntToString(nSpellLevel)+"_"+IntToString(nClass)
|
||||
The array is indexed by the slot number, starting at #0; the value contains the nSpelllbookID of the spell to be memorized
|
||||
nSpellbookID = sArrayName[nSlotNr]
|
||||
|
||||
SPELLS MEMORIZED BY PREP CASTERS - INDEX
|
||||
Array created from "spells to be memorized" in OnRest event. Only unique spellids are stored.
|
||||
sArrayName = "SpellbookIDX"+IntToString(nSpellLevel)+"_"+IntToString(nClass)
|
||||
Serves as "NewSpellbookMem_" index for fast search and delete - allows looping only through memorized SpellbookIDs
|
||||
(archivist - max 56 + bonus slots from high WIS) instead of all SpellbookIDs (archivist - 2400+)
|
||||
Should help reduce instruction count sagnificantly.
|
||||
|
||||
SPELLS KNOWN BY PREP CASTERS:
|
||||
so far prep NSB casters know all spells in their class spellbook; they need not learn spells
|
||||
motu99: This might change, if for instance wizards use the NSB system to gain higher spell slot levels (10+)
|
||||
//for archivist:
|
||||
They are stored in up to ten arrays, one array for each spell level (or rather spell slot level)
|
||||
sArrayName = "Spellbook_Known_"+IntToString(nClass)+"_"+IntToString(nSpellLevel)
|
||||
|
||||
SPELLS KNOWN BY SPONT CASTERS:
|
||||
The spells known are stored in one single array (the array contains only the non-metamagic versions and only master spells)
|
||||
sArrayName = "Spellbook" + IntToString(nClass);
|
||||
The array is indexed by a counter (the i-th spell learned); the value contains the nSpellbookID of the (non-metamagic master) spell known
|
||||
nSpellbookID = sArrayName[i]
|
||||
|
||||
AVAILABLE SPELL SLOTS FOR SPONT CASTERS:
|
||||
The nr of still available spell slots for a prep caster are all stored in one single array
|
||||
sArrayName = "NewSpellbookMem_" + IntToString(nClass)
|
||||
The array is indexed by the spell (slot) level, the value contains the nr of still available slots at that spell (slot) level
|
||||
nNrOfSpellSlotsAvailable = sArrayName[nSpellSlotLevel]
|
||||
*/
|
||||
|
||||
// spells in the class spellbook of nClass (a spont caster generally will not know all of these spells)
|
||||
/**
|
||||
SPELLS IN THE CLASS SPELLBOOK OF PREP OR SPONT CASTERS:
|
||||
The spells that are potentially learnable by nClass are stored on the prc cache object in up to 10 different tokens.
|
||||
The class spell book ONLY stores the masterspells and ONLY the non-metamagicked version!
|
||||
|
||||
There is one storage token for every spell level (and class); it has the tag name:
|
||||
sTag = "SpellLvl_"+IntToString(nClass)+"_Level_"+IntToString(nSpellLevel);
|
||||
The spells are stored on the token object oToken (defined by the unique sTag) in an array with name sArrayName
|
||||
oToken = GetObjectByTag(sTag)
|
||||
sArrayName = "Lkup"
|
||||
The array is indexed by a counter (the i-th spell of a given level in the class spellbook); the value is the spellbookID
|
||||
nSpellbookID = sArrayName[i]
|
||||
*/
|
||||
|
||||
#include "x2_inc_spellhook"
|
||||
#include "inc_dynconv"
|
||||
#include "inc_sp_gain_mem"
|
||||
|
||||
//////////////////////////////////////////////////
|
||||
/* Constant defintions */
|
||||
//////////////////////////////////////////////////
|
||||
|
||||
const int STAGE_SELECT_CLASS = 0;
|
||||
const int STAGE_SELECT_SPELL_LEVEL = 1;
|
||||
const int STAGE_SELECT_SPELL_SLOT = 2;
|
||||
const int STAGE_SELECT_METAMAGIC = 3;
|
||||
const int STAGE_SELECT_SPELL = 4;
|
||||
|
||||
const int CHOICE_RETURN_TO_PREVIOUS = 0xEFFFFFFF;
|
||||
|
||||
|
||||
const string CONV_SPELLB_CLASS = "SpellClass";
|
||||
const string CONV_SPELLB_LEVEL = "SpellLevel";
|
||||
const string CONV_SPELLB_META = "MetaMagic";
|
||||
const string CONV_SPELLB_SLOT = "SpellSlot";
|
||||
|
||||
const int DYNCONV_NEXT_STAGE = -4;
|
||||
|
||||
|
||||
//////////////////////////////////////////////////
|
||||
/* Aid functions */
|
||||
//////////////////////////////////////////////////
|
||||
|
||||
const string SPELLS_MEMORIZED_CACHE = "SMCCCache";
|
||||
|
||||
void DeleteSpellsMemorizedCache(object oPC)
|
||||
{
|
||||
int i;
|
||||
for (i=1; i <= MAX_CLASSES; i++)
|
||||
{
|
||||
int nClass = GetClassByPosition(i, oPC);
|
||||
if (nClass == CLASS_TYPE_INVALID) break;
|
||||
|
||||
if(GetLocalInt(oPC, SPELLS_MEMORIZED_CACHE + IntToString(nClass)))
|
||||
{
|
||||
DeleteLocalInt(oPC, SPELLS_MEMORIZED_CACHE + IntToString(nClass));
|
||||
DeleteLocalString(oPC, SPELLS_MEMORIZED_CACHE + IntToString(nClass) + "_" + "0");
|
||||
DeleteLocalString(oPC, SPELLS_MEMORIZED_CACHE + IntToString(nClass) + "_" + "1");
|
||||
DeleteLocalString(oPC, SPELLS_MEMORIZED_CACHE + IntToString(nClass) + "_" + "2");
|
||||
DeleteLocalString(oPC, SPELLS_MEMORIZED_CACHE + IntToString(nClass) + "_" + "3");
|
||||
DeleteLocalString(oPC, SPELLS_MEMORIZED_CACHE + IntToString(nClass) + "_" + "4");
|
||||
DeleteLocalString(oPC, SPELLS_MEMORIZED_CACHE + IntToString(nClass) + "_" + "5");
|
||||
DeleteLocalString(oPC, SPELLS_MEMORIZED_CACHE + IntToString(nClass) + "_" + "6");
|
||||
DeleteLocalString(oPC, SPELLS_MEMORIZED_CACHE + IntToString(nClass) + "_" + "7");
|
||||
DeleteLocalString(oPC, SPELLS_MEMORIZED_CACHE + IntToString(nClass) + "_" + "8");
|
||||
DeleteLocalString(oPC, SPELLS_MEMORIZED_CACHE + IntToString(nClass) + "_" + "9");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// now build the cache
|
||||
void GenerateSpellsMemorizedCache(int nClass, object oPC)
|
||||
{
|
||||
// get the object on the hide of oPC where the persistant data are stored
|
||||
object oToken = GetHideToken(oPC);
|
||||
string sSpellsMemorized = GetSpellsMemorized_Array(nClass);
|
||||
|
||||
// if the persistant array with the remaining memorized spells does not exist, abort
|
||||
if(!array_exists(oToken, sSpellsMemorized))
|
||||
{
|
||||
if(DEBUG) DoDebug("Error: " +sSpellsMemorized+ " array does not exist");
|
||||
}
|
||||
else
|
||||
{
|
||||
string sFile = GetNSBDefinitionFileName(nClass);
|
||||
string sArrayIDX, sSpellbookID, sMessage, sMess, sClass = IntToString(nClass);
|
||||
|
||||
// remember the class (because this might change during the conversation)
|
||||
SetLocalInt(oPC, SPELLS_MEMORIZED_CACHE + sClass, TRUE);
|
||||
|
||||
int nSpellLevel, nSlot, nSlots, nSpellbookID;
|
||||
for(nSpellLevel = 0; nSpellLevel <= 9; nSpellLevel++)
|
||||
{
|
||||
sArrayIDX = "SpellbookIDX" + IntToString(nSpellLevel) + "_" + sClass;
|
||||
sMessage = "";
|
||||
nSlots = array_get_size(oToken, sArrayIDX);
|
||||
for(nSlot = 0; nSlot < nSlots; nSlot++)
|
||||
{
|
||||
nSpellbookID = array_get_int(oToken, sArrayIDX, nSlot);
|
||||
int nCount = nSpellbookID ? array_get_int(oToken, sSpellsMemorized, nSpellbookID) : 0;
|
||||
if(nCount)
|
||||
{
|
||||
// determine spell name from spellID by reference
|
||||
int nSpellID = StringToInt(Get2DACache(sFile, "RealSpellID", nSpellbookID));
|
||||
sMess = PRC_TEXT_WHITE + GetStringByStrRef(StringToInt(Get2DACache("spells", "Name", nSpellID)));
|
||||
// add the metamagic [ext emp]
|
||||
int nMetaMagicFeat = StringToInt(Get2DACache(sFile, "ReqFeat", nSpellbookID));
|
||||
if(nMetaMagicFeat)
|
||||
{
|
||||
int nMetaMagic = GetMetaMagicFromFeat(nMetaMagicFeat);
|
||||
sMess += " - " +GetMetaMagicString(nMetaMagic);
|
||||
}
|
||||
// add the nr of spells in memory
|
||||
sMess += PRC_TEXT_BLUE + " [" +IntToString(nCount)+ "]\n";
|
||||
sMessage += sMess;
|
||||
}
|
||||
}
|
||||
// now store the values for later retrieval
|
||||
if (sMessage != "") SetLocalString(oPC, SPELLS_MEMORIZED_CACHE + sClass + "_" + IntToString(nSpellLevel), sMessage);
|
||||
}
|
||||
}
|
||||
|
||||
// we delete the cached values on exit from the conversation, so no need to do it now
|
||||
// DelayCommand(6.0, DeleteSpellsMemorizedCache(oPC));
|
||||
}
|
||||
|
||||
// creates a string with a list of memorized spells of the given nClass and nSpellSlotLevel
|
||||
// each spell has an extra line, which denotes the spell's name
|
||||
string ListMemorizedSpells(int nClass, int nSpellSlotLevel, object oPC)
|
||||
{
|
||||
// try to get the list from cache; but only if cache is for the correct nClass
|
||||
//if (GetLocalInt(oPC, SPELLS_MEMORIZED_CACHE) == nClass)
|
||||
//{
|
||||
return GetLocalString(oPC, SPELLS_MEMORIZED_CACHE + IntToString(nClass) + "_" + IntToString(nSpellSlotLevel));
|
||||
//}
|
||||
}
|
||||
|
||||
|
||||
//////////////////////////////////////////////////
|
||||
/* Main function */
|
||||
//////////////////////////////////////////////////
|
||||
|
||||
void main()
|
||||
{
|
||||
object oPC = GetPCSpeaker();
|
||||
/* Get the value of the local variable set by the conversation script calling
|
||||
* this script. Values:
|
||||
* DYNCONV_ABORTED Conversation aborted
|
||||
* DYNCONV_EXITED Conversation exited via the exit node
|
||||
* DYNCONV_SETUP_STAGE System's reply turn
|
||||
* 0 Error - something else called the script
|
||||
* Other The user made a choice
|
||||
*/
|
||||
int nValue = GetLocalInt(oPC, DYNCONV_VARIABLE);
|
||||
// The stage is used to determine the active conversation node.
|
||||
// 0 is the entry node.
|
||||
int nStage = GetStage(oPC);
|
||||
|
||||
// Check which of the conversation scripts called the scripts
|
||||
if(nValue == 0) // All of them set the DynConv_Var to non-zero value, so something is wrong -> abort
|
||||
return;
|
||||
|
||||
if(nValue == DYNCONV_SETUP_STAGE)
|
||||
{
|
||||
// Check if this stage is marked as already set up
|
||||
// This stops list duplication when scrolling
|
||||
if(!GetIsStageSetUp(nStage, oPC))
|
||||
{
|
||||
if(nStage == STAGE_SELECT_CLASS)
|
||||
{
|
||||
//select spell class
|
||||
SetHeader("Select a spell book:");
|
||||
int i;
|
||||
for (i=1; i <= MAX_CLASSES; i++)
|
||||
{
|
||||
int nClass = GetClassByPosition(i, oPC);
|
||||
if (nClass == CLASS_TYPE_INVALID) break;
|
||||
|
||||
if(GetIsNSBClass(nClass) && // must be a new spellbook class
|
||||
GetSpellbookTypeForClass(nClass) == SPELLBOOK_TYPE_PREPARED) // must be a prepared caster
|
||||
{
|
||||
// must have levels in the prepared class and at least level 1 spell slots
|
||||
int nAbilityScore = GetAbilityScoreForClass(nClass, oPC);
|
||||
int nClassLevel = GetLevelByPosition(i, oPC);
|
||||
if(nClassLevel
|
||||
&& (GetSlotCount(nClassLevel, 0, nAbilityScore, nClass)
|
||||
|| GetSlotCount(nClassLevel, 1, nAbilityScore, nClass)))
|
||||
{
|
||||
string sClassName = GetStringByStrRef(StringToInt(Get2DACache("classes", "Name", nClass)));
|
||||
GenerateSpellsMemorizedCache(nClass, oPC);
|
||||
AddChoice(sClassName, nClass, oPC);
|
||||
}
|
||||
}
|
||||
}
|
||||
SetDefaultTokens(); // Set the next, previous, exit and wait tokens to default values
|
||||
MarkStageSetUp(nStage, oPC);
|
||||
}
|
||||
else if(nStage == STAGE_SELECT_SPELL_LEVEL)
|
||||
{
|
||||
int nClass = GetLocalInt(oPC, CONV_SPELLB_CLASS);
|
||||
int nCasterLevel = GetCasterLevelByClass(nClass, oPC);
|
||||
|
||||
int nMaxSpellSlotLevel = GetMaxSpellLevelForCasterLevel(nClass, nCasterLevel);
|
||||
int nMinSpellSlotLevel = GetMinSpellLevelForCasterLevel(nClass, nCasterLevel);
|
||||
|
||||
int nChoiceAdded = FALSE;
|
||||
|
||||
if(nMaxSpellSlotLevel >= nMinSpellSlotLevel)
|
||||
{
|
||||
string sChoiceSpellLevel = "Spell slot level ";
|
||||
int nAbilityScore = GetAbilityScoreForClass(nClass, oPC);
|
||||
|
||||
// List all spell slot levels available to the caster for this class
|
||||
int nSpellSlotLevel;
|
||||
for(nSpellSlotLevel = nMinSpellSlotLevel; nSpellSlotLevel <= nMaxSpellSlotLevel; nSpellSlotLevel++)
|
||||
{
|
||||
// for every spell level, determine the slot count, and if it is non-zero add a choice
|
||||
// we do not break out of the loop on an empty slot count, because of bonus slot counts from items there might be gaps
|
||||
if(GetSlotCount(nCasterLevel, nSpellSlotLevel, nAbilityScore, nClass))
|
||||
{
|
||||
AddChoice(sChoiceSpellLevel +IntToString(nSpellSlotLevel), nSpellSlotLevel, oPC);
|
||||
nChoiceAdded = TRUE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (nChoiceAdded)
|
||||
SetHeader("Select a spell slot level:");
|
||||
else
|
||||
SetHeader("You cannot memorize any spells at the moment - check your ability score");
|
||||
|
||||
SetDefaultTokens(); // Set the next, previous, exit and wait tokens to default values
|
||||
MarkStageSetUp(nStage, oPC);
|
||||
}
|
||||
else if(nStage == STAGE_SELECT_SPELL_SLOT)
|
||||
{
|
||||
int nClass = GetLocalInt(oPC, CONV_SPELLB_CLASS);
|
||||
int nSpellSlotLevel = GetLocalInt(oPC, CONV_SPELLB_LEVEL);
|
||||
int nCasterLevel = GetCasterLevelByClass(nClass, oPC);
|
||||
|
||||
int nAbilityScore = GetAbilityScoreForClass(nClass, oPC);
|
||||
|
||||
// get the object on the hide of oPC where the persistant data are stored
|
||||
//object oToken = GetHideToken(oPC);
|
||||
|
||||
// determine the name of the persistant array that holds the spells to be memorized for the given nClass and nSpellLevel
|
||||
// (the index to the array is the nr of the slot of the given nClass and nSpellLevel)
|
||||
string sSpellsToBeMemorized = GetSpellsToBeMemorized_Array(nClass, nSpellSlotLevel);
|
||||
// unfortunatly, the spellsMemorized list has a different format (all spell levels in one huge sparse array, indexed by nSpellbookID)
|
||||
string sSpellsMemorized = GetSpellsMemorized_Array(nClass);
|
||||
|
||||
// now check if the arrays "spells to be memorized" and "spells memorized" exist at the given spell slot level and create them, if not
|
||||
if (persistant_array_get_size(oPC, sSpellsToBeMemorized) < 0) persistant_array_create(oPC, sSpellsToBeMemorized);
|
||||
if (persistant_array_get_size(oPC, sSpellsMemorized) < 0) persistant_array_create(oPC, sSpellsMemorized);
|
||||
|
||||
string sHeader = "You have remaining:\n";
|
||||
sHeader += ListMemorizedSpells(nClass, nSpellSlotLevel, oPC) + "\n";
|
||||
|
||||
// get the nr of spell slots for the given nClass and nSpellLevel
|
||||
// (should be non-zero, because we only allow the PC to select spell slot levels with non-zero slot count)
|
||||
int nSlots = GetSlotCount(nCasterLevel, nSpellSlotLevel, nAbilityScore, nClass, oPC);
|
||||
if (nSlots > 0)
|
||||
{
|
||||
sHeader += "Select a spell slot:\n"+ PRC_TEXT_WHITE + "spell to be memorized " + PRC_TEXT_BLUE + "[# still in memory]";
|
||||
|
||||
// set the array size of "spells to be memorized" and "spells memorized" to the nr of slots. +1 to skip 0s
|
||||
SQLocals_SetInt(oPC, sSpellsToBeMemorized, nSlots+1);
|
||||
|
||||
string sFile = GetNSBDefinitionFileName(nClass);
|
||||
string sChoice;
|
||||
string sNameToBeMemorized;
|
||||
// add a choice for every slot; show what is currently in the slot (if nothing, show "empty")
|
||||
int nSlotNr;
|
||||
for(nSlotNr = 0; nSlotNr < nSlots; nSlotNr++)
|
||||
{
|
||||
// get the spell associated with the i-th slot
|
||||
int nSpellbookID = persistant_array_get_int(oPC, sSpellsToBeMemorized, nSlotNr);
|
||||
int nMetaMagic = 0;
|
||||
// nothing "to be memorized" for this slot?
|
||||
if (nSpellbookID == 0)
|
||||
{
|
||||
sNameToBeMemorized = "Empty";
|
||||
}
|
||||
else
|
||||
{
|
||||
// get the spell name "to be memorized", including metamagic
|
||||
// int nIPFeatID = StringToInt(Get2DACache(sFile, "IPFeatID", nSpellbookID));
|
||||
// sNameToBeMemorized = GetStringByStrRef(StringToInt(Get2DACache("iprp_feats", "Name", nIPFeatID)));
|
||||
int nSpellID = StringToInt(Get2DACache(sFile, "RealSpellID", nSpellbookID));
|
||||
sNameToBeMemorized = GetStringByStrRef(StringToInt(Get2DACache("spells", "Name", nSpellID)));
|
||||
|
||||
nMetaMagic = GetMetaMagicFromFeat(StringToInt(Get2DACache(sFile, "ReqFeat", nSpellbookID)));
|
||||
if (nMetaMagic) sNameToBeMemorized += " - " + GetMetaMagicString(nMetaMagic);
|
||||
}
|
||||
|
||||
//first we show what spell will "be memorized" at next rest from the given slot (this is in white)
|
||||
sChoice = PRC_TEXT_WHITE + sNameToBeMemorized;
|
||||
|
||||
// now check if there are spells still in memory that are equal to the spell "to be memorized" at the given slot
|
||||
if (nSpellbookID)
|
||||
{
|
||||
int nNrOfSpells_Mem = persistant_array_get_int(oPC, sSpellsMemorized, nSpellbookID);
|
||||
// show in blue and in brackets
|
||||
sChoice += PRC_TEXT_BLUE + " [" +IntToString(nNrOfSpells_Mem)+ "]";
|
||||
}
|
||||
|
||||
// add the slot nr as choice
|
||||
AddChoice(sChoice, nSlotNr, oPC);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
sHeader += PRC_TEXT_WHITE + "there aren't any slots available at the chosen level - check your ability score";
|
||||
}
|
||||
SetHeader(sHeader);
|
||||
AddChoice("Back", CHOICE_RETURN_TO_PREVIOUS);
|
||||
SetDefaultTokens(); // Set the next, previous, exit and wait tokens to default values
|
||||
MarkStageSetUp(nStage, oPC);
|
||||
}
|
||||
else if (nStage == STAGE_SELECT_METAMAGIC)
|
||||
{
|
||||
// get the metamagic feats oPC possesses
|
||||
int nMetaMagicCaster = GetMetaMagicOfCaster(oPC);
|
||||
int bChoiceAdded;
|
||||
// only need to do this, if the caster has at least one metamagic feat
|
||||
if (nMetaMagicCaster)
|
||||
{
|
||||
// get the currently selected spell slot level
|
||||
int nSpellSlotLevel = GetLocalInt(oPC, CONV_SPELLB_LEVEL);
|
||||
int nClass = GetLocalInt(oPC, CONV_SPELLB_CLASS);
|
||||
int nCasterLevel = GetCasterLevelByClass(nClass, oPC);
|
||||
int nMinSpellSlotLevel = GetMinSpellLevelForCasterLevel(nClass, nCasterLevel);
|
||||
|
||||
// metamagics only for slot levels higher than the lowest slot level
|
||||
if (nSpellSlotLevel > nMinSpellSlotLevel)
|
||||
{
|
||||
// calculate the maximum metamagic adjustment that is possible at the given spell slot level
|
||||
// note that the metamagic adjustment will generally result in spells to choose from, that are
|
||||
// lower in level than the spell slot level. But we cannot reduce the level below the minimum spell level of the class
|
||||
int nMaxMetaMagicAdj = nSpellSlotLevel - nMinSpellSlotLevel;
|
||||
|
||||
// go through all possible metamagics by shifting 1 to the left
|
||||
// this will result in checking for some metamagics that are not implemented
|
||||
// but the check against the metamagic feats possessed be oPC will get rid of all non-implemented
|
||||
int nMetaMagic;
|
||||
for (nMetaMagic = 1; nMetaMagic < 0x40; nMetaMagic <<= 1)
|
||||
{
|
||||
if ((nMetaMagicCaster & nMetaMagic) // caster must have the metamagic feat
|
||||
// and the combined levels of the already chosen metamagic with the metamagic to choose must be
|
||||
// less or equal than the max metamagic adjustment allowed for nClass at the given nSpellSlotLevel
|
||||
&& GetMetaMagicSpellLevelAdjustment(nMetaMagic) <= nMaxMetaMagicAdj)
|
||||
{
|
||||
AddChoice(GetMetaMagicString(nMetaMagic), nMetaMagic, oPC);
|
||||
bChoiceAdded = TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
if (bChoiceAdded)
|
||||
{
|
||||
SetHeader("Select a metamagic adjustment:");
|
||||
AddChoice("No metamagic", 0, oPC);
|
||||
AddChoice("Back", CHOICE_RETURN_TO_PREVIOUS);
|
||||
SetDefaultTokens(); // Set the next, previous, exit and wait tokens to default values
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// no metamagics available at the spell slot level?
|
||||
if (!bChoiceAdded)
|
||||
{
|
||||
// then advance to next stage and clear metamagic
|
||||
SetStage(++nStage, oPC);
|
||||
DeleteLocalInt(oPC, CONV_SPELLB_META);
|
||||
}
|
||||
|
||||
MarkStageSetUp(STAGE_SELECT_METAMAGIC, oPC);
|
||||
}
|
||||
|
||||
// if-clause is intentional; DONT change to else-if
|
||||
if(nStage == STAGE_SELECT_SPELL)
|
||||
{
|
||||
int nClass = GetLocalInt(oPC, CONV_SPELLB_CLASS);
|
||||
int nMetaMagic = GetLocalInt(oPC, CONV_SPELLB_META);
|
||||
int nSpellSlotLevel = GetLocalInt(oPC, CONV_SPELLB_LEVEL);
|
||||
int nSpellLevel = nSpellSlotLevel - GetMetaMagicSpellLevelAdjustment(nMetaMagic);
|
||||
|
||||
// determine from where to get the spells known (for nClass at the given level)
|
||||
// so far this is the class spellbook, eg. all spells are available (divine casters)
|
||||
string sFile = GetNSBDefinitionFileName(nClass);
|
||||
object oToken;
|
||||
string sSpellBook;
|
||||
if(bKnowsAllClassSpells(nClass))
|
||||
{
|
||||
oToken = GetSpellsOfClass_Token(nClass, nSpellLevel);
|
||||
sSpellBook = GetSpellsOfClass_Array();
|
||||
}
|
||||
else
|
||||
{
|
||||
oToken = GetHideToken(oPC);
|
||||
sSpellBook = GetSpellsKnown_Array(nClass, nSpellLevel);
|
||||
}
|
||||
|
||||
// go through all spells that oPC has in his spellbook at the given nSpellLevel ( for divine casters this might be all)
|
||||
// motu99: This array does NOT include the metamagicked versions of the spells or subradial versions!
|
||||
int nSpellsKnown = array_get_size(oToken, sSpellBook);
|
||||
int bSpellSelected = FALSE;
|
||||
int i;
|
||||
for(i = 0; i < nSpellsKnown; i++)
|
||||
{
|
||||
// this is the cls_spell_* row nr for the UNMETAMAGICKED version of the spell
|
||||
int nSpellbookID = array_get_int(oToken, sSpellBook, i);
|
||||
|
||||
// get the real spellID
|
||||
int nSpellID = StringToInt(Get2DACache(sFile, "RealSpellID", nSpellbookID));
|
||||
|
||||
// if we choose a metamagic, find the nSpellbookID for the metamagic version of the spell
|
||||
// all metamagic versions of the master spell lie in a consecutive block after the non-metamagic version
|
||||
if (nMetaMagic)
|
||||
{
|
||||
// get the next row in cls_spell_* and test if it belongs to the same real spellID
|
||||
while (StringToInt(Get2DACache(sFile, "RealSpellID", ++nSpellbookID)) == nSpellID)
|
||||
{
|
||||
// do the metamagics match?
|
||||
if (nMetaMagic == GetMetaMagicFromFeat(StringToInt(Get2DACache(sFile, "ReqFeat", nSpellbookID))))
|
||||
{
|
||||
// indicate success by negative nr
|
||||
nSpellbookID = -nSpellbookID;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// success? then redo the negation
|
||||
if (nSpellbookID < 0)
|
||||
nSpellbookID = -nSpellbookID;
|
||||
// otherwise indicate failure by setting nSpellbookID to zero
|
||||
else
|
||||
nSpellbookID = 0;
|
||||
}
|
||||
|
||||
// did we find an appropriate spellbook ID for the given spell slot evel and metamagic?
|
||||
// then add it to the list
|
||||
if (nSpellbookID)
|
||||
{
|
||||
// int nIPFeatID = StringToInt(Get2DACache(sFile, "IPFeatID", nSpellbookID));
|
||||
// string sName = GetStringByStrRef(StringToInt(Get2DACache("iprp_feats", "Name", nIPFeatID)));
|
||||
string sName = GetStringByStrRef(StringToInt(Get2DACache("spells", "Name", nSpellID)));
|
||||
if (nMetaMagic) sName + " - " +GetMetaMagicString(nMetaMagic);
|
||||
|
||||
AddChoice(sName, nSpellbookID, oPC);
|
||||
bSpellSelected = TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
if (bSpellSelected)
|
||||
SetHeader("Select a spell:");
|
||||
else
|
||||
SetHeader("No spells to select at spell level " + IntToString (nSpellLevel));
|
||||
|
||||
SetDefaultTokens(); // Set the next, previous, exit and wait tokens to default values
|
||||
MarkStageSetUp(nStage, oPC);
|
||||
}
|
||||
}
|
||||
|
||||
// Do token setup
|
||||
SetupTokens();
|
||||
}
|
||||
else if(nValue == DYNCONV_EXITED ||
|
||||
nValue == DYNCONV_ABORTED )
|
||||
{
|
||||
//end of conversation cleanup
|
||||
DeleteLocalInt(oPC, CONV_SPELLB_CLASS);
|
||||
DeleteLocalInt(oPC, CONV_SPELLB_LEVEL);
|
||||
DeleteLocalInt(oPC, CONV_SPELLB_SLOT);
|
||||
DeleteLocalInt(oPC, CONV_SPELLB_META);
|
||||
|
||||
DeleteSpellsMemorizedCache(oPC);
|
||||
}
|
||||
else
|
||||
{
|
||||
int nChoice = GetChoice(oPC);
|
||||
if(nStage == STAGE_SELECT_CLASS)
|
||||
{
|
||||
//store nClass and proceed to slot level selection
|
||||
SetLocalInt(oPC, CONV_SPELLB_CLASS, nChoice);
|
||||
nStage = STAGE_SELECT_SPELL_LEVEL;
|
||||
MarkStageNotSetUp(nStage, oPC);
|
||||
}
|
||||
else if(nStage == STAGE_SELECT_SPELL_LEVEL)
|
||||
{
|
||||
//store slot level and proceed to spell slot selection
|
||||
SetLocalInt(oPC, CONV_SPELLB_LEVEL, nChoice);
|
||||
nStage = STAGE_SELECT_SPELL_SLOT;
|
||||
MarkStageNotSetUp(nStage, oPC);
|
||||
}
|
||||
else if(nStage == STAGE_SELECT_SPELL_SLOT)
|
||||
{
|
||||
if(nChoice == CHOICE_RETURN_TO_PREVIOUS)
|
||||
nStage = STAGE_SELECT_SPELL_LEVEL;
|
||||
else
|
||||
{
|
||||
// store the spell slot nr and go to metamagic selection phase
|
||||
SetLocalInt(oPC, CONV_SPELLB_SLOT, nChoice);
|
||||
nStage = STAGE_SELECT_METAMAGIC;
|
||||
}
|
||||
MarkStageNotSetUp(nStage, oPC);
|
||||
}
|
||||
else if(nStage == STAGE_SELECT_METAMAGIC)
|
||||
{
|
||||
if(nChoice == CHOICE_RETURN_TO_PREVIOUS)
|
||||
nStage = STAGE_SELECT_SPELL_SLOT;
|
||||
else
|
||||
{
|
||||
// store the metamagic and proceed to spell selection phase
|
||||
SetLocalInt(oPC, CONV_SPELLB_META, nChoice);
|
||||
nStage = STAGE_SELECT_SPELL;
|
||||
}
|
||||
MarkStageNotSetUp(nStage, oPC);
|
||||
}
|
||||
else if(nStage == STAGE_SELECT_SPELL)
|
||||
{
|
||||
// our choice is the nSpellbookID
|
||||
|
||||
// get the other vital information
|
||||
int nSpellSlot = GetLocalInt(oPC, CONV_SPELLB_SLOT);
|
||||
int nSpellSlotLevel = GetLocalInt(oPC, CONV_SPELLB_LEVEL);
|
||||
int nClass = GetLocalInt(oPC, CONV_SPELLB_CLASS);
|
||||
int nMetaMagic = GetLocalInt(oPC, CONV_SPELLB_META);
|
||||
|
||||
// get the object on the hide of oPC where the persistant data are stored
|
||||
object oToken = GetHideToken(oPC);
|
||||
// determine the name of the persistant array that holds the spells to be memorized for the given nClass and nSpellLevel
|
||||
// (the index to the array is the nr of the slot of the given nClass and nSpellLevel)
|
||||
string sSpellsToBeMemorized = GetSpellsToBeMemorized_Array(nClass, nSpellSlotLevel);
|
||||
|
||||
// store the chosen nSpellbookID (row nr in the newspellbook file cls_spells_*) in the spells to be memorized array
|
||||
array_set_int(oToken, sSpellsToBeMemorized, nSpellSlot, nChoice);
|
||||
|
||||
// let oPC select a new spell (starting with the spell level)
|
||||
nStage = STAGE_SELECT_SPELL_LEVEL;
|
||||
MarkStageNotSetUp(nStage, oPC);
|
||||
}
|
||||
|
||||
// Store the stage value. If it has been changed, this clears out the choices
|
||||
SetStage(nStage, oPC);
|
||||
}
|
||||
}
|
||||
|
598
trunk/users/Stratovarius/NWNEE Updates/inc_lookups.nss
Normal file
598
trunk/users/Stratovarius/NWNEE Updates/inc_lookups.nss
Normal file
@@ -0,0 +1,598 @@
|
||||
/*
|
||||
|
||||
This file is used for lookup functions for psionics and newspellbooks
|
||||
It is supposed to reduce the need for large loops that may result in
|
||||
TMI errors.
|
||||
It does this by creating arrays in advance and the using those as direct
|
||||
lookups.
|
||||
*/
|
||||
|
||||
//////////////////////////////////////////////////
|
||||
/* Function prototypes */
|
||||
//////////////////////////////////////////////////
|
||||
|
||||
|
||||
void MakeLookupLoop(int nClass, string sFile, int nMin, int nMax, int nLoopSize = 100, string sTemp = "");
|
||||
void SetupLookupStage(object oMod, int n);
|
||||
|
||||
|
||||
//this returns the real SpellID of "wrapper" spells cast by psionic or the new spellbooks
|
||||
int GetPowerFromSpellID(int nSpellID);
|
||||
|
||||
/**
|
||||
* Maps spells.2da rows of the class-specific entries to corresponding cls_psipw_*.2da rows.
|
||||
*
|
||||
* @param nSpellID Spells.2da row to determine cls_psipw_*.2da row for
|
||||
* @return The mapped value
|
||||
*/
|
||||
int GetPowerfileIndexFromSpellID(int nSpellID);
|
||||
|
||||
/**
|
||||
* Maps spells.2da rows of the real entries to corresponding cls_psipw_*.2da rows.
|
||||
*
|
||||
* @param nSpellID Spells.2da row to determine cls_psipw_*.2da row for
|
||||
* @return The mapped value
|
||||
*/
|
||||
int GetPowerfileIndexFromRealSpellID(int nRealSpellID);
|
||||
|
||||
//this retuns the featID of the class-specific feat for a spellID
|
||||
//useful for psionics GetHasPower function
|
||||
int GetClassFeatFromPower(int nPowerID, int nClass);
|
||||
|
||||
/**
|
||||
* Determines cls_spell_*.2da index from a given new spellbook class-specific
|
||||
* spell spells.2da index.
|
||||
*
|
||||
* @param nSpell The class-specific spell to find cls_spell_*.2da index for
|
||||
* @return The cls_spell_*.2da index in whichever class's file that the
|
||||
* given spell belongs to.
|
||||
* If the spell at nSpell isn't a newspellbook class-specific spell,
|
||||
* returns -1 instead.
|
||||
*/
|
||||
int SpellToSpellbookID(int nSpell);
|
||||
|
||||
/**
|
||||
* Determines cls_spell_*.2da index from a given spells.2da index.
|
||||
*
|
||||
* @param nClass The class in whose spellbook to search in
|
||||
* @param nSpell The spell to search for
|
||||
* @return The cls_spell_*.2da index in whichever class's file that the
|
||||
* given spell belongs to.
|
||||
* If nSpell does not exist within the spellbook,
|
||||
* returns -1 instead.
|
||||
*/
|
||||
int RealSpellToSpellbookID(int nClass, int nSpell);
|
||||
|
||||
/**
|
||||
* Determines number of metamagics from a given spells.2da index.
|
||||
*
|
||||
* @param nClass The class in whose spellbook to search in
|
||||
* @param nSpell The spell to search for
|
||||
* @return The number of metamagics in cls_spell_*.2da
|
||||
* for a particular spell.
|
||||
*/
|
||||
int RealSpellToSpellbookIDCount(int nClass, int nSpell);
|
||||
|
||||
/**
|
||||
* Determines the name of the 2da file that defines the number of alternate magic
|
||||
* system powers/spells/whathaveyou known, maximum level of such known and
|
||||
* number of uses at each level of the given class. And possibly related things
|
||||
* that apply to that specific system.
|
||||
*
|
||||
* @param nClass CLASS_TYPE_* of the class to determine the powers known 2da name of
|
||||
* @return The name of the given class's powers known 2da
|
||||
*/
|
||||
string GetAMSKnownFileName(int nClass);
|
||||
|
||||
/**
|
||||
* Determines the name of the 2da file that lists the powers/spells/whathaveyou
|
||||
* on the given class's list of such.
|
||||
*
|
||||
* @param nClass CLASS_TYPE_* of the class to determine the power list 2da name of
|
||||
* @return The name of the given class's power list 2da
|
||||
*/
|
||||
string GetAMSDefinitionFileName(int nClass);
|
||||
|
||||
//////////////////////////////////////////////////
|
||||
/* Includes */
|
||||
//////////////////////////////////////////////////
|
||||
|
||||
#include "inc_2dacache"
|
||||
#include "inc_array"
|
||||
#include "prc_class_const"
|
||||
|
||||
//////////////////////////////////////////////////
|
||||
/* Internal functions */
|
||||
//////////////////////////////////////////////////
|
||||
|
||||
object _inc_lookups_GetCacheObject(string sTag)
|
||||
{
|
||||
object oWP = GetObjectByTag(sTag);
|
||||
if(!GetIsObjectValid(oWP))
|
||||
{
|
||||
object oChest = GetObjectByTag("Bioware2DACache");
|
||||
if(!GetIsObjectValid(oChest))
|
||||
{
|
||||
//has to be an object, placeables cant go through the DB
|
||||
oChest = CreateObject(OBJECT_TYPE_CREATURE, "prc_2da_cache",
|
||||
GetLocation(GetObjectByTag("HEARTOFCHAOS")), FALSE, "Bioware2DACache");
|
||||
}
|
||||
if(!GetIsObjectValid(oChest))
|
||||
{
|
||||
//has to be an object, placeables cant go through the DB
|
||||
oChest = CreateObject(OBJECT_TYPE_CREATURE, "prc_2da_cache",
|
||||
GetStartingLocation(), FALSE, "Bioware2DACache");
|
||||
}
|
||||
|
||||
int nContainer = 0;
|
||||
string sContainerName = "Bio2DACacheTokenContainer_Lkup_";
|
||||
object oContainer = GetObjectByTag(sContainerName + IntToString(nContainer));
|
||||
|
||||
// Find last existing container
|
||||
if(GetIsObjectValid(oContainer))
|
||||
{
|
||||
nContainer = GetLocalInt(oContainer, "ContainerCount");
|
||||
oContainer = GetObjectByTag(sContainerName + IntToString(nContainer));
|
||||
|
||||
// Make sure it's not full
|
||||
if(GetLocalInt(oContainer, "NumTokensInside") >= 34) // Container has 35 slots. Attempt to not use them all, just in case
|
||||
{
|
||||
oContainer = OBJECT_INVALID;
|
||||
++nContainer; // new container is 1 higher than last one
|
||||
}
|
||||
}
|
||||
|
||||
// We need to create a container
|
||||
if(!GetIsObjectValid(oContainer))
|
||||
{
|
||||
oContainer = CreateObject(OBJECT_TYPE_ITEM, "nw_it_contain001", GetLocation(oChest), FALSE, sContainerName + IntToString(nContainer));
|
||||
DestroyObject(oContainer);
|
||||
oContainer = CopyObject(oContainer, GetLocation(oChest), oChest, sContainerName + IntToString(nContainer));
|
||||
// store the new number of containers in this series
|
||||
if(nContainer)
|
||||
SetLocalInt(GetObjectByTag(sContainerName + "0"), "ContainerCount", nContainer);
|
||||
// else this is the first container - do nothing as this is the same as storing 0 on it.
|
||||
// Also here we still have 2 objects with the same tag so above code may get
|
||||
// the object destroyed at the end of the function if this is the first container.
|
||||
}
|
||||
|
||||
// Create the new token
|
||||
oWP = CreateItemOnObject("hidetoken", oContainer, 1, sTag);
|
||||
|
||||
// Increment token count tracking variable
|
||||
SetLocalInt(oContainer, "NumTokensInside", GetLocalInt(oContainer, "NumTokensInside") + 1);
|
||||
}
|
||||
|
||||
if(!GetIsObjectValid(oWP))
|
||||
{
|
||||
DoDebug("ERROR: Failed to create lookup storage token for " + sTag);
|
||||
return OBJECT_INVALID;
|
||||
}
|
||||
|
||||
return oWP;
|
||||
}
|
||||
|
||||
void SetLkupStage(int nStage, object oModule, int nClass, string sFile)
|
||||
{
|
||||
SetLocalInt(oModule, "PRCLookup_Stage", nStage + 1);
|
||||
SetLocalInt(oModule, "PRCLookup_Class", nClass);
|
||||
SetLocalString(oModule, "PRCLookup_File", sFile);
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////
|
||||
/* Function definitions */
|
||||
//////////////////////////////////////////////////
|
||||
|
||||
void RunLookupLoop()
|
||||
{
|
||||
// check if we run lookup before
|
||||
if(GetXP(GetObjectByTag("Bioware2DACache")) & 0x01)
|
||||
{
|
||||
if (DEBUG) DoDebug("RunLookupLoop() - marker found - exiting");
|
||||
return;
|
||||
}
|
||||
|
||||
object oModule = GetModule();
|
||||
SetupLookupStage(oModule, 1);
|
||||
int nClass = GetLocalInt(oModule, "PRCLookup_Class");
|
||||
string sFile = GetLocalString(oModule, "PRCLookup_File");
|
||||
if (DEBUG) DoDebug("RunLookupLoop(): Looking in "+sFile+" for nClass "+IntToString(nClass));
|
||||
MakeLookupLoop(nClass, sFile, 1, PRCGetDynamicFileEnd(sFile));
|
||||
}
|
||||
|
||||
void RunNextLoop()
|
||||
{
|
||||
object oModule = GetModule();
|
||||
int nStage = GetLocalInt(oModule, "PRCLookup_Stage");
|
||||
SetupLookupStage(oModule, nStage);
|
||||
int nClass = GetLocalInt(oModule, "PRCLookup_Class");
|
||||
if(nClass)
|
||||
{
|
||||
string sFile = GetLocalString(oModule, "PRCLookup_File");
|
||||
if (DEBUG) DoDebug("RunNextLoop(): Looking in "+sFile+" for nClass "+IntToString(nClass));
|
||||
MakeLookupLoop(nClass, sFile, 1, PRCGetDynamicFileEnd(sFile));
|
||||
}
|
||||
else
|
||||
{
|
||||
DeleteLocalInt(oModule, "PRCLookup_Stage");
|
||||
DeleteLocalInt(oModule, "PRCLookup_Class");
|
||||
DeleteLocalString(oModule, "PRCLookup_File");
|
||||
|
||||
//mark lookup as done, tell hb to save the DB
|
||||
object oCache = GetObjectByTag("Bioware2DACache");
|
||||
SetXP(oCache, GetXP(oCache) | 0x01);
|
||||
SetLocalInt(oModule, "Bioware2dacacheCount", GetPRCSwitch(PRC_USE_BIOWARE_DATABASE) - 5);
|
||||
}
|
||||
}
|
||||
|
||||
void SetupLookupStage(object oMod, int n)
|
||||
{
|
||||
switch(n)
|
||||
{
|
||||
case 1: SetLkupStage(n, oMod, CLASS_TYPE_PSION, "cls_psipw_psion"); break;
|
||||
case 2: SetLkupStage(n, oMod, CLASS_TYPE_PSYWAR, "cls_psipw_psywar"); break;
|
||||
case 3: SetLkupStage(n, oMod, CLASS_TYPE_WILDER, "cls_psipw_wilder"); break;
|
||||
case 4: SetLkupStage(n, oMod, CLASS_TYPE_FIST_OF_ZUOKEN, "cls_psipw_foz"); break;
|
||||
case 5: SetLkupStage(n, oMod, CLASS_TYPE_WARMIND, "cls_psipw_warmnd"); break;
|
||||
case 6: SetLkupStage(n, oMod, CLASS_TYPE_TRUENAMER, "cls_true_utter"); break;
|
||||
case 7: SetLkupStage(n, oMod, CLASS_TYPE_CRUSADER, "cls_move_crusdr"); break;
|
||||
case 8: SetLkupStage(n, oMod, CLASS_TYPE_SWORDSAGE, "cls_move_swdsge"); break;
|
||||
case 9: SetLkupStage(n, oMod, CLASS_TYPE_WARBLADE, "cls_move_warbld"); break;
|
||||
case 10: SetLkupStage(n, oMod, CLASS_TYPE_DRAGONFIRE_ADEPT, "cls_inv_dfa"); break;
|
||||
case 11: SetLkupStage(n, oMod, CLASS_TYPE_DRAGON_SHAMAN, "cls_inv_drgshm"); break;
|
||||
case 12: SetLkupStage(n, oMod, CLASS_TYPE_WARLOCK, "cls_inv_warlok"); break;
|
||||
case 13: SetLkupStage(n, oMod, CLASS_TYPE_ARCHIVIST, "cls_spell_archv"); break;
|
||||
case 14: SetLkupStage(n, oMod, CLASS_TYPE_ASSASSIN, "cls_spell_asasin"); break;
|
||||
case 15: SetLkupStage(n, oMod, CLASS_TYPE_BARD, "cls_spell_bard"); break;
|
||||
case 16: SetLkupStage(n, oMod, CLASS_TYPE_BEGUILER, "cls_spell_beguil"); break;
|
||||
case 17: SetLkupStage(n, oMod, CLASS_TYPE_BLACKGUARD, "cls_spell_blkgrd"); break;
|
||||
case 18: SetLkupStage(n, oMod, CLASS_TYPE_DREAD_NECROMANCER, "cls_spell_dnecro"); break;
|
||||
case 19: SetLkupStage(n, oMod, CLASS_TYPE_DUSKBLADE, "cls_spell_duskbl"); break;
|
||||
case 20: SetLkupStage(n, oMod, CLASS_TYPE_FAVOURED_SOUL, "cls_spell_favsol"); break;
|
||||
case 21: SetLkupStage(n, oMod, CLASS_TYPE_HARPER, "cls_spell_harper"); break;
|
||||
case 22: SetLkupStage(n, oMod, CLASS_TYPE_HEALER, "cls_spell_healer"); break;
|
||||
case 23: SetLkupStage(n, oMod, CLASS_TYPE_HEXBLADE, "cls_spell_hexbl"); break;
|
||||
case 24: SetLkupStage(n, oMod, CLASS_TYPE_JUSTICEWW, "cls_spell_justww"); break;
|
||||
case 25: SetLkupStage(n, oMod, CLASS_TYPE_KNIGHT_CHALICE, "cls_spell_kchal"); break;
|
||||
case 26: SetLkupStage(n, oMod, CLASS_TYPE_KNIGHT_MIDDLECIRCLE, "cls_spell_kotmc"); break;
|
||||
case 27: SetLkupStage(n, oMod, CLASS_TYPE_OCULAR, "cls_spell_ocu"); break;
|
||||
case 28: SetLkupStage(n, oMod, CLASS_TYPE_SHADOWLORD, "cls_spell_tfshad"); break;
|
||||
case 29: SetLkupStage(n, oMod, CLASS_TYPE_SHAMAN, "cls_spell_shaman"); break;
|
||||
case 30: SetLkupStage(n, oMod, CLASS_TYPE_SLAYER_OF_DOMIEL, "cls_spell_sod"); break;
|
||||
case 31: SetLkupStage(n, oMod, CLASS_TYPE_SOHEI, "cls_spell_sohei"); break;
|
||||
case 32: SetLkupStage(n, oMod, CLASS_TYPE_SOLDIER_OF_LIGHT, "cls_spell_sol"); break;
|
||||
case 33: SetLkupStage(n, oMod, CLASS_TYPE_SORCERER, "cls_spell_sorc"); break;
|
||||
case 34: SetLkupStage(n, oMod, CLASS_TYPE_SUBLIME_CHORD, "cls_spell_schord"); break;
|
||||
case 35: SetLkupStage(n, oMod, CLASS_TYPE_SUEL_ARCHANAMACH, "cls_spell_suel"); break;
|
||||
case 36: SetLkupStage(n, oMod, CLASS_TYPE_VASSAL, "cls_spell_vassal"); break;
|
||||
case 37: SetLkupStage(n, oMod, CLASS_TYPE_VIGILANT, "cls_spell_vigil"); break;
|
||||
case 38: SetLkupStage(n, oMod, CLASS_TYPE_WARMAGE, "cls_spell_wrmage"); break;
|
||||
case 39: SetLkupStage(n, oMod, CLASS_TYPE_BLIGHTER, "cls_spell_blight"); break;
|
||||
case 40: SetLkupStage(n, oMod, CLASS_TYPE_NENTYAR_HUNTER, "cls_spell_hunter"); break;
|
||||
case 41: SetLkupStage(n, oMod, CLASS_TYPE_KNIGHT_WEAVE, "cls_spell_kngtwv"); break;
|
||||
case 42: SetLkupStage(n, oMod, CLASS_TYPE_PSYCHIC_ROGUE, "cls_psipw_psyrog"); break;
|
||||
case 43: SetLkupStage(n, oMod, CLASS_TYPE_SHADOWCASTER, "cls_myst_shdcst"); break;
|
||||
case 44: SetLkupStage(n, oMod, CLASS_TYPE_SHADOWSMITH, "cls_myst_shdsmt"); break;
|
||||
case 45: SetLkupStage(n, oMod, CLASS_TYPE_CELEBRANT_SHARESS, "cls_spell_sharss"); break;
|
||||
case 46: SetLkupStage(n, oMod, CLASS_TYPE_CULTIST_SHATTERED_PEAK, "cls_spell_cultst"); break;
|
||||
|
||||
default: SetLkupStage(n, oMod, 0, ""); break;
|
||||
}
|
||||
}
|
||||
/*
|
||||
void LookupSpells(int nRealSpellID, string sClass, string sLevel);
|
||||
{
|
||||
int nDescriptor = Get2DACache("prc_spells", "Descriptor", nRealSpellID);//should already be in cache, just read the value
|
||||
|
||||
DESCRIPTOR_ACID
|
||||
DESCRIPTOR_AIR
|
||||
DESCRIPTOR_COLD
|
||||
DESCRIPTOR_LIGHT
|
||||
DESCRIPTOR_ELECTRICITY
|
||||
DESCRIPTOR_DARKNESS
|
||||
DESCRIPTOR_FIRE
|
||||
DESCRIPTOR_SONIC
|
||||
|
||||
|
||||
SUBSCHOOL_HEALING
|
||||
SUBSCHOOL_SUMMONING
|
||||
SUBSCHOOL_POLYMORPH
|
||||
|
||||
SPELL_SCHOOL_ENCHANTMENT
|
||||
SPELL_SCHOOL_NECROMANCY
|
||||
SPELL_SCHOOL_ABJURATION
|
||||
|
||||
string sLevel = Get2DACache("spells", "Cleric", nRealSpellID);
|
||||
if(sLevel != "")
|
||||
{
|
||||
oLevelToken = _inc_lookups_GetCacheObject("SpellLvl_2_Level_"+sLevel);
|
||||
// check if array exist, if not create one
|
||||
if(!array_exists(oLevelToken, "Lkup"))
|
||||
array_create(oLevelToken, "Lkup");
|
||||
array_set_int(oLevelToken, "Lkup", array_get_size(oLevelToken, "Lkup"), i);
|
||||
}
|
||||
sLevel = Get2DACache("spells", "Druid", nRealSpellID);
|
||||
if(sLevel != "")
|
||||
{
|
||||
oLevelToken = _inc_lookups_GetCacheObject("SpellLvl_3_Level_"+sLevel);
|
||||
// check if array exist, if not create one
|
||||
if(!array_exists(oLevelToken, "Lkup"))
|
||||
array_create(oLevelToken, "Lkup");
|
||||
array_set_int(oLevelToken, "Lkup", array_get_size(oLevelToken, "Lkup"), i);
|
||||
}
|
||||
sLevel = Get2DACache("spells", "Paladin", nRealSpellID);
|
||||
if(sLevel != "")
|
||||
{
|
||||
oLevelToken = _inc_lookups_GetCacheObject("SpellLvl_6_Level_"+sLevel);
|
||||
// check if array exist, if not create one
|
||||
if(!array_exists(oLevelToken, "Lkup"))
|
||||
array_create(oLevelToken, "Lkup");
|
||||
array_set_int(oLevelToken, "Lkup", array_get_size(oLevelToken, "Lkup"), i);
|
||||
}
|
||||
sLevel = Get2DACache("spells", "Ranger", nRealSpellID);
|
||||
if(sLevel != "")
|
||||
{
|
||||
oLevelToken = _inc_lookups_GetCacheObject("SpellLvl_7_Level_"+sLevel);
|
||||
// check if array exist, if not create one
|
||||
if(!array_exists(oLevelToken, "Lkup"))
|
||||
array_create(oLevelToken, "Lkup");
|
||||
array_set_int(oLevelToken, "Lkup", array_get_size(oLevelToken, "Lkup"), i);
|
||||
}
|
||||
sLevel = Get2DACache("spells", "Wiz_Sorc", nRealSpellID);
|
||||
if(sLevel != "")
|
||||
{
|
||||
oLevelToken = _inc_lookups_GetCacheObject("SpellLvl_10_Level_"+sLevel);
|
||||
// check if array exist, if not create one
|
||||
if(!array_exists(oLevelToken, "Lkup"))
|
||||
array_create(oLevelToken, "Lkup");
|
||||
array_set_int(oLevelToken, "Lkup", array_get_size(oLevelToken, "Lkup"), i);
|
||||
}
|
||||
|
||||
*/
|
||||
|
||||
|
||||
void MakeLookupLoop(int nClass, string sFile, int nMin, int nMax, int nLoopSize = 100, string sTemp = "")
|
||||
{
|
||||
// Tell the function to skip before reaching nMax
|
||||
int bSkipLoop = FALSE;
|
||||
int i;
|
||||
|
||||
if(DEBUG) DoDebug("MakeLookupLoop("
|
||||
+IntToString(nClass)+", "
|
||||
+sFile+", "
|
||||
+IntToString(nMin)+", "
|
||||
+IntToString(nMax)+", "
|
||||
+IntToString(nLoopSize)+", "
|
||||
+") : sTemp = "+sTemp);
|
||||
|
||||
// psionic, tob, truenameing and ivocation using classes have slightly different handling
|
||||
// new AMS classes should be added here
|
||||
int bAMS = FALSE;
|
||||
|
||||
if(nClass == CLASS_TYPE_PSION
|
||||
|| nClass == CLASS_TYPE_PSYWAR
|
||||
|| nClass == CLASS_TYPE_PSYCHIC_ROGUE
|
||||
|| nClass == CLASS_TYPE_WILDER
|
||||
|| nClass == CLASS_TYPE_FIST_OF_ZUOKEN
|
||||
|| nClass == CLASS_TYPE_WARMIND
|
||||
|| nClass == CLASS_TYPE_CRUSADER
|
||||
|| nClass == CLASS_TYPE_SWORDSAGE
|
||||
|| nClass == CLASS_TYPE_WARBLADE
|
||||
|| nClass == CLASS_TYPE_TRUENAMER
|
||||
|| nClass == CLASS_TYPE_SHADOWCASTER
|
||||
|| nClass == CLASS_TYPE_SHADOWSMITH
|
||||
|| nClass == CLASS_TYPE_DRAGONFIRE_ADEPT
|
||||
|| nClass == CLASS_TYPE_DRAGON_SHAMAN
|
||||
|| nClass == CLASS_TYPE_WARLOCK)
|
||||
bAMS = TRUE;
|
||||
|
||||
//object oSpellIDToken = bAMS ? _inc_lookups_GetCacheObject("PRC_SpellIDToClsPsipw"):
|
||||
// _inc_lookups_GetCacheObject("PRC_GetRowFromSpellID");
|
||||
|
||||
// Failed to obtain a valid token - nothing to store on
|
||||
//if(!GetIsObjectValid(oSpellIDToken))
|
||||
// bSkipLoop = TRUE;
|
||||
|
||||
// Starting a new run and the data is present already. Assume the whole thing is present and abort
|
||||
if(nMin == 1
|
||||
&& GetLocalInt(oSpellIDToken, Get2DACache(sFile, "SpellID", 1)))
|
||||
{
|
||||
if(DEBUG) DoDebug("MakeLookupLoop("+sFile+") restored from database");
|
||||
bSkipLoop = TRUE;
|
||||
}
|
||||
|
||||
if(!bSkipLoop)
|
||||
{
|
||||
string sClass = IntToString(nClass);
|
||||
|
||||
//object oLevelToken;
|
||||
//object oPowerToken = _inc_lookups_GetCacheObject("PRC_GetPowerFromSpellID");
|
||||
//object oRealSpellIDToken = bAMS ? _inc_lookups_GetCacheObject("PRC_GetClassFeatFromPower_"+sClass):
|
||||
_inc_lookups_GetCacheObject("PRC_GetRowFromRealSpellID");
|
||||
|
||||
int nRealSpellID, nFeatID, nCount;
|
||||
string sSpellID, sRealSID;
|
||||
for(i = nMin; i < nMin + nLoopSize; i++)
|
||||
{
|
||||
// None of the relevant 2da files have blank Label entries on rows other than 0. We can assume i is greater than 0 at this point
|
||||
if(Get2DAString(sFile, "Label", i) == "") // Using Get2DAString() instead of Get2DACache() to avoid caching useless data
|
||||
{
|
||||
bSkipLoop = TRUE;
|
||||
break;// exit the loop
|
||||
}
|
||||
|
||||
sSpellID = Get2DACache(sFile, "SpellID", i);
|
||||
sRealSID = Get2DACache(sFile, "RealSpellID", i);
|
||||
nRealSpellID = StringToInt(sRealSID);
|
||||
|
||||
//GetPowerfileIndexFromSpellID
|
||||
//SpellToSpellbookID
|
||||
SetLocalInt(oSpellIDToken, sSpellID, i);
|
||||
|
||||
//GetPowerfileIndexFromRealSpellID
|
||||
SetLocalInt(oSpellIDToken, sRealSID, i);
|
||||
|
||||
//GetPowerFromSpellID
|
||||
SetLocalInt(oPowerToken, sSpellID, nRealSpellID);
|
||||
|
||||
//Spell level lookup
|
||||
if(!bAMS || nClass == CLASS_TYPE_WARLOCK)
|
||||
{
|
||||
string sReqFt = bAMS ? "" : Get2DACache(sFile, "ReqFeat", i);// Only new spellbooks have the ReqFeat column. No sense in caching it for other stuff
|
||||
if(sReqFt == "")
|
||||
{
|
||||
string sLevel = Get2DACache(sFile, "Level", i);
|
||||
//oLevelToken = _inc_lookups_GetCacheObject("SpellLvl_"+sClass+"_Level_"+sLevel);
|
||||
// check if array exist, if not create one
|
||||
if(!persistant_array_exists(oLevelToken, "SpellLvl_"+sClass+"_Level_"+sLevel))
|
||||
persistant_array_create(oLevelToken, "SpellLvl_"+sClass+"_Level_"+sLevel);
|
||||
|
||||
persistant_array_get_int(oLevelToken, "SpellLvl_"+sClass+"_Level_"+sLevel, persistant_array_get_size(oLevelToken, "SpellLvl_"+sClass+"_Level_"+sLevel), i);
|
||||
|
||||
//LookupSpellDescriptor(nRealSpellID, sClass, sLevel);
|
||||
}
|
||||
}
|
||||
|
||||
//GetClassFeatFromPower
|
||||
if(bAMS)
|
||||
{
|
||||
nFeatID = StringToInt(Get2DACache(sFile, "FeatID", i));
|
||||
if(nFeatID != 0)
|
||||
{
|
||||
SetLocalInt(oRealSpellIDToken, sRealSID, nFeatID);
|
||||
}
|
||||
}
|
||||
//RealSpellToSpellbookID
|
||||
//RealSpellToSpellbookIDCount
|
||||
else
|
||||
{
|
||||
if(sRealSID == sTemp)
|
||||
{
|
||||
nCount += 1;
|
||||
continue;
|
||||
}
|
||||
else
|
||||
{
|
||||
SetLocalInt(oRealSpellIDToken, sClass+"_"+sTemp+"_Count", nCount);
|
||||
SetLocalInt(oRealSpellIDToken, sClass+"_"+sRealSID+"_Start", i);
|
||||
sTemp = sRealSID;
|
||||
nCount = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// And delay continuation to avoid TMI
|
||||
if(i < nMax && !bSkipLoop)
|
||||
DelayCommand(0.0, MakeLookupLoop(nClass, sFile, i, nMax, nLoopSize, sTemp));
|
||||
else
|
||||
DelayCommand(0.0, RunNextLoop());
|
||||
}
|
||||
|
||||
int GetPowerFromSpellID(int nSpellID)
|
||||
{
|
||||
object oWP = GetObjectByTag("PRC_GetPowerFromSpellID");
|
||||
int nPower = GetLocalInt(oWP, /*"PRC_GetPowerFromSpellID_" + */IntToString(nSpellID));
|
||||
if(nPower == 0)
|
||||
nPower = -1;
|
||||
return nPower;
|
||||
}
|
||||
|
||||
int GetPowerfileIndexFromSpellID(int nSpellID)
|
||||
{
|
||||
object oWP = GetObjectByTag("PRC_SpellIDToClsPsipw");
|
||||
int nIndex = GetLocalInt(oWP, /*"PRC_SpellIDToClsPsipw_" + */IntToString(nSpellID));
|
||||
return nIndex;
|
||||
}
|
||||
|
||||
int GetPowerfileIndexFromRealSpellID(int nRealSpellID)
|
||||
{
|
||||
object oWP = GetObjectByTag("PRC_SpellIDToClsPsipw");
|
||||
int nIndex = GetLocalInt(oWP, /*"PRC_SpellIDToClsPsipw_" + */IntToString(nRealSpellID));
|
||||
return nIndex;
|
||||
}
|
||||
|
||||
int GetClassFeatFromPower(int nPowerID, int nClass)
|
||||
{
|
||||
string sLabel = "PRC_GetClassFeatFromPower_" + IntToString(nClass);
|
||||
object oWP = GetObjectByTag(sLabel);
|
||||
int nPower = GetLocalInt(oWP, /*sLabel+"_" + */IntToString(nPowerID));
|
||||
if(nPower == 0)
|
||||
nPower = -1;
|
||||
return nPower;
|
||||
}
|
||||
|
||||
int SpellToSpellbookID(int nSpell)
|
||||
{
|
||||
object oWP = GetObjectByTag("PRC_GetRowFromSpellID");
|
||||
int nOutSpellID = GetLocalInt(oWP, /*"PRC_GetRowFromSpellID_" + */IntToString(nSpell));
|
||||
if(nOutSpellID == 0)
|
||||
nOutSpellID = -1;
|
||||
//if(DEBUG) DoDebug("SpellToSpellbookID(" + IntToString(nSpell) + ", " + sFile + ") = " + IntToString(nOutSpellID));
|
||||
return nOutSpellID;
|
||||
}
|
||||
|
||||
int RealSpellToSpellbookID(int nClass, int nSpell)
|
||||
{
|
||||
object oWP = GetObjectByTag("PRC_GetRowFromRealSpellID");
|
||||
int nOutSpellID = GetLocalInt(oWP, IntToString(nClass) + "_" + IntToString(nSpell) + "_Start");
|
||||
if(nOutSpellID == 0)
|
||||
nOutSpellID = -1;
|
||||
return nOutSpellID;
|
||||
}
|
||||
|
||||
int RealSpellToSpellbookIDCount(int nClass, int nSpell)
|
||||
{
|
||||
return GetLocalInt(GetObjectByTag("PRC_GetRowFromRealSpellID"), IntToString(nClass) + "_" + IntToString(nSpell) + "_Count");
|
||||
}
|
||||
|
||||
string GetAMSKnownFileName(int nClass)
|
||||
{
|
||||
// Get the class-specific base
|
||||
string sFile = Get2DACache("classes", "FeatsTable", nClass);
|
||||
|
||||
// Various naming schemes based on system
|
||||
if(nClass == CLASS_TYPE_TRUENAMER)
|
||||
sFile = "cls_true_known";
|
||||
// ToB
|
||||
else if(nClass == CLASS_TYPE_CRUSADER || nClass == CLASS_TYPE_SWORDSAGE || nClass == CLASS_TYPE_WARBLADE)
|
||||
sFile = "cls_mvkn" + GetStringRight(sFile, GetStringLength(sFile) - 8); // Hardcoded the cls_ part. It's not as if any class uses some other prefix - Ornedan, 20061210
|
||||
// Shadowcasting
|
||||
else if(nClass == CLASS_TYPE_SHADOWCASTER || nClass == CLASS_TYPE_SHADOWSMITH)
|
||||
sFile = "cls_mykn" + GetStringRight(sFile, GetStringLength(sFile) - 8); // Hardcoded the cls_ part. It's not as if any class uses some other prefix - Ornedan, 20061210
|
||||
// Invocations
|
||||
else if(nClass == CLASS_TYPE_DRAGONFIRE_ADEPT || nClass == CLASS_TYPE_WARLOCK || nClass == CLASS_TYPE_DRAGON_SHAMAN)
|
||||
sFile = "cls_invkn" + GetStringRight(sFile, GetStringLength(sFile) - 8); // Hardcoded the cls_ part. It's not as if any class uses some other prefix - Ornedan, 20061210
|
||||
// Assume psionics if no other match
|
||||
else
|
||||
sFile = "cls_psbk" + GetStringRight(sFile, GetStringLength(sFile) - 8); // Hardcoded the cls_ part. It's not as if any class uses some other prefix - Ornedan, 20061210
|
||||
|
||||
return sFile;
|
||||
}
|
||||
|
||||
string GetAMSDefinitionFileName(int nClass)
|
||||
{
|
||||
// Get the class-specific base
|
||||
string sFile = Get2DACache("classes", "FeatsTable", nClass);
|
||||
|
||||
// Various naming schemes based on system
|
||||
if(nClass == CLASS_TYPE_TRUENAMER)
|
||||
sFile = "cls_true_utter";
|
||||
// ToB
|
||||
else if(nClass == CLASS_TYPE_CRUSADER || nClass == CLASS_TYPE_SWORDSAGE || nClass == CLASS_TYPE_WARBLADE)
|
||||
sFile = "cls_move" + GetStringRight(sFile, GetStringLength(sFile) - 8); // Hardcoded the cls_ part. It's not as if any class uses some other prefix - Ornedan, 20061210
|
||||
// Shadowcasting
|
||||
else if(nClass == CLASS_TYPE_SHADOWCASTER || nClass == CLASS_TYPE_SHADOWSMITH)
|
||||
sFile = "cls_myst" + GetStringRight(sFile, GetStringLength(sFile) - 8); // Hardcoded the cls_ part. It's not as if any class uses some other prefix - Ornedan, 20061210
|
||||
// Invoc
|
||||
else if(nClass == CLASS_TYPE_DRAGONFIRE_ADEPT || nClass == CLASS_TYPE_WARLOCK || nClass == CLASS_TYPE_DRAGON_SHAMAN)
|
||||
sFile = "cls_inv" + GetStringRight(sFile, GetStringLength(sFile) - 8); // Hardcoded the cls_ part. It's not as if any class uses some other prefix - Ornedan, 20061210
|
||||
// Assume psionics if no other match
|
||||
else
|
||||
sFile = "cls_psipw" + GetStringRight(sFile, GetStringLength(sFile) - 8); // Hardcoded the cls_ part. It's not as if any class uses some other prefix - Ornedan, 20061210
|
||||
|
||||
return sFile;
|
||||
}
|
||||
|
||||
// Test main
|
||||
//void main(){}
|
1255
trunk/users/Stratovarius/NWNEE Updates/inc_newspellbook.nss
Normal file
1255
trunk/users/Stratovarius/NWNEE Updates/inc_newspellbook.nss
Normal file
File diff suppressed because it is too large
Load Diff
376
trunk/users/Stratovarius/NWNEE Updates/inc_pers_array.nss
Normal file
376
trunk/users/Stratovarius/NWNEE Updates/inc_pers_array.nss
Normal file
@@ -0,0 +1,376 @@
|
||||
//::///////////////////////////////////////////////
|
||||
//:: Persistant array simulation include
|
||||
//:: inc_pers_array
|
||||
//:://////////////////////////////////////////////
|
||||
/** @file
|
||||
Persistant array simulation include
|
||||
|
||||
This file defines a set of functions for creating
|
||||
and manipulating persistant arrays, which are
|
||||
implemented as persistant local variables on some
|
||||
holder creature.
|
||||
|
||||
|
||||
Notes:
|
||||
|
||||
* Arrays are dynamic and may be increased in size by just _set_'ing a new
|
||||
element
|
||||
* There are no restrictions on what is in the array (can have multiple
|
||||
types in the same array)
|
||||
* Arrays start at index 0
|
||||
*/
|
||||
//:://////////////////////////////////////////////
|
||||
//:://////////////////////////////////////////////
|
||||
|
||||
|
||||
/////////////////////////////////////
|
||||
// Functions
|
||||
/////////////////////////////////////
|
||||
|
||||
/**
|
||||
* Creates a new persistant array on the given storage creature.
|
||||
* If an array with the same name already exists, the function
|
||||
* errors.
|
||||
*
|
||||
* @param store The creature to use as holder for the array
|
||||
* @param name The name of the array
|
||||
* @return SDL_SUCCESS if the array was successfully created,
|
||||
* one of SDL_ERROR_* on error.
|
||||
*/
|
||||
int persistant_array_create(object store, string name);
|
||||
|
||||
/**
|
||||
* Deletes a persistant array, erasing all it's entries.
|
||||
*
|
||||
* @param store The creature which holds the array to delete
|
||||
* @param name The name of the array
|
||||
* @return SDL_SUCCESS if the array was successfully deleted,
|
||||
* one of SDL_ERROR_* on error
|
||||
*/
|
||||
int persistant_array_delete(object store, string name);
|
||||
|
||||
/**
|
||||
* Stores a string in a persistant array.
|
||||
*
|
||||
* @param store The creature holding the array
|
||||
* @param name The name of the array
|
||||
* @param i The index to store the string at
|
||||
* @param entry The string to store
|
||||
* @return SDL_SUCCESS if the store was successfull, SDL_ERROR_* on error.
|
||||
*/
|
||||
int persistant_array_set_string(object store, string name, int i, string entry);
|
||||
|
||||
/**
|
||||
* Stores an integer in a persistant array.
|
||||
*
|
||||
* @param store The creature holding the array
|
||||
* @param name The name of the array
|
||||
* @param i The index to store the integer at
|
||||
* @param entry The integer to store
|
||||
* @return SDL_SUCCESS if the store was successfull, SDL_ERROR_* on error.
|
||||
*/
|
||||
int persistant_array_set_int(object store, string name, int i, int entry);
|
||||
|
||||
/**
|
||||
* Stores a float in a persistant array.
|
||||
*
|
||||
* @param store The creature holding the array
|
||||
* @param name The name of the array
|
||||
* @param i The index to store the float at
|
||||
* @param entry The float to store
|
||||
* @return SDL_SUCCESS if the store was successfull, SDL_ERROR_* on error.
|
||||
*/
|
||||
int persistant_array_set_float(object store, string name, int i, float entry);
|
||||
|
||||
/**
|
||||
* Stores an object in a persistant array.
|
||||
*
|
||||
* @param store The creature holding the array
|
||||
* @param name The name of the array
|
||||
* @param i The index to store the object at
|
||||
* @param entry The object to store
|
||||
* @return SDL_SUCCESS if the store was successfull, SDL_ERROR_* on error.
|
||||
*/
|
||||
int persistant_array_set_object(object store, string name, int i, object entry);
|
||||
|
||||
/**
|
||||
* Gets a string from a persistant array.
|
||||
*
|
||||
* @param store The creature holding the array
|
||||
* @param name The name of the array
|
||||
* @param i The index to retrieve the string from
|
||||
* @return The value contained at the index on success,
|
||||
* "" on error
|
||||
*/
|
||||
string persistant_array_get_string(object store, string name, int i);
|
||||
|
||||
/**
|
||||
* Gets an integer from a persistant array.
|
||||
*
|
||||
* @param store The creature holding the array
|
||||
* @param name The name of the array
|
||||
* @param i The index to retrieve the integer from
|
||||
* @return The value contained at the index on success,
|
||||
* 0 on error
|
||||
*/
|
||||
int persistant_array_get_int(object store, string name, int i);
|
||||
|
||||
/**
|
||||
* Gets a float from a persistant array.
|
||||
*
|
||||
* @param store The creature holding the array
|
||||
* @param name The name of the array
|
||||
* @param i The index to retrieve the float from
|
||||
* @return The value contained at the index on success,
|
||||
* 0.0f on error
|
||||
*/
|
||||
float persistant_array_get_float(object store, string name, int i);
|
||||
|
||||
/**
|
||||
* Gets an object from a persistant array.
|
||||
*
|
||||
* @param store The creature holding the array
|
||||
* @param name The name of the array
|
||||
* @param i The index to retrieve the object from
|
||||
* @return The value contained at the index on success,
|
||||
* OBJECT_INVALID on error
|
||||
*/
|
||||
object persistant_array_get_object(object store, string name, int i);
|
||||
|
||||
/**
|
||||
* Removes all entries in the array with indexes greater than or equal to
|
||||
* the new size and sets the array size to be equal to the new size.
|
||||
*
|
||||
* @param store The creature holding the array
|
||||
* @param name The name of the array
|
||||
* @param size_new The new number of entries in the array
|
||||
* @return SDL_SUCCESS on successful resize, SDL_ERROR_* on
|
||||
* error
|
||||
*/
|
||||
int persistant_array_shrink(object store, string name, int size_new);
|
||||
|
||||
/**
|
||||
* Gets the current size of the array. This is one greater
|
||||
* than the index of highest indexed element the array
|
||||
* has contained since the last array_shrink or the new size
|
||||
* specified by the last array_shrink, whichever is greater.
|
||||
*
|
||||
* @param store The creature holding the array
|
||||
* @param name The name of the array
|
||||
* @return The size of the array, or -1 if the specified
|
||||
* array does not exist.
|
||||
*/
|
||||
int persistant_array_get_size(object store, string name);
|
||||
|
||||
/**
|
||||
* Checks whether the given persistant array exists.
|
||||
*
|
||||
* @param store The creature holding the array
|
||||
* @param name The name of the array
|
||||
* @return TRUE if the array exists, FALSE otherwise.
|
||||
*/
|
||||
int persistant_array_exists(object store, string name);
|
||||
|
||||
/////////////////////////////////////
|
||||
// Includes
|
||||
/////////////////////////////////////
|
||||
|
||||
#include "inc_persist_loca"
|
||||
#include "inc_array" // yes this is also got via inc_persist_loca if rather indirectly
|
||||
|
||||
/////////////////////////////////////
|
||||
// Implementation
|
||||
/////////////////////////////////////
|
||||
|
||||
int persistant_array_create(object store, string name)
|
||||
{
|
||||
// error checking
|
||||
if(!GetIsObjectValid(store))
|
||||
return SDL_ERROR_NOT_VALID_OBJECT;
|
||||
else if(persistant_array_exists(store,name))
|
||||
return SDL_ERROR_ALREADY_EXISTS;
|
||||
else
|
||||
{
|
||||
// Initialize the size (always one greater than the actual size)
|
||||
SetPersistantLocalInt(store,name,1);
|
||||
return SDL_SUCCESS;
|
||||
}
|
||||
}
|
||||
|
||||
void persistant_array_delete_loop(object store, string name, int nMin, int nMax)
|
||||
{
|
||||
int i = nMin;
|
||||
while(i < nMin + 250 && i < nMax)
|
||||
{
|
||||
DeletePersistantLocalString(store,name+"_"+IntToString(i));
|
||||
|
||||
// just in case, delete possible object names
|
||||
DeletePersistantLocalObject(store,name+"_"+IntToString(i)+"_OBJECT");
|
||||
i++;
|
||||
}
|
||||
// delay continuation to avoid TMI
|
||||
if(i < nMax)
|
||||
DelayCommand(0.0, persistant_array_delete_loop(store, name, i, nMax));
|
||||
}
|
||||
|
||||
int persistant_array_delete(object store, string name)
|
||||
{
|
||||
// error checking
|
||||
int size=GetPersistantLocalInt(store,name);
|
||||
if (size==0)
|
||||
return SDL_ERROR_DOES_NOT_EXIST;
|
||||
|
||||
persistant_array_delete_loop(store, name, 0, size+5);
|
||||
|
||||
DeletePersistantLocalInt(store,name);
|
||||
|
||||
return SDL_SUCCESS;
|
||||
}
|
||||
|
||||
int persistant_array_set_string(object store, string name, int i, string entry)
|
||||
{
|
||||
int size=GetPersistantLocalInt(store,name);
|
||||
if(size == 0)
|
||||
return SDL_ERROR_DOES_NOT_EXIST;
|
||||
if(i < 0)
|
||||
return SDL_ERROR_OUT_OF_BOUNDS;
|
||||
|
||||
SetPersistantLocalString(store,name+"_"+IntToString(i),entry);
|
||||
|
||||
// save size if we've enlarged it
|
||||
if (i+2>size)
|
||||
SetPersistantLocalInt(store,name,i+2);
|
||||
|
||||
return SDL_SUCCESS;
|
||||
}
|
||||
|
||||
int persistant_array_set_int(object store, string name, int i, int entry)
|
||||
{
|
||||
return persistant_array_set_string(store,name,i,IntToString(entry));
|
||||
}
|
||||
|
||||
int persistant_array_set_float(object store, string name, int i, float entry)
|
||||
{
|
||||
return persistant_array_set_string(store,name,i,FloatToString(entry));
|
||||
}
|
||||
|
||||
int persistant_array_set_object(object store, string name, int i, object entry)
|
||||
{
|
||||
// object is a little more complicated.
|
||||
// we want to create an object as a local variable too
|
||||
if (!GetIsObjectValid(entry))
|
||||
return SDL_ERROR_NOT_VALID_OBJECT;
|
||||
|
||||
int results = persistant_array_set_string(store,name,i,"OBJECT");
|
||||
if (results==SDL_SUCCESS)
|
||||
SetPersistantLocalObject(store,name+"_"+IntToString(i)+"_OBJECT",entry);
|
||||
|
||||
return results;
|
||||
}
|
||||
|
||||
string persistant_array_get_string(object store, string name, int i)
|
||||
{
|
||||
// error checking
|
||||
int size=GetPersistantLocalInt(store,name);
|
||||
if (size==0 || i>size || i < 0)
|
||||
return "";
|
||||
|
||||
return GetPersistantLocalString(store,name+"_"+IntToString(i));
|
||||
}
|
||||
|
||||
int persistant_array_get_int(object store, string name, int i)
|
||||
{
|
||||
return StringToInt(persistant_array_get_string(store,name,i));
|
||||
}
|
||||
|
||||
float persistant_array_get_float(object store, string name, int i)
|
||||
{
|
||||
return StringToFloat(persistant_array_get_string(store,name,i));
|
||||
}
|
||||
|
||||
object persistant_array_get_object(object store, string name, int i)
|
||||
{
|
||||
if(persistant_array_get_string(store, name, i) == "OBJECT")
|
||||
return GetPersistantLocalObject(store,name+"_"+IntToString(i)+"_OBJECT");
|
||||
else
|
||||
return OBJECT_INVALID;
|
||||
}
|
||||
|
||||
int persistant_array_shrink(object store, string name, int size_new)
|
||||
{
|
||||
// Get the current size value
|
||||
int size = GetPersistantLocalInt(store, name);
|
||||
// Error check - non-existent array
|
||||
if(size == 0)
|
||||
return SDL_ERROR_DOES_NOT_EXIST;
|
||||
// If the new number of elements is equal to or greater than the current number of elements, autosuccess
|
||||
if((size - 1) <= size_new)
|
||||
return SDL_SUCCESS;
|
||||
|
||||
// Delete entries that are outside the new array bounds
|
||||
int i;
|
||||
for(i = size_new; i < size; i++)
|
||||
{
|
||||
DeletePersistantLocalString(store, name+"_"+IntToString(i));
|
||||
|
||||
// just in case, delete possible object names
|
||||
DeletePersistantLocalObject(store, name+"_"+IntToString(i)+"_OBJECT");
|
||||
}
|
||||
|
||||
// Store the new size, with the +1 existence marker
|
||||
SetPersistantLocalInt(store, name, size_new + 1);
|
||||
|
||||
return SDL_SUCCESS;
|
||||
}
|
||||
|
||||
int persistant_array_get_size(object store, string name)
|
||||
{
|
||||
return GetPersistantLocalInt(store,name)-1;
|
||||
}
|
||||
|
||||
int persistant_array_exists(object store, string name)
|
||||
{
|
||||
if (GetPersistantLocalInt(store,name))
|
||||
return TRUE;
|
||||
else
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
int IsIntSet(object oPC, string sArray, int nValue)
|
||||
{
|
||||
int nReturn = FALSE;
|
||||
// Run a loop to check if the value is set anywhere in this array
|
||||
int i;
|
||||
for(i = 0; i =< persistant_array_get_size(oPC, sArray); i++)
|
||||
{
|
||||
int nCheck = persistant_array_get_int(oPC, sArray, i);
|
||||
if (nCheck == nValue)
|
||||
{
|
||||
nReturn = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return nReturn;
|
||||
}
|
||||
|
||||
int IsStringSet(object oPC, string sArray, string sValue)
|
||||
{
|
||||
int nReturn = FALSE;
|
||||
// Run a loop to check if the value is set anywhere in this array
|
||||
int i;
|
||||
for(i = 0; i =< persistant_array_get_size(oPC, sArray); i++)
|
||||
{
|
||||
string sCheck = persistant_array_get_string(oPC, sArray, i);
|
||||
if (sCheck == sValue)
|
||||
{
|
||||
nReturn = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return nReturn;
|
||||
}
|
||||
|
||||
// Test main
|
||||
//void main(){}
|
361
trunk/users/Stratovarius/NWNEE Updates/inc_sp_gain_mem.nss
Normal file
361
trunk/users/Stratovarius/NWNEE Updates/inc_sp_gain_mem.nss
Normal file
@@ -0,0 +1,361 @@
|
||||
//:://////////////////////////////////////////////
|
||||
//:: 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)
|
||||
|
||||
//:://////////////////////////////////////////////
|
||||
//:: Constants
|
||||
//:://////////////////////////////////////////////
|
||||
|
||||
// max. number of classes a PC (or creature) can take (3 for NWN, 4 for NWN2)
|
||||
const int MAX_CLASSES = 3;
|
||||
|
||||
//////////////////////////////////////////////////
|
||||
/* 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 oToken, string sArrayName, int nSize);
|
||||
int array_has_string(object oToken, string sArrayName, string sValue, int nFirst = 0, int nSize = 0);
|
||||
int array_has_int(object oToken, string sArrayName, int nValue, int nFirst = 0, int nSize = 0);
|
||||
int persistant_array_has_string(object oToken, string sArrayName, string sValue, int nFirst = 0, int nSize = 0);
|
||||
int persistant_array_has_int(object oToken, string sArrayName, int nValue, int nFirst = 0, int nSize = 0);
|
||||
int array_extract_string(object oToken, string sArrayName, string sValue, int nFirst = 0);
|
||||
int array_extract_int(object oToken, 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 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 oToken, string sArrayName, int nSize)
|
||||
{
|
||||
SetLocalInt(oToken, sArrayName, nSize+1);
|
||||
}
|
||||
|
||||
int array_has_string(object oToken, string sArrayName, string sValue, int nFirst = 0, int nSize = 0)
|
||||
{
|
||||
// get array size, if size not already supplied
|
||||
if (nSize == 0) nSize = GetLocalInt(oToken, sArrayName) -1;
|
||||
int i;
|
||||
|
||||
for (i = nFirst; i < nSize; i++)
|
||||
{
|
||||
if (sValue == GetLocalString(oToken, sArrayName + "_" + IntToString(i)))
|
||||
return i;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
int array_has_int(object oToken, 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(oToken, 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(GetHideToken(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(GetHideToken(oPC), sArrayName, IntToString(nValue), nFirst, nSize);
|
||||
}
|
||||
|
||||
int array_extract_string(object oToken, string sArrayName, string sValue, int nFirst = 0)
|
||||
{
|
||||
// get array size
|
||||
int nSize = SQLocals_GetInt(oToken, sArrayName)-1;
|
||||
if (nSize <= nFirst) return -1;
|
||||
|
||||
// position of the first found; -1 if not found
|
||||
int nPos = IsStringSet(oToken, sArrayName, sValue);
|
||||
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 = SQLocals_GetString(oToken, sArrayName + "_" + IntToString(nSize-1));
|
||||
SQLocals_SetString(oToken, sArrayName + "_" + IntToString(nPos), sTemp);
|
||||
}
|
||||
|
||||
// now decrement the array size (note that we already subtracted one in the beginning)
|
||||
SQLocals_SetInt(oToken, 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 oToken, string sArrayName, int nValue, int nFirst = 0)
|
||||
{
|
||||
// array values are stored as strings, so convert nValue to a string
|
||||
return array_extract_string(oToken, sArrayName, IntToString(nValue), nFirst);
|
||||
}
|
||||
|
||||
int persistant_array_extract_string(object oPC, string sArrayName, string sValue, int nFirst = 0)
|
||||
{
|
||||
return array_extract_string(GetHideToken(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(GetHideToken(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;
|
||||
}
|
650
trunk/users/Stratovarius/NWNEE Updates/inc_sqllocals.nss
Normal file
650
trunk/users/Stratovarius/NWNEE Updates/inc_sqllocals.nss
Normal file
@@ -0,0 +1,650 @@
|
||||
//::///////////////////////////////////////////////
|
||||
//:: Utility Include: SQLocals
|
||||
//:: inc_layo_sqlite.nss
|
||||
//:://////////////////////////////////////////////
|
||||
/*
|
||||
Daz wrote these library functions to act as replacements for the usual local
|
||||
functions:
|
||||
* GetLocalInt / SetLocalInt / DeleteLocalInt
|
||||
* GetLocalFloat / SetLocalFloat / DeleteLocalFloat
|
||||
* GetLocalString / SetLocalString / DeleteLocalString
|
||||
* GetLocalObject / SetLocalObject / DeleteLocalObject (NB: remember these are references NOT serialised objects)
|
||||
* GetLocalLocation / SetLocalLocation / DeleteLocalLocation
|
||||
* Plus a new function for saving just a vector by itself.
|
||||
Since sometimes iterating over many locals is slow, this might be an excellent way to
|
||||
speed up large amounts of access, or for debugging, or using regex or whatever else.
|
||||
These are functions for PC Object persistence.
|
||||
*/
|
||||
//:://////////////////////////////////////////////
|
||||
//:: Based off of the nwscript_utility_scripts project; see for dates/creator info
|
||||
//:: https://github.com/Finaldeath/nwscript_utility_scripts
|
||||
//:://////////////////////////////////////////////
|
||||
|
||||
const string SQLOCALS_TABLE_NAME = "prc_sqlocals_table";
|
||||
|
||||
const int SQLOCALS_TYPE_ALL = 0;
|
||||
const int SQLOCALS_TYPE_INT = 1;
|
||||
const int SQLOCALS_TYPE_FLOAT = 2;
|
||||
const int SQLOCALS_TYPE_STRING = 4;
|
||||
const int SQLOCALS_TYPE_OBJECT = 8;
|
||||
const int SQLOCALS_TYPE_VECTOR = 16;
|
||||
const int SQLOCALS_TYPE_LOCATION = 32;
|
||||
|
||||
// Returns an integer stored on oObject, or 0 on error
|
||||
// * oObject - an object to reference against
|
||||
// * sVarName - name of the variable to retrieve
|
||||
int SQLocals_GetInt(object oObject, string sVarName);
|
||||
// Sets an integer stored on oObject to the given value
|
||||
// * oObject - an object to reference against
|
||||
// * sVarName - name of the variable to retrieve
|
||||
// * nValue - Value to store
|
||||
void SQLocals_SetInt(object oObject, string sVarName, int nValue);
|
||||
// Deletes an integer stored on oObject
|
||||
// * oObject - an object to reference against
|
||||
// * sVarName - name of the variable to delete
|
||||
void SQLocals_DeleteInt(object oObject, string sVarName);
|
||||
|
||||
// Returns a float stored on oObject, or 0.0 on error
|
||||
// * oObject - an object to reference against
|
||||
// * sVarName - name of the variable to retrieve
|
||||
float SQLocals_GetFloat(object oObject, string sVarName);
|
||||
// Sets a float stored on oObject to the given value
|
||||
// * oObject - an object to reference against
|
||||
// * sVarName - name of the variable to retrieve
|
||||
// * fValue - Value to store
|
||||
void SQLocals_SetFloat(object oObject, string sVarName, float fValue);
|
||||
// Deletes a float stored on oObject
|
||||
// * oObject - an object to reference against
|
||||
// * sVarName - name of the variable to delete
|
||||
void SQLocals_DeleteFloat(object oObject, string sVarName);
|
||||
|
||||
// Returns an string stored on oObject, or "" on error
|
||||
// * oObject - an object to reference against
|
||||
// * sVarName - name of the variable to retrieve
|
||||
string SQLocals_GetString(object oObject, string sVarName);
|
||||
// Sets a string stored on oObject to the given value
|
||||
// * oObject - an object to reference against
|
||||
// * sVarName - name of the variable to retrieve
|
||||
// * sValue - Value to store
|
||||
void SQLocals_SetString(object oObject, string sVarName, string sValue);
|
||||
// Deletes a string stored on oObject
|
||||
// * oObject - an object to reference against
|
||||
// * sVarName - name of the variable to delete
|
||||
void SQLocals_DeleteString(object oObject, string sVarName);
|
||||
|
||||
// Returns an object identifier stored on oObject
|
||||
// If this is used on a player it might return a "once valid" OID, so check
|
||||
// with GetIsObjectValid, do not compare to OBJECT_INVALID.
|
||||
// * oObject - an object to reference against
|
||||
// * sVarName - name of the variable to retrieve
|
||||
object SQLocals_GetObject(object oObject, string sVarName);
|
||||
// Sets an object identifier stored on oObject to the given value
|
||||
// * oObject - an object to reference against
|
||||
// * sVarName - name of the variable to retrieve
|
||||
// * oValue - Value to store
|
||||
void SQLocals_SetObject(object oObject, string sVarName, object oValue);
|
||||
// Deletes an object identifier stored on oObject
|
||||
// * oObject - an object to reference against
|
||||
// * sVarName - name of the variable to delete
|
||||
void SQLocals_DeleteObject(object oObject, string sVarName);
|
||||
|
||||
// Returns a vector stored on oObject, or [0.0, 0.0, 0.0] on error
|
||||
// * oObject - an object to reference against
|
||||
// * sVarName - name of the variable to retrieve
|
||||
vector SQLocals_GetVector(object oObject, string sVarName);
|
||||
// Sets a vector stored on oObject to the given value
|
||||
// * oObject - an object to reference against
|
||||
// * sVarName - name of the variable to retrieve
|
||||
// * vValue - Value to store
|
||||
void SQLocals_SetVector(object oObject, string sVarName, vector vValue);
|
||||
// Deletes a vector stored on oObject
|
||||
// * oObject - an object to reference against
|
||||
// * sVarName - name of the variable to delete
|
||||
void SQLocals_DeleteVector(object oObject, string sVarName);
|
||||
|
||||
// Returns a location stored on oObject, or the starting location of the module on error
|
||||
// * oObject - an object to reference against
|
||||
// * sVarName - name of the variable to retrieve
|
||||
location SQLocals_GetLocation(object oObject, string sVarName);
|
||||
// Sets a location stored on oObject to the given value
|
||||
// * oObject - an object to reference against
|
||||
// * sVarName - name of the variable to retrieve
|
||||
// * lValue - Value to store
|
||||
void SQLocals_SetLocation(object oObject, string sVarName, location lValue);
|
||||
// Deletes a location stored on oObject
|
||||
// * oObject - an object to reference against
|
||||
// * sVarName - name of the variable to delete
|
||||
void SQLocals_DeleteLocation(object oObject, string sVarName);
|
||||
|
||||
// Deletes a set of locals stored on oObject matching the given criteria
|
||||
// * oObject - an object to reference against
|
||||
// * nType - The SQL_LOCALS_TYPE_* you wish to remove (default: SQL_LOCALS_TYPE_ALL)
|
||||
// * sLike - The string to compare with the SQL "like" comparison
|
||||
// * sEscape - The escape character to use with the SQL "escape" keyword
|
||||
void SQLocals_Delete(object oObject, int nType = SQLOCALS_TYPE_ALL, string sLike = "", string sEscape = "");
|
||||
// Counts a set of locals stored on oObject matching the given criteria
|
||||
// * oObject - an object to reference against
|
||||
// * nType - The SQL_LOCALS_TYPE_* you wish to remove (default: SQL_LOCALS_TYPE_ALL)
|
||||
// * sLike - The string to compare with the SQL "like" comparison
|
||||
// * sEscape - The escape character to use with the SQL "escape" keyword
|
||||
int SQLocals_Count(object oObject, int nType = SQLOCALS_TYPE_ALL, string sLike = "", string sEscape = "");
|
||||
// Checks a locals stored on oObject is set
|
||||
// * oObject - an object to reference against
|
||||
// * sVarName - name of the variable to retrieve
|
||||
// * nType - The SQL_LOCALS_TYPE_* you wish to remove (default: SQL_LOCALS_TYPE_ALL)
|
||||
int SQLocals_IsSet(object oObject, string sVarName, int nType);
|
||||
// Returns the last Unix time the given variable was updated
|
||||
// * oObject - an object to reference against
|
||||
// * sVarName - name of the variable to retrieve
|
||||
// * nType - The SQL_LOCALS_TYPE_* you wish to remove (default: SQL_LOCALS_TYPE_ALL)
|
||||
int SQLocals_GetLastUpdated_UnixEpoch(object oObject, string sVarName, int nType);
|
||||
// Returns the last UTC time the given variable was updated
|
||||
// * oObject - an object to reference against
|
||||
// * sVarName - name of the variable to retrieve
|
||||
// * nType - The SQL_LOCALS_TYPE_* you wish to remove (default: SQL_LOCALS_TYPE_ALL)
|
||||
string SQLocals_GetLastUpdated_UTC(object oObject, string sVarName, int nType);
|
||||
|
||||
|
||||
/* INTERNAL */
|
||||
void SQLocals_CreateTable(object oObject)
|
||||
{
|
||||
sqlquery sql = SqlPrepareQueryObject(oObject,
|
||||
"CREATE TABLE IF NOT EXISTS " + SQLOCALS_TABLE_NAME + " (" +
|
||||
"type INTEGER, " +
|
||||
"varname TEXT, " +
|
||||
"value TEXT, " +
|
||||
"timestamp INTEGER, " +
|
||||
"PRIMARY KEY(type, varname));");
|
||||
SqlStep(sql);
|
||||
}
|
||||
|
||||
sqlquery SQLocals_PrepareSelect(object oObject, int nType, string sVarName)
|
||||
{
|
||||
SQLocals_CreateTable(oObject);
|
||||
|
||||
sqlquery sql = SqlPrepareQueryObject(oObject,
|
||||
"SELECT value FROM " + SQLOCALS_TABLE_NAME + " " +
|
||||
"WHERE type = @type AND varname = @varname;");
|
||||
|
||||
SqlBindInt(sql, "@type", nType);
|
||||
SqlBindString(sql, "@varname", sVarName);
|
||||
|
||||
return sql;
|
||||
}
|
||||
|
||||
sqlquery SQLocals_PrepareInsert(object oObject, int nType, string sVarName)
|
||||
{
|
||||
SQLocals_CreateTable(oObject);
|
||||
|
||||
sqlquery sql = SqlPrepareQueryObject(oObject,
|
||||
"INSERT INTO " + SQLOCALS_TABLE_NAME + " " +
|
||||
"(type, varname, value, timestamp) VALUES (@type, @varname, @value, strftime('%s','now')) " +
|
||||
"ON CONFLICT (type, varname) DO UPDATE SET value = @value, timestamp = strftime('%s','now');");
|
||||
|
||||
SqlBindInt(sql, "@type", nType);
|
||||
SqlBindString(sql, "@varname", sVarName);
|
||||
|
||||
return sql;
|
||||
}
|
||||
|
||||
sqlquery SQLocals_PrepareDelete(object oObject, int nType, string sVarName)
|
||||
{
|
||||
SQLocals_CreateTable(oObject);
|
||||
|
||||
sqlquery sql = SqlPrepareQueryObject(oObject,
|
||||
"DELETE FROM " + SQLOCALS_TABLE_NAME + " " +
|
||||
"WHERE type = @type AND varname = @varname;");
|
||||
|
||||
SqlBindInt(sql, "@type", nType);
|
||||
SqlBindString(sql, "@varname", sVarName);
|
||||
|
||||
return sql;
|
||||
}
|
||||
|
||||
string SQLocals_LocationToString(location locLocation)
|
||||
{
|
||||
string sAreaId = ObjectToString(GetAreaFromLocation(locLocation));
|
||||
vector vPosition = GetPositionFromLocation(locLocation);
|
||||
float fFacing = GetFacingFromLocation(locLocation);
|
||||
|
||||
return "#A#" + sAreaId +
|
||||
"#X#" + FloatToString(vPosition.x, 0, 5) +
|
||||
"#Y#" + FloatToString(vPosition.y, 0, 5) +
|
||||
"#Z#" + FloatToString(vPosition.z, 0, 5) +
|
||||
"#F#" + FloatToString(fFacing, 0, 5) + "#";
|
||||
}
|
||||
|
||||
location SQLocals_StringToLocation(string sLocation)
|
||||
{
|
||||
location locLocation;
|
||||
|
||||
int nLength = GetStringLength(sLocation);
|
||||
|
||||
if(nLength > 0)
|
||||
{
|
||||
int nPos, nCount;
|
||||
|
||||
nPos = FindSubString(sLocation, "#A#") + 3;
|
||||
nCount = FindSubString(GetSubString(sLocation, nPos, nLength - nPos), "#");
|
||||
object oArea = StringToObject(GetSubString(sLocation, nPos, nCount));
|
||||
|
||||
nPos = FindSubString(sLocation, "#X#") + 3;
|
||||
nCount = FindSubString(GetSubString(sLocation, nPos, nLength - nPos), "#");
|
||||
float fX = StringToFloat(GetSubString(sLocation, nPos, nCount));
|
||||
|
||||
nPos = FindSubString(sLocation, "#Y#") + 3;
|
||||
nCount = FindSubString(GetSubString(sLocation, nPos, nLength - nPos), "#");
|
||||
float fY = StringToFloat(GetSubString(sLocation, nPos, nCount));
|
||||
|
||||
nPos = FindSubString(sLocation, "#Z#") + 3;
|
||||
nCount = FindSubString(GetSubString(sLocation, nPos, nLength - nPos), "#");
|
||||
float fZ = StringToFloat(GetSubString(sLocation, nPos, nCount));
|
||||
|
||||
vector vPosition = Vector(fX, fY, fZ);
|
||||
|
||||
nPos = FindSubString(sLocation, "#F#") + 3;
|
||||
nCount = FindSubString(GetSubString(sLocation, nPos, nLength - nPos), "#");
|
||||
float fOrientation = StringToFloat(GetSubString(sLocation, nPos, nCount));
|
||||
|
||||
if (GetIsObjectValid(oArea))
|
||||
locLocation = Location(oArea, vPosition, fOrientation);
|
||||
else
|
||||
locLocation = GetStartingLocation();
|
||||
}
|
||||
|
||||
return locLocation;
|
||||
}
|
||||
/* **** */
|
||||
|
||||
/* INT */
|
||||
|
||||
// Returns an integer stored on oObject, or 0 on error
|
||||
// * oObject - an object to reference against
|
||||
// * sVarName - name of the variable to retrieve
|
||||
int SQLocals_GetInt(object oObject, string sVarName)
|
||||
{
|
||||
if (!GetIsPC(oObject) || sVarName == "") return 0;
|
||||
|
||||
sqlquery sql = SQLocals_PrepareSelect(oObject, SQLOCALS_TYPE_INT, sVarName);
|
||||
|
||||
if (SqlStep(sql))
|
||||
return SqlGetInt(sql, 0);
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Sets an integer stored on oObject to the given value
|
||||
// * oObject - an object to reference against
|
||||
// * sVarName - name of the variable to retrieve
|
||||
// * nValue - Value to store
|
||||
void SQLocals_SetInt(object oObject, string sVarName, int nValue)
|
||||
{
|
||||
if (!GetIsPC(oObject) || sVarName == "") return;
|
||||
|
||||
sqlquery sql = SQLocals_PrepareInsert(oObject, SQLOCALS_TYPE_INT, sVarName);
|
||||
SqlBindInt(sql, "@value", nValue);
|
||||
SqlStep(sql);
|
||||
}
|
||||
|
||||
// Deletes an integer stored on oObject
|
||||
// * oObject - an object to reference against
|
||||
// * sVarName - name of the variable to delete
|
||||
void SQLocals_DeleteInt(object oObject, string sVarName)
|
||||
{
|
||||
if (!GetIsPC(oObject) || sVarName == "") return;
|
||||
|
||||
sqlquery sql = SQLocals_PrepareDelete(oObject, SQLOCALS_TYPE_INT, sVarName);
|
||||
SqlStep(sql);
|
||||
}
|
||||
/* **** */
|
||||
|
||||
/* FLOAT */
|
||||
|
||||
// Returns a float stored on oObject, or 0.0 on error
|
||||
// * oObject - an object to reference against
|
||||
// * sVarName - name of the variable to retrieve
|
||||
float SQLocals_GetFloat(object oObject, string sVarName)
|
||||
{
|
||||
if (!GetIsPC(oObject) || sVarName == "") return 0.0f;
|
||||
|
||||
sqlquery sql = SQLocals_PrepareSelect(oObject, SQLOCALS_TYPE_FLOAT, sVarName);
|
||||
|
||||
if (SqlStep(sql))
|
||||
return SqlGetFloat(sql, 0);
|
||||
else
|
||||
return 0.0f;
|
||||
}
|
||||
|
||||
// Sets a float stored on oObject to the given value
|
||||
// * oObject - an object to reference against
|
||||
// * sVarName - name of the variable to retrieve
|
||||
// * fValue - Value to store
|
||||
void SQLocals_SetFloat(object oObject, string sVarName, float fValue)
|
||||
{
|
||||
if (!GetIsPC(oObject) || sVarName == "") return;
|
||||
|
||||
sqlquery sql = SQLocals_PrepareInsert(oObject, SQLOCALS_TYPE_FLOAT, sVarName);
|
||||
SqlBindFloat(sql, "@value", fValue);
|
||||
SqlStep(sql);
|
||||
}
|
||||
|
||||
// Deletes a float stored on oObject
|
||||
// * oObject - an object to reference against
|
||||
// * sVarName - name of the variable to delete
|
||||
void SQLocals_DeleteFloat(object oObject, string sVarName)
|
||||
{
|
||||
if (!GetIsPC(oObject) || sVarName == "") return;
|
||||
|
||||
sqlquery sql = SQLocals_PrepareDelete(oObject, SQLOCALS_TYPE_FLOAT, sVarName);
|
||||
SqlStep(sql);
|
||||
}
|
||||
/* **** */
|
||||
|
||||
/* STRING */
|
||||
|
||||
// Returns an string stored on oObject, or "" on error
|
||||
// * oObject - an object to reference against
|
||||
// * sVarName - name of the variable to retrieve
|
||||
string SQLocals_GetString(object oObject, string sVarName)
|
||||
{
|
||||
if (!GetIsPC(oObject) || sVarName == "") return "";
|
||||
|
||||
sqlquery sql = SQLocals_PrepareSelect(oObject, SQLOCALS_TYPE_STRING, sVarName);
|
||||
|
||||
if (SqlStep(sql))
|
||||
return SqlGetString(sql, 0);
|
||||
else
|
||||
return "";
|
||||
}
|
||||
|
||||
// Sets a string stored on oObject to the given value
|
||||
// * oObject - an object to reference against
|
||||
// * sVarName - name of the variable to retrieve
|
||||
// * sValue - Value to store
|
||||
void SQLocals_SetString(object oObject, string sVarName, string sValue)
|
||||
{
|
||||
if (!GetIsPC(oObject) || sVarName == "") return;
|
||||
|
||||
sqlquery sql = SQLocals_PrepareInsert(oObject, SQLOCALS_TYPE_STRING, sVarName);
|
||||
SqlBindString(sql, "@value", sValue);
|
||||
SqlStep(sql);
|
||||
}
|
||||
|
||||
// Deletes a string stored on oObject
|
||||
// * oObject - an object to reference against
|
||||
// * sVarName - name of the variable to delete
|
||||
void SQLocals_DeleteString(object oObject, string sVarName)
|
||||
{
|
||||
if (!GetIsPC(oObject) || sVarName == "") return;
|
||||
|
||||
sqlquery sql = SQLocals_PrepareDelete(oObject, SQLOCALS_TYPE_STRING, sVarName);
|
||||
SqlStep(sql);
|
||||
}
|
||||
/* **** */
|
||||
|
||||
/* OBJECT */
|
||||
|
||||
|
||||
// Returns an object identifier stored on oObject
|
||||
// If this is used on a player it might return a "once valid" OID, so check
|
||||
// with GetIsObjectValid, do not compare to OBJECT_INVALID.
|
||||
// * oObject - an object to reference against
|
||||
// * sVarName - name of the variable to retrieve
|
||||
object SQLocals_GetObject(object oObject, string sVarName)
|
||||
{
|
||||
if (!GetIsPC(oObject) || sVarName == "") return OBJECT_INVALID;
|
||||
|
||||
sqlquery sql = SQLocals_PrepareSelect(oObject, SQLOCALS_TYPE_OBJECT, sVarName);
|
||||
|
||||
if (SqlStep(sql))
|
||||
return StringToObject(SqlGetString(sql, 0));
|
||||
else
|
||||
return OBJECT_INVALID;
|
||||
}
|
||||
|
||||
// Sets an object identifier stored on oObject to the given value
|
||||
// * oObject - an object to reference against
|
||||
// * sVarName - name of the variable to retrieve
|
||||
// * oValue - Value to store
|
||||
void SQLocals_SetObject(object oObject, string sVarName, object oValue)
|
||||
{
|
||||
if (!GetIsPC(oObject) || sVarName == "") return;
|
||||
|
||||
sqlquery sql = SQLocals_PrepareInsert(oObject, SQLOCALS_TYPE_OBJECT, sVarName);
|
||||
SqlBindString(sql, "@value", ObjectToString(oValue));
|
||||
SqlStep(sql);
|
||||
}
|
||||
|
||||
// Deletes an object identifier stored on oObject
|
||||
// * oObject - an object to reference against
|
||||
// * sVarName - name of the variable to delete
|
||||
void SQLocals_DeleteObject(object oObject, string sVarName)
|
||||
{
|
||||
if (!GetIsPC(oObject) || sVarName == "") return;
|
||||
|
||||
sqlquery sql = SQLocals_PrepareDelete(oObject, SQLOCALS_TYPE_OBJECT, sVarName);
|
||||
SqlStep(sql);
|
||||
}
|
||||
/* **** */
|
||||
|
||||
/* VECTOR */
|
||||
|
||||
// Returns a vector stored on oObject, or [0.0, 0.0, 0.0] on error
|
||||
// * oObject - an object to reference against
|
||||
// * sVarName - name of the variable to retrieve
|
||||
vector SQLocals_GetVector(object oObject, string sVarName)
|
||||
{
|
||||
if (!GetIsPC(oObject) || sVarName == "") return [0.0f, 0.0f, 0.0f];
|
||||
|
||||
sqlquery sql = SQLocals_PrepareSelect(oObject, SQLOCALS_TYPE_VECTOR, sVarName);
|
||||
|
||||
if (SqlStep(sql))
|
||||
return SqlGetVector(sql, 0);
|
||||
else
|
||||
return [0.0f, 0.0f, 0.0f];
|
||||
}
|
||||
|
||||
// Sets a vector stored on oObject to the given value
|
||||
// * oObject - an object to reference against
|
||||
// * sVarName - name of the variable to retrieve
|
||||
// * vValue - Value to store
|
||||
void SQLocals_SetVector(object oObject, string sVarName, vector vValue)
|
||||
{
|
||||
if (!GetIsPC(oObject) || sVarName == "") return;
|
||||
|
||||
sqlquery sql = SQLocals_PrepareInsert(oObject, SQLOCALS_TYPE_VECTOR, sVarName);
|
||||
SqlBindVector(sql, "@value", vValue);
|
||||
SqlStep(sql);
|
||||
}
|
||||
|
||||
// Deletes a vector stored on oObject
|
||||
// * oObject - an object to reference against
|
||||
// * sVarName - name of the variable to delete
|
||||
void SQLocals_DeleteVector(object oObject, string sVarName)
|
||||
{
|
||||
if (!GetIsPC(oObject) || sVarName == "") return;
|
||||
|
||||
sqlquery sql = SQLocals_PrepareDelete(oObject, SQLOCALS_TYPE_VECTOR, sVarName);
|
||||
SqlStep(sql);
|
||||
}
|
||||
/* **** */
|
||||
|
||||
/* LOCATION */
|
||||
|
||||
// Returns a location stored on oObject, or the starting location of the module on error
|
||||
// * oObject - an object to reference against
|
||||
// * sVarName - name of the variable to retrieve
|
||||
location SQLocals_GetLocation(object oObject, string sVarName)
|
||||
{
|
||||
if (!GetIsPC(oObject) || sVarName == "") return GetStartingLocation();
|
||||
|
||||
sqlquery sql = SQLocals_PrepareSelect(oObject, SQLOCALS_TYPE_LOCATION, sVarName);
|
||||
|
||||
if (SqlStep(sql))
|
||||
return SQLocals_StringToLocation(SqlGetString(sql, 0));
|
||||
else
|
||||
return GetStartingLocation();
|
||||
}
|
||||
|
||||
// Sets a location stored on oObject to the given value
|
||||
// * oObject - an object to reference against
|
||||
// * sVarName - name of the variable to retrieve
|
||||
// * lValue - Value to store
|
||||
void SQLocals_SetLocation(object oObject, string sVarName, location lValue)
|
||||
{
|
||||
if (!GetIsPC(oObject) || sVarName == "") return;
|
||||
|
||||
sqlquery sql = SQLocals_PrepareInsert(oObject, SQLOCALS_TYPE_LOCATION, sVarName);
|
||||
SqlBindString(sql, "@value", SQLocals_LocationToString(lValue));
|
||||
SqlStep(sql);
|
||||
}
|
||||
|
||||
// Deletes a location stored on oObject
|
||||
// * oObject - an object to reference against
|
||||
// * sVarName - name of the variable to delete
|
||||
void SQLocals_DeleteLocation(object oObject, string sVarName)
|
||||
{
|
||||
if (!GetIsPC(oObject) || sVarName == "") return;
|
||||
|
||||
sqlquery sql = SQLocals_PrepareDelete(oObject, SQLOCALS_TYPE_LOCATION, sVarName);
|
||||
SqlStep(sql);
|
||||
}
|
||||
/* **** */
|
||||
|
||||
/* UTILITY */
|
||||
|
||||
// Deletes a set of locals stored on oObject matching the given criteria
|
||||
// * oObject - an object to reference against
|
||||
// * nType - The SQL_LOCALS_TYPE_* you wish to remove (default: SQL_LOCALS_TYPE_ALL)
|
||||
// * sLike - The string to compare with the SQL "like" comparison
|
||||
// * sEscape - The escape character to use with the SQL "escape" keyword
|
||||
void SQLocals_Delete(object oObject, int nType = SQLOCALS_TYPE_ALL, string sLike = "", string sEscape = "")
|
||||
{
|
||||
if (!GetIsPC(oObject) || nType < 0) return;
|
||||
|
||||
SQLocals_CreateTable(oObject);
|
||||
|
||||
sqlquery sql = SqlPrepareQueryObject(oObject,
|
||||
"DELETE FROM " + SQLOCALS_TABLE_NAME + " " +
|
||||
"WHERE " +
|
||||
(nType != SQLOCALS_TYPE_ALL ? "AND type & @type " : " ") +
|
||||
(sLike != "" ? "AND varname LIKE @like " + (sEscape != "" ? "ESCAPE @escape" : "") : "") +
|
||||
";");
|
||||
|
||||
if (nType != SQLOCALS_TYPE_ALL)
|
||||
SqlBindInt(sql, "@type", nType);
|
||||
if (sLike != "")
|
||||
{
|
||||
SqlBindString(sql, "@like", sLike);
|
||||
|
||||
if (sEscape != "")
|
||||
SqlBindString(sql, "@escape", sEscape);
|
||||
}
|
||||
|
||||
SqlStep(sql);
|
||||
}
|
||||
|
||||
// Counts a set of locals stored on oObject matching the given criteria
|
||||
// * oObject - an object to reference against
|
||||
// * nType - The SQL_LOCALS_TYPE_* you wish to remove (default: SQL_LOCALS_TYPE_ALL)
|
||||
// * sLike - The string to compare with the SQL "like" comparison
|
||||
// * sEscape - The escape character to use with the SQL "escape" keyword
|
||||
int SQLocals_Count(object oObject, int nType = SQLOCALS_TYPE_ALL, string sLike = "", string sEscape = "")
|
||||
{
|
||||
if (!GetIsPC(oObject) || nType < 0) return 0;
|
||||
|
||||
SQLocals_CreateTable(oObject);
|
||||
|
||||
sqlquery sql = SqlPrepareQueryObject(oObject,
|
||||
"SELECT COUNT(*) FROM " + SQLOCALS_TABLE_NAME + " " +
|
||||
"WHERE " +
|
||||
(nType != SQLOCALS_TYPE_ALL ? "AND type & @type " : " ") +
|
||||
(sLike != "" ? "AND varname LIKE @like " + (sEscape != "" ? "ESCAPE @escape" : "") : "") +
|
||||
";");
|
||||
|
||||
if (nType != SQLOCALS_TYPE_ALL)
|
||||
SqlBindInt(sql, "@type", nType);
|
||||
if (sLike != "")
|
||||
{
|
||||
SqlBindString(sql, "@like", sLike);
|
||||
|
||||
if (sEscape != "")
|
||||
SqlBindString(sql, "@escape", sEscape);
|
||||
}
|
||||
|
||||
if (SqlStep(sql))
|
||||
return SqlGetInt(sql, 0);
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Checks a locals stored on oObject is set
|
||||
// * oObject - an object to reference against
|
||||
// * sVarName - name of the variable to retrieve
|
||||
// * nType - The SQL_LOCALS_TYPE_* you wish to remove (default: SQL_LOCALS_TYPE_ALL)
|
||||
int SQLocals_IsSet(object oObject, string sVarName, int nType)
|
||||
{
|
||||
if (!GetIsPC(oObject) || nType < 0) return 0;
|
||||
|
||||
SQLocals_CreateTable(oObject);
|
||||
|
||||
sqlquery sql = SqlPrepareQueryObject(oObject,
|
||||
"SELECT * FROM " + SQLOCALS_TABLE_NAME + " " +
|
||||
"WHERE " +
|
||||
(nType != SQLOCALS_TYPE_ALL ? "AND type & @type " : " ") +
|
||||
"AND varname = @varname;");
|
||||
|
||||
if (nType != SQLOCALS_TYPE_ALL)
|
||||
SqlBindInt(sql, "@type", nType);
|
||||
SqlBindString(sql, "@varname", sVarName);
|
||||
|
||||
return SqlStep(sql);
|
||||
}
|
||||
|
||||
// Returns the last Unix time the given variable was updated
|
||||
// * oObject - an object to reference against
|
||||
// * sVarName - name of the variable to retrieve
|
||||
// * nType - The SQL_LOCALS_TYPE_* you wish to remove (default: SQL_LOCALS_TYPE_ALL)
|
||||
int SQLocals_GetLastUpdated_UnixEpoch(object oObject, string sVarName, int nType)
|
||||
{
|
||||
if (!GetIsPC(oObject) || nType <= 0) return 0;
|
||||
|
||||
SQLocals_CreateTable(oObject);
|
||||
|
||||
sqlquery sql = SqlPrepareQueryObject(oObject,
|
||||
"SELECT timestamp FROM " + SQLOCALS_TABLE_NAME + " " +
|
||||
"WHERE type = @type " +
|
||||
"AND varname = @varname;");
|
||||
|
||||
SqlBindInt(sql, "@type", nType);
|
||||
SqlBindString(sql, "@varname", sVarName);
|
||||
|
||||
if (SqlStep(sql))
|
||||
return SqlGetInt(sql, 0);
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Returns the last UTC time the given variable was updated
|
||||
// * oObject - an object to reference against
|
||||
// * sVarName - name of the variable to retrieve
|
||||
// * nType - The SQL_LOCALS_TYPE_* you wish to remove (default: SQL_LOCALS_TYPE_ALL)
|
||||
string SQLocals_GetLastUpdated_UTC(object oObject, string sVarName, int nType)
|
||||
{
|
||||
if (!GetIsPC(oObject) || nType <= 0) return "";
|
||||
|
||||
SQLocals_CreateTable(oObject);
|
||||
|
||||
sqlquery sql = SqlPrepareQueryObject(oObject,
|
||||
"SELECT datetime(timestamp, 'unixepoch') FROM " + SQLOCALS_TABLE_NAME + " " +
|
||||
"WHERE type = @type " +
|
||||
"AND varname = @varname;");
|
||||
|
||||
SqlBindInt(sql, "@type", nType);
|
||||
SqlBindString(sql, "@varname", sVarName);
|
||||
|
||||
if (SqlStep(sql))
|
||||
return SqlGetString(sql, 0);
|
||||
else
|
||||
return "";
|
||||
}
|
556
trunk/users/Stratovarius/NWNEE Updates/prc_amagsys_gain.nss
Normal file
556
trunk/users/Stratovarius/NWNEE Updates/prc_amagsys_gain.nss
Normal file
@@ -0,0 +1,556 @@
|
||||
//:://////////////////////////////////////////////
|
||||
//:: Alternate magic system gain evaluation script
|
||||
//:: prc_amagsys_gain
|
||||
//:://////////////////////////////////////////////
|
||||
/** @file
|
||||
This file determines if the given character
|
||||
has gained new spells / powers / utterances /
|
||||
whathaveyou since the last time it was run.
|
||||
If so, it starts the relevant selection
|
||||
conversations.
|
||||
|
||||
Add new classes to their respective magic
|
||||
user type block, or if such doesn't exist
|
||||
yet for the system the class belongs to,
|
||||
make a new block for them at the end of main().
|
||||
|
||||
|
||||
@author Ornedan
|
||||
@date Created - 2006.12.14
|
||||
*/
|
||||
//:://////////////////////////////////////////////
|
||||
//:://////////////////////////////////////////////
|
||||
|
||||
#include "inc_dynconv"
|
||||
#include "psi_inc_psifunc"
|
||||
#include "inc_newspellbook"
|
||||
#include "true_inc_trufunc"
|
||||
#include "tob_inc_tobfunc"
|
||||
#include "shd_inc_shdfunc"
|
||||
#include "inv_inc_invfunc"
|
||||
|
||||
//////////////////////////////////////////////////
|
||||
/* Function prototypes */
|
||||
//////////////////////////////////////////////////
|
||||
|
||||
void CheckSpellbooks(object oPC);
|
||||
void CheckPsionics(object oPC);
|
||||
void CheckInvocations(object oPC);
|
||||
void CheckToB(object oPC);
|
||||
void CheckShadow(object oPC);
|
||||
void CheckTruenaming(object oPC);
|
||||
int CheckMissingPowers(object oPC, int nClass);
|
||||
int CheckMissingSpells(object oPC, int nClass, int nMinLevel, int nMaxLevel);
|
||||
int CheckMissingUtterances(object oPC, int nClass, int nLexicon);
|
||||
int CheckMissingManeuvers(object oPC, int nClass);
|
||||
int CheckMissingMysteries(object oPC, int nClass);
|
||||
int CheckMissingInvocations(object oPC, int nClass);
|
||||
void AMSCompatibilityCheck(object oPC);
|
||||
|
||||
//////////////////////////////////////////////////
|
||||
/* Function definitions */
|
||||
//////////////////////////////////////////////////
|
||||
|
||||
void main()
|
||||
{
|
||||
object oPC = OBJECT_SELF;
|
||||
|
||||
// Sanity checks - Shifted or polymorphed characters may have their hide fucked up, and might be missing access to their hide-feats
|
||||
// @todo Shifting probably doesn't do this anymore, could be ditchable - Ornedan, 20061214
|
||||
if(GetLocalInt(oPC, "nPCShifted"))
|
||||
return;
|
||||
effect eTest = GetFirstEffect(oPC);
|
||||
while(GetIsEffectValid(eTest))
|
||||
{
|
||||
if(GetEffectType(eTest) == EFFECT_TYPE_POLYMORPH)
|
||||
return;
|
||||
eTest = GetNextEffect(oPC);
|
||||
}
|
||||
|
||||
DelayCommand(0.0f, CheckSpellbooks(oPC));
|
||||
}
|
||||
|
||||
// Handle new spellbooks
|
||||
void CheckSpellbooks(object oPC)
|
||||
{
|
||||
if(!GetPRCSwitch(PRC_BARD_DISALLOW_NEWSPELLBOOK) && CheckMissingSpells(oPC, CLASS_TYPE_BARD, 0, 6))
|
||||
return;
|
||||
if(!GetPRCSwitch(PRC_SORC_DISALLOW_NEWSPELLBOOK) && CheckMissingSpells(oPC, CLASS_TYPE_SORCERER, 0, 9))
|
||||
return;
|
||||
if(CheckMissingSpells(oPC, CLASS_TYPE_SUEL_ARCHANAMACH, 1, 5))
|
||||
return;
|
||||
if(CheckMissingSpells(oPC, CLASS_TYPE_FAVOURED_SOUL, 0, 9))
|
||||
return;
|
||||
if(CheckMissingSpells(oPC, CLASS_TYPE_MYSTIC, 0, 9))
|
||||
return;
|
||||
if(CheckMissingSpells(oPC, CLASS_TYPE_WARMAGE, 0, 9))
|
||||
return;
|
||||
if(CheckMissingSpells(oPC, CLASS_TYPE_DREAD_NECROMANCER, 1, 9))
|
||||
return;
|
||||
if(CheckMissingSpells(oPC, CLASS_TYPE_HEXBLADE, 1, 4))
|
||||
return;
|
||||
if(CheckMissingSpells(oPC, CLASS_TYPE_DUSKBLADE, 0, 5))
|
||||
return;
|
||||
if(CheckMissingSpells(oPC, CLASS_TYPE_JUSTICEWW, 1, 4))
|
||||
return;
|
||||
if(CheckMissingSpells(oPC, CLASS_TYPE_KNIGHT_WEAVE, 1, 6))
|
||||
return;
|
||||
if(CheckMissingSpells(oPC, CLASS_TYPE_WITCH, 0, 9))
|
||||
return;
|
||||
if(CheckMissingSpells(oPC, CLASS_TYPE_SUBLIME_CHORD, 4, 9))
|
||||
return;
|
||||
if(CheckMissingSpells(oPC, CLASS_TYPE_ARCHIVIST, 0, 9))
|
||||
return;
|
||||
if(CheckMissingSpells(oPC, CLASS_TYPE_BEGUILER, 0, 9))
|
||||
return;
|
||||
if(CheckMissingSpells(oPC, CLASS_TYPE_HARPER, 1, 3))
|
||||
return;
|
||||
if(CheckMissingSpells(oPC, CLASS_TYPE_TEMPLAR, 0, 9))
|
||||
return;
|
||||
if(CheckMissingSpells(oPC, CLASS_TYPE_ASSASSIN, 1, 4))
|
||||
return;
|
||||
if(CheckMissingSpells(oPC, CLASS_TYPE_CELEBRANT_SHARESS, 1, 4))
|
||||
return;
|
||||
|
||||
DelayCommand(0.0f, CheckPsionics(oPC));
|
||||
}
|
||||
|
||||
// Handle psionics
|
||||
void CheckPsionics(object oPC)
|
||||
{
|
||||
if(CheckMissingPowers(oPC, CLASS_TYPE_PSION))
|
||||
return;
|
||||
if(CheckMissingPowers(oPC, CLASS_TYPE_WILDER))
|
||||
return;
|
||||
if(CheckMissingPowers(oPC, CLASS_TYPE_PSYWAR))
|
||||
return;
|
||||
if(CheckMissingPowers(oPC, CLASS_TYPE_PSYCHIC_ROGUE))
|
||||
return;
|
||||
if(CheckMissingPowers(oPC, CLASS_TYPE_FIST_OF_ZUOKEN))
|
||||
return;
|
||||
if(CheckMissingPowers(oPC, CLASS_TYPE_WARMIND))
|
||||
return;
|
||||
//expanded knowledge
|
||||
if(CheckMissingPowers(oPC, -1))
|
||||
return;
|
||||
//epic expanded knowledge
|
||||
if(CheckMissingPowers(oPC, -2))
|
||||
return;
|
||||
|
||||
DelayCommand(0.0f, CheckInvocations(oPC));
|
||||
}
|
||||
|
||||
// Handle Invocations
|
||||
void CheckInvocations(object oPC)
|
||||
{
|
||||
if(CheckMissingInvocations(oPC, CLASS_TYPE_DRAGONFIRE_ADEPT))
|
||||
return;
|
||||
if(CheckMissingInvocations(oPC, CLASS_TYPE_WARLOCK))
|
||||
return;
|
||||
if(CheckMissingInvocations(oPC, CLASS_TYPE_DRAGON_SHAMAN))
|
||||
return;
|
||||
//extra invocations
|
||||
if(CheckMissingInvocations(oPC, CLASS_TYPE_INVALID))
|
||||
return;
|
||||
//epic extra invocations
|
||||
if(CheckMissingInvocations(oPC, -2))
|
||||
return;
|
||||
|
||||
DelayCommand(0.0f, CheckToB(oPC));
|
||||
}
|
||||
|
||||
// Handle Tome of Battle
|
||||
void CheckToB(object oPC)
|
||||
{
|
||||
if(CheckMissingManeuvers(oPC, CLASS_TYPE_CRUSADER))
|
||||
return;
|
||||
if(CheckMissingManeuvers(oPC, CLASS_TYPE_SWORDSAGE))
|
||||
return;
|
||||
if(CheckMissingManeuvers(oPC, CLASS_TYPE_WARBLADE))
|
||||
return;
|
||||
|
||||
DelayCommand(0.0f, CheckShadow(oPC));
|
||||
}
|
||||
|
||||
// Handle Shadowcasting
|
||||
void CheckShadow(object oPC)
|
||||
{
|
||||
if(CheckMissingMysteries(oPC, CLASS_TYPE_SHADOWCASTER))
|
||||
return;
|
||||
if(CheckMissingMysteries(oPC, CLASS_TYPE_SHADOWSMITH))
|
||||
return;
|
||||
|
||||
DelayCommand(0.0f, CheckTruenaming(oPC));
|
||||
}
|
||||
|
||||
// Handle Truenaming - Three different Lexicons to check
|
||||
void CheckTruenaming(object oPC)
|
||||
{
|
||||
if(CheckMissingUtterances(oPC, CLASS_TYPE_TRUENAMER, LEXICON_EVOLVING_MIND))
|
||||
return;
|
||||
if(CheckMissingUtterances(oPC, CLASS_TYPE_TRUENAMER, LEXICON_CRAFTED_TOOL))
|
||||
return;
|
||||
if(CheckMissingUtterances(oPC, CLASS_TYPE_TRUENAMER, LEXICON_PERFECTED_MAP))
|
||||
return;
|
||||
|
||||
if(!GetIsDM(oPC))
|
||||
DelayCommand(0.0f, AMSCompatibilityCheck(oPC));
|
||||
}
|
||||
|
||||
int CheckMissingPowers(object oPC, int nClass)
|
||||
{
|
||||
int nLevel = GetLevelByClass(nClass, oPC);
|
||||
if(!nLevel && nClass != -1 && nClass != -2)
|
||||
return FALSE;
|
||||
else if(nClass == -1 && !GetHasFeat(FEAT_EXPANDED_KNOWLEDGE_1))
|
||||
return FALSE;
|
||||
else if(nClass == -2 && !GetHasFeat(FEAT_EPIC_EXPANDED_KNOWLEDGE_1))
|
||||
return FALSE;
|
||||
|
||||
int nCurrentPowers = GetPowerCount(oPC, nClass);
|
||||
int nMaxPowers = GetMaxPowerCount(oPC, nClass);
|
||||
|
||||
if(nCurrentPowers < nMaxPowers)
|
||||
{
|
||||
// Mark the class for which the PC is to gain powers and start the conversation
|
||||
SetLocalInt(oPC, "nClass", nClass);
|
||||
StartDynamicConversation("psi_powconv", oPC, DYNCONV_EXIT_NOT_ALLOWED, FALSE, TRUE, oPC);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
int CheckMissingInvocations(object oPC, int nClass)
|
||||
{
|
||||
int nLevel = GetLevelByClass(nClass, oPC);
|
||||
if(!nLevel && (nClass == CLASS_TYPE_DRAGONFIRE_ADEPT || nClass == CLASS_TYPE_WARLOCK || nClass == CLASS_TYPE_DRAGON_SHAMAN))
|
||||
return FALSE;
|
||||
else if(nClass == CLASS_TYPE_INVALID && !GetHasFeat(FEAT_EXTRA_INVOCATION_I))
|
||||
return FALSE;
|
||||
else if(nClass == -2 && !GetHasFeat(FEAT_EPIC_EXTRA_INVOCATION_I))
|
||||
return FALSE;
|
||||
|
||||
int nCurrentInvocations = GetInvocationCount(oPC, nClass);
|
||||
if(DEBUG) DoDebug("Current Invocations: " + IntToString(nCurrentInvocations));
|
||||
int nMaxInvocations = GetMaxInvocationCount(oPC, nClass);
|
||||
if(DEBUG) DoDebug("Max Invocations: " + IntToString(nMaxInvocations));
|
||||
|
||||
if(nCurrentInvocations < nMaxInvocations)
|
||||
{
|
||||
// Mark the class for which the PC is to gain invocations and start the conversation
|
||||
SetLocalInt(oPC, "nClass", nClass);
|
||||
StartDynamicConversation("inv_invokeconv", oPC, DYNCONV_EXIT_NOT_ALLOWED, FALSE, TRUE, oPC);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
void AddSpellsForLevel(int nClass, int nLevel)
|
||||
{
|
||||
object oPC = OBJECT_SELF;
|
||||
object oSkin = GetPCSkin(oPC);
|
||||
//object oPC = GetHideToken(oPC);
|
||||
string sFile = GetFileForClass(nClass);
|
||||
string sSpellbook;
|
||||
int nSpellbookType = GetSpellbookTypeForClass(nClass);
|
||||
if(nSpellbookType == SPELLBOOK_TYPE_SPONTANEOUS)
|
||||
sSpellbook = "Spellbook"+IntToString(nClass);
|
||||
else
|
||||
sSpellbook = "Spellbook_Known_"+IntToString(nClass)+"_"+IntToString(nLevel);
|
||||
|
||||
// Create spells known persistant array if it is missing
|
||||
int nSize = persistant_array_get_size(oPC, sSpellbook);
|
||||
if (nSize < 0)
|
||||
{
|
||||
persistant_array_create(oPC, sSpellbook);
|
||||
nSize = 0;
|
||||
}
|
||||
|
||||
//check for learnable spells
|
||||
//object oPC_Class = GetObjectByTag("SpellLvl_" + IntToString(nClass) + "_Level_" + IntToString(nLevel));
|
||||
int nSpells_Total = persistant_array_get_size(oPC, "Lkup");
|
||||
int i;
|
||||
for(i = 0; i < nSpells_Total; i++)
|
||||
{
|
||||
int nSpellbookID = persistant_array_get_int(oPC, "Lkup", i);
|
||||
if(Get2DAString(sFile, "AL", nSpellbookID) != "1")
|
||||
{
|
||||
array_set_int(oPC, sSpellbook, nSize, nSpellbookID);
|
||||
nSize++;
|
||||
if(nSpellbookType == SPELLBOOK_TYPE_SPONTANEOUS)
|
||||
{
|
||||
int nIPFeatID = StringToInt(Get2DACache(sFile, "IPFeatID", nSpellbookID));
|
||||
int nFeatID = StringToInt(Get2DACache(sFile, "FeatID", nSpellbookID));
|
||||
AddSpellUse(oPC, nSpellbookID, nClass, sFile, "NewSpellbookMem_" + IntToString(nClass), nSpellbookType, oSkin, nFeatID, nIPFeatID);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int CheckMissingSpells(object oPC, int nClass, int nMinLevel, int nMaxLevel)
|
||||
{
|
||||
int nLevel;
|
||||
//Raks cast as sorcs
|
||||
if(nClass == CLASS_TYPE_SORCERER && GetRacialType(oPC) == RACIAL_TYPE_RAKSHASA)
|
||||
nLevel = GetLevelByClass(CLASS_TYPE_OUTSIDER, oPC);
|
||||
else if(nClass == CLASS_TYPE_SORCERER && GetRacialType(oPC) == RACIAL_TYPE_ARKAMOI) //Bozaks cast as sorcs
|
||||
nLevel = GetLevelByClass(CLASS_TYPE_MONSTROUS, oPC);
|
||||
else if(nClass == CLASS_TYPE_SORCERER && GetRacialType(oPC) == RACIAL_TYPE_DRIDER) //Driders cast as sorcs
|
||||
nLevel = GetLevelByClass(CLASS_TYPE_ABERRATION, oPC);
|
||||
else
|
||||
nLevel = nClass == CLASS_TYPE_SUBLIME_CHORD ? GetLevelByClass(nClass, oPC) : GetSpellslotLevel(nClass, oPC);
|
||||
|
||||
if (DEBUG) DoDebug("CheckMissingSpells 1 Class: " + IntToString(nClass));
|
||||
if (DEBUG) DoDebug("CheckMissingSpells 1 Level: " + IntToString(nLevel));
|
||||
|
||||
if(!nLevel)
|
||||
return FALSE;
|
||||
if(nClass == CLASS_TYPE_BARD || nClass == CLASS_TYPE_SORCERER)
|
||||
{
|
||||
if((GetLevelByClass(nClass, oPC) == nLevel) //no PrC
|
||||
&& !(GetHasFeat(FEAT_DRACONIC_GRACE, oPC) || GetHasFeat(FEAT_DRACONIC_BREATH, oPC))) //no Draconic feats that apply
|
||||
return FALSE;
|
||||
}
|
||||
else if(nClass == CLASS_TYPE_ARCHIVIST)
|
||||
{
|
||||
int nLastGainLevel = GetPersistantLocalInt(oPC, "LastSpellGainLevel");
|
||||
nLevel = GetLevelByClass(CLASS_TYPE_ARCHIVIST, oPC);
|
||||
|
||||
if(nLastGainLevel < nLevel)
|
||||
{
|
||||
if(nLevel == 1)
|
||||
{
|
||||
//count the number of available at 1st level spells
|
||||
int nSpellsAvailable = 3 + GetAbilityModifier(ABILITY_INTELLIGENCE, oPC);
|
||||
SetLocalInt(oPC, "LrnLvlUp", nSpellsAvailable);
|
||||
}
|
||||
else if(nLevel > 1)
|
||||
//add additional 2 spells form cleric list
|
||||
SetLocalInt(oPC, "LrnLvlUp", 2);
|
||||
|
||||
SetLocalInt(oPC, "SpellGainClass", CLASS_TYPE_ARCHIVIST);
|
||||
SetLocalInt(oPC, "SpellbookMinSpelllevel", nMinLevel);
|
||||
StartDynamicConversation("prc_s_spellgain", oPC, DYNCONV_EXIT_NOT_ALLOWED, TRUE, FALSE, oPC);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
//add cleric spells known for level 0
|
||||
else if(persistant_array_get_size(oPC, "Spellbook_Known_"+IntToString(CLASS_TYPE_ARCHIVIST)+"_0") < 5) // TODO: replace with GetSpellKnownCurrentCount
|
||||
{
|
||||
ActionDoCommand(AddSpellsForLevel(CLASS_TYPE_ARCHIVIST, 0));
|
||||
}
|
||||
else
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (DEBUG) DoDebug("CheckMissingSpells 2 Class: " + IntToString(nClass));
|
||||
if (DEBUG) DoDebug("CheckMissingSpells 2 Level: " + IntToString(nLevel));
|
||||
|
||||
int i;
|
||||
for(i = nMinLevel; i <= nMaxLevel; i++)
|
||||
{
|
||||
int nMaxSpells = GetSpellKnownMaxCount(nLevel, i, nClass, oPC);
|
||||
if(nMaxSpells > 0)
|
||||
{
|
||||
int nCurrentSpells = GetSpellKnownCurrentCount(oPC, i, nClass);
|
||||
int nSpellsAvailable = GetSpellUnknownCurrentCount(oPC, i, nClass);
|
||||
|
||||
if(nCurrentSpells < nMaxSpells && nSpellsAvailable > 0)
|
||||
{
|
||||
if(GetSpellbookTypeForClass(nClass) == SPELLBOOK_TYPE_SPONTANEOUS && bKnowsAllClassSpells(nClass))
|
||||
{
|
||||
ActionDoCommand(AddSpellsForLevel(nClass, i));
|
||||
}
|
||||
else
|
||||
{
|
||||
// Mark the class for which the PC is to gain powers and start the conversation
|
||||
SetLocalInt(oPC, "SpellGainClass", nClass);
|
||||
SetLocalInt(oPC, "SpellbookMinSpelllevel", nMinLevel);
|
||||
SetLocalInt(oPC, "SpellbookMaxSpelllevel", nMaxLevel);
|
||||
StartDynamicConversation("prc_s_spellgain", oPC, DYNCONV_EXIT_NOT_ALLOWED, FALSE, TRUE, oPC);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
//Advanced Learning check
|
||||
nLevel = GetLevelByClass(nClass, oPC);
|
||||
int nALSpells = GetPersistantLocalInt(oPC, "AdvancedLearning_"+IntToString(nClass));
|
||||
if(nClass == CLASS_TYPE_BEGUILER && nALSpells < (nLevel+1)/4)//one every 4 levels starting at 3.
|
||||
{
|
||||
// Mark the class for which the PC is to gain powers and start the conversation
|
||||
SetLocalInt(oPC, "SpellGainClass", CLASS_TYPE_BEGUILER);
|
||||
SetLocalInt(oPC, "SpellbookMinSpelllevel", nMinLevel);
|
||||
SetLocalInt(oPC, "AdvancedLearning", 1);
|
||||
StartDynamicConversation("prc_s_spellgain", oPC, DYNCONV_EXIT_NOT_ALLOWED, FALSE, TRUE, oPC);
|
||||
return TRUE;
|
||||
}
|
||||
else if(nClass == CLASS_TYPE_DREAD_NECROMANCER && nALSpells < nLevel/4)//one every 4 levels
|
||||
{
|
||||
// Mark the class for which the PC is to gain powers and start the conversation
|
||||
SetLocalInt(oPC, "SpellGainClass", CLASS_TYPE_DREAD_NECROMANCER);
|
||||
SetLocalInt(oPC, "SpellbookMinSpelllevel", nMinLevel);
|
||||
SetLocalInt(oPC, "AdvancedLearning", 1);
|
||||
StartDynamicConversation("prc_s_spellgain", oPC, DYNCONV_EXIT_NOT_ALLOWED, FALSE, TRUE, oPC);
|
||||
return TRUE;
|
||||
}
|
||||
else if(nClass == CLASS_TYPE_WARMAGE)
|
||||
{
|
||||
if((nLevel >= 40 && nALSpells < 9) ||// :/
|
||||
(nLevel >= 36 && nLevel < 40 && nALSpells < 8) ||
|
||||
(nLevel >= 32 && nLevel < 36 && nALSpells < 7) ||
|
||||
(nLevel >= 28 && nLevel < 32 && nALSpells < 6) ||
|
||||
(nLevel >= 24 && nLevel < 28 && nALSpells < 5) ||
|
||||
(nLevel >= 16 && nLevel < 24 && nALSpells < 4) ||
|
||||
(nLevel >= 11 && nLevel < 16 && nALSpells < 3) ||
|
||||
(nLevel >= 6 && nLevel < 11 && nALSpells < 2) ||
|
||||
(nLevel >= 3 && nLevel < 6 && nALSpells < 1))
|
||||
{
|
||||
// Mark the class for which the PC is to gain powers and start the conversation
|
||||
SetLocalInt(oPC, "SpellGainClass", CLASS_TYPE_WARMAGE);
|
||||
SetLocalInt(oPC, "SpellbookMinSpelllevel", nMinLevel);
|
||||
SetLocalInt(oPC, "AdvancedLearning", 1);
|
||||
StartDynamicConversation("prc_s_spellgain", oPC, DYNCONV_EXIT_NOT_ALLOWED, FALSE, TRUE, oPC);
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
else if(nClass == CLASS_TYPE_NIGHTSTALKER && nALSpells < (nLevel+1)/6)//one every 6 levels starting at 5th
|
||||
{
|
||||
// Mark the class for which the PC is to gain powers and start the conversation
|
||||
SetLocalInt(oPC, "SpellGainClass", CLASS_TYPE_NIGHTSTALKER);
|
||||
SetLocalInt(oPC, "SpellbookMinSpelllevel", nMinLevel);
|
||||
SetLocalInt(oPC, "AdvancedLearning", 1);
|
||||
StartDynamicConversation("prc_s_spellgain", oPC, DYNCONV_EXIT_NOT_ALLOWED, FALSE, TRUE, oPC);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
int CheckMissingUtterances(object oPC, int nClass, int nLexicon)
|
||||
{
|
||||
int nLevel = GetLevelByClass(nClass, oPC);
|
||||
if(!nLevel)
|
||||
return FALSE;
|
||||
|
||||
int nCurrentUtterances = GetUtteranceCount(oPC, nClass, nLexicon);
|
||||
int nMaxUtterances = GetMaxUtteranceCount(oPC, nClass, nLexicon);
|
||||
if(DEBUG) DoDebug("CheckMissingUtterances(" + IntToString(nClass) + ", " + IntToString(nLexicon) + ", " + GetName(oPC) + ") = " + IntToString(nCurrentUtterances) + ", " + IntToString(nMaxUtterances));
|
||||
|
||||
if(nCurrentUtterances < nMaxUtterances)
|
||||
{
|
||||
// Mark the class for which the PC is to gain Utterances and start the conversation
|
||||
SetLocalInt(oPC, "nClass", nClass);
|
||||
StartDynamicConversation("true_utterconv", oPC, DYNCONV_EXIT_NOT_ALLOWED, FALSE, TRUE, oPC);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
int CheckMissingManeuvers(object oPC, int nClass)
|
||||
{
|
||||
int nLevel = GetLevelByClass(nClass, oPC);
|
||||
if(!nLevel)
|
||||
return FALSE;
|
||||
|
||||
int nCurrentManeuvers = GetManeuverCount(oPC, nClass, MANEUVER_TYPE_MANEUVER);
|
||||
int nMaxManeuvers = GetMaxManeuverCount(oPC, nClass, MANEUVER_TYPE_MANEUVER);
|
||||
int nCurrentStances = GetManeuverCount(oPC, nClass, MANEUVER_TYPE_STANCE);
|
||||
int nMaxStances = GetMaxManeuverCount(oPC, nClass, MANEUVER_TYPE_STANCE);
|
||||
|
||||
if(nCurrentManeuvers < nMaxManeuvers || nCurrentStances < nMaxStances)
|
||||
{
|
||||
// Mark the class for which the PC is to gain powers and start the conversation
|
||||
SetLocalInt(oPC, "nClass", nClass);
|
||||
StartDynamicConversation("tob_moveconv", oPC, DYNCONV_EXIT_NOT_ALLOWED, FALSE, TRUE, oPC);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
int CheckMissingMysteries(object oPC, int nClass)
|
||||
{
|
||||
int nLevel = GetLevelByClass(nClass, oPC);
|
||||
if(!nLevel)
|
||||
return FALSE;
|
||||
|
||||
int nCurrentMysteries = GetMysteryCount(oPC, nClass);
|
||||
int nMaxMysteries = GetMaxMysteryCount(oPC, nClass);
|
||||
|
||||
if(nCurrentMysteries < nMaxMysteries)
|
||||
{
|
||||
// Mark the class for which the PC is to gain powers and start the conversation
|
||||
SetLocalInt(oPC, "nClass", nClass);
|
||||
StartDynamicConversation("shd_mystconv", oPC, DYNCONV_EXIT_NOT_ALLOWED, FALSE, TRUE, oPC);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
//AMS Compatibility functions - xwarren:
|
||||
void CopyAMSArray(object oHideToken, object oAMSToken, int nClass, string sArray, int nMin, int nMax, int nLoopSize = 100)
|
||||
{
|
||||
string sFile = GetFileForClass(nClass);
|
||||
int i = nMin;
|
||||
while(i < nMin + nLoopSize && i < nMax)
|
||||
{
|
||||
int nSpellbookID = array_get_int(oHideToken, sArray, i);
|
||||
int nSpell = StringToInt(Get2DACache(sFile, "RealSpellID", nSpellbookID));
|
||||
if(DEBUG) DoDebug("Copying spell "+IntToString(nSpell));
|
||||
array_set_int(oAMSToken, sArray, i, nSpell);
|
||||
i++;
|
||||
}
|
||||
if(i < nMax)
|
||||
DelayCommand(0.0, CopyAMSArray(oHideToken, oAMSToken, nClass, sArray, i, nMax));
|
||||
}
|
||||
|
||||
void DoBuckUpAMS(object oPC, int nClass, string sSpellbook, object oHideToken, object oAMSToken)
|
||||
{
|
||||
if(DEBUG) DoDebug("Creating buck-up copy of "+sSpellbook);
|
||||
if(array_exists(oAMSToken, sSpellbook))
|
||||
array_delete(oAMSToken, sSpellbook);
|
||||
array_create(oAMSToken, sSpellbook);
|
||||
int nSize = array_get_size(oHideToken, sSpellbook);
|
||||
DelayCommand(0.0, CopyAMSArray(oHideToken, oAMSToken, nClass, sSpellbook, 0, nSize));
|
||||
}
|
||||
|
||||
void AMSCompatibilityCheck(object oPC)
|
||||
{
|
||||
//Get an extra hide token with amagsys info
|
||||
object oAMSToken = GetHideToken(oPC, TRUE);
|
||||
object oHideToken = GetHideToken(oPC);
|
||||
|
||||
int i;
|
||||
for(i = 1; i <= 3; i++)
|
||||
{
|
||||
int nClass = GetClassByPosition(i, oPC);
|
||||
string sSpellbook;
|
||||
int nSpellbookType = GetSpellbookTypeForClass(nClass);
|
||||
if(nSpellbookType == SPELLBOOK_TYPE_SPONTANEOUS)
|
||||
{
|
||||
sSpellbook = "Spellbook"+IntToString(nClass);
|
||||
int nSize1 = array_get_size(oHideToken, sSpellbook);
|
||||
int nSize2 = array_get_size(oAMSToken, sSpellbook);
|
||||
if(nSize1 > nSize2)
|
||||
DelayCommand(0.1f, DoBuckUpAMS(oPC, nClass, sSpellbook, oHideToken, oAMSToken));
|
||||
}
|
||||
else if(nSpellbookType == SPELLBOOK_TYPE_PREPARED)
|
||||
{
|
||||
int j;
|
||||
for(j = 0; j <= 9; j++)
|
||||
{
|
||||
sSpellbook = "Spellbook_Known_"+IntToString(nClass)+"_"+IntToString(j);
|
||||
int nSize1 = array_get_size(oHideToken, sSpellbook);
|
||||
int nSize2 = array_get_size(oAMSToken, sSpellbook);
|
||||
if(nSize1 > nSize2)
|
||||
DelayCommand(0.1f, DoBuckUpAMS(oPC, nClass, sSpellbook, oHideToken, oAMSToken));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
114
trunk/users/Stratovarius/NWNEE Updates/prc_archv_lspell.nss
Normal file
114
trunk/users/Stratovarius/NWNEE Updates/prc_archv_lspell.nss
Normal file
@@ -0,0 +1,114 @@
|
||||
//Learn spell from scroll function for archivist class.
|
||||
|
||||
#include "inc_newspellbook"
|
||||
|
||||
void SortSpellbook()
|
||||
{
|
||||
object oToken = GetHideToken(OBJECT_SELF);
|
||||
int i;
|
||||
for(i = 0; i < 10; i++)
|
||||
{
|
||||
float fDelay = i*0.1f;
|
||||
string sSpellBook = GetSpellsKnown_Array(CLASS_TYPE_ARCHIVIST, i);
|
||||
if(persistant_array_exists(oToken, sSpellBook))
|
||||
{
|
||||
DelayCommand(fDelay, CountingSortInt(oToken, sSpellBook));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void main()
|
||||
{
|
||||
object oPC = OBJECT_SELF;
|
||||
object oScroll = GetSpellTargetObject();
|
||||
|
||||
if(GetItemPossessor(oScroll) != oPC)
|
||||
return;
|
||||
|
||||
int nItemType = GetBaseItemType(oScroll);
|
||||
if(GetIdentified(oScroll) && nItemType != BASE_ITEM_SCROLL && nItemType != BASE_ITEM_SPELLSCROLL && nItemType != BASE_ITEM_ENCHANTED_SCROLL)
|
||||
{
|
||||
PlaySound("gui_failspell");
|
||||
SendMessageToPC(oPC, GetStringByStrRef(53309));//"You cannnot learn anything from that item."
|
||||
return;
|
||||
}
|
||||
|
||||
int nSpellID = -1;
|
||||
itemproperty ipTest = GetFirstItemProperty(oScroll);
|
||||
while(GetIsItemPropertyValid(ipTest))
|
||||
{
|
||||
if(GetItemPropertyType(ipTest) == ITEM_PROPERTY_CAST_SPELL)
|
||||
{
|
||||
nSpellID = StringToInt(Get2DACache("iprp_spells", "SpellIndex", GetItemPropertySubType(ipTest)));
|
||||
break;
|
||||
}
|
||||
ipTest = GetNextItemProperty(oScroll);
|
||||
}
|
||||
|
||||
if(nSpellID > -1)
|
||||
{
|
||||
//look for the spellID in spell book
|
||||
int nSpellbookID = RealSpellToSpellbookID(CLASS_TYPE_ARCHIVIST, nSpellID);
|
||||
|
||||
//it's not in the spell book
|
||||
if(nSpellbookID == -1)
|
||||
{
|
||||
PlaySound("gui_failspell");
|
||||
SendMessageToPC(oPC, GetStringByStrRef(16789885));//"You can only learn Divine spells."
|
||||
return;
|
||||
}
|
||||
|
||||
//check spell level
|
||||
string sFile = "cls_spell_archv";
|
||||
int nSpellLevel = StringToInt(Get2DACache(sFile, "Level", nSpellbookID));
|
||||
int nCasterLevel = GetCasterLevelByClass(CLASS_TYPE_ARCHIVIST, oPC);
|
||||
int nSpellLevelMax = GetMaxSpellLevelForCasterLevel(CLASS_TYPE_ARCHIVIST, nCasterLevel);
|
||||
|
||||
if(nSpellLevel > nSpellLevelMax)
|
||||
{
|
||||
PlaySound("gui_failspell");
|
||||
SendMessageToPC(oPC, GetStringByStrRef(68612));//"You have not achieved the required level to learn that spell."
|
||||
return;
|
||||
}
|
||||
if(nSpellLevel > (GetAbilityScore(oPC, ABILITY_INTELLIGENCE) - 10))
|
||||
{
|
||||
PlaySound("gui_failspell");
|
||||
SendMessageToPC(oPC, GetStringByStrRef(68613));//"You do not have the minimum attribute required to learn this spell."
|
||||
return;
|
||||
}
|
||||
|
||||
//check if oPC doesn't have the spell and can learn it
|
||||
//object oToken = GetHideToken(oPC);
|
||||
string sSpellBook = GetSpellsKnown_Array(CLASS_TYPE_ARCHIVIST, nSpellLevel);
|
||||
|
||||
// Create spells known persistant array if it is missing
|
||||
int nSize = persistant_array_get_size(oPC, sSpellBook);
|
||||
if (nSize < 0)
|
||||
{
|
||||
persistant_array_create(oPC, sSpellBook);
|
||||
nSize = 0;
|
||||
}
|
||||
|
||||
if(IsIntSet(oPC, sSpellBook, nSpellbookID) != -1)
|
||||
{
|
||||
PlaySound("gui_failspell");
|
||||
SendMessageToPC(oPC, GetStringByStrRef(53308));//"You already have that spell in your spellbook."
|
||||
return;
|
||||
}
|
||||
|
||||
//destroy the scroll
|
||||
int nStack = GetNumStackedItems(oScroll);
|
||||
if (nStack > 1)
|
||||
SetItemStackSize(oScroll, --nStack);
|
||||
else
|
||||
DestroyObject(oScroll);
|
||||
|
||||
//add the spell
|
||||
persistant_array_set_int(oPC, sSpellBook, nSize, nSpellbookID);
|
||||
PlaySound("gui_learnspell");
|
||||
|
||||
string sName = GetStringByStrRef(StringToInt(Get2DACache("spells", "Name", nSpellID)));
|
||||
SendMessageToPC(oPC, ReplaceChars(GetStringByStrRef(53307), "<CUSTOM0>", sName));//"<CUSTOM0> has been added to your spellbook."
|
||||
}
|
||||
//SortSpellbook(); Causing TMIs - disabled at the moment
|
||||
}
|
1172
trunk/users/Stratovarius/NWNEE Updates/prc_s_spellgain.nss
Normal file
1172
trunk/users/Stratovarius/NWNEE Updates/prc_s_spellgain.nss
Normal file
File diff suppressed because it is too large
Load Diff
124
trunk/users/Stratovarius/NWNEE Updates/prc_witch_lspell.nss
Normal file
124
trunk/users/Stratovarius/NWNEE Updates/prc_witch_lspell.nss
Normal file
@@ -0,0 +1,124 @@
|
||||
//Learn spell from scroll function for witch class.
|
||||
// Deprecated as Witch is no longer in the PRC
|
||||
|
||||
#include "inc_newspellbook"
|
||||
|
||||
void main()
|
||||
{
|
||||
/* if(GetPRCSwitch(PRC_WITCH_DISABLE_SPELL_LEARN))
|
||||
{
|
||||
SendMessageToPC(OBJECT_SELF, "Spell-learning for Witch class has been disabled in this module");
|
||||
return;
|
||||
}
|
||||
|
||||
object oScroll = GetSpellTargetObject();
|
||||
if(GetItemPossessor(oScroll) != OBJECT_SELF)
|
||||
return;
|
||||
|
||||
int nItemType = GetBaseItemType(oScroll);
|
||||
if(GetIdentified(oScroll) && nItemType != BASE_ITEM_SCROLL && nItemType != BASE_ITEM_SPELLSCROLL && nItemType != BASE_ITEM_ENCHANTED_SCROLL)
|
||||
{
|
||||
PlaySound("gui_failspell");
|
||||
SendMessageToPC(OBJECT_SELF, GetStringByStrRef(53309));//"You cannnot learn anything from that item."
|
||||
return;
|
||||
}
|
||||
|
||||
int nSpellID = -1;
|
||||
itemproperty ipTest = GetFirstItemProperty(oScroll);
|
||||
while(GetIsItemPropertyValid(ipTest))
|
||||
{
|
||||
if(GetItemPropertyType(ipTest) == ITEM_PROPERTY_CAST_SPELL)
|
||||
{
|
||||
nSpellID = StringToInt(Get2DACache("iprp_spells", "SpellIndex", GetItemPropertySubType(ipTest)));
|
||||
break;
|
||||
}
|
||||
ipTest = GetNextItemProperty(oScroll);
|
||||
}
|
||||
|
||||
if(nSpellID > -1)
|
||||
{
|
||||
//look for the spellID in spell book
|
||||
int nSpellbookID = RealSpellToSpellbookID(CLASS_TYPE_WITCH, nSpellID);
|
||||
|
||||
//it's not in the spell book
|
||||
if(nSpellbookID == -1)
|
||||
{
|
||||
PlaySound("gui_failspell");
|
||||
SendMessageToPC(OBJECT_SELF, GetStringByStrRef(16789885));//"You can only learn Witch spells."
|
||||
return;
|
||||
}
|
||||
|
||||
//check spell level
|
||||
string sFile = "cls_spell_witch";
|
||||
int nSpellLevel = StringToInt(Get2DACache(sFile, "Level", nSpellbookID));
|
||||
int nCasterLevel = GetCasterLevelByClass(CLASS_TYPE_WITCH, OBJECT_SELF);
|
||||
int nSpellLevelMax = GetMaxSpellLevelForCasterLevel(CLASS_TYPE_WITCH, nCasterLevel);
|
||||
|
||||
if(nSpellLevel > nSpellLevelMax)
|
||||
{
|
||||
PlaySound("gui_failspell");
|
||||
SendMessageToPC(OBJECT_SELF, GetStringByStrRef(68612));//"You have not achieved the required level to learn that spell."
|
||||
return;
|
||||
}
|
||||
if(nSpellLevel > (GetAbilityScore(OBJECT_SELF, ABILITY_WISDOM) - 10))
|
||||
{
|
||||
PlaySound("gui_failspell");
|
||||
SendMessageToPC(OBJECT_SELF, GetStringByStrRef(68613));//"You do not have the minimum attribute required to learn this spell."
|
||||
return;
|
||||
}
|
||||
int nXPCost = 75*nSpellLevel;
|
||||
if(!nXPCost) nXPCost = 25;
|
||||
|
||||
if(!GetHasXPToSpend(OBJECT_SELF, nXPCost))
|
||||
{
|
||||
PlaySound("gui_failspell");
|
||||
SendMessageToPC(OBJECT_SELF, "Not enough XP to learn this spell.");
|
||||
return;
|
||||
}
|
||||
|
||||
//check if OBJECT_SELF doesn't have the spell and can learn it
|
||||
object oToken = GetHideToken(OBJECT_SELF);
|
||||
string sSpellBook = "Spellbook" + IntToString(CLASS_TYPE_WITCH);//GetSpellsKnown_Array(CLASS_TYPE_WITCH);
|
||||
|
||||
// Create spells known persistant array if it is missing
|
||||
int nSize = array_get_size(oToken, sSpellBook);
|
||||
if (nSize < 0)
|
||||
{
|
||||
array_create(oToken, sSpellBook);
|
||||
nSize = 0;
|
||||
}
|
||||
|
||||
if(array_has_int(oToken, sSpellBook, nSpellbookID) != -1)
|
||||
{
|
||||
PlaySound("gui_failspell");
|
||||
SendMessageToPC(OBJECT_SELF, GetStringByStrRef(53308));//"You already have that spell in your spellbook."
|
||||
return;
|
||||
}
|
||||
|
||||
//destroy the scroll
|
||||
int nStack = GetNumStackedItems(oScroll);
|
||||
if (nStack > 1)
|
||||
SetItemStackSize(oScroll, --nStack);
|
||||
else
|
||||
DestroyObject(oScroll);
|
||||
|
||||
//make a spellcraft check
|
||||
if(!GetIsSkillSuccessful(OBJECT_SELF, SKILL_SPELLCRAFT, 10 + nSpellLevel))
|
||||
{
|
||||
PlaySound("gui_failspell");
|
||||
SendMessageToPC(OBJECT_SELF, "You failed to learn this spell.");
|
||||
return;
|
||||
}
|
||||
|
||||
//add the spell
|
||||
PlaySound("gui_learnspell");
|
||||
int nIPFeatID = StringToInt(Get2DACache(sFile, "IPFeatID", nSpellbookID));
|
||||
int nFeatID = StringToInt(Get2DACache(sFile, "FeatID", nSpellbookID));
|
||||
array_set_int(oToken, sSpellBook, nSize, nSpellbookID);
|
||||
AddSpellUse(OBJECT_SELF, nSpellbookID, CLASS_TYPE_WITCH, sFile, "NewSpellbookMem_" + IntToString(CLASS_TYPE_WITCH), SPELLBOOK_TYPE_SPONTANEOUS, GetPCSkin(OBJECT_SELF), nFeatID, nIPFeatID);
|
||||
SpendXP(OBJECT_SELF, nXPCost);
|
||||
|
||||
string sName = GetStringByStrRef(StringToInt(Get2DACache("spells", "Name", nSpellID)));
|
||||
SendMessageToPC(OBJECT_SELF, ReplaceChars(GetStringByStrRef(53307), "<CUSTOM0>", sName));//"<CUSTOM0> has been added to your spellbook."
|
||||
}*/
|
||||
}
|
Reference in New Issue
Block a user