Initial upload.

Adding base PRC 4.19a files to repository.
This commit is contained in:
Jaysyn904
2022-10-07 13:51:24 -04:00
parent 646eb01834
commit 1662218bb4
22441 changed files with 1274376 additions and 0 deletions

View 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);
}
}

View 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(){}

File diff suppressed because it is too large Load Diff

View 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(){}

View 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;
}

View 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 "";
}

View 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));
}
}
}
}

View 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
}

File diff suppressed because it is too large Load Diff

View 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."
}*/
}